fix: reference check after remove collection (#1123)
This commit is contained in:
parent
54e92918b2
commit
3556ddc730
@ -260,7 +260,9 @@ export class Collection<
|
|||||||
if (!this.fields.has(name)) {
|
if (!this.fields.has(name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field = this.fields.get(name);
|
const field = this.fields.get(name);
|
||||||
|
|
||||||
const bool = this.fields.delete(name);
|
const bool = this.fields.delete(name);
|
||||||
if (bool) {
|
if (bool) {
|
||||||
this.emit('field.afterRemove', field);
|
this.emit('field.afterRemove', field);
|
||||||
|
@ -356,6 +356,8 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
const collection = this.collections.get(name);
|
const collection = this.collections.get(name);
|
||||||
this.emit('beforeRemoveCollection', collection);
|
this.emit('beforeRemoveCollection', collection);
|
||||||
|
|
||||||
|
collection.resetFields();
|
||||||
|
|
||||||
const result = this.collections.delete(name);
|
const result = this.collections.delete(name);
|
||||||
|
|
||||||
this.sequelize.modelManager.removeModel(collection.model);
|
this.sequelize.modelManager.removeModel(collection.model);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import lodash from 'lodash';
|
||||||
|
|
||||||
export interface Reference {
|
export interface Reference {
|
||||||
sourceCollectionName: string;
|
sourceCollectionName: string;
|
||||||
sourceField: string;
|
sourceField: string;
|
||||||
@ -21,7 +23,7 @@ class ReferencesMap {
|
|||||||
// using existing reference
|
// using existing reference
|
||||||
return;
|
return;
|
||||||
} else if (existReference.onDelete === 'SET NULL') {
|
} else if (existReference.onDelete === 'SET NULL') {
|
||||||
this.removeReference(existReference);
|
existReference.onDelete = reference.onDelete;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`On Delete Conflict, exist reference ${JSON.stringify(existReference)}, new reference ${JSON.stringify(
|
`On Delete Conflict, exist reference ${JSON.stringify(existReference)}, new reference ${JSON.stringify(
|
||||||
@ -31,7 +33,12 @@ class ReferencesMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.map.set(reference.targetCollectionName, [...(this.map.get(reference.targetCollectionName) || []), reference]);
|
if (!existReference) {
|
||||||
|
this.map.set(reference.targetCollectionName, [
|
||||||
|
...(this.map.get(reference.targetCollectionName) || []),
|
||||||
|
reference,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getReferences(collectionName) {
|
getReferences(collectionName) {
|
||||||
@ -55,7 +62,8 @@ class ReferencesMap {
|
|||||||
if (!references) {
|
if (!references) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const keys = Object.keys(reference);
|
|
||||||
|
const keys = ['sourceCollectionName', 'sourceField', 'targetField', 'targetCollectionName'];
|
||||||
|
|
||||||
this.map.set(
|
this.map.set(
|
||||||
reference.targetCollectionName,
|
reference.targetCollectionName,
|
||||||
|
@ -27,6 +27,7 @@ export async function referentialIntegrityCheck(options: ReferentialIntegrityChe
|
|||||||
const filter = {
|
const filter = {
|
||||||
[sourceField]: referencedInstance[targetField],
|
[sourceField]: referencedInstance[targetField],
|
||||||
};
|
};
|
||||||
|
|
||||||
const referencingExists = await sourceRepository.count({
|
const referencingExists = await sourceRepository.count({
|
||||||
filter,
|
filter,
|
||||||
transaction,
|
transaction,
|
||||||
|
@ -83,15 +83,19 @@ export class BelongsToField extends RelationField {
|
|||||||
const tcoll = database.collections.get(this.target);
|
const tcoll = database.collections.get(this.target);
|
||||||
const foreignKey = this.options.foreignKey;
|
const foreignKey = this.options.foreignKey;
|
||||||
const field1 = collection.getField(foreignKey);
|
const field1 = collection.getField(foreignKey);
|
||||||
|
|
||||||
const field2 = tcoll.findField((field) => {
|
const field2 = tcoll.findField((field) => {
|
||||||
return field.type === 'hasMany' && field.foreignKey === foreignKey;
|
return field.type === 'hasMany' && field.foreignKey === foreignKey;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!field1 && !field2) {
|
if (!field1 && !field2) {
|
||||||
collection.model.removeAttribute(foreignKey);
|
collection.model.removeAttribute(foreignKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
const association = collection.model.associations[this.name];
|
const association = collection.model.associations[this.name];
|
||||||
this.database.referenceMap.removeReference(this.reference(association));
|
const reference = this.reference(association);
|
||||||
|
|
||||||
|
this.database.referenceMap.removeReference(reference);
|
||||||
|
|
||||||
this.clearAccessors();
|
this.clearAccessors();
|
||||||
// 删掉 model 的关联字段
|
// 删掉 model 的关联字段
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
import Database, { Collection as DBCollection } from '@nocobase/database';
|
||||||
|
import { MockServer, mockServer } from '@nocobase/test';
|
||||||
|
|
||||||
|
describe('reference integrity check', () => {
|
||||||
|
let db: Database;
|
||||||
|
let app: MockServer;
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = mockServer();
|
||||||
|
db = app.db;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clean reference after collection destroy', async () => {
|
||||||
|
const users = db.collection({
|
||||||
|
name: 'users',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'hasOne',
|
||||||
|
name: 'profile',
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const profiles = db.collection({
|
||||||
|
name: 'profiles',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'integer',
|
||||||
|
name: 'age',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'belongsTo',
|
||||||
|
name: 'user',
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.sync();
|
||||||
|
|
||||||
|
expect(db.referenceMap.getReferences('users').length).toEqual(1);
|
||||||
|
|
||||||
|
await users.repository.create({
|
||||||
|
values: {
|
||||||
|
name: 'foo',
|
||||||
|
profile: {
|
||||||
|
age: 18,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
db.removeCollection('profiles');
|
||||||
|
|
||||||
|
expect(db.referenceMap.getReferences('users').length).toEqual(0);
|
||||||
|
|
||||||
|
await users.repository.destroy({
|
||||||
|
filter: {
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user