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