Query one-to-one relationship data in :create action

I have 3 resources. When creating reading I would like to pass tag_id and inside of :create function query employee to get employee.id and populate reading.employee_id with that value.

Tag:

  attributes do
    uuid_primary_key :id do
      description "Primary ID"
    end

    attribute :code, :string do
      allow_nil? false
      description "Id of the physical tag/card"
    end
  end

  identities do
    identity :unique_code, [:code]
  end

  relationships do
    belongs_to :employee, App.Api.Employee do
      description "Employee that is using this tag"
    end
  end

Employee:

  attributes do
    uuid_primary_key :id do
      description "Primary ID"
    end
  end

  relationships do
    has_one :tag, App.Api.Tag do
      description "Tag used for tracking"
    end

    has_many :readings, App.Api.Reading do
      description "User readings"
    end
  end

Reading:

  attributes do
    uuid_primary_key :id do
      description "Primary ID"
    end

  end

  relationships do
    belongs_to :employee, App.Api.Employee do
      attribute_writable? true
      description "Employee that created reading"
    end
  end

I’ve added managed_relationships to graphql block so I can send tag_id as argument to :create func but I have no idea what would be the best way to get employee.id based on tag_id?

graphql do
    type :reading

    managed_relationships do
      managed_relationship(:create_reading, :tag) do
        lookup_with_primary_key?(false)
        lookup_identities([:tag_id])
      end
    end
end

I’ve managed to do it. Now the question is: Is there a more optimal way?

  • Changed relationship between Tag and Employee to have employeeId field avaliable without having to load the relationship,
  • Added custom read fun to Tag resource:
      read :by_code do
        get? true
        argument :code, :string
        argument :tenant, :string
    
        get_by :code
    
        prepare fn query, _ ->
          Ash.Query.set_tenant(query, query.arguments[:tenant])
        end
    
  • Added create fun to Reading resource:
      create :test_create do
        argument :tag_id, :string
    
        change before_action(fn changeset ->
                 {:ok, %{employee_id: employee_id}} =
                   Timewise.Tracker.Tag.by_code(
                     Ash.Changeset.get_argument(changeset, :tag_id),
                     changeset.tenant
                   )
    
                 Ash.Changeset.change_attribute(changeset, :employee_id, employee_id)
               end)
      end
    

One thing left to do is add error handling to create function.

The way you`ve laid out is the simplest/potentially only realistic way to do it :+1: