Selecto.TypeSystem (Selecto v0.4.5)

Copy Markdown

Type inference and coercion system for Selecto SQL expressions.

This module provides:

  • Type inference for expressions (fields, functions, literals, complex expressions)
  • Type compatibility checking for comparisons and set operations
  • Type coercion rules for implicit type conversions
  • Return type determination for SQL functions and aggregates

Type Categories

Selecto organizes SQL types into the following categories:

  • Numeric: :integer, :bigint, :smallint, :decimal, :float, :numeric
  • String: :string, :text, :varchar, :char
  • Boolean: :boolean
  • DateTime: :date, :time, :datetime, :utc_datetime, :naive_datetime, :timestamp
  • JSON: :json, :jsonb, :map
  • Array: {:array, inner_type}
  • Binary: :binary, :bytea
  • UUID: :uuid, :binary_id
  • Spatial: :geometry, :geography, :point, :polygon, etc.

Usage

# Infer type of an expression
{:ok, :integer} = Selecto.TypeSystem.infer_type(selecto, {:count, "*"})
{:ok, :decimal} = Selecto.TypeSystem.infer_type(selecto, {:sum, "price"})
{:ok, :string} = Selecto.TypeSystem.infer_type(selecto, "product_name")

# Check type compatibility
true = Selecto.TypeSystem.compatible?(:integer, :decimal)
false = Selecto.TypeSystem.compatible?(:string, :boolean)

# Get coerced type for operation
{:ok, :decimal} = Selecto.TypeSystem.coerce_types(:integer, :decimal, :arithmetic)

Summary

Functions

Determine the result type when coercing two types for an operation.

Check if two types are compatible for comparisons or assignments.

Check if a type is a date/time type.

Infer the SQL type of an expression.

Infer type and return just the type (for internal use where errors are handled upstream).

Normalize Ecto types to Selecto's internal type representation.

Check if a type is numeric.

Parse a SQL type string into an atom type.

Check if a type is a string type.

Get the type category for a given SQL type.

Types

sql_type()

@type sql_type() ::
  :unknown
  | :integer
  | :bigint
  | :smallint
  | :decimal
  | :float
  | :numeric
  | :string
  | :text
  | :varchar
  | :char
  | :boolean
  | :date
  | :time
  | :datetime
  | :utc_datetime
  | :naive_datetime
  | :timestamp
  | :json
  | :jsonb
  | :map
  | :binary
  | :bytea
  | :uuid
  | :binary_id
  | :geometry
  | :geography
  | :point
  | :linestring
  | :polygon
  | :multipoint
  | :multilinestring
  | :multipolygon
  | :geometrycollection
  | {:array, sql_type()}

type_category()

@type type_category() ::
  :numeric
  | :string
  | :boolean
  | :datetime
  | :json
  | :array
  | :binary
  | :uuid
  | :spatial
  | :unknown

Functions

coerce_types(type1, type2, operation)

@spec coerce_types(sql_type(), sql_type(), atom()) ::
  {:ok, sql_type()} | {:error, String.t()}

Determine the result type when coercing two types for an operation.

Operation Types

  • :arithmetic - Numeric operations (+, -, *, /)
  • :comparison - Comparison operations (=, <>, <, >, etc.)
  • :concatenation - String concatenation (||)
  • :union - Set operations (UNION, INTERSECT, EXCEPT)

compatible?(type, type)

@spec compatible?(sql_type(), sql_type()) :: boolean()

Check if two types are compatible for comparisons or assignments.

datetime_type?(type)

@spec datetime_type?(sql_type()) :: boolean()

Check if a type is a date/time type.

infer_type(selecto, expression)

@spec infer_type(Selecto.t(), term()) :: {:ok, sql_type()} | {:error, term()}

Infer the SQL type of an expression.

Returns {:ok, type} for successfully inferred types, or {:ok, :unknown} when the type cannot be determined.

Examples

iex> infer_type(selecto, "product_name")
{:ok, :string}

iex> infer_type(selecto, {:count, "*"})
{:ok, :bigint}

iex> infer_type(selecto, {:sum, "price"})
{:ok, :decimal}

infer_type!(selecto, expression)

@spec infer_type!(Selecto.t(), term()) :: sql_type()

Infer type and return just the type (for internal use where errors are handled upstream).

normalize_type(type)

@spec normalize_type(atom()) :: sql_type()

Normalize Ecto types to Selecto's internal type representation.

numeric_type?(type)

@spec numeric_type?(sql_type()) :: boolean()

Check if a type is numeric.

parse_sql_type(type_str)

@spec parse_sql_type(String.t()) :: sql_type()

Parse a SQL type string into an atom type.

string_type?(type)

@spec string_type?(sql_type()) :: boolean()

Check if a type is a string type.

type_category(type)

@spec type_category(sql_type()) :: type_category()

Get the type category for a given SQL type.