Help us shape the future of Go! Take the 2026 Go Developer Survey

migrate

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package migrate checks a schema-change draft, .aicoded/migration.sql, and applies an app's migrations to its database as the database's owner.

A draft holds at most 64 KiB of UTF-8 and 100 statements. Check splits it into statements and allows only those that add to the schema of the app's own database (Classify): CREATE TABLE, CREATE INDEX, and ALTER TABLE with only ADD clauses, where a new NOT NULL column has a DEFAULT. Destructive statements are refused with E-MIG-003 and everything else with E-MIG-002. Each publish adds its draft's statements to the app's list of steps, and Apply runs the steps that the database's journal, the table aicoded_migrations, lacks.

The aicoded CLI and the platform import it. App code may not: E-LINT-001 refuses the import.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Check

func Check(draft []byte) ([]string, error)

Check splits a draft into its statements and classifies each. It returns the statements and one error that joins every problem, each at the line of the draft its statement starts on.

Example
package main

import (
	"fmt"

	"aicoded.dev/framework/migrate"
)

func main() {
	statements, err := migrate.Check([]byte("CREATE TABLE notes (id BIGINT AUTO_INCREMENT PRIMARY KEY, body TEXT);\n" +
		"ALTER TABLE notes ADD COLUMN author VARCHAR(100) NULL;\n"))
	fmt.Println(len(statements), err)
}
Output:
2 <nil>

func Extends

func Extends(ran, steps []Step) error

Extends returns E-MIG-004 unless ran, the steps a database's journal holds, starts steps, or steps starts ran (a rollback). Steps match by Seq, Publish, Index and SHA256.

func IsJournal

func IsJournal(name string) bool

IsJournal reports whether name, a table name without quotes, names the journal of migrations, aicoded_migrations, under any case folding MySQL may apply to table names: Unicode simple folding, and İ and ı to i. Lint uses it to keep app code away from the journal.

func Normalize

func Normalize(stmt string) string

Normalize returns the form of stmt, a statement as Split returns it, in which two statements that MySQL reads alike are the same: its tokens with one space between each two, without comments or a final ;, and each word outside quotes in upper case, but for a table's name, after TABLE, ON or REFERENCES, and a word that starts with a digit, such as 0x1f. MySQL reads keywords and the names of columns and indexes in any case, while a table's name keeps its case. Strings and names in backquotes are kept as they are. Text the checks cannot read is returned without surrounding space.

func Split

func Split(draft []byte) ([]string, error)

Split splits a draft into its statements at each ; outside strings, quoted names and comments. It returns them without comments and surrounding space, and refuses, with E-MIG-001, a draft over 64 KiB, not UTF-8, with no statement or with more than 100.

Types

type Kind

type Kind int

Kind is the kind of a statement that Classify allows.

const Expand Kind = 1

Expand is a statement that adds to the schema and changes or removes nothing in it.

func Classify

func Classify(stmt string) (Kind, error)

Classify returns Expand for a statement that only adds to the schema of the app's own database: CREATE TABLE, CREATE INDEX, and ALTER TABLE with only ADD clauses. It refuses a destructive statement with E-MIG-003, and every other statement, and any it cannot read, with E-MIG-002.

Example
package main

import (
	"fmt"

	"aicoded.dev/framework/internal/errs"
	"aicoded.dev/framework/migrate"
)

func main() {
	_, err := migrate.Classify("ALTER TABLE notes DROP COLUMN author")
	fmt.Println(errs.Code(err))
}
Output:
E-MIG-003

type Step

type Step struct {
	// Seq is the step's place in the app's list, from 1.
	Seq int `json:"seq"`
	// Publish is the id of the publish that added the step, or "draft" locally.
	Publish string `json:"publish"`
	// Index is the step's place within its publish, from 1.
	Index int `json:"index"`
	// SHA256 is the lower-case hex SHA-256 of Statement.
	SHA256 string `json:"sha256"`
	// Statement is the SQL statement.
	Statement string `json:"statement"`
}

Step is one statement of an app's migrations.

func Apply

func Apply(ctx context.Context, db *sql.DB, steps []Step) (applied []Step, err error)

Apply runs on db the steps that its journal, the table aicoded_migrations, lacks, in order, and returns them. It holds the database's migration lock meanwhile, a named lock of aicoded_migrations: and the hex SHA-256 of the database's name cut to 64 characters, on one connection with lock_wait_timeout 30, and runs each step under a 5-minute context, then adds its row to the journal.

It refuses, before running anything, a list whose steps are not numbered from 1 or whose hash does not match its statement (E-MIG-004), a list the journal does not agree with (E-MIG-004, see Extends) and a step to run that Classify refuses. A step that fails stops Apply with E-MIG-005; the journal keeps the steps that ran. So does a step that ran but whose row could not be added to the journal, even on a new connection; its message says it ran but was not recorded.

Jump to

Keyboard shortcuts

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