fix Collection rest api (#205)

* test: collections rest api

* test: add more test cases

* fix: test case

* fix: Error: src/schema-component/antd/array-table/TableRecordActionDesigner.tsx(3,38): error TS2307: Cannot find module '@nocobase/client' or its corresponding type declarations.

* fix: belongsToMany create with empty value

* fix: relation query  test

* test: appends + sort

* fix: belongsToMany find error

* fix: add cleanDb to fix database test

* fix: mysql test

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
ChengLei Shao 2022-02-22 23:38:13 +08:00 committed by GitHub
parent 2caec7a271
commit 9dd590c459
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 524 additions and 13 deletions

View File

@ -7,8 +7,11 @@ describe('belongs to many with target key', function () {
let db: Database;
let Tag: Collection;
let Post: Collection;
let Color: Collection;
beforeEach(async () => {
db = mockDatabase();
Post = db.collection({
name: 'posts',
filterTargetKey: 'title',
@ -114,6 +117,7 @@ describe('belongs to many', () => {
let Post;
let Tag;
let PostTag;
let Color;
beforeEach(async () => {
db = mockDatabase();
@ -154,6 +158,15 @@ describe('belongs to many', () => {
{ type: 'belongsToMany', name: 'posts', through: 'posts_tags' },
{ type: 'string', name: 'name' },
{ type: 'string', name: 'status' },
{ type: 'hasMany', name: 'colors' },
],
});
Color = db.collection({
name: 'colors',
fields: [
{ type: 'string', name: 'name' },
{ type: 'belongsTo', name: 'tag' },
],
});
@ -269,6 +282,35 @@ describe('belongs to many', () => {
expect(t1).toBeNull();
});
test('find with sort & appends', async () => {
const p1 = await Post.repository.create({
values: {
title: 'p1',
tags: [
{
name: 't1',
colors: [
{
name: 'red',
},
],
},
{ name: 't2', colors: [{ name: 'green' }] },
],
},
});
const PostTagsRepository = new BelongsToManyRepository(Post, 'tags', p1.id);
const tags = await PostTagsRepository.find({
appends: ['colors'],
sort: ['name'],
limit: 20,
offset: 0,
});
console.log(tags);
});
test('update raw attribute', async () => {
const otherTag = await Tag.repository.create({
values: { name: 'other_tag' },

View File

@ -33,7 +33,8 @@ export class BelongsToManyRepository extends MultipleRelationRepository implemen
const transaction = await this.getTransaction(options);
const createAccessor = this.accessors().create;
const values = options.values;
const values = options.values || {};
const sourceModel = await this.getSourceModel(transaction);

View File

@ -32,11 +32,14 @@ export abstract class MultipleRelationRepository extends RelationRepository {
async find(options?: FindOptions): Promise<any> {
const transaction = await this.getTransaction(options);
const findOptions = this.extendFindOptions(
this.buildQueryOptions({
...options,
}),
);
const findOptions = {
...this.extendFindOptions(
this.buildQueryOptions({
...options,
}),
),
subQuery: false,
};
const getAccessor = this.accessors().get;
const sourceModel = await this.getSourceModel(transaction);
@ -44,7 +47,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
if (findOptions.include && findOptions.include.length > 0) {
const ids = (
await sourceModel[getAccessor]({
...omit(findOptions, 'order'),
...findOptions,
includeIgnoreAttributes: false,
attributes: [this.targetKey()],
group: `${this.targetModel.name}.${this.targetKey()}`,

View File

@ -1,10 +1,8 @@
import { flatten } from 'flat';
import lodash, { keys } from 'lodash';
import { Collection } from './collection';
import { BelongsTo, HasOne, Model, ModelCtor } from 'sequelize';
import lodash from 'lodash';
import { Model, ModelCtor } from 'sequelize';
import { AssociationKeysToBeUpdate, BlackList, WhiteList } from './repository';
type UpdateValueItem = string | number | UpdateValues;
type UpdateValues = {
@ -130,7 +128,7 @@ export class UpdateGuard {
return values;
}
let valuesKeys = Object.keys(values);
let valuesKeys = Object.keys(values || {});
// handle whitelist
if (this.whiteList) {

View File

@ -19,6 +19,8 @@ export async function prepareApp() {
registerActions: true,
});
await app.cleanDb();
app.plugin(PluginUiSchema);
app.plugin(PluginCollectionManager);

View File

@ -0,0 +1,462 @@
import { MockServer } from '@nocobase/test';
import { createApp } from '..';
describe('collections repository', () => {
let app: MockServer;
beforeEach(async () => {
app = await createApp();
await app.install({ clean: true });
await app.start();
await app
.agent()
.resource('collections')
.create({
values: {
name: 'tags',
fields: [
{
name: 'title',
type: 'string',
},
],
},
});
await app
.agent()
.resource('collections')
.create({
values: {
name: 'foos',
fields: [
{
name: 'title',
type: 'string',
},
],
},
});
await app
.agent()
.resource('collections.fields', 'tags')
.create({
values: {
name: 'foos',
target: 'foos',
type: 'belongsToMany',
},
});
await app
.agent()
.resource('collections')
.create({
values: {
name: 'comments',
fields: [
{
name: 'title',
type: 'string',
},
],
},
});
await app
.agent()
.resource('collections')
.create({
values: {
name: 'posts',
fields: [
{
name: 'title',
type: 'string',
},
{
name: 'comments',
target: 'comments',
type: 'hasMany',
},
{
name: 'tags',
target: 'tags',
type: 'belongsToMany',
},
],
},
});
});
afterEach(async () => {
await app.destroy();
});
it('case 1', async () => {
const response1 = await app.agent().resource('posts').create();
const postId = response1.body.data.id;
const response2 = await app.agent().resource('posts.comments', postId).create();
expect(response2.statusCode).toBe(200);
});
it('case 2', async () => {
const response = await app.agent().resource('posts').create();
const postId = response.body.data.id;
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 1',
},
});
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 2',
},
});
const response2 = await app
.agent()
.resource('posts')
.list({
filter: {
'comments.title': 'comment 1',
},
});
expect(response2.body.data[0].id).toBe(1);
});
it('case 3', async () => {
const response = await app.agent().resource('posts').create();
const postId = response.body.data.id;
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 1',
},
});
const response2 = await app
.agent()
.resource('posts')
.list({
filter: {
'comments.id': 3,
},
});
expect(response2.body.data.length).toBe(0);
});
it('case 4', async () => {
const response = await app.agent().resource('posts').create();
const postId = response.body.data.id;
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 1',
},
});
const response2 = await app
.agent()
.resource('posts')
.list({
filter: {
$and: [
{
'comments.title': 'comment 1',
},
],
},
});
expect(response2.body.data[0].id).toBe(1);
});
it('case 5', async () => {
const response = await app.agent().resource('posts').create();
const postId = response.body.data.id;
await app.agent().resource('posts.tags', postId).create({
values: {},
});
expect(await app.db.getRepository('tags').count()).toEqual(1);
});
it('case 6', async () => {
const response = await app
.agent()
.resource('posts')
.create({
values: {
tags: [
{},
{
title: 'Tag1',
},
],
},
});
const postId = response.body.data.id;
const response1 = await app.agent().resource('posts.tags', postId).list();
expect(response1.body.data.length).toBe(2);
});
it('case 7', async () => {
const response = await app
.agent()
.resource('posts')
.create({
values: {
tags: [
{},
{
title: 'Tag1',
},
],
},
});
const postId = response.body.data.id;
const response1 = await app
.agent()
.resource('posts.tags', postId)
.list({
filter: {
title: 'Tag1',
},
});
expect(response1.body.data.length).toBe(1);
});
it('case 8', async () => {
const response = await app
.agent()
.resource('posts')
.create({
values: {
tags: [
{},
{
title: 'Tag1',
},
{
title: 'Tag2',
},
],
},
});
const postId = response.body.data.id;
const response1 = await app
.agent()
.resource('posts.tags', postId)
.list({
filter: {
$or: [{ title: 'Tag1' }, { title: 'Tag2' }],
},
});
expect(response1.body.data.length).toBe(2);
});
it('case 9', async () => {
const response = await app
.agent()
.resource('posts')
.create({
values: {
tags: [
{},
{
title: 'Tag1',
},
{
title: 'Tag2',
},
],
},
});
const postId = response.body.data.id;
const response1 = await app
.agent()
.resource('posts.tags', postId)
.list({
filter: {
$or: [{ title: 'Tag1' }, { title: 'Tag2' }],
},
});
expect(response1.body.data.length).toBe(2);
});
it('case 10', async () => {
const response = await app
.agent()
.resource('posts')
.create({
values: {
tags: [
{},
{
title: 'Tag1',
},
{
title: 'Tag2',
},
],
},
});
const postId = response.body.data.id;
const response1 = await app
.agent()
.resource('posts.tags', postId)
.list({
appends: ['foos'],
page: 1,
pageSize: 20,
sort: ['-createdAt', '-id'],
});
expect(response1.body.data[0]['id']).toEqual(3);
});
it('case 11', async () => {
const response = await app.agent().resource('posts').create();
const postId = response.body.data.id;
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 1',
},
});
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 2',
},
});
const response2 = await app.agent().resource('posts').create();
const postId2 = response2.body.data.id;
await app
.agent()
.resource('posts.comments', postId2)
.create({
values: {
title: 'comment 2',
},
});
await app
.agent()
.resource('posts.comments', postId2)
.create({
values: {
title: 'comment 2',
},
});
const response3 = await app
.agent()
.resource('posts')
.list({
filter: {
$or: [
{
'comments.title': 'comment 1',
},
{
'comments.title': 'comment 2',
},
],
},
});
expect(response3.body.data.length).toBe(2);
});
it('case 12', async () => {
const response = await app.agent().resource('posts').create();
const postId = response.body.data.id;
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 1',
},
});
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 2',
},
});
await app
.agent()
.resource('posts.comments', postId)
.create({
values: {
title: 'comment 3',
},
});
const response2 = await app
.agent()
.resource('posts.comments', postId)
.list({
filter: {
$or: [
{
title: 'comment 1',
},
{
title: 'comment 2',
},
],
},
});
expect(response2.body.data.length).toBe(2);
});
it('case 13', async () => {
const tagRepository = app.db.getRepository('tags');
const tag1 = await tagRepository.create({ values: { title: 'tag1' } });
const tag2 = await tagRepository.create({ values: { title: 'tag2' } });
const tag3 = await tagRepository.create({ values: { title: 'tag3' } });
await app
.agent()
.resource('posts')
.create({
values: {
tags: [tag1.get('id'), tag3.get('id')],
},
});
await app
.agent()
.resource('posts')
.create({
values: {
tags: [tag2.get('id')],
},
});
await app
.agent()
.resource('posts')
.create({
values: {
tags: [tag2.get('id'), tag3.get('id')],
},
});
const response1 = await app
.agent()
.resource('posts')
.list({
filter: {
$or: [{ 'tags.title': 'tag1' }, { 'tags.title': 'tag3' }],
},
});
expect(response1.body.data.length).toBe(2);
});
});

View File

@ -3,6 +3,7 @@ import CollectionManagerPlugin from '..';
export async function createApp() {
const app = mockServer();
await app.cleanDb();
app.plugin(CollectionManagerPlugin);
await app.load();
return app;

View File

@ -19,6 +19,7 @@ describe('server hooks', () => {
registerActions: true,
});
await app.cleanDb();
db = app.db;
app.plugin(UiSchemaStoragePlugin);

View File

@ -58,6 +58,7 @@ describe('server hooks', () => {
registerActions: true,
});
await app.cleanDb();
db = app.db;
app.plugin(UiSchemaStoragePlugin);