ddl

package
v0.62.7 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package ddl provides the schema-modification execution surface for DALgo. It defines the SchemaModifier capability interface, the composable AlterOp model for collection alterations, the TransactionalDDL capability for atomicity advertisement, and top-level helper functions that wrap a type assertion on dal.DB.

ddl imports github.com/dal-go/dalgo/dbschema for the structural types it operates on (CollectionDef, FieldDef, IndexDef, etc.) AND for the shared NotSupportedError typed error. Drivers that implement DDL satisfy ddl.SchemaModifier; drivers that don't cause helper functions to return *dbschema.NotSupportedError.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AlterCollection

func AlterCollection(ctx context.Context, db dal.DB, name string, ops ...AlterOp) error

AlterCollection applies a batch of AlterOp values to an existing collection via the driver's SchemaModifier. Returns *dbschema.NotSupportedError if db does not implement SchemaModifier.

Transactional drivers (advertised via TransactionalDDL) roll back on partial failure. Non-transactional drivers MAY return *PartialSuccessError. Consumers wanting strict atomicity should check SupportsTransactionalDDL(db) before calling.

func CreateCollection

func CreateCollection(ctx context.Context, db dal.DB, c dbschema.CollectionDef, opts ...Option) error

CreateCollection creates a new collection (and any inline indexes declared on c.Indexes) via the driver's SchemaModifier. Returns *dbschema.NotSupportedError if db does not implement SchemaModifier.

func DropCollection

func DropCollection(ctx context.Context, db dal.DB, name string, opts ...Option) error

DropCollection drops a collection and its indexes via the driver's SchemaModifier. Returns *dbschema.NotSupportedError if db does not implement SchemaModifier.

func SupportsTransactionalDDL

func SupportsTransactionalDDL(db dal.DB) bool

SupportsTransactionalDDL is the convenience helper that encapsulates the type assertion and the convention that "doesn't implement = treat as non-transactional." Consumers SHOULD use this rather than performing the assertion themselves.

Types

type AlterOp

type AlterOp interface {

	// ApplyTo dispatches this AlterOp to the matching ApplyXxx method
	// on the given Applier, passing the op's stored fields and resolved
	// Options. Returns the Applier's error verbatim. Used by driver-side
	// SchemaModifier.AlterCollection implementations to handle a slice
	// of AlterOp values without type-switching on unexported concrete
	// types.
	ApplyTo(ctx context.Context, a Applier) error
	// contains filtered or unexported methods
}

AlterOp is the sealed interface for collection-altering operations passed to AlterCollection. Sealed via an unexported marker method (alterOp) so the set of valid alterations is closed at the package boundary — drivers know which cases exist and translate accordingly. New alteration kinds require adding to this package.

MVP constructors:

All six constructors accept opts ...Option for opt-in idempotency (reusing the same Option type as CreateCollection / DropCollection). Drivers MUST silently ignore semantically-mismatched options.

func AddField

func AddField(f dbschema.FieldDef, opts ...Option) AlterOp

AddField returns an AlterOp that adds a field to the collection. IfNotExists makes it idempotent (existing field of same name = no-op). IfExists is meaningless and silently ignored.

func AddIndex

func AddIndex(idx dbschema.IndexDef, opts ...Option) AlterOp

AddIndex returns an AlterOp that creates an index on the collection. On engines that support combined ALTER TABLE ... ADD INDEX syntax (MySQL), the driver MAY fold this into a single statement alongside other AlterOps in the same batch.

IfNotExists makes it idempotent (existing index of same name = no-op). IfExists is meaningless and silently ignored.

func DropField

func DropField(name dal.FieldName, opts ...Option) AlterOp

DropField returns an AlterOp that drops a field by name. IfExists makes it idempotent (missing field = no-op). IfNotExists is meaningless and silently ignored.

func DropIndex

func DropIndex(name string, opts ...Option) AlterOp

DropIndex returns an AlterOp that drops an index by name. IfExists makes it idempotent (missing index = no-op). IfNotExists is meaningless and silently ignored.

func ModifyField

func ModifyField(name dal.FieldName, newDef dbschema.FieldDef, opts ...Option) AlterOp

ModifyField returns an AlterOp that replaces an existing field's definition with newDef. The driver diffs old vs new and emits the minimal engine-specific change. When name != newDef.Name, the operation also renames the field.

