# `Selecto.Types`

Comprehensive type definitions for the Selecto query builder.

This module defines all the types used throughout Selecto for better
developer experience and Dialyzer support.

# `advanced_join_type`

```elixir
@type advanced_join_type() ::
  :hierarchical | :tagging | :dimension | :star_dimension | :snowflake_dimension
```

# `association`

```elixir
@type association() :: %{
  :queryable =&gt; atom(),
  :field =&gt; atom(),
  :owner_key =&gt; atom(),
  :related_key =&gt; atom(),
  optional(:cardinality) =&gt; :one | :many,
  optional(:through) =&gt; [atom()]
}
```

# `atom_or_string`

```elixir
@type atom_or_string() :: atom() | String.t()
```

# `basic_filter`

```elixir
@type basic_filter() :: {field_name(), term()}
```

# `basic_join_config`

```elixir
@type basic_join_config() :: %{
  :type =&gt; basic_join_type(),
  optional(:name) =&gt; String.t(),
  optional(:on) =&gt; term(),
  optional(:joins) =&gt; %{required(atom()) =&gt; join_config()}
}
```

# `basic_join_type`

```elixir
@type basic_join_type() :: :left | :right | :inner | :full
```

# `basic_selector`

```elixir
@type basic_selector() :: field_name()
```

# `builder_result`

```elixir
@type builder_result() :: {iodata_with_markers(), sql_params(), join_dependencies()}
```

# `case_selector`

```elixir
@type case_selector() ::
  {:case, conditions :: [{condition :: term(), value :: term()}],
   else_value :: term()}
```

# `column_definition`

```elixir
@type column_definition() :: %{
  :type =&gt; column_type(),
  optional(:icon) =&gt; atom() | String.t(),
  optional(:icon_family) =&gt; atom() | String.t(),
  optional(:presentation_type) =&gt;
    :date | :datetime | :utc_datetime | :naive_datetime,
  optional(:presentation) =&gt; %{
    optional(:semantic_type) =&gt; :measurement | :temporal | :number,
    optional(:quantity) =&gt; atom() | String.t(),
    optional(:canonical_unit) =&gt; atom() | String.t(),
    optional(:available_units) =&gt; [atom() | String.t()],
    optional(:default_unit) =&gt; atom() | String.t(),
    optional(:temporal_kind) =&gt;
      :instant | :local_date | :local_time | :naive_datetime,
    optional(:storage_timezone) =&gt; String.t(),
    optional(:display_timezone) =&gt; :viewer | String.t(),
    optional(:format) =&gt; map()
  },
  optional(:datetime_storage) =&gt;
    :unix
    | :unix_s
    | :unix_seconds
    | :unix_ms
    | :unix_milliseconds
    | :javascript_ms,
  optional(:precision) =&gt; pos_integer(),
  optional(:scale) =&gt; non_neg_integer(),
  optional(:default) =&gt; term(),
  optional(:null) =&gt; boolean()
}
```

# `column_type`

```elixir
@type column_type() ::
  :integer
  | :string
  | :text
  | :boolean
  | :decimal
  | :float
  | :date
  | :time
  | :utc_datetime
  | :naive_datetime
  | :binary
  | :uuid
  | :json
  | :jsonb
  | :array
  | :geometry
  | :geography
  | :point
  | :linestring
  | :polygon
  | :multipoint
  | :multilinestring
  | :multipolygon
  | :geometrycollection
```

# `comparison_filter`

```elixir
@type comparison_filter() :: {field_name(), {comparison_operator(), term()}}
```

# `comparison_operator`

```elixir
@type comparison_operator() ::
  :eq
  | :not_eq
  | :gt
  | :gte
  | :lt
  | :lte
  | :like
  | :ilike
  | :not_like
  | :not_ilike
  | :is_null
  | :not_null
  | :in
  | :not_in
  | :between
  | :not_between
```

# `configure_options`

```elixir
@type configure_options() :: [
  validate: boolean(),
  pool: boolean(),
  pool_options: keyword(),
  adapter: module(),
  rollup_sort_fix: boolean() | :auto
]
```

# `cte_builder_result`

