lode/gen/schema
gen.schema — scaffold a schema (and migration) from a Phoenix-style
field:type command line, the macro-less equivalent of mix phx.gen.schema.
Product products name:string price:decimal in_stock:boolean
author_id:references:users email:string:unique
Two output modes (both produce the same runtime Schema(row) — they differ
only in source-of-truth and maintenance):
- spec mode (default, §14-pure):
spec_snippetrenders aspec.table(...)entry to paste into yourdb_spec.gleam; you thenregenerate. One source of truth, no drift. - standalone mode (
--standalone, the §14.6 manual opt-out):standalone_modulewrites a finished, hand-owned schema module (viacodegen), Phoenix-style.
migration_source emits the create_table migration for either mode. A
table must be registered ONE way — a CLI wrapper enforces the no-overlap
guard (don’t spec-feed a table that already has a standalone module, and
vice versa).
Types
One parsed field:type[:modifier] argument.
pub type Field {
Column(name: String, type_: spec.ColumnType, unique: Bool)
Reference(assoc: String, fk_column: String, table: String)
}
Constructors
-
Column(name: String, type_: spec.ColumnType, unique: Bool)A scalar column (
name:string,price:decimal:unique). -
Reference(assoc: String, fk_column: String, table: String)A
belongs_toreference (author_id:references:users): the foreign-key column, the related table, and the association name (the fk minus_id).
Values
pub fn context_source(
p: Parsed,
schema_module schema_module: String,
) -> String
Render a context module — a thin set of CRUD wrappers over the schema
(Ecto/Phoenix’s context): list_<plural>, get_<singular>,
create_/update_<singular> (taking a changeset), delete_<singular>, and
change_<singular> (the cast builder with this schema’s fields). The
schema is imported from schema_module (the module holding its Record +
schema() — e.g. "user" for a standalone User).
Param names avoid the snake-record module name and the repo/changeset
modules (which a same-named binding would shadow): r, cs, record.
pub fn exists(path path: String) -> Bool
Whether a file already exists — for the no-clobber guard (don’t overwrite a hand-owned standalone module).
pub fn migration_file(p: Parsed) -> String
The migration module’s file name, create_<table>.gleam. Unlike Ecto, the
name carries no timestamp prefix: a Gleam module name can’t start with a
digit, and ordering is by the version inside migration.new(...) (and the
migrations() list), not the file name.
pub fn migration_source(
p: Parsed,
version version: Int,
) -> String
Render the create_table migration module for this schema.
pub fn module_file(p: Parsed) -> String
The conventional standalone schema module file name, <snake-record>.gleam.
pub fn now_version() -> Int
A migration version stamped from the current UTC time, YYYYMMDDHHMMSS
(Ecto’s migration-timestamp convention). Impure — reads the clock.
pub fn parse(args: List(String)) -> Result(Parsed, String)
Parse [--standalone] <Record> <table> <field:type>....
pub fn spec_snippet(p: Parsed) -> String
Render a spec.table(...) entry (spec mode) to paste into db_spec.gleam.
pub fn standalone_module(p: Parsed) -> Result(String, String)
Render the finished, hand-owned schema module (standalone mode), via codegen.
pub fn to_table_spec(p: Parsed) -> spec.TableSpec
Build the TableSpec for standalone codegen: an auto id serial primary
key, then the parsed columns. A references: becomes a plain foreign-key
Integer column — not a belongs_to — because codegen validates that an
association’s table is in the batch, and a single-table generation has no
other tables. (Spec mode keeps the belongs_to; see spec_snippet. In
standalone mode, add the belongs_to and the related schema by hand.)