Documentation
¶
Index ¶
- func ConnectDB(ctx context.Context, dsn string) (*sql.DB, error)
- func CreateMigration(ctx context.Context, name, dir string, opts *MigrationOptions) error
- func FormatSchemaJSON(tables []Table) (string, error)
- func FormatSchemaText(tables []Table) string
- func GenerateContextComment(ctx *MigrationContext) string
- func GeneratePointerComment(name string, history []string, created time.Time) string
- func GetMigrationHistory(dir string) ([]string, error)
- func PendingMigrations(dir string) ([]string, error)
- type AlreadyMergedError
- type Column
- type ForeignKey
- type Index
- type MigrationContext
- type MigrationOptions
- type MigrationService
- type ParsedColumn
- type ParsedTable
- type PreviousMigrationInfo
- type RebaseResult
- type SchemaIntrospector
- type Table
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateMigration ¶
func CreateMigration(ctx context.Context, name, dir string, opts *MigrationOptions) error
CreateMigration creates a new forward-only SQL migration, versioned with a UTC timestamp (YYYYMMDDHHMMSS_name.up.sql). See internal/migrationver for why the version is a timestamp rather than max+1: a sequential allocator hands the same number to every branch cut from the same commit, which is how ten version numbers in control-plane each ended up claimed by two different migrations. Existing sequential files are never renamed — a 14-digit timestamp sorts after any 5-digit number. The file opens with a short header naming where the schema lives (GeneratePointerComment); with opts.Context (or opts.DSN) it carries the full schema context instead.
func FormatSchemaJSON ¶
FormatSchemaJSON formats schema as JSON.
func FormatSchemaText ¶
FormatSchemaText formats schema as a human-readable text table.
func GenerateContextComment ¶
func GenerateContextComment(ctx *MigrationContext) string
GenerateContextComment builds the full SQL comment block for a new migration.
func GeneratePointerComment ¶ added in v0.1.46
GeneratePointerComment is the header a new migration gets by default: what it is and where the schema lives, not the schema itself.
The full context block (GenerateContextComment) copies the reconstructed schema, the whole previous migration and every filename into the file. On a real project that is thousands of lines — 4,658 on reliant, most of it a baseline it had just squashed — in a file whose SQL is three lines, and an agent or reviewer reads all of it. The schema is one command away, kept current, and not frozen into a migration that will outlive it.
It names no path: the file is committed, and the directory it sits in is the one it means.
func GetMigrationHistory ¶
GetMigrationHistory returns a sorted list of all migration filenames (just .up.sql).
func PendingMigrations ¶ added in v0.1.45
PendingMigrations returns the *.up.sql files in dir that are new on this branch — above the default branch's merge-base high-water mark — which is what `--all-pending` means.
Without git, newness is unknowable and this returns nothing rather than guessing. Offering to rename every migration in a directory, including merged history, is exactly the outcome the refusal exists to prevent, and an empty answer with an explanation is the honest version of "cannot tell".
Types ¶
type AlreadyMergedError ¶ added in v0.1.45
type AlreadyMergedError struct {
// File is the base name of the migration that was refused.
File string
// Version is the version it claims.
Version uint64
// MergeBaseMax is the high-water mark it is at or below.
MergeBaseMax uint64
}
AlreadyMergedError reports a refusal to re-version a migration that has already merged to the default branch.
It is a type, not a formatted string, so the CLI can report every refused file in one pass and a test can assert on the reason rather than on prose.
func (*AlreadyMergedError) Error ¶ added in v0.1.45
func (e *AlreadyMergedError) Error() string
type Column ¶
type Column struct {
Name string `json:"name"`
Type string `json:"type"`
Nullable bool `json:"nullable"`
Default string `json:"default,omitempty"`
IsPrimary bool `json:"is_primary"`
MaxLength *int `json:"max_length,omitempty"`
UDTName string `json:"udt_name,omitempty"`
}
Column represents a database column.
type ForeignKey ¶
type ForeignKey struct {
Name string `json:"name"`
Column string `json:"column"`
ReferencedTable string `json:"referenced_table"`
ReferencedColumn string `json:"referenced_column"`
}
ForeignKey represents a foreign key constraint.
type Index ¶
type Index struct {
Name string `json:"name"`
Columns []string `json:"columns"`
Unique bool `json:"unique"`
}
Index represents a database index.
type MigrationContext ¶
type MigrationContext struct {
MigrationName string
CreatedAt time.Time
ParsedTables []ParsedTable // Schema reconstructed from existing migrations
LiveTables []Table // Schema from live DB introspection (if --dsn)
PreviousMigration *PreviousMigrationInfo
MigrationHistory []string // List of all previous migration filenames
}
MigrationContext holds all gathered context for generating rich migration comments.
func GatherMigrationContext ¶
func GatherMigrationContext(ctx context.Context, name, migDir string, opts MigrationOptions) (*MigrationContext, error)
GatherMigrationContext collects all available context for a new migration.
type MigrationOptions ¶
type MigrationOptions struct {
DSN string // If set, introspect the live DB for schema
// Context writes the full context block — the schema, the previous
// migration and the history — into the new file instead of a pointer to
// where they live. Set by --context, and implied by DSN.
Context bool
// The compatibility declaration written at the top of the file (see
// compatHeader). At most one of BackwardCompatible and BreaksRollback,
// each the reason; RequireCompatDeclaration writes the choices as
// examples when neither is given.
BackwardCompatible string
BreaksRollback string
RequireCompatDeclaration bool
// Body is SQL written after the header, for a migration whose content
// forge already knows (`forge db migration new --closed-set`). Empty
// leaves the file for the author to write.
Body string
}
MigrationOptions controls what context is included when creating a new migration.
type MigrationService ¶
type MigrationService interface {
CreateMigration(ctx context.Context, name string, dir string, opts *MigrationOptions) error
GatherMigrationContext(ctx context.Context, name string, migDir string, opts MigrationOptions) (*MigrationContext, error)
GetPreviousMigration(ctx context.Context, dir string) (*PreviousMigrationInfo, error)
GetMigrationHistory(ctx context.Context, dir string) ([]string, error)
}
MigrationService creates and manages database migrations.
type ParsedColumn ¶
type ParsedColumn struct {
Name string
Type string
Constraint string // e.g. "PRIMARY KEY", "NOT NULL", "UNIQUE", "REFERENCES users(id)"
}
ParsedColumn represents a column extracted from a CREATE TABLE or ALTER TABLE statement.
type ParsedTable ¶
type ParsedTable struct {
Name string
Columns []ParsedColumn
}
ParsedTable represents a table reconstructed from parsing migration SQL files.
func ParseMigrationsForSchema ¶
func ParseMigrationsForSchema(dir string) ([]ParsedTable, error)
ParseMigrationsForSchema reads all .up.sql files in dir (sorted by name) and reconstructs a best-effort schema by parsing CREATE TABLE and ALTER TABLE statements.
type PreviousMigrationInfo ¶
PreviousMigrationInfo holds information about the most recent migration.
func GetPreviousMigration ¶
func GetPreviousMigration(dir string) (*PreviousMigrationInfo, error)
GetPreviousMigration reads the most recent .up.sql file from the migrations dir. Content is that migration's SQL without forge's generated header.
type RebaseResult ¶ added in v0.1.45
type RebaseResult struct {
OldPath string
NewPath string
// OldVersion and NewVersion are the numeric version prefixes, so a
// caller can assert ordering without re-parsing the filenames.
OldVersion uint64
NewVersion uint64
}
RebaseResult is one file's rename: what it was called and what it is called now. Returned rather than only printed so the CLI owns the output format and a test can assert on the decision instead of parsing stdout.
func RebaseMigrations ¶ added in v0.1.45
func RebaseMigrations(dir string, paths []string) ([]RebaseResult, error)
RebaseMigrations re-versions each file in paths to a fresh UTC timestamp that sorts after every version in dir and after the default branch's merge-base high-water mark.
The name stem is preserved: the version is the only thing that changes, so a reviewer following the file across the rename sees the same migration. Files are processed in ascending version order, which keeps their relative order intact — a batch that depends on being applied in sequence still is.
type SchemaIntrospector ¶
type SchemaIntrospector interface {
ConnectDB(ctx context.Context, dsn string) (*sql.DB, error)
IntrospectSchema(ctx context.Context, db *sql.DB, tableFilter string) ([]Table, error)
IntrospectTable(ctx context.Context, db *sql.DB, tableName string) (*Table, error)
}
SchemaIntrospector connects to databases and introspects their schema.
type Table ¶
type Table struct {
Name string `json:"name"`
Schema string `json:"schema"`
Columns []Column `json:"columns"`
PrimaryKey []string `json:"primary_key"`
Indexes []Index `json:"indexes"`
ForeignKeys []ForeignKey `json:"foreign_keys"`
}
Table represents a database table with its full schema metadata.
func IntrospectSchema ¶
IntrospectSchema connects to the database and returns the full schema. If tableFilter is non-empty, only that table is returned.