remodel-core

Logical Model

The relational schema produced by converting a conceptual model — tables, columns, constraints, and foreign keys.

The logical model (models::logical) represents a relational database schema: tables with typed columns, primary keys, foreign keys, unique constraints, and check constraints. You rarely construct it by hand — it is the output of ConceptualModel::to_logical() — but you can build and modify it directly if needed.

LogicalModel

let mut lm = LogicalModel::new("e_commerce");
FieldTypeDescription
nameStringDatabase or schema name
tablesIndexMap<TableId, Table>All tables, in insertion order

Building manually

let customers = lm.add_table("Customer");
let cid  = lm.add_column(customers, "id",    DataType::Integer)?;
let name = lm.add_column(customers, "email", DataType::Varchar(120))?;
lm.set_primary_key(customers, vec![cid])?;

let orders = lm.add_table("Order");
let oid    = lm.add_column(orders, "id",          DataType::Integer)?;
let cfk    = lm.add_column(orders, "customer_id", DataType::Integer)?;
lm.set_primary_key(orders, vec![oid])?;
lm.add_foreign_key(orders, ForeignKey {
    columns:           vec![cfk],
    references_table:  customers,
    references_columns: vec![cid],
    on_update: ReferentialAction::NoAction,
    on_delete: ReferentialAction::Cascade,
})?;

Querying

let t = lm.table(customers)?;
let pk_cols = t.primary_key_columns();  // &[ColumnId]
let pk      = t.primary_key();          // Option<&Constraint>

Table

FieldTypeDescription
idTableIdUnique handle
nameStringTable name
columnsIndexMap<ColumnId, Column>Columns in insertion order
constraintsIndexMap<ConstraintId, Constraint>PK, UNIQUE, FK, CHECK
commentStringOptional DDL comment

Iterating columns

for col in t.columns_iter() {
    println!("{}: {:?} (pk={}, fk={})", col.name, col.data_type, col.is_primary, col.is_foreign);
}

Column

FieldTypeDescription
idColumnIdUnique handle
nameStringColumn name
data_typeDataTypeSee Data Types
nullablebooltrueNULL; falseNOT NULL
is_primaryboolSet automatically by set_primary_key
is_foreignboolSet automatically by add_foreign_key
is_uniqueboolSet automatically by add_unique for single-column uniques
defaultOption<String>Verbatim DEFAULT clause value
commentStringOptional DDL comment

Constraint

FieldTypeDescription
idConstraintIdUnique handle
nameOption<String>Explicit constraint name; auto-generated if None
kindConstraintKindDetermines payload

ConstraintKind

pub enum ConstraintKind {
    PrimaryKey { columns: Vec<ColumnId> },
    Unique     { columns: Vec<ColumnId> },
    ForeignKey(ForeignKey),
    Check      { expression: String },
}

Constraint helpers

constraint.is_primary_key();  // true for PrimaryKey variant
constraint.is_foreign_key();  // true for ForeignKey variant

ForeignKey

FieldTypeDescription
columnsVec<ColumnId>Local FK columns (in order)
references_tableTableIdReferenced table
references_columnsVec<ColumnId>Referenced columns (matching order)
on_updateReferentialActionAction on parent UPDATE
on_deleteReferentialActionAction on parent DELETE

ReferentialAction

VariantSQL keyword
NoActionNO ACTION
RestrictRESTRICT
CascadeCASCADE
SetNullSET NULL
SetDefaultSET DEFAULT

The default for both on_update and on_delete is NoAction.

Generating SQL

Once you have a LogicalModel, call to_sql:

let ddl = lm.to_sql(SqlDialect::Postgres);

See SQL Generation for dialect differences and full output examples.

On this page