```elixir
@type cte_builder_result() ::
  {iodata_with_markers(), sql_params(), [cte_definition()]}
```

# `cte_definition`

```elixir
@type cte_definition() :: %{
  name: String.t(),
  sql: iodata_with_markers(),
  params: sql_params(),
  recursive: boolean()
}
```

# `cte_marker`

```elixir
@type cte_marker() :: {:cte, name :: String.t(), iodata_fragment()}
```

# `custom_selector`

```elixir
@type custom_selector() :: {:custom, sql :: String.t(), params :: [term()]}
```

# `detail_action`

```elixir
@type detail_action() :: %{
  :name =&gt; String.t(),
  :type =&gt; detail_action_type(),
  optional(:description) =&gt; String.t(),
  optional(:required_fields) =&gt; [field_name()],
  optional(:payload) =&gt; map()
}
```

# `detail_action_type`

```elixir
@type detail_action_type() ::
  :modal | :iframe_modal | :external_link | :live_component
```

# `dimension_join_config`

```elixir
@type dimension_join_config() :: %{
  :type =&gt; :dimension | :star_dimension | :snowflake_dimension,
  :display_field =&gt; atom(),
  optional(:dimension_key) =&gt; atom(),
  optional(:normalization_joins) =&gt; [
    %{table: String.t(), key: atom(), foreign_key: atom()}
  ],
  optional(:joins) =&gt; %{required(atom()) =&gt; join_config()}
}
```

# `domain`

```elixir
@type domain() :: %{
  :name =&gt; String.t(),
  :source =&gt; source(),
  :schemas =&gt; %{required(atom()) =&gt; schema()},
  :joins =&gt; %{required(atom()) =&gt; join_config()},
  optional(:default_selected) =&gt; [selector()],
  optional(:required_filters) =&gt; [filter()],
  optional(:required_selected) =&gt; [selector()],
  optional(:required_order_by) =&gt; [order_spec()],
  optional(:required_group_by) =&gt; [field_name()],
  optional(:filters) =&gt; %{required(String.t()) =&gt; term()},
  optional(:detail_actions) =&gt; %{
    optional(atom() | String.t()) =&gt; detail_action()
  },
  optional(:domain_data) =&gt; term(),
  optional(:extensions) =&gt; [term()],
  optional(:functions) =&gt; function_registry(),
  optional(:query_members) =&gt; query_member_registry(),
  optional(:published_views) =&gt; published_view_registry()
}
```

# `domain_option_provider`

```elixir
@type domain_option_provider() :: %{
  type: :domain,
  domain: atom(),
  value_field: atom(),
  display_field: atom(),
  filters: [filter()],
  order_by: [order_spec()]
}
```

# `enum_option_provider`

```elixir
@type enum_option_provider() :: %{type: :enum, schema: module(), field: atom()}
```

# `execute_one_result_error`

```elixir
@type execute_one_result_error() :: {:error, Selecto.Error.t()}
```

# `execute_one_result_ok`

```elixir
@type execute_one_result_ok() :: {:ok, single_row_result()}
```

# `execute_options`

```elixir
@type execute_options() :: [
  timeout: timeout(),
  log: boolean(),
  max_rows: pos_integer(),
  receive_timeout: timeout(),
  queue_timeout: timeout(),
  stream_timeout: timeout(),
  analyze_complexity: boolean(),
  format: term(),
  format_options: keyword() | map(),
  cache: boolean(),
  cache_ttl: pos_integer(),
  cache_namespace: String.t(),
  stream_producer: function()
]
```

# `execute_result_error`

```elixir
@type execute_result_error() :: {:error, Selecto.Error.t()}
```

# `execute_result_ok`

```elixir
@type execute_result_ok() :: {:ok, query_result()}
```

# `execute_stream_result_error`

```elixir
@type execute_stream_result_error() :: {:error, Selecto.Error.t()}
```

# `execute_stream_result_ok`

```elixir
@type execute_stream_result_ok() :: {:ok, Enumerable.t()}
```

# `extract_selector`

```elixir
@type extract_selector() :: {:extract, part :: String.t(), from_field :: field_name()}
```

# `field_name`

```elixir
@type field_name() :: atom() | String.t()
```

