diff --git a/packages/core/database/src/__tests__/repository.test.ts b/packages/core/database/src/__tests__/repository.test.ts index 060a1d434..513bdfde4 100644 --- a/packages/core/database/src/__tests__/repository.test.ts +++ b/packages/core/database/src/__tests__/repository.test.ts @@ -181,6 +181,80 @@ describe('repository.find', () => { }); }); +describe('repository create with belongs to many', () => { + let db: Database; + + beforeEach(async () => { + db = mockDatabase({ + tablePrefix: '', + }); + await db.clean({ drop: true }); + }); + + afterEach(async () => [await db.close()]); + + it('should save value at through table', async () => { + const Product = db.collection({ + name: 'products', + fields: [ + { type: 'string', name: 'name' }, + { type: 'integer', name: 'price' }, + ], + }); + + const OrderProduct = db.collection({ + name: 'orders_products', + fields: [{ type: 'integer', name: 'quantity' }], + }); + + const Order = db.collection({ + name: 'orders', + fields: [ + { + type: 'belongsToMany', + name: 'products', + through: 'orders_products', + }, + ], + }); + + await db.sync(); + + await Product.repository.create({ + values: [ + { + name: 'product1', + price: 100, + }, + { + name: 'product2', + price: 200, + }, + ], + }); + + const p1 = await Product.repository.findOne({ + filter: { name: 'product1' }, + }); + + await Order.repository.create({ + values: { + products: [ + { + id: p1.get('id'), + orders_products: { + quantity: 20, + }, + }, + ], + }, + }); + + const through = await OrderProduct.repository.findOne(); + expect(through.get('quantity')).toBe(20); + }); +}); + describe('repository.create', () => { let db: Database; let User: Collection; diff --git a/packages/core/database/src/update-associations.ts b/packages/core/database/src/update-associations.ts index cd9bd4a86..a16853cc5 100644 --- a/packages/core/database/src/update-associations.ts +++ b/packages/core/database/src/update-associations.ts @@ -6,10 +6,11 @@ import { HasOne, Hookable, ModelStatic, - Transactionable + Transactionable, } from 'sequelize'; import { Model } from './model'; import { UpdateGuard } from './update-guard'; +import lodash from 'lodash'; function isUndefinedOrNull(value: any) { return typeof value === 'undefined' || value === null; @@ -396,38 +397,40 @@ export async function updateMultipleAssociation( return; } - if (!Array.isArray(value)) { - value = [value]; - } + value = lodash.castArray(value); - const list1 = []; // to be setted - const list2 = []; // to be added - const created = []; + const setItems = []; // to be setted + const objectItems = []; // to be added + + // iterate item in value for (const item of value) { if (isUndefinedOrNull(item)) { continue; } + if (isStringOrNumber(item)) { - list1.push(item); + setItems.push(item); } else if (item instanceof Model) { - list1.push(item); + setItems.push(item); } else if (item.sequelize) { - list1.push(item); + setItems.push(item); } else if (typeof item === 'object') { const targetKey = (association as any).targetKey || 'id'; + if (item[targetKey]) { - created.push(item[targetKey]); - list1.push(item[targetKey]); + setItems.push(item[targetKey]); } - list2.push(item); + + objectItems.push(item); } } // associate targets in lists1 - await model[setAccessor](list1, { transaction, context, individualHooks: true }); + await model[setAccessor](setItems, { transaction, context, individualHooks: true }); - const list3 = []; - for (const item of list2) { + const newItems = []; + + for (const item of objectItems) { const pk = association.target.primaryKeyAttribute; const through = (association).through ? (association).through.model.name : null; @@ -446,13 +449,14 @@ export async function updateMultipleAssociation( if (isUndefinedOrNull(item[pk])) { // create new record const instance = await model[createAccessor](item, accessorOptions); + await updateAssociations(instance, item, { ...options, transaction, associationContext: association, updateAssociationValues: keys, }); - list3.push(instance); + newItems.push(instance); } else { // set & update record const instance = await association.target.findByPk(item[pk], { @@ -462,9 +466,9 @@ export async function updateMultipleAssociation( continue; } const addAccessor = association.accessors.add; - if (!created.includes(item[pk])) { - await model[addAccessor](item[pk], accessorOptions); - } + + await model[addAccessor](item[pk], accessorOptions); + if (!recursive) { continue; } @@ -477,11 +481,11 @@ export async function updateMultipleAssociation( associationContext: association, updateAssociationValues: keys, }); - list3.push(instance); + newItems.push(instance); } } - model.setDataValue(key, list1.concat(list3)); + model.setDataValue(key, setItems.concat(newItems)); } catch (error) { throw error; }