defmodule Ash.Flow.Dsl do @debug %Spark.Dsl.Entity{ name: :debug, describe: """ Declares a step that will inspect its input and provide additional debug information. """, examples: [ """ debug :show_some_information do input %{post: result(:create_post)} end """ ], target: Ash.Flow.Step.Debug, args: [:name], schema: Ash.Flow.Step.Debug.schema() } @create %Spark.Dsl.Entity{ name: :create, describe: """ Declares a step that will call a create action on a resource. """, examples: [ """ create :create_post, MyApp.Post, :create """ ], no_depend_modules: [:resource, :touches_resources], modules: [:manual], target: Ash.Flow.Step.Create, args: [:name, :resource, :action], schema: Ash.Flow.Step.Create.schema() } @update %Spark.Dsl.Entity{ name: :update, describe: """ Declares a step that will call a update action on a resource. """, examples: [ """ update :update_post, MyApp.Post, :update do record result(:get_post) end """ ], no_depend_modules: [:resource, :touches_resources], modules: [:manual], target: Ash.Flow.Step.Update, args: [:name, :resource, :action], schema: Ash.Flow.Step.Update.schema() } @validate %Spark.Dsl.Entity{ name: :validate, describe: """ Validates some input against an action. """, examples: [ """ validate :update_post, MyApp.Post, :update do record result(:get_post) only_keys [:name] end """ ], no_depend_modules: [:resource, :touches_resources], target: Ash.Flow.Step.Update, args: [:name, :resource, :action], schema: Ash.Flow.Step.Validate.schema() } @destroy %Spark.Dsl.Entity{ name: :destroy, describe: """ Declares a step that will call a destroy action on a resource. """, examples: [ """ destroy :destroy_post, MyApp.Post, :destroy """ ], modules: [:manual], no_depend_modules: [:resource, :touches_resources], target: Ash.Flow.Step.Destroy, args: [:name, :resource, :action], schema: Ash.Flow.Step.Destroy.schema() } @read %Spark.Dsl.Entity{ name: :read, describe: """ Declares a step that will call a read action on a resource. """, examples: [ """ read :destroy_post, MyApp.Post, :destroy """ ], no_depend_modules: [:resource, :touches_resources], modules: [:manual], target: Ash.Flow.Step.Read, args: [:name, :resource, :action], schema: Ash.Flow.Step.Read.schema() } @run_flow %Spark.Dsl.Entity{ name: :run_flow, describe: """ Runs another flow as part of the current flow. The return value of the step is the return value of the flow. """, examples: [ """ run_flow :get_org, GetOrgByName do input %{ name: arg(:org_name) } """ ], no_depend_modules: [:resource, :touches_resources], target: Ash.Flow.Step.RunFlow, args: [:name, :flow], schema: Ash.Flow.Step.RunFlow.schema() } @custom %Spark.Dsl.Entity{ name: :custom, describe: """ Runs a custom step module. See `Ash.Flow.Step` for the necessary callbacks and more information. """, examples: [ """ custom :do_custom_thing, MyApp.DoCustomThing do input %{...} end """, """ custom :do_custom_thing, {MyApp.DoCustomThing, opt1: :foo, opt2: :bar} do input %{...} end """ ], no_depend_modules: [:custom, :touches_resources], target: Ash.Flow.Step.Custom, args: [:name, :custom], schema: Ash.Flow.Step.Custom.schema() } @argument %Spark.Dsl.Entity{ name: :argument, describe: """ An argument to be passed into the flow """, examples: [ """ argument :params, :map do default %{} end """, """ argument :retries, :integer do allow_nil? false end """ ], no_depend_modules: [:type], target: Ash.Flow.Argument, args: [:name, :type], transform: {Ash.Type, :set_type_transformation, []}, schema: Ash.Flow.Argument.schema() } @flow %Spark.Dsl.Section{ name: :flow, describe: """ Details about the flow itself, like description and the successful return type. """, entities: [ @argument ], schema: [ api: [ type: {:behaviour, Ash.Api}, doc: "An api to use by default when calling actions" ], description: [ type: :string, doc: "A description of the flow" ], trace_name: [ type: :string, doc: "The name to use when creating traces. Defaults to the short name." ], short_name: [ type: :atom, doc: "A short name to use for the flow. Defaults to the last to parts of the module name, underscored." ], returns: [ type: :any, doc: """ The step or step that should constitute the return value. """ ] ] } @leaf_steps [@create, @debug, @update, @destroy, @validate, @read, @run_flow, @custom] @transaction %Spark.Dsl.Entity{ name: :transaction, describe: """ Runs a set of steps in a transaction. """, schema: Ash.Flow.Step.Transaction.schema(), target: Ash.Flow.Step.Transaction, args: [:name, :resource], recursive_as: :steps, entities: [ steps: @leaf_steps ], no_depend_modules: [:touches_resources], examples: [ """ transaction :create_users do create :create_user, User, :create do input %{ first_name: {Faker.Person, :first_name, []}, last_name: {Faker.Person, :last_name, []} } end create :create_user, Org, :create do input %{ first_name: {Faker.Person, :first_name, []}, last_name: {Faker.Person, :last_name, []} } end end """ ] } @map %Spark.Dsl.Entity{ name: :map, describe: """ Runs a set of steps for each item in a provided list. """, schema: Ash.Flow.Step.Map.schema(), target: Ash.Flow.Step.Map, args: [:name, :over], recursive_as: :steps, no_depend_modules: [:touches_resources], entities: [ steps: @leaf_steps ], examples: [ """ map :create_users, range(1, arg(:count)) do output :create_user create :create_user, Org, :create do input %{ first_name: {Faker.Person, :first_name, []}, last_name: {Faker.Person, :last_name, []} } end end """ ] } @branch %Spark.Dsl.Entity{ name: :branch, describe: """ Runs a set of steps based on a given value. """, schema: Ash.Flow.Step.Branch.schema(), target: Ash.Flow.Step.Branch, args: [:name, :condition], recursive_as: :steps, no_depend_modules: [:touches_resources], entities: [ steps: @leaf_steps ], examples: [ """ branch :create_users, result(:create_users?) do output :create_user create :create_user, Org, :create do input %{ first_name: {Faker.Person, :first_name, []}, last_name: {Faker.Person, :last_name, []} } end end """ ] } @steps %Spark.Dsl.Section{ name: :steps, describe: """ The steps to run. """, examples: [ """ steps do # invokes a create action create :create_post, MyApp.Post, :create end """ ], imports: [Ash.Flow.StepHelpers], entities: [ @map, @branch, @transaction ] ++ @leaf_steps } @transformers [ Ash.Flow.Transformers.SetApi ] @verifiers [ Ash.Flow.Verifiers.VerifyReturn, Ash.Flow.Verifiers.ValidateUniqueNames, Ash.Flow.Verifiers.ValidateNoEmptySteps ] @sections [@flow, @steps] @moduledoc """ The built in flow DSL. ## DSL Documentation ### Index #{Spark.Dsl.Extension.doc_index(@sections)} ### Docs #{Spark.Dsl.Extension.doc(@sections)} """ use Spark.Dsl.Extension, sections: @sections, transformers: @transformers, verifiers: @verifiers end