# `filter`

```elixir
@type filter() :: basic_filter() | comparison_filter() | logical_filter()
```

# `function_arg_spec`

```elixir
@type function_arg_spec() :: %{
  name: atom() | String.t(),
  type: term(),
  source: :selector | :value | :literal
}
```

# `function_kind`

```elixir
@type function_kind() :: :scalar | :predicate | :table
```

# `function_registry`

```elixir
@type function_registry() :: %{optional(atom() | String.t()) =&gt; function_spec()}
```

# `function_selector`

```elixir
@type function_selector() ::
  {:func, function_name :: String.t(), args :: [field_name() | term()]}
```

# `function_spec`

```elixir
@type function_spec() :: %{
  :kind =&gt; function_kind(),
  :sql_name =&gt; String.t(),
  optional(:args) =&gt; [function_arg_spec()],
  optional(:returns) =&gt; term(),
  optional(:allowed_in) =&gt; [atom()]
}
```

# `hierarchical_join_config`

```elixir
@type hierarchical_join_config() :: %{
  :type =&gt; :hierarchical,
  :hierarchy_type =&gt; hierarchy_type(),
  optional(:depth_limit) =&gt; pos_integer(),
  optional(:path_field) =&gt; atom(),
  optional(:path_separator) =&gt; String.t(),
  optional(:root_condition) =&gt; term(),
  optional(:joins) =&gt; %{required(atom()) =&gt; join_config()}
}
```

# `hierarchy_type`

```elixir
@type hierarchy_type() :: :adjacency_list | :materialized_path | :closure_table
```

# `iodata_fragment`

```elixir
@type iodata_fragment() :: iolist() | String.t()
```

# `iodata_with_markers`

```elixir
@type iodata_with_markers() :: [iodata_fragment() | param_marker() | cte_marker()]
```

# `join_config`

```elixir
@type join_config() ::
  basic_join_config()
  | hierarchical_join_config()
  | tagging_join_config()
  | dimension_join_config()
```

# `join_dependencies`

```elixir
@type join_dependencies() :: [join_requirement()]
```

# `join_requirement`

```elixir
@type join_requirement() :: {join_name :: atom(), required_for :: String.t()}
```

# `join_type`

```elixir
@type join_type() :: basic_join_type() | advanced_join_type()
```

# `logical_filter`

```elixir
@type logical_filter() :: {:and | :or, [filter()]}
```

# `maybe`

```elixir
@type maybe(t) :: {:ok, t} | {:error, term()}
```

# `option_provider`

```elixir
@type option_provider() ::
  static_option_provider()
  | domain_option_provider()
  | enum_option_provider()
  | query_option_provider()
```

# `order_direction`

```elixir
@type order_direction() :: :asc | :desc
```

# `order_spec`

```elixir
@type order_spec() :: field_name() | {order_direction(), field_name()}
```

# `param_marker`

```elixir
@type param_marker() :: {:param, term()}
```

# `pivot_config`

```elixir
@type pivot_config() :: retarget_config()
```

# `pivot_join_path`

```elixir
@type pivot_join_path() :: retarget_join_path()
```

# `processed_config`

```elixir
@type processed_config() :: %{
  :source =&gt; source(),
  :source_table =&gt; table_name(),
  :primary_key =&gt; atom(),
  :columns =&gt; %{required(String.t()) =&gt; %{name: String.t()}},
  :joins =&gt; %{required(atom()) =&gt; processed_join()},
  :filters =&gt; %{required(String.t()) =&gt; term()},
  optional(:functions) =&gt; function_registry(),
  :domain_data =&gt; term(),
  optional(:extensions) =&gt; [{module(), keyword()}]
}
```

# `processed_join`

```elixir
@type processed_join() :: %{
  :type =&gt; join_type(),
  :source =&gt; atom() | String.t(),
  :name =&gt; String.t(),
  optional(:fields) =&gt; %{required(String.t()) =&gt; %{name: String.t()}},
  optional(:filters) =&gt; %{required(String.t()) =&gt; term()},
  optional(:joins) =&gt; %{required(atom()) =&gt; processed_join()},
  optional(:parameters) =&gt; [term()],
  optional(:hierarchy_type) =&gt; hierarchy_type(),
  optional(:depth_limit) =&gt; pos_integer(),
  optional(:path_field) =&gt; atom(),
  optional(:path_separator) =&gt; String.t(),
  optional(:tag_field) =&gt; atom(),
  optional(:weight_field) =&gt; atom(),
  optional(:display_field) =&gt; atom(),
  optional(:dimension_key) =&gt; atom()
}
```

