fix: sort by association collection (#3058)
* fix: sort by association collection * fix: test * chore: test * chore: create sortfield if hasmany sortable set true * fix: drag sort * chore: update sort by options * chore: sync collection after update sortBy * chore: test * chore: test * chore: test * fix: sort by * fix: model.syncSortByField * fix: hasmany only * fix: sortBy --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
635dcfdbd5
commit
0acd7b6dd3
@ -1,9 +1,157 @@
|
|||||||
import { mockServer, MockServer } from './index';
|
import { mockServer, MockServer } from './index';
|
||||||
import { registerActions } from '@nocobase/actions';
|
import { registerActions } from '@nocobase/actions';
|
||||||
import { Database } from '@nocobase/database';
|
import { Collection, Database } from '@nocobase/database';
|
||||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
import { waitSecond } from '@nocobase/test';
|
||||||
|
|
||||||
describe('sort action', () => {
|
describe('sort action', () => {
|
||||||
|
describe('associations', () => {
|
||||||
|
let api: MockServer;
|
||||||
|
|
||||||
|
let UserCollection: Collection;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
api = mockServer();
|
||||||
|
|
||||||
|
registerActions(api);
|
||||||
|
|
||||||
|
UserCollection = api.db.collection({
|
||||||
|
name: 'users',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'name' },
|
||||||
|
{
|
||||||
|
type: 'hasMany',
|
||||||
|
name: 'posts',
|
||||||
|
},
|
||||||
|
|
||||||
|
{ type: 'sort', name: 'sort' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
api.db.collection({
|
||||||
|
name: 'posts',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'title' },
|
||||||
|
{ type: 'sort', name: 'sort' },
|
||||||
|
{ type: 'belongsTo', name: 'user' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.db.sync();
|
||||||
|
|
||||||
|
for (let index = 1; index < 5; index++) {
|
||||||
|
await UserCollection.repository.create({
|
||||||
|
values: {
|
||||||
|
name: `u${index}`,
|
||||||
|
posts: [
|
||||||
|
{
|
||||||
|
title: `u${index}p1`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `u${index}p2`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `u${index}p3`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
return api.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not move association items when association not sortable', async () => {
|
||||||
|
const u1 = await api.db.getRepository('users').findOne({
|
||||||
|
filter: {
|
||||||
|
name: 'u1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await api.agent().resource('users.posts', u1.get('id')).move({
|
||||||
|
sourceId: 1,
|
||||||
|
targetId: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).not.toEqual(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move association item', async () => {
|
||||||
|
UserCollection.setField('posts', {
|
||||||
|
sortable: true,
|
||||||
|
type: 'hasMany',
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.db.sync({
|
||||||
|
alter: {
|
||||||
|
drop: false,
|
||||||
|
},
|
||||||
|
force: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const PostCollection = api.db.getCollection('posts');
|
||||||
|
|
||||||
|
const sortFieldName = `${UserCollection.model.associations.posts.foreignKey}Sort`;
|
||||||
|
expect(PostCollection.fields.get(sortFieldName)).toBeDefined();
|
||||||
|
|
||||||
|
const u1 = await api.db.getRepository('users').findOne({
|
||||||
|
filter: {
|
||||||
|
name: 'u1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await api
|
||||||
|
.agent()
|
||||||
|
.resource('users.posts', u1.get('id'))
|
||||||
|
.create({
|
||||||
|
values: {
|
||||||
|
title: 'u1p4',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const u1p4 = await api.db.getRepository('posts').findOne({
|
||||||
|
filter: {
|
||||||
|
title: 'u1p4',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// should move by association sort field
|
||||||
|
await api
|
||||||
|
.agent()
|
||||||
|
.resource('users.posts', u1.get('id'))
|
||||||
|
.move({
|
||||||
|
sourceId: 1,
|
||||||
|
targetId: u1p4.get('id'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const u1Posts = await api
|
||||||
|
.agent()
|
||||||
|
.resource('users.posts', u1.get('id'))
|
||||||
|
.list({
|
||||||
|
fields: ['title'],
|
||||||
|
sort: [sortFieldName],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(u1Posts.body).toMatchObject({
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
title: 'u1p2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'u1p3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'u1p4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'u1p1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('same scope', () => {
|
describe('same scope', () => {
|
||||||
let api: MockServer;
|
let api: MockServer;
|
||||||
|
|
||||||
@ -250,7 +398,7 @@ describe('sort action', () => {
|
|||||||
|
|
||||||
const beforeUpdatedAts = await getUpdatedAts();
|
const beforeUpdatedAts = await getUpdatedAts();
|
||||||
|
|
||||||
await sleep(1000);
|
await waitSecond(1000);
|
||||||
|
|
||||||
await api.agent().resource('tests').move({
|
await api.agent().resource('tests').move({
|
||||||
sourceId: moveItemId,
|
sourceId: moveItemId,
|
||||||
@ -301,7 +449,7 @@ describe('sort action', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const beforeUpdated = t1.get('updatedAt');
|
const beforeUpdated = t1.get('updatedAt');
|
||||||
await sleep(1000);
|
await waitSecond(1000);
|
||||||
|
|
||||||
await api
|
await api
|
||||||
.agent()
|
.agent()
|
||||||
|
@ -20,6 +20,7 @@ function findArgs(ctx: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { tree, fields, filter, appends, except, sort } = params;
|
const { tree, fields, filter, appends, except, sort } = params;
|
||||||
|
|
||||||
return { tree, filter, fields, appends, except, sort };
|
return { tree, filter, fields, appends, except, sort };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import { Op, Model } from 'sequelize';
|
import { Model, Op } from 'sequelize';
|
||||||
|
|
||||||
import { Context } from '..';
|
import { Context } from '..';
|
||||||
import { Collection, TargetKey, Repository, SortField } from '@nocobase/database';
|
import {
|
||||||
|
BelongsToManyRepository,
|
||||||
|
Collection,
|
||||||
|
HasManyRepository,
|
||||||
|
Repository,
|
||||||
|
SortField,
|
||||||
|
TargetKey,
|
||||||
|
} from '@nocobase/database';
|
||||||
import { getRepositoryFromParams } from '../utils';
|
import { getRepositoryFromParams } from '../utils';
|
||||||
|
|
||||||
export async function move(ctx: Context, next) {
|
export async function move(ctx: Context, next) {
|
||||||
@ -9,24 +16,39 @@ export async function move(ctx: Context, next) {
|
|||||||
|
|
||||||
const { sourceId, targetId, sortField, targetScope, sticky, method } = ctx.action.params;
|
const { sourceId, targetId, sortField, targetScope, sticky, method } = ctx.action.params;
|
||||||
|
|
||||||
if (repository instanceof Repository) {
|
if (repository instanceof BelongsToManyRepository) {
|
||||||
const sortAbleCollection = new SortAbleCollection(repository.collection, sortField);
|
throw new Error("Sorting association as 'belongs-to-many' type is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
if (sourceId && targetId) {
|
if (repository instanceof HasManyRepository) {
|
||||||
await sortAbleCollection.move(sourceId, targetId, {
|
const hasManyField = repository.sourceCollection.getField(repository.associationName);
|
||||||
insertAfter: method === 'insertAfter',
|
if (!hasManyField.options.sortable) {
|
||||||
});
|
throw new Error(
|
||||||
}
|
`association ${hasManyField.options.name} in ${repository.sourceCollection.name} is not sortable`,
|
||||||
|
);
|
||||||
// change scope
|
|
||||||
if (sourceId && targetScope) {
|
|
||||||
await sortAbleCollection.changeScope(sourceId, targetScope, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceId && sticky) {
|
|
||||||
await sortAbleCollection.sticky(sourceId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sortAbleCollection = new SortAbleCollection(
|
||||||
|
repository instanceof Repository ? repository.collection : repository.targetCollection,
|
||||||
|
repository instanceof Repository ? sortField : `${repository.association.foreignKey}Sort`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sourceId && targetId) {
|
||||||
|
await sortAbleCollection.move(sourceId, targetId, {
|
||||||
|
insertAfter: method === 'insertAfter',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// change scope
|
||||||
|
if (sourceId && targetScope) {
|
||||||
|
await sortAbleCollection.changeScope(sourceId, targetScope, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceId && sticky) {
|
||||||
|
await sortAbleCollection.sticky(sourceId);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.body = 'ok';
|
ctx.body = 'ok';
|
||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
@ -81,9 +81,9 @@ export const TableBlockProvider = (props) => {
|
|||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
|
|
||||||
const collection = getCollection(props.collection);
|
const collection = getCollection(props.collection);
|
||||||
const { treeTable } = fieldSchema?.['x-decorator-props'] || {};
|
const { treeTable, dragSortBy } = fieldSchema?.['x-decorator-props'] || {};
|
||||||
if (props.dragSort) {
|
if (props.dragSort) {
|
||||||
params['sort'] = ['sort'];
|
params['sort'] = dragSortBy || ['sort'];
|
||||||
}
|
}
|
||||||
let childrenColumnName = 'children';
|
let childrenColumnName = 'children';
|
||||||
if (collection?.tree && treeTable !== false) {
|
if (collection?.tree && treeTable !== false) {
|
||||||
|
@ -2,6 +2,7 @@ import { ArrayItems } from '@formily/antd-v5';
|
|||||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAPIClient } from '../../../api-client';
|
||||||
import { useFormBlockContext, useTableBlockContext } from '../../../block-provider';
|
import { useFormBlockContext, useTableBlockContext } from '../../../block-provider';
|
||||||
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
||||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
@ -66,6 +67,7 @@ export const TableBlockDesigner = () => {
|
|||||||
},
|
},
|
||||||
[dn, field.decoratorProps, fieldSchema, service],
|
[dn, field.decoratorProps, fieldSchema, service],
|
||||||
);
|
);
|
||||||
|
const api = useAPIClient();
|
||||||
return (
|
return (
|
||||||
// fix https://nocobase.height.app/T-2259
|
// fix https://nocobase.height.app/T-2259
|
||||||
<RecordProvider parent={record} record={{}}>
|
<RecordProvider parent={record} record={{}}>
|
||||||
@ -95,10 +97,20 @@ export const TableBlockDesigner = () => {
|
|||||||
<SchemaSettings.SwitchItem
|
<SchemaSettings.SwitchItem
|
||||||
title={t('Enable drag and drop sorting')}
|
title={t('Enable drag and drop sorting')}
|
||||||
checked={field.decoratorProps.dragSort}
|
checked={field.decoratorProps.dragSort}
|
||||||
onChange={(dragSort) => {
|
onChange={async (dragSort) => {
|
||||||
|
if (dragSort && collectionField) {
|
||||||
|
const { data } = await api.resource('collections.fields', collectionField.collectionName).update({
|
||||||
|
filterByTk: collectionField.name,
|
||||||
|
values: {
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const sortBy = data?.data?.[0]?.sortBy;
|
||||||
|
fieldSchema['x-decorator-props'].dragSortBy = sortBy;
|
||||||
|
}
|
||||||
field.decoratorProps.dragSort = dragSort;
|
field.decoratorProps.dragSort = dragSort;
|
||||||
fieldSchema['x-decorator-props'].dragSort = dragSort;
|
fieldSchema['x-decorator-props'].dragSort = dragSort;
|
||||||
service.run({ ...service.params?.[0], sort: 'sort' });
|
service.run({ ...service.params?.[0], sort: fieldSchema['x-decorator-props'].dragSortBy });
|
||||||
dn.emit('patch', {
|
dn.emit('patch', {
|
||||||
schema: {
|
schema: {
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
@ -150,6 +150,20 @@ export class HasManyField extends RelationField {
|
|||||||
|
|
||||||
this.database.referenceMap.addReference(this.reference(association));
|
this.database.referenceMap.addReference(this.reference(association));
|
||||||
|
|
||||||
|
// add sort field if association is sortable
|
||||||
|
if (this.options.sortable) {
|
||||||
|
const targetCollection = database.modelCollection.get(this.TargetModel);
|
||||||
|
const sortFieldName = `${this.options.foreignKey}Sort`;
|
||||||
|
|
||||||
|
targetCollection.setField(sortFieldName, {
|
||||||
|
type: 'sort',
|
||||||
|
hidden: true,
|
||||||
|
scopeKey: this.options.foreignKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.options.sortBy = sortFieldName;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,12 +82,13 @@ export class SortField extends Field {
|
|||||||
const queryInterface = this.collection.db.sequelize.getQueryInterface();
|
const queryInterface = this.collection.db.sequelize.getQueryInterface();
|
||||||
|
|
||||||
if (scopeKey) {
|
if (scopeKey) {
|
||||||
const scopeField = this.collection.getField(scopeKey);
|
const scopeAttribute = this.collection.model.rawAttributes[scopeKey];
|
||||||
if (!scopeField) {
|
|
||||||
|
if (!scopeAttribute) {
|
||||||
throw new Error(`can not find scope field ${scopeKey} for collection ${this.collection.name}`);
|
throw new Error(`can not find scope field ${scopeKey} for collection ${this.collection.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
scopeKey = this.collection.model.rawAttributes[scopeKey].field;
|
scopeKey = scopeAttribute.field;
|
||||||
}
|
}
|
||||||
|
|
||||||
const quotedOrderField = queryInterface.quoteIdentifier(orderField);
|
const quotedOrderField = queryInterface.quoteIdentifier(orderField);
|
||||||
|
@ -20,6 +20,24 @@ describe('collections repository', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create collection with sortable option', async () => {
|
||||||
|
await Collection.repository.create({
|
||||||
|
values: {
|
||||||
|
name: 'posts',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'title',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(db.getCollection('posts').getField('sort')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create through table when pending fields', async () => {
|
it('should create through table when pending fields', async () => {
|
||||||
await Collection.repository.create({
|
await Collection.repository.create({
|
||||||
values: {
|
values: {
|
||||||
|
@ -17,11 +17,14 @@ describe('hasMany field options', () => {
|
|||||||
values: {
|
values: {
|
||||||
name: 'tests',
|
name: 'tests',
|
||||||
},
|
},
|
||||||
|
context: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
await Collection.repository.create({
|
await Collection.repository.create({
|
||||||
values: {
|
values: {
|
||||||
name: 'foos',
|
name: 'foos',
|
||||||
},
|
},
|
||||||
|
context: {},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -29,6 +32,56 @@ describe('hasMany field options', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create fields with sortable option', async () => {
|
||||||
|
const field = await Field.repository.create({
|
||||||
|
values: {
|
||||||
|
type: 'hasMany',
|
||||||
|
collectionName: 'tests',
|
||||||
|
target: 'foos',
|
||||||
|
sortable: true,
|
||||||
|
foreignKey: 'test_id',
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await field.reload();
|
||||||
|
expect(field.get('sortable')).toBe(true);
|
||||||
|
expect(field.get('sortBy')).toBe('test_idSort');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update field with sortable option', async () => {
|
||||||
|
const field = await Field.repository.create({
|
||||||
|
values: {
|
||||||
|
type: 'hasMany',
|
||||||
|
collectionName: 'tests',
|
||||||
|
target: 'foos',
|
||||||
|
foreignKey: 'test_id',
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await field.reload();
|
||||||
|
|
||||||
|
expect(field.get('sortBy')).toBe(undefined);
|
||||||
|
|
||||||
|
await Field.repository.update({
|
||||||
|
values: {
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
key: field.get('key'),
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await field.reload();
|
||||||
|
|
||||||
|
expect(field.get('sortBy')).toBe('test_idSort');
|
||||||
|
const collection = db.getCollection('foos');
|
||||||
|
const columns = await db.sequelize.getQueryInterface().describeTable(collection.getTableNameWithSchema());
|
||||||
|
expect(columns).toHaveProperty(collection.model.rawAttributes['test_idSort'].field);
|
||||||
|
});
|
||||||
|
|
||||||
it('should generate the foreignKey randomly', async () => {
|
it('should generate the foreignKey randomly', async () => {
|
||||||
const field = await Field.repository.create({
|
const field = await Field.repository.create({
|
||||||
values: {
|
values: {
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
import { MockServer } from '@nocobase/test';
|
||||||
|
import { createApp } from '../index';
|
||||||
|
|
||||||
|
describe('collections repository', () => {
|
||||||
|
let app: MockServer;
|
||||||
|
let agent;
|
||||||
|
let db;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await createApp();
|
||||||
|
db = app.db;
|
||||||
|
|
||||||
|
agent = app.agent();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update belongs to many field sortable option', async () => {
|
||||||
|
await agent.resource('collections').create({
|
||||||
|
values: {
|
||||||
|
name: 'users',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'hasMany',
|
||||||
|
name: 'posts',
|
||||||
|
target: 'posts',
|
||||||
|
foreignKey: 'userId',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await agent.resource('collections').create({
|
||||||
|
values: {
|
||||||
|
name: 'posts',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const postField = await db.getRepository('fields').findOne({
|
||||||
|
filter: {
|
||||||
|
name: 'posts',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// update has many field
|
||||||
|
const response = await agent.resource('collections.fields', 'users').update({
|
||||||
|
values: {
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
key: postField.get('key'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.body.data[0].sortable).toBe(true);
|
||||||
|
expect(response.body.data[0].sortBy).toBe('userIdSort');
|
||||||
|
});
|
||||||
|
});
|
@ -9,7 +9,6 @@ export async function createApp(
|
|||||||
const app = mockServer({
|
const app = mockServer({
|
||||||
acl: false,
|
acl: false,
|
||||||
...options,
|
...options,
|
||||||
// plugins: ['error-handler', 'collection-manager', 'ui-schema-storage'],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
options.beforePlugin && options.beforePlugin(app);
|
options.beforePlugin && options.beforePlugin(app);
|
||||||
|
@ -73,6 +73,9 @@ export const beforeInitOptions = {
|
|||||||
}
|
}
|
||||||
setTargetKey(database, model);
|
setTargetKey(database, model);
|
||||||
setSourceKey(database, model);
|
setSourceKey(database, model);
|
||||||
|
if (model.get('sortable') && model.get('type') === 'hasMany') {
|
||||||
|
model.set('sortBy', model.get('foreignKey') + 'Sort');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
hasOne(model: Model, { database }) {
|
hasOne(model: Model, { database }) {
|
||||||
const defaults = {
|
const defaults = {
|
||||||
|
@ -25,6 +25,7 @@ export class CollectionModel extends MagicAttributeModel {
|
|||||||
...this.get(),
|
...this.get(),
|
||||||
fields: [],
|
fields: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.db.hasCollection(name)) {
|
if (this.db.hasCollection(name)) {
|
||||||
collection = this.db.getCollection(name);
|
collection = this.db.getCollection(name);
|
||||||
|
|
||||||
|
@ -48,6 +48,20 @@ export class FieldModel extends MagicAttributeModel {
|
|||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async syncSortByField(options: Transactionable) {
|
||||||
|
const collectionName = this.get('collectionName');
|
||||||
|
const collection = this.db.getCollection(collectionName);
|
||||||
|
await this.load(options);
|
||||||
|
await collection.sync({
|
||||||
|
force: false,
|
||||||
|
alter: {
|
||||||
|
drop: false,
|
||||||
|
},
|
||||||
|
// @ts-ignore
|
||||||
|
transaction: options.transaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async migrate({ isNew, ...options }: MigrateOptions = {}) {
|
async migrate({ isNew, ...options }: MigrateOptions = {}) {
|
||||||
let field;
|
let field;
|
||||||
try {
|
try {
|
||||||
|
@ -13,12 +13,12 @@ import {
|
|||||||
beforeDestroyForeignKey,
|
beforeDestroyForeignKey,
|
||||||
beforeInitOptions,
|
beforeInitOptions,
|
||||||
} from './hooks';
|
} from './hooks';
|
||||||
|
import { beforeCreateForValidateField } from './hooks/beforeCreateForValidateField';
|
||||||
import { beforeCreateForViewCollection } from './hooks/beforeCreateForViewCollection';
|
import { beforeCreateForViewCollection } from './hooks/beforeCreateForViewCollection';
|
||||||
import { CollectionModel, FieldModel } from './models';
|
import { CollectionModel, FieldModel } from './models';
|
||||||
import collectionActions from './resourcers/collections';
|
import collectionActions from './resourcers/collections';
|
||||||
import viewResourcer from './resourcers/views';
|
|
||||||
import sqlResourcer from './resourcers/sql';
|
import sqlResourcer from './resourcers/sql';
|
||||||
import { beforeCreateForValidateField } from './hooks/beforeCreateForValidateField';
|
import viewResourcer from './resourcers/views';
|
||||||
|
|
||||||
export class CollectionManagerPlugin extends Plugin {
|
export class CollectionManagerPlugin extends Plugin {
|
||||||
public schema: string;
|
public schema: string;
|
||||||
@ -152,6 +152,10 @@ export class CollectionManagerPlugin extends Plugin {
|
|||||||
throw new Error('cant update field without a reverseField key');
|
throw new Error('cant update field without a reverseField key');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// todo: 目前只支持一对多
|
||||||
|
if (model.get('sortable') && model.get('type') === 'hasMany') {
|
||||||
|
model.set('sortBy', model.get('foreignKey') + 'Sort');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.db.on('fields.afterUpdate', async (model: FieldModel, { context, transaction }) => {
|
this.app.db.on('fields.afterUpdate', async (model: FieldModel, { context, transaction }) => {
|
||||||
@ -180,6 +184,10 @@ export class CollectionManagerPlugin extends Plugin {
|
|||||||
if (prevOnDelete != currentOnDelete) {
|
if (prevOnDelete != currentOnDelete) {
|
||||||
await model.syncReferenceCheckOption({ transaction });
|
await model.syncReferenceCheckOption({ transaction });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model.get('type') === 'hasMany' && model.get('sortable') && model.get('sortBy')) {
|
||||||
|
await model.syncSortByField({ transaction });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.db.on('fields.afterSaveWithAssociations', async (model: FieldModel, { context, transaction }) => {
|
this.app.db.on('fields.afterSaveWithAssociations', async (model: FieldModel, { context, transaction }) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user