add: test (#224)

* add: test

* feat: updateAssociation Skip reverseAssociationPair

* feat: reverseAssociationPair with HasMany && HasOne
This commit is contained in:
ChengLei Shao 2022-03-06 19:12:44 +08:00 committed by GitHub
parent 4ce41cf7b2
commit e76eb1edac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 224 additions and 48 deletions

View 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);
});
});

View File

@ -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);
});
});

View File

@ -6,7 +6,7 @@ import {
HasOne,
Hookable,
ModelCtor,
Transactionable
Transactionable,
} from 'sequelize';
import { Model } from './model';
import { TransactionAble } from './repository';
@ -64,6 +64,7 @@ interface UpdateAssociationOptions extends Transactionable, Hookable {
updateAssociationValues?: string[];
sourceModel?: Model;
context?: any;
associationContext?: any;
}
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
* @param instance
@ -183,6 +215,10 @@ export async function updateAssociation(
return false;
}
if (options.associationContext && isReverseAssociationPair(association, options.associationContext)) {
return false;
}
switch (association.associationType) {
case 'HasOne':
case 'BelongsTo':
@ -280,7 +316,12 @@ export async function updateSingleAssociation(
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);
if (!options.transaction) {
await transaction.commit();
@ -290,7 +331,12 @@ export async function updateSingleAssociation(
}
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);
// @ts-ignore
if (association.targetKey) {
@ -392,7 +438,12 @@ export async function updateMultipleAssociation(
if (isUndefinedOrNull(item[pk])) {
// create new record
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);
} else {
// set & update record
@ -405,7 +456,12 @@ export async function updateMultipleAssociation(
if (updateAssociationValues.includes(key)) {
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);
}
}