feat: add sortable parameter to collection options

This commit is contained in:
chenos 2022-02-11 14:34:33 +08:00
parent e12b8f44d1
commit 16d07e9b4a
4 changed files with 124 additions and 24 deletions

View File

@ -0,0 +1,60 @@
import { mockDatabase } from './index';
describe('collection sortable options', () => {
test('sortable=true', async () => {
const db = mockDatabase();
const Test = db.collection({
name: 'test',
sortable: true,
});
const model = Test.model;
await db.sync();
const instance = await model.create();
expect(model.rawAttributes['sort']).toBeDefined();
expect(instance.get('sort')).toBe(1);
});
test('sortable=string', async () => {
const db = mockDatabase();
const Test = db.collection({
name: 'test',
sortable: 'order',
});
const model = Test.model;
await db.sync();
const instance = await model.create();
expect(model.rawAttributes['order']).toBeDefined();
expect(instance.get('order')).toBe(1);
});
test('sortable=object', async () => {
const db = mockDatabase();
const Test = db.collection({
name: 'test',
sortable: {
name: 'sort',
scopeKey: 'status',
},
fields: [{ type: 'string', name: 'status' }],
});
await db.sync();
const t1 = await Test.model.create({ status: 'publish' });
const t2 = await Test.model.create({ status: 'publish' });
const t3 = await Test.model.create({ status: 'draft' });
const t4 = await Test.model.create({ status: 'draft' });
expect(t1.get('sort')).toBe(1);
expect(t2.get('sort')).toBe(2);
expect(t3.get('sort')).toBe(1);
expect(t4.get('sort')).toBe(2);
});
});

View File

