Skip to content

feat: Allow adding unique constraints to existing tables#4465

Open
Ludv1gL wants to merge 1 commit intoclockworklabs:masterfrom
Ludv1gL:feat/allow-add-unique-constraint
Open

feat: Allow adding unique constraints to existing tables#4465
Ludv1gL wants to merge 1 commit intoclockworklabs:masterfrom
Ludv1gL:feat/allow-add-unique-constraint

Conversation

@Ludv1gL
Copy link
Contributor

@Ludv1gL Ludv1gL commented Feb 26, 2026

Summary

Adding #[unique] or #[primary_key] to an existing column currently triggers AutoMigrateError::AddUniqueConstraint, forcing a full database clear to apply the schema change. This PR makes it a non-breaking migration by validating existing data first:

  • If all values are unique: constraint is added seamlessly (non-breaking migration)
  • If duplicates exist: migration fails with a detailed error listing up to 10 duplicate groups

Changes

  • auto_migrate.rs: Replace hard AddUniqueConstraint error with CheckAddUniqueConstraintValid precheck + AddConstraint migration step
  • update.rs: Implement precheck (full table scan, project constrained columns, count duplicates) and AddConstraint step execution
  • relational_db.rs: Expose create_constraint() (counterpart to existing drop_constraint())
  • traits.rs / datastore.rs: Add create_constraint_mut_tx to MutTxDatastore trait
  • mut_tx.rs: Make create_constraint public
  • formatter.rs: Format the new AddConstraint step

Safety

  • Transaction safety: Precheck and constraint creation run in the same MutTx — no window for concurrent duplicate inserts
  • Index creation: auto_migrate_indexes() already handles adding the backing btree index (with is_unique=true from the new schema). The constraint step only adds metadata.
  • Rollback: If the precheck finds duplicates, the entire migration aborts before any changes are applied
  • Error quality: Duplicate error shows table name, column names, and up to 10 example duplicate values with counts

Example error output

Precheck failed: cannot add unique constraint 'Users_email_key' on table 'Users' column(s) [email]:
3 duplicate group(s) found.
  - String("alice@example.com") appears 2 times
  - String("bob@example.com") appears 3 times
  - String("charlie@example.com") appears 2 times

Test plan

  • All 12 auto_migrate tests pass
  • cargo check passes for spacetimedb-schema and spacetimedb-core
  • Verified the previously-expected AddUniqueConstraint error test is updated
  • Manual test: add #[unique] to existing column with clean data → succeeds
  • Manual test: add #[unique] to existing column with duplicates → fails with detailed error

🤖 Generated with Claude Code

…lidation precheck

Instead of hard-rejecting #[unique] or #[primary_key] on existing columns,
scan for duplicates first. If data is clean, allow the constraint. If
duplicates exist, return a detailed error showing which values clash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Centril Centril self-requested a review February 26, 2026 13:34
@bfops
Copy link
Collaborator

bfops commented Feb 26, 2026

Interesting, thank you for filing this! We'll work on getting it reviewed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants