Skip to content

Commit 4d22224

Browse files
author
jarrod
committed
fix: render default values in SDL output for schema.sdl task
Previously, the `mix absinthe.schema.sdl` task would not include default values for arguments and input object fields in the generated SDL output, even though the schema.json task included them in its output. Changes: - Modified SDL renderer to handle default values for InputValueDefinition (arguments) and FieldDefinition (input object fields) - Added support for DSL-defined schemas where default_value is an Elixir term that needs conversion to Blueprint.Input structures - Added support for SDL-parsed schemas where default_value_blueprint is already a Blueprint structure - Skip non-serializable values (refs, functions) Tests: - Added DefaultValueTestSchema with default value coverage to prevent regression while rendering boolean, string, and input object default values - All existing tests updated to expect default values in output
1 parent a035261 commit 4d22224

File tree

4 files changed

+130
-7
lines changed

4 files changed

+130
-7
lines changed

lib/absinthe/schema/notation/sdl_render.ex

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ defmodule Absinthe.Schema.Notation.SDL.Render do
7070
string(@adapter.to_external_name(input_value.name, :argument)),
7171
": ",
7272
render(input_value.type, type_definitions),
73-
default(input_value.default_value_blueprint),
73+
default(input_value),
7474
directives(input_value.directives, type_definitions)
7575
])
7676
|> description(input_value.description)
@@ -107,7 +107,7 @@ defmodule Absinthe.Schema.Notation.SDL.Render do
107107
string(input_object_type.name),
108108
directives(input_object_type.directives, type_definitions)
109109
]),
110-
render_list(input_object_type.fields, type_definitions)
110+
render_input_fields(input_object_type.fields, type_definitions)
111111
)
112112
|> description(input_object_type.description)
113113
end
@@ -306,12 +306,54 @@ defmodule Absinthe.Schema.Notation.SDL.Render do
306306
)
307307
end
308308

309-
defp default(nil) do
309+
defp default(%Blueprint.Schema.FieldDefinition{default_value: nil}) do
310310
empty()
311311
end
312312

313-
defp default(default_value) do
314-
concat([" = ", render_value(default_value)])
313+
defp default(%Blueprint.Schema.FieldDefinition{default_value: {:ref, _, _}}) do
314+
empty()
315+
end
316+
317+
defp default(%Blueprint.Schema.FieldDefinition{default_value: default_value})
318+
when is_atom(default_value) or is_binary(default_value) or is_number(default_value) or
319+
is_boolean(default_value) or is_list(default_value) or is_map(default_value) do
320+
try do
321+
blueprint_value = Blueprint.Input.parse(default_value)
322+
concat([" = ", render_value(blueprint_value)])
323+
rescue
324+
_ -> empty()
325+
end
326+
end
327+
328+
defp default(%Blueprint.Schema.FieldDefinition{}) do
329+
empty()
330+
end
331+
332+
defp default(%Blueprint.Schema.InputValueDefinition{
333+
default_value_blueprint: nil,
334+
default_value: nil
335+
}) do
336+
empty()
337+
end
338+
339+
defp default(%Blueprint.Schema.InputValueDefinition{
340+
default_value_blueprint: nil,
341+
default_value: default_value
342+
})
343+
when not is_nil(default_value) do
344+
blueprint_value = Blueprint.Input.parse(default_value)
345+
concat([" = ", render_value(blueprint_value)])
346+
end
347+
348+
defp default(%Blueprint.Schema.InputValueDefinition{
349+
default_value_blueprint: default_value_blueprint
350+
})
351+
when not is_nil(default_value_blueprint) do
352+
concat([" = ", render_value(default_value_blueprint)])
353+
end
354+
355+
defp default(_) do
356+
empty()
315357
end
316358

317359
defp description(docs, nil) do
@@ -356,6 +398,47 @@ defmodule Absinthe.Schema.Notation.SDL.Render do
356398

357399
# Render Helpers
358400

