xSHYNE
xSHYNE
AEAsh Elixir
Created by xSHYNE on 8/10/2023 in #support
DISTINCT ON LEAST() GREATEST()
SELECT DISTINCT ON (LEAST(author_id, recipient_id), GREATEST(author_id, recipient_id)) id, text, author_id, recipient_id FROM private_messages WHERE author_id = ? OR recipient_id = ? ORDER BY LEAST(author_id, recipient_id), GREATEST(author_id, recipient_id), inserted_at DESC; This is the query that I would like to run. I am not quite sure after combing through the Ash docs, unfortunately Ash.Query.distinct([:author_id, recipient_id]) does not quite get me what I am looking for. The point of this query is to hydrate a view in my application similar to whatsapp, groupme, facebook messages that displays for each user you have messages with the last message sent. The way I set my database up I did not create an inbox for each user which would have made this a ton easier. Instead I have a private message that has exactly whats listed above, an id, text, author_id, recipient_id and an inserted_at. I want to basically do a window function or distinct and grab the greatest inserted at for each unique combination of author and recipient. A conversation would be englishified by saying that its all private_messages for a user_id that is equal to the author_id OR the recipient_id Is there an easier way to go about doing this? If not, how do I even run this as a fragment? Is it possible to return my PrivateMessage resource as a result? I realize I could solve all of this by reworking my database, and I'm more than willing to do that, the thing is I know I'll need to be doing these sorts of queries in the future for analytics purposes as well. Any suggestions? I've spun my head around this for a bit.
7 replies
AEAsh Elixir
Created by xSHYNE on 7/20/2023 in #support
Policy checks on related resources
I have been looking for quite some time so this may be a noob ish question. I have a couple answers potentially but I'd like to know kind of the standard way to write a policy for a resource where the relationship to that resource is how I would authorize the actor. For example Let's say I have a GroupRequest resource which represents a users request to join a group (contains a group_id and user_id) I also have a Group that has a group_admin relationship which belongs to a user. I'd only like actions occuring on a GroupRequest to be performed by the group_admin (and other similar resources such as GroupUser or GroupMembership) So the way I'd like to authorize the actor is via
authorize_if(relates_to_actor_via([:group, :group_admin]))
authorize_if(relates_to_actor_via([:group, :group_admin]))
which I believe is giving me what I want. but I can't seem to figure out how to write a policy for a create_action in the same way. Lets say for a create action I'd like to "destroy" or "update" a group_request and then create the group_membership, but I'm not sure how to write a policy that does this. A simple check seems correct but how do I pass the group_id from the create action into the check? Did I go about this the wrong way? I also read I could potentially do a calculations field on any "group" related resource which loads the admin and then I do a check with the actor against that? What's the best scenario here?
10 replies
AEAsh Elixir
Created by xSHYNE on 7/13/2023 in #support
manage_relationship argument not relating primary key to resource
resource
create :add_to_group do
argument :group, :uuid do
allow_nil? false
end

change manage_relationship(:group, type: :append_and_remove)
change relate_actor(:member)
end
end

relationships do
belongs_to(:group, Digsync.Accounts.Group, primary_key?: true, allow_nil?: false)
belongs_to(:member, Digsync.Accounts.User, primary_key?: true, allow_nil?: false)
end
create :add_to_group do
argument :group, :uuid do
allow_nil? false
end

change manage_relationship(:group, type: :append_and_remove)
change relate_actor(:member)
end
end

