defmodule Ash.Query.Calculation do @moduledoc "Represents a calculated attribute requested on a query" defstruct [ :name, :module, :opts, :load, :type, :constraints, :calc_name, context: %{}, required_loads: [], select: [], filterable?: true, sortable?: true, sensitive?: false ] @type t :: %__MODULE__{} @opt_schema [ arguments: [ type: :map, doc: "Arguments to pass to the calculation", default: %{} ], filterable?: [ type: :boolean, doc: "Whether or not this calculation can be filtered on", default: true ], sortable?: [ type: :boolean, doc: "Whether or not this calculation can be sorted on", default: true ], sensitive?: [ type: :boolean, doc: "Whether or not references to this calculation will be considered sensitive", default: false ], load: [ type: :any, doc: "Loads that are required for the calculation." ], source_context: [ type: :map, doc: "Context from the source query or changeset.", default: %{} ] ] @doc """ Creates a new query calculation. ## Options #{Spark.Options.docs(@opt_schema)} """ def new( name, module, calc_opts, type, constraints, opts \\ [] ) do with {:ok, opts} <- Spark.Options.validate(opts, @opt_schema), {:ok, calc_opts} <- module.init(calc_opts) do context = %Ash.Resource.Calculation.Context{ arguments: opts[:arguments], type: type, constraints: constraints, source_context: opts[:source_context] } {:ok, %__MODULE__{ name: name, module: module, type: type, opts: calc_opts, calc_name: name, constraints: constraints, context: context, required_loads: opts[:load], filterable?: opts[:filterable?], sortable?: opts[:sortable?], sensitive?: opts[:sensitive?] }} end end defimpl Inspect do import Inspect.Algebra def inspect(%{module: module, opts: calculation_opts, context: context}, _opts) do context = Map.drop(context, [ :actor, :authorize?, :all_referenced_calcs_support_expressions?, :filter_requests, :initial_limit, :initial_offset, :context, :tenant, :tracer, :ash ]) if context == %{} do module.describe(calculation_opts) else concat([module.describe(calculation_opts), " - ", inspect(context)]) end end end end