Documentation
¶
Index ¶
- Constants
- func AnyBlocking(impacts []ContractImpact) bool
- func ChangedTables(ctx context.Context, devConnStr, schemaPath, migrationsPath, engine string) ([]string, error)
- func CheckPendingMigration(ctx context.Context, devConnStr, schemaPath, migrationsPath, engine string) (bool, error)
- func DefaultPostgresCredentials() (user, password, database string)
- func ExportSchema(s *Schema, format ExportFormat, resourceName string) (string, error)
- func FindContractsFile(dir string) (string, bool)
- func FormatConnectionString(host, port, user, password, database string) string
- func GenerateMigration(ctx context.Context, ...) (string, error)
- func HasSqlDatabaseResources(bp *schema.Blueprint) bool
- func InspectCurrentSchema(ctx context.Context, a *Applier) (string, error)
- func RehashMigrationDir(migrationsPath string) error
- func RenderContractImpacts(w io.Writer, impacts []ContractImpact)
- func RenderMigrationHistory(w io.Writer, records []MigrationRecord)
- func ResourceType() string
- func ScaffoldMigration(migrationsPath, description string) (string, error)
- func ValidateContracts(cf *ContractsFile, schemas map[string]*Schema) []string
- func ValidateMigrationDir(migrationsPath string) error
- func ValidateMigrationFileNames(migrationsPath string) error
- func ValidateSchema(schemaPath, engine string) error
- type AppUser
- type Applier
- func (a *Applier) Apply(ctx context.Context, schemaPath, migrationsPath, engine string) error
- func (a *Applier) ApplyDeclarative(ctx context.Context, schemaPath, engine string) error
- func (a *Applier) ApplyMigrationDir(ctx context.Context, migrationsPath string, maxRisk RiskLevel) error
- func (a *Applier) Close() error
- func (a *Applier) DropDatabase(ctx context.Context, dbName string) error
- func (a *Applier) EnsureDatabase(ctx context.Context, dbName string) error
- func (a *Applier) ExecSQL(ctx context.Context, sqlContent string) error
- func (a *Applier) ForDatabase(dbName string) (*Applier, error)
- func (a *Applier) HasUncommittedSchemaChanges(ctx context.Context, schemaPath, migrationsPath, engine, scratchDBName string) (bool, error)
- func (a *Applier) PendingMigrations(ctx context.Context, migrationsPath string) ([]PendingMigration, error)
- func (a *Applier) ProvisionAppUser(ctx context.Context, user AppUser) (*ProvisionReport, error)
- type CodegenLanguage
- type Column
- type Constraint
- type Contract
- type ContractImpact
- type ContractPolicy
- type ContractsFile
- type DatabaseResource
- type Dependency
- type DriftReport
- type ExportFormat
- type ForeignKey
- type GeneratedFile
- type Index
- type MigrationRecord
- type PendingMigration
- type ProvisionReport
- type RiskLevel
- type Schema
- type Table
Constants ¶
const ContractsFileName = "schema-contracts.yaml"
ContractsFileName is the name of the file data teams maintain alongside the blueprint to declare their schema dependencies.
Variables ¶
This section is empty.
Functions ¶
func AnyBlocking ¶
func AnyBlocking(impacts []ContractImpact) bool
AnyBlocking reports whether any impact has a blocking policy.
func ChangedTables ¶
func ChangedTables(ctx context.Context, devConnStr, schemaPath, migrationsPath, engine string) ([]string, error)
ChangedTables returns the tables the pending schema change would touch, those added, dropped or modified by the migration `schema diff` would generate. It computes the diff against the dev database (replaying the existing migration directory) but writes nothing. Used to evaluate schema contracts.
func CheckPendingMigration ¶
func CheckPendingMigration(ctx context.Context, devConnStr, schemaPath, migrationsPath, engine string) (bool, error)
CheckPendingMigration reports whether the schema YAML has changes that are not yet captured by a committed migration, which is to say whether `celerity schema diff` would generate a new migration. It computes the diff against the dev database (replaying the existing migration directory) but writes nothing. Used by `schema diff --check` as a CI completeness gate.
func DefaultPostgresCredentials ¶
func DefaultPostgresCredentials() (user, password, database string)
DefaultPostgresCredentials returns the default local dev credentials for PostgreSQL containers.
func ExportSchema ¶
func ExportSchema(s *Schema, format ExportFormat, resourceName string) (string, error)
ExportSchema renders a parsed schema in the given format for data-team consumption. resourceName is used in headers/titles. The export is derived purely from the schema YAML, so it needs no database connection.
func FindContractsFile ¶
FindContractsFile returns the path to a schema-contracts.yaml in dir, and whether it exists.
func FormatConnectionString ¶
FormatConnectionString builds a PostgreSQL connection string from components.
func GenerateMigration ¶
func GenerateMigration(ctx context.Context, devConnStr, schemaPath, migrationsPath, engine, name string) (string, error)
GenerateMigration computes the difference between the schema YAML (desired state) and the current state, which it obtains by replaying the existing migration directory on the dev database at devConnStr. The difference is written as a new timestamped migration file and atlas.sum is updated. It returns the path of the created file, or "" if there is no difference.
The dev database must be empty; the planner replays the migration directory into it to compute the current state.
func HasSqlDatabaseResources ¶
HasSqlDatabaseResources returns true if the blueprint contains any celerity/sqlDatabase resources.
func InspectCurrentSchema ¶
InspectCurrentSchema reads the live database's public schema and renders it as a readable summary of the current deployed state.
func RehashMigrationDir ¶
RehashMigrationDir recomputes atlas.sum from the files currently in the migration directory. It is the deliberate "I edited a migration on purpose" step. Everything else in the CLI treats a checksum mismatch as a hard error, because on an already-applied migration it means the history no longer matches what ran.
func RenderContractImpacts ¶
func RenderContractImpacts(w io.Writer, impacts []ContractImpact)
RenderContractImpacts writes a "Contracts affected" section for the given impacts. Blocking impacts are marked ⛔, notify impacts ⚠. It writes nothing when there are no impacts.
func RenderMigrationHistory ¶
func RenderMigrationHistory(w io.Writer, records []MigrationRecord)
RenderMigrationHistory writes a human-readable migration history table.
func ResourceType ¶
func ResourceType() string
ResourceType returns the blueprint resource type for SQL databases, for use by the compose generator.
func ScaffoldMigration ¶
ScaffoldMigration creates an empty, timestamped migration file for hand-written SQL and updates the atlas.sum integrity file. It returns the path of the created file.
func ValidateContracts ¶
func ValidateContracts(cf *ContractsFile, schemas map[string]*Schema) []string
ValidateContracts checks a contracts file against the blueprint's SQL database resources and their schemas: every SQL dependency must name a known database and only tables that exist in it, and every dependency must declare a valid policy. It returns a list of human-readable problems (empty when valid). Datastore (NoSQL) dependencies are only checked for a valid policy, since NoSQL schema management is not yet implemented.
func ValidateMigrationDir ¶
ValidateMigrationDir checks that the atlas.sum integrity file is present and matches the migration directory contents. Returns nil when the directory holds no migrations yet.
func ValidateMigrationFileNames ¶
ValidateMigrationFileNames checks that every .sql file in the directory follows the <timestamp>_<description>.sql convention and that no two files share a version.
Atlas derives a migration's identity from the leading segment of its file name. Files that do not follow the convention, such as a Flyway-style "V001__name.up.sql" pair, collide on version, and the collision surfaces deep inside the executor as a panic rather than an error, so this runs before anything is executed.
func ValidateSchema ¶
ValidateSchema parses a schema YAML file and checks that it maps cleanly to the target engine: the file must parse, foreign keys must reference existing tables and columns, and column types must be understood. It does not require a database connection.
Types ¶
type AppUser ¶
type AppUser struct {
// Name is the role to create. It is validated as an identifier, since
// provisioning takes no free-form SQL.
Name string
// Password backs password authentication. Ignored in IAM mode.
Password string
// IAMAuth grants the engine's IAM authentication role instead of setting a
// password, so the handler exchanges its execution role for a short-lived
// token.
IAMAuth bool
// Database is the database the role is granted CONNECT on. Defaults to the
// connected database when empty.
Database string
}
AppUser describes the database role the application connects as.
This is deliberately not the master user. The master can drop any table and read every database on the instance, and the RDS Proxy already holds it to authenticate on the application's behalf; handing it to every handler would undo the per-handler role work. Migrations keep running as the master, the application runs as this role, and provisioning is what connects the two.
type Applier ¶
type Applier struct {
// contains filtered or unexported fields
}
Applier connects to a SQL database and applies schemas and migrations to it, backed by the embedded Atlas engine. Migration history is tracked in the atlas_schema_revisions table (see pgRevisions). Engine-specific connection concerns are delegated to a dialect implementation.
func NewApplier ¶
NewApplier creates an Applier for the given engine and connection string.
func (*Applier) Apply ¶
Apply brings the connected database up to date for local development.
Once a migration directory exists it is the only source of schema changes, so a local database comes up from exactly the migration history every other environment runs. Uncommitted schema YAML edits are reported separately (see HasUncommittedSchemaChanges) rather than being silently applied on top. Reconciling the YAML declaratively over a migrated database would drop anything the YAML cannot model, including hand-written indexes, triggers and the migration-history table itself.
The schema YAML is applied declaratively only before the first migration exists, so a new project gets a working local database without having to run `celerity schema diff` first.
The risk gate is fully open here (local dev applies everything); the gate is for deployed/live databases (see `schema apply`).
func (*Applier) ApplyDeclarative ¶
ApplyDeclarative brings the connected database into line with the desired state described by a schema YAML file, applying the diff directly without writing migration files. This is the local-development path: it keeps the schema YAML as the source of truth for ephemeral databases. Committed migrations (via `celerity schema diff`) are applied by ApplyMigrationDir.
func (*Applier) ApplyMigrationDir ¶
func (a *Applier) ApplyMigrationDir(ctx context.Context, migrationsPath string, maxRisk RiskLevel) error
ApplyMigrationDir applies pending migration files from an Atlas migration directory in timestamp order, tracking each in the atlas_schema_revisions table so already-applied migrations are skipped. Returns nil if the directory is empty or absent.
maxRisk is the highest risk level (see the migration risk header) that may be auto-applied. Pending migrations are applied in order until one exceeds maxRisk, at which point the apply stops with an error naming that migration, so a live system is never broken by an auto-applied contract change. Migrations already applied before the blocked one remain committed.
func (*Applier) DropDatabase ¶
DropDatabase removes a database if it exists. Must be called on an Applier connected to the admin database, with nothing else connected to the target.
func (*Applier) EnsureDatabase ¶
EnsureDatabase creates a database if it does not already exist. Must be called on an Applier connected to the admin database.
func (*Applier) ForDatabase ¶
ForDatabase returns a new Applier connected to a specific database, derived from the original connection string by replacing the database path.
func (*Applier) HasUncommittedSchemaChanges ¶
func (a *Applier) HasUncommittedSchemaChanges( ctx context.Context, schemaPath, migrationsPath, engine, scratchDBName string, ) (bool, error)
HasUncommittedSchemaChanges reports whether the schema YAML describes changes that no committed migration covers. It answers the same question as `schema diff --check`, but against a scratch database on the connection this Applier already holds rather than a throwaway container.
Must be called on an Applier connected to the admin database. The scratch database is created empty, replayed into, and dropped again.
func (*Applier) PendingMigrations ¶
func (a *Applier) PendingMigrations(ctx context.Context, migrationsPath string) ([]PendingMigration, error)
PendingMigrations returns the migrations that are committed but not yet applied to the connected database, in apply order, each with its effective risk.
func (*Applier) ProvisionAppUser ¶
ProvisionAppUser creates or repairs the application database role. It is idempotent, so it can run after every deploy, and after a database is restored or replaced, without a caller having to determine whether it is needed.
It must be called on an Applier connected as the owner/master, the role that runs migrations, since it grants privileges over that role's objects. The default privileges it sets are attached to that same role, so tables created by later migrations are usable by the application without provisioning running again.
type CodegenLanguage ¶
type CodegenLanguage string
CodegenLanguage is a target language for `schema codegen`.
const ( LangTypeScript CodegenLanguage = "typescript" LangPython CodegenLanguage = "python" )
type Column ¶
type Column struct {
Type string `yaml:"type"`
PrimaryKey bool `yaml:"primaryKey"`
Nullable bool `yaml:"nullable"`
Unique bool `yaml:"unique"`
Default string `yaml:"default"`
Description string `yaml:"description"`
Classification string `yaml:"classification"`
// Tags are free-form categorisation labels for the column, surfaced in
// exports. They have no effect on DDL.
Tags []string `yaml:"tags"`
References *ForeignKey `yaml:"references"`
}
Column describes a single table column with engine-native type.
type Constraint ¶
type Constraint struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Expression string `yaml:"expression"`
Columns []string `yaml:"columns"`
}
Constraint describes a table constraint (check, unique, composite foreign key).
type Contract ¶
type Contract struct {
Name string `yaml:"name"`
Owner string `yaml:"owner"`
Dependencies []Dependency `yaml:"dependencies"`
}
Contract declares a downstream consumer and the schema objects it depends on.
type ContractImpact ¶
type ContractImpact struct {
Contract string
Owner string
Policy ContractPolicy
Database string
Tables []string
}
ContractImpact records that a change to a database's tables touched a contract.
func EvaluateContracts ¶
func EvaluateContracts(cf *ContractsFile, changed map[string][]string) []ContractImpact
EvaluateContracts returns the contracts affected by a set of changed tables, keyed by database resource name. A contract is affected when any table it watches on a database appears in that database's changed set.
type ContractPolicy ¶
type ContractPolicy string
ContractPolicy is how a contract reacts when a watched table changes.
const ( // PolicyBlocking fails CI (non-zero exit) when a watched table changes. PolicyBlocking ContractPolicy = "blocking" // PolicyNotify warns but does not affect the exit code. PolicyNotify ContractPolicy = "notify" )
type ContractsFile ¶
type ContractsFile struct {
Contracts []Contract `yaml:"contracts"`
}
ContractsFile is a parsed schema-contracts.yaml.
func LoadContractsFile ¶
func LoadContractsFile(path string) (*ContractsFile, error)
LoadContractsFile reads and parses a schema-contracts.yaml.
type DatabaseResource ¶
type DatabaseResource struct {
ResourceName string
Name string
Engine string
SchemaPath string
MigrationsPath string
AuthMode string
}
DatabaseResource holds the resolved configuration for a celerity/sqlDatabase blueprint resource. Paths are resolved to absolute paths.
func CollectDatabaseResources ¶
func CollectDatabaseResources(bp *schema.Blueprint, projectRoot string) []DatabaseResource
CollectDatabaseResources extracts celerity/sqlDatabase resources from a blueprint and resolves schema/migration paths relative to the project root.
type Dependency ¶
type Dependency struct {
Database string `yaml:"database"`
Tables []string `yaml:"tables"`
// Datastore/Entities cover NoSQL datastores; SQL schema management ignores
// them, but they are parsed so a combined contracts file stays valid.
Datastore string `yaml:"datastore"`
Entities []string `yaml:"entities"`
Policy ContractPolicy `yaml:"policy"`
}
Dependency is a single database (or datastore) dependency within a contract.
type DriftReport ¶
type DriftReport struct {
Resource string
Target string
History []string
Structural []string
Advanced []string
// StructuralTables lists the tables that drifted structurally, for schema
// contract evaluation. Contracts, when populated by the caller, are rendered
// in the report.
StructuralTables []string
Contracts []ContractImpact
}
DriftReport describes how a live database has diverged from the state its committed migrations should have produced. It is reported at three layers, matching the schema-management spec:
- History: the revision table vs the migration directory (migrations applied out-of-band, missing from the directory, or applied out of order).
- Structural: the live tables/columns/indexes/keys/constraints vs the expected state (everything the schema YAML models).
- Advanced: triggers/functions/views/RLS policies fingerprinted from the catalog (objects created by hand-written migrations), reported coarsely as changed / missing / unexpected.
Each layer is a list of human-readable lines; empty means no drift at that layer.
func DetectDrift ¶
func DetectDrift(ctx context.Context, live *Applier, devConnStr, migrationsPath, engine string) (*DriftReport, error)
DetectDrift compares the live database behind `live` against the state its committed migrations should have produced.
History drift is always computed (it needs only the revision table and the migration directory). Structural and advanced-object drift require a clean dev database at devConnStr: the migrations recorded as applied are replayed into it to reconstruct the expected state, which is then diffed against the live database. Pass devConnStr == "" to run history drift only.
func (*DriftReport) HasDrift ¶
func (r *DriftReport) HasDrift() bool
HasDrift reports whether any layer found drift.
func (*DriftReport) Render ¶
func (r *DriftReport) Render(w io.Writer)
Render writes a human-readable report to w.
type ExportFormat ¶
type ExportFormat string
ExportFormat is an output format for `schema export`.
const ( ExportSQL ExportFormat = "sql" ExportMarkdown ExportFormat = "markdown" ExportJSONSchema ExportFormat = "json-schema" ExportMermaid ExportFormat = "mermaid" )
type ForeignKey ¶
type ForeignKey struct {
Table string `yaml:"table"`
Column string `yaml:"column"`
OnDelete string `yaml:"onDelete"`
}
ForeignKey describes a foreign key reference from a column.
type GeneratedFile ¶
GeneratedFile is a single codegen output: the file name (relative to the output directory) and its contents.
func GenerateCode ¶
func GenerateCode(s *Schema, lang CodegenLanguage, resourceName string) (*GeneratedFile, error)
GenerateCode renders type-safe code for a parsed schema in the given language. resourceName names the output file and is used only for the header. v0 supports TypeScript (row interfaces + column/table constants) and Python (Pydantic models). There is no ORM coupling.
type Index ¶
type Index struct {
Name string `yaml:"name"`
Columns []string `yaml:"columns"`
Unique bool `yaml:"unique"`
// Type is the index method (Postgres: btree, gin, gist, spgist, brin, hash;
// MySQL: btree, hash, fulltext, spatial). Empty means the engine default
// (btree). Only the index method is covered. Expression parts, operator
// classes and partial-index predicates are not modelled here, and those
// indexes belong in a hand-written migration listed under Schema.Exclude.
Type string `yaml:"type"`
}
Index describes a table index.
type MigrationRecord ¶
type MigrationRecord struct {
Version string
Description string
AppliedAt time.Time
ExecutionTime time.Duration
Failed bool
Error string
}
MigrationRecord is a single applied migration read from the revision history.
func ReadMigrationHistory ¶
func ReadMigrationHistory(ctx context.Context, a *Applier) ([]MigrationRecord, error)
ReadMigrationHistory returns the applied-migration history recorded in the database's atlas_schema_revisions table, ordered by version.
type PendingMigration ¶
PendingMigration describes a committed migration that has not yet been applied to the connected database.
type ProvisionReport ¶
type ProvisionReport struct {
// User is the role that was provisioned.
User string
// Schema is the schema its object privileges were granted in.
Schema string
// RoleCreated is true when the role did not exist and was created.
RoleCreated bool
// AuthConfigured is true when a password was set or the IAM role granted.
AuthConfigured bool
// IAMAuth records which authentication mode was configured.
IAMAuth bool
// Grants lists the privileges applied, in the order they were applied. Safe
// to print: identifiers only, never the password.
Grants []string
}
ProvisionReport records what provisioning actually changed, so a repeat run can honestly report that it did nothing.
func (*ProvisionReport) Changed ¶
func (r *ProvisionReport) Changed() bool
Changed reports whether provisioning altered anything beyond re-applying grants that were already in place. Grants are idempotent and cheap, so they are re-applied every run and do not count as a change.
type RiskLevel ¶
type RiskLevel string
RiskLevel classifies how safe it is to auto-apply a migration against a live database.
const ( // RiskSafe changes are additive and backward-compatible with running code // (add table/column-with-default, add non-unique index, drop index/constraint). RiskSafe RiskLevel = "safe" // RiskRisky changes are data-dependent and can fail or lock depending on // existing data (set NOT NULL, add unique index, add foreign key/check, // change column type, add NOT NULL column without a default). RiskRisky RiskLevel = "risky" // RiskBreaking changes are destructive/backward-incompatible with running // code (drop table/column/schema). RiskBreaking RiskLevel = "breaking" )
func ReadMigrationRisk ¶
ReadMigrationRisk returns the risk classification recorded in a migration file's header (falling back to risky when absent).
type Schema ¶
type Schema struct {
Tables map[string]Table `yaml:"tables"`
Extensions []string `yaml:"extensions"`
// Exclude lists objects that exist in the database but are deliberately not
// modelled here, typically because a hand-written migration creates them
// (expression or partial indexes, triggers, functions, policies). Patterns
// use Atlas's glob syntax relative to the managed schema, e.g.
// "audit_log.index[idx_*]" or "legacy_*". Excluded objects are never
// created, altered or dropped by schema-YAML-driven diffs.
Exclude []string `yaml:"exclude"`
}
Schema represents a parsed SQL database schema YAML file. Column types are engine-native (e.g. "serial", "varchar(50)", "jsonb").
func ParseSchema ¶
ParseSchema parses a SQL schema YAML from a reader.
func ParseSchemaFile ¶
ParseSchemaFile reads and parses a SQL schema YAML file from disk.
type Table ¶
type Table struct {
Description string `yaml:"description"`
Columns map[string]Column `yaml:"columns"`
Indexes []Index `yaml:"indexes"`
Constraints []Constraint `yaml:"constraints"`
// Tags are free-form categorisation labels (e.g. "financial", "core-entity")
// surfaced in exports. They have no effect on DDL.
Tags []string `yaml:"tags"`
// TypeName overrides the generated entity type name for this table (used by
// `schema codegen`). When empty, the name is derived by singularising the
// table name (e.g. customers → Customer). Set this for irregular plurals the
// singulariser gets wrong.
TypeName string `yaml:"typeName"`
}
Table describes a single database table.