Problem using resource define

In trying to work through an example of defining an api for an Ash Domain, I am having problems using “define.”

The Example application has one Ash Domain (Bids).

For the Example app, the Bids Domain has two Ash Resources defined as follows:
Company.ex

defmodule Example.Bids.Company do
  use Ash.Resource,
    domain: Example.Bids,
    data_layer: AshPostgres.DataLayer

  postgres do
    table "companies"
    repo Example.Repo
  end

  resource do
    plural_name :companies
  end

  attributes do
    uuid_primary_key :id

    attribute :name, :string do
      description "A short, unique name for this Company"

      constraints max_length: 60,
                  min_length: 1

      public? true
      allow_nil? false
    end

    attribute :status, :atom do
      description "Notes whether the Company is Active or Inactive"
      default :active
      constraints one_of: [:active, :inactive]
      allow_nil? false
      public? true
    end

    timestamps()

    attribute :last_accessed_at, :utc_datetime_usec do
      description "Date/Time This Company Last Accessed"
      default &DateTime.utc_now/0
      update_default &DateTime.utc_now/0
      match_other_defaults? true
      allow_nil? false
      writable? true
    end
  end

  identities do
    identity :uniq_company, [:name]
  end

  relationships do
    has_many :bids, Example.Bids.Bid
  end

  actions do
    default_accept [:*]
    defaults [:create, :read, :update, :destroy]
  end
end

The second Ash Resource is Bid:
**Bid.ex**

defmodule Example.Bids.Bid do
  use Ash.Resource,
    domain: Example.Bids,
    data_layer: AshPostgres.DataLayer

  require Ash.Query

  postgres do
    table "bids"
    repo Example.Repo
  end

  resource do
    plural_name :bids
  end

  attributes do
    uuid_primary_key :id

    attribute :name, :string do
      description "A short unique name for this Bid"

      constraints max_length: 60,
                  min_length: 1

      public? true
      allow_nil? false
    end

    attribute :status, :atom do
      description "An Indicator of the Bid's Status or Progress"
      default :requested
      constraints one_of: [:requested, :preparing, :awaiting_award, :awarded, :not_awarded]
      allow_nil? false
      public? true
    end

    attribute :company_id, :uuid do
      public? true
      allow_nil? false
      writable? true
    end

    timestamps()

    attribute :last_accessed_at, :utc_datetime_usec do
      description "Date/Time This Bid Last Accessed"
      default &DateTime.utc_now/0
      update_default &DateTime.utc_now/0
      match_other_defaults? true
      allow_nil? false
      writable? true
    end
  end

The Ash Domain interface is in the Bids.ex file:
**Bids.ex**

defmodule Example.Bids do
  use Ash.Domain

  resources do
    resource Example.Bids.Company do
      define :new_company, action: :create, args: [:name]
      define :list_companies, action: :read, args: []
      define :get_company_by_name, action: :read, get_by: [:name]
      define :get_company_by_id, action: :read, get_by: [:id]
      define :remove_company, action: :destroy, get_by: [:id]
      define :update_company_name, action: :update, get_by: [:id], args: [:name]
    end

    resource Example.Bids.Bid do
      define :new_bid, action: :create, args: [:name, :company_id]
      define :list_bids, action: :read, args: []

      define :list_bids_by_company, action: :read, args: [:company_id] do
        argument :company_id, :uuid do
          allow_nil? false
        end
        
        filter expr(company_id == ^arg(:company_id))
      end
    end
  end
end

When I compile the application, I get the following error:

** (CompileError) lib/example/bids/bids.ex: cannot compile module Example.Bids (errors have been logged)
    (ash 3.1.0) expanding macro: Ash.Domain.Dsl.Resources.Resource.resource/2
    lib/example/bids/bids.ex:14: Example.Bids (module)
    (ash 3.1.0) expanding macro: Ash.Domain.Dsl.resources/1
    lib/example/bids/bids.ex:4: Example.Bids (module)
undefined function define/3 (there is no such import)

Not sure why the "define" associated with the :get_bids_by_company reports no such import.

Removing the define block for :get_bids_by_company, all other defined functions work as expected.

Any insights would be helpful. Thanks for your help

I don’t think this is valid DSL in the resource . You are passing the argument and filter to the define function which it does not accept.
The best way you to define that action is, in your Example.Bids.Bid resource add a read action, for example:

read :list_by_company do
    argument :company_id, :uuid do
        allow_nil? false
    end

    filter expr(company_id == ^arg(company_id)
end

An then in your Example.Bids domain module, you can define the :list_bids_by_company

resource Example.Bids.Bid do
    ....
    define :list_bids_by_company, action: :list_by_company, args: [:company_id]
    ....
end

Thanks. That solved the problem. I was unclear about creating a read action on the resource itself and then referencing in the Ash Domain. That makes perfect sense.

Thanks again for your help. I really appreciate the Ash Framework and the community.

2 Likes