Documentation
¶
Overview ¶
Package compat reads the contracts a migration declares about itself: that it is BACKWARD-COMPATIBLE (this file), and which foreign migration history a baseline ADOPTS (adopt.go).
THE CONTRACT. A migration's .up.sql may carry the line
-- forge:backward-compatible
which is its author's statement that the PREVIOUS release's code keeps working against the schema this migration leaves behind — the "expand" half of expand/contract. An ADD COLUMN that old code never reads is backward-compatible; a DROP COLUMN old code still SELECTs is not.
WHY A DECLARATION AND NOT AN INFERENCE. Whether N-1 code survives a schema is a fact about that code, not about the SQL, and nothing short of running it can prove it. An inference from the SQL would be wrong in both directions: `DROP TABLE` of a table nothing reads is safe, and `ADD COLUMN ... NOT NULL` without a default breaks every old INSERT. So the author, who knows, states it once, in the file, in review — and forge enforces what follows from it: the migrator records the declared versions in the database as it applies them, so an OLDER binary that meets a schema ahead of it — the previous release's pods, still serving or rescheduled, during every rolling deploy — can prove the extra versions are safe rather than hoping (see migratekit.SchemaAheadError).
WHY THIS IS ITS OWN PACKAGE. It is a comment parser every project's migrator links; keeping it free of golang-migrate lets any tool read the declaration without that dependency, so it imports nothing but the standard library.
Index ¶
Constants ¶
const AdoptsDirective = "-- forge:adopts"
AdoptsDirective is the line a baseline carries to declare the history it replaces, followed by the tool and its versions. Exported so the linter, errors and docs quote the spelling the parser matches.
const Directive = "-- forge:backward-compatible"
Directive is the exact line a migration carries to declare itself backward-compatible. Exported so remediation text, the linter and the scaffolded comment all quote the same spelling the parser matches.
const ToolForge = "forge"
ToolForge names forge's own migrator: a history `forge db squash` replaced, recorded in schema_migrations and schema_migrations_applied.
const ToolGoose = "goose"
ToolGoose names pressly/goose, whose history lives in goose_db_version.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Adoption ¶
type Adoption struct {
// Tool is the migration tool whose history this replaces (ToolGoose).
Tool string
// Versions is every version that tool recorded for the history this
// migration replaces: ascending, distinct, each positive.
Versions []int64
// Line is the 1-based line of the first directive, for messages.
Line int
}
Adoption is the foreign history one migration declares it replaces.
func ParseAdoption ¶
ParseAdoption reads the adoption one migration's up SQL declares. No directive is (nil, nil): almost every migration adopts nothing.
The grammar is strict, and deliberately so. Every database the binary meets parses it at boot — a fresh test database included — so a malformed list fails the first CI run instead of waiting for the one production database it was written for.
type AdoptionSyntaxError ¶
AdoptionSyntaxError is a malformed adoption directive. It carries the line so the linter can point at it; the migrator refuses the whole migration set, because a baseline whose adoption cannot be read would run its SQL against a database that already has the schema.
func (*AdoptionSyntaxError) Error ¶
func (e *AdoptionSyntaxError) Error() string
type Migration ¶
type Migration struct {
// Version is the numeric prefix — the value golang-migrate records in
// schema_migrations.
Version uint
// Name is the filename, for messages.
Name string
// Descriptor is the filename between the version prefix and `.up.` —
// `retire_plan_compute_free` in `00091_retire_plan_compute_free.up.sql`.
// It is what identifies WHICH migration a version is: two branches that
// both claim 91 differ here, while a change of zero-padding does not.
Descriptor string
// BackwardCompatible is whether the file carries Directive.
BackwardCompatible bool
// Adopts is the foreign history this migration replaces, from its
// AdoptsDirective lines; nil when it declares none. See adopt.go.
Adopts *Adoption
}
Migration is one up migration's version and what it declares.
func Scan ¶
Scan reads every up migration in dir of fsys, in version order.
A directory holding no up migrations returns an empty slice, not an error: a project that has not written one yet is a normal state. An unreadable directory IS an error, because "no migrations" and "could not look" call for different fixes.