Skip to content

Commit

Permalink
improvement!: port AshGraphql to Ash 3.0
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rbino committed Mar 30, 2024
1 parent 9674614 commit 74d870a
Show file tree
Hide file tree
Showing 87 changed files with 1,037 additions and 869 deletions.
4 changes: 2 additions & 2 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
```
Expand All @@ -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 |



Expand Down
6 changes: 3 additions & 3 deletions documentation/dsls/DSL:-AshGraphql.Resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand Down Expand Up @@ -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. |
Expand Down
2 changes: 1 addition & 1 deletion documentation/how_to/authorize-with-graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions documentation/how_to/handle-errors.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
]
Expand Down
4 changes: 2 additions & 2 deletions documentation/how_to/use-subscriptions-with-graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions documentation/how_to/use-unions-with-graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions documentation/topics/graphql-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`
14 changes: 7 additions & 7 deletions documentation/topics/monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
16 changes: 8 additions & 8 deletions documentation/tutorials/getting-started-with-graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

...
Expand Down Expand Up @@ -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
Expand Down
44 changes: 0 additions & 44 deletions lib/api/info.ex

This file was deleted.

Loading

0 comments on commit 74d870a

Please sign in to comment.