dewetblomerus
How to filter using a code interface
I am trying to create a code interface that is powered by a query that will grow and evolve over time.
To just play around with Ash queries I tried to start easy and return all the resources where the attribute word is "red".
This code works:
require Ash.Query
Red.Practice.Card
|> Ash.Query.filter(word == "red")
|> Red.Practice.read!()
But the above is not a nice code interface.
Under actions I have tried to create the following:
read :next do
# filter(is_nil([:retry_at]))
# filter(expr([:retry_at] == "NULL"))
# filter([:word] == "red")
end
None of those worked.
I am clearly guessing here and not finding any examples in the documentation. I was looking here but it does not seem like any of these examples are for using inside of a resource. It looks like it is meant for building queries like I already have working.
Bonus round:
Ultimately I need a next action that filters to actor: user, if there is a resource with a retry_at in the past, return the one with the oldest retry_at date. If not, return a resource with retry_at: nil and the oldest created_at. I don’t need that code written for me, but which documentation or example should I be looking at for composing a query inside of a resource action and exposing it through a code interface.
Marked As Solved
dewetblomerus
By Golly it works ![]()
![]()
![]()
If anyone else is still following along and wants a complete example, here is the now-beautiful interface that can be used elsewhere in the application:
Red.Practice.Card.next(actor: user)
And here is the resource:
defmodule Red.Practice.Card do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
code_interface do
define_for Red.Practice
define :create, action: :create
define :next, action: :next
define :oldest_untried_card, action: :oldest_untried_card
end
actions do
defaults [:read, :update]
create :create do
change relate_actor(:user)
end
read :next do
get? true
prepare build(limit: 1, sort: [retry_at: :asc])
filter expr(retry_at < now() and user_id == ^actor(:id))
prepare fn query, context ->
Ash.Query.after_action(query, fn
query, [] ->
dbg("No cards found with retry_at < now")
Red.Practice.Card.oldest_untried_card(actor: context.actor)
_query, results ->
dbg("A card was found with retry_at < now")
{:ok, results}
end)
end
end
read :oldest_untried_card do
prepare build(limit: 1, sort: [created_at: :asc])
filter expr(is_nil(retry_at) and user_id == ^actor(:id))
end
end
attributes do
integer_primary_key :id
attribute :word, :string, allow_nil?: false
attribute :tried_at, :utc_datetime, allow_nil?: true
attribute :retry_at, :utc_datetime, allow_nil?: true
attribute :correct_streak, :integer, allow_nil?: false, default: 0
create_timestamp :created_at
create_timestamp :updated_at
end
identities do
identity :unique_word, [:word, :user_id]
end
relationships do
belongs_to :user, Red.Accounts.User,
attribute_writable?: true,
attribute_type: :integer,
allow_nil?: false
end
postgres do
table "cards"
repo Red.Repo
end
end
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









