compat

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package compat defines the engine-neutral contract used by the compatibility implementation. It deliberately requires explicit targets: a claim of exact compatibility has no meaning without source and destination versions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CompileDDL

func CompileDDL(target Target, schema Schema) ([]string, error)

CompileDDL emits the target-specific physical schema from the canonical AST. Callers must audit transformed features before treating the result as an exact migration plan.

func CompileDropTable added in v0.2.0

func CompileDropTable(target Target, table string) (string, error)

CompileDropTable compiles the statement that drops one existing table.

It does NOT emit IF EXISTS: dropping a table that is not there is a mistake in the caller's model of the database, and the engine's "no such table" error is the only signal that surfaces it. Idempotence is available explicitly through CompileDropTableIfExists / Store.DropTableIfExists — two named entry points instead of an unnamed boolean at the call site, so a reader of the call always sees which semantics were chosen.

The table name is quoted with quoteIdentifier, so a name containing double quotes, a semicolon or any other punctuation stays a single identifier and can never introduce extra SQL.

func CompileDropTableIfExists added in v0.2.0

func CompileDropTableIfExists(target Target, table string) (string, error)

CompileDropTableIfExists compiles the idempotent form, `DROP TABLE IF EXISTS`, for callers that genuinely want "make sure this table is gone" (teardown, reruns of a rebuild). IF EXISTS is spelled out in the function name precisely because it hides a real error — a typo in the table name becomes a silent no-op — so choosing it must be visible at the call site.

The IF EXISTS keyword is likewise identical in both engines.

func RequireEquivalent

func RequireEquivalent(report VerificationReport) error

func RequireExact

func RequireExact(findings []Finding) error

func SnapshotDigest

func SnapshotDigest(snapshot Snapshot) (string, error)

SnapshotDigest creates a deterministic data-integrity proof for a canonical snapshot. Row order is normalized; table, column and value names are encoded by encoding/json with stable map ordering.

Types

type Assignment

type Assignment struct {
	Column string     `json:"column"`
	Value  Expression `json:"value"`
}

type CatalogObject

type CatalogObject struct {
	Kind       string `json:"kind"`
	Name       string `json:"name"`
	Definition string `json:"definition,omitempty"`
	Reason     string `json:"reason"`
}

type Change

type Change struct {
	Source        Target     `json:"source"`
	Sequence      uint64     `json:"sequence"`
	CommittedAt   time.Time  `json:"committed_at"`
	Kind          ChangeKind `json:"kind"`
	Table         string     `json:"table"`
	PrimaryKey    Row        `json:"primary_key"`
	Before        Row        `json:"before,omitempty"`
	After         Row        `json:"after,omitempty"`
	TransactionID string     `json:"transaction_id"`
}

Change is an engine-neutral mutation. Sequence is monotonically increasing per source, which lets a destination apply the same ordered history.

func OrderedChanges

func OrderedChanges(changes []Change) ([]Change, error)

OrderedChanges rejects ambiguous or out-of-order histories before applying them to the other engine.

func (Change) Validate

func (change Change) Validate() error

type ChangeKind

type ChangeKind string
const (
	Insert ChangeKind = "insert"
	Update ChangeKind = "update"
	Delete ChangeKind = "delete"
)

type Column

type Column struct {
	Name     string      `json:"name"`
	Type     Type        `json:"type"`
	Nullable bool        `json:"nullable"`
	Default  *Expression `json:"default,omitempty"`
	// DomainRef, when set, names a Schema.Domains entry this column takes its
	// CHECK/NOT NULL/DEFAULT from. It is additive and omitempty, so a column
	// without it stays byte-identical. The column MUST still carry Type equal to
	// the domain's base type: the data chain (export/import canonicalization) keys
	// off Column.Type.Family, and both engines physically store the domain value
	// as its base type, so the redundant Type keeps that path unchanged and keeps
	// PG(native domain) and SQLite(inlined) storing identical values. A
	// domain-referencing column must be otherwise neutral — Nullable true, no own
	// Default, no Generated — so the domain is the single source of the constraint
	// (validated in Schema.Validate). On PostgreSQL the column's SQL type is the
	// domain name; on SQLite it is the base type with the domain's CHECK/NOT
	// NULL/DEFAULT inlined.
	DomainRef string `json:"domain,omitempty"`
	// Generated, when set, makes this a STORED generated column whose value is
	// computed from Expression rather than supplied on INSERT/UPDATE. It is an
	// additive, omitempty field: a column without it stays byte-identical in the
	// canonical JSON and in every emitted statement. See GeneratedColumn.
	Generated *GeneratedColumn `json:"generated,omitempty"`
}

