-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
feat: add createMultiple method to HasMany and BelongsToMany associations #18038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add createMultiple method to HasMany and BelongsToMany associations #18038
Conversation
…ToMany - Add createMultiple method to HasManyAssociation and BelongsToManyAssociation - Enables bulk creation of associated records (e.g., createRoles, createComments) - Uses bulkCreate for efficient database operations - Automatically sets foreign keys and applies association scope - Add comprehensive TypeScript types and interfaces - Add tests for both hasMany and belongsToMany associations - Resolves feature request for bulk creation of associated records Closes: #XXXX (replace with actual issue number)
WalkthroughAdds Changes
Sequence DiagramsequenceDiagram
participant App as Application
participant Source as Source Instance
participant Assoc as Association.createMultiple
participant Target as Target Model
participant DB as Database
App->>Source: source.createMultiple([attrs...], options)
activate Assoc
Assoc->>Assoc: apply scope & inject FK / merge through attrs
Assoc->>Target: bulkCreate(preparedRecords, options)
activate Target
Target->>DB: INSERT multiple rows
DB-->>Target: Created instances
deactivate Target
Assoc->>Assoc: for BelongsToMany -> create join records
Assoc-->>App: Promise<Array<Target>> (created & associated)
deactivate Assoc
note over Assoc,Target: empty array -> return [] immediately
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
- Fix Array type syntax to use Array<T> instead of T[] for non-simple types - Apply Prettier formatting to test files - Ensure code style compliance with project standards
…le methods - Update type definitions in createMultiple methods of HasManyAssociation and BelongsToManyAssociation to use Array<T> instead of T[] for consistency. - Ensure return types reflect the new array syntax for better type clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/core/src/associations/base.ts(1 hunks)packages/core/src/associations/belongs-to-many.ts(4 hunks)packages/core/src/associations/has-many.ts(4 hunks)packages/core/test/integration/associations/belongs-to-many.test.js(1 hunks)packages/core/test/integration/associations/has-many.test.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/**/test/**/*.test.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name integration tests with the .test.js suffix
Files:
packages/core/test/integration/associations/belongs-to-many.test.jspackages/core/test/integration/associations/has-many.test.js
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/integration/associations/belongs-to-many.test.jspackages/core/test/integration/associations/has-many.test.js
🧬 Code graph analysis (2)
packages/core/src/associations/belongs-to-many.ts (1)
packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)BulkCreateOptions(1151-1211)Attributes(3433-3433)
packages/core/src/associations/has-many.ts (2)
packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)CreateOptions(1044-1072)Attributes(3433-3433)packages/core/src/model.js (1)
Model(148-4636)
🪛 ESLint
packages/core/src/associations/belongs-to-many.ts
[error] 923-923: Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead.
(@typescript-eslint/array-type)
[error] 1410-1410: Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead.
(@typescript-eslint/array-type)
packages/core/src/associations/has-many.ts
[error] 620-620: Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead.
(@typescript-eslint/array-type)
[error] 890-890: Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead.
(@typescript-eslint/array-type)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 20)
- GitHub Check: Upload install and build artifact (Node 18)
- Fix critical issue where scope columns were silently dropped when fields option was specified - Mirror the logic from single create methods to ensure scope attributes are included in fields array - Add comprehensive tests to verify scope columns are preserved with fields option - Ensures data integrity and prevents scope filter violations in bulk creation Fixes: Critical scope persistence issue in createMultiple method
- Change HasManyCreateAssociationsMixinOptions to extend BulkCreateOptions instead of CreateOptions - Add BulkCreateOptions import to has-many.ts - Allows callers to use bulk-specific options like updateOnDuplicate, ignoreDuplicates, individualHooks, etc. - Add comprehensive tests to verify bulk-specific options work correctly - Ensures createMultiple method has full parity with bulkCreate functionality Fixes: Major typing issue that blocked bulk-specific options at compile time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (2)
packages/core/src/associations/belongs-to-many.ts (1)
931-952: Do not mutate caller options; clone and dedupefieldsbefore bulkCreate.Nice job ensuring scope keys are included when
fieldsis provided. To avoid side effects on the caller’soptionsand to dedupe cleanly, shallow‑clone intobulkCreateOptionsand buildfieldsvia a Set, then pass that tobulkCreate.Apply this diff:
- // Handle fields option to include scope columns - if (options.fields && this.scope) { - const scopeKeys = Object.keys(this.scope); - options.fields = [ - ...options.fields, - ...scopeKeys.filter(key => !options.fields!.includes(key)), - ]; - } + // Handle fields option to include scope columns without mutating caller options + let bulkCreateOptions = options; + if (this.scope && options.fields) { + const fieldSet = new Set(options.fields as Array<keyof Attributes<TargetModel>>); + for (const key of Object.keys(this.scope)) { + fieldSet.add(key as keyof Attributes<TargetModel>); + } + bulkCreateOptions = { ...options, fields: Array.from(fieldSet) }; + } @@ - // Create the related model instances - const newAssociatedObjects = await this.target.bulkCreate(recordsToCreate, options); + // Create the related model instances + const newAssociatedObjects = await this.target.bulkCreate(recordsToCreate, bulkCreateOptions);packages/core/src/associations/has-many.ts (1)
887-889: Expose bulk options: extendBulkCreateOptionsinstead ofCreateOptions.
createMultipledelegates tobulkCreate; callers must be able to pass bulk‑specific options (e.g.,updateOnDuplicate,individualHooks).Apply this diff:
-export interface HasManyCreateAssociationsMixinOptions<T extends Model> - extends CreateOptions<Attributes<T>> {} +export interface HasManyCreateAssociationsMixinOptions<T extends Model> + extends BulkCreateOptions<Attributes<T>> {}Add the missing import at the top of the file:
- Attributes, - CreateOptions, + Attributes, + BulkCreateOptions, + CreateOptions,
🧹 Nitpick comments (1)
packages/core/src/associations/has-many.ts (1)
630-644: Avoid mutating options and dedupefieldsbefore bulkCreate.Clone
optionswhen augmentingfieldsand build it via a Set; then pass the cloned options tobulkCreate.Apply this diff:
- // Handle fields option to include scope and foreign key columns - if (options.fields) { - // Add scope attributes to fields if scope exists - if (this.scope) { - for (const attribute of Object.keys(this.scope)) { - if (!options.fields.includes(attribute)) { - options.fields.push(attribute); - } - } - } - - // Add foreign key to fields if not already present - if (!options.fields.includes(this.foreignKey)) { - options.fields.push(this.foreignKey); - } - } + // Handle fields option without mutating caller options + let bulkCreateOptions = options; + if (options.fields) { + const fieldSet = new Set(options.fields as Array<keyof Attributes<T>>); + if (this.scope) { + for (const attribute of Object.keys(this.scope)) { + fieldSet.add(attribute as keyof Attributes<T>); + } + } + fieldSet.add(this.foreignKey as keyof Attributes<T>); + bulkCreateOptions = { ...options, fields: Array.from(fieldSet) }; + } @@ - return this.target.bulkCreate(recordsToCreate, options); + return this.target.bulkCreate(recordsToCreate, bulkCreateOptions);Also applies to: 664-664
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/core/src/associations/belongs-to-many.ts(4 hunks)packages/core/src/associations/has-many.ts(4 hunks)packages/core/test/integration/associations/belongs-to-many.test.js(1 hunks)packages/core/test/integration/associations/has-many.test.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/core/test/integration/associations/has-many.test.js
🧰 Additional context used
📓 Path-based instructions (2)
packages/**/test/**/*.test.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name integration tests with the .test.js suffix
Files:
packages/core/test/integration/associations/belongs-to-many.test.js
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/integration/associations/belongs-to-many.test.js
🧬 Code graph analysis (2)
packages/core/src/associations/has-many.ts (1)
packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)CreateOptions(1044-1072)Attributes(3433-3433)
packages/core/src/associations/belongs-to-many.ts (1)
packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)BulkCreateOptions(1151-1211)Attributes(3433-3433)
🪛 ESLint
packages/core/src/associations/has-many.ts
[error] 622-622: Array type using 'Array' is forbidden for simple types. Use 'T[]' instead.
(@typescript-eslint/array-type)
[error] 910-910: Array type using 'Array' is forbidden for simple types. Use 'Target[]' instead.
(@typescript-eslint/array-type)
packages/core/src/associations/belongs-to-many.ts
[error] 925-925: Array type using 'Array' is forbidden for simple types. Use 'TargetModel[]' instead.
(@typescript-eslint/array-type)
[error] 1421-1421: Array type using 'Array' is forbidden for simple types. Use 'T[]' instead.
(@typescript-eslint/array-type)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 20)
- GitHub Check: Upload install and build artifact (Node 18)
🔇 Additional comments (7)
packages/core/src/associations/belongs-to-many.ts (2)
372-372: Accessor name for bulk-create is consistent.
createMultiple: "create${plural}"matches existing accessor patterns. LGTM.
496-497: Mixin exposure looks correct.Exposing
'createMultiple'alongside existing accessors is appropriate. LGTM.packages/core/test/integration/associations/belongs-to-many.test.js (3)
2271-2294: Bulk-create happy path test looks good.Covers createUsers with multiple rows and association verification. LGTM.
2296-2312: Empty array case is correct.Asserts no creation/associations on empty payload. LGTM.
2314-2340: Through-table attributes test is solid.Verifies join row attributes after createUsers. LGTM.
packages/core/src/associations/has-many.ts (2)
163-164: Accessor name for bulk-create is consistent.
createMultipleaccessor mirrorscreate. LGTM.
232-233: Mixin exposure looks correct.Adding
'createMultiple'to the mixin list is appropriate. LGTM.
- Fix ESLint array-type rule violations in createMultiple method signatures - Change Array<TargetModel> to TargetModel[] in belongsToMany - Change Array<T> to T[] in hasMany - Update corresponding TypeScript type definitions - Ensures CI compliance with ESLint array-type rule Fixes: ESLint array-type rule violations that would fail CI
- Use Array<T> for non-simple types like CreationAttributes<T> and Omit<CreationAttributes<T>, ExcludedAttributes> - Keep T[] for simple generics like TargetModel[] and Target[] - Fixes ESLint array-type rule violations that were causing CI failures - Ensures proper compliance with TypeScript ESLint array-type rule Fixes: ESLint array-type rule violations for non-simple generic types
- Move scope from User.belongsToMany to Task.belongsToMany where it belongs - Remove non-existent 'priority' attribute from User model and test assertions - Fix fields option to only include 'username' (removed 'priority') - Remove priority from createUsers payload and assertions - Ensure test only validates username and status attributes - Fixes test logic to properly test scope persistence with fields option Fixes: Incorrect scope placement and non-existent attribute usage in tests
- Remove status attribute from User and Task models (not needed for this test) - Fix test to check scope on junction table (UserTasks) instead of User model - In belongsToMany associations, scope is applied to the through table, not target model - Test now correctly validates that status: 'active' is set on junction table records - Ensures test properly validates scope persistence with fields option Fixes: Test failure where scope was being checked on wrong table
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
packages/core/src/associations/has-many.ts (1)
631-645: Consider cloningoptionsbefore mutatingfieldsto avoid side effects.The current implementation mutates the caller's
options.fieldsarray by pushing to it. While this mirrors the pattern in the single-recordcreatemethod (lines 593–600), it can cause unexpected behavior if the caller:
- Reuses the same options object for multiple calls
- Passes a frozen or readonly object
- Expects the options object to remain unchanged
Apply this diff to create a shallow copy:
const sourceKeyValue = sourceInstance.get(this.sourceKey); // Handle fields option to include scope and foreign key columns + let bulkCreateOptions = options; if (options.fields) { + bulkCreateOptions = { + ...options, + fields: [...options.fields], + }; + // Add scope attributes to fields if scope exists if (this.scope) { for (const attribute of Object.keys(this.scope)) { - if (!options.fields.includes(attribute)) { - options.fields.push(attribute); + if (!bulkCreateOptions.fields.includes(attribute)) { + bulkCreateOptions.fields.push(attribute); } } } // Add foreign key to fields if not already present - if (!options.fields.includes(this.foreignKey)) { - options.fields.push(this.foreignKey); + if (!bulkCreateOptions.fields.includes(this.foreignKey)) { + bulkCreateOptions.fields.push(this.foreignKey); } } const recordsToCreate = valuesArray.map(values => { const recordValues = { ...values }; // Apply scope if it exists if (this.scope) { for (const attribute of Object.keys(this.scope)) { // @ts-expect-error -- TODO: fix the typing of {@link AssociationScope} recordValues[attribute] = this.scope[attribute]; } } // Set the foreign key // @ts-expect-error -- TODO: fix the typing of foreign key assignment recordValues[this.foreignKey] = sourceKeyValue; return recordValues; }); - return this.target.bulkCreate(recordsToCreate, options); + return this.target.bulkCreate(recordsToCreate, bulkCreateOptions);packages/core/src/associations/belongs-to-many.ts (1)
930-937: Consider cloningoptionsbefore mutatingfieldsto avoid side effects.The current implementation mutates the caller's
optionsobject by reassigningoptions.fields(lines 933–936). While this approach creates a new array, it still modifies the originaloptionsobject, which can cause unexpected behavior if the caller:
- Reuses the same options object for multiple calls
- Passes a frozen or readonly object
- Expects the options object to remain unchanged
Apply this diff to create a shallow copy:
- // Handle fields option to include scope columns - if (options.fields && this.scope) { + let bulkCreateOptions = options; + if (bulkCreateOptions.fields && this.scope) { const scopeKeys = Object.keys(this.scope); - options.fields = [ - ...options.fields, + bulkCreateOptions = { + ...bulkCreateOptions, + fields: [ + ...bulkCreateOptions.fields, ...scopeKeys.filter(key => !options.fields!.includes(key)), - ]; + ], + }; } const recordsToCreate = valuesArray.map(values => { const recordValues = { ...values }; // Apply scope if it exists if (this.scope) { Object.assign(recordValues, this.scope); } return recordValues; }); // Create the related model instances - const newAssociatedObjects = await this.target.bulkCreate(recordsToCreate, options); + const newAssociatedObjects = await this.target.bulkCreate(recordsToCreate, bulkCreateOptions); // Associate all created instances await this.add(sourceInstance, newAssociatedObjects, omit(options, ['fields'])); return newAssociatedObjects;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/core/src/associations/belongs-to-many.ts(4 hunks)packages/core/src/associations/has-many.ts(5 hunks)packages/core/test/integration/associations/belongs-to-many.test.js(1 hunks)packages/core/test/integration/associations/has-many.test.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/core/test/integration/associations/has-many.test.js
- packages/core/test/integration/associations/belongs-to-many.test.js
🧰 Additional context used
🧬 Code graph analysis (2)
packages/core/src/associations/belongs-to-many.ts (1)
packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)BulkCreateOptions(1151-1211)Attributes(3433-3433)
packages/core/src/associations/has-many.ts (2)
packages/core/src/associations/belongs-to-many.ts (1)
sourceInstance(766-850)packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)BulkCreateOptions(1151-1211)Attributes(3433-3433)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 18)
- GitHub Check: Upload install and build artifact (Node 20)
🔇 Additional comments (5)
packages/core/src/associations/has-many.ts (3)
12-12: LGTM! Import aligns with the new bulk-create mixin.The
BulkCreateOptionsimport is correctly added to support the newHasManyCreateAssociationsMixinOptionsinterface.
883-889: LGTM! Interface correctly extendsBulkCreateOptions.The interface properly extends
BulkCreateOptions<Attributes<T>>to allow bulk-specific options likeupdateOnDuplicate,ignoreDuplicates, etc.
905-911: LGTM! Type signature follows ESLint conventions.The mixin type correctly uses:
Array<Omit<...>>for the complex parameter typePromise<Target[]>for the simple return typeThis satisfies the
@typescript-eslint/array-typerule.packages/core/src/associations/belongs-to-many.ts (2)
1399-1402: LGTM! Interface correctly extendsBulkCreateOptionswith through support.The interface properly extends
BulkCreateOptions<Attributes<T>>and adds thethroughoption to support passing attributes for the join table during bulk creation.
1418-1421: LGTM! Type signature follows ESLint conventions.The mixin type correctly uses:
Array<CreationAttributes<T>>for the complex parameter typePromise<T[]>for the simple return typeThis satisfies the
@typescript-eslint/array-typerule.
- Add scope to both User.belongsToMany and Task.belongsToMany associations
- Ensures both associations have compatible options to avoid SequelizeAssociationError
- Both associations now have the same scope: { status: 'active' }
- Fixes test failure where associations were incompatible due to different scope options
Fixes: SequelizeAssociationError about incompatible association options
- Change User/Task models to UserScope/TaskScope to avoid conflicts with other tests - Change junction table from UserTasks to UserTaskScopes for isolation - Update junction table query to use correct foreign key (taskScopeId) - Prevents SequelizeAssociationError from model name collisions across tests - Ensures test isolation and prevents throughAssociations conflicts Fixes: SequelizeAssociationError due to model name conflicts between tests
- Add explicit 'as' aliases to belongsToMany associations (taskScopes, userScopes) - Update test to use correct association method names (createUserScopes, getUserScopes) - Prevents SequelizeAssociationError from association name conflicts - Ensures complete test isolation with unique model names and association aliases Fixes: SequelizeAssociationError due to association name conflicts between tests
…olation - Move 'creates multiple associated objects with scope and fields option' test to its own describe block - Create new 'createMultiple with scope and fields' describe block after createAssociations - Ensures complete test isolation from other tests in the same file - Prevents SequelizeAssociationError from test interference and throughAssociations conflicts - Maintains all existing functionality while providing proper test isolation Fixes: SequelizeAssociationError due to test interference within same describe block
…plete isolation - Update all 4 tests in createAssociations describe block to use unique model names - UserBasic/TaskBasic for basic test - UserEmpty/TaskEmpty for empty array test - UserThrough/TaskThrough for through table attributes test - UserBulk/TaskBulk for bulk-specific options test - Each test now uses unique junction table names (UserTaskBasics, UserTaskEmpties, etc.) - Prevents SequelizeAssociationError from model name conflicts between tests - Ensures complete test isolation within the createAssociations describe block Fixes: SequelizeAssociationError due to model name conflicts between tests in same describe block
- Introduce a new test file to verify the functionality of the createMultiple method in Sequelize. - Define User and Post models with a one-to-many association. - Implement tests for creating multiple posts associated with a user, including scoped associations. - Ensure proper logging of test results and error handling. - Validate that associations are correctly established and scoped posts are created as expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
test-createmultiple-simple.js (3)
17-24: Remove redundant foreign key definition.The
userIdfield on line 20 is redundant. When you defineUser.hasMany(Post), Sequelize automatically creates theuserIdforeign key on the Post model. Explicitly defining it can cause confusion and potential conflicts.Apply this diff:
const Post = sequelize.define('Post', { title: DataTypes.STRING, content: DataTypes.STRING, - userId: DataTypes.INTEGER, });
55-66: Restructure test to avoid dropping tables mid-execution.The second
sync({ force: true })on line 66 drops all tables created in the first test scenario, making the test structure confusing.Consider either:
- Creating separate test functions for each scenario
- Using a fresh Sequelize instance for each test
- Using unique table names for each scenario (UserWithScope/PostWithScope vs User/Post)
Also, the explicit
userIddefinition on line 58 is redundant, as noted in the previous comment.Apply this diff:
const PostWithScope = sequelize.define('PostWithScope', { title: DataTypes.STRING, content: DataTypes.STRING, - userId: DataTypes.INTEGER, status: DataTypes.STRING, });
4-10: Clean up SQLite database file after test.The test creates
./test.dbbut doesn't clean it up. Consider using an in-memory database (:memory:) or explicitly deleting the file after the test completes.For in-memory database:
const sequelize = new Sequelize({ dialect: SqliteDialect, - storage: './test.db', + storage: ':memory:', logging: false, });Or add cleanup in finally block:
+ const fs = require('node:fs'); } finally { await sequelize.close(); + try { + fs.unlinkSync('./test.db'); + } catch (error) { + // Ignore if file doesn't exist + } }packages/core/test/integration/associations/belongs-to-many.test.js (1)
2381-2385: Consider removing unused scope definition.The scope defined on
User.belongsToMany(Task)(lines 2381-2385) is not used in this test, since the test only callstask.createUserScopes(), which uses theTask.belongsToMany(User)association. The unused scope definition may cause confusion.If the scope on the User→Task association is not needed for this test, consider removing it for clarity.
-User.belongsToMany(Task, { - through: 'UserTaskScopes', - as: 'taskScopes', - scope: { status: 'active' }, -}); +User.belongsToMany(Task, { + through: 'UserTaskScopes', + as: 'taskScopes', +});
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/test/integration/associations/belongs-to-many.test.js(1 hunks)test-createmultiple-simple.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/**/test/**/*.test.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name integration tests with the .test.js suffix
Files:
packages/core/test/integration/associations/belongs-to-many.test.js
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/integration/associations/belongs-to-many.test.js
🪛 ESLint
test-createmultiple-simple.js
[error] 34-34: Unexpected console statement.
(no-console)
[error] 40-40: Unexpected console statement.
(no-console)
[error] 41-41: Unexpected console statement.
(no-console)
[error] 42-42: Unexpected console statement.
(no-console)
[error] 46-46: Unexpected console statement.
(no-console)
[error] 47-47: Unexpected console statement.
(no-console)
[error] 50-50: Unexpected console statement.
(no-console)
[error] 74-74: Unexpected console statement.
(no-console)
[error] 75-75: Unexpected console statement.
(no-console)
[error] 76-76: Unexpected console statement.
(no-console)
[error] 78-78: Unexpected console statement.
(no-console)
- Remove test-createmultiple-simple.js which was used for manual verification - File was causing linting/formatting errors in CI - Implementation has been verified and is working correctly
- Use explicit object spread instead of omit() for add options - This may help with transaction management issues - Ensures proper options passing to the add method
- Refactor the normalization of throughAssociations to ensure it defaults to EMPTY_OBJECT when empty. - Improve clarity and consistency in the handling of throughAssociations within the normalizeBelongsToManyOptions function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/core/src/associations/belongs-to-many.ts (1)
914-959: LGTM: Implementation correctly handles bulk creation with scope and association.The method properly:
- Returns early for empty arrays
- Merges scope keys into
options.fieldsto ensure scoped columns are persisted (addressing previous review concerns)- Applies scope attributes to each record before bulk creation
- Associates all created instances with the source
The implementation follows the established pattern from the single
createmethod and efficiently usesbulkCreatefor the bulk operation.Optional: Consider using
omitfor consistency.For consistency with the single
createmethod (line 909), consider usingomitinstead of manual property deletion:- const addOptions = { ...options }; - delete addOptions.fields; - await this.add(sourceInstance, newAssociatedObjects, addOptions); + await this.add(sourceInstance, newAssociatedObjects, omit(options, ['fields']));This is a minor stylistic preference and not a functional issue.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/core/src/associations/belongs-to-many.ts(6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/core/src/associations/belongs-to-many.ts (2)
packages/core/src/model.d.ts (3)
CreationAttributes(3420-3420)BulkCreateOptions(1151-1211)Attributes(3433-3433)packages/core/src/utils/object.ts (1)
removeUndefined(219-221)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 20)
- GitHub Check: Upload install and build artifact (Node 18)
🔇 Additional comments (4)
packages/core/src/associations/belongs-to-many.ts (4)
372-372: LGTM: Accessor registration follows naming convention.The
createMultipleaccessor correctly follows the established naming pattern (using plural form), consistent with other bulk operations likeaddMultipleandremoveMultiple.
496-496: LGTM: Mixin registration is correct.The
createMultiplemethod is properly registered in the mixin list, ensuring it will be exposed on model instances.
1041-1059: LGTM: Normalization ensuresthroughAssociationsis always defined.The two-stage normalization correctly handles:
- Missing
throughAssociationsoption (usesEMPTY_OBJECT)- Provided but all-undefined properties (also uses
EMPTY_OBJECTafterremoveUndefined())This ensures the normalized options always have a defined
throughAssociationsproperty (either a non-empty object or theEMPTY_OBJECTsingleton), which aligns with theRequiredBytype constraint and enables efficient object identity checks.
1401-1428: LGTM: Type definitions are correct and follow linting conventions.The type definitions properly:
- Use
Array<CreationAttributes<T>>(long form) for complex parameter types- Use
T[](short form) for simple return types- Extend
BulkCreateOptions<Attributes<T>>to inherit standard bulk creation options- Add
through?: JoinTableAttributesto support join table attributes- Include clear JSDoc with usage examples
All previously flagged ESLint array-type issues have been resolved.
Closes: #11372
Pull Request Checklist
Description of Changes
List of Breaking Changes
Summary by CodeRabbit
New Features
Tests