add: test (#224)
* add: test * feat: updateAssociation Skip reverseAssociationPair * feat: reverseAssociationPair with HasMany && HasOne
This commit is contained in:
parent
4ce41cf7b2
commit
e76eb1edac
163
packages/database/src/__tests__/repository/create.test.ts
Normal file
163
packages/database/src/__tests__/repository/create.test.ts
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import { mockDatabase } from '../index';
|
||||||
|
import Database from '../../database';
|
||||||
|
|
||||||
|
describe('create with hasMany', () => {
|
||||||
|
let db: Database;
|
||||||
|
let Post;
|
||||||
|
let User;
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = mockDatabase();
|
||||||
|
|
||||||
|
await db.clean({ drop: true });
|
||||||
|
User = db.collection({
|
||||||
|
name: 'users',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'hasMany',
|
||||||
|
name: 'posts',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Post = db.collection({
|
||||||
|
name: 'posts',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'title',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'belongsTo',
|
||||||
|
name: 'user',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.sync();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should save associations with reverseField value', async () => {
|
||||||
|
const u1 = await db.getRepository('users').create({
|
||||||
|
values: {
|
||||||
|
name: 'u1',
|
||||||
|
posts: [{ title: 't1', user: null }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const p1 = await db.getRepository('posts').findOne();
|
||||||
|
// @ts-ignore
|
||||||
|
expect(await p1.getUser()).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create with belongsToMany', () => {
|
||||||
|
let db: Database;
|
||||||
|
let Post;
|
||||||
|
let Tag;
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = mockDatabase();
|
||||||
|
Post = db.collection({
|
||||||
|
name: 'posts',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'title',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'belongsToMany',
|
||||||
|
name: 'tags',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Tag = db.collection({
|
||||||
|
name: 'tags',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'belongsToMany',
|
||||||
|
name: 'posts',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.sync();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should save associations with reverseField value', async () => {
|
||||||
|
const t1 = await db.getRepository('tags').create({
|
||||||
|
values: {
|
||||||
|
name: 't1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const p1 = await db.getRepository('posts').create({
|
||||||
|
values: {
|
||||||
|
title: 'p1',
|
||||||
|
tags: [{ id: t1.get('id'), name: 't1', posts: [] }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
expect(await p1.countTags()).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
let db: Database;
|
||||||
|
let User;
|
||||||
|
let Post;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = mockDatabase();
|
||||||
|
User = db.collection({
|
||||||
|
name: 'users',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'name' },
|
||||||
|
{ type: 'hasMany', name: 'posts' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Post = db.collection({
|
||||||
|
name: 'posts',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'title' },
|
||||||
|
{ type: 'belongsTo', name: 'user' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await db.sync();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create with association', async () => {
|
||||||
|
const u1 = await User.repository.create({
|
||||||
|
values: {
|
||||||
|
name: 'u1',
|
||||||
|
posts: [{ title: 'u1p1' }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(u1.name).toEqual('u1');
|
||||||
|
expect(await u1.countPosts()).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
@ -1,43 +0,0 @@
|
|||||||
import { mockDatabase } from '../index';
|
|
||||||
import Database from '../../database';
|
|
||||||
|
|
||||||
describe('create', () => {
|
|
||||||
let db: Database;
|
|
||||||
let User;
|
|
||||||
let Post;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
db = mockDatabase();
|
|
||||||
User = db.collection({
|
|
||||||
name: 'users',
|
|
||||||
fields: [
|
|
||||||
{ type: 'string', name: 'name' },
|
|
||||||
{ type: 'hasMany', name: 'posts' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
Post = db.collection({
|
|
||||||
name: 'posts',
|
|
||||||
fields: [
|
|
||||||
{ type: 'string', name: 'title' },
|
|
||||||
{ type: 'belongsTo', name: 'user' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
await db.sync();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
test('create with association', async () => {
|
|
||||||
const u1 = await User.repository.create({
|
|
||||||
values: {
|
|
||||||
name: 'u1',
|
|
||||||
posts: [{ title: 'u1p1' }],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(u1.name).toEqual('u1');
|
|
||||||
expect(await u1.countPosts()).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
@ -6,7 +6,7 @@ import {
|
|||||||
HasOne,
|
HasOne,
|
||||||
Hookable,
|
Hookable,
|
||||||
ModelCtor,
|
ModelCtor,
|
||||||
Transactionable
|
Transactionable,
|
||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
import { TransactionAble } from './repository';
|
import { TransactionAble } from './repository';
|
||||||
@ -64,6 +64,7 @@ interface UpdateAssociationOptions extends Transactionable, Hookable {
|
|||||||
updateAssociationValues?: string[];
|
updateAssociationValues?: string[];
|
||||||
sourceModel?: Model;
|
sourceModel?: Model;
|
||||||
context?: any;
|
context?: any;
|
||||||
|
associationContext?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateModelByValues(instance: Model, values: UpdateValue, options?: UpdateOptions) {
|
export async function updateModelByValues(instance: Model, values: UpdateValue, options?: UpdateOptions) {
|
||||||
@ -164,6 +165,37 @@ export async function updateAssociations(instance: Model, values: any, options:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isReverseAssociationPair(a: any, b: any) {
|
||||||
|
const typeSet = new Set();
|
||||||
|
typeSet.add(a.associationType);
|
||||||
|
typeSet.add(b.associationType);
|
||||||
|
|
||||||
|
if (typeSet.size == 1 && typeSet.has('BelongsToMany')) {
|
||||||
|
return (
|
||||||
|
a.through.tableName === b.through.tableName &&
|
||||||
|
a.target.name === b.source.name &&
|
||||||
|
b.target.name === a.source.name &&
|
||||||
|
a.foreignKey === b.otherKey &&
|
||||||
|
a.sourceKey === b.targetKey &&
|
||||||
|
a.otherKey === b.foreignKey &&
|
||||||
|
a.targetKey === b.sourceKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((typeSet.has('HasOne') && typeSet.has('BelongsTo')) || (typeSet.has('HasMany') && typeSet.has('BelongsTo'))) {
|
||||||
|
const sourceAssoc = a.associationType == 'BelongsTo' ? b : a;
|
||||||
|
const targetAssoc = sourceAssoc == a ? b : a;
|
||||||
|
|
||||||
|
return (
|
||||||
|
sourceAssoc.source.name === targetAssoc.target.name &&
|
||||||
|
sourceAssoc.foreignKey === targetAssoc.foreignKey &&
|
||||||
|
sourceAssoc.sourceKey === targetAssoc.targetKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update model association by key
|
* update model association by key
|
||||||
* @param instance
|
* @param instance
|
||||||
@ -183,6 +215,10 @@ export async function updateAssociation(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.associationContext && isReverseAssociationPair(association, options.associationContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (association.associationType) {
|
switch (association.associationType) {
|
||||||
case 'HasOne':
|
case 'HasOne':
|
||||||
case 'BelongsTo':
|
case 'BelongsTo':
|
||||||
@ -280,7 +316,12 @@ export async function updateSingleAssociation(
|
|||||||
await instance.update(value, { ...options, transaction });
|
await instance.update(value, { ...options, transaction });
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateAssociations(instance, value, { ...options, transaction, updateAssociationValues: keys });
|
await updateAssociations(instance, value, {
|
||||||
|
...options,
|
||||||
|
transaction,
|
||||||
|
associationContext: association,
|
||||||
|
updateAssociationValues: keys,
|
||||||
|
});
|
||||||
model.setDataValue(key, instance);
|
model.setDataValue(key, instance);
|
||||||
if (!options.transaction) {
|
if (!options.transaction) {
|
||||||
await transaction.commit();
|
await transaction.commit();
|
||||||
@ -290,7 +331,12 @@ export async function updateSingleAssociation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const instance = await model[createAccessor](value, { context, transaction });
|
const instance = await model[createAccessor](value, { context, transaction });
|
||||||
await updateAssociations(instance, value, { ...options, transaction, updateAssociationValues: keys });
|
await updateAssociations(instance, value, {
|
||||||
|
...options,
|
||||||
|
transaction,
|
||||||
|
associationContext: association,
|
||||||
|
updateAssociationValues: keys,
|
||||||
|
});
|
||||||
model.setDataValue(key, instance);
|
model.setDataValue(key, instance);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (association.targetKey) {
|
if (association.targetKey) {
|
||||||
@ -392,7 +438,12 @@ export async function updateMultipleAssociation(
|
|||||||
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, { ...options, transaction, updateAssociationValues: keys });
|
await updateAssociations(instance, item, {
|
||||||
|
...options,
|
||||||
|
transaction,
|
||||||
|
associationContext: association,
|
||||||
|
updateAssociationValues: keys,
|
||||||
|
});
|
||||||
list3.push(instance);
|
list3.push(instance);
|
||||||
} else {
|
} else {
|
||||||
// set & update record
|
// set & update record
|
||||||
@ -405,7 +456,12 @@ export async function updateMultipleAssociation(
|
|||||||
if (updateAssociationValues.includes(key)) {
|
if (updateAssociationValues.includes(key)) {
|
||||||
await instance.update(item, { ...options, transaction });
|
await instance.update(item, { ...options, transaction });
|
||||||
}
|
}
|
||||||
await updateAssociations(instance, item, { ...options, transaction, updateAssociationValues: keys });
|
await updateAssociations(instance, item, {
|
||||||
|
...options,
|
||||||
|
transaction,
|
||||||
|
associationContext: association,
|
||||||
|
updateAssociationValues: keys,
|
||||||
|
});
|
||||||
list3.push(instance);
|
list3.push(instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user