type CommonTableExpr

type CommonTableExpr struct {
	Name  string      `json:"name"`
	Query SelectQuery `json:"query"`
}

CommonTableExpr is one named, non-recursive common table expression: the CTE name and the query it binds. Referenced from a FROM clause by its name like an ordinary table, a CTE has identical materialized-result semantics in SQLite and PostgreSQL. A CTE name shadows a real table of the same name for the duration of the query in both engines (standard SQL), so no special resolution is needed.

type CompoundSelect

type CompoundSelect struct {
	Operator string      `json:"operator"`
	Query    SelectQuery `json:"query"`
}

CompoundSelect is one branch of a compound (set-operation) SELECT: the set operator that joins it to everything to its left, plus the branch query. The operator is one of "union", "union_all", "intersect", "except"; all four have identical set semantics in SQLite and PostgreSQL. A chain that mixes "intersect" with any other operator is rejected, because INTERSECT binds more tightly than UNION/EXCEPT in PostgreSQL but has equal (left-associative) precedence in SQLite, so a flat left-associative chain would group differently between the two engines.

type ConflictError

type ConflictError struct {
	Table      string
	PrimaryKey Row
	Expected   Row
	Actual     Row
}

func (*ConflictError) Error

func (err *ConflictError) Error() string

type Constraint

type Constraint struct {
	Kind       ConstraintKind `json:"kind"`
	Columns    []string       `json:"columns"`
	References *Reference     `json:"references,omitempty"`
	Expression *Expression    `json:"expression,omitempty"`
}

type ConstraintKind

type ConstraintKind string
const (
	PrimaryKey ConstraintKind = "primary_key"
	UniqueKey  ConstraintKind = "unique"
	ForeignKey ConstraintKind = "foreign_key"
	Check      ConstraintKind = "check"
)

type Contract

type Contract struct {
	Source           Target    `json:"source"`
	Destination      Target    `json:"destination"`
	RequiredFeatures []Feature `json:"required_features"`
}

Contract is the complete compatibility claim made for one migration or synchronization relationship. RequiredFeatures must be audited before data movement begins; unknown capabilities are failures, never silent fallbacks.

func (Contract) Validate

func (c Contract) Validate() error

type Domain

type Domain struct {
	Name    string      `json:"name"`
	Type    Type        `json:"type"`
	Check   *Expression `json:"check,omitempty"`
	NotNull bool        `json:"not_null,omitempty"`
	Default *Expression `json:"default,omitempty"`
}

Domain is a named SQL domain: a base Type plus an optional CHECK constraint, NOT NULL flag and DEFAULT expression. It is asymmetric across the two engines by nature:

  • PostgreSQL emits a native CREATE DOMAIN and columns reference it by name.
  • SQLite has no domains, so every column that references the domain is compiled INLINE with the domain's base type and the same CHECK/NOT NULL/DEFAULT — semantically equivalent (same base type, same constraint), the only portable rendering.

