Documentation Blog Community Forum Media
|
|
Sign In
    • Ash
      • Get Started
      • Philosophy
      • Why Ash
      • Extending Resources
    • AshPostgres
      • Get Started With Postgres
    • AshSqlite
      • Get Started With Sqlite
    • AshPhoenix
      • Getting Started With Ash And Phoenix
    • AshGraphql
      • Getting Started With Graphql
    • AshJsonApi
      • Getting Started With Json Api
    • AshAuthentication
      • Auth0 Quickstart
      • Getting Started With Authentication
      • Github Quickstart
      • Magic Links Quickstart
    • AshAuthenticationPhoenix
      • Getting Started With Ash Authentication Phoenix
      • Use Ash Authentication With Liveview
    • AshStateMachine
      • Get Started With State Machines
    • AshCSV
      • Get Started With Csv
    • Reactor
      • Getting Started With Reactor
    • Spark
      • Get Started With Spark
    • Ash
      • Actions
      • Aggregates
      • Atomics
      • Attributes
      • Bulk Actions
      • Calculations
      • Code Interface
      • Constraints
      • Development Utilities
      • Embedded Resources
      • Expressions
      • Flows
      • Glossary
      • Identities
      • Managing Relationships
      • Manual Actions
      • Monitoring
      • Multitenancy
      • Notifiers
      • Pagination
      • Phoenix
      • Policies
      • Pub Sub
      • Relationships
      • Security
      • Store Context In Process
      • Testing
      • Timeouts
      • Validations
    • AshPostgres
      • Migrations And Tasks
      • Polymorphic Resources
      • Postgres Expressions
      • References
      • Schema Based Multitenancy
    • AshSqlite
      • Migrations And Tasks
      • Polymorphic Resources
      • References
      • Sqlite Expressions
    • AshPhoenix
      • Working With Phoenix
    • AshGraphql
      • Graphql Generation
      • Modifying The Resolution
      • Relay
    • AshJsonApi
      • Open Api
      • Relationships
    • AshAuthentication
      • Custom Strategy
      • Policies On Authentication Resources
      • Upgrading
    • Ash
      • Contribute
      • Define Idiomatic Actions
      • Defining Manual Relationships
      • Handle Errors
      • Structure Your Project
      • Upgrade
      • Use Without Data Layers
      • Validate Changes
    • AshPostgres
      • Join Manual Relationships
      • Test With Postgres
      • Using Fragments
    • AshSqlite
      • Join Manual Relationships
      • Test With Sqlite
      • Using Fragments
    • AshGraphql
      • Authorize With Graphql
      • Handle Errors
      • Use Enums With Graphql
      • Use Json With Graphql
      • Use Subscriptions With Graphql
      • Use Unions With Graphql
    • Spark
      • Writing Extensions
    • AshGraphql
      • Monitoring
    • AshArchival
      • Archival
      • Unarchiving
    • Ash
      • Get Started
      • Philosophy
      • Why Ash
      • Extending Resources
    • AshPostgres
      • Get Started With Postgres
    • AshSqlite
      • Get Started With Sqlite
    • AshPhoenix
      • Getting Started With Ash And Phoenix
    • AshGraphql
      • Getting Started With Graphql
    • AshJsonApi
      • Getting Started With Json Api
    • AshAuthentication
      • Auth0 Quickstart
      • Getting Started With Authentication
      • Github Quickstart
      • Magic Links Quickstart
    • AshAuthenticationPhoenix
      • Getting Started With Ash Authentication Phoenix
      • Use Ash Authentication With Liveview
    • AshStateMachine
      • Get Started With State Machines
    • AshCSV
      • Get Started With Csv
    • Reactor
      • Getting Started With Reactor
    • Spark
      • Get Started With Spark
    • Ash
      • Actions
      • Aggregates
      • Atomics
      • Attributes
      • Bulk Actions
      • Calculations
      • Code Interface
      • Constraints
      • Development Utilities
      • Embedded Resources
      • Expressions
      • Flows
      • Glossary
      • Identities
      • Managing Relationships
      • Manual Actions
      • Monitoring
      • Multitenancy
      • Notifiers
      • Pagination
      • Phoenix
      • Policies
      • Pub Sub
      • Relationships
      • Security
      • Store Context In Process
      • Testing
      • Timeouts
      • Validations
    • AshPostgres
      • Migrations And Tasks
      • Polymorphic Resources
      • Postgres Expressions
      • References
      • Schema Based Multitenancy
    • AshSqlite
      • Migrations And Tasks
      • Polymorphic Resources
      • References
      • Sqlite Expressions
    • AshPhoenix
      • Working With Phoenix
    • AshGraphql
      • Graphql Generation
      • Modifying The Resolution
      • Relay
    • AshJsonApi
      • Open Api
      • Relationships
    • AshAuthentication
      • Custom Strategy
      • Policies On Authentication Resources
      • Upgrading
    • Ash
      • Contribute
      • Define Idiomatic Actions
      • Defining Manual Relationships
      • Handle Errors
      • Structure Your Project
      • Upgrade
      • Use Without Data Layers
      • Validate Changes
    • AshPostgres
      • Join Manual Relationships
      • Test With Postgres
      • Using Fragments
    • AshSqlite
      • Join Manual Relationships
      • Test With Sqlite
      • Using Fragments
    • AshGraphql
      • Authorize With Graphql
      • Handle Errors
      • Use Enums With Graphql
      • Use Json With Graphql
      • Use Subscriptions With Graphql
      • Use Unions With Graphql
    • Spark
      • Writing Extensions
    • AshGraphql
      • Monitoring
    • AshArchival
      • Archival
      • Unarchiving
