Files
livebook/ash_tutorial/querying.livemd
2025-09-29 19:25:33 +08:00

6.2 KiB

Ash: 3 - Querying

Application.put_env(:ash, :validate_domain_resource_inclusion?, false)
Application.put_env(:ash, :validate_domain_config_inclusion?, false)
Mix.install([{:ash, "~> 3.0"}], consolidate_protocols: false)

But First, Data Persistence

So far we have just created changesets, but we have not actually created any instances of a resource, also known as records. Before we can play around with querying, we need to add a data layer. It is much more common to use Postgres in production, but we will use ETS data layer for the remainder of this tutorial to keep dependencies to a minimum.

 use Ash.Resource,
      domain: YourDomain,
      data_layer: Ash.DataLayer.Ets

In this tutorial you will do basic Query and CRUD operations

But first you need to enable all basic CRUD operations.

Do this by adding default :read and :destroy actions, as well as :create and :update actions that accept [:name].

Show Solution
defmodule Tutorial.Profile do
  use Ash.Resource,
    domain: Tutorial,
    data_layer: Ash.DataLayer.Ets

  actions do
    defaults [:read, :destroy]

    create :create do
      accept [:name]
    end

    update :update do
      accept [:name]
    end
  end

  attributes do
    uuid_primary_key :id
    attribute :name, :string
  end
end

defmodule Tutorial do
  use Ash.Domain

  resources do
    resource Tutorial.Profile
  end
end

Enter your solution

defmodule Tutorial.Profile do
  use Ash.Resource,
    domain: Tutorial,
    data_layer: Ash.DataLayer.Ets

  actions do
    # <--- Create your actions here
  end

  attributes do
    uuid_primary_key :id
    attribute :name, :string
  end
end

defmodule Tutorial do
  use Ash.Domain

  resources do
    resource Tutorial.Profile
  end
end

Creating

Add 2 Profiles to the database.

  • One with the name "Joe Armstrong"
  • One with your name

You can create a Profile by:

  • Creating a Changeset with Ash.Changeset.for_create(Tutorial.Profile, :create, %{name: "Your Name"}),
  • Then giving the changeset to Ash.create!().

Hint: Use a pipeline

Show Solution
Tutorial.Profile
|> Ash.Changeset.for_create(:create, %{name: "The Name"})
|> Ash.create!()

Enter your solution


Reading

Now, read all the generated Profiles.

Call Ash.read!/1 with the Tutorial.Profile module.

Show Solution
Tutorial.Profile
|> Ash.read!()

Enter your solution


Now fetch the "Joe Armstrong" Profile.

You can achieve this by introducing a filter.

First you'll need to require Ash.Query

Then call Ash.Query.filter(name == "Joe Armstrong") with the Tutorial.Profile.

Put the result into the joe variable. Ash.read!/1 returns a list, so make sure to extract the single returned value out of that list.

Show Solution
require Ash.Query

[joe] =
  Tutorial.Profile
  |> Ash.Query.filter(name == "Joe Armstrong")
  |> Ash.read!()

Enter your solution


You'll use the joe variable in the next sections.

Updating

Now change Joe Armstrong's name to Neil Armstrong.

You can do this by providing the Ash.Changeset.for_update/3 with:

  • the resource you want to change, in this case joe
  • the :update atom
  • a map of the values you want to change, in this case %{name: "Neil Armstrong"}

Then apply the changeset by calling Ash.update!/1 with the changeset.

Hint: Using a pipeline might be a good idea.

Show Solution
joe
|> Ash.Changeset.for_update(:update, %{name: "Neil Armstrong"})
|> Ash.update!()

Enter your solution


Destroying

Finally, remove joe from the database.

Do this using the Ash.destroy!/1 function.

Show Solution
Ash.destroy!(joe)

Enter your solution