opts is accepted for surface symmetry but both IfNotExists and IfExists are semantically meaningless on ModifyField. Drivers MUST silently ignore them.

func RenameField

func RenameField(oldName, newName dal.FieldName, opts ...Option) AlterOp

RenameField returns an AlterOp that renames a field from oldName to newName.

opts is accepted for surface symmetry but both IfNotExists and IfExists are semantically meaningless on RenameField. Drivers MUST silently ignore them.

type Applier

type Applier interface {
	// ApplyAddField is called by addFieldOp.ApplyTo.
	ApplyAddField(ctx context.Context, f dbschema.FieldDef, opts Options) error

	// ApplyDropField is called by dropFieldOp.ApplyTo.
	ApplyDropField(ctx context.Context, name dal.FieldName, opts Options) error

	// ApplyModifyField is called by modifyFieldOp.ApplyTo. name is
	// the current field name; newDef is its replacement (which MAY
	// have a different Name, indicating a rename as part of modify).
	ApplyModifyField(ctx context.Context, name dal.FieldName, newDef dbschema.FieldDef, opts Options) error

	// ApplyRenameField is called by renameFieldOp.ApplyTo.
	ApplyRenameField(ctx context.Context, oldName, newName dal.FieldName, opts Options) error

	// ApplyAddIndex is called by addIndexOp.ApplyTo.
	ApplyAddIndex(ctx context.Context, idx dbschema.IndexDef, opts Options) error

	// ApplyDropIndex is called by dropIndexOp.ApplyTo.
	ApplyDropIndex(ctx context.Context, name string, opts Options) error
}

Applier is the visitor interface for AlterOp dispatch. Driver-side implementations of SchemaModifier.AlterCollection construct an Applier (typically a struct holding the in-flight transaction and the target table name), then call AlterOp.ApplyTo on each op in their batch. ApplyTo dispatches to the matching ApplyXxx method on the Applier, where the driver translates the operation into engine-specific SQL or other side effects.

All six methods take ctx as the first parameter (forwarded by AlterOp.ApplyTo) and return error so driver-side failures surface to the AlterCollection caller.

The resolved Options value (already processed by ResolveOptions at AlterOp-constructor time) is passed last. Drivers MAY consult opts.IfNotExists / opts.IfExists for the field/index-level AlterOps where those flags are semantically meaningful (see the alter-ops Feature for which combinations matter per op).

Applier is NOT sealed — driver packages MUST implement it. Test stubs (e.g. a recording fakeApplier) MAY also implement it. New AlterOp variants added in future dalgo releases will extend this interface, which is a breaking change for existing implementers (compile-time error) — the same property the AlterOp sealed interface has on the producer side.

type Option

type Option func(*Options)

Option is the functional-option type accepted by CreateCollection, DropCollection, and all six AlterOp constructors via variadic opts ...Option. AlterCollection itself does NOT accept Option values directly — each AlterOp carries its own resolved Options set by the caller through the constructor.

func IfExists

func IfExists() Option

IfExists makes a Drop operation idempotent: the target being absent is a no-op rather than an error. Meaningless and silently ignored on Create / Add operations.

func IfNotExists

func IfNotExists() Option

IfNotExists makes a Create / Add operation idempotent: the target already existing is a no-op rather than an error. Meaningless and silently ignored on Drop operations.

type Options

type Options struct {
	IfNotExists bool
	IfExists    bool
}

Options is the resolved set of functional options for the collection-level and AlterOp-level operations.

IfNotExists makes Create / Add operations idempotent — the target existing already is a no-op rather than an error. IfExists makes Drop operations idempotent — the target being absent is a no-op.

Drivers MUST silently ignore semantically-mismatched options:

  • IfNotExists on Drop operations
  • IfExists on Create / Add operations
  • Any option on ModifyField or RenameField

The meaning is unambiguous (there is nothing to do with a mismatched hint), so a real error there would be a footgun.

func ResolveOptions

func ResolveOptions(opts ...Option) Options

ResolveOptions applies opts to a zero-value Options and returns the result. Drivers and AlterOp constructors use this to fold a variadic options slice into a struct.

type PartialSuccessError

