Skip to content

Latest commit

 

History

History
227 lines (169 loc) · 6.02 KB

code_interfaces.livemd

File metadata and controls

227 lines (169 loc) · 6.02 KB

Ash: 10 - Code Interfaces

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

Code Interfaces

In this tutorial you will add a Code Interface

In previous tutorials you always used Changesets directly to CRUD on resources. While this is a perfectly valid way of handling CRUD operations, Ash provides Code Interfaces to make this more ergonomic for you. The code interface can be defined on the resources or the domain. In this example, we will define it on the domain.

You will add 3 code interfaces for:

  • Creating a representative
  • Opening a ticket
  • Assigning a representative

For each resource you want to add a code interface to, inside that resource definition on the domain, you will place "definitions". For example:

resource MyApp.Tweet do
  define :create_tweet, args: [:content]
end

Then add the 3 interfaces by defining the following inside the Ticket resource's block:

  • define :assign_ticket, args: [:representative_id], action: :assign
  • define :open_ticket, args: [:subject, :description], action: :open

And the following inside the Representative resource's block.

  • define :create_ticket, args: [:name], action: :create
Show Solution
resource Tutorial.Support.Ticket do
  define :assign_ticket, args: [:representative_id], action: :assign
  define :open_ticket, args: [:subject, :description], action: :open
end

resource Tutorial.Support.Representative do
  define :create_representative, args: [:name], action: :create
end

Enter your solution

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

  actions do
    defaults [:read]

    create :open do
      accept [:subject, :description]
    end

    update :close do
      change set_attribute(:status, :closed)
    end

    update :assign do
      argument :representative_id, :uuid, allow_nil?: false
      change manage_relationship(:representative_id, :representative, type: :append_and_remove)
    end
  end

  attributes do
    uuid_primary_key :id
    attribute :subject, :string, allow_nil?: false
    attribute :description, :string, allow_nil?: true

    attribute :status, :atom do
      constraints one_of: [:open, :closed]
      default :open
      allow_nil? false
    end

    create_timestamp :created_at
    update_timestamp :updated_at
  end

  relationships do
    belongs_to :representative, Tutorial.Support.Representative
  end
end

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

  actions do
    defaults [:read]

    create :create do
      accept [:name]
    end
  end

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

defmodule Tutorial.Support do
  use Ash.Domain

  resources do
    resource Tutorial.Support.Ticket do
      # <-- Add ticket code interface here
    end

    resource Tutorial.Support.Representative do
      # <-- Add representative code interface here
    end
  end
end

Using the Code Interfaces

Create a Representative, but instead of using a changeset, use the code interface you created.

You can use a code interface by calling Tutorial.Support.create_representative!/1 with the desired name.

Set the name to Joe Armstrong and store it in a joe variable.

Show Solution
joe = Tutorial.Support.create_representative!("Joe Armstrong")

Create a Ticket with the created code interface.

Call Tutorial.Support.open_ticket!/2 with a subject and description and store the result in a ticket variable.

Show Solution
ticket = Tutorial.Support.open_ticket!("I can't find my hand!", "I think someone stole it.")

Assign the Representative joe to the Ticket using the code Interface.

Use Tutorial.Support.assign_ticket!/2.

Show Solution
Tutorial.Support.assign_ticket!(ticket, joe.id)