Code Interfaces returning booleans

:wave:

Learning Ash after chatting with y’all at ElixirConf. Here’s my situation:
I have some tokens that can either expire or be revoked. I want to check if a specific token is valid based on its primary key.

This is the action:

read :valid? do
  argument :jti, :string do
    allow_nil? false
  end

  filter expr(jti == ^arg(:jti) and expires_at >= ^DateTime.utc_now() and is_nil(revoked_at))
end

I also have the following code interface on the resource.

define :valid?, action: :valid?

That returns, an {:ok, [%Token{}]} which I can match on. That’s fine, and it works. I would like some better ergonomics though, so my question: is there a way to define a quick code interface that calls Ash.exists/2 like that, or do I need to define my own function for it?

Yes, you can do that :slight_smile:

action :valid?, :boolean do
  argument :jti, :string do
    allow_nil? false
  end

  run fn input, context -> 
    __MODULE__
    |> Ash.Query.filter(jti == ^input.arguments.jti)
    |> Ash.Query.for_read(:valid_tokens, %{}, Ash.Context.to_opts(context))
    |> Ash.exists()
  end
end

read :valid_tokens do
  filter expr(expires_at >= ^DateTime.utc_now() and is_nil(revoked_at))
end

Then, you can do

define :valid?, args: [:jti]

And then YourDomain.valid?(jti) should do what you want :slight_smile: (barring any typos/misakes in my code example above :laughing: )

1 Like

Ahhhh that explains the combination of generic and specific actions. Thanks so much for also taking the time to type out the full example, that’s appreciated so much.

1 Like