fix: update association value
This commit is contained in:
parent
f09991d932
commit
90846686ac
@ -35,44 +35,6 @@ describe('database', () => {
|
||||
expect(imageCollection.fields.has('url2')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('hasMany with inverse belongsTo relation', async () => {
|
||||
const db = mockDatabase();
|
||||
const UserCollection = db.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'hasMany', name: 'posts' },
|
||||
],
|
||||
});
|
||||
|
||||
const PostCollection = db.collection({
|
||||
name: 'posts',
|
||||
fields: [{ type: 'string', name: 'title' }],
|
||||
});
|
||||
|
||||
expect(UserCollection.model.associations.posts).toBeDefined();
|
||||
expect(PostCollection.model.associations.user).toBeDefined();
|
||||
});
|
||||
|
||||
test('belongsTo with inverse hasMany relation', async () => {
|
||||
const db = mockDatabase();
|
||||
const UserCollection = db.collection({
|
||||
name: 'users',
|
||||
fields: [{ type: 'string', name: 'name' }],
|
||||
});
|
||||
|
||||
const PostCollection = db.collection({
|
||||
name: 'posts',
|
||||
fields: [
|
||||
{ type: 'string', name: 'title' },
|
||||
{ type: 'belongsTo', name: 'user' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(PostCollection.model.associations.user).toBeDefined();
|
||||
expect(UserCollection.model.associations.posts).toBeDefined();
|
||||
});
|
||||
|
||||
test('get collection', async () => {
|
||||
const db = mockDatabase();
|
||||
expect(db.getCollection('test')).toBeUndefined();
|
||||
|
@ -17,6 +17,7 @@ describe('option parser', () => {
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'integer', name: 'age' },
|
||||
{ type: 'hasMany', name: 'posts' },
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { mockDatabase } from '../index';
|
||||
import { BelongsToManyRepository } from '../../relation-repository/belongs-to-many-repository';
|
||||
import Database from '../../database';
|
||||
|
||||
describe('belongs to many', () => {
|
||||
let db;
|
||||
let db: Database;
|
||||
let User;
|
||||
let Post;
|
||||
let Tag;
|
||||
let PostTag;
|
||||
@ -14,11 +16,29 @@ describe('belongs to many', () => {
|
||||
fields: [{ type: 'string', name: 'tagged_at' }],
|
||||
});
|
||||
|
||||
User = db.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'name',
|
||||
},
|
||||
{
|
||||
type: 'hasMany',
|
||||
name: 'posts',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Post = db.collection({
|
||||
name: 'posts',
|
||||
fields: [
|
||||
{ type: 'belongsToMany', name: 'tags', through: 'posts_tags' },
|
||||
{ type: 'string', name: 'title' },
|
||||
{
|
||||
type: 'belongsTo',
|
||||
name: 'user',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@ -248,6 +268,50 @@ describe('belongs to many', () => {
|
||||
expect(p2Tag.posts_tags.tagged_at).toBeNull();
|
||||
});
|
||||
|
||||
test('update association values', async () => {
|
||||
const u1 = await User.repository.create({
|
||||
values: {
|
||||
name: 'u1',
|
||||
},
|
||||
});
|
||||
|
||||
const p1 = await Post.repository.create({
|
||||
values: {
|
||||
title: 'p1',
|
||||
tags: [{ name: 't1' }, { name: 't2' }],
|
||||
user: u1.id,
|
||||
},
|
||||
});
|
||||
|
||||
const tag = await Tag.repository.findOne();
|
||||
const tagPostsRepository = new BelongsToManyRepository(Tag, 'posts', tag.id);
|
||||
|
||||
await tagPostsRepository.update({
|
||||
values: {
|
||||
user: {
|
||||
id: u1.get('id'),
|
||||
name: 'u0',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await u1.reload();
|
||||
expect(u1.get('name')).toEqual('u1');
|
||||
|
||||
await tagPostsRepository.update({
|
||||
values: {
|
||||
user: {
|
||||
id: u1.get('id'),
|
||||
name: 'u0',
|
||||
},
|
||||
},
|
||||
updateAssociationValues: ['user'],
|
||||
});
|
||||
|
||||
await u1.reload();
|
||||
expect(u1.get('name')).toEqual('u0');
|
||||
});
|
||||
|
||||
test('add', async () => {
|
||||
let t1 = await Tag.repository.create({
|
||||
values: { name: 't1' },
|
||||
|
@ -21,12 +21,16 @@ describe('repository.find', () => {
|
||||
name: 'posts',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'belongsTo', name: 'user' },
|
||||
{ type: 'hasMany', name: 'comments' },
|
||||
],
|
||||
});
|
||||
Comment = db.collection({
|
||||
name: 'comments',
|
||||
fields: [{ type: 'string', name: 'name' }],
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'belongsTo', name: 'post' },
|
||||
],
|
||||
});
|
||||
await db.sync();
|
||||
await User.repository.createMany({
|
||||
|
@ -15,6 +15,7 @@ describe('repository find', () => {
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'integer', name: 'age' },
|
||||
{ type: 'hasMany', name: 'posts' },
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
HasMany,
|
||||
Transactionable,
|
||||
Hookable,
|
||||
} from 'sequelize';
|
||||
import { UpdateGuard } from './update-guard';
|
||||
import { TransactionAble } from './repository';
|
||||
@ -21,6 +23,10 @@ function isStringOrNumber(value: any) {
|
||||
return typeof value === 'string' || typeof value === 'number';
|
||||
}
|
||||
|
||||
function getKeysByPrefix(keys: string[], prefix: string) {
|
||||
return keys.filter((key) => key.startsWith(`${prefix}.`)).map((key) => key.substring(prefix.length + 1));
|
||||
}
|
||||
|
||||
export function modelAssociations(instance: Model) {
|
||||
return (<typeof Model>instance.constructor).associations;
|
||||
}
|
||||
@ -57,6 +63,11 @@ interface UpdateOptions extends TransactionAble {
|
||||
sourceModel?: Model;
|
||||
}
|
||||
|
||||
interface UpdateAssociationOptions extends Transactionable, Hookable {
|
||||
updateAssociationValues?: string[];
|
||||
sourceModel?: Model;
|
||||
}
|
||||
|
||||
export async function updateModelByValues(instance: Model, values: UpdateValue, options?: UpdateOptions) {
|
||||
if (!options?.sanitized) {
|
||||
const guard = new UpdateGuard();
|
||||
@ -105,7 +116,7 @@ export async function updateThroughTableValue(
|
||||
* @param values
|
||||
* @param options
|
||||
*/
|
||||
export async function updateAssociations(instance: Model, values: any, options: any = {}) {
|
||||
export async function updateAssociations(instance: Model, values: any, options: UpdateAssociationOptions = {}) {
|
||||
// if no values set, return
|
||||
if (!values) {
|
||||
return;
|
||||
@ -119,8 +130,10 @@ export async function updateAssociations(instance: Model, values: any, options:
|
||||
transaction = await instance.sequelize.transaction();
|
||||
}
|
||||
|
||||
const keys = Object.keys(values);
|
||||
|
||||
for (const key of Object.keys(modelAssociations(instance))) {
|
||||
if (values[key]) {
|
||||
if (keys.includes(key)) {
|
||||
await updateAssociation(instance, key, values[key], {
|
||||
...options,
|
||||
transaction,
|
||||
@ -159,7 +172,12 @@ export async function updateAssociations(instance: Model, values: any, options:
|
||||
* @param value
|
||||
* @param options
|
||||
*/
|
||||
export async function updateAssociation(instance: Model, key: string, value: any, options: any = {}) {
|
||||
export async function updateAssociation(
|
||||
instance: Model,
|
||||
key: string,
|
||||
value: any,
|
||||
options: UpdateAssociationOptions = {},
|
||||
) {
|
||||
const association = modelAssociationByKey(instance, key);
|
||||
|
||||
if (!association) {
|
||||
@ -183,7 +201,12 @@ export async function updateAssociation(instance: Model, key: string, value: any
|
||||
* @param value
|
||||
* @param options
|
||||
*/
|
||||
export async function updateSingleAssociation(model: Model, key: string, value: any, options: any = {}) {
|
||||
export async function updateSingleAssociation(
|
||||
model: Model,
|
||||
key: string,
|
||||
value: any,
|
||||
options: UpdateAssociationOptions = {},
|
||||
) {
|
||||
const association = <HasOne | BelongsTo>modelAssociationByKey(model, key);
|
||||
|
||||
if (!association) {
|
||||
@ -194,7 +217,8 @@ export async function updateSingleAssociation(model: Model, key: string, value:
|
||||
return false;
|
||||
}
|
||||
|
||||
const { transaction = await model.sequelize.transaction() } = options;
|
||||
const { updateAssociationValues = [], transaction = await model.sequelize.transaction() } = options;
|
||||
const keys = getKeysByPrefix(updateAssociationValues, key);
|
||||
|
||||
try {
|
||||
// set method of association
|
||||
@ -220,6 +244,7 @@ export async function updateSingleAssociation(model: Model, key: string, value:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value instanceof Model) {
|
||||
await model[setAccessor](value);
|
||||
model.setDataValue(key, value);
|
||||
@ -248,9 +273,15 @@ export async function updateSingleAssociation(model: Model, key: string, value:
|
||||
},
|
||||
transaction,
|
||||
});
|
||||
|
||||
if (instance) {
|
||||
await model[setAccessor](instance);
|
||||
await updateAssociations(instance, value, { transaction, ...options });
|
||||
|
||||
if (updateAssociationValues.includes(key)) {
|
||||
await instance.update(value, { ...options, transaction });
|
||||
}
|
||||
|
||||
await updateAssociations(instance, value, { ...options, transaction, updateAssociationValues: keys });
|
||||
model.setDataValue(key, instance);
|
||||
if (!options.transaction) {
|
||||
await transaction.commit();
|
||||
@ -259,12 +290,8 @@ export async function updateSingleAssociation(model: Model, key: string, value:
|
||||
}
|
||||
}
|
||||
|
||||
if (value[dataKey] === null) {
|
||||
return await removeAssociation();
|
||||
}
|
||||
|
||||
const instance = await model[createAccessor](value, { transaction });
|
||||
await updateAssociations(instance, value, { transaction, ...options });
|
||||
await updateAssociations(instance, value, { ...options, transaction, updateAssociationValues: keys });
|
||||
model.setDataValue(key, instance);
|
||||
// @ts-ignore
|
||||
if (association.targetKey) {
|
||||
@ -288,7 +315,12 @@ export async function updateSingleAssociation(model: Model, key: string, value:
|
||||
* @param value
|
||||
* @param options
|
||||
*/
|
||||
export async function updateMultipleAssociation(model: Model, key: string, value: any, options: any = {}) {
|
||||
export async function updateMultipleAssociation(
|
||||
model: Model,
|
||||
key: string,
|
||||
value: any,
|
||||
options: UpdateAssociationOptions = {},
|
||||
) {
|
||||
const association = <BelongsToMany | HasMany>modelAssociationByKey(model, key);
|
||||
|
||||
if (!association) {
|
||||
@ -299,7 +331,8 @@ export async function updateMultipleAssociation(model: Model, key: string, value
|
||||
return false;
|
||||
}
|
||||
|
||||
const { transaction = await model.sequelize.transaction() } = options;
|
||||
const { updateAssociationValues = [], transaction = await model.sequelize.transaction() } = options;
|
||||
const keys = getKeysByPrefix(updateAssociationValues, key);
|
||||
|
||||
try {
|
||||
const setAccessor = association.accessors.set;
|
||||
@ -359,7 +392,7 @@ export async function updateMultipleAssociation(model: Model, key: string, value
|
||||
if (isUndefinedOrNull(item[pk])) {
|
||||
// create new record
|
||||
const instance = await model[createAccessor](item, accessorOptions);
|
||||
await updateAssociations(instance, item, { transaction, ...options });
|
||||
await updateAssociations(instance, item, { ...options, transaction, updateAssociationValues: keys });
|
||||
list3.push(instance);
|
||||
} else {
|
||||
// set & update record
|
||||
@ -369,7 +402,10 @@ export async function updateMultipleAssociation(model: Model, key: string, value
|
||||
const addAccessor = association.accessors.add;
|
||||
|
||||
await model[addAccessor](item[pk], accessorOptions);
|
||||
await updateAssociations(instance, item, { transaction, ...options });
|
||||
if (updateAssociationValues.includes(key)) {
|
||||
await instance.update(item, { ...options, transaction });
|
||||
}
|
||||
await updateAssociations(instance, item, { ...options, transaction, updateAssociationValues: keys });
|
||||
list3.push(instance);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user