Skip to content
This repository was archived by the owner on Aug 3, 2026. It is now read-only.

fix: worktable_version! does not compile for an unsized primary key - #178

Merged
pathscale merged 2 commits into
masterfrom
fix/worktable-version-non-generated-pk
Jul 31, 2026
Merged

fix: worktable_version! does not compile for an unsized primary key#178
pathscale merged 2 commits into
masterfrom
fix/worktable-version-non-generated-pk

Conversation

@pathscale

Copy link
Copy Markdown
Owner

The bug

worktable_version! fails to compile for any table whose primary key is not
fixed-size. A String key is the common case, and it is the case that matters:
a table keyed on a String cannot have a schema migration written against it at
all. Changing only the key type takes the same macro invocation from 0 errors to 4.

worktable_version!(
    name: Thing,
    columns: { id: String primary_key, name: String },
    indexes: { name_idx: name },
);
error[E0061]: this method takes 1 argument but 0 arguments were supplied
error[E0308]: mismatched types: expected `ThingWorkTable`, found future
error[E0061]: this struct takes 1 argument but 2 arguments were supplied
error[E0609]: no field `1` on type `&ThingWorkTable`

Cause

read_only and pk_unsized are independent flags on the PersistTable derive.
read_only selects the read-only shape: no persistence engine or task, a sync
into_worktable(), and a 1-tuple table struct. pk_unsized separately selects
the unsized primary index.

The read-only table generator emitted them as if they were mutually exclusive
(codegen/src/generators/read_only/table/mod.rs), so an unsized key silently
dropped read_only and generated the full persist shape against a read-only
table struct. load() then called an into_worktable() that had been generated
as async and returning Self(table, PersistenceTask), against a struct with one
field, which is exactly the four errors above.

The generator type is not involved. pk_gen_state() emitting
self.0.pk_gen.get_state() unconditionally is fine, since the state impl exists
for every generator including GeneratorType::None.

Fix

Emit #[table(read_only, pk_unsized)]. The attribute parser already accepts both
via parse_nested_meta, and every downstream read_only branch already composes
with pk_unsized: into_worktable's read-only arm uses the shared
primary_index_init, and the engine and task types return empty regardless. The
sized path is byte-for-byte unchanged.

Tests

Two, both verified to fail before the fix and pass after:

  • tests/worktable_version/string_primary_key.rs writes two rows through a
    persisted String-keyed table, reloads them through worktable_version!, and
    asserts on both a full scan and a lookup by string key. Without the fix it
    reproduces the four errors verbatim.
  • codegen/src/worktable_version/mod.rs gains a unit test asserting the emitted
    attribute keeps read_only for an unsized key.

The path was never covered because tests/worktable_version/basic.rs, the only
user of the macro, uses u64 primary_key autoincrement.

Release

Bumps worktable and worktable_codegen to 0.9.3 with the exact pin, matching
the 0.9.2 release commit. CHANGELOG.md is untouched, consistent with the 0.9.x
releases. Publishing is left for a human to run from merged master per
AGENTS.md.

Verification

cargo test 320 passed / 0 failed / 4 ignored (the 4 ignores are pre-existing and
annotated as such on master), 115 unit and 45 codegen tests pass,
cargo clippy --all-targets clean, cargo fmt --check clean.

meh added 2 commits August 1, 2026 06:01
The read-only table generator emitted the PersistTable derive attribute as
either #[table(pk_unsized)] or #[table(read_only)], never both. The two flags
are independent: read_only selects the read-only shape (no persistence engine
or task, sync into_worktable, 1-tuple table struct), pk_unsized selects the
unsized primary index. A read-only table with an unsized key needs both, so
picking pk_unsized silently dropped read_only and generated the full persist
shape against a read-only table struct.

The result was that worktable_version! did not compile at all for any table
whose primary key is not fixed-size, a String key being the common case:
load() called a sync into_worktable() that had been generated as async and
returning Self(table, PersistenceTask), against a struct with one field.

Fixed by emitting #[table(read_only, pk_unsized)]; the attribute parser
already accepts both, and every downstream read_only branch already composes
with pk_unsized. The sized path is unchanged.

This was never caught because tests/worktable_version/basic.rs, the only user
of the macro, uses u64 primary_key autoincrement.
Ships the worktable_version! fix for unsized primary keys. The macro did not
compile for any table whose key is not fixed-size, which is every table that
keys on a String, so no schema migration could be written against one. Bumps
worktable and worktable_codegen to 0.9.3 with the exact pin.
@pathscale
pathscale merged commit 375f73c into master Jul 31, 2026
2 checks passed
@pathscale
pathscale deleted the fix/worktable-version-non-generated-pk branch July 31, 2026 23:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant