docs: more condensation/relocation of docs

This commit is contained in:
Zach Daniel 2024-04-07 10:11:19 -04:00
parent e6abba0de8
commit 2226b00ca5
12 changed files with 99 additions and 126 deletions

View file

@ -2402,7 +2402,7 @@ Declare named aggregates on the resource.
These are aggregates that can be loaded only by name using `Ash.Query.load/2`.
They are also available as top level fields on the resource.
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -2449,7 +2449,7 @@ Declares a named count aggregate on the resource
Supports `filter`, but not `sort` (because that wouldn't affect the count)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -2542,7 +2542,7 @@ Declares a named `exists` aggregate on the resource
Supports `filter`, but not `sort` (because that wouldn't affect if something exists)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -2632,7 +2632,7 @@ Declares a named `first` aggregate on the resource
First aggregates return the first value of the related record
that matches. Supports both `filter` and `sort`.
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -2727,7 +2727,7 @@ Declares a named `sum` aggregate on the resource
Supports `filter`, but not `sort` (because that wouldn't affect the sum)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -2820,7 +2820,7 @@ Declares a named `list` aggregate on the resource.
A list aggregate selects the list of all values for the given field
and relationship combination.
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -2914,7 +2914,7 @@ Declares a named `max` aggregate on the resource
Supports `filter`, but not `sort` (because that wouldn't affect the max)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -3006,7 +3006,7 @@ Declares a named `min` aggregate on the resource
Supports `filter`, but not `sort` (because that wouldn't affect the min)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -3098,7 +3098,7 @@ Declares a named `avg` aggregate on the resource
Supports `filter`, but not `sort` (because that wouldn't affect the avg)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -3192,7 +3192,7 @@ Supports `filter` and `sort`.
Custom aggregates provide an `implementation` which must implement data layer specific callbacks.
See the relevant data layer documentation and the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the relevant data layer documentation and the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
### Nested DSLs
@ -3286,7 +3286,7 @@ Declare named calculations on the resource.
These are calculations that can be loaded only by name using `Ash.Query.load/2`.
They are also available as top level fields on the resource.
See the [calculations guide](/documentation/topics/calculations.md) for more.
See the [calculations guide](/documentation/topics/resources/calculations.md) for more.
### Nested DSLs
@ -3322,7 +3322,7 @@ To ensure that the necessary fields are selected:
2.) Define a `select/2` callback in the calculation module
3.) Set `always_select?` on the attribute in question
See the [calculations guide](/documentation/topics/calculations.md) for more.
See the [calculations guide](/documentation/topics/resources/calculations.md) for more.
### Nested DSLs
@ -3371,7 +3371,7 @@ argument name, type
An argument to be passed into the calculation's arguments map
See the [calculations guide](/documentation/topics/calculations.md) for more.
See the [calculations guide](/documentation/topics/resources/calculations.md) for more.

View file

@ -33,6 +33,12 @@ Welcome to the Ash Framework documentation! Here you will find everything you ne
- [Glossary](documentation/topics/glossary.md)
### Resources
- [Attributes](documentation/topics/resources/attributes.md)
- [Calculations](documentation/topics/resources/calculations.md)
- [Aggregates](documentation/topics/resources/aggregates.md)
### Actions
- [Actions](documentation/topics/actions/actions.md)

View file

@ -1,51 +0,0 @@
# Auto-Format Ash code
Ash comes with several utilities that can help keep your modules consistently formatted and organized.
## Basic setup
Add `:ash` (and any other Ash libraries you are using) to your `.formatter.exs` file:
```elixir
[
# ...
import_deps: [..., :ash],
# ...
]
```
This means that when you auto-format your code, either via `mix format` or via an integration in your code editor, the exported data from Ash's `.formatter.exs` will be included and followed.
It includes definitions for `locals_without_parens`, meaning that your DSL builder code such as `attribute :name, :string` won't have parentheses added (to make it `attribute(:name, :string)`) when formatting the file. The parentheses won't be removed if they currently exist, but they won't be added if missing when formatting.
## Spark.Formatter
For more granular formatting, you can use `Spark.Formatter`, from the `spark` library.
> #### What is `spark`? {: .info}
>
> [`spark`](https://hexdocs.pm/spark) is a small library for building domain-specific languages (DSLs), and is what Ash itself uses internally. It provides the secret sauce to allow you to write your resources declaratively, and the editor integration so you get full autocomplete and documentation for free.
Add `Spark.Formatter` as a plugin in your `.formatter.exs` file:
```elixir
[
# ...
plugins: [..., Spark.Formatter]
# ...
]
```
By itself, `Spark.Formatter` doesn't do much - but it is configurable.
The most common configuration is to remove _all_ extra parentheses from your DSL builder code - this is how the examples within Ash documentation is formatted.
To enable this, add the following line to your application config in `config.exs`:
```elixir
config :spark, :formatter, remove_parens?: true, "Ash.Resource": []
```
This tells Spark that it should remove parenthesis from all modules that use `Ash.Resource`, following the `locals_without_parens` rules exported from all your dependencies (and any you may have added yourself).
`Spark.Formatter` has more configuration available - check the documentation for more details!

View file

@ -1,12 +1,24 @@
# Development Utilities
## Formatting DSLs
All Ash packages that ship with extensions provide exports in their `.formatter.exs`. This prevents the formatter from turning, for example, `attribute :name, :string` into `attribute(:name, :string)`. To enable this, add `:ash` (and any other Ash libraries you are using) to your `.formatter.exs` file:
```elixir
[
# ...
import_deps: [..., :ash],
# ...
]
```
## ElixirSense Plugin
Ash uses [Spark](https://hexdocs.pm/spark) to build all of our DSLs (like `Ash.Resource` and `Ash.Domain`) and to validate options lists to functions. `Spark` ships with an extension that is automatically picked up by ElixirLS to provide autocomplete for all of our DSLs, and options list. You don't need to do anything to enable this, but it only works with ElixirLS (not other language server tools).
## Formatter plugin
`Spark` also ships with a formatter plugin that can help you keep your resources formatted consistently. This plugin can sort the sections of your DSL to make your resources more consistent, and it can ensure that the DSL builders don't have parenthesis around them. (i.e `attribute :foo, :bar` vs `attribute(:foo, :bar)`).
`Spark` also ships with a formatter plugin that can help you keep your resources formatted consistently. This plugin can sort the sections of your DSL to make your resources more consistent, and it can remove any accidentally added parentheses around DSL code.
### Adding the plugin

View file

@ -27,7 +27,7 @@ An aggregate is a special type of field for a resource, one that summarizes rela
If a Project resource has_many Ticket resources, an example of an aggregate on the Project might be to count the tickets associated to each project.
See the [Aggregates guide](/documentation/topics/aggregates.md) for more.
See the [Aggregates guide](/documentation/topics/resources/aggregates.md) for more.
## Domain
@ -39,7 +39,7 @@ See the [Domains guide](/documentation/topics/domains.md) for more.
A piece of data belonging to a resource. The most basic building block; an attribute has a type and a value. For resources backed by a data layer, they typically represent a column in a database table, or a key in an object store, for example.
See the [Attributes guide](/documentation/topics/attributes.md) for more.
See the [Attributes guide](/documentation/topics/resources/attributes.md) for more.
## Authorizer
@ -51,7 +51,7 @@ See the [Actors & Authorization](documentation/topics/security/actors-and-author
A calculation is a special type of field for a resource, one that is not directly stored in the data layer but generated on-demand. Typically it will derive from other information on the record, but it may come from some other data source entirely.
See the [Calculations guide](/documentation/topics/calculations.md) for more.
See the [Calculations guide](/documentation/topics/resources/calculations.md) for more.
## Changeset

View file

@ -1,6 +1,6 @@
# Aggregates
Aggregates in Ash allow for retrieving summary information over groups of related data. A simple example might be to show the "count of published posts for a user". Aggregates allow us quick and performant access to this data, in a way that supports being filtered/sorted on automatically. More aggregate types can be added, but you will be restricted to only the supported types. In cases where aggregates don't suffice, use [Calculations](/documentation/topics/calculations.md), which are intended to be much more flexible.
Aggregates in Ash allow for retrieving summary information over groups of related data. A simple example might be to show the "count of published posts for a user". Aggregates allow us quick and performant access to this data, in a way that supports being filtered/sorted on automatically. More aggregate types can be added, but you will be restricted to only the supported types. In cases where aggregates don't suffice, use [Calculations](/documentation/topics/resources/calculations.md), which are intended to be much more flexible.
## Declaring aggregates on a resource
@ -16,17 +16,20 @@ end
The available aggregate types are:
- `count` - counts related items meeting the criteria
- `first` - gets the first related value matching the criteria. Must specify the `field` to get.
- `sum` - sums the related items meeting the criteria. Must specify the `field` to sum.
- `list` - lists the related values. Must specify the `field` to list.
- `count` - counts related items meeting the criteria.
- `exists` - checks if any related items meet the criteria.
- `first` - gets the first related value matching the criteria. Must specify the `field`.
- `sum` - sums the related items meeting the criteria. Must specify the `field`.
- `list` - lists the related values. Must specify the `field`.
- `max` - gets the maximum related value. Must specify the `field`.
- `min` - gets the minimum related value. Must specify the `field`.
- `avg` - gets the average related value. Must specify the `field`.
- `custom` - allows for a custom aggregate. Implementation depends on the data layer. Must provide an `implementation`.
The declared set of named aggregates can be used by extensions and referred to throughout your application As an escape hatch, they can also be loaded in the query using `Ash.Query.load/2`, or after the fact using `Ash.load/3`. Aggregates declared on the resource will be keys in the resource's struct.
See the docs on `d:Ash.Resource.Dsl.aggregates` for more information.
The aggregates declared on a resource allow for declaring a set of named aggregates that can be used by extensions.
As an escape hatch, they can also be loaded in the query using `Ash.Query.load/2`, or after the fact using `Ash.load/3`. Aggregates declared on the resource will be keys in the resource's struct.
## Custom aggregates in the query
Custom aggregates can be added to the query and will be placed in the `aggregates` key of the results. This is an escape hatch, and is not the primary way that you should be using aggregates. It does, however, allow for dynamism, i.e if you are accepting user input that determines what the filter and/or field should be, that kind of thing.
@ -36,9 +39,9 @@ Example:
```elixir
User
|> Ash.Query.aggregate(
:count_of_posts,
:count,
:posts,
:count_of_posts,
:count,
:posts,
query: [
filter: [published: published?]
]
@ -52,15 +55,31 @@ See the documentation for `Ash.Query.aggregate/4` for more information.
Join filters allows for more complex aggregate queries, including joining with predicates based on multiple related values.
### Example
```elixir
aggregates do
sum :saved_money, [:redeems, :deal], :amount do
# where any redeem of the deal is redeemed
filter expr(redeems.redeemed == true)
# where the `redeems` are `redeemed`
join_filter :redeems, expr(redeemed == true)
# where the `redeems.deal.active` == `redeems.require_active`
join_filter [:redeems, :deal], expr(active == parent(require_active))
end
end
```
end
```
## Inline Aggregates
Aggregates can be created in-line in expressions, with their relationship path specified and any options provided that match the options given to `Ash.Query.Aggregate.new/4`. For example:
```elixir
calculate :grade, :decimal, expr(
count(answers, query: [filter: expr(correct == true)]) /
count(answers, query: [filter: expr(correct == false)])
)
```
See the [Expressions guide](/documentation/topics/expressions.md#inline-aggregates) for more.

View file

@ -1,25 +1,10 @@
# Attributes
Attributes specify the name, type and properties of a piece of information in a resource.
Attributes specify the `name`, `type` and additional configuration of a simple property of a record. When using SQL data layers, for example, an attribute would correspond to a column in a database table.
## Ways of writing attributes
To see the options available when building attributes, see `d:Ash.Resource.Dsl.attributes.attribute`
There are two ways to write an attribute:
```elixir
attribute :name, :string, allow_nil?: false
# or ...
attribute :name, :string do
allow_nil? false
end
```
Both ways will work. Though when you're using many options the latter is preferred. This is also true of any other keyword in the Ash DSL, so you can build a flexible yet concise domain model.
For more information on attribute types including composite types and defining your own custom type see `Ash.Type`
You can find a comprehensive of attribute options with detailed descriptions on the `d:Ash.Resource.Dsl.attributes` page.
If you are looking to compute values on demand, see the [Calculations guide](/documentation/topics/resources/calculations.md) and the [aggregates guide](/documentation/topics/resources/aggregates.md).
## Special attributes

View file

@ -42,6 +42,8 @@ defmodule Concat do
@impl true
# A callback to tell Ash what keys must be loaded/selected when running this calculation
# you can include related data here, but be sure to include the attributes you need from said related data
# i.e `posts: [:title, :body]`.
def load(_query, opts, _context) do
opts[:keys]
end
@ -106,5 +108,5 @@ If the calculation uses an expression, you can also filter and sort on it like s
```elixir
query
|> Ash.Query.filter(full_name(separator: ","))
|> Ash.Query.sort(full_name: {:asc, %{separator: ","}})
|> Ash.Query.sort(full_name: {%{separator: ","}, :asc})
```

View file

@ -6,7 +6,7 @@ By default, attributes, calculations, aggregates and relationships are *private*
## Public & Private Arguments
Public/private arguments work the same way as public/private fields, except that they default to `public?: true`. This is because arguments to an action being usedin a public interface would naturally be expected to be `public`. If an argument is marked as `public?: false`, it can only be set with `Ash.Query.set_argument/3` or `Ash.Changeset.set_argument/3`
Public/private arguments work the same way as public/private fields, except that they default to `public?: true`. This is because arguments to an action being used in a public interface would naturally be expected to be `public`. If an argument is marked as `public?: false`, it can only be set with `Ash.Query.set_argument/3` or `Ash.Changeset.set_argument/3`
## Sensitive Attributes

View file

@ -91,7 +91,7 @@ To ensure that your code stays formatted like the examples here, you can add `:a
> #### Note {: .neutral}
>
> For more auto-formatting options, see the [Auto-Format Code guide](/documentation/how_to/auto-format-code.md).
> For more auto-formatting options, see the [Development Utilities guide](/documentation/topics/development/development-utilities.md).
And run `mix deps.get`, to install the dependency.

View file

@ -991,7 +991,7 @@ defmodule Ash.Resource.Dsl do
Supports `filter`, but not `sort` (because that wouldn't affect the count)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1022,7 +1022,7 @@ defmodule Ash.Resource.Dsl do
First aggregates return the first value of the related record
that matches. Supports both `filter` and `sort`.
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1053,7 +1053,7 @@ defmodule Ash.Resource.Dsl do
Supports `filter`, but not `sort` (because that wouldn't affect the max)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1078,7 +1078,7 @@ defmodule Ash.Resource.Dsl do
Supports `filter`, but not `sort` (because that wouldn't affect the min)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1103,7 +1103,7 @@ defmodule Ash.Resource.Dsl do
Supports `filter`, but not `sort` (because that wouldn't affect the sum)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1128,7 +1128,7 @@ defmodule Ash.Resource.Dsl do
Supports `filter`, but not `sort` (because that wouldn't affect the avg)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1153,7 +1153,7 @@ defmodule Ash.Resource.Dsl do
Supports `filter`, but not `sort` (because that wouldn't affect if something exists)
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1178,7 +1178,7 @@ defmodule Ash.Resource.Dsl do
Custom aggregates provide an `implementation` which must implement data layer specific callbacks.
See the relevant data layer documentation and the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the relevant data layer documentation and the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1215,7 +1215,7 @@ defmodule Ash.Resource.Dsl do
A list aggregate selects the list of all values for the given field
and relationship combination.
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1246,7 +1246,7 @@ defmodule Ash.Resource.Dsl do
These are aggregates that can be loaded only by name using `Ash.Query.load/2`.
They are also available as top level fields on the resource.
See the [aggregates guide](/documentation/topics/aggregates.md) for more.
See the [aggregates guide](/documentation/topics/resources/aggregates.md) for more.
""",
examples: [
"""
@ -1276,7 +1276,7 @@ defmodule Ash.Resource.Dsl do
describe: """
An argument to be passed into the calculation's arguments map
See the [calculations guide](/documentation/topics/calculations.md) for more.
See the [calculations guide](/documentation/topics/resources/calculations.md) for more.
""",
examples: [
"""
@ -1310,7 +1310,7 @@ defmodule Ash.Resource.Dsl do
2.) Define a `select/2` callback in the calculation module
3.) Set `always_select?` on the attribute in question
See the [calculations guide](/documentation/topics/calculations.md) for more.
See the [calculations guide](/documentation/topics/resources/calculations.md) for more.
""",
examples: [
{
@ -1340,7 +1340,7 @@ defmodule Ash.Resource.Dsl do
These are calculations that can be loaded only by name using `Ash.Query.load/2`.
They are also available as top level fields on the resource.
See the [calculations guide](/documentation/topics/calculations.md) for more.
See the [calculations guide](/documentation/topics/resources/calculations.md) for more.
""",
examples: [
"""

16
mix.exs
View file

@ -46,6 +46,7 @@ defmodule Ash.MixProject do
"documentation/topics/about_ash/what-is-ash.md",
"documentation/topics/about_ash/design-principles.md",
"documentation/topics/about_ash/contributing-to-ash.md",
"documentation/topics/resources/attributes.md",
"documentation/topics/actions/actions.md",
"documentation/topics/actions/read-actions.md",
"documentation/topics/actions/create-actions.md",
@ -63,10 +64,8 @@ defmodule Ash.MixProject do
"documentation/how_to/structure-your-project.md",
"documentation/how_to/use-without-data-layers.md",
"documentation/how_to/validate-changes.md",
"documentation/how_to/auto-format-code.md",
"documentation/topics/aggregates.md",
"documentation/topics/attributes.md",
"documentation/topics/calculations.md",
"documentation/topics/resources/aggregates.md",
"documentation/topics/resources/calculations.md",
"documentation/topics/code-interface.md",
"documentation/topics/constraints.md",
"documentation/topics/embedded-resources.md",
@ -101,6 +100,11 @@ defmodule Ash.MixProject do
"documentation/tutorials/get-started.md"
],
Tutorials: [],
Resources: [
"documentation/topics/resources/attributes.md",
"documentation/topics/resources/calculations.md",
"documentation/topics/resources/aggregates.md"
],
Actions: [
"documentation/topics/actions/actions.md",
"documentation/topics/actions/read-actions.md",
@ -144,10 +148,6 @@ defmodule Ash.MixProject do
"documentation/how_to/structure-your-project.md",
"documentation/how_to/use-without-data-layers.md",
"documentation/how_to/validate-changes.md",
"documentation/how_to/auto-format-code.md",
"documentation/topics/aggregates.md",
"documentation/topics/attributes.md",
"documentation/topics/calculations.md",
"documentation/topics/code-interface.md",
"documentation/topics/constraints.md",
"documentation/topics/embedded-resources.md",