From a942eee7699724fe831a98bae3f67a42db91a28b Mon Sep 17 00:00:00 2001 From: Chareice Date: Mon, 20 Feb 2023 18:14:52 +0800 Subject: [PATCH] feat: collection extender --- .../core/database/src/__tests__/tree.test.ts | 1 + .../adjacency-list-extender.ts | 66 +++++++++++++++++++ .../src/collection-extenders/index.ts | 19 ++++++ packages/core/database/src/collection.ts | 53 +-------------- packages/core/database/src/database.ts | 5 ++ yarn.lock | 2 +- 6 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 packages/core/database/src/collection-extenders/adjacency-list-extender.ts create mode 100644 packages/core/database/src/collection-extenders/index.ts diff --git a/packages/core/database/src/__tests__/tree.test.ts b/packages/core/database/src/__tests__/tree.test.ts index 3f9d3dd75..9116bcab5 100644 --- a/packages/core/database/src/__tests__/tree.test.ts +++ b/packages/core/database/src/__tests__/tree.test.ts @@ -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'); diff --git a/packages/core/database/src/collection-extenders/adjacency-list-extender.ts b/packages/core/database/src/collection-extenders/adjacency-list-extender.ts new file mode 100644 index 000000000..41d77f28a --- /dev/null +++ b/packages/core/database/src/collection-extenders/adjacency-list-extender.ts @@ -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()), + ); + } + } + }); + } +} diff --git a/packages/core/database/src/collection-extenders/index.ts b/packages/core/database/src/collection-extenders/index.ts new file mode 100644 index 000000000..093b8251b --- /dev/null +++ b/packages/core/database/src/collection-extenders/index.ts @@ -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); + } + } +} diff --git a/packages/core/database/src/collection.ts b/packages/core/database/src/collection.ts index 8ef063279..13b1105dc 100644 --- a/packages/core/database/src/collection.ts +++ b/packages/core/database/src/collection.ts @@ -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(); diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 625186df2..3e8256e14 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -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) { diff --git a/yarn.lock b/yarn.lock index 5e13f87b8..947ba8486 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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==