@ -1,17 +1,18 @@
import { Sequelize, ModelCtor, Model, ModelOptions } from 'sequelize'; import merge from 'deepmerge';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { default as lodash, default as _ } from 'lodash';
import { Model, ModelCtor, ModelOptions } from 'sequelize';
import { SyncOptions } from 'sequelize/types/lib/sequelize';
import { Database } from './database'; import { Database } from './database';
import { Field, FieldOptions } from './fields'; import { Field, FieldOptions } from './fields';
import _ from 'lodash';
import { Repository } from './repository'; import { Repository } from './repository';
import { SyncOptions } from 'sequelize/types/lib/sequelize';
import lodash from 'lodash';
import merge from 'deepmerge';
const { hooks } = require('sequelize/lib/hooks'); const { hooks } = require('sequelize/lib/hooks');
export type RepositoryType = typeof Repository; export type RepositoryType = typeof Repository;
export type CollectionSortable = string | boolean | { name?: string; scopeKey?: string };
export interface CollectionOptions extends Omit<ModelOptions, 'name'> { export interface CollectionOptions extends Omit<ModelOptions, 'name'> {
name: string; name: string;
tableName?: string; tableName?: string;
@ -19,6 +20,7 @@ export interface CollectionOptions extends Omit<ModelOptions, 'name'> {
fields?: FieldOptions[]; fields?: FieldOptions[];
model?: string | ModelCtor<Model>; model?: string | ModelCtor<Model>;
repository?: string | RepositoryType; repository?: string | RepositoryType;
sortable?: CollectionSortable;
/** /**
* @default true * @default true
*/ */
@ -61,6 +63,7 @@ export class Collection<
this.modelInit(); this.modelInit();
this.setFields(options.fields); this.setFields(options.fields);
this.setRepository(options.repository); this.setRepository(options.repository);
this.setSortable(options.sortable);
} }
private sequelizeModelOptions() { private sequelizeModelOptions() {
@ -211,6 +214,27 @@ export class Collection<
(<any>this.model)._setupHooks(bindHooks); (<any>this.model)._setupHooks(bindHooks);
} }
setSortable(sortable) {
if (!sortable) {
return;
}
if (sortable === true) {
this.setField('sort', {
type: 'sort',
hidden: true,
});
}
if (typeof sortable === 'string') {
this.setField(sortable, {
type: 'sort',
hidden: true,
});
} else if (typeof sortable === 'object') {
const { name, ...opts } = sortable;
this.setField(name || 'sort', { type: 'sort', hidden: true, ...opts });
}
}
/** /**
* TODO * TODO
* *

View File

@ -1,7 +1,16 @@
import { applyMixins, AsyncEmitter } from '@nocobase/utils'; import { applyMixins, AsyncEmitter } from '@nocobase/utils';
import merge from 'deepmerge'; import merge from 'deepmerge';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Model, ModelCtor, Op, Options, QueryInterfaceDropAllTablesOptions, Sequelize, SyncOptions, Utils } from 'sequelize'; import {
Model,
ModelCtor,
Op,
Options,
QueryInterfaceDropAllTablesOptions,
Sequelize,
SyncOptions,
Utils
} from 'sequelize';
import { Collection, CollectionOptions, RepositoryType } from './collection'; import { Collection, CollectionOptions, RepositoryType } from './collection';
import { ImporterReader, ImportFileExtension } from './collection-importer'; import { ImporterReader, ImportFileExtension } from './collection-importer';
import * as FieldTypes from './fields'; import * as FieldTypes from './fields';
@ -295,6 +304,18 @@ export function extend(collectionOptions: CollectionOptions, mergeOptions?: Merg
}; };
} }
export const defineCollection = (collectionOptions: CollectionOptions) => {
return collectionOptions;
};
export const extendCollection = (collectionOptions: CollectionOptions, mergeOptions?: MergeOptions) => {
return {
collectionOptions,
mergeOptions,
extend: true,
};
};
applyMixins(Database, [AsyncEmitter]); applyMixins(Database, [AsyncEmitter]);
export default Database; export default Database;

View File

@ -1,31 +1,30 @@
import lodash, { omit } from 'lodash';
import { import {
Association, Association,
BulkCreateOptions, BulkCreateOptions,
CreateOptions as SequelizeCreateOptions, CreateOptions as SequelizeCreateOptions,
UpdateOptions as SequelizeUpdateOptions,
FindAndCountOptions as SequelizeAndCountOptions,
DestroyOptions as SequelizeDestroyOptions, DestroyOptions as SequelizeDestroyOptions,
FindAndCountOptions as SequelizeAndCountOptions,
FindOptions as SequelizeFindOptions, FindOptions as SequelizeFindOptions,
Model, Model,
ModelCtor, ModelCtor,
Op, Op,
Transaction, Transaction,
UpdateOptions as SequelizeUpdateOptions
} from 'sequelize'; } from 'sequelize';
import { Collection } from './collection'; import { Collection } from './collection';
import lodash, { omit } from 'lodash';
import { Database } from './database'; import { Database } from './database';
import { updateAssociations, updateModelByValues } from './update-associations';
import { RelationField } from './fields'; import { RelationField } from './fields';
import FilterParser from './filter-parser'; import FilterParser from './filter-parser';
import { OptionsParser } from './options-parser'; import { OptionsParser } from './options-parser';
import { RelationRepository } from './relation-repository/relation-repository';
import { HasOneRepository } from './relation-repository/hasone-repository';
import { BelongsToRepository } from './relation-repository/belongs-to-repository';
import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository'; import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository';
import { BelongsToRepository } from './relation-repository/belongs-to-repository';
import { HasManyRepository } from './relation-repository/hasmany-repository'; import { HasManyRepository } from './relation-repository/hasmany-repository';
import { UpdateGuard } from './update-guard'; import { HasOneRepository } from './relation-repository/hasone-repository';
import { RelationRepository } from './relation-repository/relation-repository';
import { transactionWrapperBuilder } from './transaction-decorator'; import { transactionWrapperBuilder } from './transaction-decorator';
import { updateAssociations, updateModelByValues } from './update-associations';
import { UpdateGuard } from './update-guard';
const debug = require('debug')('noco-database'); const debug = require('debug')('noco-database');
@ -324,15 +323,11 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
async createMany(options: CreateManyOptions) { async createMany(options: CreateManyOptions) {
const transaction = await this.getTransaction(options); const transaction = await this.getTransaction(options);
const { records } = options; const { records } = options;
const instances = await this.collection.model.bulkCreate(records, { const instances = [];
...options, for (const values of records) {
transaction, const instance = await this.create({ values, transaction });
}); instances.push(instance);
for (let i = 0; i < instances.length; i++) {
await updateAssociations(instances[i], records[i], { ...options, transaction });
} }
return instances; return instances;
} }