fix(database): update belongs to many relation with target collection (#2393)

* fix(database): update belongs to many relation with target collection

* chore: test
This commit is contained in:
ChengLei Shao 2023-08-04 18:19:45 +08:00 committed by GitHub
parent 457082ffa1
commit e3e4e63146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 17 deletions

View File

@ -2,6 +2,89 @@ import { Collection } from '@nocobase/database';
import Database from '../../database'; import Database from '../../database';
import { BelongsToManyRepository } from '../../relation-repository/belongs-to-many-repository'; import { BelongsToManyRepository } from '../../relation-repository/belongs-to-many-repository';
import { mockDatabase } from '../index'; import { mockDatabase } from '../index';
import { pgOnly } from '@nocobase/test';
pgOnly()('belongs to many with targetCollection', () => {
let db: Database;
let Org: Collection;
let User: Collection;
let Student: Collection;
let OrgUser: Collection;
beforeEach(async () => {
db = mockDatabase();
await db.clean({ drop: true });
OrgUser = db.collection({
name: 'org_user',
});
Org = db.collection({
name: 'orgs',
fields: [
{ type: 'string', name: 'name' },
{ type: 'belongsToMany', name: 'users', target: 'users', through: 'org_user' },
],
});
User = db.collection({
name: 'users',
fields: [
{ type: 'string', name: 'name' },
{ type: 'belongsToMany', name: 'orgs', target: 'orgs', through: 'org_user' },
],
});
Student = db.collection({
name: 'students',
inherits: ['users'],
fields: [{ type: 'integer', name: 'score' }],
});
await db.sync();
});
afterEach(async () => {
await db.close();
});
it('should update child collection', async () => {
const u1 = await User.repository.create({
values: {
name: 'user1',
},
});
const s1 = await Student.repository.create({
values: {
name: 'student1',
score: 100,
},
});
const org1 = await Org.repository.create({
values: {
name: 'org1',
users: [u1.get('id'), s1.get('id')],
},
});
const repository = Org.repository.relation<BelongsToManyRepository>('users').of(org1.get('id'));
await repository.update({
filterByTk: s1.get('id'),
targetCollection: Student.name,
values: {
score: 200,
},
});
const s1AfterUpdate = await Student.repository.findOne({});
expect(s1AfterUpdate.get('score')).toBe(200);
});
});
describe('belongs to many with collection that has no id key', () => { describe('belongs to many with collection that has no id key', () => {
let db: Database; let db: Database;

View File

@ -121,14 +121,14 @@ export const DialectVersionAccessors = {
if (v.toLowerCase().includes('mariadb')) { if (v.toLowerCase().includes('mariadb')) {
return ''; return '';
} }
const m = /([\d+\.]+)/.exec(v); const m = /([\d+.]+)/.exec(v);
return m[0]; return m[0];
}, },
}, },
postgres: { postgres: {
sql: 'select version() as version', sql: 'select version() as version',
get: (v: string) => { get: (v: string) => {
const m = /([\d+\.]+)/.exec(v); const m = /([\d+.]+)/.exec(v);
return semver.minVersion(m[0]).version; return semver.minVersion(m[0]).version;
}, },
}, },
@ -290,17 +290,6 @@ export class Database extends EventEmitter implements AsyncEmitter {
}), }),
}); });
this.migrator = new Umzug({
logger: migratorOptions.logger || console,
migrations: this.migrations.callback(),
context,
storage: new SequelizeStorage({
modelName: `${this.options.tablePrefix || ''}migrations`,
...migratorOptions.storage,
sequelize: this.sequelize,
}),
});
this.initListener(); this.initListener();
patchSequelizeQueryInterface(this); patchSequelizeQueryInterface(this);
} }
@ -711,7 +700,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
async auth(options: Omit<QueryOptions, 'retry'> & { retry?: number | Pick<QueryOptions, 'retry'> } = {}) { async auth(options: Omit<QueryOptions, 'retry'> & { retry?: number | Pick<QueryOptions, 'retry'> } = {}) {
const { retry = 10, ...others } = options; const { retry = 10, ...others } = options;
const delay = (ms) => new Promise((yea) => setTimeout(yea, ms)); const delay = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
let count = 1; let count = 1;
const authenticate = async () => { const authenticate = async () => {
try { try {

View File

@ -1,4 +1,5 @@
import { HasOne, MultiAssociationAccessors, Sequelize, Transaction, Transactionable } from 'sequelize'; import { HasOne, MultiAssociationAccessors, Sequelize, Transaction, Transactionable } from 'sequelize';
import lodash from 'lodash';
import injectTargetCollection from '../decorators/target-collection-decorator'; import injectTargetCollection from '../decorators/target-collection-decorator';
import { import {
CommonFindOptions, CommonFindOptions,
@ -134,10 +135,8 @@ export abstract class MultipleRelationRepository extends RelationRepository {
const values = guard.sanitize(options.values); const values = guard.sanitize(options.values);
const queryOptions = this.buildQueryOptions(options as any);
const instances = await this.find({ const instances = await this.find({
...queryOptions, ...(lodash.omit(options, ['values']) as any),
transaction, transaction,
}); });