# `published_view_kind`

```elixir
@type published_view_kind() :: :view | :materialized_view
```

# `published_view_registry`

```elixir
@type published_view_registry() :: %{
  optional(atom() | String.t()) =&gt; published_view_spec()
}
```

# `published_view_spec`

```elixir
@type published_view_spec() :: %{
  :database_name =&gt; String.t(),
  :kind =&gt; published_view_kind(),
  :query =&gt; function(),
  :columns =&gt; %{optional(atom() | String.t()) =&gt; map()},
  optional(:indexes) =&gt; [map()],
  optional(:refresh) =&gt; map()
}
```

# `query_member_registry`

```elixir
@type query_member_registry() :: %{
  optional(:ctes) =&gt; %{optional(atom() | String.t()) =&gt; map()},
  optional(:values) =&gt; %{optional(atom() | String.t()) =&gt; map()},
  optional(:subqueries) =&gt; %{optional(atom() | String.t()) =&gt; map()},
  optional(:laterals) =&gt; %{optional(atom() | String.t()) =&gt; map()},
  optional(:unnests) =&gt; %{optional(atom() | String.t()) =&gt; map()}
}
```

# `query_option_provider`

```elixir
@type query_option_provider() :: %{type: :query, query: String.t(), params: [term()]}
```

# `query_result`

```elixir
@type query_result() ::
  {rows :: [[term()]], columns :: [String.t()],
   aliases :: %{required(String.t()) =&gt; String.t()}}
```

# `query_set`

```elixir
@type query_set() :: %{
  :selected =&gt; [selector()],
  :filtered =&gt; [filter()],
  optional(:required_filters) =&gt; [filter()],
  optional(:post_retarget_filters) =&gt; [filter()],
  optional(:post_pivot_filters) =&gt; [filter()],
  :order_by =&gt; [order_spec()],
  :group_by =&gt; [field_name()],
  optional(:retarget_state) =&gt; retarget_config(),
  optional(:pivot_state) =&gt; retarget_config(),
  optional(:subselected) =&gt; [subselect_selector()]
}
```

# `relation_source_kind`

```elixir
@type relation_source_kind() :: :table | :view | :materialized_view
```

# `result`

```elixir
@type result(t, e) :: {:ok, t} | {:error, e}
```

# `retarget_config`

```elixir
@type retarget_config() :: %{
  :target_schema =&gt; atom(),
  :join_path =&gt; [atom()],
  optional(:preserve_filters) =&gt; boolean(),
  optional(:subquery_strategy) =&gt; :exists | :in | :join
}
```

# `retarget_join_path`

```elixir
@type retarget_join_path() :: [
  %{
    from_schema: atom(),
    to_schema: atom(),
    association_name: atom(),
    join_type: join_type()
  }
]
```

# `safe_execute_one_result`

```elixir
@type safe_execute_one_result() ::
  execute_one_result_ok() | execute_one_result_error()
```

# `safe_execute_result`

```elixir
@type safe_execute_result() :: execute_result_ok() | execute_result_error()
```

# `safe_execute_stream_result`

```elixir
@type safe_execute_stream_result() ::
  execute_stream_result_ok() | execute_stream_result_error()
```

# `schema`

```elixir
@type schema() :: %{
  :name =&gt; String.t(),
  :source_table =&gt; table_name(),
  :primary_key =&gt; atom(),
  :fields =&gt; [atom()],
  :redact_fields =&gt; [atom()],
  :columns =&gt; %{required(atom()) =&gt; column_definition()},
  :associations =&gt; %{required(atom()) =&gt; association()},
  optional(:source_kind) =&gt; relation_source_kind(),
  optional(:readonly) =&gt; boolean(),
  optional(:custom_filters) =&gt; %{required(atom()) =&gt; term()}
}
```

