Skip to content

Commit

Permalink
Handle unions, intersections and lists when generating sample GQL (#49)
Browse files Browse the repository at this point in the history
* Add mutation with union return type to schema.json

* Handle union type returns in OperationDetailsHelper

* Handle union types in printing of sample GQL

* Add interface return types to operation details

* Handle interface return types when providing GQL samples in markdown

* Handle simple list return

* Handle non-null list of objects as a return value

* Bump version to 0.3.1

* Update CHANGELOG.md to mark retired version

Co-authored-by: E. Sambo <[email protected]>

* Add link to this MR in changelog note

* Add colon before link to MR

* Use Fixed as header for the changes in this MR

---------

Co-authored-by: Clifton McIntosh <[email protected]>
Co-authored-by: E. Sambo <[email protected]>
  • Loading branch information
3 people authored Jul 2, 2024
1 parent e578197 commit 1f604f1
Show file tree
Hide file tree
Showing 6 changed files with 896 additions and 7 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## 0.3.0 - 2024-06-25
## 0.3.1 - 2024-07-01

### Fixed

* Fix problems with generating example queries and mutations when the return types are unions, interfaces or lists: [#49](https://github.com/podium/graphql_markdown/pull/49)

## 0.3.0 - 2024-06-25 [RETIRED]

### Added

Expand Down
55 changes: 54 additions & 1 deletion lib/graphql_markdown/markdown_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ defmodule GraphqlMarkdown.MarkdownHelpers do
@spec returned_fields(OperationDetailsHelpers.return_type()) :: String.t()
defp returned_fields(%{kind: "SCALAR"}), do: ""

defp returned_fields(%{kind: "OBJECT"} = return_type) do
defp returned_fields(%{kind: kind} = return_type) when kind in ~w(OBJECT LIST) do
fields = Map.get(return_type, :fields, [])

return_values =
Expand All @@ -192,4 +192,57 @@ defmodule GraphqlMarkdown.MarkdownHelpers do
_ -> ""
end
end

defp returned_fields(%{kind: "UNION"} = return_type) do
possible_types = Map.get(return_type, :possible_types, [])

return_values =
for possible_type <- possible_types do
"... on #{possible_type.name} {\n }"
end

case return_values do
[_ | _] ->
"\n __typename\n " <> Enum.join(return_values, "\n ")

_ ->
""
end
end

defp returned_fields(%{kind: "INTERFACE"} = return_type) do
fields = Map.get(return_type, :fields, [])
possible_types = Map.get(return_type, :possible_types, [])

interface_fields =
for field <- fields do
if field.type == "OBJECT" do
"#{field.name} {\n }"
else
field.name
end
end

shared_fields_string =
case interface_fields do
[_ | _] -> "\n " <> Enum.join(interface_fields, "\n ")
_ -> ""
end

specific_types =
for possible_type <- possible_types do
"... on #{possible_type.name} {\n }"
end

specific_types_string =
case specific_types do
[_ | _] ->
"\n " <> Enum.join(specific_types, "\n ")

_ ->
""
end

shared_fields_string <> specific_types_string
end
end
103 changes: 102 additions & 1 deletion lib/graphql_markdown/operation_details_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ defmodule GraphqlMarkdown.OperationDetailsHelpers do
@type return_type :: %{
name: String.t(),
kind: String.t(),
fields: [field()]
fields: [field()],
possible_types: [field()]
}

@type graphql_operation_details :: %{
Expand Down Expand Up @@ -89,6 +90,106 @@ defmodule GraphqlMarkdown.OperationDetailsHelpers do
}
end

defp return_fields(%{"name" => name, "kind" => "UNION"}, schema_details) do
possible_types =
schema_details
|> Map.get(:unions, [])
|> Enum.find(fn union -> union["name"] == name end)
|> Map.get("possibleTypes", [])
|> Enum.map(fn field ->
name = field["name"]
%{name: name, type: "OBJECT"}
end)

%{
name: name,
kind: "UNION",
possible_types: possible_types
}
end

defp return_fields(%{"name" => name, "kind" => "INTERFACE"}, schema_details) do
interface_fields =
schema_details
|> Map.get(:interfaces, [])
|> Enum.find(fn x -> x["name"] == name end)
|> Map.get("fields", [])
|> Enum.map(fn field ->
field_name = field["name"]
type = return_field_type(field)
%{name: field_name, type: type}
end)

possible_types =
schema_details
|> Map.get(:interfaces, [])
|> Enum.find(fn interface -> interface["name"] == name end)
|> Map.get("possibleTypes", [])
|> Enum.map(fn field ->
name = field["name"]
%{name: name, type: "OBJECT"}
end)

%{
name: name,
kind: "INTERFACE",
fields: interface_fields,
possible_types: possible_types
}
end

defp return_fields(
%{"name" => name, "kind" => "LIST", "ofType" => %{"kind" => "OBJECT"}} = return_field,
schema_details
) do
name_of_list_type = get_in(return_field, ["ofType", "name"])

fields =
schema_details
|> Map.get(:objects, [])
|> Enum.find(fn object -> object["name"] == name_of_list_type end)
|> Map.get("fields", [])
|> Enum.map(fn field ->
field_name = field["name"]
type = return_field_type(field)
%{name: field_name, type: type}
end)

%{
name: name,
kind: "LIST",
fields: fields
}
end

defp return_fields(
%{
"name" => name,
"kind" => "NON_NULL",
"ofType" => %{"kind" => "LIST", "ofType" => %{"kind" => "OBJECT"}}
} = return_field,
schema_details
) do
name_of_list_type = get_in(return_field, ["ofType", "ofType", "name"])

fields =
schema_details
|> Map.get(:objects, [])
|> Enum.find(fn object -> object["name"] == name_of_list_type end)
|> Map.get("fields", [])
|> Enum.map(fn field ->
field_name = field["name"]
type = return_field_type(field)
%{name: field_name, type: type}
end)

%{
name: name,
kind: "LIST",
fields: fields
}
end

defp return_fields(return_type, _schema_details) do
%{
name: return_type["name"],
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule GraphqlMarkdown.MixProject do
use Mix.Project

@project_url "https://github.com/podium/graphql_markdown"
@version "0.3.0"
@version "0.3.1"

def project do
[
Expand Down
Loading

0 comments on commit 1f604f1

Please sign in to comment.