Delete Queries.

How does delete queries work? like if i want to fetch a record based on and id or maybe two columns and want to delete that record?
33 Replies
talha-azeem
talha-azeemOPβ€’3y ago
MyApp.Accounts.TeamJoinedUser
|> Ash.Query.filter(team_id == ^team_id and user_id == ^user_id)
|> MyApp.Accounts.destroy()
MyApp.Accounts.TeamJoinedUser
|> Ash.Query.filter(team_id == ^team_id and user_id == ^user_id)
|> MyApp.Accounts.destroy()
I tried doing this.
ZachDaniel
ZachDanielβ€’3y ago
So you can look up a record however you want and destroy it, i.e Api.get!(..) |> Api.destroy() but right now we don’t have destroys with queries. Its coming soon.
talha-azeem
talha-azeemOPβ€’3y ago
and i had a lot of help from ash-hq repo. Thank you so much for your hard work πŸ™ŒπŸ»
ZachDaniel
ZachDanielβ€’3y ago
If you want to delete from a query, you can do MyApp.Accounts.TeamJoinedUser |> Ash.Query.filter(…) |> Ash.Query.data_layer_query() That will get you an ecto query that you can pass into Repo.delete_all
talha-azeem
talha-azeemOPβ€’3y ago
{:ok, team_joined_user} =
MyApp.Accounts.TeamJoinedUser
|> Ash.Query.filter(team_id == ^team_id and user_id == ^user_id)
|> Ash.Query.data_layer_query()

MyApp.Repo.delete(team_joined_user)
{:ok, team_joined_user} =
MyApp.Accounts.TeamJoinedUser
|> Ash.Query.filter(team_id == ^team_id and user_id == ^user_id)
|> Ash.Query.data_layer_query()

MyApp.Repo.delete(team_joined_user)
Is this okay? it says module repo is not defined.
ZachDaniel
ZachDanielβ€’3y ago
It would be your apps repo module
talha-azeem
talha-azeemOPβ€’3y ago
yeah i know but usually we have this code in our repo.ex
use Ecto.Repo, otp_app: :app_name, adapter: Ecto.Adapters.Postgres
use Ecto.Repo, otp_app: :app_name, adapter: Ecto.Adapters.Postgres
but for this i have this in my repo.ex
defmodule AppName.Repo do
use AshPostgres.Repo,
otp_app: :app_name,
adapter: Ecto.Adapters.Postgres

def installed_extensions do
["citext"]
end
end
defmodule AppName.Repo do
use AshPostgres.Repo,
otp_app: :app_name,
adapter: Ecto.Adapters.Postgres

def installed_extensions do
["citext"]
end
end
frankdugan3
frankdugan3β€’3y ago
You don't need the adapter line w/ AshPostregres.Repo In your examples, you've got MyApp.Repo in the query, and here AppName.Repo. I get that you may be trying to hide private code, but it seems like the issue is probably not using the right module name?
talha-azeem
talha-azeemOPβ€’3y ago
my module to repo.ex is AppName.Repo and i have aliased it at the top like this alias AppName.Repo but i am getting the below error
** (UndefinedFunctionError) function Repo.delete/1 is undefined (module Repo is not available)
** (UndefinedFunctionError) function Repo.delete/1 is undefined (module Repo is not available)
yeah just hiding the private info
frankdugan3
frankdugan3β€’3y ago
Do you have the repo in your config.exs? config :app_name, ecto_repos: [AppName.Repo]?
talha-azeem
talha-azeemOPβ€’3y ago
yes
config :app_name,
ecto_repos: [AppName.Repo],
ash_apis: [...]
config :app_name,
ecto_repos: [AppName.Repo],
ash_apis: [...]
Can i give two params here?
AppName.Accounts.get!(TeamJoinedUser, team_id: team_id, user_id: user_id) |> AppName.Accounts.destroy()
AppName.Accounts.get!(TeamJoinedUser, team_id: team_id, user_id: user_id) |> AppName.Accounts.destroy()
I don't know what is wrong here. Is there any other way that i can fetch the data? basically i want to fetch data from TeamJoinedUser based on team id and user id after getting that one record delete that record.
frankdugan3
frankdugan3β€’3y ago
The easiest way IMO would be to create a custom action:
read :get_by_team_and_user do
get? true
argument :team_id, :string, allow_nil?: false
argument :user_id, :string, allow_nil?: false

filter expr(team_id == ^arg(:team_id) and user_id == ^arg(:user_id))
end
read :get_by_team_and_user do
get? true
argument :team_id, :string, allow_nil?: false
argument :user_id, :string, allow_nil?: false

filter expr(team_id == ^arg(:team_id) and user_id == ^arg(:user_id))
end
talha-azeem
talha-azeemOPβ€’3y ago
this would be in TeamJoinedUser?
frankdugan3
frankdugan3β€’3y ago
That will expect exactly 1 result, so you will want to ensure you have an identity set up on those two fields to ensure uniqueness by that trait.
talha-azeem
talha-azeemOPβ€’3y ago
and then how will i call it?
frankdugan3
frankdugan3β€’3y ago
Yeah. I would use code_interface and add it to TeamJoinedUser, then you can just do TeamJoinedUser.get_by_team_and_user.
talha-azeem
talha-azeemOPβ€’3y ago
and this will be in
actions do
defaults [:create, :read, :update, :destroy]
end
actions do
defaults [:create, :read, :update, :destroy]
end
in it or outside?
frankdugan3
frankdugan3β€’3y ago
code_interface do
define_for AppName.Api

define :get_by_team_and_user, action: :get_by_team_and_user, get?: true, args: [:team_id, :user_id]
end
code_interface do
define_for AppName.Api

define :get_by_team_and_user, action: :get_by_team_and_user, get?: true, args: [:team_id, :user_id]
end
The custom action goes inside actions do, after defaults ...
talha-azeem
talha-azeemOPβ€’3y ago
okay and i defined both of them.
frankdugan3
frankdugan3β€’3y ago
To clarify what's going on in the DSL:
actions do
defaults [:create, :read, :update, :destroy]
end
actions do
defaults [:create, :read, :update, :destroy]
end
is shorthand for
actions do
create :create do
primary?: true
end

read :read do
primary?: true
end

update :update do
primary?: true
end

destroy :destroy do
primary?: true
end
end
actions do
create :create do
primary?: true
end

read :read do
primary?: true
end

update :update do
primary?: true
end

destroy :destroy do
primary?: true
end
end
The syntax is [type of action] [name of action] do
talha-azeem
talha-azeemOPβ€’3y ago
TeamJoinedUser.get_by_team_and_user(team_id, user_id) It will be called like this? in the live view?
frankdugan3
frankdugan3β€’3y ago
Yes. But you'll want the ! if you're going to pipe it into destroy. TeamJoinedUser.get_by_team_and_user!(team_id, user_id)
talha-azeem
talha-azeemOPβ€’3y ago
and defined this in team_joined_user.ex
actions do
defaults [:create, :read, :update, :destroy]

read :get_by_team_and_user do
get? true
argument :team_id, :string, allow_nil?: false
argument :user_id, :string, allow_nil?: false

filter expr(team_id == ^arg(:team_id) and user_id == ^arg(:user_id))
end
end

code_interface do
define_for MyApp.Api

define :get_by_team_and_user, action: :get_by_team_and_user, get?: true, args: [:team_id, :user_id]
end
actions do
defaults [:create, :read, :update, :destroy]

read :get_by_team_and_user do
get? true
argument :team_id, :string, allow_nil?: false
argument :user_id, :string, allow_nil?: false

filter expr(team_id == ^arg(:team_id) and user_id == ^arg(:user_id))
end
end

code_interface do
define_for MyApp.Api

define :get_by_team_and_user, action: :get_by_team_and_user, get?: true, args: [:team_id, :user_id]
end
MyApp.Api This will be like this or MyApp.Accounts.Api?
frankdugan3
frankdugan3β€’3y ago
Depends entirely on how you set it up. You'll use whichever Api has this resource in its registry.
talha-azeem
talha-azeemOPβ€’3y ago
got it. Let me try to implement it @frankdugan3 it gives me an error
** (UndefinedFunctionError) function AppName.Accounts.Api.read_one/2 is undefined (module AppName.Accounts.Api is not available)
** (UndefinedFunctionError) function AppName.Accounts.Api.read_one/2 is undefined (module AppName.Accounts.Api is not available)
even though i have aliased it
frankdugan3
frankdugan3β€’3y ago
How are you calling it?
talha-azeem
talha-azeemOPβ€’3y ago
(app_name 0.1.0) lib/ash/code_interface.ex:348: AppName.Accounts.TeamJoinedUser.get_by_team_and_user/4
(app_name 0.1.0) lib/ash/code_interface.ex:348: AppName.Accounts.TeamJoinedUser.get_by_team_and_user/4
frankdugan3
frankdugan3β€’3y ago
Also, do you have the API in config.exs?
config :app_name,
ash_apis: [
AppName.Accounts.Api,
# ...
]
config :app_name,
ash_apis: [
AppName.Accounts.Api,
# ...
]
talha-azeem
talha-azeemOPβ€’3y ago
in my liveview i am calling it like this TeamJoinedUser.get_by_team_and_user(team_id, user_id) yes but it is defined like AppName.Accounts
frankdugan3
frankdugan3β€’3y ago
OK, it's hard to debug when you don't provide the module details. If your Api is defined defmodule AppName.Accounts do, then you need to refer to it that way, not as AppName.Accounts.Api.
talha-azeem
talha-azeemOPβ€’3y ago
I can provide details that you need. What should i send?
frankdugan3
frankdugan3β€’3y ago
The Api module to start with.
talha-azeem
talha-azeemOPβ€’3y ago
This was the issue. Thank you so much @frankdugan3 πŸ™ŒπŸ»

Did you find this page helpful?