feat: collection extender

This commit is contained in:
Chareice 2023-02-20 18:14:52 +08:00
parent 479676d678
commit a942eee769
6 changed files with 95 additions and 51 deletions

View File

@ -27,6 +27,7 @@ describe('sort', function () {
},
],
});
expect(collection.getField('parent').options.target).toBe('categories');
expect(collection.getField('parent').options.foreignKey).toBe('parentId');
expect(collection.getField('children').options.target).toBe('categories');

View File

@ -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()),
);
}
}
});
}
}

View 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);
}
}
}

View File

@ -7,7 +7,7 @@ import {
QueryInterfaceDropTableOptions,
SyncOptions,
Transactionable,
Utils
Utils,
} from 'sequelize';
import { Database } from './database';
import { Field, FieldOptions } from './fields';
@ -85,7 +85,8 @@ export class Collection<
this.db.modelCollection.set(this.model, this);
this.db.tableNameCollectionMap.set(this.model.tableName, this);
this.treeHook();
this.db.emit('definingCollection', this);
if (!options.inherits) {
this.setFields(options.fields);
@ -95,54 +96,6 @@ export class Collection<
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) {
checkIdentifier(options.name);
this.checkTableName();

View File

@ -64,6 +64,7 @@ import { patchSequelizeQueryInterface, snakeCase } from './utils';
import DatabaseUtils from './database-utils';
import { BaseValueParser, registerFieldValueParsers } from './value-parsers';
import { applyExtenders } from './collection-extenders';
export interface MergeOptions extends merge.Options {}
@ -336,6 +337,10 @@ export class Database extends EventEmitter implements AsyncEmitter {
options.schema = this.options.schema;
}
});
this.on('definingCollection', (collection) => {
applyExtenders(collection);
});
}
addMigration(item: MigrationItem) {

View File

@ -4236,7 +4236,7 @@
dependencies:
"@formily/shared" "2.0.20"
"@formulajs/formulajs@^4.2.0":
"@formulajs/formulajs@4.2.0", "@formulajs/formulajs@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@formulajs/formulajs/-/formulajs-4.2.0.tgz#e5c6a98fa5863442cb68f93b8b9b28d75070abc4"
integrity sha512-egxyvwj08iwOznFgxv7dvjgHUC7C8jdtznAs+15uThIti7TwDGhB3wsbJt1dlfhSHKvlRAiW4MDYxNkvgmyjyg==