relationships do
belongs_to(:group, Digsync.Accounts.Group, primary_key?: true, allow_nil?: false)
belongs_to(:member, Digsync.Accounts.User, primary_key?: true, allow_nil?: false)
end
changeset after GroupMembership |> Ash.Changeset.for_create(:add_to_group, %{group: group_id})
#Ash.Changeset<
action_type: :create,
action: :add_to_group,
attributes: %{},
relationships: %{
group: [
{"b6937067-651d-4385-8323-20f193f03cd9",
[
ignore?: false,
on_missing: :unrelate,
on_match: :ignore,
on_lookup: :relate,
on_no_match: :error,
eager_validate_with: false,
authorize?: true,
meta: [inputs_was_list?: false, id: :group],
type: :append_and_remove
]}
],
member: [
{[
#Digsync.Accounts.User<
id: "b86d7074-a35a-4df6-8eac-a60327cc254f",
>
],
[
ignore?: false,
on_missing: :unrelate,
on_match: :ignore,
on_lookup: :relate,
on_no_match: :error,
eager_validate_with: false,
authorize?: true,
type: :append_and_remove,
meta: [inputs_was_list?: false]
]}
]
},
arguments: %{group: "b6937067-651d-4385-8323-20f193f03cd9"},
errors: [],
>,
valid?: true
>
#Ash.Changeset<
action_type: :create,
action: :add_to_group,
attributes: %{},
relationships: %{
group: [
{"b6937067-651d-4385-8323-20f193f03cd9",
[
ignore?: false,
on_missing: :unrelate,
on_match: :ignore,
on_lookup: :relate,
on_no_match: :error,
eager_validate_with: false,
authorize?: true,
meta: [inputs_was_list?: false, id: :group],
type: :append_and_remove
]}
],
member: [
{[
#Digsync.Accounts.User<
id: "b86d7074-a35a-4df6-8eac-a60327cc254f",
>
],
[
ignore?: false,
on_missing: :unrelate,
on_match: :ignore,
on_lookup: :relate,
on_no_match: :error,
eager_validate_with: false,
authorize?: true,
type: :append_and_remove,
meta: [inputs_was_list?: false]
]}
]
},
arguments: %{group: "b6937067-651d-4385-8323-20f193f03cd9"},
errors: [],
>,
valid?: true
>
** (Ash.Error.Invalid) Input Invalid

* record with "b6937067-651d-4385-8323-20f193f03cd9" not found
(ash 2.11.6) lib/ash/api/api.ex:2124: Ash.Api.unwrap_or_raise!/3
** (Ash.Error.Invalid) Input Invalid

* record with "b6937067-651d-4385-8323-20f193f03cd9" not found
(ash 2.11.6) lib/ash/api/api.ex:2124: Ash.Api.unwrap_or_raise!/3
I'm very confused, that id absolute exists and is a Group. When I do a different relationship which is coded almost identically it has a different data structure for the id:
action_type: :create,
action: :create_from_flow,
attributes: %{},
relationships: %{
friend_one: [
{[%{id: "266d68e7-3a8b-401a-a616-1b42c385a811"}],
action_type: :create,
action: :create_from_flow,
attributes: %{},
relationships: %{
friend_one: [
{[%{id: "266d68e7-3a8b-401a-a616-1b42c385a811"}],
22 replies
AEAsh Elixir
Created by xSHYNE on 7/12/2023 in #support
Ash Admin dependency for newest liveview
Because your app depends on ash_admin ~> 0.8.1 which depends on phoenix_live_view ~> 0.18.3, phoenix_live_view ~> 0.18.3 is required.
So, because your app depends on phoenix_live_view ~> 0.19.0, version solving failed.
Because your app depends on ash_admin ~> 0.8.1 which depends on phoenix_live_view ~> 0.18.3, phoenix_live_view ~> 0.18.3 is required.
So, because your app depends on phoenix_live_view ~> 0.19.0, version solving failed.
Anyway to solve this? or have to wait for update? create an issue?
4 replies
AEAsh Elixir
Created by xSHYNE on 7/7/2023 in #support
Ash.Query.load not loading nested relationship?
User |> Ash.Query.load([friendships: [:first, :second]])
|> Accounts.read!()

#Ash.Query<
resource: User,
errors: [
%Ash.Error.Query.InvalidLoad{
load: :first,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [:friendships, :load],
stacktrace: #Stacktrace<>,
class: :invalid
},
%Ash.Error.Query.InvalidLoad{
load: :second,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [:friendships, :load],
stacktrace: #Stacktrace<>,
class: :invalid
}
]
>
User |> Ash.Query.load([friendships: [:first, :second]])
|> Accounts.read!()

#Ash.Query<
resource: User,
errors: [
%Ash.Error.Query.InvalidLoad{
load: :first,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [:friendships, :load],
stacktrace: #Stacktrace<>,
class: :invalid
},
%Ash.Error.Query.InvalidLoad{
load: :second,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [:friendships, :load],
stacktrace: #Stacktrace<>,
class: :invalid
}
]
>
this gives an invalid load BUT:
Friendship |> Ash.Query.load([:first, :second]) |> Accounts.read!()

#Friendship<
second: User<>
first: User<>
Friendship |> Ash.Query.load([:first, :second]) |> Accounts.read!()

#Friendship<
second: User<>
first: User<>
works fine? Why can't I load nested on the parent many_to_many relationship?
19 replies