improvement!: port AshGraphql to Ash 3.0 (#123)

Step 1: update Ash

Step 2: mass rename Api to Domain

Step 3: Ash.Query.expr -> Ash.Expr.expr

Also change ref interpolation

Step 4: remove all warnings

Step 5: remove registries from tests

Step 6: fix filter

Step 7: private? -> !public?

Step 8: Ash.Calculation -> Ash.Resource.Calculation

Step 9: use depend_on_resources/1 -> resources/1

Step 10: add Domain to all resources

Step 11: use Ash module for all actions

Step 12: add public? true all around

Step 13: remove verbose? from options passed during Domain calls

Step 14: add simple_sat

Step 15: Ash.ErrorKind is no more, so remove code from errors

Step 16: sprinkle default_accept :* around tests

Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_*

Step 18: calculation fixups

- Context is now a struct and arguments go under the arguments key
- Function based calculations receive a list of records
- Add a select to query-based loads
- select -> load

Step 19: pass the correct name to pass the policy in tests

Step 20: Ash.Query.new/2 is no more

Step 21: add AshGraphql.Resource.embedded? utility function

Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources
are not types anymore

Step 22: handle struct + instance_of: Resource in unions

Resources are not type anymore so they need to be passed this way in unions

Step 23: ensure we only check GraphQL actions for pagination

All reads are now paginated by default, so this triggered a compilation error

Step 24: swap arguments for sort on calculations

Step 25: remove unused debug? option
This commit is contained in:
Riccardo Binetti 2024-04-01 20:03:06 +02:00 committed by GitHub
parent 9f0ed5ed7e
commit 513c1ac68f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
88 changed files with 1036 additions and 869 deletions

View file

@ -10,7 +10,6 @@ spark_locals_without_parens = [
auto?: 1,
create: 2,
create: 3,
debug?: 1,
depth_limit: 1,
derive_filter?: 1,
derive_sort?: 1,

View file

@ -2,8 +2,8 @@ import Config
config :ash, :utc_datetime_type, :datetime
config :ash, :disable_async?, true
config :ash, :validate_api_resource_inclusion?, false
config :ash, :validate_api_config_inclusion?, false
config :ash, :validate_domain_resource_inclusion?, false
config :ash, :validate_domain_config_inclusion?, false
config :ash_graphql, :default_managed_relationship_type_name_template, :action_name
config :ash_graphql, :allow_non_null_mutation_arguments?, true

View file

@ -1,9 +1,9 @@
<!--
This file was generated by Spark. Do not edit it by hand.
-->
# DSL: AshGraphql.Api
# DSL: AshGraphql.Domain
The entrypoint for adding graphql behavior to an Ash API
The entrypoint for adding graphql behavior to an Ash domain
## graphql
@ -15,7 +15,7 @@ Global configuration for graphql
### Examples
```
graphql do
authorize? false # To skip authorization for this API
authorize? false # To skip authorization for this domain
end
```
@ -27,12 +27,11 @@ end
| Name | Type | Default | Docs |
|------|------|---------|------|
| [`authorize?`](#graphql-authorize?){: #graphql-authorize? } | `boolean` | `true` | Whether or not to perform authorization for this API |
| [`authorize?`](#graphql-authorize?){: #graphql-authorize? } | `boolean` | `true` | Whether or not to perform authorization for this domain |
| [`tracer`](#graphql-tracer){: #graphql-tracer } | `atom` | | A tracer to use to trace execution in the graphql. Will use `config :ash, :tracer` if it is set. |
| [`root_level_errors?`](#graphql-root_level_errors?){: #graphql-root_level_errors? } | `boolean` | `false` | By default, mutation errors are shown in their result object's errors key, but this setting places those errors in the top level errors list |
| [`error_handler`](#graphql-error_handler){: #graphql-error_handler } | `mfa` | `{AshGraphql.DefaultErrorHandler, :handle_error, []}` | Set an MFA to intercept/handle any errors that are generated. |
| [`show_raised_errors?`](#graphql-show_raised_errors?){: #graphql-show_raised_errors? } | `boolean` | `false` | For security purposes, if an error is *raised* then Ash simply shows a generic error. If you want to show those errors, set this to true. |
| [`debug?`](#graphql-debug?){: #graphql-debug? } | `boolean` | `false` | Whether or not to log (extremely verbose) debug information |

View file

@ -57,8 +57,8 @@ end
| [`encode_primary_key?`](#graphql-encode_primary_key?){: #graphql-encode_primary_key? } | `boolean` | `true` | For resources with composite primary keys, or primary keys not called `:id`, this will cause the id to be encoded as a single `id` attribute, both in the representation of the resource and in get requests |
| [`relationships`](#graphql-relationships){: #graphql-relationships } | `list(atom)` | | A list of relationships to include on the created type. Defaults to all public relationships where the destination defines a graphql type. |
| [`field_names`](#graphql-field_names){: #graphql-field_names } | `keyword` | | A keyword list of name overrides for attributes. |
| [`hide_fields`](#graphql-hide_fields){: #graphql-hide_fields } | `list(atom)` | | A list of attributes to hide from the api |
| [`show_fields`](#graphql-show_fields){: #graphql-show_fields } | `list(atom)` | | A list of attributes to show in the api. If not specified includes all (excluding `hide_fiels`). |
| [`hide_fields`](#graphql-hide_fields){: #graphql-hide_fields } | `list(atom)` | | A list of attributes to hide from the domain |
| [`show_fields`](#graphql-show_fields){: #graphql-show_fields } | `list(atom)` | | A list of attributes to show in the domain. If not specified includes all (excluding `hide_fiels`). |
| [`argument_names`](#graphql-argument_names){: #graphql-argument_names } | `keyword` | | A nested keyword list of action names, to argument name remappings. i.e `create: [arg_name: :new_name]` |
| [`keyset_field`](#graphql-keyset_field){: #graphql-keyset_field } | `atom` | | If set, the keyset will be displayed on all read actions in this field. It will be `nil` unless at least one of the read actions on a resource uses keyset pagination or it is the result of a mutation |
| [`attribute_types`](#graphql-attribute_types){: #graphql-attribute_types } | `keyword` | | A keyword list of type overrides for attributes. The type overrides should refer to types available in the graphql (absinthe) schema. `list_of/1` and `non_null/1` helpers can be used. |
@ -322,7 +322,7 @@ create :create_post, :create
| Name | Type | Default | Docs |
|------|------|---------|------|
| [`upsert?`](#graphql-mutations-create-upsert?){: #graphql-mutations-create-upsert? } | `boolean` | `false` | Whether or not to use the `upsert?: true` option when calling `YourApi.create/2`. |
| [`upsert?`](#graphql-mutations-create-upsert?){: #graphql-mutations-create-upsert? } | `boolean` | `false` | Whether or not to use the `upsert?: true` option when calling `YourDomain.create/2`. |
| [`upsert_identity`](#graphql-mutations-create-upsert_identity){: #graphql-mutations-create-upsert_identity } | `atom` | `false` | Which identity to use for the upsert |
| [`modify_resolution`](#graphql-mutations-create-modify_resolution){: #graphql-mutations-create-modify_resolution } | `mfa` | | An MFA that will be called with the resolution, the query, and the result of the action as the first three arguments. See the [the guide](/documentation/topics/modifying-the-resolution.html) for more. |
| [`hide_inputs`](#graphql-mutations-create-hide_inputs){: #graphql-mutations-create-hide_inputs } | `list(atom)` | `[]` | A list of inputs to hide from the mutation. |

View file

@ -6,7 +6,7 @@ AshGraphql uses three special keys in the `absinthe` context:
* `:tenant` - a tenant when using [multitenancy](https://ash-hq.org/docs/guides/ash/latest/topics/multitenancy.md).
* `:ash_context` - a map of arbitrary context to be passed into the changeset/query. Accessible via `changeset.context` and `query.context`
By default, `authorize?` in the api is set to true. To disable authorization for a given API in graphql, use:
By default, `authorize?` in the domain is set to true. To disable authorization for a given domain in graphql, use:
```elixir
graphql do

View file

@ -1,6 +1,6 @@
# Handling Errors
There are various options that can be set on the Api module to determine how errors behave and/or are shown in the GraphQL.
There are various options that can be set on the Domain module to determine how errors behave and/or are shown in the GraphQL.
## Showing raised errors
@ -12,9 +12,9 @@ graphql do
end
# or it can be done in config
# make sure you've set `otp_app` in your api, i.e use Ash.Api, otp_app: :my_app
# make sure you've set `otp_app` in your domain, i.e use Ash.Domain, otp_app: :my_app
config :my_app, YourApi, [
config :my_app, YourDomain, [
graphql: [
show_raised_errors?: true
]

View file

@ -18,11 +18,11 @@ subscription do
# loads all the data you need
AshGraphql.Subscription.query_for_subscription(
YourResource,
YourAPi,
YourDomain,
resolution
)
|> Ash.Query.filter(id == ^args.id)
|> YourAPi.read(actor: resolution.context.current_user)
|> Ash.read(actor: resolution.context.current_user)
end)
end
end

View file

@ -9,11 +9,13 @@ defmodule MyApp.Armor do
types: [
plate: [
# This is an embedded resource, with its own fields
type: MyApp.Armor.Plate
type: :struct,
constraints: [MyApp.Armor.Plate]
],
chain_mail: [
# And so is this
type: MyApp.Armor.ChainMail
type: :struct,
constraints: [instance_of: MyApp.Armor.ChainMail]
],
custom: [
type: :string

View file

@ -247,11 +247,11 @@ mutation($input: CreateTicketInput!) {
- Validation errors are wrapped in a list of error objects under `errors`, also specified in the query.
AshGraphql does this by default instead of exposing errors in GraphQL's standard `errors` array.
This behavior can be changed by setting `root_level_errors? true` in the `graphql` section
of your Ash API module:
of your Ash domain module:
```elixir
defmodule Helpdesk.Support do
use Ash.Api, extensions: [AshGraphql.Api]
use Ash.Domain, extensions: [AshGraphql.Domain]
graphql do
root_level_errors? true
@ -302,4 +302,4 @@ If you haven't already, please turn on the documentation tag for AshGraphql. Tag
at the top of the left navigation menu, under "Including Libraries:".
- [Getting Started With GraphQL](/documentation/tutorials/getting-started-with-graphql.md)
- `AshGraphql.Api`
- `AshGraphql.Domain`

View file

@ -2,7 +2,7 @@
Please read [the Ash monitoring guide](https://hexdocs.pm/ash/monitoring.html) for more information. Here we simply cover the additional traces & telemetry events that we publish from this extension.
A tracer can be configured in the api. It will fallback to the global tracer configuration `config :ash, :tracer, Tracer`
A tracer can be configured in the domain. It will fallback to the global tracer configuration `config :ash, :tracer, Tracer`
```elixir
graphql do
@ -18,13 +18,13 @@ Each graphql resolver, and batch resolution of the underlying data loader, will
AshGraphql emits the following telemetry events, suffixed with `:start` and `:stop`. Start events have `system_time` measurements, and stop events have `system_time` and `duration` measurements. All times will be in the native time unit.
- `[:ash, <api_short_name>, :gql_mutation]` - The execution of a mutation. Use `resource_short_name` and `mutation` (or `action`) metadata to break down measurements.
- `[:ash, <api_short_name>, :gql_query]` - The execution of a mutation. Use `resource_short_name` and `query` (or `action`) metadata to break down measurements.
- `[:ash, <domain_short_name>, :gql_mutation]` - The execution of a mutation. Use `resource_short_name` and `mutation` (or `action`) metadata to break down measurements.
- `[:ash, <domain_short_name>, :gql_query]` - The execution of a mutation. Use `resource_short_name` and `query` (or `action`) metadata to break down measurements.
- `[:ash, <api_short_name>, :gql_relationship]` - The resolution of a relationship. Use `resource_short_name` and `relationship` metadata to break down measurements.
- `[:ash, <domain_short_name>, :gql_relationship]` - The resolution of a relationship. Use `resource_short_name` and `relationship` metadata to break down measurements.
- `[:ash, <api_short_name>, :gql_calculation]` - The resolution of a calculation. Use `resource_short_name` and `calculation` metadata to break down measurements.
- `[:ash, <domain_short_name>, :gql_calculation]` - The resolution of a calculation. Use `resource_short_name` and `calculation` metadata to break down measurements.
- `[:ash, <api_short_name>, :gql_relationship_batch]` - The resolution of a batch of relationships by the data loader. Use `resource_short_name` and `relationship` metadata to break down measurements.
- `[:ash, <domain_short_name>, :gql_relationship_batch]` - The resolution of a batch of relationships by the data loader. Use `resource_short_name` and `relationship` metadata to break down measurements.
- `[:ash, <api_short_name>, :gql_calculation_batch]` - The resolution of a batch of calculations by the data loader. Use `resource_short_name` and `calculation` metadata to break down measurements.
- `[:ash, <domain_short_name>, :gql_calculation_batch]` - The resolution of a batch of calculations by the data loader. Use `resource_short_name` and `calculation` metadata to break down measurements.

View file

@ -2,7 +2,7 @@
## Get familiar with Ash resources
If you haven't already, read the [Ash Getting Started Guide](https://hexdocs.pm/ash/get-started.html). This assumes that you already have resources set up, and only gives you the steps to _add_ AshGraphql to your resources/apis.
If you haven't already, read the [Ash Getting Started Guide](https://hexdocs.pm/ash/get-started.html). This assumes that you already have resources set up, and only gives you the steps to _add_ AshGraphql to your resources/domains.
## Bring in the ash_graphql dependency
@ -26,18 +26,18 @@ config :ash_graphql, :allow_non_null_mutation_arguments?, true
This won't be necessary after the next major release, where this new configuration will be the default.
## Add the API Extension
## Add the domain Extension
Add the following to your API module. If you don't have one, be sure to start with the [Ash Getting Started Guide](https://hexdocs.pm/ash/get-started.html).
Add the following to your domain module. If you don't have one, be sure to start with the [Ash Getting Started Guide](https://hexdocs.pm/ash/get-started.html).
```elixir
defmodule Helpdesk.Support do
use Ash.Api, extensions: [
AshGraphql.Api
use Ash.Domain, extensions: [
AshGraphql.Domain
]
graphql do
authorize? false # Defaults to `true`, use this to disable authorization for the entire API (you probably only want this while prototyping)
authorize? false # Defaults to `true`, use this to disable authorization for the entire domain (you probably only want this while prototyping)
end
...
@ -94,9 +94,9 @@ in `lib/helpdesk/schema.ex`
defmodule Helpdesk.Schema do
use Absinthe.Schema
@apis [Helpdesk.Support]
@domains [Helpdesk.Support]
use AshGraphql, apis: @apis
use AshGraphql, domains: @domains
# The query and mutation blocks is where you can add custom absinthe code
query do

View file

@ -1,44 +0,0 @@
defmodule AshGraphql.Api.Info do
@moduledoc "Introspection helpers for AshGraphql.Api"
alias Spark.Dsl.Extension
@doc "Wether or not to run authorization on this api"
def authorize?(api) do
Extension.get_opt(api, [:graphql], :authorize?, true)
end
@doc "The tracer to use for the given schema"
def tracer(api) do
api
|> Extension.get_opt([:graphql], :tracer, nil, true)
|> List.wrap()
|> Enum.concat(List.wrap(Application.get_env(:ash, :tracer)))
end
@doc "Wether or not to surface errors to the root of the response"
def root_level_errors?(api) do
Extension.get_opt(api, [:graphql], :root_level_errors?, false, true)
end
@doc "An error handler for errors produced by api"
def error_handler(api) do
Extension.get_opt(
api,
[:graphql],
:error_handler,
{AshGraphql.DefaultErrorHandler, :handle_error, []},
true
)
end
@doc "Wether or not to render raised errors in the graphql response"
def show_raised_errors?(api) do
Extension.get_opt(api, [:graphql], :show_raised_errors?, false, true)
end
@doc "Wether or not to pass debug? down to internal execution"
def debug?(api) do
Extension.get_opt(api, [:graphql], :debug?, false)
end
end

View file

@ -33,14 +33,14 @@ defmodule AshGraphql do
defmacro __using__(opts) do
quote bind_quoted: [
apis: opts[:apis],
api: opts[:api],
domains: opts[:domains],
domain: opts[:domain],
action_middleware: opts[:action_middleware] || [],
define_relay_types?: Keyword.get(opts, :define_relay_types?, true),
relay_ids?: Keyword.get(opts, :relay_ids?, false)
],
generated: true do
require Ash.Api.Info
require Ash.Domain.Info
import Absinthe.Schema,
except: [
@ -52,34 +52,34 @@ defmodule AshGraphql do
mutation: 1
]
apis =
api
domains =
domain
|> List.wrap()
|> Kernel.++(List.wrap(apis))
|> Kernel.++(List.wrap(domains))
apis =
apis
domains =
domains
|> Enum.map(fn
{api, registry} ->
{domain, registry} ->
IO.warn("""
It is no longer required to list the registry along with an API when using `AshGraphql`
It is no longer required to list the registry along with a domain when using `AshGraphql`
use AshGraphql, apis: [{My.App.Api, My.App.Registry}]
use AshGraphql, domains: [{My.App.Domain, My.App.Registry}]
Can now be stated simply as
use AshGraphql, apis: [My.App.Api]
use AshGraphql, domains: [My.App.Domain]
""")
api
domain
api ->
api
domain ->
domain
end)
|> Enum.map(fn api -> {api, Ash.Api.Info.depend_on_resources(api), false} end)
|> List.update_at(0, fn {api, resources, _} -> {api, resources, true} end)
|> Enum.map(fn domain -> {domain, Ash.Domain.Info.resources(domain), false} end)
|> List.update_at(0, fn {domain, resources, _} -> {domain, resources, true} end)
@ash_resources Enum.flat_map(apis, &elem(&1, 1))
@ash_resources Enum.flat_map(domains, &elem(&1, 1))
ash_resources = @ash_resources
schema = __MODULE__
@ -119,8 +119,8 @@ defmodule AshGraphql do
end)
end
for {api, resources, first?} <- apis do
defmodule Module.concat(api, AshTypes) do
for {domain, resources, first?} <- domains do
defmodule Module.concat(domain, AshTypes) do
@moduledoc false
alias Absinthe.{Blueprint, Phase, Pipeline}
@ -134,12 +134,12 @@ defmodule AshGraphql do
@dialyzer {:nowarn_function, {:run, 2}}
def run(blueprint, _opts) do
api = unquote(api)
domain = unquote(domain)
action_middleware = unquote(action_middleware)
api_queries =
AshGraphql.Api.queries(
api,
domain_queries =
AshGraphql.Domain.queries(
domain,
unquote(resources),
action_middleware,
__MODULE__,
@ -148,21 +148,21 @@ defmodule AshGraphql do
relay_queries =
if unquote(first?) and unquote(define_relay_types?) and unquote(relay_ids?) do
apis_with_resources = unquote(Enum.map(apis, &{elem(&1, 0), elem(&1, 1)}))
AshGraphql.relay_queries(apis_with_resources, unquote(schema), __ENV__)
domains_with_resources = unquote(Enum.map(domains, &{elem(&1, 0), elem(&1, 1)}))
AshGraphql.relay_queries(domains_with_resources, unquote(schema), __ENV__)
else
[]
end
blueprint_with_queries =
(relay_queries ++ api_queries)
(relay_queries ++ domain_queries)
|> Enum.reduce(blueprint, fn query, blueprint ->
Absinthe.Blueprint.add_field(blueprint, "RootQueryType", query)
end)
blueprint_with_mutations =
api
|> AshGraphql.Api.mutations(
domain
|> AshGraphql.Domain.mutations(
unquote(resources),
action_middleware,
__MODULE__,
@ -174,7 +174,7 @@ defmodule AshGraphql do
type_definitions =
if unquote(first?) do
apis = unquote(Enum.map(apis, &elem(&1, 0)))
domains = unquote(Enum.map(domains, &elem(&1, 0)))
embedded_types =
AshGraphql.get_embedded_types(
@ -190,9 +190,9 @@ defmodule AshGraphql do
AshGraphql.global_unions(unquote(ash_resources), unquote(schema), __ENV__)
Enum.uniq_by(
AshGraphql.Api.global_type_definitions(unquote(schema), __ENV__) ++
AshGraphql.Api.type_definitions(
api,
AshGraphql.Domain.global_type_definitions(unquote(schema), __ENV__) ++
AshGraphql.Domain.type_definitions(
domain,
unquote(resources),
unquote(schema),
__ENV__,
@ -206,8 +206,8 @@ defmodule AshGraphql do
& &1.identifier
)
else
AshGraphql.Api.type_definitions(
api,
AshGraphql.Domain.type_definitions(
domain,
unquote(resources),
unquote(schema),
__ENV__,
@ -235,7 +235,7 @@ defmodule AshGraphql do
import_types(AshGraphql.Types.JSONString)
end
@pipeline_modifier Module.concat(api, AshTypes)
@pipeline_modifier Module.concat(domain, AshTypes)
end
end
end
@ -386,16 +386,16 @@ defmodule AshGraphql do
end
end
def relay_queries(apis_with_resources, schema, env) do
type_to_api_and_resource_map =
apis_with_resources
|> Enum.flat_map(fn {api, resources} ->
def relay_queries(domains_with_resources, schema, env) do
type_to_domain_and_resource_map =
domains_with_resources
|> Enum.flat_map(fn {domain, resources} ->
resources
|> Enum.flat_map(fn resource ->
type = AshGraphql.Resource.Info.type(resource)
if type do
[{type, {api, resource}}]
[{type, {domain, resource}}]
else
[]
end
@ -419,7 +419,7 @@ defmodule AshGraphql do
}
],
middleware: [
{{AshGraphql.Graphql.Resolver, :resolve_node}, type_to_api_and_resource_map}
{{AshGraphql.Graphql.Resolver, :resolve_node}, type_to_domain_and_resource_map}
],
complexity: {AshGraphql.Graphql.Resolver, :query_complexity},
module: schema,
@ -458,7 +458,7 @@ defmodule AshGraphql do
defp nested_attrs(type, constraints, already_checked) do
cond do
Ash.Type.embedded_type?(type) ->
AshGraphql.Resource.embedded?(type) ->
type
|> unwrap_type()
|> all_attributes_and_arguments(already_checked, true, true)
@ -625,7 +625,7 @@ defmodule AshGraphql do
attribute.constraints[:types]
|> Kernel.||([])
|> Enum.flat_map(fn {name, config} ->
if Ash.Type.embedded_type?(config[:type]) do
if AshGraphql.Resource.embedded?(config[:type]) do
[
{source_resource,
%{
@ -641,7 +641,7 @@ defmodule AshGraphql do
end)
other ->
if Ash.Type.embedded_type?(other) do
if AshGraphql.Resource.embedded?(other) do
[{source_resource, attribute}]
else
[]
@ -661,7 +661,7 @@ defmodule AshGraphql do
[
AshGraphql.Resource.type_definition(
embedded_type,
Module.concat(embedded_type, ShadowApi),
Module.concat(embedded_type, ShadowDomain),
schema,
relay_ids?
),
@ -732,7 +732,7 @@ defmodule AshGraphql do
defp get_nested_embedded_types(embedded_type) do
embedded_type
|> Ash.Resource.Info.public_attributes()
|> Enum.filter(&Ash.Type.embedded_type?(&1.type))
|> Enum.filter(&AshGraphql.Resource.embedded?(&1.type))
|> Enum.map(fn attribute ->
{attribute, unwrap_type(attribute.type)}
end)
@ -742,7 +742,7 @@ defmodule AshGraphql do
end
@deprecated "add_context is no longer necessary"
def add_context(ctx, _apis, _options \\ []) do
def add_context(ctx, _domains, _options \\ []) do
ctx
end
end

View file

@ -1,4 +1,4 @@
defmodule AshGraphql.Api do
defmodule AshGraphql.Domain do
@graphql %Spark.Dsl.Section{
name: :graphql,
describe: """
@ -7,14 +7,14 @@ defmodule AshGraphql.Api do
examples: [
"""
graphql do
authorize? false # To skip authorization for this API
authorize? false # To skip authorization for this domain
end
"""
],
schema: [
authorize?: [
type: :boolean,
doc: "Whether or not to perform authorization for this API",
doc: "Whether or not to perform authorization for this domain",
default: true
],
tracer: [
@ -40,11 +40,6 @@ defmodule AshGraphql.Api do
default: false,
doc:
"For security purposes, if an error is *raised* then Ash simply shows a generic error. If you want to show those errors, set this to true."
],
debug?: [
type: :boolean,
doc: "Whether or not to log (extremely verbose) debug information",
default: false
]
]
}
@ -52,52 +47,49 @@ defmodule AshGraphql.Api do
@sections [@graphql]
@moduledoc """
The entrypoint for adding graphql behavior to an Ash API
The entrypoint for adding graphql behavior to an Ash domain
"""
require Ash.Api.Info
require Ash.Domain.Info
use Spark.Dsl.Extension, sections: @sections
@deprecated "See `AshGraphql.Api.Info.authorize?/1`"
defdelegate authorize?(api), to: AshGraphql.Api.Info
@deprecated "See `AshGraphql.Domain.Info.authorize?/1`"
defdelegate authorize?(domain), to: AshGraphql.Domain.Info
@deprecated "See `AshGraphql.Api.Info.root_level_errors?/1`"
defdelegate root_level_errors?(api), to: AshGraphql.Api.Info
@deprecated "See `AshGraphql.Domain.Info.root_level_errors?/1`"
defdelegate root_level_errors?(domain), to: AshGraphql.Domain.Info
@deprecated "See `AshGraphql.Api.Info.show_raised_errors?/1`"
defdelegate show_raised_errors?(api), to: AshGraphql.Api.Info
@deprecated "See `AshGraphql.Api.Info.debug?/1`"
defdelegate debug?(api), to: AshGraphql.Api.Info
@deprecated "See `AshGraphql.Domain.Info.show_raised_errors?/1`"
defdelegate show_raised_errors?(domain), to: AshGraphql.Domain.Info
@doc false
def queries(api, resources, action_middleware, schema, relay_ids?) do
def queries(domain, resources, action_middleware, schema, relay_ids?) do
Enum.flat_map(
resources,
&AshGraphql.Resource.queries(api, &1, action_middleware, schema, relay_ids?)
&AshGraphql.Resource.queries(domain, &1, action_middleware, schema, relay_ids?)
)
end
@doc false
def mutations(api, resources, action_middleware, schema, relay_ids?) do
def mutations(domain, resources, action_middleware, schema, relay_ids?) do
resources
|> Enum.filter(fn resource ->
AshGraphql.Resource in Spark.extensions(resource)
end)
|> Enum.flat_map(
&AshGraphql.Resource.mutations(api, &1, action_middleware, schema, relay_ids?)
&AshGraphql.Resource.mutations(domain, &1, action_middleware, schema, relay_ids?)
)
end
@doc false
def type_definitions(api, resources, schema, env, first?, define_relay_types?, relay_ids?) do
def type_definitions(domain, resources, schema, env, first?, define_relay_types?, relay_ids?) do
resource_types =
resources
|> Enum.reject(&Ash.Resource.Info.embedded?/1)
|> Enum.flat_map(fn resource ->
if AshGraphql.Resource in Spark.extensions(resource) do
AshGraphql.Resource.type_definitions(resource, api, schema, relay_ids?) ++
AshGraphql.Resource.type_definitions(resource, domain, schema, relay_ids?) ++
AshGraphql.Resource.mutation_types(resource, schema)
else
AshGraphql.Resource.no_graphql_types(resource, schema)

39
lib/domain/info.ex Normal file
View file

@ -0,0 +1,39 @@
defmodule AshGraphql.Domain.Info do
@moduledoc "Introspection helpers for AshGraphql.Domain"
alias Spark.Dsl.Extension
@doc "Wether or not to run authorization on this domain"
def authorize?(domain) do
Extension.get_opt(domain, [:graphql], :authorize?, true)
end
@doc "The tracer to use for the given schema"
def tracer(domain) do
domain
|> Extension.get_opt([:graphql], :tracer, nil, true)
|> List.wrap()
|> Enum.concat(List.wrap(Application.get_env(:ash, :tracer)))
end
@doc "Wether or not to surface errors to the root of the response"
def root_level_errors?(domain) do
Extension.get_opt(domain, [:graphql], :root_level_errors?, false, true)
end
@doc "An error handler for errors produced by domain"
def error_handler(domain) do
Extension.get_opt(
domain,
[:graphql],
:error_handler,
{AshGraphql.DefaultErrorHandler, :handle_error, []},
true
)
end
@doc "Wether or not to render raised errors in the graphql response"
def show_raised_errors?(domain) do
Extension.get_opt(domain, [:graphql], :show_raised_errors?, false, true)
end
end

View file

@ -8,7 +8,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Changes.InvalidChanges do
message: error.message,
short_message: error.message,
vars: Map.new(error.vars),
code: Ash.ErrorKind.code(error),
fields: List.wrap(error.fields)
}
end
@ -20,7 +19,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Query.InvalidQuery do
message: error.message,
short_message: error.message,
vars: Map.new(error.vars),
code: Ash.ErrorKind.code(error),
fields: [error.field]
}
end
@ -32,7 +30,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Page.InvalidKeyset do
message: "Invalid value provided as a keyset for %{key}: %{value}",
short_message: "invalid keyset",
vars: Map.merge(Map.new(error.vars), %{value: inspect(error.value), key: error.key}),
code: Ash.ErrorKind.code(error),
fields: List.wrap(Map.get(error, :key))
}
end
@ -44,7 +41,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Changes.InvalidAttribute do
message: error.message,
short_message: error.message,
vars: Map.new(error.vars),
code: Ash.ErrorKind.code(error),
fields: [error.field]
}
end
@ -54,7 +50,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Changes.InvalidArgument do
def to_error(error) do
%{
message: error.message,
code: Ash.ErrorKind.code(error),
short_message: error.message,
vars: Map.new(error.vars),
fields: [error.field]
@ -66,7 +61,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Query.InvalidArgument do
def to_error(error) do
%{
message: error.message,
code: Ash.ErrorKind.code(error),
short_message: error.message,
vars: Map.new(error.vars),
fields: [error.field]
@ -79,7 +73,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Changes.Required do
%{
message: "is required",
short_message: "is required",
code: Ash.ErrorKind.code(error),
vars: error.vars,
fields: [error.field]
}
@ -92,8 +85,7 @@ defimpl AshGraphql.Error, for: Ash.Error.Query.NotFound do
message: "could not be found",
short_message: "could not be found",
fields: Map.keys(error.primary_key || %{}),
vars: error.vars,
code: Ash.ErrorKind.code(error)
vars: error.vars
}
end
end
@ -104,7 +96,6 @@ defimpl AshGraphql.Error, for: Ash.Error.Query.Required do
message: "is required",
short_message: "is required",
vars: error.vars,
code: Ash.ErrorKind.code(error),
fields: [error.field]
}
end
@ -148,8 +139,7 @@ defimpl AshGraphql.Error, for: Ash.Error.Invalid.InvalidPrimaryKey do
message: "invalid primary key provided",
short_message: "invalid primary key provided",
fields: [],
vars: Map.new(error.vars),
code: Ash.ErrorKind.code(error)
vars: Map.new(error.vars)
}
end
end

View file

@ -1,6 +0,0 @@
defmodule AshGraphql.Graphql.ApiMiddleware do
@moduledoc false
def set_api(resolution, api) do
Map.update!(resolution, :context, &Map.put(&1, :api, api))
end
end

View file

@ -0,0 +1,6 @@
defmodule AshGraphql.Graphql.DomainMiddleware do
@moduledoc false
def set_domain(resolution, domain) do
Map.update!(resolution, :context, &Map.put(&1, :domain, domain))
end
end

View file

@ -7,14 +7,14 @@ defmodule AshGraphql.Errors do
@doc """
Transform an error or list of errors into the response for graphql.
"""
def to_errors(errors, context, api) do
def to_errors(errors, context, domain) do
errors
|> AshGraphql.Graphql.Resolver.unwrap_errors()
|> Enum.map(fn error ->
if AshGraphql.Error.impl_for(error) do
error = AshGraphql.Error.to_error(error)
case AshGraphql.Api.Info.error_handler(api) do
case AshGraphql.Domain.Info.error_handler(domain) do
nil ->
error

File diff suppressed because it is too large Load diff

View file

@ -94,12 +94,12 @@ defmodule AshGraphql.Resource.Info do
Extension.get_opt(resource, [:graphql], :field_names, [])
end
@doc "Fields to hide from the graphql api"
@doc "Fields to hide from the graphql domain"
def hide_fields(resource) do
Extension.get_opt(resource, [:graphql], :hide_fields, [])
end
@doc "Fields to show in the graphql api"
@doc "Fields to show in the graphql domain"
def show_fields(resource) do
Extension.get_opt(resource, [:graphql], :show_fields, nil)
end

View file

@ -27,7 +27,7 @@ defmodule AshGraphql.Resource.Mutation do
upsert?: [
type: :boolean,
default: false,
doc: "Whether or not to use the `upsert?: true` option when calling `YourApi.create/2`."
doc: "Whether or not to use the `upsert?: true` option when calling `YourDomain.create/2`."
],
upsert_identity: [
type: :atom,

View file

@ -89,7 +89,7 @@ defmodule AshGraphql.Resource.Query do
"""
]
]
|> Spark.OptionsHelpers.merge_schemas(@query_schema, "Shared Query Options")
|> Spark.Options.merge(@query_schema, "Shared Query Options")
@read_one_schema [
allow_nil?: [
@ -98,7 +98,7 @@ defmodule AshGraphql.Resource.Query do
doc: "Whether or not the action can return nil."
]
]
|> Spark.OptionsHelpers.merge_schemas(@query_schema, "Shared Query Options")
|> Spark.Options.merge(@query_schema, "Shared Query Options")
@list_schema [
relay?: [
@ -116,7 +116,7 @@ defmodule AshGraphql.Resource.Query do
"""
]
]
|> Spark.OptionsHelpers.merge_schemas(@query_schema, "Shared Query Options")
|> Spark.Options.merge(@query_schema, "Shared Query Options")
def get_schema, do: @get_schema
def read_one_schema, do: @read_one_schema

View file

@ -316,12 +316,12 @@ defmodule AshGraphql.Resource do
],
hide_fields: [
type: {:list, :atom},
doc: "A list of attributes to hide from the api"
doc: "A list of attributes to hide from the domain"
],
show_fields: [
type: {:list, :atom},
doc:
"A list of attributes to show in the api. If not specified includes all (excluding `hide_fiels`)."
"A list of attributes to show in the domain. If not specified includes all (excluding `hide_fiels`)."
],
argument_names: [
type: :keyword_list,
@ -498,7 +498,7 @@ defmodule AshGraphql.Resource do
end
@doc false
def queries(api, resource, action_middleware, schema, relay_ids?, as_mutations? \\ false) do
def queries(domain, resource, action_middleware, schema, relay_ids?, as_mutations? \\ false) do
resource
|> queries()
|> Enum.filter(&(Map.get(&1, :as_mutation?, false) == as_mutations?))
@ -513,10 +513,10 @@ defmodule AshGraphql.Resource do
identifier: name,
middleware:
action_middleware ++
api_middleware(api) ++
domain_middleware(domain) ++
id_translation_middleware(query.relay_id_translations, relay_ids?) ++
[
{{AshGraphql.Graphql.Resolver, :resolve}, {api, resource, query, false}}
{{AshGraphql.Graphql.Resolver, :resolve}, {domain, resource, query, false}}
],
complexity: {AshGraphql.Graphql.Resolver, :query_complexity},
module: schema,
@ -554,10 +554,10 @@ defmodule AshGraphql.Resource do
identifier: query.name,
middleware:
action_middleware ++
api_middleware(api) ++
domain_middleware(domain) ++
id_translation_middleware(query.relay_id_translations, relay_ids?) ++
[
{{AshGraphql.Graphql.Resolver, :resolve}, {api, resource, query, relay_ids?}}
{{AshGraphql.Graphql.Resolver, :resolve}, {domain, resource, query, relay_ids?}}
],
complexity: {AshGraphql.Graphql.Resolver, :query_complexity},
module: schema,
@ -571,7 +571,7 @@ defmodule AshGraphql.Resource do
# sobelow_skip ["DOS.StringToAtom"]
@doc false
def mutations(api, resource, action_middleware, schema, relay_ids?) do
def mutations(domain, resource, action_middleware, schema, relay_ids?) do
resource
|> mutations()
|> Enum.map(fn
@ -602,10 +602,10 @@ defmodule AshGraphql.Resource do
identifier: name,
middleware:
action_middleware ++
api_middleware(api) ++
domain_middleware(domain) ++
id_translation_middleware(query.relay_id_translations, relay_ids?) ++
[
{{AshGraphql.Graphql.Resolver, :resolve}, {api, resource, query, true}}
{{AshGraphql.Graphql.Resolver, :resolve}, {domain, resource, query, true}}
],
complexity: {AshGraphql.Graphql.Resolver, :query_complexity},
module: schema,
@ -621,22 +621,31 @@ defmodule AshGraphql.Resource do
raise "No such action #{mutation.action} for #{inspect(resource)}"
if action.soft? do
update_mutation(resource, schema, mutation, schema, action_middleware, api, relay_ids?)
update_mutation(
resource,
schema,
mutation,
schema,
action_middleware,
domain,
relay_ids?
)
else
%Absinthe.Blueprint.Schema.FieldDefinition{
arguments: mutation_args(mutation, resource, schema),
identifier: mutation.name,
middleware:
action_middleware ++
api_middleware(api) ++
domain_middleware(domain) ++
id_translation_middleware(mutation.relay_id_translations, relay_ids?) ++
[
{{AshGraphql.Graphql.Resolver, :mutate}, {api, resource, mutation, relay_ids?}}
{{AshGraphql.Graphql.Resolver, :mutate},
{domain, resource, mutation, relay_ids?}}
],
module: schema,
name: to_string(mutation.name),
description: Ash.Resource.Info.action(resource, mutation.action).description,
type: mutation_result_type(mutation.name, api),
type: mutation_result_type(mutation.name, domain),
__reference__: ref(__ENV__)
}
end
@ -674,26 +683,26 @@ defmodule AshGraphql.Resource do
identifier: mutation.name,
middleware:
action_middleware ++
api_middleware(api) ++
domain_middleware(domain) ++
id_translation_middleware(mutation.relay_id_translations, relay_ids?) ++
[
{{AshGraphql.Graphql.Resolver, :mutate}, {api, resource, mutation, relay_ids?}}
{{AshGraphql.Graphql.Resolver, :mutate}, {domain, resource, mutation, relay_ids?}}
],
module: schema,
name: to_string(mutation.name),
description: Ash.Resource.Info.action(resource, mutation.action).description,
type: mutation_result_type(mutation.name, api),
type: mutation_result_type(mutation.name, domain),
__reference__: ref(__ENV__)
}
mutation ->
update_mutation(resource, schema, mutation, schema, action_middleware, api, relay_ids?)
update_mutation(resource, schema, mutation, schema, action_middleware, domain, relay_ids?)
end)
|> Enum.concat(queries(api, resource, action_middleware, schema, relay_ids?, true))
|> Enum.concat(queries(domain, resource, action_middleware, schema, relay_ids?, true))
end
# sobelow_skip ["DOS.StringToAtom"]
defp update_mutation(resource, schema, mutation, schema, action_middleware, api, relay_ids?) do
defp update_mutation(resource, schema, mutation, schema, action_middleware, domain, relay_ids?) do
action =
Ash.Resource.Info.action(resource, mutation.action) ||
raise "No such action #{mutation.action} for #{inspect(resource)}"
@ -728,23 +737,23 @@ defmodule AshGraphql.Resource do
identifier: mutation.name,
middleware:
action_middleware ++
api_middleware(api) ++
domain_middleware(domain) ++
id_translation_middleware(mutation.relay_id_translations, relay_ids?) ++
[
{{AshGraphql.Graphql.Resolver, :mutate}, {api, resource, mutation, relay_ids?}}
{{AshGraphql.Graphql.Resolver, :mutate}, {domain, resource, mutation, relay_ids?}}
],
module: schema,
name: to_string(mutation.name),
description: Ash.Resource.Info.action(resource, mutation.action).description,
type: mutation_result_type(mutation.name, api),
type: mutation_result_type(mutation.name, domain),
__reference__: ref(__ENV__)
}
end
# sobelow_skip ["DOS.StringToAtom"]
defp mutation_result_type(mutation_name, api) do
defp mutation_result_type(mutation_name, domain) do
type = String.to_atom("#{mutation_name}_result")
root_level_errors? = AshGraphql.Api.Info.root_level_errors?(api)
root_level_errors? = AshGraphql.Domain.Info.root_level_errors?(domain)
maybe_wrap_non_null(type, not root_level_errors?)
end
@ -827,7 +836,7 @@ defmodule AshGraphql.Resource do
end
read_action.arguments
|> Enum.reject(& &1.private?)
|> Enum.filter(& &1.public?)
|> Enum.map(fn argument ->
type =
argument.type
@ -959,8 +968,8 @@ defmodule AshGraphql.Resource do
[]
end
defp api_middleware(api) do
[{{AshGraphql.Graphql.ApiMiddleware, :set_api}, api}]
defp domain_middleware(domain) do
[{{AshGraphql.Graphql.DomainMiddleware, :set_domain}, domain}]
end
# sobelow_skip ["DOS.StringToAtom"]
@ -1113,7 +1122,7 @@ defmodule AshGraphql.Resource do
argument_fields =
action.arguments
|> Enum.reject(& &1.private?)
|> Enum.filter(& &1.public?)
|> Enum.map(fn argument ->
name = argument_names[action.name][argument.name] || argument.name
@ -1180,7 +1189,7 @@ defmodule AshGraphql.Resource do
of_type:
maybe_wrap_non_null(
wrap_arrays(arg_type, type, constraints[:items] || []),
!constraints[:nil_items?] || Ash.Type.embedded_type?(type)
!constraints[:nil_items?] || embedded?(type)
)
}
end
@ -1388,7 +1397,7 @@ defmodule AshGraphql.Resource do
defp generic_action_args(action, resource, schema) do
action.arguments
|> Enum.reject(& &1.private?)
|> Enum.filter(& &1.public?)
|> Enum.map(fn argument ->
type =
argument.type
@ -1546,7 +1555,7 @@ defmodule AshGraphql.Resource do
defp read_args(resource, action, schema, hide_inputs) do
action.arguments
|> Enum.reject(&(&1.private? || &1.name in hide_inputs))
|> Enum.filter(&(&1.public? && &1.name not in hide_inputs))
|> Enum.map(fn argument ->
type =
argument.type
@ -1689,10 +1698,10 @@ defmodule AshGraphql.Resource do
end
@doc false
def type_definitions(resource, api, schema, relay_ids?) do
def type_definitions(resource, domain, schema, relay_ids?) do
List.wrap(calculation_input(resource, schema)) ++
List.wrap(type_definition(resource, api, schema, relay_ids?)) ++
List.wrap(query_type_definitions(resource, api, schema, relay_ids?)) ++
List.wrap(type_definition(resource, domain, schema, relay_ids?)) ++
List.wrap(query_type_definitions(resource, domain, schema, relay_ids?)) ++
List.wrap(sort_input(resource, schema)) ++
List.wrap(filter_input(resource, schema)) ++
filter_field_types(resource, schema) ++
@ -1759,13 +1768,13 @@ defmodule AshGraphql.Resource do
Enum.reduce(defaults, Ash.Changeset.manage_relationship_schema(), fn {key, value},
manage_opts ->
Spark.OptionsHelpers.set_default!(manage_opts, key, value)
Spark.Options.Helpers.set_default!(manage_opts, key, value)
end)
else
Ash.Changeset.manage_relationship_schema()
end
manage_opts = Spark.OptionsHelpers.validate!(opts[:opts], manage_opts_schema)
manage_opts = Spark.Options.validate!(opts[:opts], manage_opts_schema)
fields = manage_fields(manage_opts, managed_relationship, relationship, schema)
@ -2288,7 +2297,7 @@ defmodule AshGraphql.Resource do
{type, attribute_or_aggregate}
end
if Ash.Type.embedded_type?(type) do
if embedded?(type) do
[]
else
attribute_or_aggregate = constraints_to_item_constraints(type, attribute_or_aggregate)
@ -2375,7 +2384,7 @@ defmodule AshGraphql.Resource do
attribute
| constraints: [
items: constraints,
nil_items?: allow_nil? || Ash.Type.embedded_type?(attribute.type)
nil_items?: allow_nil? || embedded?(attribute.type)
]
}
end
@ -2432,7 +2441,7 @@ defmodule AshGraphql.Resource do
true
calc ->
Ash.Type.embedded_type?(calc.type) || Enum.empty?(calc.arguments)
embedded?(calc.type) || Enum.empty?(calc.arguments)
end)
field_names = AshGraphql.Resource.Info.field_names(resource)
@ -2670,7 +2679,7 @@ defmodule AshGraphql.Resource do
defp filterable?(%{type: Ash.Type.Union}, _), do: false
defp filterable?(%Ash.Resource.Calculation{type: type, calculation: {module, _opts}}, _) do
!Ash.Type.embedded_type?(type) && function_exported?(module, :expression, 2)
!embedded?(type) && function_exported?(module, :expression, 2)
end
defp filterable?(%{type: type} = attribute, resource) do
@ -2684,7 +2693,7 @@ defmodule AshGraphql.Resource do
resource
)
else
!Ash.Type.embedded_type?(type)
!embedded?(type)
end
end
@ -3171,8 +3180,13 @@ defmodule AshGraphql.Resource do
{name,
field_type(
config[:type],
%{attribute | name: nested_union_type_name(attribute, name)},
resource
%{
attribute
| name: nested_union_type_name(attribute, name),
constraints: config[:constraints]
},
resource,
false
)}
end)
@ -3519,8 +3533,9 @@ defmodule AshGraphql.Resource do
paginatable? =
resource
|> Ash.Resource.Info.actions()
|> Enum.any?(fn action ->
|> queries()
|> Enum.any?(fn query ->
action = Ash.Resource.Info.action(resource, query.action)
action.type == :read && action.pagination
end)
@ -3581,7 +3596,7 @@ defmodule AshGraphql.Resource do
type.identifier == :node
end
def query_type_definitions(resource, api, schema, relay_ids?) do
def query_type_definitions(resource, domain, schema, relay_ids?) do
resource_type = AshGraphql.Resource.Info.type(resource)
resource
@ -3602,7 +3617,7 @@ defmodule AshGraphql.Resource do
%Absinthe.Blueprint.Schema.ObjectTypeDefinition{
description: Ash.Resource.Info.description(resource),
interfaces: interfaces,
fields: fields(resource, api, schema, relay_ids?, query),
fields: fields(resource, domain, schema, relay_ids?, query),
identifier: query.type_name,
module: schema,
name: Macro.camelize(to_string(query.type_name)),
@ -3611,7 +3626,7 @@ defmodule AshGraphql.Resource do
end)
end
def type_definition(resource, api, schema, relay_ids?) do
def type_definition(resource, domain, schema, relay_ids?) do
actual_resource = Ash.Type.NewType.subtype_of(resource)
if generate_object?(resource) do
@ -3652,7 +3667,7 @@ defmodule AshGraphql.Resource do
%Absinthe.Blueprint.Schema.ObjectTypeDefinition{
description: Ash.Resource.Info.description(resource),
interfaces: interfaces,
fields: fields(resource, api, schema, relay_ids?),
fields: fields(resource, domain, schema, relay_ids?),
identifier: type,
module: schema,
name: Macro.camelize(to_string(type)),
@ -3661,12 +3676,12 @@ defmodule AshGraphql.Resource do
end
end
defp fields(resource, api, schema, relay_ids?, query \\ nil) do
attributes(resource, api, schema, relay_ids?) ++
defp fields(resource, domain, schema, relay_ids?, query \\ nil) do
attributes(resource, domain, schema, relay_ids?) ++
metadata(query, resource, schema) ++
relationships(resource, api, schema) ++
aggregates(resource, api, schema) ++
calculations(resource, api, schema) ++
relationships(resource, domain, schema) ++
aggregates(resource, domain, schema) ++
calculations(resource, domain, schema) ++
keyset(resource, schema)
end
@ -3725,7 +3740,7 @@ defmodule AshGraphql.Resource do
end
end
defp attributes(resource, api, schema, relay_ids?) do
defp attributes(resource, domain, schema, relay_ids?) do
attribute_names = AshGraphql.Resource.Info.field_names(resource)
attributes =
@ -3759,7 +3774,7 @@ defmodule AshGraphql.Resource do
attribute.name,
attribute.type,
attribute.constraints,
api
domain
),
name: to_string(name),
type: field_type,
@ -3780,9 +3795,7 @@ defmodule AshGraphql.Resource do
[field] ->
attribute = Ash.Resource.Info.attribute(resource, field)
if attribute.private? do
[]
else
if attribute.public? do
[
%Absinthe.Blueprint.Schema.FieldDefinition{
description: attribute.description,
@ -3796,6 +3809,8 @@ defmodule AshGraphql.Resource do
__reference__: ref(__ENV__)
}
]
else
[]
end
fields ->
@ -3861,7 +3876,7 @@ defmodule AshGraphql.Resource do
defp argument_required?(_), do: true
# sobelow_skip ["DOS.StringToAtom"]
defp relationships(resource, api, schema) do
defp relationships(resource, domain, schema) do
field_names = AshGraphql.Resource.Info.field_names(resource)
relationships = AshGraphql.Resource.Info.relationships(resource)
@ -3897,7 +3912,7 @@ defmodule AshGraphql.Resource do
description: relationship.description,
arguments: args(:one_related, relationship.destination, read_action, schema),
middleware: [
{{AshGraphql.Graphql.Resolver, :resolve_assoc}, {api, relationship}}
{{AshGraphql.Graphql.Resolver, :resolve_assoc}, {domain, relationship}}
],
type: type,
__reference__: ref(__ENV__)
@ -3930,7 +3945,7 @@ defmodule AshGraphql.Resource do
description: relationship.description,
complexity: {AshGraphql.Graphql.Resolver, :query_complexity},
middleware: [
{{AshGraphql.Graphql.Resolver, :resolve_assoc}, {api, relationship}}
{{AshGraphql.Graphql.Resolver, :resolve_assoc}, {domain, relationship}}
],
arguments: args(:list_related, relationship.destination, read_action, schema),
type: query_type,
@ -3939,7 +3954,7 @@ defmodule AshGraphql.Resource do
end)
end
defp aggregates(resource, api, schema) do
defp aggregates(resource, domain, schema) do
field_names = AshGraphql.Resource.Info.field_names(resource)
resource
@ -3991,7 +4006,7 @@ defmodule AshGraphql.Resource do
identifier: aggregate.name,
module: schema,
middleware:
middleware_for_field(resource, aggregate, aggregate.name, agg_type, constraints, api),
middleware_for_field(resource, aggregate, aggregate.name, agg_type, constraints, domain),
name: to_string(name),
description: aggregate.description,
type: type,
@ -4000,11 +4015,11 @@ defmodule AshGraphql.Resource do
end)
end
defp middleware_for_field(resource, field, name, {:array, type}, constraints, api) do
middleware_for_field(resource, field, name, type, constraints, api)
defp middleware_for_field(resource, field, name, {:array, type}, constraints, domain) do
middleware_for_field(resource, field, name, type, constraints, domain)
end
defp middleware_for_field(resource, field, name, type, constraints, api) do
defp middleware_for_field(resource, field, name, type, constraints, domain) do
if Ash.Type.NewType.new_type?(type) &&
Ash.Type.NewType.subtype_of(type) == Ash.Type.Union &&
function_exported?(type, :graphql_unnested_unions, 1) do
@ -4012,16 +4027,16 @@ defmodule AshGraphql.Resource do
[
{{AshGraphql.Graphql.Resolver, :resolve_union},
{name, type, field, resource, unnested_types, api}}
{name, type, field, resource, unnested_types, domain}}
]
else
[
{{AshGraphql.Graphql.Resolver, :resolve_attribute}, {name, type, constraints, api}}
{{AshGraphql.Graphql.Resolver, :resolve_attribute}, {name, type, constraints, domain}}
]
end
end
defp calculations(resource, api, schema) do
defp calculations(resource, domain, schema) do
field_names = AshGraphql.Resource.Info.field_names(resource)
resource
@ -4039,7 +4054,7 @@ defmodule AshGraphql.Resource do
arguments: arguments,
complexity: 2,
middleware: [
{{AshGraphql.Graphql.Resolver, :resolve_calculation}, {api, resource, calculation}}
{{AshGraphql.Graphql.Resolver, :resolve_calculation}, {domain, resource, calculation}}
],
name: to_string(name),
description: calculation.description,
@ -4144,9 +4159,7 @@ defmodule AshGraphql.Resource do
field_type =
type
|> do_field_type(new_attribute, resource, input?)
|> maybe_wrap_non_null(
!attribute.constraints[:nil_items?] || Ash.Type.embedded_type?(attribute.type)
)
|> maybe_wrap_non_null(!attribute.constraints[:nil_items?] || embedded?(attribute.type))
%Absinthe.Blueprint.TypeReference.List{
of_type: field_type
@ -4166,7 +4179,7 @@ defmodule AshGraphql.Resource do
if Ash.Type.builtin?(type) do
get_specific_field_type(type, attribute, resource, input?)
else
if Spark.Dsl.is?(type, Ash.Resource) && !Ash.Type.embedded_type?(type) do
if Ash.Resource.Info.resource?(type) && !Ash.Resource.Info.embedded?(type) do
if input? do
Application.get_env(:ash_graphql, :json_type) || :json_string
else
@ -4410,4 +4423,16 @@ defmodule AshGraphql.Resource do
|> AshGraphql.Resource.Info.queries()
|> Enum.find(&(&1.type == :get and (&1.identity == nil or &1.identity == false)))
end
def embedded?({:array, resource_or_type}) do
embedded?(resource_or_type)
end
def embedded?(resource_or_type) do
if Ash.Resource.Info.resource?(resource_or_type) do
Ash.Resource.Info.embedded?(resource_or_type)
else
Ash.Type.embedded_type?(resource_or_type)
end
end
end

View file

@ -8,18 +8,17 @@ defmodule AshGraphql.Subscription do
@doc """
Produce a query that will load the correct data for a subscription.
"""
def query_for_subscription(query, api, %{context: context} = resolution) do
query = Ash.Query.to_query(query)
def query_for_subscription(query, domain, %{context: context} = resolution) do
query
|> Ash.Query.new()
|> Ash.Query.set_tenant(Map.get(context, :tenant))
|> Ash.Query.set_context(get_context(context))
|> AshGraphql.Graphql.Resolver.select_fields(query.resource, resolution, nil)
|> AshGraphql.Graphql.Resolver.load_fields(
[
api: api,
domain: domain,
tenant: Map.get(context, :tenant),
authorize?: AshGraphql.Api.Info.authorize?(api),
authorize?: AshGraphql.Domain.Info.authorize?(domain),
actor: Map.get(context, :actor)
],
query.resource,

View file

@ -1,30 +1,30 @@
defmodule AshGraphql.TraceHelpers do
@moduledoc false
defmacro trace(api, resource, type, name, metadata, do: body) do
defmacro trace(domain, resource, type, name, metadata, do: body) do
quote do
require Ash.Tracer
api = unquote(api)
domain = unquote(domain)
resource = unquote(resource)
type = unquote(type)
name = unquote(name)
metadata = unquote(metadata)
Ash.Tracer.span type,
AshGraphql.TraceHelpers.span_name(api, resource, type, name),
AshGraphql.Api.Info.tracer(api) do
Ash.Tracer.set_metadata(AshGraphql.Api.Info.tracer(api), type, metadata)
AshGraphql.TraceHelpers.span_name(domain, resource, type, name),
AshGraphql.Domain.Info.tracer(domain) do
Ash.Tracer.set_metadata(AshGraphql.Domain.Info.tracer(domain), type, metadata)
Ash.Tracer.telemetry_span [:ash, Ash.Api.Info.short_name(api), type], metadata do
Ash.Tracer.telemetry_span [:ash, Ash.Domain.Info.short_name(domain), type], metadata do
unquote(body)
end
end
end
end
def span_name(api, resource, type, name)
when is_atom(api) and is_atom(resource) and is_atom(type) and
def span_name(domain, resource, type, name)
when is_atom(domain) and is_atom(resource) and is_atom(type) and
(is_atom(name) or is_binary(name)) do
Ash.Api.Info.span_name(api, resource, "#{type}.#{name}")
Ash.Domain.Info.span_name(domain, resource, "#{type}.#{name}")
end
end

18
mix.exs
View file

@ -71,7 +71,7 @@ defmodule AshGraphql.MixProject do
"documentation/topics/graphql-generation.md",
"documentation/topics/modifying-the-resolution.md",
"documentation/topics/relay.md",
"documentation/dsls/DSL:-AshGraphql.Api.md",
"documentation/dsls/DSL:-AshGraphql.Domain.md",
"documentation/dsls/DSL:-AshGraphql.Resource.md"
],
groups_for_extras: [
@ -86,9 +86,9 @@ defmodule AshGraphql.MixProject do
],
Introspection: [
AshGraphql.Resource.Info,
AshGraphql.Api.Info,
AshGraphql.Domain.Info,
AshGraphql.Resource,
AshGraphql.Api,
AshGraphql.Domain,
AshGraphql.Resource.Action,
AshGraphql.Resource.ManagedRelationship,
AshGraphql.Resource.Mutation,
@ -136,7 +136,7 @@ defmodule AshGraphql.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:ash, ash_version("~> 2.17")},
{:ash, ash_version("~> 3.0-dev")},
{:absinthe_plug, "~> 1.4"},
{:absinthe, "~> 1.7"},
{:jason, "~> 1.2"},
@ -147,7 +147,8 @@ defmodule AshGraphql.MixProject do
{:sobelow, ">= 0.0.0", only: [:dev, :test], runtime: false},
{:git_ops, "~> 2.5", only: [:dev, :test]},
{:excoveralls, "~> 0.13", only: [:dev, :test]},
{:mix_test_watch, "~> 1.0", only: :dev, runtime: false}
{:mix_test_watch, "~> 1.0", only: :dev, runtime: false},
{:simple_sat, ">= 0.0.0", only: :test}
]
end
@ -170,10 +171,11 @@ defmodule AshGraphql.MixProject do
"spark.replace_doc_links",
"spark.cheat_sheets_in_search"
],
"spark.formatter": "spark.formatter --extensions AshGraphql.Resource,AshGraphql.Api",
"spark.formatter": "spark.formatter --extensions AshGraphql.Resource,AshGraphql.Domain",
"spark.cheat_sheets_in_search":
"spark.cheat_sheets_in_search --extensions AshGraphql.Resource,AshGraphql.Api",
"spark.cheat_sheets": "spark.cheat_sheets --extensions AshGraphql.Resource,AshGraphql.Api"
"spark.cheat_sheets_in_search --extensions AshGraphql.Resource,AshGraphql.Domain",
"spark.cheat_sheets":
"spark.cheat_sheets --extensions AshGraphql.Resource,AshGraphql.Domain"
]
end
end

View file

@ -1,16 +1,14 @@
%{
"absinthe": {:hex, :absinthe, "1.7.5", "a15054f05738e766f7cc7fd352887dfd5e61cec371fb4741cca37c3359ff74ac", [:mix], [{:dataloader, "~> 1.0.0 or ~> 2.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.2.2 or ~> 1.3.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:opentelemetry_process_propagator, "~> 0.2.1", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "22a9a38adca26294ad0ee91226168f5d215b401efd770b8a1b8fd9c9b21ec316"},
"absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"},
"ash": {:hex, :ash, "2.21.1", "4b098f68ba0bb20b49216f4771b885c88f72446ea98ad97eb3ea5a2b3543770b", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:reactor, "~> 0.6", [hex: :reactor, repo: "hexpm", optional: false]}, {:spark, ">= 1.1.55 and < 2.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.6", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8890215fe59c85325af302ca307e2d103d555383f7d20b4da98bde79ec6dd76c"},
"ash": {:hex, :ash, "3.0.0-rc.4", "b8142d27a4541d44d2400f5a127d87cc88a54928945f302210b779fcbaf8fc41", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:reactor, "~> 0.8", [hex: :reactor, repo: "hexpm", optional: false]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:spark, ">= 2.1.7 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.6", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "518a8948e3973efe5df432825db58eaf03cf3f0cd6445e98479aa398ebaedfdf"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"},
"credo": {:hex, :credo, "1.7.4", "68ca5cf89071511c12fd9919eb84e388d231121988f6932756596195ccf7fd35", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9cf776d062c78bbe0f0de1ecaee183f18f2c3ec591326107989b054b7dddefc2"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"},
"earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"elixir_make": {:hex, :elixir_make, "0.8.3", "d38d7ee1578d722d89b4d452a3e36bcfdc644c618f0d063b874661876e708683", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "5c99a18571a756d4af7a4d89ca75c28ac899e6103af6f223982f09ce44942cc9"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"},
"ex_check": {:hex, :ex_check, "0.15.0", "074b94c02de11c37bba1ca82ae5cc4926e6ccee862e57a485b6ba60fca2d8dc1", [:mix], [], "hexpm", "33848031a0c7e4209c3b4369ce154019788b5219956220c35ca5474299fb6a0e"},
@ -26,15 +24,15 @@
"makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mix_test_watch": {:hex, :mix_test_watch, "1.1.1", "eee6fc570d77ad6851c7bc08de420a47fd1e449ef5ccfa6a77ef68b72e7e51ad", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "f82262b54dee533467021723892e15c3267349849f1f737526523ecba4e6baae"},
"nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
"picosat_elixir": {:hex, :picosat_elixir, "0.2.3", "bf326d0f179fbb3b706bb2c15fbc367dacfa2517157d090fdfc32edae004c597", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f76c9db2dec9d2561ffaa9be35f65403d53e984e8cd99c832383b7ab78c16c66"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"reactor": {:hex, :reactor, "0.7.0", "fb76d23d95829b28ac9b9d654620c43c890c6a32ea26ac13086c48540b34e8c5", [:mix], [{:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 1.0", [hex: :spark, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4310da820d753aafd7dc4ee8cc687b84565dd6d9536e38806ee211da792178fd"},
"reactor": {:hex, :reactor, "0.8.1", "1aec71d16083901277727c8162f6dd0f07e80f5ca98911b6ef4f2c95e6e62758", [:mix], [{:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ae3936d97a3e4a316744f70c77b85345b08b70da334024c26e6b5eb8ede1246b"},
"simple_sat": {:hex, :simple_sat, "0.1.1", "68a5ebe6f6d5956bd806e4881c495692c14580a2f1a4420488985abd0fba2119", [:mix], [], "hexpm", "63571218f92ff029838df7645eb8f0c38df8ed60d2d14578412a8d142a94471e"},
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
"sourceror": {:hex, :sourceror, "1.0.2", "c5e86fdc14881f797749d1fe5df017ca66727a8146e7ee3e736605a3df78f3e6", [:mix], [], "hexpm", "832335e87d0913658f129d58b2a7dc0490ddd4487b02de6d85bca0169ec2bd79"},
"spark": {:hex, :spark, "1.1.55", "d20c3f899b23d841add29edc912ffab4463d3bb801bc73448738631389291d2e", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "bbc15a4223d8e610c81ceca825d5d0bae3738d1c4ac4dbb1061749966776c3f1"},
"spark": {:hex, :spark, "2.1.11", "8093149dfd583b5ce2c06e1fea1faaf4125b50e4703138b2cbefb78c8f4aa07f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "1877d92ab993b860e9d828bfd72d50367c0d3a53dd84f4de5d221baf66ae8723"},
"splode": {:hex, :splode, "0.2.1", "020079ec06c9e00f8b6586852e781b5e07aee6ba588f3f45dd993831c87b0511", [:mix], [], "hexpm", "d232a933666061fe1f659d9906042fa94b9b393bb1129a4fde6fa680033b2611"},
"stream_data": {:hex, :stream_data, "0.6.0", "e87a9a79d7ec23d10ff83eb025141ef4915eeb09d4491f79e52f2562b73e5f47", [:mix], [], "hexpm", "b92b5031b650ca480ced047578f1d57ea6dd563f5b57464ad274718c9c29501c"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"},

View file

@ -13,7 +13,7 @@ defmodule AliasTest do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true, score: 9.8)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -39,7 +39,7 @@ defmodule AliasTest do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true, score: 9.8)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -70,7 +70,7 @@ defmodule AliasTest do
published: true,
score: 9.8
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -103,7 +103,7 @@ defmodule AliasTest do
published: true,
score: 9.8
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -144,7 +144,7 @@ defmodule AliasTest do
published: true,
score: 9.8
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -179,7 +179,7 @@ defmodule AliasTest do
published: true,
score: 9.8
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -209,8 +209,8 @@ defmodule AliasTest do
test "relationship alias works correctly" do
author =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, name: "test")
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, name: "My Name")
|> Ash.create!()
post =
AshGraphql.Test.Post
@ -220,7 +220,7 @@ defmodule AliasTest do
score: 9.8,
author_id: author.id
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""

View file

@ -3,7 +3,7 @@ defmodule AshGraphql.AttributeTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
try do
AshGraphql.TestHelpers.stop_ets()

View file

@ -3,7 +3,7 @@ defmodule AshGraphql.CreateTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
AshGraphql.TestHelpers.stop_ets()
end)
@ -304,7 +304,7 @@ defmodule AshGraphql.CreateTest do
simpleCreatePost(input: $input) {
result{
text1
integerAsStringInApi
integerAsStringInDomain
}
errors{
message
@ -313,7 +313,7 @@ defmodule AshGraphql.CreateTest do
}
"""
|> Absinthe.run(AshGraphql.Test.Schema,
variables: %{"input" => %{"text1" => "foo", "integerAsStringInApi" => "1"}}
variables: %{"input" => %{"text1" => "foo", "integerAsStringInDomain" => "1"}}
)
assert {:ok, result} = resp
@ -324,7 +324,7 @@ defmodule AshGraphql.CreateTest do
data: %{
"simpleCreatePost" => %{
"result" => %{
"integerAsStringInApi" => "1"
"integerAsStringInDomain" => "1"
}
}
}
@ -332,7 +332,10 @@ defmodule AshGraphql.CreateTest do
end
test "a create can load a calculation on a related belongs_to record" do
author = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.User, name: "bob"))
author =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, name: "My Name")
|> Ash.create!()
resp =
"""
@ -365,7 +368,7 @@ defmodule AshGraphql.CreateTest do
"result" => %{
"fullText" => "foobar",
"author" => %{
"nameTwice" => "bob bob"
"nameTwice" => "My Name My Name"
}
}
}
@ -487,8 +490,8 @@ defmodule AshGraphql.CreateTest do
test "an upsert works" do
post =
AshGraphql.Test.Post
|> Ash.Changeset.new(text: "foobar")
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, text: "foobar")
|> Ash.create!()
resp =
"""
@ -560,7 +563,7 @@ defmodule AshGraphql.CreateTest do
end
test "errors can be intercepted" do
Application.put_env(:ash_graphql, AshGraphql.Test.Api,
Application.put_env(:ash_graphql, AshGraphql.Test.Domain,
graphql: [
error_handler: {ErrorHandler, :handle_error, []}
]
@ -600,7 +603,7 @@ defmodule AshGraphql.CreateTest do
end
test "root level error" do
Application.put_env(:ash_graphql, AshGraphql.Test.Api,
Application.put_env(:ash_graphql, AshGraphql.Test.Domain,
graphql: [show_raised_errors?: true, root_level_errors?: true]
)

View file

@ -17,20 +17,20 @@ defmodule AshGraphql.CustpmPaginateTest do
test "channel record with direct union message records are fetched" do
channel =
AshGraphql.Test.Channel
|> Ash.Changeset.new(%{})
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
text_message =
AshGraphql.Test.TextMessage
|> Ash.Changeset.for_create(:create, text: "test text message")
|> Ash.Changeset.manage_relationship(:channel, channel, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
image_message =
AshGraphql.Test.ImageMessage
|> Ash.Changeset.for_create(:create, text: "test image message")
|> Ash.Changeset.manage_relationship(:channel, channel, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -88,20 +88,20 @@ defmodule AshGraphql.CustpmPaginateTest do
test "channel record with page of channel messages record is fetched" do
channel =
AshGraphql.Test.Channel
|> Ash.Changeset.new(%{})
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
text_message =
AshGraphql.Test.TextMessage
|> Ash.Changeset.for_create(:create, text: "test text message")
|> Ash.Changeset.manage_relationship(:channel, channel, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
image_message =
AshGraphql.Test.ImageMessage
|> Ash.Changeset.for_create(:create, text: "test image message")
|> Ash.Changeset.manage_relationship(:channel, channel, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""

View file

@ -3,14 +3,17 @@ defmodule AshGraphql.DestroyTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
AshGraphql.TestHelpers.stop_ets()
end)
end
test "a destroy works" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar")
|> Ash.create!()
resp =
"""
@ -38,7 +41,10 @@ defmodule AshGraphql.DestroyTest do
end
test "a soft destroy works" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar")
|> Ash.create!()
resp =
"""
@ -66,9 +72,9 @@ defmodule AshGraphql.DestroyTest do
end
test "a destroy with a configured read action and no identity works" do
AshGraphql.Test.Api.create!(
Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar", best: true)
)
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -92,7 +98,10 @@ defmodule AshGraphql.DestroyTest do
end
test "a destroy with an error" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -154,11 +163,14 @@ defmodule AshGraphql.DestroyTest do
end
test "root level error on destroy" do
Application.put_env(:ash_graphql, AshGraphql.Test.Api,
Application.put_env(:ash_graphql, AshGraphql.Test.Domain,
graphql: [show_raised_errors?: true, root_level_errors?: true]
)
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""

View file

@ -3,7 +3,7 @@ defmodule AshGraphql.EnumTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
AshGraphql.TestHelpers.stop_ets()
end)

View file

@ -4,7 +4,7 @@ defmodule AshGraphql.ErrorsTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
Application.delete_env(:ash_graphql, :policies)
AshGraphql.TestHelpers.stop_ets()
@ -74,7 +74,9 @@ defmodule AshGraphql.ErrorsTest do
end
test "raised errors can be configured to be shown" do
Application.put_env(:ash_graphql, AshGraphql.Test.Api, graphql: [show_raised_errors?: true])
Application.put_env(:ash_graphql, AshGraphql.Test.Domain,
graphql: [show_raised_errors?: true]
)
resp =
"""
@ -109,7 +111,7 @@ defmodule AshGraphql.ErrorsTest do
end
test "showing raised errors alongside root errors shows raised errors in the root" do
Application.put_env(:ash_graphql, AshGraphql.Test.RootLevelErrorsApi,
Application.put_env(:ash_graphql, AshGraphql.Test.RootLevelErrorsDomain,
graphql: [show_raised_errors?: true]
)
@ -157,7 +159,7 @@ defmodule AshGraphql.ErrorsTest do
[name: "My Tag4"],
tenant: tenant
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -188,7 +190,7 @@ defmodule AshGraphql.ErrorsTest do
[name: "My Tag2"],
tenant: tenant
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -219,7 +221,7 @@ defmodule AshGraphql.ErrorsTest do
[name: "My Tag3"],
tenant: tenant
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post =
AshGraphql.Test.Post
@ -230,7 +232,7 @@ defmodule AshGraphql.ErrorsTest do
on_no_match: {:create, :create_action},
on_lookup: :relate
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -266,7 +268,7 @@ defmodule AshGraphql.ErrorsTest do
|> Ash.Changeset.for_create(:create,
name: "My Name"
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -315,7 +317,7 @@ defmodule AshGraphql.ErrorsTest do
|> Ash.Changeset.for_create(:create,
name: "My Name"
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""

View file

@ -3,7 +3,7 @@ defmodule AshGraphql.GenericActionsTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
AshGraphql.TestHelpers.stop_ets()
end)
@ -55,7 +55,10 @@ defmodule AshGraphql.GenericActionsTest do
end
test "generic action mutations can be run" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -79,7 +82,10 @@ defmodule AshGraphql.GenericActionsTest do
end
test "generic action mutations can be run with input" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""

View file

@ -17,13 +17,13 @@ defmodule AshGraphql.PaginateTest do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: text, published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
for text <- letters do
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, text: text)
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
end
end
@ -77,13 +77,13 @@ defmodule AshGraphql.PaginateTest do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: text, published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
for text <- letters do
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, text: text)
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
end
end

View file

@ -25,8 +25,8 @@ defmodule AshGraphql.PlugTest do
test "when the actor is set, the current user returns the correct value" do
user =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, %{name: "Marty McFly"})
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, %{name: "My Name"})
|> Ash.create!()
resp =
"""
@ -67,7 +67,7 @@ defmodule AshGraphql.PlugTest do
tag =
AshGraphql.Test.MultitenantTag
|> Ash.Changeset.for_create(:create, [name: "1985"], tenant: tenant)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""

View file

@ -12,11 +12,11 @@ defmodule AshGraphql.ReadTest do
test "float fields works correctly" do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true, score: 9.8)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", published: true, score: 9.85)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -41,11 +41,11 @@ defmodule AshGraphql.ReadTest do
test "union fields works correctly" do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true, simple_union: 10)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", published: true, simple_union: "foo")
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -83,7 +83,7 @@ defmodule AshGraphql.ReadTest do
|> Ash.Changeset.for_create(:create,
name: "My Name"
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -107,7 +107,7 @@ defmodule AshGraphql.ReadTest do
|> Ash.Changeset.for_create(:create,
name: "My Name"
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -131,8 +131,8 @@ defmodule AshGraphql.ReadTest do
test "loading relationships with fragment works" do
user =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, %{name: "fred"})
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, %{name: "My Name"})
|> Ash.create!()
post =
AshGraphql.Test.Post
@ -144,7 +144,7 @@ defmodule AshGraphql.ReadTest do
published: true
}
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post
|> Ash.Changeset.for_update(
@ -153,7 +153,7 @@ defmodule AshGraphql.ReadTest do
comments: [%{text: "comment", author_id: user.id}]
}
)
|> AshGraphql.Test.Api.update!()
|> Ash.update!()
resp =
"""
@ -186,7 +186,7 @@ defmodule AshGraphql.ReadTest do
%{
"comments" => [
%{
"author" => %{"name" => "fred"}
"author" => %{"name" => "My Name"}
}
]
}
@ -198,11 +198,11 @@ defmodule AshGraphql.ReadTest do
test "a read with arguments works" do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", published: false)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -228,17 +228,17 @@ defmodule AshGraphql.ReadTest do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create,
text: "foo",
integer_as_string_in_api: 1,
integer_as_string_in_domain: 1,
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
query PostLibrary {
postLibrary {
text
integerAsStringInApi
integerAsStringInDomain
}
}
"""
@ -247,19 +247,19 @@ defmodule AshGraphql.ReadTest do
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{data: %{"postLibrary" => [%{"integerAsStringInApi" => "1"}]}} = result
assert %{data: %{"postLibrary" => [%{"integerAsStringInDomain" => "1"}]}} = result
end
test "reading relationships works, without selecting the id field" do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, %{text: "stuff"})
|> Ash.Changeset.force_change_attribute(:post_id, post.id)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -290,12 +290,12 @@ defmodule AshGraphql.ReadTest do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, %{text: "stuff"})
|> Ash.Changeset.force_change_attribute(:post_id, post.id)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -332,13 +332,13 @@ defmodule AshGraphql.ReadTest do
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
for _ <- 0..1 do
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, %{text: "stuff"})
|> Ash.Changeset.force_change_attribute(:post_id, post.id)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
end
resp =
@ -424,7 +424,7 @@ defmodule AshGraphql.ReadTest do
test "a read with a loaded field works" do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -452,7 +452,7 @@ defmodule AshGraphql.ReadTest do
test "the same calculation can be loaded twice with different arguments via aliases" do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", text1: "1", text2: "2", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -475,11 +475,11 @@ defmodule AshGraphql.ReadTest do
test "the same calculation can be sorted on twice with different arguments via aliases" do
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", text1: "1", text2: "2", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", text1: "1", text2: "2", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -507,7 +507,7 @@ defmodule AshGraphql.ReadTest do
record =
AshGraphql.Test.NonIdPrimaryKey
|> Ash.Changeset.for_create(:create, %{})
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -535,7 +535,7 @@ defmodule AshGraphql.ReadTest do
record =
AshGraphql.Test.CompositePrimaryKeyNotEncoded
|> Ash.Changeset.for_create(:create, %{})
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -570,7 +570,7 @@ defmodule AshGraphql.ReadTest do
record =
AshGraphql.Test.CompositePrimaryKey
|> Ash.Changeset.for_create(:create, %{})
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -601,17 +601,17 @@ defmodule AshGraphql.ReadTest do
published: true,
score: 9.8
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Comment
|> Ash.Changeset.for_create(:create, %{text: "stuff"})
|> Ash.Changeset.force_change_attribute(:post_id, post.id)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -638,7 +638,7 @@ defmodule AshGraphql.ReadTest do
published: true,
foo: %{foo: "foo", bar: "bar"}
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -682,7 +682,7 @@ defmodule AshGraphql.ReadTest do
|> Ash.Changeset.for_create(:create,
name: "My Name"
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
doc = """
query CurrentUser {
@ -712,7 +712,7 @@ defmodule AshGraphql.ReadTest do
[name: "My Tag1"],
tenant: tenant
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
doc = """
query MultitenantTag($id: ID!) {
@ -746,7 +746,7 @@ defmodule AshGraphql.ReadTest do
[name: "My Tag"],
tenant: tenant
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post =
AshGraphql.Test.Post
@ -757,7 +757,7 @@ defmodule AshGraphql.ReadTest do
on_no_match: {:create, :create_action},
on_lookup: :relate
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
doc = """
query MultitenantPostTag($id: ID!) {
@ -798,7 +798,7 @@ defmodule AshGraphql.ReadTest do
:create,
name: "My Tag"
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post_1 =
AshGraphql.Test.Post
@ -809,7 +809,7 @@ defmodule AshGraphql.ReadTest do
on_no_match: {:create, :create_action},
on_lookup: :relate
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "bar", published: true)
@ -819,7 +819,7 @@ defmodule AshGraphql.ReadTest do
on_no_match: {:create, :create_action},
on_lookup: :relate
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
doc = """
query ($id: ID!) {
@ -847,8 +847,11 @@ defmodule AshGraphql.ReadTest do
describe "loading through types" do
test "loading through an embed works" do
AshGraphql.Test.Post
|> Ash.Changeset.new(embed_foo: %{type: "foo", foo: "fred"}, published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create,
embed_foo: %{foo: "fred"},
published: true
)
|> Ash.create!()
resp =
"""
@ -881,12 +884,20 @@ defmodule AshGraphql.ReadTest do
test "loading through a union works" do
AshGraphql.Test.Post
|> Ash.Changeset.new(text: "a", embed_union: %{type: :foo, foo: "fred"}, published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create,
text: "a",
embed_union: %{type: :foo, foo: "fred"},
published: true
)
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.new(text: "b", embed_union: %{type: :bar, bar: "george"}, published: true)
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create,
text: "b",
embed_union: %{type: :bar, bar: "george"},
published: true
)
|> Ash.create!()
resp =
"""
@ -937,20 +948,20 @@ defmodule AshGraphql.ReadTest do
test "loading through an unnested union works" do
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "a",
embed_union_unnested: %{type: :foo, foo: "fred"},
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "b",
embed_union_unnested: %{type: :bar, bar: "george"},
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -993,20 +1004,20 @@ defmodule AshGraphql.ReadTest do
test "loading through a list of unnested union with aliases works" do
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "a",
embed_union_new_type_list: [%{type: :foo, foo: "fred"}],
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "b",
embed_union_new_type_list: [%{type: :bar, bar: "george"}],
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -1055,20 +1066,20 @@ defmodule AshGraphql.ReadTest do
test "loading through an unnested union with aliases works" do
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "a",
embed_union_unnested: %{type: :foo, foo: "fred"},
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "b",
embed_union_unnested: %{type: :bar, bar: "george"},
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -1117,19 +1128,19 @@ defmodule AshGraphql.ReadTest do
test "loading through an unnested union with aliases works when one is nil" do
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "a",
embed_union_unnested: %{type: :foo, foo: "fred"},
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
AshGraphql.Test.Post
|> Ash.Changeset.new(
|> Ash.Changeset.for_create(:create,
text: "b",
published: true
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
resp =
"""
@ -1180,12 +1191,12 @@ defmodule AshGraphql.ReadTest do
user1 =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, %{name: "fred"})
|> AshGraphql.Test.Api.create!()
|> Ash.create!(authorize?: false)
user2 =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, %{name: "barney"})
|> AshGraphql.Test.Api.create!()
|> Ash.create!(authorize?: false)
post1 =
AshGraphql.Test.Post
@ -1197,7 +1208,7 @@ defmodule AshGraphql.ReadTest do
published: true
}
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post1 =
post1
@ -1208,7 +1219,7 @@ defmodule AshGraphql.ReadTest do
sponsored_comments: [%{text: "sponsored"}]
}
)
|> AshGraphql.Test.Api.update!()
|> Ash.update!()
resp =
"""
@ -1253,8 +1264,8 @@ defmodule AshGraphql.ReadTest do
test "loading relationships through an unnested union with aliases works" do
user =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, %{name: "fred"})
|> AshGraphql.Test.Api.create!()
|> Ash.Changeset.for_create(:create, %{name: "My Name"})
|> Ash.create!()
post =
AshGraphql.Test.Post
@ -1266,7 +1277,7 @@ defmodule AshGraphql.ReadTest do
published: true
}
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
post =
post
@ -1277,7 +1288,7 @@ defmodule AshGraphql.ReadTest do
sponsored_comments: [%{text: "sponsored"}]
}
)
|> AshGraphql.Test.Api.update!()
|> Ash.update!()
resp =
"""
@ -1340,12 +1351,12 @@ defmodule AshGraphql.ReadTest do
%{
"__typename" => "SponsoredComment",
"text" => "sponsored",
"p" => %{"id" => ^post_id, "user" => %{"name" => "fred"}}
"p" => %{"id" => ^post_id, "user" => %{"name" => "My Name"}}
},
%{
"__typename" => "Comment",
"text" => "comment",
"author" => %{"name" => "fred"}
"author" => %{"name" => "My Name"}
}
],
"bar" => [
@ -1357,7 +1368,7 @@ defmodule AshGraphql.ReadTest do
%{
"__typename" => "Comment",
"text" => "comment",
"author" => %{"name" => "fred"}
"author" => %{"name" => "My Name"}
}
]
}

View file

@ -1,7 +1,7 @@
defmodule AshGraphql.RelayIdsTest do
use ExUnit.Case, async: false
alias AshGraphql.Test.RelayIds.{Api, Post, ResourceWithNoPrimaryKeyGet, Schema, User}
alias AshGraphql.Test.RelayIds.{Post, ResourceWithNoPrimaryKeyGet, Schema, User}
setup do
on_exit(fn ->
@ -14,7 +14,7 @@ defmodule AshGraphql.RelayIdsTest do
user =
User
|> Ash.Changeset.for_create(:create, %{name: "fred"})
|> Api.create!()
|> Ash.create!()
post =
Post
@ -22,11 +22,10 @@ defmodule AshGraphql.RelayIdsTest do
:create,
%{
author_id: user.id,
text: "foo",
published: true
text: "foo"
}
)
|> Api.create!()
|> Ash.create!()
user_relay_id = AshGraphql.Resource.encode_relay_id(user)
post_relay_id = AshGraphql.Resource.encode_relay_id(post)
@ -79,14 +78,14 @@ defmodule AshGraphql.RelayIdsTest do
)
assert {:ok, result} = resp
assert [%{code: "invalid_primary_key"}] = result[:errors]
assert [%{message: "invalid primary key provided"}] = result[:errors]
end
test "returns error on ID for wrong resource" do
user =
User
|> Ash.Changeset.for_create(:create, %{name: "fred"})
|> Api.create!()
|> Ash.create!()
user_relay_id = AshGraphql.Resource.encode_relay_id(user)
@ -105,7 +104,7 @@ defmodule AshGraphql.RelayIdsTest do
)
assert {:ok, result} = resp
assert [%{code: "invalid_primary_key"}] = result[:errors]
assert [%{message: "invalid primary key provided"}] = result[:errors]
end
end
@ -114,7 +113,7 @@ defmodule AshGraphql.RelayIdsTest do
user =
User
|> Ash.Changeset.for_create(:create, %{name: "fred"})
|> Api.create!()
|> Ash.create!()
post =
Post
@ -122,11 +121,10 @@ defmodule AshGraphql.RelayIdsTest do
:create,
%{
author_id: user.id,
text: "foo",
published: true
text: "foo"
}
)
|> Api.create!()
|> Ash.create!()
user_relay_id = AshGraphql.Resource.encode_relay_id(user)
post_relay_id = AshGraphql.Resource.encode_relay_id(post)
@ -195,7 +193,7 @@ defmodule AshGraphql.RelayIdsTest do
resource =
ResourceWithNoPrimaryKeyGet
|> Ash.Changeset.for_create(:create, %{name: "foo"})
|> Api.create!()
|> Ash.create!()
document =
"""
@ -231,7 +229,7 @@ defmodule AshGraphql.RelayIdsTest do
user =
User
|> Ash.Changeset.for_create(:create, %{name: "Fred"})
|> Api.create!()
|> Ash.create!()
user_id = user.id
user_type = AshGraphql.Resource.Info.type(User)
@ -263,7 +261,7 @@ defmodule AshGraphql.RelayIdsTest do
author_id =
User
|> Ash.Changeset.for_create(:create, %{name: "Fred"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
resp =
@ -313,13 +311,13 @@ defmodule AshGraphql.RelayIdsTest do
author_id =
User
|> Ash.Changeset.for_create(:create, %{name: "Fred"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
post_id =
Post
|> Ash.Changeset.for_create(:create, %{text: "foo"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
resp =
@ -368,14 +366,14 @@ defmodule AshGraphql.RelayIdsTest do
author_id =
User
|> Ash.Changeset.for_create(:create, %{name: "Fred"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
post_ids =
Enum.map(1..5, fn i ->
Post
|> Ash.Changeset.for_create(:create, %{text: "foo #{i}"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
end)
@ -425,14 +423,14 @@ defmodule AshGraphql.RelayIdsTest do
author_id =
User
|> Ash.Changeset.for_create(:create, %{name: "Fred"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
post_ids =
Enum.map(1..5, fn i ->
Post
|> Ash.Changeset.for_create(:create, %{text: "foo #{i}"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
end)
@ -484,7 +482,7 @@ defmodule AshGraphql.RelayIdsTest do
author_id =
User
|> Ash.Changeset.for_create(:create, %{name: "Fred"})
|> Api.create!()
|> Ash.create!()
|> AshGraphql.Resource.encode_relay_id()
post_ids = [author_id]

View file

@ -20,7 +20,7 @@ defmodule AshGraphql.RelayTest do
:create,
name: name
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
for text <- letters do
AshGraphql.Test.Post
@ -31,7 +31,7 @@ defmodule AshGraphql.RelayTest do
on_no_match: :error,
on_lookup: :relate_and_update
)
|> AshGraphql.Test.Api.create!()
|> Ash.create!()
end
end
@ -796,7 +796,6 @@ defmodule AshGraphql.RelayTest do
%{
locations: [%{column: 3, line: 2}],
message: "Invalid value provided as a keyset for after: \"abc\"",
code: "invalid_keyset",
short_message: "invalid keyset",
path: ["getRelayTags"]
}
@ -833,7 +832,6 @@ defmodule AshGraphql.RelayTest do
%{
locations: [%{column: 3, line: 2}],
message: "Invalid value provided as a keyset for before: \"abc\"",
code: "invalid_keyset",
short_message: "invalid keyset",
path: ["getRelayTags"]
}

View file

@ -1,13 +0,0 @@
defmodule AshGraphql.Test.Api do
@moduledoc false
use Ash.Api,
extensions: [
AshGraphql.Api
],
otp_app: :ash_graphql
resources do
registry(AshGraphql.Test.Registry)
end
end

34
test/support/domain.ex Normal file
View file

@ -0,0 +1,34 @@
defmodule AshGraphql.Test.Domain do
@moduledoc false
use Ash.Domain,
extensions: [
AshGraphql.Domain
],
otp_app: :ash_graphql
resources do
resource(AshGraphql.Test.Comment)
resource(AshGraphql.Test.CompositePrimaryKey)
resource(AshGraphql.Test.CompositePrimaryKeyNotEncoded)
resource(AshGraphql.Test.DoubleRelRecursive)
resource(AshGraphql.Test.DoubleRelToRecursiveParentOfEmbed)
resource(AshGraphql.Test.MapTypes)
resource(AshGraphql.Test.MultitenantPostTag)
resource(AshGraphql.Test.MultitenantTag)
resource(AshGraphql.Test.NoGraphql)
resource(AshGraphql.Test.NoObject)
resource(AshGraphql.Test.NonIdPrimaryKey)
resource(AshGraphql.Test.Post)
resource(AshGraphql.Test.PostTag)
resource(AshGraphql.Test.RelayPostTag)
resource(AshGraphql.Test.RelayTag)
resource(AshGraphql.Test.SponsoredComment)
resource(AshGraphql.Test.Tag)
resource(AshGraphql.Test.User)
resource(AshGraphql.Test.Channel)
resource(AshGraphql.Test.Message)
resource(AshGraphql.Test.TextMessage)
resource(AshGraphql.Test.ImageMessage)
end
end

View file

@ -1,6 +1,7 @@
defmodule Foo do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: :embedded,
extensions: [
AshGraphql.Resource
@ -12,24 +13,27 @@ defmodule Foo do
attributes do
attribute :type, :atom do
public?(true)
constraints(one_of: [:foo])
writable?(false)
end
attribute :foo, :string do
public?(true)
allow_nil? false
end
end
calculations do
calculate(:always_true, :boolean, expr(true))
calculate(:always_nil, :boolean, expr(nil))
calculate(:always_true, :boolean, expr(true), public?: true)
calculate(:always_nil, :boolean, expr(nil), public?: true)
end
end
defmodule Bar do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: :embedded,
extensions: [
AshGraphql.Resource
@ -41,17 +45,19 @@ defmodule Bar do
attributes do
attribute :type, :atom do
public?(true)
constraints(one_of: [:foo])
writable?(false)
end
attribute :bar, :string do
public?(true)
allow_nil? false
end
end
calculations do
calculate(:always_true, :boolean, expr(true))
calculate(:always_false, :boolean, expr(false))
calculate(:always_true, :boolean, expr(true), public?: true)
calculate(:always_false, :boolean, expr(false), public?: true)
end
end

View file

@ -1,29 +0,0 @@
defmodule AshGraphql.Test.Registry do
@moduledoc false
use Ash.Registry
entries do
entry(AshGraphql.Test.Comment)
entry(AshGraphql.Test.CompositePrimaryKey)
entry(AshGraphql.Test.CompositePrimaryKeyNotEncoded)
entry(AshGraphql.Test.DoubleRelRecursive)
entry(AshGraphql.Test.DoubleRelToRecursiveParentOfEmbed)
entry(AshGraphql.Test.MapTypes)
entry(AshGraphql.Test.MultitenantPostTag)
entry(AshGraphql.Test.MultitenantTag)
entry(AshGraphql.Test.NoGraphql)
entry(AshGraphql.Test.NoObject)
entry(AshGraphql.Test.NonIdPrimaryKey)
entry(AshGraphql.Test.Post)
entry(AshGraphql.Test.PostTag)
entry(AshGraphql.Test.RelayPostTag)
entry(AshGraphql.Test.RelayTag)
entry(AshGraphql.Test.SponsoredComment)
entry(AshGraphql.Test.Tag)
entry(AshGraphql.Test.User)
entry(AshGraphql.Test.Channel)
entry(AshGraphql.Test.Message)
entry(AshGraphql.Test.TextMessage)
entry(AshGraphql.Test.ImageMessage)
end
end

View file

@ -1,13 +0,0 @@
defmodule AshGraphql.Test.RelayIds.Api do
@moduledoc false
use Ash.Api,
extensions: [
AshGraphql.Api
],
otp_app: :ash_graphql
resources do
registry(AshGraphql.Test.RelayIds.Registry)
end
end

View file

@ -0,0 +1,15 @@
defmodule AshGraphql.Test.RelayIds.Domain do
@moduledoc false
use Ash.Domain,
extensions: [
AshGraphql.Domain
],
otp_app: :ash_graphql
resources do
resource(AshGraphql.Test.RelayIds.Post)
resource(AshGraphql.Test.RelayIds.ResourceWithNoPrimaryKeyGet)
resource(AshGraphql.Test.RelayIds.User)
end
end

View file

@ -1,10 +0,0 @@
defmodule AshGraphql.Test.RelayIds.Registry do
@moduledoc false
use Ash.Registry
entries do
entry(AshGraphql.Test.RelayIds.Post)
entry(AshGraphql.Test.RelayIds.ResourceWithNoPrimaryKeyGet)
entry(AshGraphql.Test.RelayIds.User)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.RelayIds.Post do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.RelayIds.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -24,6 +25,7 @@ defmodule AshGraphql.Test.RelayIds.Post do
end
actions do
default_accept(:*)
defaults([:update, :read, :destroy])
create :create do
@ -42,11 +44,12 @@ defmodule AshGraphql.Test.RelayIds.Post do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:text, :string, public?: true)
end
relationships do
belongs_to(:author, AshGraphql.Test.RelayIds.User) do
public?(true)
attribute_writable?(true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.RelayIds.ResourceWithNoPrimaryKeyGet do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.RelayIds.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -18,6 +19,7 @@ defmodule AshGraphql.Test.RelayIds.ResourceWithNoPrimaryKeyGet do
end
actions do
default_accept(:*)
defaults([:create, :update, :destroy, :read])
read(:get_by_name, get_by: :name)
@ -25,14 +27,17 @@ defmodule AshGraphql.Test.RelayIds.ResourceWithNoPrimaryKeyGet do
attributes do
uuid_primary_key(:id)
attribute(:name, :string, allow_nil?: false)
attribute(:name, :string, allow_nil?: false, public?: true)
end
identities do
identity(:name, [:name], pre_check_with: AshGraphql.Test.RelayIds.Api)
identity(:name, [:name], pre_check_with: AshGraphql.Test.RelayIds.Domain)
end
relationships do
has_many(:posts, AshGraphql.Test.RelayIds.Post, destination_attribute: :author_id)
has_many(:posts, AshGraphql.Test.RelayIds.Post,
destination_attribute: :author_id,
public?: true
)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.RelayIds.User do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.RelayIds.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -19,6 +20,7 @@ defmodule AshGraphql.Test.RelayIds.User do
end
actions do
default_accept(:*)
defaults([:create, :update, :destroy, :read])
update :assign_posts do
@ -30,10 +32,13 @@ defmodule AshGraphql.Test.RelayIds.User do
attributes do
uuid_primary_key(:id)
attribute(:name, :string)
attribute(:name, :string, public?: true)
end
relationships do
has_many(:posts, AshGraphql.Test.RelayIds.Post, destination_attribute: :author_id)
has_many(:posts, AshGraphql.Test.RelayIds.Post,
destination_attribute: :author_id,
public?: true
)
end
end

View file

@ -3,9 +3,9 @@ defmodule AshGraphql.Test.RelayIds.Schema do
use Absinthe.Schema
@apis [AshGraphql.Test.RelayIds.Api]
@domains [AshGraphql.Test.RelayIds.Domain]
use AshGraphql, apis: @apis, relay_ids?: true
use AshGraphql, domains: @domains, relay_ids?: true
query do
end

View file

@ -1,20 +1,24 @@
defmodule AshGraphql.Test.PageOfChannelMessagesCalculation do
@moduledoc false
use Ash.Calculation
use Ash.Resource.Calculation
def load(_, _, context) do
limit = context[:limit] || 100
offset = context[:offset] || 0
limit = context.arguments.limit || 100
offset = context.arguments.offset || 0
[
:channel_message_count,
messages: AshGraphql.Test.Message |> Ash.Query.limit(limit) |> Ash.Query.offset(offset)
messages:
AshGraphql.Test.Message
|> Ash.Query.limit(limit)
|> Ash.Query.offset(offset)
|> Ash.Query.select([:type, :text])
]
end
def calculate([post], _, context) do
limit = context[:limit] || 100
offset = context[:offset] || 0
limit = context.arguments.limit || 100
offset = context.arguments.offset || 0
{:ok,
[

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.Channel do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -16,6 +17,8 @@ defmodule AshGraphql.Test.Channel do
end
actions do
default_accept(:*)
create :create do
primary?(true)
end
@ -30,30 +33,32 @@ defmodule AshGraphql.Test.Channel do
attributes do
uuid_primary_key(:id)
create_timestamp(:created_at, private?: false)
create_timestamp(:created_at, public?: true)
end
calculations do
calculate(
:direct_channel_messages,
{:array, AshGraphql.Test.MessageUnion},
fn record,
%{
api: api
} ->
record = api.load!(record, :messages)
fn records, _ ->
records = Ash.load!(records, :messages)
{:ok,
record.messages
|> Enum.map(
&%Ash.Union{type: AshGraphql.Test.MessageUnion.struct_to_name(&1), value: &1}
)}
end
Enum.map(records, fn record ->
record.messages
|> Enum.map(
&%Ash.Union{type: AshGraphql.Test.MessageUnion.struct_to_name(&1), value: &1}
)
end)}
end,
public?: true
)
calculate :indirect_channel_messages,
AshGraphql.Test.PageOfChannelMessages,
AshGraphql.Test.PageOfChannelMessagesCalculation do
public?(true)
argument :offset, :integer do
default(0)
end
@ -65,10 +70,10 @@ defmodule AshGraphql.Test.Channel do
end
aggregates do
count(:channel_message_count, :messages)
count(:channel_message_count, :messages, public?: true)
end
relationships do
has_many(:messages, AshGraphql.Test.Message)
has_many(:messages, AshGraphql.Test.Message, public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.ImageMessage do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -18,6 +19,7 @@ defmodule AshGraphql.Test.ImageMessage do
end
actions do
default_accept(:*)
defaults([:read, :update, :destroy])
create :create do
@ -28,12 +30,16 @@ defmodule AshGraphql.Test.ImageMessage do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:text, :string, public?: true)
attribute(:type, :atom, default: :image, constraints: [one_of: [:text, :image]])
attribute(:type, :atom,
default: :image,
constraints: [one_of: [:text, :image]],
public?: true
)
end
relationships do
belongs_to(:channel, AshGraphql.Test.Channel)
belongs_to(:channel, AshGraphql.Test.Channel, public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.Message do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets
# extensions: [AshGraphql.Resource]
@ -11,6 +12,7 @@ defmodule AshGraphql.Test.Message do
end
actions do
default_accept(:*)
defaults([:read, :update, :destroy])
create :create do
@ -21,13 +23,13 @@ defmodule AshGraphql.Test.Message do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:text, :string, public?: true)
attribute(:type, :atom, default: :text, constraints: [one_of: [:text, :image]])
attribute(:type, :atom, default: :text, constraints: [one_of: [:text, :image]], public?: true)
end
relationships do
belongs_to(:channel, AshGraphql.Test.Channel)
belongs_to(:channel, AshGraphql.Test.Channel, public?: true)
end
# graphql do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.TextMessage do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -18,6 +19,7 @@ defmodule AshGraphql.Test.TextMessage do
end
actions do
default_accept(:*)
defaults([:read, :update, :destroy])
create :create do
@ -28,12 +30,12 @@ defmodule AshGraphql.Test.TextMessage do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:text, :string, public?: true)
attribute(:type, :atom, default: :text, constraints: [one_of: [:text, :image]])
attribute(:type, :atom, default: :text, constraints: [one_of: [:text, :image]], public?: true)
end
relationships do
belongs_to(:channel, AshGraphql.Test.Channel)
belongs_to(:channel, AshGraphql.Test.Channel, public?: true)
end
end

View file

@ -3,12 +3,14 @@ defmodule AshGraphql.Test.MessageUnion do
@types [
text: [
type: AshGraphql.Test.TextMessage,
type: :struct,
constraints: [instance_of: AshGraphql.Test.TextMessage],
tag: :type,
tag_value: :text_message
],
image: [
type: AshGraphql.Test.ImageMessage,
type: :struct,
constraints: [instance_of: AshGraphql.Test.ImageMessage],
tag: :type,
tag_value: :image_message
]

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.Comment do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -19,6 +20,7 @@ defmodule AshGraphql.Test.Comment do
end
actions do
default_accept(:*)
defaults([:create, :update, :destroy])
read :read do
@ -32,9 +34,10 @@ defmodule AshGraphql.Test.Comment do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:text, :string, public?: true)
attribute :type, :atom do
public?(true)
writable?(false)
default(:comment)
constraints(one_of: [:comment, :reply])
@ -47,14 +50,16 @@ defmodule AshGraphql.Test.Comment do
calculate(
:timestamp,
:utc_datetime_usec,
expr(created_at)
expr(created_at),
public?: true
)
end
relationships do
belongs_to(:post, AshGraphql.Test.Post)
belongs_to(:post, AshGraphql.Test.Post, public?: true)
belongs_to :author, AshGraphql.Test.User do
public?(true)
attribute_writable?(true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.CompositePrimaryKey do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.CompositePrimaryKeyNotEncoded do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.DoubleRelEmbed do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: :embedded,
extensions: [AshGraphql.Resource]
@ -10,6 +11,6 @@ defmodule AshGraphql.Test.DoubleRelEmbed do
end
attributes do
attribute(:recursive, :string, default: "No, not I, but me dad be!")
attribute(:recursive, :string, default: "No, not I, but me dad be!", public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.DoubleRelRecursive do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -12,12 +13,13 @@ defmodule AshGraphql.Test.DoubleRelRecursive do
attributes do
uuid_primary_key(:id)
attribute(:type, DoubleRelType, allow_nil?: true)
attribute(:this, :string, allow_nil?: true)
attribute(:or_that, DoubleRelEmbed, allow_nil?: true)
attribute(:type, DoubleRelType, allow_nil?: true, public?: true)
attribute(:this, :string, allow_nil?: true, public?: true)
attribute(:or_that, DoubleRelEmbed, allow_nil?: true, public?: true)
end
actions do
default_accept(:*)
defaults([:create, :read, :update, :destroy])
end
@ -27,6 +29,7 @@ defmodule AshGraphql.Test.DoubleRelRecursive do
relationships do
belongs_to :double_rel, DoubleRelToRecursiveParentOfEmbed do
public?(true)
source_attribute(:double_rel_id)
allow_nil?(false)
end
@ -34,15 +37,17 @@ defmodule AshGraphql.Test.DoubleRelRecursive do
belongs_to :myself, DoubleRelRecursive do
source_attribute(:recursive_id)
allow_nil?(false)
private?(true)
public?(true)
end
has_many :first_rel, DoubleRelRecursive do
public?(true)
destination_attribute(:recursive_id)
filter(expr(type == :first))
end
has_many :second_rel, DoubleRelRecursive do
public?(true)
destination_attribute(:recursive_id)
filter(expr(type == :second))
end

View file

@ -2,12 +2,14 @@ defmodule AshGraphql.Test.DoubleRelToRecursiveParentOfEmbed do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
alias AshGraphql.Test.DoubleRelRecursive
actions do
default_accept(:*)
defaults([:read, :create, :update, :destroy])
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.Embed do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: :embedded,
extensions: [AshGraphql.Resource]
@ -10,6 +11,6 @@ defmodule AshGraphql.Test.Embed do
end
attributes do
attribute(:nested_embed, AshGraphql.Test.NestedEmbed)
attribute(:nested_embed, AshGraphql.Test.NestedEmbed, public?: true)
end
end

View file

@ -1,6 +1,7 @@
defmodule AshGraphql.Test.MapTypes do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -24,15 +25,19 @@ defmodule AshGraphql.Test.MapTypes do
)
allow_nil? false
public?(true)
end
attribute(:json_map, :map)
attribute(:json_map, :map, public?: true)
attribute :values, AshGraphql.Test.ConstrainedMap do
public?(true)
end
end
actions do
default_accept(:*)
defaults([:create, :read, :update, :destroy])
update :inline do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.MultitenantPostTag do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets
actions do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.MultitenantTag do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -24,6 +25,7 @@ defmodule AshGraphql.Test.MultitenantTag do
end
actions do
default_accept(:*)
defaults([:read, :update, :destroy])
create :create do
@ -34,18 +36,19 @@ defmodule AshGraphql.Test.MultitenantTag do
attributes do
uuid_primary_key(:id)
attribute(:name, :string)
attribute(:name, :string, public?: true)
end
identities do
identity(:name, [:name], pre_check_with: AshGraphql.Test.Api)
identity(:name, [:name], pre_check_with: AshGraphql.Test.Domain)
end
relationships do
many_to_many(:posts, AshGraphql.Test.Post,
through: AshGraphql.Test.MultitenantPostTag,
source_attribute_on_join_resource: :tag_id,
destination_attribute_on_join_resource: :post_id
destination_attribute_on_join_resource: :post_id,
public?: true
)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.NestedEmbed do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: :embedded,
extensions: [AshGraphql.Resource]
@ -10,7 +11,7 @@ defmodule AshGraphql.Test.NestedEmbed do
end
attributes do
attribute(:name, :string)
attribute(:enum, AshGraphql.Test.NestedEnum)
attribute(:name, :string, public?: true)
attribute(:enum, AshGraphql.Test.NestedEnum, public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.NoGraphql do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets
attributes do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.NoObject do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -26,6 +27,6 @@ defmodule AshGraphql.Test.NoObject do
attributes do
uuid_primary_key(:id)
attribute(:name, :string)
attribute(:name, :string, public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.NonIdPrimaryKey do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]

View file

@ -36,7 +36,7 @@ end
defmodule FullTextCalculation do
@moduledoc false
use Ash.Calculation
use Ash.Resource.Calculation
def calculate(posts, _, _) do
Enum.map(posts, fn post ->
@ -44,7 +44,7 @@ defmodule FullTextCalculation do
end)
end
def select(_, _, _), do: [:text1, :text2]
def load(_, _, _), do: [:text1, :text2]
end
defmodule AfterActionRaiseResourceError do
@ -63,8 +63,8 @@ defmodule RelatedPosts do
use Ash.Resource.ManualRelationship
require Ash.Query
def load(posts, _opts, %{api: api}) do
posts = api.load!(posts, :tags)
def load(posts, _opts, %{domain: domain}) do
posts = domain.load!(posts, :tags)
{
:ok,
@ -78,7 +78,7 @@ defmodule RelatedPosts do
AshGraphql.Test.Post
|> Ash.Query.filter(tags.id in ^tag_ids)
|> Ash.Query.filter(id != ^post.id)
|> api.read!()
|> Ash.read!()
{post.id, other_posts}
end)
@ -93,6 +93,7 @@ defmodule AshGraphql.Test.Post do
alias AshGraphql.Test.SponsoredComment
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
authorizers: [Ash.Policy.Authorizer],
extensions: [AshGraphql.Resource]
@ -112,8 +113,8 @@ defmodule AshGraphql.Test.Post do
graphql do
type :post
attribute_types integer_as_string_in_api: :string
attribute_input_types integer_as_string_in_api: :string
attribute_types integer_as_string_in_domain: :string
attribute_input_types integer_as_string_in_domain: :string
field_names text_1_and_2: :text1_and2
keyset_field :keyset
@ -172,6 +173,8 @@ defmodule AshGraphql.Test.Post do
end
actions do
default_accept(:*)
create :create do
primary?(true)
metadata(:foo, :string)
@ -206,7 +209,7 @@ defmodule AshGraphql.Test.Post do
__MODULE__
end
input.api.count(query)
input.domain.count(query)
end)
end
@ -218,7 +221,7 @@ defmodule AshGraphql.Test.Post do
run(fn input, _ ->
__MODULE__
|> Ash.Query.limit(1)
|> input.api.read_one()
|> input.domain.read_one()
end)
end
@ -324,20 +327,24 @@ defmodule AshGraphql.Test.Post do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:published, :boolean, default: false)
attribute(:foo, AshGraphql.Test.Foo)
attribute(:status, AshGraphql.Test.Status)
attribute(:status_enum, AshGraphql.Test.StatusEnum)
attribute(:enum_with_ash_graphql_description, AshGraphql.Test.EnumWithAshGraphqlDescription)
attribute(:enum_with_ash_description, AshGraphql.Test.EnumWithAshDescription)
attribute(:best, :boolean)
attribute(:score, :float)
attribute(:integer_as_string_in_api, :integer)
attribute(:embed, AshGraphql.Test.Embed)
attribute(:text1, :string)
attribute(:text2, :string)
attribute(:visibility, :atom, constraints: [one_of: [:public, :private]])
attribute(:text, :string, public?: true)
attribute(:published, :boolean, default: false, public?: true)
attribute(:foo, AshGraphql.Test.Foo, public?: true)
attribute(:status, AshGraphql.Test.Status, public?: true)
attribute(:status_enum, AshGraphql.Test.StatusEnum, public?: true)
attribute(:enum_with_ash_graphql_description, AshGraphql.Test.EnumWithAshGraphqlDescription,
public?: true
)
attribute(:enum_with_ash_description, AshGraphql.Test.EnumWithAshDescription, public?: true)
attribute(:best, :boolean, public?: true)
attribute(:score, :float, public?: true)
attribute(:integer_as_string_in_domain, :integer, public?: true)
attribute(:embed, AshGraphql.Test.Embed, public?: true)
attribute(:text1, :string, public?: true)
attribute(:text2, :string, public?: true)
attribute(:visibility, :atom, constraints: [one_of: [:public, :private]], public?: true)
attribute(:simple_union, :union,
constraints: [
@ -349,10 +356,11 @@ defmodule AshGraphql.Test.Post do
type: :string
]
]
]
],
public?: true
)
attribute(:embed_foo, Foo)
attribute(:embed_foo, Foo, public?: true)
attribute(:embed_union, :union,
constraints: [
@ -368,90 +376,110 @@ defmodule AshGraphql.Test.Post do
tag_value: :bar
]
]
]
],
public?: true
)
attribute(:embed_union_new_type_list, {:array, AshGraphql.Types.EmbedUnionNewTypeUnnested})
attribute(:embed_union_new_type, AshGraphql.Types.EmbedUnionNewType)
attribute(:embed_union_unnested, AshGraphql.Types.EmbedUnionNewTypeUnnested)
attribute(:enum_new_type, AshGraphql.Types.EnumNewType)
attribute(:string_new_type, AshGraphql.Types.StringNewType)
attribute(:embed_union_new_type_list, {:array, AshGraphql.Types.EmbedUnionNewTypeUnnested},
public?: true
)
attribute(:embed_union_new_type, AshGraphql.Types.EmbedUnionNewType, public?: true)
attribute(:embed_union_unnested, AshGraphql.Types.EmbedUnionNewTypeUnnested, public?: true)
attribute(:enum_new_type, AshGraphql.Types.EnumNewType, public?: true)
attribute(:string_new_type, AshGraphql.Types.StringNewType, public?: true)
attribute :required_string, :string do
allow_nil? false
default("test")
public?(true)
end
create_timestamp(:created_at, private?: false)
create_timestamp(:created_at, public?: true)
end
calculations do
calculate(:static_calculation, :string, AshGraphql.Test.StaticCalculation)
calculate(:full_text, :string, FullTextCalculation)
calculate(:static_calculation, :string, AshGraphql.Test.StaticCalculation, public?: true)
calculate(:full_text, :string, FullTextCalculation, public?: true)
calculate(:text_1_and_2, :string, expr(text1 <> ^arg(:separator) <> text2)) do
public?(true)
argument :separator, :string do
allow_nil? false
default(" ")
end
end
calculate(:post_comments, {:array, UnionRelation}, fn record, _ ->
# This is very inefficient, do not copy this pattern into your own app!!!
values =
[
SponsoredComment |> AshGraphql.Test.Api.read!(),
Comment |> AshGraphql.Test.Api.read!()
]
|> List.flatten()
|> Stream.filter(&(&1.post_id == record.id))
|> Enum.map(&%Ash.Union{type: UnionRelation.struct_to_name(&1), value: &1})
calculate(
:post_comments,
{:array, UnionRelation},
fn records, _ ->
# This is very inefficient, do not copy this pattern into your own app!!!
values =
Enum.map(records, fn record ->
[
SponsoredComment |> Ash.read!(),
Comment |> Ash.read!()
]
|> List.flatten()
|> Stream.filter(&(&1.post_id == record.id))
|> Enum.map(&%Ash.Union{type: UnionRelation.struct_to_name(&1), value: &1})
end)
{:ok, values}
end)
{:ok, values}
end,
public?: true
)
end
aggregates do
count(:comment_count, :comments)
max(:latest_comment_at, [:comments], :timestamp)
count(:comment_count, :comments, public?: true)
max(:latest_comment_at, [:comments], :timestamp, public?: true)
first :latest_comment_type, [:comments], :type do
public?(true)
sort(timestamp: :desc)
end
end
relationships do
belongs_to(:author, AshGraphql.Test.User) do
public?(true)
attribute_writable?(true)
end
has_many(:comments, AshGraphql.Test.Comment)
has_many(:sponsored_comments, AshGraphql.Test.SponsoredComment)
has_many(:paginated_comments, AshGraphql.Test.Comment, read_action: :paginated)
has_many(:comments, AshGraphql.Test.Comment, public?: true)
has_many(:sponsored_comments, AshGraphql.Test.SponsoredComment, public?: true)
has_many(:paginated_comments, AshGraphql.Test.Comment, read_action: :paginated, public?: true)
many_to_many(:tags, AshGraphql.Test.Tag,
through: AshGraphql.Test.PostTag,
source_attribute_on_join_resource: :post_id,
destination_attribute_on_join_resource: :tag_id
destination_attribute_on_join_resource: :tag_id,
public?: true
)
many_to_many(:multitenant_tags, AshGraphql.Test.MultitenantTag,
through: AshGraphql.Test.MultitenantPostTag,
source_attribute_on_join_resource: :post_id,
destination_attribute_on_join_resource: :tag_id
destination_attribute_on_join_resource: :tag_id,
public?: true
)
many_to_many(:relay_tags, AshGraphql.Test.RelayTag,
through: AshGraphql.Test.RelayPostTag,
source_attribute_on_join_resource: :post_id,
destination_attribute_on_join_resource: :tag_id
destination_attribute_on_join_resource: :tag_id,
public?: true
)
has_many :related_posts, AshGraphql.Test.Post do
public?(true)
manual(RelatedPosts)
no_attributes?(true)
end
has_one(:no_graphql, AshGraphql.Test.NoGraphql)
has_one(:no_graphql, AshGraphql.Test.NoGraphql, public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.PostTag do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets
actions do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.RelayPostTag do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets
actions do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.RelayTag do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -20,6 +21,7 @@ defmodule AshGraphql.Test.RelayTag do
end
actions do
default_accept(:*)
defaults([:create, :update, :destroy, :read])
read :read_paginated do
@ -30,11 +32,11 @@ defmodule AshGraphql.Test.RelayTag do
attributes do
uuid_primary_key(:id)
attribute(:name, :string)
attribute(:name, :string, public?: true)
end
identities do
identity(:name, [:name], pre_check_with: AshGraphql.Test.Api)
identity(:name, [:name], pre_check_with: AshGraphql.Test.Domain)
end
relationships do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.SponsoredComment do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -18,6 +19,7 @@ defmodule AshGraphql.Test.SponsoredComment do
end
actions do
default_accept(:*)
defaults([:create, :update, :destroy])
read :read do
@ -31,15 +33,16 @@ defmodule AshGraphql.Test.SponsoredComment do
attributes do
uuid_primary_key(:id)
attribute(:text, :string)
attribute(:text, :string, public?: true)
attribute :type, :atom do
public?(true)
writable?(false)
default(:sponsored)
end
end
relationships do
belongs_to(:post, AshGraphql.Test.Post)
belongs_to(:post, AshGraphql.Test.Post, public?: true)
end
end

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.Tag do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshGraphql.Resource]
@ -20,6 +21,7 @@ defmodule AshGraphql.Test.Tag do
end
actions do
default_accept(:*)
defaults([:read, :update, :destroy])
create :create do
@ -30,11 +32,11 @@ defmodule AshGraphql.Test.Tag do
attributes do
uuid_primary_key(:id)
attribute(:name, :string)
attribute(:name, :string, public?: true)
end
identities do
identity(:name, [:name], pre_check_with: AshGraphql.Test.Api)
identity(:name, [:name], pre_check_with: AshGraphql.Test.Domain)
end
relationships do

View file

@ -2,6 +2,7 @@ defmodule AshGraphql.Test.User do
@moduledoc false
use Ash.Resource,
domain: AshGraphql.Test.Domain,
data_layer: Ash.DataLayer.Ets,
authorizers: [Ash.Policy.Authorizer],
extensions: [AshGraphql.Resource]
@ -25,12 +26,14 @@ defmodule AshGraphql.Test.User do
end
actions do
default_accept(:*)
defaults([:create, :update, :destroy, :read])
create(:create_policies)
read :current_user do
filter(id: actor(:id))
filter(expr(id == ^actor(:id)))
end
read :current_user_with_metadata do
@ -50,20 +53,21 @@ defmodule AshGraphql.Test.User do
attributes do
uuid_primary_key(:id)
attribute(:name, :string)
attribute(:name, :string, public?: true)
attribute(:secret, :string) do
public?(true)
allow_nil? false
default("super secret")
end
end
relationships do
has_many(:posts, AshGraphql.Test.Post, destination_attribute: :author_id)
has_many(:posts, AshGraphql.Test.Post, destination_attribute: :author_id, public?: true)
end
calculations do
calculate(:name_twice, :string, expr(name <> " " <> name))
calculate(:name_twice, :string, expr(name <> " " <> name), public?: true)
end
policies do

View file

@ -1,17 +0,0 @@
defmodule AshGraphql.Test.RootLevelErrorsApi do
@moduledoc false
use Ash.Api,
extensions: [
AshGraphql.Api
],
otp_app: :ash_graphql
graphql do
root_level_errors? true
end
resources do
registry(AshGraphql.Test.Registry)
end
end

View file

@ -0,0 +1,38 @@
defmodule AshGraphql.Test.RootLevelErrorsDomain do
@moduledoc false
use Ash.Domain,
extensions: [
AshGraphql.Domain
],
otp_app: :ash_graphql
graphql do
root_level_errors? true
end
resources do
resource(AshGraphql.Test.Comment)
resource(AshGraphql.Test.CompositePrimaryKey)
resource(AshGraphql.Test.CompositePrimaryKeyNotEncoded)
resource(AshGraphql.Test.DoubleRelRecursive)
resource(AshGraphql.Test.DoubleRelToRecursiveParentOfEmbed)
resource(AshGraphql.Test.MapTypes)
resource(AshGraphql.Test.MultitenantPostTag)
resource(AshGraphql.Test.MultitenantTag)
resource(AshGraphql.Test.NoGraphql)
resource(AshGraphql.Test.NoObject)
resource(AshGraphql.Test.NonIdPrimaryKey)
resource(AshGraphql.Test.Post)
resource(AshGraphql.Test.PostTag)
resource(AshGraphql.Test.RelayPostTag)
resource(AshGraphql.Test.RelayTag)
resource(AshGraphql.Test.SponsoredComment)
resource(AshGraphql.Test.Tag)
resource(AshGraphql.Test.User)
resource(AshGraphql.Test.Channel)
resource(AshGraphql.Test.Message)
resource(AshGraphql.Test.TextMessage)
resource(AshGraphql.Test.ImageMessage)
end
end

View file

@ -3,9 +3,9 @@ defmodule AshGraphql.Test.RootLevelErrorsSchema do
use Absinthe.Schema
@apis [AshGraphql.Test.RootLevelErrorsApi]
@domains [AshGraphql.Test.RootLevelErrorsDomain]
use AshGraphql, apis: @apis
use AshGraphql, domains: @domains
query do
end

View file

@ -3,9 +3,9 @@ defmodule AshGraphql.Test.Schema do
use Absinthe.Schema
@apis [AshGraphql.Test.Api]
@domains [AshGraphql.Test.Domain]
use AshGraphql, apis: @apis
use AshGraphql, domains: @domains
query do
end

View file

@ -1,6 +1,6 @@
defmodule AshGraphql.Test.StaticCalculation do
@moduledoc false
use Ash.Calculation, type: :string
use Ash.Resource.Calculation, type: :string
def calculate(records, _, _) do
Enum.map(records, fn _ -> "static" end)

View file

@ -3,7 +3,7 @@ defmodule AshGraphql.TestHelpers do
require Logger
def stop_ets do
for resource <- Ash.Registry.Info.entries(AshGraphql.Test.Registry) do
for resource <- Ash.Domain.Info.resources(AshGraphql.Test.Domain) do
try do
Ash.DataLayer.Ets.stop(resource)
rescue

View file

@ -4,18 +4,22 @@ defmodule UnionRelation do
@types [
comment: [
type: Comment,
type: :struct,
constraints: [instance_of: Comment],
tag: :type,
tag_value: :comment
],
sponsored_comment: [
type: SponsoredComment,
type: :struct,
constraints: [instance_of: SponsoredComment],
tag: :type,
tag_value: :sponsored
]
]
@structs_to_names Keyword.new(@types, fn {key, value} -> {value[:type], key} end)
@structs_to_names Keyword.new(@types, fn {key, value} ->
{value[:constraints][:instance_of], key}
end)
use Ash.Type.NewType,
subtype_of: :union,

View file

@ -1,3 +1,3 @@
ExUnit.start()
Code.ensure_compiled(AshGraphql.Test.Api)
Code.ensure_compiled(AshGraphql.Test.Domain)

View file

@ -3,7 +3,7 @@ defmodule AshGraphql.UpdateTest do
setup do
on_exit(fn ->
Application.delete_env(:ash_graphql, AshGraphql.Test.Api)
Application.delete_env(:ash_graphql, AshGraphql.Test.Domain)
try do
AshGraphql.TestHelpers.stop_ets()
@ -15,7 +15,10 @@ defmodule AshGraphql.UpdateTest do
end
test "an update works" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar")
|> Ash.create!()
resp =
"""
@ -137,9 +140,9 @@ defmodule AshGraphql.UpdateTest do
test "an update with a configured read action and no identity works" do
post =
AshGraphql.Test.Api.create!(
Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar", best: true)
)
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -169,9 +172,9 @@ defmodule AshGraphql.UpdateTest do
end
test "an update with a configured read action and no identity works with an argument the same name as an attribute" do
AshGraphql.Test.Api.create!(
Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar", best: true)
)
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -203,9 +206,9 @@ defmodule AshGraphql.UpdateTest do
test "arguments are threaded properly" do
post =
AshGraphql.Test.Api.create!(
Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar", best: true)
)
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -242,14 +245,14 @@ defmodule AshGraphql.UpdateTest do
end
test "root level error" do
Application.put_env(:ash_graphql, AshGraphql.Test.Api,
Application.put_env(:ash_graphql, AshGraphql.Test.Domain,
graphql: [show_raised_errors?: true, root_level_errors?: true]
)
post =
AshGraphql.Test.Api.create!(
Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar", best: true)
)
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar", best: true)
|> Ash.create!()
resp =
"""
@ -282,7 +285,10 @@ defmodule AshGraphql.UpdateTest do
end
test "referencing a hidden input is not allowed" do
post = AshGraphql.Test.Api.create!(Ash.Changeset.new(AshGraphql.Test.Post, text: "foobar"))
post =
AshGraphql.Test.Post
|> Ash.Changeset.for_create(:create, text: "foobar")
|> Ash.create!()
resp =
"""