mirror of
https://github.com/ash-project/ash_graphql.git
synced 2024-09-19 12:53:40 +12:00
improvement: add schema codegen features & guide
This commit is contained in:
parent
1b9722a1fb
commit
3d1babb9f1
13 changed files with 6473 additions and 7 deletions
27
documentation/topics/sdl-file.md
Normal file
27
documentation/topics/sdl-file.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Using the SDL File
|
||||||
|
|
||||||
|
By passing the `generate_sdl_file` to `use AshGraphql.Schema`, AshGraphql will generate
|
||||||
|
a schema file when you run `mix ash.codegen`.
|
||||||
|
|
||||||
|
> ### Ensure your schema is up to date, gitignored, or not generated {: .info}
|
||||||
|
>
|
||||||
|
> We suggest first adding `mix ash.codegen --check` to your CI/CD pipeline to
|
||||||
|
> ensure the schema is always up-to-date. Alternatively you can add the file
|
||||||
|
> to your `.gitignore`, or you can remove the `generate_sdl_file` option to skip
|
||||||
|
> generating the file.
|
||||||
|
|
||||||
|
Some things that you can use this SDL file for:
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The schema file itself represents your entire GraphQL API definition, and examining it can be very useful.
|
||||||
|
|
||||||
|
## Code Generation
|
||||||
|
|
||||||
|
You can use tools like [GraphQL codegen](https://the-guild.dev/graphql/codegen) to generate a client
|
||||||
|
for your GraphQL API.
|
||||||
|
|
||||||
|
## Validating Changes
|
||||||
|
|
||||||
|
Use the SDL file to check for breaking changes in your schema, especially if you are exposing a public API.
|
||||||
|
A plug and play github action for this can be found here: https://the-guild.dev/graphql/inspector/docs/products/action
|
|
@ -29,7 +29,11 @@ end
|
||||||
|
|
||||||
#### Setting up your schema
|
#### Setting up your schema
|
||||||
|
|
||||||
If you don't have an absinthe schema, you can create one just for ash. Replace `helpdesk` in the examples with your own application name.
|
If you don't have an absinthe schema, you can create one just for ash.
|
||||||
|
Replace `helpdesk` in the examples with your own application name.
|
||||||
|
|
||||||
|
See [the SDL file guide](/documentation/topics/sdl-file.md) for more information on using the SDL file,
|
||||||
|
or remove the `generate_sdl_file` option to skip generating it on calls to `mix ash.codegen`.
|
||||||
|
|
||||||
in `lib/helpdesk/schema.ex`
|
in `lib/helpdesk/schema.ex`
|
||||||
|
|
||||||
|
@ -38,7 +42,9 @@ defmodule Helpdesk.GraphqlSchema do
|
||||||
use Absinthe.Schema
|
use Absinthe.Schema
|
||||||
|
|
||||||
# Add your domains here
|
# Add your domains here
|
||||||
use AshGraphql, domains: [Your.Domains]
|
use AshGraphql,
|
||||||
|
domains: [Your.Domains],
|
||||||
|
generate_sdl_file: "priv/schema.graphql"
|
||||||
|
|
||||||
query do
|
query do
|
||||||
# Custom absinthe queries can be placed here
|
# Custom absinthe queries can be placed here
|
||||||
|
@ -56,7 +62,6 @@ defmodule Helpdesk.GraphqlSchema do
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Connect your schema
|
#### Connect your schema
|
||||||
|
|
||||||
##### Using Phoenix
|
##### Using Phoenix
|
||||||
|
|
|
@ -44,6 +44,7 @@ defmodule AshGraphql do
|
||||||
quote bind_quoted: [
|
quote bind_quoted: [
|
||||||
domains: opts[:domains],
|
domains: opts[:domains],
|
||||||
domain: opts[:domain],
|
domain: opts[:domain],
|
||||||
|
generate_sdl_file: opts[:generate_sdl_file],
|
||||||
action_middleware: opts[:action_middleware] || [],
|
action_middleware: opts[:action_middleware] || [],
|
||||||
define_relay_types?: Keyword.get(opts, :define_relay_types?, true),
|
define_relay_types?: Keyword.get(opts, :define_relay_types?, true),
|
||||||
relay_ids?: Keyword.get(opts, :relay_ids?, false),
|
relay_ids?: Keyword.get(opts, :relay_ids?, false),
|
||||||
|
@ -98,6 +99,16 @@ defmodule AshGraphql do
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|> List.update_at(0, fn {domain, resources, _} -> {domain, resources, true} end)
|
|> List.update_at(0, fn {domain, resources, _} -> {domain, resources, true} end)
|
||||||
|
|
||||||
|
@generate_sdl_file generate_sdl_file
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def generate_sdl_file do
|
||||||
|
@generate_sdl_file
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def ash_graphql_schema?, do: true
|
||||||
|
|
||||||
@ash_resources Enum.flat_map(domains, &elem(&1, 1))
|
@ash_resources Enum.flat_map(domains, &elem(&1, 1))
|
||||||
ash_resources = @ash_resources
|
ash_resources = @ash_resources
|
||||||
@all_domains Enum.map(domains, &elem(&1, 0))
|
@all_domains Enum.map(domains, &elem(&1, 0))
|
||||||
|
|
92
lib/codegen.ex
Normal file
92
lib/codegen.ex
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
defmodule AshGraphql.Codegen do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
def generate_sdl_file(schema, opts) do
|
||||||
|
target = schema.generate_sdl_file()
|
||||||
|
|
||||||
|
case Mix.Tasks.Absinthe.Schema.Sdl.generate_schema(%Mix.Tasks.Absinthe.Schema.Sdl.Options{
|
||||||
|
schema: schema,
|
||||||
|
filename: target
|
||||||
|
}) do
|
||||||
|
{:ok, contents} ->
|
||||||
|
if opts[:check?] do
|
||||||
|
target_contents = File.read!(target)
|
||||||
|
|
||||||
|
if String.trim(target_contents) != String.trim(contents) do
|
||||||
|
raise "Generated SDL file for #{} does not match existing file. Please run `mix ash.codegen` to generate the new file."
|
||||||
|
end
|
||||||
|
else
|
||||||
|
File.write!(target, contents)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def schemas do
|
||||||
|
apps =
|
||||||
|
if Code.ensure_loaded?(Mix.Project) do
|
||||||
|
if apps_paths = Mix.Project.apps_paths() do
|
||||||
|
apps_paths |> Map.keys() |> Enum.sort()
|
||||||
|
else
|
||||||
|
[Mix.Project.config()[:app]]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
apps()
|
||||||
|
|> Stream.concat(apps)
|
||||||
|
|> Stream.uniq()
|
||||||
|
|> Task.async_stream(
|
||||||
|
fn app ->
|
||||||
|
app
|
||||||
|
|> :application.get_key(:modules)
|
||||||
|
|> case do
|
||||||
|
:undefined ->
|
||||||
|
[]
|
||||||
|
|
||||||
|
{_, mods} ->
|
||||||
|
mods
|
||||||
|
|> List.wrap()
|
||||||
|
|> Enum.filter(&ash_graphql_schema?/1)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
timeout: :infinity
|
||||||
|
)
|
||||||
|
|> Stream.map(&elem(&1, 1))
|
||||||
|
|> Stream.flat_map(& &1)
|
||||||
|
|> Stream.uniq()
|
||||||
|
|> Enum.to_list()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp ash_graphql_schema?(module) do
|
||||||
|
Code.ensure_compiled!(module)
|
||||||
|
function_exported?(module, :ash_graphql_schema?, 0) && module.ash_graphql_schema?()
|
||||||
|
end
|
||||||
|
|
||||||
|
Code.ensure_loaded!(Mix.Project)
|
||||||
|
|
||||||
|
if function_exported?(Mix.Project, :deps_tree, 0) do
|
||||||
|
# for our app, and all dependency apps, we want to find extensions
|
||||||
|
# the benefit of not just getting all loaded applications is that this
|
||||||
|
# is actually a surprisingly expensive thing to do for every single built
|
||||||
|
# in application for elixir/erlang. Instead we get anything w/ a dependency on ash or spark
|
||||||
|
# this could miss things, but its unlikely. And if it misses things, it actually should be
|
||||||
|
# fixed in the dependency that is relying on a transitive dependency :)
|
||||||
|
defp apps do
|
||||||
|
Mix.Project.deps_tree()
|
||||||
|
|> Stream.filter(fn {_, nested_deps} ->
|
||||||
|
Enum.any?(nested_deps, &(&1 == :spark || &1 == :ash))
|
||||||
|
end)
|
||||||
|
|> Stream.map(&elem(&1, 0))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
defp apps do
|
||||||
|
Logger.warning(
|
||||||
|
"Mix.Project.deps_tree/0 not available, falling back to loaded_applications/0. Upgrade to Elixir 1.15+ to make this *much* faster."
|
||||||
|
)
|
||||||
|
|
||||||
|
:application.loaded_applications()
|
||||||
|
|> Stream.map(&elem(&1, 0))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -118,7 +118,10 @@ defmodule AshGraphql.Igniter do
|
||||||
schema_name,
|
schema_name,
|
||||||
"""
|
"""
|
||||||
use Absinthe.Schema
|
use Absinthe.Schema
|
||||||
use AshGraphql, domains: #{inspect(domains)}
|
|
||||||
|
use AshGraphql,
|
||||||
|
domains: #{inspect(domains)},
|
||||||
|
generate_sdl_file: "priv/schema.graphql"
|
||||||
|
|
||||||
import_types Absinthe.Plug.Types
|
import_types Absinthe.Plug.Types
|
||||||
|
|
||||||
|
|
|
@ -452,6 +452,16 @@ defmodule AshGraphql.Resource do
|
||||||
%{module: __MODULE__, location: %{file: env.file, line: env.line}}
|
%{module: __MODULE__, location: %{file: env.file, line: env.line}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def codegen(argv) do
|
||||||
|
schemas = AshGraphql.Codegen.schemas()
|
||||||
|
|
||||||
|
check? = "--check" in argv
|
||||||
|
|
||||||
|
for schema <- schemas, schema.generate_sdl_file() do
|
||||||
|
AshGraphql.Codegen.generate_sdl_file(schema, check?: check?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# sobelow_skip ["DOS.StringToAtom"]
|
# sobelow_skip ["DOS.StringToAtom"]
|
||||||
def install(igniter, module, Ash.Resource, _path, _argv) do
|
def install(igniter, module, Ash.Resource, _path, _argv) do
|
||||||
type =
|
type =
|
||||||
|
|
1
mix.exs
1
mix.exs
|
@ -59,6 +59,7 @@ defmodule AshGraphql.MixProject do
|
||||||
"documentation/tutorials/getting-started-with-graphql.md",
|
"documentation/tutorials/getting-started-with-graphql.md",
|
||||||
"documentation/topics/authorize-with-graphql.md",
|
"documentation/topics/authorize-with-graphql.md",
|
||||||
"documentation/topics/handle-errors.md",
|
"documentation/topics/handle-errors.md",
|
||||||
|
"documentation/topics/sdl-file.md",
|
||||||
"documentation/topics/use-enums-with-graphql.md",
|
"documentation/topics/use-enums-with-graphql.md",
|
||||||
"documentation/topics/use-json-with-graphql.md",
|
"documentation/topics/use-json-with-graphql.md",
|
||||||
"documentation/topics/use-subscriptions-with-graphql.md",
|
"documentation/topics/use-subscriptions-with-graphql.md",
|
||||||
|
|
333
priv/relay_ids.graphql
Normal file
333
priv/relay_ids.graphql
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
schema {
|
||||||
|
mutation: RootMutationType
|
||||||
|
query: RootQueryType
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :assign_posts mutation"
|
||||||
|
type AssignPostsResult {
|
||||||
|
"The successful result of the mutation"
|
||||||
|
result: User
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input AssignPostsInput {
|
||||||
|
name: String
|
||||||
|
postIds: [ID!]
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :create_user mutation"
|
||||||
|
type CreateUserResult {
|
||||||
|
"The successful result of the mutation"
|
||||||
|
result: User
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateUserInput {
|
||||||
|
name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input UserFilterName {
|
||||||
|
isNil: Boolean
|
||||||
|
eq: String
|
||||||
|
notEq: String
|
||||||
|
in: [String]
|
||||||
|
lessThan: String
|
||||||
|
greaterThan: String
|
||||||
|
lessThanOrEqual: String
|
||||||
|
greaterThanOrEqual: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input UserFilterId {
|
||||||
|
isNil: Boolean
|
||||||
|
eq: ID
|
||||||
|
notEq: ID
|
||||||
|
in: [ID!]
|
||||||
|
lessThan: ID
|
||||||
|
greaterThan: ID
|
||||||
|
lessThanOrEqual: ID
|
||||||
|
greaterThanOrEqual: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
input UserFilterInput {
|
||||||
|
and: [UserFilterInput!]
|
||||||
|
or: [UserFilterInput!]
|
||||||
|
not: [UserFilterInput!]
|
||||||
|
id: UserFilterId
|
||||||
|
name: UserFilterName
|
||||||
|
posts: PostFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
|
type User implements Node {
|
||||||
|
id: ID!
|
||||||
|
name: String
|
||||||
|
posts(
|
||||||
|
"How to sort the records in the response"
|
||||||
|
sort: [PostSortInput]
|
||||||
|
|
||||||
|
"A filter to limit the results"
|
||||||
|
filter: PostFilterInput
|
||||||
|
|
||||||
|
"The number of records to return."
|
||||||
|
limit: Int
|
||||||
|
|
||||||
|
"The number of records to skip."
|
||||||
|
offset: Int
|
||||||
|
): [Post!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :create_resource mutation"
|
||||||
|
type CreateResourceResult {
|
||||||
|
"The successful result of the mutation"
|
||||||
|
result: ResourceWithNoPrimaryKeyGet
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateResourceInput {
|
||||||
|
name: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResourceWithNoPrimaryKeyGet implements Node {
|
||||||
|
id: ID!
|
||||||
|
name: String!
|
||||||
|
posts(
|
||||||
|
"How to sort the records in the response"
|
||||||
|
sort: [PostSortInput]
|
||||||
|
|
||||||
|
"A filter to limit the results"
|
||||||
|
filter: PostFilterInput
|
||||||
|
|
||||||
|
"The number of records to return."
|
||||||
|
limit: Int
|
||||||
|
|
||||||
|
"The number of records to skip."
|
||||||
|
offset: Int
|
||||||
|
): [Post!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :delete_post mutation"
|
||||||
|
type DeletePostResult {
|
||||||
|
"The record that was successfully deleted"
|
||||||
|
result: Post
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :assign_author mutation"
|
||||||
|
type AssignAuthorResult {
|
||||||
|
"The successful result of the mutation"
|
||||||
|
result: Post
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input AssignAuthorInput {
|
||||||
|
text: String
|
||||||
|
authorId: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :update_post mutation"
|
||||||
|
type UpdatePostResult {
|
||||||
|
"The successful result of the mutation"
|
||||||
|
result: Post
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input UpdatePostInput {
|
||||||
|
text: String
|
||||||
|
authorId: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
"The result of the :simple_create_post mutation"
|
||||||
|
type SimpleCreatePostResult {
|
||||||
|
"The successful result of the mutation"
|
||||||
|
result: Post
|
||||||
|
|
||||||
|
"Any errors generated, if the mutation failed"
|
||||||
|
errors: [MutationError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input SimpleCreatePostInput {
|
||||||
|
text: String
|
||||||
|
authorId: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PostSortField {
|
||||||
|
ID
|
||||||
|
TEXT
|
||||||
|
AUTHOR_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
"A keyset page of :post"
|
||||||
|
type KeysetPageOfPost {
|
||||||
|
"Total count on all pages"
|
||||||
|
count: Int
|
||||||
|
|
||||||
|
"The records contained in the page"
|
||||||
|
results: [Post!]
|
||||||
|
|
||||||
|
"The first keyset in the results"
|
||||||
|
startKeyset: String
|
||||||
|
|
||||||
|
"The last keyset in the results"
|
||||||
|
endKeyset: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input PostFilterAuthorId {
|
||||||
|
isNil: Boolean
|
||||||
|
eq: ID
|
||||||
|
notEq: ID
|
||||||
|
in: [ID]
|
||||||
|
lessThan: ID
|
||||||
|
greaterThan: ID
|
||||||
|
lessThanOrEqual: ID
|
||||||
|
greaterThanOrEqual: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
input PostFilterText {
|
||||||
|
isNil: Boolean
|
||||||
|
eq: String
|
||||||
|
notEq: String
|
||||||
|
in: [String]
|
||||||
|
lessThan: String
|
||||||
|
greaterThan: String
|
||||||
|
lessThanOrEqual: String
|
||||||
|
greaterThanOrEqual: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input PostFilterId {
|
||||||
|
isNil: Boolean
|
||||||
|
eq: ID
|
||||||
|
notEq: ID
|
||||||
|
in: [ID!]
|
||||||
|
lessThan: ID
|
||||||
|
greaterThan: ID
|
||||||
|
lessThanOrEqual: ID
|
||||||
|
greaterThanOrEqual: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
input PostFilterInput {
|
||||||
|
and: [PostFilterInput!]
|
||||||
|
or: [PostFilterInput!]
|
||||||
|
not: [PostFilterInput!]
|
||||||
|
id: PostFilterId
|
||||||
|
text: PostFilterText
|
||||||
|
authorId: PostFilterAuthorId
|
||||||
|
author: UserFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
|
input PostSortInput {
|
||||||
|
order: SortOrder
|
||||||
|
field: PostSortField!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Post implements Node {
|
||||||
|
id: ID!
|
||||||
|
text: String
|
||||||
|
authorId: ID
|
||||||
|
author: User
|
||||||
|
}
|
||||||
|
|
||||||
|
"A relay node"
|
||||||
|
interface Node {
|
||||||
|
"A unique identifier"
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortOrder {
|
||||||
|
DESC
|
||||||
|
DESC_NULLS_FIRST
|
||||||
|
DESC_NULLS_LAST
|
||||||
|
ASC
|
||||||
|
ASC_NULLS_FIRST
|
||||||
|
ASC_NULLS_LAST
|
||||||
|
}
|
||||||
|
|
||||||
|
"An error generated by a failed mutation"
|
||||||
|
type MutationError {
|
||||||
|
"The human readable error message"
|
||||||
|
message: String
|
||||||
|
|
||||||
|
"A shorter error message, with vars not replaced"
|
||||||
|
shortMessage: String
|
||||||
|
|
||||||
|
"Replacements for the short message"
|
||||||
|
vars: Json
|
||||||
|
|
||||||
|
"An error code for the given error"
|
||||||
|
code: String
|
||||||
|
|
||||||
|
"The field or fields that produced the error"
|
||||||
|
fields: [String!]
|
||||||
|
}
|
||||||
|
|
||||||
|
type RootQueryType {
|
||||||
|
"Retrieves a Node from its global id"
|
||||||
|
node(
|
||||||
|
"The Node unique identifier"
|
||||||
|
id: ID!
|
||||||
|
): Node!
|
||||||
|
|
||||||
|
getPost(
|
||||||
|
"The id of the record"
|
||||||
|
id: ID!
|
||||||
|
): Post
|
||||||
|
|
||||||
|
postLibrary(
|
||||||
|
"How to sort the records in the response"
|
||||||
|
sort: [PostSortInput]
|
||||||
|
|
||||||
|
"A filter to limit the results"
|
||||||
|
filter: PostFilterInput
|
||||||
|
|
||||||
|
"The number of records to return from the beginning. Maximum 250"
|
||||||
|
first: Int
|
||||||
|
|
||||||
|
"Show records before the specified keyset."
|
||||||
|
before: String
|
||||||
|
|
||||||
|
"Show records after the specified keyset."
|
||||||
|
after: String
|
||||||
|
|
||||||
|
"The number of records to return to the end. Maximum 250"
|
||||||
|
last: Int
|
||||||
|
): KeysetPageOfPost
|
||||||
|
|
||||||
|
getResourceByName(
|
||||||
|
"The id of the record"
|
||||||
|
id: ID!
|
||||||
|
|
||||||
|
name: String
|
||||||
|
): ResourceWithNoPrimaryKeyGet
|
||||||
|
|
||||||
|
getUser(
|
||||||
|
"The id of the record"
|
||||||
|
id: ID!
|
||||||
|
): User
|
||||||
|
}
|
||||||
|
|
||||||
|
type RootMutationType {
|
||||||
|
simpleCreatePost(input: SimpleCreatePostInput): SimpleCreatePostResult!
|
||||||
|
updatePost(id: ID!, input: UpdatePostInput): UpdatePostResult!
|
||||||
|
assignAuthor(id: ID!, input: AssignAuthorInput): AssignAuthorResult!
|
||||||
|
deletePost(id: ID!): DeletePostResult!
|
||||||
|
createResource(input: CreateResourceInput!): CreateResourceResult!
|
||||||
|
createUser(input: CreateUserInput): CreateUserResult!
|
||||||
|
assignPosts(id: ID!, input: AssignPostsInput): AssignPostsResult!
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
The `Json` scalar type represents arbitrary json string data, represented as UTF-8
|
||||||
|
character sequences. The Json type is most often used to represent a free-form
|
||||||
|
human-readable json string.
|
||||||
|
"""
|
||||||
|
scalar Json
|
2685
priv/root_level_errors.graphql
Normal file
2685
priv/root_level_errors.graphql
Normal file
File diff suppressed because it is too large
Load diff
3299
priv/schema.graphql
Normal file
3299
priv/schema.graphql
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@ defmodule AshGraphql.Test.RelayIds.Schema do
|
||||||
|
|
||||||
@domains [AshGraphql.Test.RelayIds.Domain]
|
@domains [AshGraphql.Test.RelayIds.Domain]
|
||||||
|
|
||||||
use AshGraphql, domains: @domains, relay_ids?: true
|
use AshGraphql, domains: @domains, relay_ids?: true, generate_sdl_file: "priv/relay_ids.graphql"
|
||||||
|
|
||||||
query do
|
query do
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule AshGraphql.Test.RootLevelErrorsSchema do
|
||||||
|
|
||||||
@domains [AshGraphql.Test.RootLevelErrorsDomain]
|
@domains [AshGraphql.Test.RootLevelErrorsDomain]
|
||||||
|
|
||||||
use AshGraphql, domains: @domains
|
use AshGraphql, domains: @domains, generate_sdl_file: "priv/root_level_errors.graphql"
|
||||||
|
|
||||||
query do
|
query do
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule AshGraphql.Test.Schema do
|
||||||
|
|
||||||
@domains [AshGraphql.Test.Domain, AshGraphql.Test.OtherDomain]
|
@domains [AshGraphql.Test.Domain, AshGraphql.Test.OtherDomain]
|
||||||
|
|
||||||
use AshGraphql, domains: @domains
|
use AshGraphql, domains: @domains, generate_sdl_file: "priv/schema.graphql"
|
||||||
|
|
||||||
query do
|
query do
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue