Allianaab2m/aya/ddl does not have a README file

    DdlError

    pub(all) suberror DdlError {
    DuplicateTable(table~ : String)
    UnknownColumnType(table~ : String, column~ : String, ty~ : String)
    UnsupportedDialect(dialect~ : String, reason~ : String)
    UnsafeChange(table~ : String, reason~ : String)
    BadSnapshot(reason~ : String)
    } derive(
    Debug
    )

    impl Show for DdlError

    Change

    pub(all) enum Change {
    CreateTable(TableDef)
    DropTable(String)
    AddColumn(table~ : String, column~ : ColumnDef)
    DropColumn(table~ : String, column~ : String)
    AlterColumn(table~ : String, before~ : ColumnDef, after~ : ColumnDef)
    CreateIndex(table~ : String, index~ : IndexDef)
    DropIndex(table~ : String, index~ : String)
    } derive(Eq,
    Debug
    )

    One step from the previous snapshot to the next one.

    A rename is not in this list on purpose: nothing in the source says whether a vanished column and a new one are the same column, and guessing wrong silently deletes data. A rename shows up as a drop and an add, which is at least visible in the generated SQL before it runs.

    Change::summary

    fn Change::summary(self : Change) -> String

    A one-line description of a change, for status output and for naming a migration after what it does.

    ColumnDef

    pub struct ColumnDef {
    name : String
    ty : String
    not_null : Bool
    primary_key : Bool
    autoincrement : Bool
    unique : Bool
    default_sql : String?
    references : ForeignKey?
    } derive(Eq,
    Debug
    )

    One column, with its type already resolved for the snapshot's dialect.

    The snapshot stores SQL, not MoonBit: two dialects disagree about what Int64 is called, and the diff has to compare what the database will actually hold.

    ForeignKey

    pub struct ForeignKey {
    table : String
    column : String
    on_delete : String?
    on_update : String?
    } derive(Eq,
    Debug
    )

    IndexDef

    pub struct IndexDef {
    name : String
    columns : Array[String]
    unique : Bool
    } derive(Eq,
    Debug
    )

    Snapshot

    pub struct Snapshot {
    version : String
    dialect :
    Dialect

    tables : Array[TableDef]
    } derive(Eq,
    Debug
    )

    The database schema as aya understands it, at one point in time.

    This is the artefact that gets committed next to the migration it belongs to: the next generate diffs against it rather than against the database, so generating a migration needs no connection.

    Snapshot::empty

    An empty schema: what the first migration is diffed against.

    Snapshot::from_json_string

    fn Snapshot::from_json_string(text : String) -> Snapshot raise DdlError

    Read a snapshot back from its JSON.

    Every failure is a BadSnapshot carrying where it went wrong: a snapshot is machine-written but human-edited often enough that "invalid JSON" is not a useful thing to say.

    Snapshot::table

    fn Snapshot::table(self : Snapshot, name : String) -> TableDef?

    Snapshot::to_json_string

    fn Snapshot::to_json_string(self : Snapshot) -> String

    Render a snapshot as the JSON that gets written to meta/NNNN_snapshot.json.

    TableDef

    pub struct TableDef {
    name : String
    columns : Array[ColumnDef]
    indexes : Array[IndexDef]
    } derive(Eq,
    Debug
    )

    TableDef::column

    fn TableDef::column(self : TableDef, name : String) -> ColumnDef?

    TableDef::index

    fn TableDef::index(self : TableDef, name : String) -> IndexDef?

    BREAKPOINT

    let BREAKPOINT : String

    What separates two statements inside a generated migration file.

    A marker rather than a bare ;: a default expression or a trigger body can contain a semicolon, so a runner that splits on ; eventually splits in the wrong place.

    SNAPSHOT_VERSION

    let SNAPSHOT_VERSION : String

    Version stamped into every snapshot file.

    Bumped when the JSON shape changes, so an old snapshot is rejected with a clear message instead of being half-understood by a newer generator.

    auto_name

    fn auto_name(changes : Array[Change]) -> String

    A file-name slug derived from what the migration actually does.

    drizzle-kit names migrations after a random word pair; naming them after the change means git log on the migrations directory reads as a schema changelog. Falls back to migration when there is nothing to say.

    creation_order

    fn creation_order(tables : Array[TableDef]) -> Array[TableDef]

    Order tables so that a table comes after everything it references.

    SQLite would not mind — it resolves foreign keys lazily — but a migration file is also something a person reads, and "referenced first" is the order the schema is easiest to follow in. It is also the order the stricter dialects will need when their emitter arrives.

    A reference cycle is left in name order rather than reported: two tables pointing at each other is a legal schema, and this function's job is presentation, not validation.

    dialect_name

    fn dialect_name(d :
    Dialect
    ) -> String

    The name a dialect goes by in config files and snapshots.

    dialect_of_name

    fn dialect_of_name(name : String) ->
    Dialect
    raise DdlError

    Parse a dialect name, rejecting anything aya does not model.

    diff

    fn diff(before : Snapshot, after : Snapshot) -> Array[Change]

    Compare two snapshots, in the order the statements should run.

    Tables are created before columns move, so a new foreign key can point at a table this same migration introduces.

    ident

    fn ident(name : String) -> String

    Quote an identifier, doubling any embedded quote.

    Both dialects aya targets accept the SQL standard's double quotes, which is also what sql/emit.mbt writes for column references.

    infer_sql_type

    fn infer_sql_type(ty : String, dialect :
    Dialect
    ) -> String?

    Map a MoonBit type to its column type, for the types aya can store.

    The table is deliberately no wider than SqlValue: a type that is not one of these has to state its storage with #aya.column(type="..."), because guessing what a wrapper type wraps is how a domain UserId ends up in a TEXT column.

    migration_sql

    fn migration_sql(statements : Array[String]) -> String

    Render statements as the body of a .sql migration file.

    snapshot_of

    Turn the entities found in the schema sources into a snapshot.

    Every dialect-specific decision — what Int64 is called, whether Bool is a type at all — is made here, once, so that everything downstream compares SQL against SQL.

    split_migration

    fn split_migration(text : String) -> Array[String]

    Split a migration file back into the statements that made it.

    The mirror of migration_sql, so a runner does not have to reimplement the split, and so the round trip can be tested.

    statements

    fn statements(before : Snapshot, after : Snapshot) -> Array[String] raise DdlError

    Render the statements that take before to after.

    Dispatching on the target snapshot's dialect, not on an argument: a snapshot records which dialect it was written for, so a migration cannot be generated against a snapshot of another database by accident.