Current section
Files
Jump to
Current section
Files
lib/predicate/dsl/step.ex
defmodule Funx.Predicate.Dsl.Step do
@moduledoc false
# Data structure representing a single predicate check in the DSL.
#
# ## Fields
#
# - `projection`: Optional projection (optic, field, or function) to focus on
# - `predicate`: Quoted AST for the predicate function
# - `negate`: Boolean - true for `negate` directives
# - `type`: Projection type for optimization (:bare or :projection)
# - `__meta__`: Source location for error reporting
#
# ## Type Field
#
# The `type` field indicates the step type:
#
# - `:bare` - No projection, just a predicate
# - `:projection` - Has projection (optic, field, or function)
# - `:behaviour` - Behaviour module that returns a predicate
#
# ## Responsibilities
#
# This is a pure data container with no logic:
# - Parser: Creates Steps with optional projection and predicate AST
# - Executor: Composes projection with predicate if needed
@type projection :: Macro.t() | nil
@type projection_type :: :bare | :projection | :behaviour
@type t :: %__MODULE__{
projection: projection(),
predicate: Macro.t(),
negate: boolean(),
type: projection_type(),
__meta__: map()
}
defstruct [:projection, :predicate, :negate, :type, :__meta__]
@doc """
Creates a new step with the given predicate AST, negate flag, and metadata.
For bare predicates (no projection), pass nil for projection.
"""
@spec new(Macro.t(), boolean(), map()) :: t()
def new(predicate, negate \\ false, meta \\ %{}) do
%__MODULE__{
projection: nil,
predicate: predicate,
negate: negate,
type: :bare,
__meta__: meta
}
end
@doc """
Creates a new step with a projection and predicate.
Used for `on` directives that focus on a specific part of the data.
"""
@spec new_with_projection(Macro.t(), Macro.t(), boolean(), map()) :: t()
def new_with_projection(projection, predicate, negate \\ false, meta \\ %{}) do
%__MODULE__{
projection: projection,
predicate: predicate,
negate: negate,
type: :projection,
__meta__: meta
}
end
@doc """
Creates a new step for a behaviour module.
Used when a behaviour module is referenced in the DSL.
The `predicate` field contains the AST for calling `Module.pred(opts)`.
"""
@spec new_behaviour(Macro.t(), boolean(), map()) :: t()
def new_behaviour(behaviour_ast, negate \\ false, meta \\ %{}) do
%__MODULE__{
projection: nil,
predicate: behaviour_ast,
negate: negate,
type: :behaviour,
__meta__: meta
}
end
end