glimr/db/schema

Schema DSL

A fluent builder for defining database table schemas in Gleam. Schemas serve as the source of truth for code generation, migration generation, and type inference.

Types

Represents a column definition within a table. Each column has a name, type, nullability flag, and optional default value.

pub type Column {
  Column(
    name: String,
    column_type: ColumnType,
    nullable: Bool,
    default: option.Option(Default),
    renamed_from: option.Option(String),
  )
}

Constructors

Wrapper for column definitions that allows single columns or multiple columns (like timestamps) to be used in the same list.

pub type ColumnDef {
  Single(Column)
  Multiple(List(Column))
}

Constructors

Defines the available column types that map to both PostgreSQL and SQLite data types. The codegen tool uses these to generate appropriate Gleam types and SQL DDL statements.

pub type ColumnType {
  Id
  String(max: option.Option(Int))
  Text
  Int
  SmallInt
  BigInt
  Float
  Boolean
  Timestamp
  UnixTimestamp
  Date
  Json
  Uuid
  Foreign(
    table: String,
    on_delete: option.Option(ForeignAction),
    on_update: option.Option(ForeignAction),
  )
  Array(ColumnType)
  Enum(name: String, variants: List(String))
  Decimal(precision: Int, scale: Int)
  Blob
  Time
}

Constructors

  • Id

    Auto-incrementing integer primary key

  • String(max: option.Option(Int))

    Variable-length string with optional max length (VARCHAR)

  • Text

    Unlimited text (TEXT)

  • Int

    Standard integer (INT/INTEGER)

  • SmallInt

    Small integer (SMALLINT)

  • BigInt

    Large integer (BIGINT)

  • Float

    Floating point number (REAL/DOUBLE PRECISION)

  • Boolean

    Boolean value (BOOLEAN/INTEGER for SQLite)

  • Timestamp

    Timestamp with timezone (TIMESTAMP/TEXT for SQLite)

  • UnixTimestamp

    Unix timestamp as integer seconds (INTEGER)

  • Date

    Date without time (DATE/TEXT for SQLite)

  • Json

    JSON data (JSONB for Postgres, TEXT for SQLite)

  • Uuid

    UUID (UUID for Postgres, TEXT for SQLite)

  • Foreign(
      table: String,
      on_delete: option.Option(ForeignAction),
      on_update: option.Option(ForeignAction),
    )

    Foreign key reference to another table with optional actions

  • Array(ColumnType)

    Array of another column type (PostgreSQL native arrays, JSON in SQLite)

  • Enum(name: String, variants: List(String))

    Enum with named variants (CREATE TYPE in Postgres, CHECK in SQLite). Generates a Gleam custom type with to_string/from_string.

  • Decimal(precision: Int, scale: Int)

    Precise numeric value (NUMERIC in Postgres, TEXT in SQLite)

  • Blob

    Binary data (BYTEA in Postgres, BLOB in SQLite)

  • Time

    Time without date (TIME in Postgres, TEXT in SQLite)

Defines default values that can be assigned to columns. Used in migration generation to produce appropriate SQL DEFAULT clauses.

pub type Default {
  DefaultString(String)
  DefaultInt(Int)
  DefaultFloat(Float)
  DefaultBool(Bool)
  DefaultNow
  DefaultUnixNow
  DefaultAutoUuid
  DefaultNull
  DefaultEmptyArray
}

Constructors

  • DefaultString(String)
  • DefaultInt(Int)
  • DefaultFloat(Float)
  • DefaultBool(Bool)
  • DefaultNow
  • DefaultUnixNow
  • DefaultAutoUuid
  • DefaultNull
  • DefaultEmptyArray

Defines the referential actions for foreign key constraints. Used with on_delete and on_update modifiers to control what happens when the referenced row is deleted or updated.

pub type ForeignAction {
  Cascade
  Restrict
  SetNull
  SetDefault
  NoAction
}

Constructors

  • Cascade
  • Restrict
  • SetNull
  • SetDefault
  • NoAction

Database queries that filter or sort by a column benefit hugely from an index — without one, the database scans every row. This type captures what the developer wants indexed, whether it should enforce uniqueness, and an optional custom name (otherwise the migration generates idx_{table}_{col1}_{col2} automatically).

pub type IndexDef {
  IndexDef(
    columns: List(String),
    unique: Bool,
    name: option.Option(String),
  )
}

Constructors

  • IndexDef(
      columns: List(String),
      unique: Bool,
      name: option.Option(String),
    )

Represents a database table definition with its name and column definitions. Used as the source of truth for code generation, migrations, and type inference.

pub type Table {
  Table(
    name: String,
    columns: List(Column),
    indexes: List(IndexDef),
  )
}

Constructors

  • Table(
      name: String,
      columns: List(Column),
      indexes: List(IndexDef),
    )

Values

pub fn array(def: ColumnDef) -> ColumnDef

Sometimes you need a column that holds multiple values — tags, scores, email addresses. This wraps any column type in an Array so string("tags") |> array() becomes List(String) in Gleam, TEXT[] in Postgres, and JSON text in SQLite. Chaining |> array() |> array() gives you nested arrays for matrix-style data.

pub fn auto_uuid(def: ColumnDef) -> ColumnDef

Sets the default value to an auto-generated UUID. Use with uuid columns for automatic unique identifier generation.

Maps to:

  • PostgreSQL: gen_random_uuid()
  • SQLite: Custom expression generating UUID v4 format

Example:

table("users", [
  uuid("external_id")
    |> auto_uuid(),
])
pub fn bigint(name: String) -> ColumnDef

Creates a large integer column for values exceeding standard integer range.

Maps to:

  • PostgreSQL: name BIGINT
  • SQLite: name INTEGER
pub fn blob(name: String) -> ColumnDef

Creates a binary data column.

Maps to:

  • PostgreSQL: BYTEA
  • SQLite: BLOB
pub fn boolean(name: String) -> ColumnDef

Creates a boolean column.

Maps to:

  • PostgreSQL: name BOOLEAN
  • SQLite: name INTEGER (0 = false, 1 = true)
pub fn columns(t: Table) -> List(Column)

Returns the table’s columns in definition order. Useful for iterating over columns when generating code or performing schema introspection.

pub fn date(name: String) -> ColumnDef

Creates a date column (without time component).

Maps to:

  • PostgreSQL: name DATE
  • SQLite: name TEXT (YYYY-MM-DD format)
pub fn decimal(
  name: String,
  precision: Int,
  scale: Int,
) -> ColumnDef

Creates a precise numeric column with the given precision and scale.

Maps to:

  • PostgreSQL: NUMERIC(precision, scale)
  • SQLite: TEXT
pub fn default_bool(def: ColumnDef, value: Bool) -> ColumnDef

Sets a boolean default value for the column.

Example:

table("users", [
  boolean("is_active")
    |> default_bool(True),
])
pub fn default_empty_array(def: ColumnDef) -> ColumnDef

Without a default, inserting a row without specifying the array column would violate NOT NULL. This sets the default to an empty array ('{}' in Postgres, '[]' in SQLite) so new rows get a valid empty list instead of failing.

pub fn default_float(def: ColumnDef, value: Float) -> ColumnDef

Sets a float default value for the column.

Example:

table("products", [
  float("price")
    |> default_float(0.0),
])
pub fn default_int(def: ColumnDef, value: Int) -> ColumnDef

Sets an integer default value for the column.

Example:

table("posts", [
  int("view_count")
    |> default_int(0),
])
pub fn default_now(def: ColumnDef) -> ColumnDef

Sets the default value to the current timestamp.

Example:

table("posts", [
  timestamp("published_at")
    |> default_now(),
])
pub fn default_null(def: ColumnDef) -> ColumnDef

Sets the default value to NULL. Use with nullable columns to explicitly set NULL as the default rather than having no default value specified.

pub fn default_string(def: ColumnDef, value: String) -> ColumnDef

Sets a string default value for the column.

Example:

table("users", [
  string("role")
    |> default_string("user"),
])
pub fn default_unix_now(def: ColumnDef) -> ColumnDef

Sets the default value to the current Unix timestamp (seconds since epoch). Use with unix_timestamp columns.

Example:

table("events", [
  unix_timestamp("created_at")
    |> default_unix_now(),
])
pub fn enum(name: String, variants: List(String)) -> ColumnDef

Creates an enum column that generates a Gleam custom type with to_string and from_string converters. The enum name is auto-generated from the column name (PascalCase) but can be overridden with |> enum_name("custom").

Maps to:

  • PostgreSQL: Custom CREATE TYPE with enum values
  • SQLite: TEXT with CHECK constraint

Example:

table("users", [
  schema.enum("status", ["active", "inactive", "banned"]),
])
pub fn enum_name(def: ColumnDef, name: String) -> ColumnDef

Overrides the auto-generated enum type name. By default, the enum type name is derived from the column name in PascalCase. Use this to set a custom name.

Example:

schema.enum("status", ["active", "inactive"])
  |> enum_name("user_status")
pub fn float(name: String) -> ColumnDef

Creates a floating-point number column.

Maps to:

  • PostgreSQL: name DOUBLE PRECISION
  • SQLite: name REAL
pub fn foreign(name: String, references: String) -> ColumnDef

Creates an integer column that references another table’s id. The column name should follow the convention {table}_id.

Maps to:

  • PostgreSQL: name INTEGER REFERENCES table(id)
  • SQLite: name INTEGER REFERENCES table(id)

Example:

table("posts", [
  id(),
  foreign("user_id", "users"),
  string("title"),
])
pub fn id() -> ColumnDef

Creates an auto-incrementing integer primary key column named “id”. This is typically the first column in a table.

Maps to:

  • PostgreSQL: id SERIAL PRIMARY KEY
  • SQLite: id INTEGER PRIMARY KEY AUTOINCREMENT
pub fn index(columns: List(String)) -> IndexDef

Creates a regular (non-unique) index on the given columns. Use this when you frequently query by a column but don’t need uniqueness enforced — for example, indexing a status column that your list queries filter on.

pub fn indexes(table: Table, defs: List(IndexDef)) -> Table

Pipes onto table() to declare indexes alongside columns. Keeping indexes in the schema definition means the migration generator can detect when you add or remove an index and produce the right CREATE INDEX / DROP INDEX SQL automatically — no hand-written migrations needed.

Example:

table(name, [id(), string("email")])
|> indexes([unique(["email"])])
pub fn int(name: String) -> ColumnDef

Creates a standard integer column.

Maps to:

  • PostgreSQL: name INTEGER
  • SQLite: name INTEGER
pub fn json(name: String) -> ColumnDef

Creates a JSON column for structured data.

Maps to:

  • PostgreSQL: name JSONB
  • SQLite: name TEXT
pub fn named(def: IndexDef, name: String) -> IndexDef

Overrides the auto-generated index name. The default idx_{table}_{col1}_{col2} is fine most of the time, but if you need a specific name for constraint error handling or migration compatibility with an existing database, pipe through this.

pub fn nullable(def: ColumnDef) -> ColumnDef

Marks the column as nullable (allows NULL). By default, columns are NOT NULL.

Example:

table("users", [
  id(),
  string("name"),
  string("bio")
    |> nullable(),
])
pub fn on_delete(
  def: ColumnDef,
  action: ForeignAction,
) -> ColumnDef

Sets the ON DELETE action for a foreign key column. Only applies to columns with Foreign type.

Example:

foreign("user_id", "users")
  |> on_delete(Cascade)
pub fn on_update(
  def: ColumnDef,
  action: ForeignAction,
) -> ColumnDef

Sets the ON UPDATE action for a foreign key column. Only applies to columns with Foreign type.

Example:

foreign("user_id", "users")
  |> on_update(Restrict)
pub fn rename_from(def: ColumnDef, old_name: String) -> ColumnDef

Indicates that this column was renamed from a previous name. The migration generator will use RENAME COLUMN instead of drop/add, preserving data. This modifier is automatically removed from the schema after the migration is generated.

Example:

table("users", [
  string("email_address")
    |> rename_from("email"),
])
pub fn smallint(name: String) -> ColumnDef

Creates a small integer column for compact storage of small values like status codes or counters.

Maps to:

  • PostgreSQL: name SMALLINT
  • SQLite: name INTEGER
pub fn soft_deletes() -> ColumnDef

Adds a nullable deleted_at timestamp column for soft delete support. Records are marked as deleted by setting this column instead of being removed from the database.

Maps to:

  • PostgreSQL: deleted_at TIMESTAMP WITH TIME ZONE
  • SQLite: deleted_at TEXT
pub fn string(name: String) -> ColumnDef

Creates a VARCHAR(255) column with the given name.

Maps to:

  • PostgreSQL: name VARCHAR(255)
  • SQLite: name TEXT
pub fn string_sized(name: String, max: Int) -> ColumnDef

Creates a VARCHAR column with a specific maximum length.

Maps to:

  • PostgreSQL: name VARCHAR(max)
  • SQLite: name TEXT
pub fn table(name: String, column_defs: List(ColumnDef)) -> Table

Creates a new table definition with the given name and column definitions.

Example:

import glimr/db/schema

pub const table_name = "users"

pub fn definition() {
  schema.table(table_name, [
    schema.id(),
    schema.string("name"),
    schema.string("email"),
    schema.timestamps(),
  ])
}
pub fn table_indexes(t: Table) -> List(IndexDef)

Returns the table’s index definitions. The migration generator and snapshot system use this to detect when indexes have been added, removed, or changed between schema versions.

pub fn text(name: String) -> ColumnDef

Creates an unlimited text column. Use for large text content like blog posts, descriptions, etc.

Maps to:

  • PostgreSQL: name TEXT
  • SQLite: name TEXT
pub fn time(name: String) -> ColumnDef

Creates a time column (without date component).

Maps to:

  • PostgreSQL: TIME
  • SQLite: TEXT
pub fn timestamp(name: String) -> ColumnDef

Creates a timestamp column for date/time values.

Maps to:

  • PostgreSQL: name TIMESTAMP WITH TIME ZONE
  • SQLite: name TEXT (ISO 8601 format)
pub fn timestamps() -> ColumnDef

Creates both created_at and updated_at timestamp columns. This is a convenience function for the common pattern of tracking record creation and modification times.

pub fn unique(columns: List(String)) -> IndexDef

Creates a unique index — the database will reject any INSERT or UPDATE that would create a duplicate. This is how you enforce “one account per email” or “one vote per user per post” at the database level rather than relying on application-level checks that can race.

pub fn unix_timestamp(name: String) -> ColumnDef

Creates an integer column for storing Unix timestamps (seconds since epoch).

Maps to:

  • PostgreSQL: name BIGINT
  • SQLite: name INTEGER
pub fn unix_timestamps() -> ColumnDef

Creates both created_at and updated_at as unix timestamp columns (integer seconds since epoch). This is a convenience function for the common pattern of tracking record creation and modification times using integer timestamps.

pub fn uuid(name: String) -> ColumnDef

Creates a UUID column for universally unique identifiers.

Maps to:

  • PostgreSQL: name UUID
  • SQLite: name TEXT
Search Document