ash-project / ash

A declarative, extensible framework for building Elixir applications.
https://www.ash-hq.org
MIT License
1.46k stars 186 forks source link

Add ability to extend actions #966

Open zachdaniel opened 3 months ago

zachdaniel commented 3 months ago

The idea is that sometimes you have small variations on the same action that you want with slightly different modifiers.

In my case I wanted to expose the generated sign_in_with_password read action generated by AshAuthentication but change the token type (from :sign_in to :user) via GraphQL. What I had to do was copy the entire action and add a set_context/1 preparation. What I wanted to do was this:

extend :sign_in_with_password do
  as :sign_in_with_password_for_graphql
  prepare set_context(%{token_type: :user, strategy_name: :password})
end

Behind the scenes I expect that the transformer will load all the entities from the other action, and then prepend them to all the entities in the extend action.

This could be a bad idea. I am sure Zach will tell me why.

zachdaniel commented 3 months ago

This is definitely an interesting idea. There are some complexities w/ the construction if the action type is itself extend. But if we were to do it like so:

read :sign_in_with_password_for_graphql do
  extends :sign_in_with_password
  prepare set_context(%{token_type: :user, strategy_name: :password})
end

then we could make it work.

vonagam commented 2 months ago

You mentioned idea of templates (fragments for actions) and I think it might be better.

actions do
  create :create do
    uses :validate_email
  end

  update :update_email do
    uses :validate_email
  end

  template :validate_email do
    validate ...
    validate ...
    change ...
  end
end

Because if you have two methods A and B that have the same parts but also different ones you would need something C. In case of extending it would be a method, but you don't actually want it to be a separate method (to expose it and so on) and in this template example action types are even different - create and update - which won't be possible with simple extension of an action. Templates also allow multiple uses in the same action.

The only advantage action extension can theoretically provide is when you do not define an action that you want to extend by yourself - if it is automatically defined by some extension.

zachdaniel commented 2 months ago

I'm on board for the structure laid out, but not the term template (which was my term in the first place I'm aware 🙃) Ultimately we're talking about something that we compose, a simple named container of changes/validations.

vonagam commented 2 months ago

Synonyms for template:

Synonyms for uses:

zachdaniel commented 1 month ago

I think fragment is the best name for it, but unfortunately that is kind of taken...We could call them action_fragments

i.e

action_fragments do
  ...
end

Alternatively, what we could do is do this using modules:

defmodule Change do
  use Ash.Resource.Change.Composer

  ...some DSL here?

end

Its a bit heavier, and seems a bit obtuse, but has the benefit that they can be shared across resources.

vonagam commented 1 month ago

If you want fragment, why not just fragment? Yes, there is fragment in a query expression and there is Spark fragments, but that should be ok. And there should not be any import conflicts with those.

As for modules - I assume it will be both, like with most other things, where you will be able to define it inline (with fragment call) or in a module (to reuse between multiple resources). Both will be identified by atoms in uses call but collisions are unlikely (inline are lowercase and modules are capitalized).

zachdaniel commented 1 month ago

I'm cautious of conflating terms, and these terms are kind of related. i.e "how do I share action behavior? With fragments, no, not that kind of fragment, this kind of fragment". Just want to make sure we've considered all the options. Haven't seen anything I really like yet TBH.

pierrelegall commented 1 month ago

I'm not english native, but what do you think about "piece"?

vonagam commented 1 month ago

There is also "pattern" and "recipe".