The CHECK expression refers to the value under test with the placeholder node Expression{Kind:"domain_value"}: it compiles to the SQL keyword VALUE on PostgreSQL (the domain's own value) and to the referencing column's name when inlined on SQLite. Grammar validity of the CHECK is enforced at compile time by the same compileExpression path as any other expression, so an out-of-grammar CHECK fails with an explicit error.

A domain is a schema-level constraint, not data: the stored value is identical whether the constraint is enforced by a native PG domain or by an inline SQLite CHECK, so data fidelity is preserved. Only the canonical path (schema created by this layer, kept in __compat_schema) round-trips the domain exactly; external inspection cannot rebuild a domain that never physically existed as such (see docs/COMPATIBILITY.md).

type Engine

type Engine string
const (
	SQLite   Engine = "sqlite"
	Postgres Engine = "postgres"
)

type Expression

type Expression struct {
	Kind  string       `json:"kind"`
	Value string       `json:"value,omitempty"`
	Args  []Expression `json:"args,omitempty"`
}

Expression is an AST placeholder. Raw SQL is intentionally excluded from this layer because exact compatibility requires the expression to be parsed and compiled separately for each target dialect.

type Feature

type Feature string
const (
	Tables               Feature = "tables"
	PrimaryKeys          Feature = "primary_keys"
	ForeignKeys          Feature = "foreign_keys"
	CanonicalForeignKeys Feature = "canonical_foreign_keys"
	CheckRules           Feature = "check_constraints"
	CanonicalChecks      Feature = "canonical_check_constraints"
	Transactions         Feature = "transactions"
	Indexes              Feature = "indexes"
	CanonicalIndexes     Feature = "canonical_indexes"
	JSONValues           Feature = "json"
	UUIDValues           Feature = "uuid"
	Triggers             Feature = "triggers"
	CanonicalTriggers    Feature = "canonical_triggers"
	Views                Feature = "views"
	CanonicalViews       Feature = "canonical_views"
	StoredRoutines       Feature = "stored_routines"
	CanonicalRoutines    Feature = "canonical_routines"
	FullText             Feature = "full_text"
	CanonicalFullText    Feature = "canonical_full_text"
	CanonicalVectors     Feature = "canonical_vectors"
)

func InferFeatures

func InferFeatures(schema Schema) []Feature

InferFeatures derives the minimum capabilities required by a canonical schema. Migration callers use this to prevent a schema from claiming an exact plan while omitting its difficult capabilities from the contract.

type Finding

type Finding struct {
	Feature Feature       `json:"feature"`
	Status  MappingStatus `json:"status"`
	Reason  string        `json:"reason,omitempty"`
}

func Audit

func Audit(contract Contract) ([]Finding, error)

Audit reports the current compatibility status. It never represents a transformed or emulated behavior as exact equivalence.

type GeneratedColumn

type GeneratedColumn struct {
	Expression Expression `json:"expression"`
	Stored     bool       `json:"stored"`
}

GeneratedColumn describes a STORED generated column: `col TYPE GENERATED ALWAYS AS (<expression>) STORED`. Only STORED is supported because it is computed and physically stored identically by SQLite (>= 3.31) and PostgreSQL (>= 12) with this exact syntax; the value is recomputed on the destination from the same deterministic expression, which is the equivalence proof. VIRTUAL is deliberately not supported (PostgreSQL cannot express it), so Stored must be true — a false Stored is rejected by Schema.Validate rather than silently emitting divergent DDL. Expression uses the canonical grammar (compat/sqlparse.go, parseCatalogExpression) and is compiled by the same compileExpression path as any other expression, so an out-of-grammar expression fails at compile time with an explicit error. A generated column cannot also carry a Default and cannot be part of a canonical primary key (both engines restrict this).

type Index

type Index struct {
	Name    string        `json:"name"`
	Table   string        `json:"table"`
	Unique  bool          `json:"unique,omitempty"`
	Columns []IndexColumn `json:"columns"`
	Where   *Expression   `json:"where,omitempty"`
}

type IndexColumn

type IndexColumn struct {
	Column     string      `json:"column,omitempty"`
	Descending bool        `json:"descending,omitempty"`
	Expression *Expression `json:"expression,omitempty"`
}

IndexColumn is one key of an index. Ordinarily the key is a plain column (Column). When Expression is set the key is that catalog expression (Section 3 grammar) compiled inside parentheses — an expression index, supported by SQLite (>= 3.9) and PostgreSQL with identical `(expr)` key syntax — and Column is left empty. Descending applies to either form. Expression is additive and omitted from JSON when nil, so a plain-column index stays byte-identical in canonical metadata and in every emitted statement.

type Inspection

type Inspection struct {
	Schema     Schema          `json:"schema"`
	Exact      bool            `json:"exact"`
	Source     string          `json:"source"`
	Unresolved []CatalogObject `json:"unresolved,omitempty"`
}

type Join

type Join struct {
	Kind  string      `json:"kind"`
	Table TableSource `json:"table"`
	On    Expression  `json:"on"`
}

type MappingStatus

type MappingStatus string
const (
	Exact       MappingStatus = "exact"
	Transformed MappingStatus = "transformed"
	Emulated    MappingStatus = "emulated"
	Unsupported MappingStatus = "unsupported"
	Unknown     MappingStatus = "unknown"
)

type Ordering

type Ordering struct {
	Expression Expression `json:"expression"`
	Descending bool       `json:"descending,omitempty"`
}

type Projection

type Projection struct {
	Expression Expression `json:"expression"`
	Alias      string     `json:"alias,omitempty"`
}

type Reference

type Reference struct {
	Table    string            `json:"table"`
	Columns  []string          `json:"columns"`
	OnUpdate ReferentialAction `json:"on_update,omitempty"`
	OnDelete ReferentialAction `json:"on_delete,omitempty"`
}

type ReferentialAction

type ReferentialAction string
const (
	NoAction   ReferentialAction = "no_action"
	Restrict   ReferentialAction = "restrict"
	Cascade    ReferentialAction = "cascade"
	SetNull    ReferentialAction = "set_null"
	SetDefault ReferentialAction = "set_default"
)

type Routine

type Routine struct {
	Name       string             `json:"name"`
	Parameters []RoutineParameter `json:"parameters,omitempty"`
	Actions    []RoutineAction    `json:"actions"`
}

type RoutineAction

type RoutineAction struct {
	Kind        string       `json:"kind"`
	Table       string       `json:"table"`
	Assignments []Assignment `json:"assignments,omitempty"`
	Where       *Expression  `json:"where,omitempty"`
	// The fields below belong to the read action ("select") and are all additive
	// and omitempty, so an insert/update/delete action serializes byte-identically
	// to how it did before the read action existed.
	//
	// Relation is the source of a "select": a table OR a view. It is a separate
	// field from Table (which names the written table of a write action) because a
	// read may target a view, where the joins/aggregates live — the canonical
	// division that keeps the read action free of joins.
	Relation string `json:"relation,omitempty"`
	// Columns are the DECLARED output columns of a "select". A View carries no
	// output types (it is {Name, Query}) and they cannot be inferred in general
	// (count(*), arbitrary expressions), so the action declares them: this layer
	// declares, it does not guess. The declaration is also the check — a value
	// that is not of the declared family fails loudly in canonicalValue instead of
	// reaching the caller as garbage.
	Columns []RoutineResultColumn `json:"columns,omitempty"`
	// OrderBy is the DECLARED ordering of a "select". Order columns are never
	// caller-supplied: a column name cannot be bound as a placeholder, so taking
	// it from the caller would be an injection path. It is mandatory whenever
	// Limit or Offset is present, because without a total order "page 2" can mean
	// different rows on each engine.
	OrderBy []RoutineOrdering `json:"order_by,omitempty"`
	// Limit and Offset are values, so they MAY come from the caller: each is a
	// routine expression resolving to a non-negative integer ("parameter" or
	// "integer"), bound as a placeholder after the WHERE placeholders. Offset
	// requires Limit: SQLite has no OFFSET without LIMIT, and emitting a synthetic
	// "LIMIT -1" to paper over that would be exactly the silent divergence this
	// layer refuses.
	Limit  *Expression `json:"limit,omitempty"`
	Offset *Expression `json:"offset,omitempty"`
}

type RoutineOrdering added in v0.3.0

type RoutineOrdering struct {
	Column     string `json:"column"`
	Descending bool   `json:"descending,omitempty"`
}

RoutineOrdering is one declared ORDER BY key of a "select" routine action. It is a plain column name (quoted at compile time), never an expression and never a caller-supplied value.

type RoutineParameter

type RoutineParameter struct {
	Name string `json:"name"`
	Type Type   `json:"type"`
}

type RoutineResultColumn added in v0.3.0

type RoutineResultColumn struct {
	Name string `json:"name"`
	Type Type   `json:"type"`
}

RoutineResultColumn is one declared output column of a "select" routine action: the column name as projected by the relation, plus the canonical type family used to canonicalize every scanned value (the same contract as Column.Type on a table). It mirrors RoutineParameter, which declares the inputs.

type Row

type Row map[string]Value

type Schema

type Schema struct {
	Tables  []Table `json:"tables"`
	Indexes []Index `json:"indexes,omitempty"`
	// Domains is the list of named SQL domains (a base type plus an optional
	// CHECK, NOT NULL and DEFAULT). It is additive and omitempty, so a schema
	// without domains stays byte-identical in the canonical JSON and in every
	// emitted statement. PostgreSQL has native domains (CREATE DOMAIN emitted
	// before the tables); SQLite has none, so a column that references a domain is
	// inlined with the domain's base type + CHECK (+ NOT NULL/DEFAULT). See Domain.
	Domains  []Domain  `json:"domains,omitempty"`
	Views    []View    `json:"views,omitempty"`
	Triggers []Trigger `json:"triggers,omitempty"`
	Routines []Routine `json:"routines,omitempty"`
}

Schema is the engine-neutral representation used before emitting SQLite or PostgreSQL DDL. Every engine-specific construct must be represented as an explicit capability rather than hidden in a raw SQL string.

func (Schema) Validate

func (s Schema) Validate() error

type SearchResult

type SearchResult struct {
	ID string `json:"id"`
}

type SelectQuery

type SelectQuery struct {
	// With is the list of non-recursive common table expressions (CTEs) that
	// precede this query: WITH name AS (SELECT ...), ... <query>. Each CTE query
	// is itself a SelectQuery in the same bounded grammar. WITH RECURSIVE is
	// deliberately not modeled and is rejected at parse time, because its
	// termination and row-ordering semantics are hard to guarantee byte-identical
	// between SQLite and PostgreSQL. Absent CTEs leave the query byte-identical,
	// and the field is omitted from JSON so existing view snapshots do not change.
	With     []CommonTableExpr `json:"with,omitempty"`
	Distinct bool              `json:"distinct,omitempty"`
	Columns  []Projection      `json:"columns"`
	From     TableSource       `json:"from"`
	Joins    []Join            `json:"joins,omitempty"`
	Where    *Expression       `json:"where,omitempty"`
	GroupBy  []Expression      `json:"group_by,omitempty"`
	Having   *Expression       `json:"having,omitempty"`
	// Compounds is the left-associative chain of set operations applied after
	// this (the leading) SELECT: q0 op1 q1 op2 q2 ... The trailing OrderBy,
	// Limit and Offset below apply to the whole compound, not to the last
	// branch, so each CompoundSelect.Query carries none of them. Absent
	// compounds leave the single-SELECT behavior byte-identical, and the field
	// is omitted from JSON so existing view snapshots do not change.
	Compounds []CompoundSelect `json:"compounds,omitempty"`
	OrderBy   []Ordering       `json:"order_by,omitempty"`
	Limit     *int             `json:"limit,omitempty"`
	Offset    *int             `json:"offset,omitempty"`
}

type Snapshot

type Snapshot struct {
	Schema Schema           `json:"schema"`
	Rows   map[string][]Row `json:"rows"`
}

type Store

type Store struct {
	Target Target
	DB     *sql.DB
}

Store is the database/sql boundary for a concrete engine. All values crossing this boundary are converted into the canonical Value representation.

func OpenPostgres

func OpenPostgres(version Version, dsn string) (*Store, error)

func OpenSQLite

func OpenSQLite(version Version, dsn string) (*Store, error)

func OpenStore

func OpenStore(target Target, dsn string) (*Store, error)

func (*Store) ApplyChanges

func (store *Store) ApplyChanges(ctx context.Context, schema Schema, changes []Change) error

ApplyChanges applies one ordered source stream atomically. Reapplying the same stream is safe: committed source sequences are recorded in the target transaction and skipped on subsequent attempts.

func (*Store) ApplyChangesTolerant

func (store *Store) ApplyChangesTolerant(ctx context.Context, schema Schema, changes []Change) error

ApplyChangesTolerant applies one ordered source stream atomically with an opt-in, catch-up conflict policy. It exists for zero-window migrations whose capture-install → snapshot → catch-up sequence inherently overlaps: a change journaled after capture was installed may already have traveled inside the snapshot, so re-applying it would trip a spurious ConflictError even though the destination already reflects the change's final state.

The only difference from ApplyChanges is conflict resolution. A change is treated as already applied — and recorded in __compat_applied_changes as if it had just been applied — when the destination's CURRENT state already equals the change's FINAL state:

  • insert: the row already exists and rowsEqual(after, actual);
  • update: the row exists and rowsEqual(after, actual) even though Before no longer matches (the snapshot already carried the after state);
  • delete: the row no longer exists.

Any other divergence remains a strict ConflictError: the tolerant mode is a catch-up convenience, not a bypass. ApplyChanges is unchanged.

func (*Store) ApplySchema

func (store *Store) ApplySchema(ctx context.Context, schema Schema) error

func (*Store) CallRoutine

func (store *Store) CallRoutine(ctx context.Context, schema Schema, name string, arguments map[string]Value) error

CallRoutine executes a canonical routine inside one transaction. The routine is stored in the canonical schema and therefore has the same implementation on SQLite and PostgreSQL instead of relying on engine-specific languages.

func (*Store) Close

func (store *Store) Close() error

func (*Store) DropTable added in v0.2.0

func (store *Store) DropTable(ctx context.Context, table string) error

DropTable compiles (CompileDropTable) and executes the drop against this store's database. Engine errors — a missing table, or a foreign key from another table pointing at this one — are wrapped with the operation name and propagated; nothing is retried with CASCADE.

Note on the change-capture triggers installed by InstallChangeCapture: both engines drop the triggers attached to the table together with the table itself. On PostgreSQL the trigger FUNCTIONS (`__compat_capture_<table>_<kind>_fn`) are separate catalog objects and survive the drop, orphaned but harmless; re-running InstallChangeCapture recreates them with CREATE OR REPLACE. The rows already written to `__compat_change_journal` for the dropped table are also kept on both engines — the journal is an append-only history and this package never deletes data implicitly.

func (*Store) DropTableIfExists added in v0.2.0

func (store *Store) DropTableIfExists(ctx context.Context, table string) error

DropTableIfExists is DropTable with the idempotent statement; see CompileDropTableIfExists for why the choice is explicit in the name.

func (*Store) ExportSnapshot

func (store *Store) ExportSnapshot(ctx context.Context, schema Schema) (Snapshot, error)

func (*Store) ImportSnapshot

func (store *Store) ImportSnapshot(ctx context.Context, snapshot Snapshot) error

ImportSnapshot creates the canonical schema and inserts every canonical row. It is intentionally append-only; replacement and synchronization policies are handled by higher layers so data is never deleted implicitly.

func (*Store) InspectSchema

func (store *Store) InspectSchema(ctx context.Context) (Inspection, error)

InspectSchema reconstructs the exact canonical schema when the database was managed by this compatibility layer. For external databases it falls back to catalog inspection and explicitly reports objects not yet translated.

func (*Store) InstallChangeCapture

func (store *Store) InstallChangeCapture(ctx context.Context, schema Schema) error

InstallChangeCapture installs engine-native triggers which journal every committed row mutation in canonical, ordered form.

func (*Store) QueryRoutine added in v0.3.0

func (store *Store) QueryRoutine(ctx context.Context, schema Schema, name string, arguments map[string]Value) ([]Row, error)

QueryRoutine executes a canonical READ routine and returns canonical rows. It is the read counterpart of CallRoutine, which stays write-only and unchanged: CallRoutine returns only error and has production consumers, so reading is new, additive surface rather than a signature change.

The routine must contain exactly one action, of kind "select" (enforced by Schema.Validate too). The statement is composed from pieces that already exist: compileRoutineWhere for the filter — which emits the right placeholder per engine and binds every caller value instead of inlining it, and already maps LIKE to ILIKE on PostgreSQL — and the exportTable pattern for reading, which canonicalizes every scanned value by type family. Here the family comes from the action's DECLARED output columns, because a view has no output types.

Every identifier (relation, output columns, order keys) goes through quoteIdentifier; every caller value, including LIMIT and OFFSET, is bound as a placeholder. Nothing supplied by the caller is ever concatenated into the SQL.

func (*Store) ReadCapturedChanges

func (store *Store) ReadCapturedChanges(ctx context.Context, schema Schema, after uint64, limit int) ([]Change, error)

ReadCapturedChanges reads an ordered source stream after the supplied cursor.

func (*Store) SearchText

func (store *Store) SearchText(ctx context.Context, table, idColumn string, textColumns []string, query string) ([]SearchResult, error)

SearchText implements deterministic Unicode token matching in the common Go runtime. It does not delegate tokenization or ranking to either database.

type Table

type Table struct {
	Name        string       `json:"name"`
	Columns     []Column     `json:"columns"`
	Constraints []Constraint `json:"constraints,omitempty"`
}

type TableSource

type TableSource struct {
	Table    string       `json:"table,omitempty"`
	Alias    string       `json:"alias,omitempty"`
	Subquery *SelectQuery `json:"subquery,omitempty"`
}

TableSource is a FROM/JOIN source: either a named table (Table) or a derived table (Subquery). Exactly one of Table or Subquery is set. A derived table is a full SelectQuery evaluated as a table; both engines give it identical results (it cannot be correlated with the enclosing query in standard SQL). A derived table requires an Alias. Subquery is omitted from JSON when absent, so existing table-source snapshots do not change.

type Target

type Target struct {
	Engine  Engine  `json:"engine"`
	Version Version `json:"version"`
}

func (Target) Validate

func (t Target) Validate() error

type Trigger

type Trigger struct {
	Name    string          `json:"name"`
	Table   string          `json:"table"`
	Timing  string          `json:"timing"`
	Event   string          `json:"event"`
	When    *Expression     `json:"when,omitempty"`
	Actions []TriggerAction `json:"actions"`
}

type TriggerAction

type TriggerAction struct {
	Kind        string       `json:"kind"`
	Table       string       `json:"table"`
	Assignments []Assignment `json:"assignments,omitempty"`
	Where       *Expression  `json:"where,omitempty"`
}

type Type

type Type struct {
	Family TypeFamily `json:"family"`
	// Arguments preserve details such as precision, scale, length or array
	// dimensions without coupling the canonical schema to SQL text.
	Arguments []int `json:"arguments,omitempty"`
}

type TypeFamily

type TypeFamily string
const (
	BooleanType   TypeFamily = "boolean"
	IntegerType   TypeFamily = "integer"
	DecimalType   TypeFamily = "decimal"
	FloatType     TypeFamily = "float"
	TextType      TypeFamily = "text"
	BinaryType    TypeFamily = "binary"
	DateType      TypeFamily = "date"
	TimestampType TypeFamily = "timestamp"
	JSONType      TypeFamily = "json"
	UUIDType      TypeFamily = "uuid"
	VectorType    TypeFamily = "vector"
)

type Value

type Value struct {
	Kind  ValueKind `json:"kind"`
	Value string    `json:"value,omitempty"`
}

Value keeps data independent from either driver's Go representation. Values are encoded canonically before persistence in a migration artifact or change journal, preserving null and type information across both engines.

type ValueKind

type ValueKind string
const (
	NullValue      ValueKind = "null"
	BooleanValue   ValueKind = "boolean"
	IntegerValue   ValueKind = "integer"
	DecimalValue   ValueKind = "decimal"
	FloatValue     ValueKind = "float"
	TextValue      ValueKind = "text"
	BinaryValue    ValueKind = "binary"
	DateValue      ValueKind = "date"
	TimestampValue ValueKind = "timestamp"
	JSONValue      ValueKind = "json"
	UUIDValue      ValueKind = "uuid"
	VectorValue    ValueKind = "vector"
)

type VerificationReport

type VerificationReport struct {
	SourceDigest      string `json:"source_digest"`
	DestinationDigest string `json:"destination_digest"`
	Equivalent        bool   `json:"equivalent"`
}

func VerifySnapshots

func VerifySnapshots(source, destination Snapshot) (VerificationReport, error)

type Version

type Version struct {
	Major int `json:"major"`
	Minor int `json:"minor"`
	Patch int `json:"patch"`
}

func (Version) String

func (v Version) String() string

func (Version) Valid

func (v Version) Valid() bool

type View

type View struct {
	Name  string      `json:"name"`
	Query SelectQuery `json:"query"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL