fix(core): Model#equals always returns true for instances of different models#18143
Conversation
…t models otherModelDefinition was incorrectly assigned from this.modelDefinition instead of other.modelDefinition, making the model-type guard a no-op. Adds a unit test covering cross-model comparison. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughFixed a copy‑paste bug in Model#equals: the method now compares Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/core/test/unit/instance/equals.test.ts (1)
8-14: Declareidattribute for TypeScript type safety.The models don't declare the
idattribute, but it's used inbuild()calls throughout the tests. While Sequelize addsidas the default primary key at runtime,InferAttributesonly picks up explicitly declared properties, so TypeScript won't recognizeidin the build options.♻️ Suggested fix
- class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> { - declare username: string; - } - - class Project extends Model<InferAttributes<Project>, InferCreationAttributes<Project>> { - declare title: string; - } + class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> { + declare id: number; + declare username: string; + } + + class Project extends Model<InferAttributes<Project>, InferCreationAttributes<Project>> { + declare id: number; + declare title: string; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/test/unit/instance/equals.test.ts` around lines 8 - 14, The tests use build() with an id property but the Model subclasses (User and Project) don't declare id, so TypeScript won't recognize it; add an explicit id declaration (e.g. declare id?: number) to both class User and class Project declarations so InferAttributes includes id for build/create options and other usages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/core/test/unit/instance/equals.test.ts`:
- Around line 8-14: The tests use build() with an id property but the Model
subclasses (User and Project) don't declare id, so TypeScript won't recognize
it; add an explicit id declaration (e.g. declare id?: number) to both class User
and class Project declarations so InferAttributes includes id for build/create
options and other usages.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: da004d41-58aa-4b28-a11b-f4a05fad6fdb
📒 Files selected for processing (1)
packages/core/test/unit/instance/equals.test.ts
Co-authored-by: Rik Smale <13023439+WikiRik@users.noreply.github.com>
|
I approved too early, can you fix the CI issues? For the failing test; sequelize/packages/core/src/associations/has-one.ts Lines 298 to 304 in 9a972bb That also seems to be the only place that we use it internally. |
Cast to the base Model type at the cross-model call site so TypeScript accepts it without changing the equals(other: this) declaration: (user as Model).equals(project) Also cast null/undefined with as unknown as Model in the non-Model test, consistent with the existing plain-object cast. https://claude.ai/code/session_01DqaGiyPC1Eo1VXDVdwJ3cG
Head branch was pushed to by a user without write access
Sure, tried to fix 'em on the go, but id didn't fly. I will do it properly once I'm back to my computer and push 🫡 |
Add proper type declarations for the id attribute and provide all required model attributes when building test instances. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
e948ad1 to
eac6ed2
Compare
Model variants created by withScope, withoutScope, or withSchema have different modelDefinition objects. This caused equals() to return false for instances of the same logical model when one was loaded via a scoped query (e.g., in hasOne.set() which uses withoutScope()). Fix by using isSameInitialModel() to compare base models instead of comparing modelDefinition directly.
eac6ed2 to
b3d8950
Compare
Prevent DB2 constraint introspection from mixing referenced columns across tables that reuse the same key constraint name, and align DB2 query-generator expectations accordingly.
Summary
Fixes #18142.
Model#equalswas comparingthis.modelDefinitionagainst itself (copy-paste bug on line 4518), so the model-type guard was always a no-opconst otherModelDefinition = this.modelDefinition→const otherModelDefinition = other.modelDefinitionModel#equalscovering same-model, cross-model, and non-Model comparisonsRegression note
This is a recurring regression in
equals()— the same class of bug was previously reported and fixed in:The current regression was introduced when the codebase was refactored to use
modelDefinition.Test plan
packages/core/test/unit/instance/equals.test.jscovers:truetruefalsefalse(was broken)null,undefined, plain object →false🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests