mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 23:19:26 +08:00
feat: collection extender
This commit is contained in:
parent
479676d678
commit
a942eee769
@ -27,6 +27,7 @@ describe('sort', function () {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(collection.getField('parent').options.target).toBe('categories');
|
expect(collection.getField('parent').options.target).toBe('categories');
|
||||||
expect(collection.getField('parent').options.foreignKey).toBe('parentId');
|
expect(collection.getField('parent').options.foreignKey).toBe('parentId');
|
||||||
expect(collection.getField('children').options.target).toBe('categories');
|
expect(collection.getField('children').options.target).toBe('categories');
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
import lodash from 'lodash';
|
||||||
|
import { Model } from '../model';
|
||||||
|
|
||||||
|
import { CollectionExtender } from '.';
|
||||||
|
|
||||||
|
export class AdjacencyListExtender implements CollectionExtender {
|
||||||
|
static condition(options) {
|
||||||
|
return options.tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(collection) {
|
||||||
|
this.treeHook(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
treeHook(collection) {
|
||||||
|
if (!collection.options.tree) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.on('field.beforeAdd', (name, opts, { collection }) => {
|
||||||
|
console.log('field beforeAdd');
|
||||||
|
if (!collection.options.tree) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'parent' || name === 'children') {
|
||||||
|
opts.target = collection.name;
|
||||||
|
opts.foreignKey = 'parentId';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
collection.model.afterFind(async (instances, options: any) => {
|
||||||
|
if (!options.tree) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const arr: Model[] = Array.isArray(instances) ? instances : [instances];
|
||||||
|
let index = 0;
|
||||||
|
for (const instance of arr) {
|
||||||
|
const opts = {
|
||||||
|
...lodash.pick(options, ['tree', 'fields', 'appends', 'except', 'sort']),
|
||||||
|
};
|
||||||
|
let __index = `${index++}`;
|
||||||
|
if (options.parentIndex) {
|
||||||
|
__index = `${options.parentIndex}.${__index}`;
|
||||||
|
}
|
||||||
|
instance.setDataValue('__index', __index);
|
||||||
|
const children = await collection.repository.find({
|
||||||
|
filter: {
|
||||||
|
parentId: instance.id,
|
||||||
|
},
|
||||||
|
transaction: options.transaction,
|
||||||
|
...opts,
|
||||||
|
// @ts-ignore
|
||||||
|
parentIndex: `${__index}.children`,
|
||||||
|
context: options.context,
|
||||||
|
});
|
||||||
|
if (children?.length > 0) {
|
||||||
|
instance.setDataValue(
|
||||||
|
'children',
|
||||||
|
children.map((r) => r.toJSON()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
19
packages/core/database/src/collection-extenders/index.ts
Normal file
19
packages/core/database/src/collection-extenders/index.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Collection } from '../collection';
|
||||||
|
import { AdjacencyListExtender } from './adjacency-list-extender';
|
||||||
|
|
||||||
|
export abstract class CollectionExtender {
|
||||||
|
static condition: (options: any) => boolean;
|
||||||
|
apply: (collection: Collection) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyExtenders(collection: Collection) {
|
||||||
|
const extenderClasses = [AdjacencyListExtender];
|
||||||
|
|
||||||
|
for (const extenderClass of extenderClasses) {
|
||||||
|
if (extenderClass.condition(collection.options)) {
|
||||||
|
console.log('apply extender', extenderClass.name);
|
||||||
|
const extender = new extenderClass();
|
||||||
|
extender.apply(collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ import {
|
|||||||
QueryInterfaceDropTableOptions,
|
QueryInterfaceDropTableOptions,
|
||||||
SyncOptions,
|
SyncOptions,
|
||||||
Transactionable,
|
Transactionable,
|
||||||
Utils
|
Utils,
|
||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Field, FieldOptions } from './fields';
|
import { Field, FieldOptions } from './fields';
|
||||||
@ -85,7 +85,8 @@ export class Collection<
|
|||||||
|
|
||||||
this.db.modelCollection.set(this.model, this);
|
this.db.modelCollection.set(this.model, this);
|
||||||
this.db.tableNameCollectionMap.set(this.model.tableName, this);
|
this.db.tableNameCollectionMap.set(this.model.tableName, this);
|
||||||
this.treeHook();
|
|
||||||
|
this.db.emit('definingCollection', this);
|
||||||
|
|
||||||
if (!options.inherits) {
|
if (!options.inherits) {
|
||||||
this.setFields(options.fields);
|
this.setFields(options.fields);
|
||||||
@ -95,54 +96,6 @@ export class Collection<
|
|||||||
this.setSortable(options.sortable);
|
this.setSortable(options.sortable);
|
||||||
}
|
}
|
||||||
|
|
||||||
treeHook() {
|
|
||||||
if (!this.options.tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.on('field.beforeAdd', (name, opts, { collection }) => {
|
|
||||||
if (!collection.options.tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (name === 'parent' || name === 'children') {
|
|
||||||
opts.target = collection.name;
|
|
||||||
opts.foreignKey = 'parentId';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.model.afterFind(async (instances, options: any) => {
|
|
||||||
if (!options.tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const arr: Model[] = Array.isArray(instances) ? instances : [instances];
|
|
||||||
let index = 0;
|
|
||||||
for (const instance of arr) {
|
|
||||||
const opts = {
|
|
||||||
...lodash.pick(options, ['tree', 'fields', 'appends', 'except', 'sort']),
|
|
||||||
};
|
|
||||||
let __index = `${index++}`;
|
|
||||||
if (options.parentIndex) {
|
|
||||||
__index = `${options.parentIndex}.${__index}`;
|
|
||||||
}
|
|
||||||
instance.setDataValue('__index', __index);
|
|
||||||
const children = await this.repository.find({
|
|
||||||
filter: {
|
|
||||||
parentId: instance.id,
|
|
||||||
},
|
|
||||||
transaction: options.transaction,
|
|
||||||
...opts,
|
|
||||||
// @ts-ignore
|
|
||||||
parentIndex: `${__index}.children`,
|
|
||||||
context: options.context,
|
|
||||||
});
|
|
||||||
if (children?.length > 0) {
|
|
||||||
instance.setDataValue(
|
|
||||||
'children',
|
|
||||||
children.map((r) => r.toJSON()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private checkOptions(options: CollectionOptions) {
|
private checkOptions(options: CollectionOptions) {
|
||||||
checkIdentifier(options.name);
|
checkIdentifier(options.name);
|
||||||
this.checkTableName();
|
this.checkTableName();
|
||||||
|
@ -64,6 +64,7 @@ import { patchSequelizeQueryInterface, snakeCase } from './utils';
|
|||||||
|
|
||||||
import DatabaseUtils from './database-utils';
|
import DatabaseUtils from './database-utils';
|
||||||
import { BaseValueParser, registerFieldValueParsers } from './value-parsers';
|
import { BaseValueParser, registerFieldValueParsers } from './value-parsers';
|
||||||
|
import { applyExtenders } from './collection-extenders';
|
||||||
|
|
||||||
export interface MergeOptions extends merge.Options {}
|
export interface MergeOptions extends merge.Options {}
|
||||||
|
|
||||||
@ -336,6 +337,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
options.schema = this.options.schema;
|
options.schema = this.options.schema;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.on('definingCollection', (collection) => {
|
||||||
|
applyExtenders(collection);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addMigration(item: MigrationItem) {
|
addMigration(item: MigrationItem) {
|
||||||
|
@ -4236,7 +4236,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@formily/shared" "2.0.20"
|
"@formily/shared" "2.0.20"
|
||||||
|
|
||||||
"@formulajs/formulajs@^4.2.0":
|
"@formulajs/formulajs@4.2.0", "@formulajs/formulajs@^4.2.0":
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@formulajs/formulajs/-/formulajs-4.2.0.tgz#e5c6a98fa5863442cb68f93b8b9b28d75070abc4"
|
resolved "https://registry.yarnpkg.com/@formulajs/formulajs/-/formulajs-4.2.0.tgz#e5c6a98fa5863442cb68f93b8b9b28d75070abc4"
|
||||||
integrity sha512-egxyvwj08iwOznFgxv7dvjgHUC7C8jdtznAs+15uThIti7TwDGhB3wsbJt1dlfhSHKvlRAiW4MDYxNkvgmyjyg==
|
integrity sha512-egxyvwj08iwOznFgxv7dvjgHUC7C8jdtznAs+15uThIti7TwDGhB3wsbJt1dlfhSHKvlRAiW4MDYxNkvgmyjyg==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user