Fix/recreate association field (#1789)

* chore: test

* fix: recreate association with same name as field
This commit is contained in:
ChengLei Shao 2023-05-03 08:05:55 +08:00 committed by GitHub
parent cba7de55d8
commit d4636311e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 178 additions and 0 deletions

View File

@ -17,6 +17,25 @@ describe('collection', () => {
await db.close(); await db.close();
}); });
it('should remove sequelize model prototype methods after field remove', async () => {
db.collection({
name: 'tags',
});
const UserCollection = db.collection({
name: 'users',
fields: [{ type: 'belongsToMany', name: 'tags' }],
});
console.log(Object.getOwnPropertyNames(UserCollection.model.prototype));
await UserCollection.removeField('tags');
console.log(Object.getOwnPropertyNames(UserCollection.model.prototype));
// @ts-ignore
expect(UserCollection.model.prototype.getTags).toBeUndefined();
});
it('should not throw error when create empty collection in sqlite and mysql', async () => { it('should not throw error when create empty collection in sqlite and mysql', async () => {
if (!db.inDialect('sqlite', 'mysql')) { if (!db.inDialect('sqlite', 'mysql')) {
return; return;

View File

@ -217,6 +217,7 @@ export abstract class Field {
bind() { bind() {
const { model } = this.context.collection; const { model } = this.context.collection;
model.rawAttributes[this.name] = this.toSequelize(); model.rawAttributes[this.name] = this.toSequelize();
// @ts-ignore // @ts-ignore
model.refreshAttributes(); model.refreshAttributes();
if (this.options.index) { if (this.options.index) {
@ -226,6 +227,9 @@ export abstract class Field {
unbind() { unbind() {
const { model } = this.context.collection; const { model } = this.context.collection;
delete model.prototype[this.name];
model.removeAttribute(this.name); model.removeAttribute(this.name);
if (this.options.index || this.options.unique) { if (this.options.index || this.options.unique) {
this.context.collection.removeIndex([this.name]); this.context.collection.removeIndex([this.name]);

View File

@ -2,6 +2,95 @@ import Database, { Collection as DBCollection, StringFieldOptions } from '@nocob
import Application from '@nocobase/server'; import Application from '@nocobase/server';
import { createApp } from '.'; import { createApp } from '.';
describe('recreate field', () => {
let db: Database;
let app: Application;
let Collection: DBCollection;
let Field: DBCollection;
beforeEach(async () => {
app = await createApp();
db = app.db;
Collection = db.getCollection('collections');
Field = db.getCollection('fields');
});
afterEach(async () => {
await app.destroy();
});
it('should recreate field', async () => {
await Collection.repository.create({
values: {
name: 'a1',
},
context: {},
});
await Collection.repository.create({
values: {
name: 'a2',
},
context: {},
});
await Field.repository.create({
values: {
name: 'a',
type: 'string',
collectionName: 'a1',
},
context: {},
});
await db.getRepository('a1').create({
values: {
a: 'a',
},
});
await Field.repository.destroy({
filter: {
name: 'a',
collectionName: 'a1',
},
context: {},
});
await Field.repository.create({
values: {
name: 'a',
type: 'hasOne',
collectionName: 'a1',
target: 'a2',
foreignKey: 'a_id',
},
context: {},
});
const a1Model = db.getRepository('a1').model;
const results = await a1Model.findAll({
include: [
{
association: 'a',
},
],
});
expect(Object.getOwnPropertyNames(db.getCollection('a1').model.prototype)).toContain('getA');
await Field.repository.destroy({
filter: {
name: 'a',
collectionName: 'a1',
},
});
expect(Object.getOwnPropertyNames(db.getCollection('a1').model.prototype)).not.toContain('getA');
expect(Object.getOwnPropertyNames(db.getCollection('a1').model.prototype)).not.toContain('a');
});
});
describe('collections repository', () => { describe('collections repository', () => {
let db: Database; let db: Database;
let app: Application; let app: Application;

View File

@ -0,0 +1,66 @@
import { MockServer } from '@nocobase/test';
import { createApp } from '../index';
describe('recreate field', () => {
let app: MockServer;
let agent;
beforeEach(async () => {
app = await createApp();
agent = app.agent();
});
afterEach(async () => {
await app.destroy();
});
it('should recreate field', async () => {
await agent.resource('collections').create({
values: {
name: 'a1',
},
});
await agent.resource('collections').create({
values: {
name: 'a2',
},
});
await agent.resource('fields').create({
values: {
name: 'a',
type: 'string',
collectionName: 'a1',
},
});
await agent.resource('a1').create({
values: {
a: 'a-value',
},
});
await agent.resource('fields').destroy({
filter: {
name: 'a',
collectionName: 'a1',
},
});
await agent.resource('fields').create({
values: {
name: 'a',
type: 'belongsToMany',
collectionName: 'a1',
target: 'a2',
},
});
const response = await agent.resource('a1').list({
appends: ['a'],
});
expect(response.statusCode).toBe(200);
});
});