From ec38d3e44108a6ce168c8789ca97ffaf4889b802 Mon Sep 17 00:00:00 2001 From: meh Date: Sat, 1 Aug 2026 05:39:37 +0700 Subject: [PATCH] docs: how to migrate a schema, not just that you can The feature table named `worktable_version!` and `migration_engine!` and that was the whole of it. Working out how to use them meant reading the codegen and then finding a project that had already done it, which is a poor trade for a feature whose failure mode is silent data corruption. So the doc leads with what goes wrong rather than with the API. A persisted row carries no record of the columns that produced it, so a table whose columns change reads every existing row through the new layout and rkyv obliges. Nothing errors. Fields shift by one, ids arrive as titles, and the table opened cleanly. The example output is real, from a five-column table that gained a sixth. Everything here is verified against worktable 0.9.2 and a production migration: version defaults to 1 and must precede `columns`, old shapes use `worktable_version!` and are stripped of persist, indexes and queries, the table name stays fixed across versions, custom primary-key generators must be repeated per version module, hops compose so v1 to v4 is three functions, unchanged tables are copied rather than migrated, and a source already at the current version reports `Unsupported version: N`, which is how a run is made idempotent. Two things are called out because they are judgement rather than API. Source and target are separate directories, so a failed migration leaves the original untouched. And migration belongs in its own binary rather than in application startup, because a crash halfway through a boot-time migration is the case with no good recovery. --- README.md | 2 +- docs/migration.md | Bin 0 -> 7373 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/migration.md diff --git a/README.md b/README.md index e87c5243..d2d09f3b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ cargo add worktable | **Paged in-memory storage** | Records live in `DataPages` with a free list for reuse. `rkyv` gives zero-copy access to archived rows. | | **Concurrency** | Lock-free concurrent indexes with change-data-capture, plus a row-level `LockMap` for ordered access. | | **Optional persistence** | `PersistedWorkTable` writes to local disk; the `s3-support` feature syncs that to S3. Both opt-in, so a purely in-memory table pays for neither. | -| **Schema migration** | `worktable_version!` and `migration_engine!` version a table's schema and generate migrations between versions. | +| **Schema migration** | `worktable_version!` and `migration_engine!` version a table's schema and generate migrations between versions. See [docs/migration.md](docs/migration.md). | | **Memory accounting** | `MemStat` reports actual memory held. | ## Persistence diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 0000000000000000000000000000000000000000..8a901ba2721988d3ffbdebd9b95bf4b4ce547975 GIT binary patch literal 7373 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 literal 0 HcmV?d00001