Skip to content

Newtype primary keys#3076

Draft
AngelOnFira wants to merge 1 commit into
SeaQL:masterfrom
AngelOnFira:angel/pk-newtype-gen
Draft

Newtype primary keys#3076
AngelOnFira wants to merge 1 commit into
SeaQL:masterfrom
AngelOnFira:angel/pk-newtype-gen

Conversation

@AngelOnFira

Copy link
Copy Markdown
Contributor

PR Info

New Features

1. Opt-in type-safe primary keys via newtypes

Adds a code-generation mode (sea-orm-cli generate entity --with-pk-newtypes) plus a library surface (sea_orm::Id<E, T>, PkAutoIncrementHint, FindByIdArg) that together give compile-time protection against mixing up primary-key values across entities. With the flag, user::Entity::find_by_id(post.id) no longer compiles because post.id is PostId (Id<post::Entity, i32>), which has no Into<Id<user::Entity, i32>> impl by design.

2. sea_orm::Id<E, T> library type

Phantom-typed PK wrapper, unique for each table's primary key. The only construction path is Id::new(value), there is deliberately no impl<E, T> From<T> for Id<E, T> blanket, which is what makes the compiler reject cross-entity confusion at every use site.

3. FindByIdArg<E> trait

The shared bound on find_by_id / filter_by_id / delete_by_id. A thin sea-orm-owned wrapper around Into<<E::PrimaryKey as PrimaryKeyTrait>::ValueType> so we can attach a curated #[diagnostic::on_unimplemented] message.

4. PkAutoIncrementHint trait

Trait-resolved default for whether a PK column is AUTO_INCREMENT (integers -> true, String/Vec<u8>/Uuid -> false). DeriveValueType emits an impl so the new PK wrappers will resolve through their inner type. This will replace the previous text-search method.

Breaking Changes

  • None

Notes: Backwards-compatible: nothing changes for entities generated without --with-pk-newtypes. find_by_id(7u8) against an i32 PK still works via the Into-forwarding blanket impl, and the auto_increment() body now resolves through PkAutoIncrementHint while producing the same defaults as before. DeleteMany::filter_by_ids (plural) keeps its pre-PR IntoIterator<Item = ValueType> bound to avoid unrelated behavior changes.

Changes

  • Codegen resolution chain. Per column, the emitted Rust type is resolved in a fixed precedence: (1) role wrapper for PK columns of junction tables with multiple FKs to the same parent (UserFollowerPkUserId), (2) single-parent FK column -> parent's PK alias, (3) own-PK alias (CakePk), (4) raw scalar fallback. Column::refs: Vec<ColumnRef> is populated from FK constraints (multi-parent supported).
  • auto_increment() macro body: composite PK -> false; explicit annotation -> literal bool; otherwise <FieldType as PkAutoIncrementHint>::IS_AUTO. DeriveValueType emits DelegatesPkAutoIncrementHint.
  • --with-pk-newtypes CLI flag (sea-orm-cli/src/cli.rs)
  • find_by_id / delete_by_id / filter_by_id now take T: FindByIdArg<Self>

Out of scope

  • Multi-parent FK columns aren't handled, and instead fall back to raw scalars

@AngelOnFira AngelOnFira force-pushed the angel/pk-newtype-gen branch from c82c606 to 8d32814 Compare June 6, 2026 03:23
@Huliiiiii

Copy link
Copy Markdown
Member

Could you split this into smaller PRs or commits? A 4k-loc change is quite difficult to review.

@AngelOnFira

Copy link
Copy Markdown
Contributor Author

Thanks for the suggestion @Huliiiiii! I have a few things I want to improve before setting this draft PR ready to review, so I'm happy to split the PR in places that make sense. I'm open for suggestions, here's the current breakdown;

  • ~650 LoC new example in examples/basic_typed_pk/
  • ~860 LoC sea-orm-codegen/
  • ~500 LoC new core code
  • ~670 LoC new tests
  • ~1.1k Loc duplicate code in sea-orm-sync/ (duplicates tests + core code)

I'm not sure I can easily split the core functionality into multiple PRs, but it would be easy to split this up into separate commits. I can also move examples/basic_typed_pk/ to another PR since that's just a demo of the feature.

If it seems like just making more commits won't help the problem, I can drill deeper into separating functionality into multiple PRs. Let me know what you think!

@Huliiiiii

Copy link
Copy Markdown
Member

I think you can keep going with the current implementations for now.

If it ends up being too hard to review once it’s ready, I’ll ask you to split it up then.

@AngelOnFira AngelOnFira changed the title Newtype pk Newtype primary keys Jun 6, 2026
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.

Type-safe primary keys

2 participants