ChengLei Shao e991b2965a
feat: collection inheritance (#1069)
* chore: test

* chore: inherited-collection class

* feat: collection inherit

* feat: collection inherit

* feat: inhertis sync runner

* test: get parents fields

* feat: collection inherit style promote

* feat: sync

* feat: sync alter table

* feat: pgOnly Test

* fix: child collection create api

* feat: replace parent field

* chore: reload parent fields

* test: reload collection test

* feat: details are displayed according to conditions

* fix: typo

* feat: inheritance map class

* chore: is parent node

* feat: display where child row created from

* fix: find with appends

* feat: add parent collection fields

* fix: create table

* feat: load fields for all children

* refactor: sync fields from parent

* test: has one field inhertis

* feat: replace child association target

* feat: should not replace child field when parent field update

* test: should update inherit field when parent field update

* feat: only the blocks directly inherited from the current data are displayed

* fix: inherit from multiple collections

* feat: only the blocks directly inherited from the current data are displayed

* fix: test

* feat: parent collection expend

* fix: test

* test: belongsToMany inherits

* test: belongsToMany inherits

* feat: block display

* feat: collection inherite

* feat: collection inherite

* feat: multiple inherits

* fix: sync runner

* feat: collection inherite

* feat: collecton inherits

* feat: cannot be modified after inheritance and saving

* feat: collection inherit for graph

* feat: collection inherits

* fix: drop inhertied field

* fix: should throw error when type conflit

* feat: output inherited fields

* feat: bulk update collection fields

* feat: collection fields

* feat: collection fields

* test: create relation with child table

* fix: test

* fix: test

* fix: test

* feat: style impove

* test: should not replace field with difference type

* feat: add text

* fix: throw error when replace field with difference type

* feat: overriding

* feat: kan bankanban group fields

* feat: calendar block fields

* feat: kan bankanban group fields

* fix: test

* feat: relationship fields

* feat: should delete child's field when parent field deleted

* feat: foreign key filter

* fix: build error & multiple inherit destory field

* fix: test

* chore: disable error

* feat: no recursive update associations (#1091)

* feat: update associations

* fix(collection-manager): should update uiSchema

* chore: flip if

* feat: mutile inherits

* feat: db dialect

* feat: inherits show by database

* chore: git hash into docker image

* fix: js gzip

* fix: dockerfile

* chore: error message

* feat: overriding

* feat: overriding

* feat: overriding

* feat: local

* feat: filter fields by interface

* fix: database logging env

* test: replace hasOne target

* feat: add view

* feat: local

* chore: enable error

* fix: update docs

Co-authored-by: katherinehhh <katherine_15995@163.com>
Co-authored-by: chenos <chenlinxh@gmail.com>
2022-11-16 12:53:58 +08:00

282 lines
6.2 KiB
TypeScript

import { MockServer, pgOnly } from '@nocobase/test';
import { createApp } from '..';
pgOnly()('Inherited Collection', () => {
let app: MockServer;
let agent;
beforeEach(async () => {
app = await createApp();
agent = app.agent();
await agent.resource('collections').create({
values: {
name: 'person',
fields: [
{
name: 'name',
type: 'string',
},
],
},
});
});
afterEach(async () => {
await app.destroy();
});
it('should not replace field with difference type when add field', async () => {
let response = await agent.resource('collections').create({
values: {
name: 'students',
inherits: 'person',
fields: [],
},
});
expect(response.statusCode).toBe(200);
response = await agent.resource('fields').create({
values: {
collectionName: 'students',
name: 'name',
type: 'integer',
},
});
expect(response.statusCode).not.toBe(200);
});
it('should not replace field with difference type when create collection', async () => {
const response = await agent.resource('collections').create({
context: {},
values: {
name: 'students',
inherits: ['person'],
fields: [
{
name: 'name',
type: 'integer',
},
],
},
});
expect(response.statusCode).toBe(500);
});
it('can create relation with child table', async () => {
await agent.resource('collections').create({
values: {
name: 'a',
fields: [
{
name: 'af',
type: 'string',
},
{
name: 'bs',
type: 'hasMany',
target: 'b',
},
],
},
});
await agent.resource('collections').create({
values: {
name: 'b',
inherits: ['a'],
fields: [
{
name: 'bf',
type: 'string',
},
{
name: 'a',
type: 'belongsTo',
target: 'a',
},
],
},
});
const res = await agent.resource('b').create({
values: {
af: 'a1',
bs: [{ bf: 'b1' }, { bf: 'b2' }],
},
});
expect(res.statusCode).toEqual(200);
const a1 = await agent.resource('b').list({
filter: {
af: 'a1',
},
appends: 'bs',
});
expect(a1.body.data[0].bs.length).toEqual(2);
});
it('can drop child replaced field', async () => {
await agent.resource('collections').create({
values: {
name: 'students',
inherits: 'person',
fields: [
{
name: 'name',
type: 'string',
},
],
},
});
const response = await agent.resource('collections.fields', 'students').destroy({
filter: {
name: 'name',
},
});
expect(response.status).toBe(200);
});
it('should reload collection when parent fields change', async () => {
await agent.resource('collections').create({
values: {
name: 'employee',
inherits: 'person',
fields: [
{
name: 'salary',
type: 'integer',
},
],
},
});
await agent.resource('collections').create({
values: {
name: 'instructor',
inherits: 'employee',
fields: [
{
name: 'rank',
type: 'integer',
},
],
},
});
const createInstructorResponse = await agent.resource('instructor').create({
values: {
name: 'foo',
salary: 1000,
rank: 100,
},
});
expect(createInstructorResponse.statusCode).toBe(200);
const employeeCollection = app.db.getCollection('employee');
expect(employeeCollection.fields.get('new-field')).not.toBeDefined();
// add new field to root collection
await agent.resource('fields').create({
values: {
collectionName: 'person',
name: 'age',
type: 'integer',
},
});
expect(employeeCollection.fields.get('age')).toBeDefined();
let listResponse = await agent.resource('employee').list();
expect(listResponse.statusCode).toBe(200);
expect(listResponse.body.data[0].age).toBeDefined();
listResponse = await agent.resource('instructor').list();
expect(listResponse.statusCode).toBe(200);
expect(listResponse.body.data[0].age).toBeDefined();
});
it('should create inherited collection', async () => {
const response = await agent.resource('collections').create({
values: {
name: 'students',
inherits: 'person',
fields: [
{
name: 'score',
type: 'integer',
},
],
},
});
expect(response.statusCode).toBe(200);
const studentCollection = app.db.getCollection('students');
expect(studentCollection).toBeDefined();
const studentFieldsResponse = await agent.resource('fields').list({
filter: {
collectionName: 'students',
},
});
expect(studentFieldsResponse.statusCode).toBe(200);
const studentFields = studentFieldsResponse.body.data;
expect(studentFields.length).toBe(1);
const createStudentResponse = await agent.resource('students').create({
values: {
name: 'foo',
score: 100,
},
});
expect(createStudentResponse.statusCode).toBe(200);
const fooStudent = createStudentResponse.body.data;
expect(fooStudent.name).toBe('foo');
const studentList = await agent.resource('students').list();
expect(studentList.statusCode).toBe(200);
});
it('should know which child table row it is', async () => {
await agent.resource('collections').create({
values: {
name: 'students',
inherits: 'person',
fields: [
{
name: 'score',
type: 'integer',
},
],
},
});
await agent.resource('students').create({
values: {
name: 'foo',
score: 100,
},
});
const personList = await agent.resource('person').list();
const person = personList.body.data[0];
expect(person['__collection']).toBe('students');
});
});