Files
skills/docs/foundation/bitpacker/bitpacker-schema/src/migration/migration.md
2026-05-29 08:20:56 +01:00

3.3 KiB

Schema Migration

(no submodules)

Purpose

migration.ts ports the bit-packer schema migration toolkit from upstream. A migration describes how to transform data shaped by an old BitPackerSchema into data shaped by a newer one — adding fields, removing fields, renaming, changing types, splitting, merging, or running a fully custom transform. The toolkit is designed to be composable: a single migration step is a MigrationFunction, a strategy is one of MigrationStrategy, and a chain of strategies forms a path between two schema versions tracked by bitpacker-schema/versioning/.

This module is the data-shape side of schema evolution. The companion versioning.ts module owns version registration, lookup, and chain-execution; this file owns the per-step transform vocabulary, operation descriptors, and the helper builders that turn a strategy into a runnable function.

Features

  • MigrationStrategy enum covering the eight common transforms (ADD_FIELD, REMOVE_FIELD, RENAME_FIELD, CHANGE_FIELD_TYPE, MOVE_FIELD, SPLIT_FIELD, MERGE_FIELDS, CUSTOM).
  • MigrationOperation descriptor — a serialisable record of one step.
  • MigrationFunction<T, U> — a pure data transform, no side effects.
  • SchemaTypeToDataType<T> helper — propagates inferred runtime types.
  • Pure functions; no state, no I/O.

Usage: Basic Example

import {
    MigrationStrategy,
    type MigrationFunction,
} from "@suaveplan/bitpacker-schema";

// A v1 record is a plain `{ id }`; v2 adds `createdAt`.
const addCreatedAt: MigrationFunction = (data) => ({
    ...(data as Record<string, unknown>),
    createdAt: new Date().toISOString(),
});

Usage: Advanced Example

Compose multiple migrations through the versioning store. The migration.ts module supplies the building blocks; versioning.ts chains them.

import {
    MigrationStrategy,
    type MigrationFunction,
    type MigrationOperation,
} from "@suaveplan/bitpacker-schema";

const renameUserId: MigrationFunction = (raw) => {
    const r = raw as Record<string, unknown>;
    const { user_id, ...rest } = r;
    return { ...rest, userId: user_id };
};

const renameOp: MigrationOperation = {
    strategy: MigrationStrategy.RENAME_FIELD,
    fromField: "user_id",
    toField: "userId",
};

// Combined with versioning's `addMigration(fromVersion, toVersion, fn)`,
// the v2 -> v3 hop becomes a deterministic, replayable transform.

API Reference

  • enum MigrationStrategy — eight strategy tags.
  • interface MigrationOperation — strategy, plus optional fromField / toField / fromType / toType / metadata.
  • type MigrationFunction<T, U> — (data: T) => U.
  • type SchemaTypeToDataType<T> — placeholder for runtime data type inference; ported as unknown (upstream uses ad-hoc inference).

Implementation Notes

  • This file deliberately avoids any reference to actual BitPackerSchema evaluation; it is shape-only metadata. Execution lives in versioning.ts where chains are walked.
  • Strategies map 1:1 with the upstream enum so that migrations authored against the old API port without modification.
  • The CUSTOM strategy is the escape hatch for transforms that don't fit the other seven; the consumer supplies an arbitrary MigrationFunction and a description.