diff --git a/example/src/example.gleam b/example/src/example.gleam index 0581efc..76ddb5a 100644 --- a/example/src/example.gleam +++ b/example/src/example.gleam @@ -7,8 +7,7 @@ pub fn main() { io.println("Squall Multi-Field Query Example") io.println("=================================\n") - let client = - squall.new_client("https://rickandmortyapi.com/graphql", []) + let client = squall.new_client("https://rickandmortyapi.com/graphql", []) let result = multi_query.multi_query(client) diff --git a/example/src/example_with_vars.gleam b/example/src/example_with_vars.gleam index 270957e..3a1a546 100644 --- a/example/src/example_with_vars.gleam +++ b/example/src/example_with_vars.gleam @@ -13,17 +13,10 @@ pub fn main() { io.println(" locationId: \"1\"") io.println(" episodeIds: [1, 2]\n") - let client = - squall.new_client("https://rickandmortyapi.com/graphql", []) + let client = squall.new_client("https://rickandmortyapi.com/graphql", []) let result = - multi_query_with_vars.multi_query_with_vars( - client, - 2, - "rick", - "1", - [1, 2], - ) + multi_query_with_vars.multi_query_with_vars(client, 2, "rick", "1", [1, 2]) case result { Ok(response) -> { diff --git a/example/src/graphql/get_character.gleam b/example/src/graphql/get_character.gleam index e55c033..95bbf57 100644 --- a/example/src/graphql/get_character.gleam +++ b/example/src/graphql/get_character.gleam @@ -41,15 +41,20 @@ pub type GetCharacterResponse { } pub fn get_character_response_decoder() -> decode.Decoder(GetCharacterResponse) { - use character <- decode.field("character", decode.optional(character_decoder())) + use character <- decode.field( + "character", + decode.optional(character_decoder()), + ) decode.success(GetCharacterResponse(character: character)) } -pub fn get_character(client: squall.Client, id: String) -> Result(GetCharacterResponse, String) { +pub fn get_character( + client: squall.Client, + id: String, +) -> Result(GetCharacterResponse, String) { let query = "query GetCharacter($id: ID!) { character(id: $id) { id name status species type gender } }" - let variables = - json.object([#("id", json.string(id))]) + let variables = json.object([#("id", json.string(id))]) let body = json.object([#("query", json.string(query)), #("variables", variables)]) use req <- result.try( diff --git a/example/src/graphql/get_characters.gleam b/example/src/graphql/get_characters.gleam index f8ff977..abac3be 100644 --- a/example/src/graphql/get_characters.gleam +++ b/example/src/graphql/get_characters.gleam @@ -13,7 +13,10 @@ pub type Characters { } pub fn characters_decoder() -> decode.Decoder(Characters) { - use results <- decode.field("results", decode.optional(decode.list(character_decoder()))) + use results <- decode.field( + "results", + decode.optional(decode.list(character_decoder())), + ) decode.success(Characters(results: results)) } @@ -38,16 +41,22 @@ pub type GetCharactersResponse { GetCharactersResponse(characters: Option(Characters)) } -pub fn get_characters_response_decoder() -> decode.Decoder(GetCharactersResponse) { - use characters <- decode.field("characters", decode.optional(characters_decoder())) +pub fn get_characters_response_decoder() -> decode.Decoder( + GetCharactersResponse, +) { + use characters <- decode.field( + "characters", + decode.optional(characters_decoder()), + ) decode.success(GetCharactersResponse(characters: characters)) } -pub fn get_characters(client: squall.Client) -> Result(GetCharactersResponse, String) { +pub fn get_characters( + client: squall.Client, +) -> Result(GetCharactersResponse, String) { let query = "query GetCharacters { characters { results { id name status species } } }" - let variables = - json.object([]) + let variables = json.object([]) let body = json.object([#("query", json.string(query)), #("variables", variables)]) use req <- result.try( diff --git a/example/src/graphql/multi_query.gleam b/example/src/graphql/multi_query.gleam index 648e3c0..52bead4 100644 --- a/example/src/graphql/multi_query.gleam +++ b/example/src/graphql/multi_query.gleam @@ -14,7 +14,10 @@ pub type Characters { pub fn characters_decoder() -> decode.Decoder(Characters) { use info <- decode.field("info", decode.optional(info_decoder())) - use results <- decode.field("results", decode.optional(decode.list(character_decoder()))) + use results <- decode.field( + "results", + decode.optional(decode.list(character_decoder())), + ) decode.success(Characters(info: info, results: results)) } @@ -63,9 +66,15 @@ pub type MultiQueryResponse { } pub fn multi_query_response_decoder() -> decode.Decoder(MultiQueryResponse) { - use characters <- decode.field("characters", decode.optional(characters_decoder())) + use characters <- decode.field( + "characters", + decode.optional(characters_decoder()), + ) use location <- decode.field("location", decode.optional(location_decoder())) - use episodes_by_ids <- decode.field("episodesByIds", decode.optional(decode.list(episode_decoder()))) + use episodes_by_ids <- decode.field( + "episodesByIds", + decode.optional(decode.list(episode_decoder())), + ) decode.success(MultiQueryResponse( characters: characters, location: location, @@ -76,8 +85,7 @@ pub fn multi_query_response_decoder() -> decode.Decoder(MultiQueryResponse) { pub fn multi_query(client: squall.Client) -> Result(MultiQueryResponse, String) { let query = "query MultiQuery { characters(page: 2, filter: { name: \"rick\" }) { info { count } results { name } } location(id: 1) { id } episodesByIds(ids: [1, 2]) { id } }" - let variables = - json.object([]) + let variables = json.object([]) let body = json.object([#("query", json.string(query)), #("variables", variables)]) use req <- result.try( diff --git a/example/src/graphql/multi_query_with_vars.gleam b/example/src/graphql/multi_query_with_vars.gleam index 2b58c72..7b89248 100644 --- a/example/src/graphql/multi_query_with_vars.gleam +++ b/example/src/graphql/multi_query_with_vars.gleam @@ -14,7 +14,10 @@ pub type Characters { pub fn characters_decoder() -> decode.Decoder(Characters) { use info <- decode.field("info", decode.optional(info_decoder())) - use results <- decode.field("results", decode.optional(decode.list(character_decoder()))) + use results <- decode.field( + "results", + decode.optional(decode.list(character_decoder())), + ) decode.success(Characters(info: info, results: results)) } @@ -64,10 +67,18 @@ pub type MultiQueryWithVarsResponse { ) } -pub fn multi_query_with_vars_response_decoder() -> decode.Decoder(MultiQueryWithVarsResponse) { - use characters <- decode.field("characters", decode.optional(characters_decoder())) +pub fn multi_query_with_vars_response_decoder() -> decode.Decoder( + MultiQueryWithVarsResponse, +) { + use characters <- decode.field( + "characters", + decode.optional(characters_decoder()), + ) use location <- decode.field("location", decode.optional(location_decoder())) - use episodes_by_ids <- decode.field("episodesByIds", decode.optional(decode.list(episode_decoder()))) + use episodes_by_ids <- decode.field( + "episodesByIds", + decode.optional(decode.list(episode_decoder())), + ) decode.success(MultiQueryWithVarsResponse( characters: characters, location: location, @@ -75,18 +86,22 @@ pub fn multi_query_with_vars_response_decoder() -> decode.Decoder(MultiQueryWith )) } -pub fn multi_query_with_vars(client: squall.Client, page: Int, name: String, location_id: String, episode_ids: List(Int)) -> Result(MultiQueryWithVarsResponse, String) { +pub fn multi_query_with_vars( + client: squall.Client, + page: Int, + name: String, + location_id: String, + episode_ids: List(Int), +) -> Result(MultiQueryWithVarsResponse, String) { let query = "query MultiQueryWithVars($page: Int, $name: String, $locationId: ID!, $episodeIds: [Int!]!) { characters(page: $page, filter: { name: $name }) { info { count } results { name } } location(id: $locationId) { id name } episodesByIds(ids: $episodeIds) { id name } }" let variables = - json.object( - [ - #("page", json.int(page)), - #("name", json.string(name)), - #("locationId", json.string(location_id)), - #("episodeIds", json.array(from: episode_ids, of: json.int)), - ], - ) + json.object([ + #("page", json.int(page)), + #("name", json.string(name)), + #("locationId", json.string(location_id)), + #("episodeIds", json.array(from: episode_ids, of: json.int)), + ]) let body = json.object([#("query", json.string(query)), #("variables", variables)]) use req <- result.try( diff --git a/src/squall/internal/codegen.gleam b/src/squall/internal/codegen.gleam index e7e1ab2..fe0db62 100644 --- a/src/squall/internal/codegen.gleam +++ b/src/squall/internal/codegen.gleam @@ -92,10 +92,12 @@ fn block(body: List(Document)) -> Document { /// A pretty printed let assignment. fn let_var(name: String, body: Document) -> Document { - doc.group(doc.concat([ - doc.from_string("let " <> name <> " ="), - doc.nest(doc.concat([doc.line, body]), by: indent), - ])) + doc.group( + doc.concat([ + doc.from_string("let " <> name <> " ="), + doc.nest(doc.concat([doc.line, body]), by: indent), + ]), + ) } /// A pretty printed Gleam string with proper escaping. @@ -121,9 +123,7 @@ fn sanitize_field_name(name: String) -> String { } /// Recursively detect if Option types are used -fn detect_option_usage_in_gleam_type( - gleam_type: type_mapping.GleamType, -) -> Bool { +fn detect_option_usage_in_gleam_type(gleam_type: type_mapping.GleamType) -> Bool { case gleam_type { type_mapping.StringType | type_mapping.IntType @@ -160,7 +160,12 @@ fn detect_option_usage(fields: List(#(String, schema.TypeRef))) -> Bool { let #(_field_name, type_ref) = field // Convert to GleamType (use OutputContext for response types) - case type_mapping.graphql_to_gleam_nullable(type_ref, type_mapping.OutputContext) { + case + type_mapping.graphql_to_gleam_nullable( + type_ref, + type_mapping.OutputContext, + ) + { Ok(gleam_type) -> { let needs_option = detect_option_usage_in_gleam_type(gleam_type) acc || needs_option @@ -177,7 +182,12 @@ fn detect_dynamic_usage(fields: List(#(String, schema.TypeRef))) -> Bool { let #(_field_name, type_ref) = field // Convert to GleamType (use OutputContext for response types) - case type_mapping.graphql_to_gleam_nullable(type_ref, type_mapping.OutputContext) { + case + type_mapping.graphql_to_gleam_nullable( + type_ref, + type_mapping.OutputContext, + ) + { Ok(gleam_type) -> { let needs_dynamic = detect_dynamic_usage_in_gleam_type(gleam_type) acc || needs_dynamic @@ -203,7 +213,11 @@ fn detect_optional_input_fields(input_types: List(InputTypeInfo)) -> Bool { } /// Generate imports section with conditional Option and Dynamic imports -fn imports_doc(needs_option: Bool, needs_dynamic: Bool, needs_option_constructors: Bool) -> Document { +fn imports_doc( + needs_option: Bool, + needs_dynamic: Bool, + needs_option_constructors: Bool, +) -> Document { let core_imports = [ "import gleam/dynamic/decode", "import gleam/http", @@ -299,11 +313,18 @@ pub fn generate_operation( // Generate response decoder let decoder = - generate_decoder_with_schema(response_type_name, field_types, schema_data.types) + generate_decoder_with_schema( + response_type_name, + field_types, + schema_data.types, + ) // Collect Input types from variables let variables = parser.get_variables(operation) - use input_types <- result.try(collect_input_types(variables, schema_data.types)) + use input_types <- result.try(collect_input_types( + variables, + schema_data.types, + )) // Generate Input type definitions and serializers let input_docs = @@ -347,7 +368,8 @@ pub fn generate_operation( let needs_option_constructors = detect_optional_input_fields(input_types) // Build imports - let imports = imports_doc(needs_option, needs_dynamic, needs_option_constructors) + let imports = + imports_doc(needs_option, needs_dynamic, needs_option_constructors) // Combine all code using doc combinators // Order: imports, input types, nested types, response type, response decoder, function @@ -520,7 +542,9 @@ fn collect_input_types_from_type_ref( use input_type <- result.try( dict.get(schema_types, name) |> result.map_error(fn(_) { - error.InvalidSchemaResponse("InputObject type not found: " <> name) + error.InvalidSchemaResponse( + "InputObject type not found: " <> name, + ) }), ) @@ -687,8 +711,7 @@ fn generate_field_decoder_with_schema( type_mapping.CustomType(name) -> { // Check if this is an object type that has a decoder case dict.get(schema_types, name) { - Ok(schema.ObjectType(_, _, _)) -> - snake_case(name) <> "_decoder()" + Ok(schema.ObjectType(_, _, _)) -> snake_case(name) <> "_decoder()" _ -> "decode.dynamic" } } @@ -804,7 +827,9 @@ fn generate_input_serializer(input_info: InputTypeInfo) -> Document { doc.concat([ doc.from_string("{"), doc.line, - doc.from_string(" case " <> param_name <> "." <> sanitized_name <> " {"), + doc.from_string( + " case " <> param_name <> "." <> sanitized_name <> " {", + ), doc.line, doc.from_string(" Some(val) -> Some(#("), string_doc(input_value.name), @@ -993,11 +1018,9 @@ fn generate_function( type_mapping.InputContext, )) let param_name = snake_case(var.name) - Ok( - doc.from_string( - param_name <> ": " <> type_mapping.to_gleam_type_string(gleam_type), - ), - ) + Ok(doc.from_string( + param_name <> ": " <> type_mapping.to_gleam_type_string(gleam_type), + )) }) |> list.filter_map(fn(r) { r }) @@ -1053,10 +1076,14 @@ fn generate_function( let_var( "body", call_doc("json.object", [ - comma_list("[", [ - doc.from_string("#(\"query\", json.string(query))"), - doc.from_string("#(\"variables\", variables)"), - ], "]"), + comma_list( + "[", + [ + doc.from_string("#(\"query\", json.string(query))"), + doc.from_string("#(\"variables\", variables)"), + ], + "]", + ), ]), ), doc.concat([ @@ -1065,7 +1092,9 @@ fn generate_function( doc.line, call_doc("request.to", [doc.from_string("client.endpoint")]), doc.line, - doc.from_string("|> result.map_error(fn(_) { \"Invalid endpoint URL\" }),"), + doc.from_string( + "|> result.map_error(fn(_) { \"Invalid endpoint URL\" }),", + ), ]) |> doc.nest(by: indent), doc.line, @@ -1080,7 +1109,9 @@ fn generate_function( doc.line, doc.from_string("|> request.set_body(json.to_string(body))"), doc.line, - doc.from_string("|> request.set_header(\"content-type\", \"application/json\")"), + doc.from_string( + "|> request.set_header(\"content-type\", \"application/json\")", + ), ]), ), let_var( @@ -1099,7 +1130,9 @@ fn generate_function( doc.line, call_doc("httpc.send", [doc.from_string("req")]), doc.line, - doc.from_string("|> result.map_error(fn(_) { \"HTTP request failed\" }),"), + doc.from_string( + "|> result.map_error(fn(_) { \"HTTP request failed\" }),", + ), ]) |> doc.nest(by: indent), doc.line, @@ -1126,25 +1159,31 @@ fn generate_function( doc.from_string("let data_and_response_decoder = {"), doc.line |> doc.nest(by: indent), doc.concat([ - doc.from_string("use data <- decode.field(\"data\", " <> snake_case(response_type_name) <> "_decoder())"), + doc.from_string( + "use data <- decode.field(\"data\", " + <> snake_case(response_type_name) + <> "_decoder())", + ), doc.line, doc.from_string("decode.success(data)"), - ]) |> doc.nest(by: indent), + ]) + |> doc.nest(by: indent), doc.line, doc.from_string("}"), ]), doc.concat([ doc.from_string("decode.run(json_value, data_and_response_decoder)"), doc.line, - doc.from_string("|> result.map_error(fn(_) { \"Failed to decode response data\" })"), + doc.from_string( + "|> result.map_error(fn(_) { \"Failed to decode response data\" })", + ), ]), ] // Build function signature // Don't use call_doc for return type to prevent it from breaking before parameters - let return_type = doc.from_string( - "Result(" <> response_type_name <> ", String)", - ) + let return_type = + doc.from_string("Result(" <> response_type_name <> ", String)") doc.concat([ doc.from_string("pub fn " <> function_name), @@ -1370,4 +1409,3 @@ fn snake_case(s: String) -> String { } }) } - diff --git a/src/squall/internal/discovery.gleam b/src/squall/internal/discovery.gleam index b556b7f..a7e1622 100644 --- a/src/squall/internal/discovery.gleam +++ b/src/squall/internal/discovery.gleam @@ -17,8 +17,7 @@ pub fn find_graphql_files(root: String) -> Result(List(GraphQLFile), Error) { let gql_files = paths |> list.filter(fn(path) { - string.ends_with(path, ".gql") - && string.contains(path, "/graphql/") + string.ends_with(path, ".gql") && string.contains(path, "/graphql/") }) |> list.sort(string.compare) @@ -88,8 +87,32 @@ fn is_valid_gleam_identifier(name: String) -> Bool { fn is_lowercase_letter(char: String) -> Bool { case char { - "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" -> - True + "a" + | "b" + | "c" + | "d" + | "e" + | "f" + | "g" + | "h" + | "i" + | "j" + | "k" + | "l" + | "m" + | "n" + | "o" + | "p" + | "q" + | "r" + | "s" + | "t" + | "u" + | "v" + | "w" + | "x" + | "y" + | "z" -> True _ -> False } } diff --git a/src/squall/internal/error.gleam b/src/squall/internal/error.gleam index 182dc42..89acf38 100644 --- a/src/squall/internal/error.gleam +++ b/src/squall/internal/error.gleam @@ -33,7 +33,8 @@ pub fn to_string(error: Error) -> String { SchemaIntrospectionFailed(reason) -> "Schema introspection failed: " <> reason InvalidSchemaResponse(reason) -> "Invalid schema response: " <> reason - CannotReadFile(file, reason) -> "Cannot read file " <> file <> ": " <> reason + CannotReadFile(file, reason) -> + "Cannot read file " <> file <> ": " <> reason CannotWriteToFile(file, reason) -> "Cannot write to file " <> file <> ": " <> reason InvalidGraphQLSyntax(file, line, message) -> @@ -44,12 +45,7 @@ pub fn to_string(error: Error) -> String { <> ": " <> message InvalidOperationName(file, name, reason) -> - "Invalid operation name '" - <> name - <> "' in " - <> file - <> ": " - <> reason + "Invalid operation name '" <> name <> "' in " <> file <> ": " <> reason UnsupportedGraphQLType(file, type_name) -> "Unsupported GraphQL type '" <> type_name <> "' in " <> file InvalidTypeMapping(reason) -> "Invalid type mapping: " <> reason diff --git a/src/squall/internal/parser.gleam b/src/squall/internal/parser.gleam index 91ec534..ccba981 100644 --- a/src/squall/internal/parser.gleam +++ b/src/squall/internal/parser.gleam @@ -262,14 +262,16 @@ fn read_string( col: Int, ) -> Result(#(String, String, Int), Error) { case string.pop_grapheme(source) { - Error(_) -> Error(error.InvalidGraphQLSyntax("string", 0, "Unterminated string")) + Error(_) -> + Error(error.InvalidGraphQLSyntax("string", 0, "Unterminated string")) Ok(#("\"", rest)) -> Ok(#(acc, rest, col + 1)) Ok(#("\\", rest)) -> { case string.pop_grapheme(rest) { Ok(#(escaped, rest2)) -> { read_string(rest2, acc <> escaped, col + 2) } - Error(_) -> Error(error.InvalidGraphQLSyntax("string", 0, "Unterminated string")) + Error(_) -> + Error(error.InvalidGraphQLSyntax("string", 0, "Unterminated string")) } } Ok(#(char, rest)) -> read_string(rest, acc <> char, col + 1) @@ -280,7 +282,11 @@ fn read_name(source: String, col: Int) -> #(String, String, Int) { read_name_helper(source, "", col) } -fn read_name_helper(source: String, acc: String, col: Int) -> #(String, String, Int) { +fn read_name_helper( + source: String, + acc: String, + col: Int, +) -> #(String, String, Int) { case string.pop_grapheme(source) { Error(_) -> #(acc, "", col) Ok(#(char, rest)) -> { @@ -299,7 +305,11 @@ fn read_number( ) -> Result(#(Token, String, Int), Error) { let #(num_str, rest, new_col) = read_number_helper(source, "", col) - case string.contains(num_str, ".") || string.contains(num_str, "e") || string.contains(num_str, "E") { + case + string.contains(num_str, ".") + || string.contains(num_str, "e") + || string.contains(num_str, "E") + { True -> { // Try to parse as float case try_parse_float(num_str) { @@ -351,11 +361,21 @@ fn try_parse_float(s: String) -> Result(Float, Nil) { } } -fn read_number_helper(source: String, acc: String, col: Int) -> #(String, String, Int) { +fn read_number_helper( + source: String, + acc: String, + col: Int, +) -> #(String, String, Int) { case string.pop_grapheme(source) { Error(_) -> #(acc, "", col) Ok(#(char, rest)) -> { - case is_digit(char) || char == "." || char == "-" || char == "e" || char == "E" { + case + is_digit(char) + || char == "." + || char == "-" + || char == "e" + || char == "E" + { True -> read_number_helper(rest, acc <> char, col + 1) False -> #(acc, char <> rest, col) } @@ -365,8 +385,58 @@ fn read_number_helper(source: String, acc: String, col: Int) -> #(String, String fn is_alpha(char: String) -> Bool { case char { - "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" -> - True + "a" + | "b" + | "c" + | "d" + | "e" + | "f" + | "g" + | "h" + | "i" + | "j" + | "k" + | "l" + | "m" + | "n" + | "o" + | "p" + | "q" + | "r" + | "s" + | "t" + | "u" + | "v" + | "w" + | "x" + | "y" + | "z" + | "A" + | "B" + | "C" + | "D" + | "E" + | "F" + | "G" + | "H" + | "I" + | "J" + | "K" + | "L" + | "M" + | "N" + | "O" + | "P" + | "Q" + | "R" + | "S" + | "T" + | "U" + | "V" + | "W" + | "X" + | "Y" + | "Z" -> True _ -> False } } @@ -711,7 +781,8 @@ fn parse_name(state: ParserState) -> Result(#(String, ParserState), Error) { fn peek_token(state: ParserState) -> Result(TokenPosition, Error) { case list.drop(state.tokens, state.position) { [token, ..] -> Ok(token) - [] -> Error(error.InvalidGraphQLSyntax("parser", 0, "Unexpected end of input")) + [] -> + Error(error.InvalidGraphQLSyntax("parser", 0, "Unexpected end of input")) } } diff --git a/src/squall/internal/schema.gleam b/src/squall/internal/schema.gleam index fdd971a..1a27b63 100644 --- a/src/squall/internal/schema.gleam +++ b/src/squall/internal/schema.gleam @@ -51,11 +51,7 @@ pub type Type { possible_types: List(String), description: Option(String), ) - EnumType( - name: String, - enum_values: List(String), - description: Option(String), - ) + EnumType(name: String, enum_values: List(String), description: Option(String)) InputObjectType( name: String, input_fields: List(InputValue), @@ -139,7 +135,9 @@ fn decode_schema(dyn: Dynamic) -> Result(Schema, Error) { } // Parse optional subscription type - let subscription_type = case field(schema_obj, "subscriptionType", decode.dynamic) { + let subscription_type = case + field(schema_obj, "subscriptionType", decode.dynamic) + { Ok(st) -> optional_field(st, "name", decode.string) Error(_) -> None } @@ -197,7 +195,9 @@ fn decode_type(dyn: Dynamic) -> Result(Type, Error) { } "UNION" -> { - let possible_types = case field(dyn, "possibleTypes", decode.list(of: decode.dynamic)) { + let possible_types = case + field(dyn, "possibleTypes", decode.list(of: decode.dynamic)) + { Ok(types_dyn) -> { list.try_map(types_dyn, fn(d) { field(d, "name", decode.string) @@ -212,7 +212,9 @@ fn decode_type(dyn: Dynamic) -> Result(Type, Error) { } "ENUM" -> { - let enum_values = case field(dyn, "enumValues", decode.list(of: decode.dynamic)) { + let enum_values = case + field(dyn, "enumValues", decode.list(of: decode.dynamic)) + { Ok(values_dyn) -> { list.try_map(values_dyn, fn(d) { field(d, "name", decode.string) @@ -227,7 +229,9 @@ fn decode_type(dyn: Dynamic) -> Result(Type, Error) { } "INPUT_OBJECT" -> { - let input_fields = case field(dyn, "inputFields", decode.list(of: decode.dynamic)) { + let input_fields = case + field(dyn, "inputFields", decode.list(of: decode.dynamic)) + { Ok(fields_dyn) -> { list.try_map(fields_dyn, decode_input_value) |> result.unwrap([]) diff --git a/src/squall/internal/type_mapping.gleam b/src/squall/internal/type_mapping.gleam index 6787a91..6b3c551 100644 --- a/src/squall/internal/type_mapping.gleam +++ b/src/squall/internal/type_mapping.gleam @@ -71,7 +71,10 @@ fn map_named_type( } // Map scalar types -fn map_scalar_type(name: String, context: TypeContext) -> Result(GleamType, Error) { +fn map_scalar_type( + name: String, + context: TypeContext, +) -> Result(GleamType, Error) { case name { "String" -> Ok(StringType) "Int" -> Ok(IntType) diff --git a/test/codegen_test.gleam b/test/codegen_test.gleam index c08e868..5dfb783 100644 --- a/test/codegen_test.gleam +++ b/test/codegen_test.gleam @@ -556,10 +556,9 @@ pub fn generate_inline_array_arguments_test() { [ schema.InputValue( "ids", - schema.ListType(schema.NonNullType(schema.NamedType( - "Int", - schema.Scalar, - ))), + schema.ListType( + schema.NonNullType(schema.NamedType("Int", schema.Scalar)), + ), None, ), ], @@ -617,12 +616,7 @@ pub fn generate_multiple_root_fields_test() { ] let characters_result_fields = [ - schema.Field( - "info", - schema.NamedType("Info", schema.Object), - [], - None, - ), + schema.Field("info", schema.NamedType("Info", schema.Object), [], None), schema.Field( "results", schema.ListType(schema.NamedType("Character", schema.Object)), @@ -693,10 +687,9 @@ pub fn generate_multiple_root_fields_test() { [ schema.InputValue( "ids", - schema.ListType(schema.NonNullType(schema.NamedType( - "Int", - schema.Scalar, - ))), + schema.ListType( + schema.NonNullType(schema.NamedType("Int", schema.Scalar)), + ), None, ), ], @@ -715,7 +708,9 @@ pub fn generate_multiple_root_fields_test() { case result { Ok(code) -> { code - |> birdie.snap(title: "Query with multiple root fields and mixed arguments") + |> birdie.snap( + title: "Query with multiple root fields and mixed arguments", + ) } Error(_) -> Nil } @@ -855,10 +850,9 @@ pub fn generate_mutation_with_nested_input_object_test() { ), schema.InputValue( "interests", - schema.ListType(schema.NonNullType(schema.NamedType( - "String", - schema.Scalar, - ))), + schema.ListType( + schema.NonNullType(schema.NamedType("String", schema.Scalar)), + ), None, ), ] @@ -1000,7 +994,9 @@ pub fn generate_query_with_all_non_nullable_fields_test() { case result { Ok(code) -> { code - |> birdie.snap(title: "Query with all non-nullable fields (no Option import)") + |> birdie.snap( + title: "Query with all non-nullable fields (no Option import)", + ) } Error(_) -> Nil } @@ -1091,11 +1087,7 @@ pub fn generate_mutation_with_json_input_field_test() { // Define InputObject type with JSON field let settings_input_fields = [ - schema.InputValue( - "metadata", - schema.NamedType("JSON", schema.Scalar), - None, - ), + schema.InputValue("metadata", schema.NamedType("JSON", schema.Scalar), None), schema.InputValue( "displayName", schema.NamedType("String", schema.Scalar), @@ -1110,12 +1102,7 @@ pub fn generate_mutation_with_json_input_field_test() { [], None, ), - schema.Field( - "metadata", - schema.NamedType("JSON", schema.Scalar), - [], - None, - ), + schema.Field("metadata", schema.NamedType("JSON", schema.Scalar), [], None), ] let mock_schema = @@ -1195,11 +1182,7 @@ pub fn generate_mutation_with_optional_input_fields_test() { schema.NamedType("String", schema.Scalar), None, ), - schema.InputValue( - "avatar", - schema.NamedType("JSON", schema.Scalar), - None, - ), + schema.InputValue("avatar", schema.NamedType("JSON", schema.Scalar), None), ] let profile_fields = [ diff --git a/test/type_mapping_test.gleam b/test/type_mapping_test.gleam index dce26ed..16e8bf5 100644 --- a/test/type_mapping_test.gleam +++ b/test/type_mapping_test.gleam @@ -7,7 +7,8 @@ import squall/internal/type_mapping // Test: Map GraphQL String to Gleam String pub fn map_string_type_test() { let graphql_type = schema.NamedType("String", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -19,7 +20,8 @@ pub fn map_string_type_test() { // Test: Map GraphQL Int to Gleam Int pub fn map_int_type_test() { let graphql_type = schema.NamedType("Int", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -31,7 +33,8 @@ pub fn map_int_type_test() { // Test: Map GraphQL Float to Gleam Float pub fn map_float_type_test() { let graphql_type = schema.NamedType("Float", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -43,7 +46,8 @@ pub fn map_float_type_test() { // Test: Map GraphQL Boolean to Gleam Bool pub fn map_boolean_type_test() { let graphql_type = schema.NamedType("Boolean", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -55,7 +59,8 @@ pub fn map_boolean_type_test() { // Test: Map GraphQL ID to Gleam String pub fn map_id_type_test() { let graphql_type = schema.NamedType("ID", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -67,7 +72,11 @@ pub fn map_id_type_test() { // Test: Map nullable String to Option(String) pub fn map_nullable_string_test() { let graphql_type = schema.NamedType("String", schema.Scalar) - let result = type_mapping.graphql_to_gleam_nullable(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam_nullable( + graphql_type, + type_mapping.OutputContext, + ) should.be_ok(result) let assert Ok(gleam_type) = result @@ -80,7 +89,8 @@ pub fn map_nullable_string_test() { pub fn map_non_null_string_test() { let inner = schema.NamedType("String", schema.Scalar) let graphql_type = schema.NonNullType(inner) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -96,7 +106,8 @@ pub fn map_non_null_string_test() { pub fn map_list_of_strings_test() { let inner = schema.NamedType("String", schema.Scalar) let graphql_type = schema.ListType(inner) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -112,7 +123,8 @@ pub fn map_non_null_list_non_null_strings_test() { let list_type = schema.ListType(non_null_string) let graphql_type = schema.NonNullType(list_type) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -124,7 +136,8 @@ pub fn map_non_null_list_non_null_strings_test() { // Test: Map custom object type pub fn map_custom_object_type_test() { let graphql_type = schema.NamedType("Character", schema.Object) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -153,7 +166,8 @@ pub fn parse_variable_type_test() { // Test: Unsupported custom scalar pub fn unsupported_scalar_test() { let graphql_type = schema.NamedType("DateTime", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) // Should map unknown scalars to String by default should.be_ok(result) @@ -162,7 +176,8 @@ pub fn unsupported_scalar_test() { // Test: Map GraphQL JSON scalar to Gleam Dynamic (OutputContext) pub fn map_json_type_output_test() { let graphql_type = schema.NamedType("JSON", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -174,7 +189,8 @@ pub fn map_json_type_output_test() { // Test: Map GraphQL JSON scalar to Gleam json.Json (InputContext) pub fn map_json_type_input_test() { let graphql_type = schema.NamedType("JSON", schema.Scalar) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.InputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.InputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -186,7 +202,11 @@ pub fn map_json_type_input_test() { // Test: Map nullable JSON to Option(Dynamic) (OutputContext) pub fn map_nullable_json_output_test() { let graphql_type = schema.NamedType("JSON", schema.Scalar) - let result = type_mapping.graphql_to_gleam_nullable(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam_nullable( + graphql_type, + type_mapping.OutputContext, + ) should.be_ok(result) let assert Ok(gleam_type) = result @@ -198,7 +218,11 @@ pub fn map_nullable_json_output_test() { // Test: Map nullable JSON to Option(json.Json) (InputContext) pub fn map_nullable_json_input_test() { let graphql_type = schema.NamedType("JSON", schema.Scalar) - let result = type_mapping.graphql_to_gleam_nullable(graphql_type, type_mapping.InputContext) + let result = + type_mapping.graphql_to_gleam_nullable( + graphql_type, + type_mapping.InputContext, + ) should.be_ok(result) let assert Ok(gleam_type) = result @@ -220,7 +244,8 @@ pub fn map_nullable_json_input_test() { pub fn map_non_null_json_output_test() { let inner = schema.NamedType("JSON", schema.Scalar) let graphql_type = schema.NonNullType(inner) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.OutputContext) should.be_ok(result) let assert Ok(gleam_type) = result @@ -236,7 +261,8 @@ pub fn map_non_null_json_output_test() { pub fn map_non_null_json_input_test() { let inner = schema.NamedType("JSON", schema.Scalar) let graphql_type = schema.NonNullType(inner) - let result = type_mapping.graphql_to_gleam(graphql_type, type_mapping.InputContext) + let result = + type_mapping.graphql_to_gleam(graphql_type, type_mapping.InputContext) should.be_ok(result) let assert Ok(gleam_type) = result