fix: reference options sync (#1061)
* fix: sync onDelete options between field and reverseField * feat: reference compatibility
This commit is contained in:
parent
8a8478cf4c
commit
83cc19a013
@ -10,22 +10,25 @@ class ReferencesMap {
|
||||
protected map: Map<string, Reference[]> = new Map();
|
||||
|
||||
addReference(reference: Reference) {
|
||||
if (!reference.onDelete) {
|
||||
reference.onDelete = 'SET NULL';
|
||||
}
|
||||
|
||||
const existReference = this.existReference(reference);
|
||||
|
||||
if (existReference) {
|
||||
if (reference.onDelete && existReference.onDelete !== reference.onDelete) {
|
||||
if (existReference && existReference.onDelete !== reference.onDelete) {
|
||||
if (reference.onDelete === 'SET NULL') {
|
||||
// using existing reference
|
||||
return;
|
||||
} else if (existReference.onDelete === 'SET NULL') {
|
||||
this.removeReference(existReference);
|
||||
} else {
|
||||
throw new Error(
|
||||
`On Delete Conflict, exist reference ${JSON.stringify(existReference)}, new reference ${JSON.stringify(
|
||||
reference,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reference.onDelete) {
|
||||
reference.onDelete = 'SET NULL';
|
||||
}
|
||||
|
||||
this.map.set(reference.targetCollectionName, [...(this.map.get(reference.targetCollectionName) || []), reference]);
|
||||
|
@ -106,6 +106,9 @@ export class ApplicationVersion {
|
||||
async get() {
|
||||
if (await this.app.db.collectionExistsInDb('applicationVersion')) {
|
||||
const model = await this.collection.model.findOne();
|
||||
if (!model) {
|
||||
return null;
|
||||
}
|
||||
return model.get('value') as any;
|
||||
}
|
||||
return null;
|
||||
|
@ -56,6 +56,49 @@ describe('reverseField options', () => {
|
||||
expect(json.foreignKey).toBe(json.reverseField.foreignKey);
|
||||
});
|
||||
|
||||
it('should sync onDelete options for reverse field', async () => {
|
||||
const field = await Field.repository.create({
|
||||
values: {
|
||||
type: 'hasMany',
|
||||
collectionName: 'tests',
|
||||
target: 'targets',
|
||||
onDelete: 'CASCADE',
|
||||
reverseField: {},
|
||||
},
|
||||
});
|
||||
|
||||
const { reverseField } = field.toJSON();
|
||||
|
||||
expect(reverseField.onDelete).toBe('CASCADE');
|
||||
});
|
||||
|
||||
it('should update reverseField onDelete options', async () => {
|
||||
const field = await Field.repository.create({
|
||||
values: {
|
||||
type: 'hasMany',
|
||||
collectionName: 'tests',
|
||||
target: 'targets',
|
||||
onDelete: 'CASCADE',
|
||||
reverseField: {},
|
||||
},
|
||||
});
|
||||
|
||||
const { reverseField } = field.toJSON();
|
||||
|
||||
await Field.repository.update({
|
||||
filterByTk: reverseField.key,
|
||||
values: {
|
||||
onDelete: 'SET NULL',
|
||||
},
|
||||
});
|
||||
|
||||
const mainField = await Field.repository.findOne({
|
||||
filterByTk: field.get('key'),
|
||||
});
|
||||
|
||||
expect(mainField.get('onDelete')).toBe('SET NULL');
|
||||
});
|
||||
|
||||
it('should update reverseField', async () => {
|
||||
const field = await Field.repository.create({
|
||||
values: {
|
||||
|
@ -81,9 +81,9 @@ export function afterCreateForForeignKeyField(db: Database) {
|
||||
await r.update({
|
||||
filter: {
|
||||
collectionName,
|
||||
options:{
|
||||
primaryKey: true
|
||||
}
|
||||
options: {
|
||||
primaryKey: true,
|
||||
},
|
||||
},
|
||||
values: {
|
||||
sort: 0,
|
||||
|
@ -4,6 +4,7 @@ export function afterCreateForReverseField(db: Database) {
|
||||
return async (model, { transaction }) => {
|
||||
const Field = db.getCollection('fields');
|
||||
const reverseKey = model.get('reverseKey');
|
||||
|
||||
if (!reverseKey) {
|
||||
return;
|
||||
}
|
||||
|
@ -4,19 +4,28 @@ export function beforeCreateForReverseField(db: Database) {
|
||||
return async (model, { transaction }) => {
|
||||
const Field = db.getCollection('fields');
|
||||
const reverseKey = model.get('reverseKey');
|
||||
|
||||
if (!reverseKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reverse = await Field.model.findByPk(reverseKey, { transaction });
|
||||
model.set('collectionName', reverse.get('target'));
|
||||
model.set('target', reverse.get('collectionName'));
|
||||
|
||||
if (reverse.get('onDelete')) {
|
||||
model.set('onDelete', reverse.get('onDelete'));
|
||||
}
|
||||
|
||||
const reverseType = reverse.get('type') as any;
|
||||
|
||||
if (['hasMany', 'hasOne'].includes(reverseType)) {
|
||||
model.set('type', 'belongsTo');
|
||||
model.set('targetKey', reverse.get('sourceKey'));
|
||||
model.set('foreignKey', reverse.get('foreignKey'));
|
||||
model.set('sourceKey', reverse.get('targetKey'));
|
||||
}
|
||||
|
||||
if (['belongsTo'].includes(reverseType)) {
|
||||
if (!model.get('type')) {
|
||||
model.set('type', 'hasMany');
|
||||
@ -25,6 +34,7 @@ export function beforeCreateForReverseField(db: Database) {
|
||||
model.set('foreignKey', reverse.get('foreignKey'));
|
||||
model.set('targetKey', reverse.get('sourceKey'));
|
||||
}
|
||||
|
||||
if (['belongsToMany'].includes(reverseType)) {
|
||||
model.set('type', 'belongsToMany');
|
||||
model.set('through', reverse.get('through'));
|
||||
|
@ -156,6 +156,20 @@ export class FieldModel extends MagicAttributeModel {
|
||||
);
|
||||
}
|
||||
|
||||
async syncReferenceCheckOption(options: Transactionable) {
|
||||
const reverseKey = this.get('reverseKey');
|
||||
if (!reverseKey) return;
|
||||
|
||||
const reverseField = await this.db.getCollection('fields').repository.findOne({
|
||||
filterByTk: reverseKey,
|
||||
transaction: options.transaction,
|
||||
});
|
||||
|
||||
if (!reverseField) return;
|
||||
reverseField.set('onDelete', this.get('onDelete'));
|
||||
await reverseField.save({ hooks: false, transaction: options.transaction });
|
||||
}
|
||||
|
||||
protected getFieldCollection(): Collection | null {
|
||||
const collectionName = this.get('collectionName');
|
||||
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
beforeCreateForChildrenCollection,
|
||||
beforeCreateForReverseField,
|
||||
beforeDestroyForeignKey,
|
||||
beforeInitOptions
|
||||
beforeInitOptions,
|
||||
} from './hooks';
|
||||
|
||||
import { CollectionModel, FieldModel } from './models';
|
||||
@ -106,6 +106,13 @@ export class CollectionManagerPlugin extends Plugin {
|
||||
if (prevDefaultValue != currentDefaultValue) {
|
||||
await model.syncDefaultValue({ transaction, defaultValue: currentDefaultValue });
|
||||
}
|
||||
|
||||
const prevOnDelete = prevOptions['onDelete'];
|
||||
const currentOnDelete = currentOptions['onDelete'];
|
||||
|
||||
if (prevOnDelete != currentOnDelete) {
|
||||
await model.syncReferenceCheckOption({ transaction });
|
||||
}
|
||||
});
|
||||
|
||||
this.app.db.on('fields.afterSaveWithAssociations', async (model: FieldModel, { context, transaction }) => {
|
||||
|
Loading…
Reference in New Issue
Block a user