Documentation
¶
Overview ¶
Package migration defines Ridu's database-agnostic, reviewable migration artifact vocabulary. Store adapters translate schema manifests into physical steps while Ridu retains ownership of content-aware semantic steps.
Index ¶
- Constants
- Variables
- func DataTransformChecksum(source []byte) string
- func DigestArtifactHistory(identities []ArtifactIdentity, headDigest string, manifest schema.Manifest) (string, error)
- func DigestManifest(manifest schema.Manifest) (string, error)
- func MarshalStepPayload(value any) (json.RawMessage, error)
- func PhasePhysicalDigest(before string, mode PhaseMode, steps []Step) (string, error)
- func PhysicalDigestSeed(fromManifestDigest string) string
- func UnmanagedSchemaError(engine string, objects []string) error
- type Artifact
- func (artifact Artifact) AfterManifest() (schema.Manifest, error)
- func (artifact Artifact) BeforeManifest() (schema.Manifest, error)
- func (artifact Artifact) Digest() (string, error)
- func (artifact Artifact) MarshalJSON() ([]byte, error)
- func (artifact *Artifact) UnmarshalJSON(encoded []byte) error
- func (artifact Artifact) Validate() error
- type ArtifactIdentity
- type AssertSchemaPayload
- type AuditRequiredValuesPayload
- type BackfillReferencesPayload
- type BaselineReplacementOptions
- type ConcurrentIndexAction
- type ConcurrentIndexPayload
- type DataTransaction
- type DataTransform
- type DataTransformCallback
- type DataTransformDescriptor
- type DataTransformPayload
- type FieldRename
- type MongoDBCreateIndexPayload
- type MongoDBDropIndexPayload
- type MongoDBDropResourcesPayload
- type MongoDBRenameResourcePayload
- type Operation
- type Phase
- type PhaseMode
- type Planner
- type ProjectAction
- type ProjectDriver
- type ProjectRequest
- type Rename
- type RenamePayload
- type RequiredFieldAddress
- type RetireResourcesPayload
- type Risk
- type RiskLevel
- type SQLPayload
- type Step
- type StepKind
- type UpdateRequest
Constants ¶
const ( RequiredScopeLocalized = "localized" RequiredScopeUnlocalized = "unlocalized" )
Required-value audit scopes of a block definition's field.
const ArtifactVersion uint32 = 1
ArtifactVersion is the migration artifact format emitted by this build.
const PhysicalContractVersion uint32 = 1
PhysicalContractVersion identifies the meaning of intermediate physical digests.
const RunnerContractVersion uint32 = 1
RunnerContractVersion is the execution contract implemented by this build.
Variables ¶
var ErrReplacementNeedsConfirmation = errors.New("this database is exactly at its recorded " +
"migration head, so an application binary built from the old history may be serving it; " +
"after the replacement those binaries fail readiness until they are rebuilt from the new " +
"history; stop every application process and writer first")
ErrReplacementNeedsConfirmation reports a baseline replacement that would rewrite the history of a database exactly at its recorded head. Repeat the replacement with AllowProduction once its application processes are stopped.
Functions ¶
func DataTransformChecksum ¶
DataTransformChecksum returns the lowercase SHA-256 identity of reviewed callback source bytes. Applications normally compute and commit this value when authoring the migration callback.
func DigestArtifactHistory ¶
func DigestArtifactHistory(identities []ArtifactIdentity, headDigest string, manifest schema.Manifest) (string, error)
DigestArtifactHistory binds one complete ordered migration history to its recorded head manifest and the executable's storage schema. Settings outside the storage schema may differ from the head without changing this identity. Names must be unique and strictly increasing because committed filenames define execution order.
func DigestManifest ¶
DigestManifest returns the SHA-256 digest of a canonical manifest: its schema.Manifest.Bytes encoding. Readiness checks and every migration step digest whole manifests, so the indented form is streamed into the hash from the compact encoding instead of being materialized.
func MarshalStepPayload ¶
func MarshalStepPayload(value any) (json.RawMessage, error)
MarshalStepPayload emits one compact, deterministic payload object.
func PhasePhysicalDigest ¶
PhasePhysicalDigest advances the reviewed physical execution contract by one complete phase. The database is additionally inspected against the embedded manifests at the artifact boundaries.
func PhysicalDigestSeed ¶
PhysicalDigestSeed returns the canonical starting identity for the artifact's reviewed physical execution contract.
func UnmanagedSchemaError ¶ added in v0.8.0
UnmanagedSchemaError reports database objects found where a migration runner expected an empty database. `ridu dev` leaves exactly this behind: it synchronizes a schema directly and never records migration history.
Types ¶
type Artifact ¶
type Artifact struct {
// Version identifies this Ridu artifact JSON format.
Version uint32 `json:"version"`
// Name is the lowercase author-supplied migration name.
Name string `json:"name"`
// Planner records the exact planner and version used at creation.
Planner Planner `json:"planner"`
// MinimumRunnerContract is the lowest execution contract that may run
// every phase and executor in this artifact.
MinimumRunnerContract uint32 `json:"minimumRunnerContract,omitempty"`
// PreviousArtifactDigest binds this artifact to the exact preceding artifact,
// including data-only transitions whose manifest digest does not change.
// It is empty only for the initial artifact.
PreviousArtifactDigest string `json:"previousArtifactDigest"`
// FromDigest and ToDigest establish immutable manifest lineage.
FromDigest string `json:"fromDigest"`
ToDigest string `json:"toDigest"`
// Before is absent only for an initial migration from an empty schema.
Before *schema.Snapshot `json:"before,omitempty"`
// After is the complete desired manifest after every step succeeds.
After schema.Snapshot `json:"after"`
// Phases are the resumable execution plan.
Phases []Phase `json:"phases"`
// Risks retains machine-readable planner and linter findings for review.
Risks []Risk `json:"risks"`
}
Artifact is the immutable source of truth for one migration. It embeds both manifest states so history does not depend on a mutable latest-snapshot file.
func DecodeArtifact ¶
DecodeArtifact strictly decodes one frozen Ridu artifact format. Future versions and unknown fields are rejected before a runner can inspect a database.
func NewArtifact ¶
func NewArtifact(name string, planner Planner, before *schema.Manifest, after schema.Manifest) (Artifact, error)
NewArtifact creates an unpublished planner result with exact manifest lineage. Callers add ordered steps and risks before structural validation. The history publisher binds a non-initial result to its exact predecessor before it can be serialized or digested.
func (Artifact) AfterManifest ¶
AfterManifest returns the validated immutable after snapshot.
func (Artifact) BeforeManifest ¶
BeforeManifest returns the validated immutable before snapshot. Initial artifacts return an error because they intentionally have no parent state.
func (Artifact) MarshalJSON ¶
MarshalJSON emits the frozen artifact wire contract.
func (*Artifact) UnmarshalJSON ¶
UnmarshalJSON uses the same fail-closed versioned decoder as artifact files.
type ArtifactIdentity ¶
ArtifactIdentity is one committed migration file's immutable runtime identity. Name is the ordered filename recorded in an adapter's ledger; Digest authenticates the canonical artifact contents.
type AssertSchemaPayload ¶
type AssertSchemaPayload struct{}
AssertSchemaPayload is deliberately empty. The expected schema is the artifact's immutable after manifest.
type AuditRequiredValuesPayload ¶ added in v0.15.0
type AuditRequiredValuesPayload struct {
Fields []RequiredFieldAddress `json:"fields"`
}
AuditRequiredValuesPayload lists the fields whose stored values the audit checks, in planner order. Each field is newly required by the artifact.
type BackfillReferencesPayload ¶
type BackfillReferencesPayload struct {
BatchSize uint32 `json:"batchSize"`
}
BackfillReferencesPayload configures the one supported keyset batch executor. BatchSize is an artifact property, not a runner-side guess.
type BaselineReplacementOptions ¶ added in v0.12.0
type BaselineReplacementOptions struct {
PreviousDirectory string
// AllowProduction permits rewriting the history of a database that is
// exactly at its recorded head, where binaries built from that history may
// still pass readiness. Stop every application process and writer first.
AllowProduction bool
}
BaselineReplacementOptions controls an explicit rewrite of recorded history. PreviousDirectory must contain the immutable artifacts the database records; when empty, the replacement directory is also used as the previous history.
type ConcurrentIndexAction ¶
type ConcurrentIndexAction string
ConcurrentIndexAction selects typed concurrent index creation or removal.
const ( ConcurrentIndexCreate ConcurrentIndexAction = "create" ConcurrentIndexDrop ConcurrentIndexAction = "drop" )
type ConcurrentIndexPayload ¶
type ConcurrentIndexPayload struct {
Action ConcurrentIndexAction `json:"action"`
Name string `json:"name"`
Table string `json:"table,omitempty"`
Unique bool `json:"unique,omitempty"`
Method string `json:"method,omitempty"`
Parts []string `json:"parts,omitempty"`
Predicate string `json:"predicate,omitempty"`
}
ConcurrentIndexPayload is the closed concurrent-index vocabulary. Parts are PostgreSQL expressions emitted by the frozen planner; the runner quotes identifiers and never accepts a free-form no-transaction statement.
type DataTransaction ¶
type DataTransaction interface {
// Collection returns the collection with this slug as the running
// migration leaves it, or as it was before when the migration removes it.
// Every request must use a shape from the migration itself, so a
// transform keeps replaying after later migrations change the collection.
Collection(slug string) (schema.Collection, error)
// Global returns the global with this slug, resolved like Collection.
Global(slug string) (schema.Collection, error)
Create(context.Context, store.CreateRequest) (store.Document, error)
Find(context.Context, store.Request) (store.Document, error)
List(context.Context, store.Request) (store.Page, error)
Update(context.Context, UpdateRequest) (store.Document, error)
Trash(context.Context, store.Request) (store.Document, error)
Restore(context.Context, store.Request) (store.Document, error)
Delete(context.Context, store.Request) (store.Document, error)
}
DataTransaction is the transaction-bound semantic surface available to a migration callback. It intentionally omits Commit, Rollback, and generic SQL so the adapter retains ownership of the enclosing schema/data transaction. Update locks and reads the stored document itself; a callback never supplies it. Delete also removes the framework state the document owns, such as its versions, sessions, and preferences.
type DataTransform ¶
type DataTransform struct {
DataTransformDescriptor
Up DataTransformCallback
Down DataTransformCallback
}
DataTransform binds executable up/down behavior to the immutable descriptor stored in an artifact. Both directions are required for lifecycle parity.
func (DataTransform) Validate ¶
func (transform DataTransform) Validate() error
Validate checks the immutable and executable portions of a registration.
type DataTransformCallback ¶
type DataTransformCallback func(context.Context, DataTransaction) error
DataTransformCallback performs one direction of a reviewed migration.
type DataTransformDescriptor ¶
DataTransformDescriptor is the immutable artifact identity of one compiled migration callback. Checksum is author-supplied SHA-256 source identity; changing callback behavior requires a new checksum before artifact creation.
func (DataTransformDescriptor) Validate ¶
func (descriptor DataTransformDescriptor) Validate() error
Validate checks one artifact-safe callback descriptor.
type DataTransformPayload ¶
type DataTransformPayload struct {
Transform DataTransformDescriptor `json:"transform"`
}
DataTransformPayload identifies one application-compiled callback without serializing executable code into the immutable artifact.
type FieldRename ¶
type FieldRename struct {
// Before is the canonical field path in the before manifest.
Before string `json:"before"`
// After is the canonical field path in the after manifest.
After string `json:"after"`
}
FieldRename preserves one field address across an authored rename.
type MongoDBCreateIndexPayload ¶
type MongoDBCreateIndexPayload struct {
Collection string `json:"collection"`
Index string `json:"index"`
}
MongoDBCreateIndexPayload identifies one planner-owned physical index without serializing BSON, commands, or a portable schema language into the artifact.
type MongoDBDropIndexPayload ¶
type MongoDBDropIndexPayload struct {
CollectionID schema.StableID `json:"collectionId"`
Version bool `json:"version,omitempty"`
Published bool `json:"published,omitempty"`
Index string `json:"index"`
}
MongoDBDropIndexPayload identifies one adapter-owned index by the resource stable identity and deterministic index name.
type MongoDBDropResourcesPayload ¶
MongoDBDropResourcesPayload binds physical namespace removal to the same reviewed resource identities as the typed semantic retirement step.
type MongoDBRenameResourcePayload ¶
type MongoDBRenameResourcePayload struct {
BeforeID schema.StableID `json:"beforeId"`
AfterID schema.StableID `json:"afterId"`
}
MongoDBRenameResourcePayload binds one explicit collection identity rename.
type Operation ¶
type Operation struct {
// Kind selects the runner behavior.
Kind StepKind `json:"kind"`
// Name is a stable, review-friendly operation label.
Name string `json:"name"`
// SQL is present only for StepSQL.
SQL string `json:"sql,omitempty"`
// Rename is present only for StepRenameContent.
Rename *Rename `json:"rename,omitempty"`
// ResourceIDs is present only while planning a StepRetireResources step.
ResourceIDs []schema.StableID `json:"resourceIds,omitempty"`
// PurgeVersionOwnerIDs identifies surviving resources whose complete
// historical version rows could otherwise restore references to a retired
// resource. It is present only while planning StepRetireResources.
PurgeVersionOwnerIDs []schema.StableID `json:"purgeVersionOwnerIds,omitempty"`
// RequiredFields is present only for StepAuditRequiredValues.
RequiredFields []RequiredFieldAddress `json:"requiredFields,omitempty"`
}
Operation is one ordered physical or semantic planner operation. It is converted into a checkpointed artifact step before an artifact is written.
type Phase ¶
type Phase struct {
ID string `json:"id"`
Mode PhaseMode `json:"mode"`
PhysicalContractVersion uint32 `json:"physicalContractVersion"`
BeforePhysicalDigest string `json:"beforePhysicalDigest"`
AfterPhysicalDigest string `json:"afterPhysicalDigest"`
Steps []Step `json:"steps"`
}
Phase is one resumable execution boundary in an immutable artifact.
type PhaseMode ¶
type PhaseMode string
PhaseMode determines the transaction boundary used to execute one phase.
const ( // PhaseTransaction executes every phase step and its ledger completion in // one database transaction. PhaseTransaction PhaseMode = "transaction" // PhaseBatch executes one typed keyset executor in bounded transactions. PhaseBatch PhaseMode = "batch" // PhaseNoTransaction executes one typed physical operation which cannot run // inside a database transaction. Each operation is its own resumable phase. PhaseNoTransaction PhaseMode = "no_transaction" )
type ProjectAction ¶
type ProjectAction string
ProjectAction is one lifecycle operation delegated from the portable CLI to an application's compiled migration driver when artifacts contain callbacks.
const ( ProjectApply ProjectAction = "up" ProjectDown ProjectAction = "down" ProjectReset ProjectAction = "reset" ProjectRefresh ProjectAction = "refresh" ProjectFresh ProjectAction = "fresh" ProjectVerify ProjectAction = "verify" )
type ProjectDriver ¶
type ProjectDriver interface {
// Validate checks the complete executable registration before a project
// command resolves config or changes database state.
Validate() error
DataTransforms() []DataTransformDescriptor
// RunProjectMigration receives the exact manifest resolved by the process
// that will execute the request. The driver must validate it against the
// selected artifact history before opening or changing the database.
RunProjectMigration(context.Context, ProjectRequest, schema.Manifest) error
}
ProjectDriver keeps application callbacks compiled into the project while letting the selected adapter own the enclosing database transaction.
type ProjectRequest ¶
type ProjectRequest struct {
Action ProjectAction
DatabasePath string
DatabaseURL string
Directory string
AllowInsecureDatabase bool
AllowMaintenance bool
AllowUnbounded bool
LockWait time.Duration
OperationTimeout time.Duration
LockTimeout time.Duration
StatementTimeout time.Duration
BatchTimeout time.Duration
IdleTransactionTimeout time.Duration
StopAfterPhase string
StopAfterStep string
}
ProjectRequest contains only the database selection and structural paths selected by the invoking CLI. It carries no executable code and is private to the local project process. Credential-bearing URLs must be transported to that process outside its command-line arguments.
func (ProjectRequest) Validate ¶
func (request ProjectRequest) Validate() error
Validate rejects incomplete or unknown project migration requests.
type Rename ¶
type Rename struct {
// CollectionBefore and CollectionAfter are current public slugs. Both are
// empty for a block field rename.
CollectionBefore schema.CollectionSlug `json:"collectionBefore,omitempty"`
CollectionAfter schema.CollectionSlug `json:"collectionAfter,omitempty"`
// Block names the block definition whose field is renamed. The definition
// is shared, so the rename moves the field's content in every stored block
// of it, in every resource and version snapshot.
Block string `json:"block,omitempty"`
// FieldBefore and FieldAfter are canonical field paths, relative to Block
// for a block field rename. Empty paths mean the rename applies to the
// collection itself.
FieldBefore string `json:"fieldBefore,omitempty"`
FieldAfter string `json:"fieldAfter,omitempty"`
// Fields records every nested or top-level field path whose identity changed
// as part of a collection rename.
Fields []FieldRename `json:"fields,omitempty"`
}
Rename records explicit, committed content identity intent. Inference is allowed only while proposing this value; runners execute only persisted intent.
type RenamePayload ¶
type RenamePayload struct {
Rename Rename `json:"rename"`
}
RenamePayload contains one frozen content-identity rewrite.
type RequiredFieldAddress ¶ added in v0.15.0
type RequiredFieldAddress struct {
ResourceID schema.StableID `json:"resourceId,omitempty"`
Path string `json:"path"`
Scope string `json:"scope,omitempty"`
}
RequiredFieldAddress identifies a field of the artifact's after manifest. With a resource stable ID, Path is its canonical path in that resource: a path through a blocks field names the block type, as in layout.hero.heading. Without one, Path starts with a "**" segment and the field belongs to a block definition, checked in every stored block of it: **.hero.heading. A "**" segment finds the block it precedes at any depth beneath the preceding segment, so layout.**.hero.heading reaches every hero block stored in layout and **.card.items.**.hero.heading every hero block stored in a card's items. Scope, when set, limits the first block found to placements beneath a localized ancestor ("localized") or not ("unlocalized").
type RetireResourcesPayload ¶
type RetireResourcesPayload struct {
ResourceIDs []schema.StableID `json:"resourceIds"`
PurgeVersionOwnerIDs []schema.StableID `json:"purgeVersionOwnerIds,omitempty"`
}
RetireResourcesPayload identifies removed collection or global resources by their immutable stable IDs. IDs are strictly sorted so the artifact and its physical contract remain deterministic.
type Risk ¶
type Risk struct {
// Code is a stable identifier suitable for CI policy.
Code string `json:"code"`
// Level classifies whether the finding is informational, risky, or destructive.
Level RiskLevel `json:"level"`
// Message explains the concrete impact and required review.
Message string `json:"message"`
}
Risk is one machine-readable finding produced while planning a migration.
type RiskLevel ¶
type RiskLevel string
RiskLevel classifies the operational impact of a migration step.
const ( // RiskNotice records operational context that does not require intervention. RiskNotice RiskLevel = "notice" // RiskWarning records a change that deserves explicit deployment review. RiskWarning RiskLevel = "warning" // RiskDestructive records a change that can permanently remove stored data. RiskDestructive RiskLevel = "destructive" )
type SQLPayload ¶
type SQLPayload struct {
SQL string `json:"sql"`
}
SQLPayload contains SQL which is permitted only in a transaction phase.
type Step ¶
type Step struct {
ID string `json:"id"`
Kind StepKind `json:"kind"`
ExecutorVersion uint32 `json:"executorVersion"`
Name string `json:"name"`
Payload json.RawMessage `json:"payload"`
}
Step is one stable, independently ledgered executor invocation.
type StepKind ¶
type StepKind string
StepKind identifies how a migration runner executes one ordered step.
const ( // StepSQL executes one physical schema statement. StepSQL StepKind = "sql" // StepRenameContent rewrites schema-addressed content after physical renames. StepRenameContent StepKind = "rename_content" // StepAssertSchema verifies the resulting physical schema fingerprint. StepAssertSchema StepKind = "assert_schema" // StepBackfillReferences derives the current-document reference index after // its physical table has been created. Version snapshots are not indexed. StepBackfillReferences StepKind = "backfill_references" // StepRetireResources removes framework-owned shared state for resources // that a reviewed destructive migration removes. It is a typed semantic // executor and must run before the corresponding physical tables are dropped. StepRetireResources StepKind = "retire_resources" // StepDataTransform invokes one application-compiled, checksum-bound // callback inside the adapter's migration transaction. StepDataTransform StepKind = "data_transform" // StepAuditRequiredValues fails the migration while a stored document has // no value for a field the artifact makes required. It runs after every // data transform in its transaction, so a transform can backfill values. StepAuditRequiredValues StepKind = "audit_required_values" )
const StepConcurrentIndex StepKind = "concurrent_index"
StepConcurrentIndex executes one structured PostgreSQL concurrent-index operation outside a database transaction.
const StepMongoDBAssertSchema StepKind = "mongodb_assert_schema"
StepMongoDBAssertSchema verifies the complete planner-owned MongoDB catalog outside a database transaction after every physical step has completed.
const StepMongoDBCreateIndex StepKind = "mongodb_create_index"
StepMongoDBCreateIndex creates one planner-owned MongoDB index outside a database transaction. The payload freezes physical identity only; the adapter must reconstruct and exactly match the definition from the embedded manifest and versioned planner before touching a database.
const StepMongoDBDropIndex StepKind = "mongodb_drop_index"
StepMongoDBDropIndex removes one planner-owned MongoDB index outside a database transaction. The adapter reconstructs the exact physical collection and index definition from the embedded manifests; the payload never carries an arbitrary command.
const StepMongoDBDropResources StepKind = "mongodb_drop_resources"
StepMongoDBDropResources removes the content and version namespaces for one exact, sorted set of reviewed retired stable identities. Framework-owned shared state is removed by the preceding transactional retirement step.
const StepMongoDBRebuildHeadReservations StepKind = "mongodb_rebuild_head_reservations"
StepMongoDBRebuildHeadReservations recalculates active cross-head unique reservations before newly declared unique indexes are built.
const StepMongoDBRenameResource StepKind = "mongodb_rename_resource"
StepMongoDBRenameResource moves one collection identity to another outside a database transaction. Only stable manifest identities are persisted; the MongoDB adapter derives the exact content and version namespaces.
type UpdateRequest ¶ added in v0.15.0
UpdateRequest changes one document from a data transform. Values patch the stored document unless ReplaceValues makes them its complete authored state. The transaction applies the patch to the stored row it locks, never to a document the callback read or edited.