View this guide on GitHub View this guide on Hex

Calculations

Table of Contents

  1. Primer
  2. Declaring calculations on a resource
    1. Expression Calculations
    2. Module Calculations
  3. Custom calculations in the query
  4. Arguments in calculations

Calculations in Ash allow for displaying complex values as a top level value of a resource.

Primer

Declaring calculations on a resource

Expression Calculations

The simplest kind of calculation refers to an Ash expression. For example:

calculations do
  calculate :full_name, :string, expr(first_name <> " " <> last_name)
end

See the Expressions guide for more.

Module Calculations

When calculations require more complex code or can’t be pushed down into the data layer, a module that uses Ash.Calculation can be used.

defmodule Concat do
  # An example concatenation calculation, that accepts the delimiter as an argument,
  #and the fields to concatenate as options
  use Ash.Calculation

  # Optional callback that verifies the passed in options (and optionally transforms them)
  @impl true
  def init(opts) do
    if opts[:keys] && is_list(opts[:keys]) && Enum.all?(opts[:keys], &is_atom/1) do
      {:ok, opts}
    else
      {:error, "Expected a `keys` option for which keys to concat"}
    end
  end

  @impl true
  # A callback to tell Ash what keys must be loaded/selected when running this calculation
  def load(_query, opts, _context) do
    opts[:keys]
  end

  @impl true
  def calculate(records, opts, %{separator: separator}) do
    Enum.map(records, fn record ->
      Enum.map_join(opts[:keys], separator, fn key ->
        to_string(Map.get(record, key))
      end)
    end)
  end

  # You can implement this callback to make this calculation possible in the data layer
  # *and* in elixir. Ash expressions are already executable in Elixir or in the data layer, but this gives you fine grain control over how it is done
  # @impl true
  # def expression(opts, context) do
  # end
end

# Usage in a resource
calculations do
  calculate :full_name, :string, {Concat, keys: [:first_name, :last_name]} do
    # You need to use the [allow_empty?: true, trim?: false] constraints here.
    # The separator could be an empty string or require a leading or trailing space,
    # but would be trimmed or even set to `nil` without the constraints shown below.
    argument :separator, :string do
      allow_nil? false
      constraints [allow_empty?: true, trim?: false]
      default ""
    end
  end
end

See the documentation for the calculations section in Resource DSL docs and the Ash.Calculation docs for more information.

The calculations declared on a resource allow for declaring a set of named calculations that can be used by extensions. They can also be loaded in the query using Ash.Query.load/2 , or after the fact using c:Ash.Api.load/3 . Calculations declared on the resource will be keys in the resource’s struct.

Custom calculations in the query

Example:

User
|> Ash.Query.new()
|> Ash.Query.calculate(:full_name, {Concat, keys: [:first_name, :last_name]}, :string, %{separator: ","})

See the documentation for Ash.Query.calculate/4 for more information.

Arguments in calculations

Using the above example with arguments, you can load a calculation with arguments like so:

load(full_name: [separator: ","])

If the calculation uses an expression, you can also filter and sort on it like so:

query
|> Ash.Query.filter(full_name(separator: ","))
|> Ash.Query.sort(full_name: {:asc, %{separator: ","}})
Source Report an issue