401+
defp render_input_fields(fields, type_definitions) do
402+
items = Enum.reject(fields, &(&1.module in @skip_modules))
403+
404+
splitter =
405+
items
406+
|> Enum.any?(&(&1.description not in ["", nil]))
407+
|> case do
408+
true -> [nest(line(), :reset), line()]
409+
false -> [line()]
410+
end
411+
412+
items
413+
|> Enum.reverse()
414+
|> Enum.reduce(:start, fn
415+
item, :start -> render_input_field(item, type_definitions)
416+
item, acc -> concat([render_input_field(item, type_definitions)] ++ splitter ++ [acc])
417+
end)
418+
end
419+
420+
defp render_input_field(%Blueprint.Schema.FieldDefinition{} = field, type_definitions) do
421+
concat([
422+
string(@adapter.to_external_name(field.name, :field)),
423+
": ",
424+
render(field.type, type_definitions),
425+
default(field),
426+
directives(field.directives, type_definitions)
427+
])
428+
|> description(field.description)
429+
end
430+
431+
defp render_input_field(%Blueprint.Schema.InputValueDefinition{} = field, type_definitions) do
432+
concat([
433+
string(@adapter.to_external_name(field.name, :argument)),
434+
": ",
435+
render(field.type, type_definitions),
436+
default(field),
437+
directives(field.directives, type_definitions)
438+
])
439+
|> description(field.description)
440+
end
441+
359442
defp render_list(items, type_definitions, separator \\ line())
360443

361444
# Workaround for `values` macro which temporarily defines

test/absinthe/schema/sdl_render_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ defmodule Absinthe.Schema.SdlRenderTest do
275275
type RootQueryType {
276276
echo(
277277
\"The number of times\"
278-
times: Int
278+
times: Int = 10
279279
280280
timeInterval: Int
281281
): String

test/absinthe/schema/type_system_directive_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ defmodule Absinthe.Schema.TypeSystemDirectiveTest do
225225
}
226226
227227
input SearchFilter @feature(name: \":input_object\") {
228-
query: String @feature(name: \":input_field_definition\")
228+
query: String = "default" @feature(name: \":input_field_definition\")
229229
}
230230
231231
union SearchResult @feature(name: \":union\") = Dog | Post

test/mix/tasks/absinthe.schema.sdl_test.exs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,35 @@ defmodule Mix.Tasks.Absinthe.Schema.SdlTest do
123123
end
124124
end
125125

126+
defmodule DefaultValueTestSchema do
127+
use Absinthe.Schema
128+
129+
query do
130+
field :item, :string do
131+
arg :show, :boolean, default_value: true
132+
end
133+
134+
field :search, :string do
135+
arg :filters, :filters, default_value: %{query: "mystring"}
136+
end
137+
end
138+
139+
mutation do
140+
field :create_item, :string do
141+
arg :input, non_null(:test_input)
142+
arg :other, :string, default_value: "other"
143+
end
144+
end
145+
146+
input_object :filters do
147+
field :query, :string
148+
end
149+
150+
input_object :test_input do
151+
field :value, non_null(:string), default_value: "test"
152+
end
153+
end
154+
126155
@test_mod_schema "Mix.Tasks.Absinthe.Schema.SdlTest.TestSchemaWithMods"
127156

128157
setup_all do
@@ -193,5 +222,16 @@ defmodule Mix.Tasks.Absinthe.Schema.SdlTest do
193222

194223
assert File.exists?(path)
195224
end
225+
226+
test "with default values" do
227+
argv = ["output.graphql", "--schema", "#{DefaultValueTestSchema}"]
228+
opts = Task.parse_options(argv)
229+
230+
{:ok, schema} = Task.generate_schema(opts)
231+
assert schema =~ "value: String! = \"test\""
232+
assert schema =~ "other: String = \"other\""
233+
assert schema =~ "show: Boolean = true"
234+
assert schema =~ "filters: Filters = {query: \"mystring\"}"
235+
end
196236
end
197237
end

0 commit comments

Comments
 (0)