# `select_options_column`

```elixir
@type select_options_column() :: %{
  :type =&gt; :select_options,
  :option_provider =&gt; option_provider(),
  :name =&gt; String.t(),
  optional(:multiple) =&gt; boolean(),
  optional(:searchable) =&gt; boolean(),
  optional(:cache_ttl) =&gt; pos_integer()
}
```

# `selector`

```elixir
@type selector() ::
  basic_selector()
  | function_selector()
  | case_selector()
  | extract_selector()
  | window_selector()
  | custom_selector()
```

# `single_row_result`

```elixir
@type single_row_result() ::
  {row :: [term()], aliases :: %{required(String.t()) =&gt; String.t()}}
```

# `source`

```elixir
@type source() :: %{
  :source_table =&gt; table_name(),
  :primary_key =&gt; atom(),
  :fields =&gt; [atom()],
  :redact_fields =&gt; [atom()],
  :columns =&gt; %{required(atom()) =&gt; column_definition()},
  :associations =&gt; %{required(atom()) =&gt; association()},
  optional(:source_kind) =&gt; relation_source_kind(),
  optional(:readonly) =&gt; boolean()
}
```

# `sql_error`

```elixir
@type sql_error() :: term()
```

# `sql_generation_options`

```elixir
@type sql_generation_options() :: [
  include_comments: boolean(),
  pretty_print: boolean()
]
```

# `sql_params`

```elixir
@type sql_params() :: [term()]
```

# `sql_result`

```elixir
@type sql_result() :: {sql :: String.t(), params :: sql_params()}
```

# `static_option_provider`

```elixir
@type static_option_provider() :: %{type: :static, values: [term()]}
```

# `stream_row_result`

```elixir
@type stream_row_result() ::
  {row :: [term()], columns :: [String.t()], aliases :: [String.t()]}
```

# `subselect_config`

```elixir
@type subselect_config() :: %{
  :target_table =&gt; table_name(),
  :join_condition =&gt; {field_name(), field_name()},
  :aggregation_type =&gt; subselect_format(),
  optional(:additional_filters) =&gt; [filter()]
}
```

# `subselect_format`

```elixir
@type subselect_format() :: :json_agg | :array_agg | :string_agg | :count
```

# `subselect_selector`

```elixir
@type subselect_selector() :: %{
  :fields =&gt; [field_name()],
  :target_schema =&gt; atom(),
  :format =&gt; subselect_format(),
  optional(:alias) =&gt; String.t(),
  optional(:join_path) =&gt; [atom() | String.t()],
  optional(:separator) =&gt; String.t(),
  optional(:order_by) =&gt; [order_spec()],
  optional(:filters) =&gt; [filter()]
}
```

# `t`

```elixir
@type t() :: %Selecto{
  adapter: module() | nil,
  config: processed_config(),
  connection: term() | nil,
  domain: domain(),
  extensions: [{module(), keyword()}],
  postgrex_opts: term() | nil,
  set: query_set(),
  tenant: tenant_context() | nil
}
```

# `table_name`

```elixir
@type table_name() :: String.t()
```

# `tagging_join_config`

```elixir
@type tagging_join_config() :: %{
  :type =&gt; :tagging,
  :tag_field =&gt; atom(),
  optional(:weight_field) =&gt; atom(),
  optional(:min_weight) =&gt; number(),
  optional(:aggregation) =&gt; :string_agg | :array_agg | :count,
  optional(:separator) =&gt; String.t(),
  optional(:joins) =&gt; %{required(atom()) =&gt; join_config()}
}
```

# `tenant_context`

```elixir
@type tenant_context() :: %{
  optional(:tenant_id) =&gt; term(),
  optional(:tenant_mode) =&gt; atom() | String.t(),
  optional(:tenant_field) =&gt; atom() | String.t(),
  optional(:prefix) =&gt; String.t(),
  optional(:namespace) =&gt; String.t(),
  optional(:required_filters) =&gt; [filter()]
}
```

# `window_selector`

```elixir
@type window_selector() ::
  {:window, function_name :: String.t(), args :: [term()],
   window_spec :: term()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