type PartialSuccessError struct {
	// Op names the batched operation (currently always "AlterCollection").
	Op string
	// Collection is the target collection name.
	Collection string
	// Backend optionally identifies the driver.
	Backend string
	// Applied lists the ops that completed successfully, in original
	// order.
	Applied []AlterOp
	// FirstFailed is the op that failed.
	FirstFailed AlterOp
	// NotAttempted lists the ops that came after FirstFailed and were
	// not tried. May be empty if the driver attempted every op
	// regardless of earlier failures.
	NotAttempted []AlterOp
	// Cause is the underlying error from the failed op (driver-specific).
	Cause error
}

PartialSuccessError is the typed error returned by AlterCollection (and any future batched DDL call) when a non-transactional driver succeeds at some sub-operations and fails at others.

Distinct from *dbschema.NotSupportedError: NotSupportedError means "the driver can't do this at all"; PartialSuccessError means "the driver started doing this, then failed partway."

Transactional drivers — those for which TransactionalDDL.SupportsTransactionalDDL returns true — MUST NOT produce *PartialSuccessError. Their failure mode is a regular error (rollback already performed; nothing was applied).

Unwrap returns Cause so errors.Is(err, dal.ErrNotSupported) propagates transitively if the underlying failure was a not-supported case.

func (*PartialSuccessError) Error

func (e *PartialSuccessError) Error() string

Error returns a readable single-line summary.

func (*PartialSuccessError) Unwrap

func (e *PartialSuccessError) Unwrap() error

Unwrap returns Cause so errors.Is and errors.As propagate through the underlying driver-specific failure.

type SchemaModifier

type SchemaModifier interface {
	// CreateCollection creates the collection (table) and any inline
	// indexes declared on c.Indexes. Caller passes opts for opt-in
	// idempotency.
	CreateCollection(ctx context.Context, c dbschema.CollectionDef, opts ...Option) error

	// DropCollection drops the collection and its indexes. Caller
	// passes opts for opt-in idempotency.
	DropCollection(ctx context.Context, name string, opts ...Option) error

	// AlterCollection applies ops to the existing collection. The
	// driver decides how to apply the batch (one combined ALTER
	// statement on PostgreSQL; a sequence on SQLite; etc.).
	// Transactional drivers (advertised via TransactionalDDL) MUST
	// roll back on partial failure; non-transactional drivers MAY
	// return *PartialSuccessError listing applied/failed/not-attempted ops.
	AlterCollection(ctx context.Context, name string, ops ...AlterOp) error
}

SchemaModifier is the capability interface drivers implement to support DDL operations on dalgo collections. The interface is three methods:

  • CreateCollection creates a collection (table) along with any inline indexes declared in CollectionDef.Indexes.
  • DropCollection drops a collection along with its indexes.
  • AlterCollection applies a batch of AlterOp values (field-level and index-level alterations) to an existing collection. The driver decides how to apply the batch atomically; consumers check TransactionalDDL to know whether to expect rollback.

SchemaModifier is NOT embedded into dal.DB. DDL is genuinely optional for some backends — read-only wrappers, analytics drivers, mocks. Drivers opt in by implementing SchemaModifier on their dal.DB value (or a related type reachable via type assertion). The top-level helper functions CreateCollection, DropCollection, and AlterCollection type-assert against SchemaModifier and return *dbschema.NotSupportedError on the failed assertion.

Index-level operations after initial collection creation are NOT separate methods — they are AlterOp values passed to AlterCollection. See AddIndex and DropIndex.

type TransactionalDDL

type TransactionalDDL interface {
	SupportsTransactionalDDL() bool
}

TransactionalDDL is the optional capability interface drivers implement to advertise that they guarantee all-or-nothing atomicity for DDL calls that perform multiple sub-operations (notably AlterCollection with multiple AlterOps, or CreateCollection with inline indexes on some engines).

The pattern mirrors dal.ConcurrencyAware: a one-method optional interface that consumers type-assert against. Drivers that don't implement TransactionalDDL are treated as non-transactional.

When SupportsTransactionalDDL returns true: if any sub-operation fails, the driver MUST roll back all previously-applied sub-operations in the same call. The whole call returns a non-nil error; the DB is left in its pre-call state.

When SupportsTransactionalDDL returns false (or the interface is not implemented): the driver MAY apply some sub-operations and fail on others. Callers receive a *PartialSuccessError listing applied / failed / not-attempted ops.

The return value is constant from the moment a DB value is returned by its constructor until it is discarded; the same stability contract as dal.ConcurrencyAware.

Jump to

Keyboard shortcuts

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