From 499cb6d5928339deb509d9e26cba099fa7ccb58c Mon Sep 17 00:00:00 2001 From: Xc Date: Fri, 15 Apr 2022 18:35:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E6=94=B9=E4=BA=86=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/aspects/crud.d.ts | 2 +- lib/base-ed/EntityDict.d.ts | 2 +- lib/cacheStore/CacheStore.d.ts | 18 +++ lib/cacheStore/CacheStore.js | 57 +++++++ lib/cacheStore/context.d.ts | 12 ++ lib/cacheStore/context.js | 18 +++ lib/checkers/address.d.ts | 4 + lib/checkers/address.js | 30 ++++ lib/checkers/index.d.ts | 2 + lib/checkers/index.js | 7 + lib/data/area.d.ts | 35 ++++- lib/data/area.js | 4 +- lib/data/index.d.ts | 35 ++++- lib/index.d.ts | 4 +- lib/index.js | 19 ++- lib/triggers/address.d.ts | 5 +- lib/triggers/address.js | 14 +- lib/triggers/index.d.ts | 5 +- lib/triggers/index.js | 6 +- lib/types/RuntimeContext.d.ts | 4 +- lib/utils/check.d.ts | 2 + lib/utils/check.js | 26 ++++ package.json | 6 +- src/RuntimeContext.ts | 30 ++++ src/aspects/crud.ts | 15 +- src/aspects/index.ts | 9 +- src/aspects/token.ts | 16 +- src/checkers/address.ts | 3 +- src/index.ts | 9 +- src/triggers/address.ts | 9 +- src/triggers/index.ts | 4 +- src/types/Aspect.ts | 6 - src/types/Auth.ts | 35 ----- src/types/RuntimeContext.ts | 12 -- src/types/Trigger.ts | 121 --------------- src/utils/TriggerExecutor.d.ts | 20 --- src/utils/TriggerExecutor.js | 215 -------------------------- src/utils/TriggerExecutor.ts | 268 --------------------------------- src/utils/check.ts | 2 +- test/build-test-domain.ts | 6 + test/entities/House.ts | 12 ++ tsconfig.json | 1 + 42 files changed, 379 insertions(+), 731 deletions(-) create mode 100644 lib/cacheStore/CacheStore.d.ts create mode 100644 lib/cacheStore/CacheStore.js create mode 100644 lib/cacheStore/context.d.ts create mode 100644 lib/cacheStore/context.js create mode 100644 lib/checkers/address.d.ts create mode 100644 lib/checkers/address.js create mode 100644 lib/checkers/index.d.ts create mode 100644 lib/checkers/index.js create mode 100644 lib/utils/check.d.ts create mode 100644 lib/utils/check.js create mode 100644 src/RuntimeContext.ts delete mode 100644 src/types/Aspect.ts delete mode 100644 src/types/Auth.ts delete mode 100644 src/types/RuntimeContext.ts delete mode 100644 src/types/Trigger.ts delete mode 100644 src/utils/TriggerExecutor.d.ts delete mode 100644 src/utils/TriggerExecutor.js delete mode 100644 src/utils/TriggerExecutor.ts create mode 100644 test/build-test-domain.ts create mode 100644 test/entities/House.ts diff --git a/lib/aspects/crud.d.ts b/lib/aspects/crud.d.ts index aefe14b1a..11d320220 100644 --- a/lib/aspects/crud.d.ts +++ b/lib/aspects/crud.d.ts @@ -9,4 +9,4 @@ export declare function select(option entity: T; selection: ED[T]['Selection']; params?: object; -}, context: RuntimeContext): Promise>; +}, context: RuntimeContext): Promise>; diff --git a/lib/base-ed/EntityDict.d.ts b/lib/base-ed/EntityDict.d.ts index bfc925f84..58334f6f4 100644 --- a/lib/base-ed/EntityDict.d.ts +++ b/lib/base-ed/EntityDict.d.ts @@ -10,7 +10,7 @@ import { EntityDef as System } from "./System/Schema"; import { EntityDef as Token } from "./Token/Schema"; import { EntityDef as User } from "./User/Schema"; import { EntityDef as WechatUser } from "./WechatUser/Schema"; -export declare type BaseEntityDict = { +export declare type EntityDict = { address: Address; application: Application; area: Area; diff --git a/lib/cacheStore/CacheStore.d.ts b/lib/cacheStore/CacheStore.d.ts new file mode 100644 index 000000000..8142a9f67 --- /dev/null +++ b/lib/cacheStore/CacheStore.d.ts @@ -0,0 +1,18 @@ +import { EntityDict, OperationResult } from 'oak-domain/lib/types/Entity'; +import { StorageSchema } from "oak-domain/lib/types/Storage"; +import { Checker } from 'oak-domain/lib/types/Auth'; +import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; +import { TreeStore } from 'oak-memory-tree-store'; +import { CacheContext } from './context'; +export declare class CacheStore extends TreeStore { + private executor; + constructor(storageSchema: StorageSchema, initialData?: { + [T in keyof ED]?: { + [ID: string]: ED[T]['OpSchema']; + }; + }); + operate(entity: T, operation: ED[T]['Operation'], context: CacheContext, params?: Object): Promise; + select(entity: T, selection: S, context: CacheContext, params?: Object): Promise>; + count(entity: T, selection: Omit, context: CacheContext, params?: Object): Promise; + registerChecker(checker: Checker): void; +} diff --git a/lib/cacheStore/CacheStore.js b/lib/cacheStore/CacheStore.js new file mode 100644 index 000000000..6f5145a5d --- /dev/null +++ b/lib/cacheStore/CacheStore.js @@ -0,0 +1,57 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CacheStore = void 0; +const TriggerExecutor_1 = require("oak-domain/lib/store/TriggerExecutor"); +const oak_memory_tree_store_1 = require("oak-memory-tree-store"); +class CacheStore extends oak_memory_tree_store_1.TreeStore { + executor; + constructor(storageSchema, initialData) { + super(storageSchema, true, initialData); + this.executor = new TriggerExecutor_1.TriggerExecutor(); + } + async operate(entity, operation, context, params) { + const autoCommit = !context.uuid; + let result; + if (autoCommit) { + await context.begin(); + } + try { + await this.executor.preOperation(entity, operation, context); + result = await super.operate(entity, operation, context, params); + await this.executor.postOperation(entity, operation, context); + } + catch (err) { + await context.rollback(); + throw err; + } + if (autoCommit) { + await context.commit(); + } + return result; + } + async select(entity, selection, context, params) { + const autoCommit = !context.uuid; + if (autoCommit) { + await context.begin(); + } + let result; + try { + result = await super.select(entity, selection, context, params); + } + catch (err) { + await context.rollback(); + throw err; + } + if (autoCommit) { + await context.commit(); + } + return result; + } + async count(entity, selection, context, params) { + throw new Error("Method not implemented."); + } + registerChecker(checker) { + this.executor.registerChecker(checker); + } +} +exports.CacheStore = CacheStore; diff --git a/lib/cacheStore/context.d.ts b/lib/cacheStore/context.d.ts new file mode 100644 index 000000000..9b7903525 --- /dev/null +++ b/lib/cacheStore/context.d.ts @@ -0,0 +1,12 @@ +import { EntityDict } from 'oak-domain/lib/types/Entity'; +import { RuntimeContext } from '../types/RuntimeContext'; +import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; +import { Schema as Application } from '../base-ed/Application/Schema'; +import { Schema as Token } from '../base-ed/Token/Schema'; +import { Context, TreeStore } from 'oak-memory-tree-store'; +export declare class CacheContext extends Context implements RuntimeContext { + getApplication: () => Pick | undefined; + getToken: () => Pick | undefined; + constructor(store: TreeStore, application?: Pick, token?: Pick); + on(event: "commit" | "rollback", callback: (context: any) => Promise): void; +} diff --git a/lib/cacheStore/context.js b/lib/cacheStore/context.js new file mode 100644 index 000000000..afe8e4fbf --- /dev/null +++ b/lib/cacheStore/context.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CacheContext = void 0; +const oak_memory_tree_store_1 = require("oak-memory-tree-store"); +class CacheContext extends oak_memory_tree_store_1.Context { + getApplication; + getToken; + constructor(store, application, token) { + super(store); + this.getApplication = () => application; + this.getToken = () => token; + } + on(event, callback) { + throw new Error('disallow cross txn events in FrontContext'); + } +} +exports.CacheContext = CacheContext; +; diff --git a/lib/checkers/address.d.ts b/lib/checkers/address.d.ts new file mode 100644 index 000000000..1a1da59a5 --- /dev/null +++ b/lib/checkers/address.d.ts @@ -0,0 +1,4 @@ +import { Checker } from "oak-domain/lib/types"; +import { EntityDict } from '../base-ed/EntityDict'; +declare const checkers: Checker[]; +export default checkers; diff --git a/lib/checkers/address.js b/lib/checkers/address.js new file mode 100644 index 000000000..7e1361f32 --- /dev/null +++ b/lib/checkers/address.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const validator_1 = require("oak-domain/lib/utils/validator"); +const types_1 = require("oak-domain/lib/types"); +const check_1 = require("../utils/check"); +const checkers = [ + { + action: 'create', + entity: 'address', + checker: async ({ operation }) => { + const { action, data } = operation; + if (data instanceof Array) { + data.forEach(ele => { + (0, check_1.checkAttributesNotNull)(ele, ['name', 'detail', 'phone', 'areaId']); + if (!(0, validator_1.isMobile)(ele.phone)) { + throw new types_1.AttrIllegalError(['phone'], '手机号非法'); + } + }); + } + else { + (0, check_1.checkAttributesNotNull)(data, ['name', 'detail', 'phone', 'areaId']); + if (!(0, validator_1.isMobile)(data.phone)) { + throw new types_1.AttrIllegalError(['phone'], '手机号非法'); + } + } + return 0; + }, + } +]; +exports.default = checkers; diff --git a/lib/checkers/index.d.ts b/lib/checkers/index.d.ts new file mode 100644 index 000000000..a2839eb2a --- /dev/null +++ b/lib/checkers/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import("oak-domain/lib/types").Checker[]; +export default _default; diff --git a/lib/checkers/index.js b/lib/checkers/index.js new file mode 100644 index 000000000..8a56346b3 --- /dev/null +++ b/lib/checkers/index.js @@ -0,0 +1,7 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const address_1 = __importDefault(require("./address")); +exports.default = [...address_1.default]; diff --git a/lib/data/area.d.ts b/lib/data/area.d.ts index dbec3c268..5063f7b8c 100644 --- a/lib/data/area.d.ts +++ b/lib/data/area.d.ts @@ -1,2 +1,35 @@ -declare const area: any[]; +declare const area: ({ + code: string; + level: string; + parentId: null; + name: string; + depth: number; + id: string; + center: { + type: string; + coordinate: number[]; + }; +} | { + code: string; + level: string; + parentId: string; + name: string; + depth: number; + id: string; + center: { + type: string; + coordinate: number[]; + }; +} | { + code: number; + level: string; + parentId: string; + name: string; + depth: number; + id: number; + center: { + type: string; + coordinate: number[]; + }; +})[]; export { area, }; diff --git a/lib/data/area.js b/lib/data/area.js index c373a4f13..ff736dcbe 100644 --- a/lib/data/area.js +++ b/lib/data/area.js @@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.area = void 0; -const area_json_1 = __importDefault(require("./area.json")); +// import area2 from './area.json'; const area_debug_json_1 = __importDefault(require("./area-debug.json")); -const area = process.env.NODE_ENV === 'production' ? area_json_1.default : area_debug_json_1.default; +const area = area_debug_json_1.default; exports.area = area; diff --git a/lib/data/index.d.ts b/lib/data/index.d.ts index eeaa67167..b2d144d56 100644 --- a/lib/data/index.d.ts +++ b/lib/data/index.d.ts @@ -2,6 +2,39 @@ declare const _default: { userRole: import("../base-ed/UserRole/Schema").CreateOperationData[]; user: import("../base-ed/User/Schema").CreateOperationData[]; role: import("../base-ed/Role/Schema").CreateOperationData[]; - area: any[]; + area: ({ + code: string; + level: string; + parentId: null; + name: string; + depth: number; + id: string; + center: { + type: string; + coordinate: number[]; + }; + } | { + code: string; + level: string; + parentId: string; + name: string; + depth: number; + id: string; + center: { + type: string; + coordinate: number[]; + }; + } | { + code: number; + level: string; + parentId: string; + name: string; + depth: number; + id: number; + center: { + type: string; + coordinate: number[]; + }; + })[]; }; export default _default; diff --git a/lib/index.d.ts b/lib/index.d.ts index 2f768625c..ccb4a567e 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,4 +1,6 @@ import aspectDict from "./aspects"; import triggers from "./triggers"; +import checkers from './checkers'; import data from "./data"; -export { triggers, data, aspectDict, }; +export { checkers, triggers, data, aspectDict, }; +export * from './types/RuntimeContext'; diff --git a/lib/index.js b/lib/index.js index e3dda5fa5..85e2eab42 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,12 +1,29 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.aspectDict = exports.data = exports.triggers = void 0; +exports.aspectDict = exports.data = exports.triggers = exports.checkers = void 0; const aspects_1 = __importDefault(require("./aspects")); exports.aspectDict = aspects_1.default; const triggers_1 = __importDefault(require("./triggers")); exports.triggers = triggers_1.default; +const checkers_1 = __importDefault(require("./checkers")); +exports.checkers = checkers_1.default; const data_1 = __importDefault(require("./data")); exports.data = data_1.default; +__exportStar(require("./types/RuntimeContext"), exports); diff --git a/lib/triggers/address.d.ts b/lib/triggers/address.d.ts index cb0ff5c3b..51c3a209e 100644 --- a/lib/triggers/address.d.ts +++ b/lib/triggers/address.d.ts @@ -1 +1,4 @@ -export {}; +import { CreateTriggerInTxn } from 'oak-domain/lib/types/Trigger'; +import { EntityDict } from '../base-ed/EntityDict'; +declare const triggers: CreateTriggerInTxn[]; +export default triggers; diff --git a/lib/triggers/address.js b/lib/triggers/address.js index 647679a71..56a293951 100644 --- a/lib/triggers/address.js +++ b/lib/triggers/address.js @@ -1,14 +1,4 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const triggers = [ - { - entity: 'address', - action: 'create', - when: 'before', - fn: async ({ operation }, context) => { - const { action, data } = operation; - return 0; - }, - name: '建立新area前检查数据', - } -]; +const triggers = []; +exports.default = triggers; diff --git a/lib/triggers/index.d.ts b/lib/triggers/index.d.ts index b177b57e9..12875a49f 100644 --- a/lib/triggers/index.d.ts +++ b/lib/triggers/index.d.ts @@ -1,2 +1,5 @@ -declare const _default: never[]; +import { EntityDict } from 'oak-domain/lib/types/Entity'; +import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; +import { Trigger } from 'oak-domain/lib/types'; +declare const _default: Trigger[]; export default _default; diff --git a/lib/triggers/index.js b/lib/triggers/index.js index 72df42189..8a56346b3 100644 --- a/lib/triggers/index.js +++ b/lib/triggers/index.js @@ -1,3 +1,7 @@ "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = []; +const address_1 = __importDefault(require("./address")); +exports.default = [...address_1.default]; diff --git a/lib/types/RuntimeContext.d.ts b/lib/types/RuntimeContext.d.ts index 62d13c313..b5b9a3c4a 100644 --- a/lib/types/RuntimeContext.d.ts +++ b/lib/types/RuntimeContext.d.ts @@ -3,6 +3,6 @@ import { EntityDict } from 'oak-domain/lib/types/Entity'; import { Schema as Application } from '../base-ed/Application/Schema'; import { Schema as Token } from '../base-ed/Token/Schema'; export interface RuntimeContext extends Context { - getApplication: () => Application; - getToken: () => Token | undefined; + getApplication: () => Pick | undefined; + getToken: () => Pick | undefined; } diff --git a/lib/utils/check.d.ts b/lib/utils/check.d.ts new file mode 100644 index 000000000..60a79e6df --- /dev/null +++ b/lib/utils/check.d.ts @@ -0,0 +1,2 @@ +export declare function checkAttributesNotNull>(data: T, attributes: Array, allowEmpty?: true): void; +export declare function checkAttributesScope>(data: T, attributes: Array): void; diff --git a/lib/utils/check.js b/lib/utils/check.js new file mode 100644 index 000000000..289278e2b --- /dev/null +++ b/lib/utils/check.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkAttributesScope = exports.checkAttributesNotNull = void 0; +const types_1 = require("oak-domain/lib/types"); +function checkAttributesNotNull(data, attributes, allowEmpty) { + const attrs = attributes.filter((attr) => { + if (data[attr] === null || data[attr] === '') { + return true; + } + if (!allowEmpty && !data.hasOwnProperty(attr)) { + return true; + } + }); + if (attrs.length > 0) { + throw new types_1.AttrIllegalError(attrs, '属性不能为空'); + } +} +exports.checkAttributesNotNull = checkAttributesNotNull; +; +function checkAttributesScope(data, attributes) { + const attrs = attributes.filter(attr => !data.hasOwnProperty(attr)); + if (attrs.length > 0) { + throw new types_1.AttrIllegalError(attrs, '多余的属性'); + } +} +exports.checkAttributesScope = checkAttributesScope; diff --git a/package.json b/package.json index 8848a5fdc..02f8b68e6 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,10 @@ "version": "1.0.0", "description": "oak框架中公共业务逻辑的实现", "dependencies": { - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "oak-domain": "file:../oak-domain", + "oak-frontend-base": "file:../oak-frontend-base", + "oak-memory-tree-store": "file:../oak-memory-tree-store" }, "devDependencies": { "@babel/cli": "^7.12.13", @@ -24,7 +27,6 @@ "fs-extra": "^10.0.0", "isomorphic-fetch": "^3.0.0", "mocha": "^8.2.1", - "oak-domain": "file:../oak-domain", "ts-node": "^9.1.1", "typescript": "^4.5.2" }, diff --git a/src/RuntimeContext.ts b/src/RuntimeContext.ts new file mode 100644 index 000000000..7691cb3be --- /dev/null +++ b/src/RuntimeContext.ts @@ -0,0 +1,30 @@ + +import { Context } from 'oak-domain/lib/types'; +import { UniversalContext } from 'oak-domain/lib/store/UniversalContext'; +import { EntityDict } from './base-ed/EntityDict'; +import { RowStore } from 'oak-domain/lib/types'; + + +export class RuntimeContext extends UniversalContext implements Context { + applicationId: string; + constructor(store: RowStore, appId: string) { + super(store); + this.applicationId = appId; + } + + getApplication () { + return this.rowStore.select('application', { + data: { + id: 1, + name: 1, + }, + filter: { + id: this.applicationId, + } + }, this); + } + + getToken() { + + } +}; \ No newline at end of file diff --git a/src/aspects/crud.ts b/src/aspects/crud.ts index 3c81667df..ad541adfc 100644 --- a/src/aspects/crud.ts +++ b/src/aspects/crud.ts @@ -1,14 +1,21 @@ -import { EntityDict, OperateParams } from 'oak-domain/lib/types/Entity'; -import { RuntimeContext } from '../types/RuntimeContext'; +import { OperateParams, EntityDict, OperationResult, SelectionResult2 } from 'oak-domain/lib/types/Entity'; +import { RuntimeContext } from '../RuntimeContext'; +import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; -export async function operate( +export async function operate( options: { entity: T, operation: ED[T]['Operation'], params?: OperateParams }, context: RuntimeContext) { const { entity, operation, params } = options; return context.rowStore.operate(entity, operation, context, params); } -export async function select( +export async function select( options: { entity: T, selection: ED[T]['Selection'], params?: object }, context: RuntimeContext) { const { entity, selection, params } = options; return context.rowStore.select(entity, selection, context, params); } + +/* +export type AspectDict = { + operation: (options: { entity: T, operation: ED[T]['Operation'], params?: OperateParams }, context: RuntimeContext) => Promise; + select: ( options: { entity: T, selection: S, params?: object }, context: RuntimeContext) => Promise>; +}; */ diff --git a/src/aspects/index.ts b/src/aspects/index.ts index 7b0d31df4..087310896 100644 --- a/src/aspects/index.ts +++ b/src/aspects/index.ts @@ -1,5 +1,7 @@ -import { loginByPassword, loginMp } from './token'; -import { operate, select } from './crud'; +import { EntityDict } from 'oak-domain/lib/types'; +import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; +import { loginByPassword, loginMp, /* AspectDict as TokenAD */} from './token'; +import { operate, select, /* AspectDict as CrudAD */ } from './crud'; const aspectDict = { loginByPassword, @@ -8,5 +10,6 @@ const aspectDict = { select, }; +export default aspectDict; -export default aspectDict; \ No newline at end of file +// export type AspectDict = TokenAD & CrudAD; \ No newline at end of file diff --git a/src/aspects/token.ts b/src/aspects/token.ts index 79adc30e0..a9541afbb 100644 --- a/src/aspects/token.ts +++ b/src/aspects/token.ts @@ -1,14 +1,18 @@ -import { RuntimeContext } from '../types/RuntimeContext'; -import { Schema as Token } from '../base-ed/Token/Schema'; -import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; -import { EntityDict } from 'oak-domain/lib/types/Entity'; +import { RuntimeContext } from '../RuntimeContext'; +import { EntityDict } from '../base-ed/EntityDict'; -export async function loginMp(params: { code: string }, context: RuntimeContext): Promise { +export async function loginMp(params: { code: string }, context: RuntimeContext): Promise { const { rowStore } = context; throw new Error('method not implemented!'); } -export async function loginByPassword(params: { password: string, mobile: string }, context: RuntimeContext): Promise { +export async function loginByPassword(params: { password: string, mobile: string }, context: RuntimeContext): Promise { const { rowStore } = context; throw new Error('method not implemented!'); } + +/* export type AspectDict = { + loginMp: (params: { code: string }, context: RuntimeContext) => Promise; + loginByPassword: (params: { password: string, mobile: string }, context: RuntimeContext) => Promise; +}; + */ \ No newline at end of file diff --git a/src/checkers/address.ts b/src/checkers/address.ts index 6af3df547..e7b9052ce 100644 --- a/src/checkers/address.ts +++ b/src/checkers/address.ts @@ -1,5 +1,5 @@ import { isMobile } from 'oak-domain/lib/utils/validator'; -import { AttrIllegalError, Checker } from "../types/Auth"; +import { AttrIllegalError, Checker, CreateChecker, DeduceCreateOperation, InstinctiveAttributes } from "oak-domain/lib/types"; import { EntityDict } from '../base-ed/EntityDict'; import { checkAttributesNotNull } from '../utils/check'; @@ -12,6 +12,7 @@ const checkers: Checker [] = [ if (data instanceof Array) { data.forEach( ele => { + const a: Exclude = 'name'; checkAttributesNotNull(ele, ['name', 'detail', 'phone', 'areaId']); if (!isMobile(ele.phone)) { throw new AttrIllegalError(['phone'], '手机号非法'); diff --git a/src/index.ts b/src/index.ts index d4cc9b8ac..40f95a3a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import aspectDict from "./aspects"; +import aspectDict/* , { AspectDict } */ from "./aspects"; import triggers from "./triggers"; import checkers from './checkers'; import data from "./data"; @@ -8,10 +8,7 @@ export { triggers, data, aspectDict, + /* AspectDict, */ }; -export * from './types/Trigger'; -export * from './types/Aspect'; -export * from './utils/TriggerExecutor'; -export * from './types/RuntimeContext'; -export * from './types/Auth'; +export * from './RuntimeContext'; diff --git a/src/triggers/address.ts b/src/triggers/address.ts index 446dda6c2..6fd2d5557 100644 --- a/src/triggers/address.ts +++ b/src/triggers/address.ts @@ -1,8 +1,9 @@ -import { CreateTriggerInTxn, Trigger } from '../types/Trigger'; +import { CreateTriggerInTxn, Trigger } from 'oak-domain/lib/types/Trigger'; import { EntityDict } from '../base-ed/EntityDict'; -const triggers: CreateTriggerInTxn[] = [ - + +const triggers: Trigger[] = [ + ]; -export default triggers; \ No newline at end of file +export default triggers; diff --git a/src/triggers/index.ts b/src/triggers/index.ts index d03850fd2..02c5e7f50 100644 --- a/src/triggers/index.ts +++ b/src/triggers/index.ts @@ -1,6 +1,6 @@ import { EntityDict } from 'oak-domain/lib/types/Entity'; import { EntityDict as BaseEntityDict } from '../base-ed/EntityDict'; -import { Trigger } from '../types/Trigger'; +import { Trigger } from 'oak-domain/lib/types'; import addressTriggers from './address'; -export default [...addressTriggers] as Array>; \ No newline at end of file +export default [...addressTriggers]; diff --git a/src/types/Aspect.ts b/src/types/Aspect.ts deleted file mode 100644 index 6a4dbb3cc..000000000 --- a/src/types/Aspect.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { EntityDict } from "oak-domain/lib/types/Entity"; -import { RuntimeContext } from './RuntimeContext'; - -export interface Aspect{ - (params: any, context: RuntimeContext): Promise; -}; \ No newline at end of file diff --git a/src/types/Auth.ts b/src/types/Auth.ts deleted file mode 100644 index 7f7c272f5..000000000 --- a/src/types/Auth.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { EntityDict } from "oak-domain/lib/types/Entity"; -import { CreateTriggerBase, RemoveTriggerBase, UpdateTriggerBase } from "./Trigger"; - -export class AttrIllegalError extends Error { - private attributes: string[]; - constructor(attributes: string[], message?: string) { - super(message); - this.attributes = attributes; - } - - getAttributes() { - return this.attributes; - } -}; - - -export type CreateChecker = { - action: 'create'; - entity: T; - checker: CreateTriggerBase['fn'], -}; - -export type UpdateChecker = { - action: UpdateTriggerBase['action']; - entity: T; - checker: UpdateTriggerBase['fn'], -}; - -export type RemoveChecker = { - action: 'remove'; - entity: T; - checker: RemoveTriggerBase['fn'], -}; - -export type Checker = CreateChecker | UpdateChecker | RemoveChecker; diff --git a/src/types/RuntimeContext.ts b/src/types/RuntimeContext.ts deleted file mode 100644 index 2d8a5605a..000000000 --- a/src/types/RuntimeContext.ts +++ /dev/null @@ -1,12 +0,0 @@ - -import { Context } from 'oak-domain/lib/types/Context'; -import { EntityDict } from 'oak-domain/lib/types/Entity'; -import { Schema as Application } from '../base-ed/Application/Schema'; -import { Schema as Token } from '../base-ed/Token/Schema'; - - -export interface RuntimeContext extends Context { - getApplication: () => Pick | undefined; - getToken: () => Pick | undefined; - on(event: 'commit' | 'rollback', callback: (context: RuntimeContext) => Promise): void; -}; \ No newline at end of file diff --git a/src/types/Trigger.ts b/src/types/Trigger.ts deleted file mode 100644 index c182d4ab9..000000000 --- a/src/types/Trigger.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { GenericAction } from "oak-domain/lib/actions/action"; -import { DeduceCreateOperation, DeduceRemoveOperation, DeduceSelection, DeduceUpdateOperation, EntityDict } from "oak-domain/lib/types/Entity"; -import { EntityDef, EntityShape, OperationResult, SelectionResult2, TriggerDataAttribute, TriggerTimestampAttribute } from "oak-domain/src/types/Entity"; -import { RuntimeContext } from "./RuntimeContext"; - -export interface CreateTriggerBase { - entity: T; - name: string; - action: 'create', - check?: (operation: DeduceCreateOperation) => boolean; - fn: (event: { operation: DeduceCreateOperation; }, context: RuntimeContext, params?: Object) => Promise; -}; - -export interface CreateTriggerInTxn extends CreateTriggerBase { - when: 'before' | 'after', -}; - -export interface CreateTriggerCrossTxn extends CreateTriggerBase { - when: 'commit', - strict?: 'takeEasy' | 'makeSure'; -}; - -export type CreateTrigger = CreateTriggerInTxn | CreateTriggerCrossTxn; - - -export interface UpdateTriggerBase { - entity: T; - name: string; - action: Exclude | 'update', - attributes?: keyof ED[T]['OpSchema'] | Array; - check?: (operation: DeduceUpdateOperation) => boolean; - fn: (event: { operation: DeduceUpdateOperation }, context: RuntimeContext, params?: Object) => Promise; -}; - -export interface UpdateTriggerInTxn extends UpdateTriggerBase { - when: 'before' | 'after', -}; - -export interface UpdateTriggerCrossTxn extends UpdateTriggerBase { - when: 'commit', - strict?: 'takeEasy' | 'makeSure'; -}; - -export type UpdateTrigger = UpdateTriggerInTxn | UpdateTriggerCrossTxn; - - -export interface RemoveTriggerBase { - entity: T; - name: string; - action: 'remove', - check?: (operation: DeduceRemoveOperation) => boolean; - fn: (event: { operation: DeduceRemoveOperation }, context: RuntimeContext, params?: Object) => Promise; -}; - -export interface RemoveTriggerInTxn extends RemoveTriggerBase { - when: 'before' | 'after', -}; - -export interface RemoveTriggerCrossTxn extends RemoveTriggerBase { - when: 'commit', - strict?: 'takeEasy' | 'makeSure'; -}; - -export type RemoveTrigger = RemoveTriggerInTxn | RemoveTriggerCrossTxn; - - -export interface SelectTriggerBase { - entity: T; - name: string; - action: 'select'; -}; - -/** - * selection似乎不需要支持跨事务?没想清楚 - * todo by Xc - */ -export interface SelectTriggerBefore extends SelectTriggerBase { - when: 'before'; - fn: (event: { operation: DeduceSelection }, context: RuntimeContext, params?: Object) => Promise; -}; - -export interface SelectTriggerAfter extends SelectTriggerBase { - when: 'after', - fn: (event: { - operation: S; - result: SelectionResult2; - }, context: RuntimeContext, params?: Object) => Promise; -}; - -export type SelectTrigger = SelectTriggerBefore | SelectTriggerAfter; - -export type Trigger = CreateTrigger | UpdateTrigger | RemoveTrigger | SelectTrigger; - -export interface TriggerEntityShape extends EntityShape { - $$triggerData$$?: { - name: string; - operation: object; - }; - $$triggerTimestamp$$?: number; -}; - -export abstract class Executor { - static dataAttr: TriggerDataAttribute = '$$triggerData$$'; - static timestampAttr: TriggerTimestampAttribute = '$$triggerTimestamp$$'; - - abstract registerTrigger(trigger: Trigger): void; - - abstract preOperation( - entity: T, - operation: ED[T]['Operation'], - context: RuntimeContext - ): Promise; - - abstract postOperation( - entity: T, - operation: ED[T]['Operation'], - context: RuntimeContext - ): Promise; - - abstract checkpoint(context: RuntimeContext, timestamp: number): Promise; // 将所有在timestamp之前存在不一致的数据进行恢复 -} diff --git a/src/utils/TriggerExecutor.d.ts b/src/utils/TriggerExecutor.d.ts deleted file mode 100644 index 4a42240b2..000000000 --- a/src/utils/TriggerExecutor.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { EntityDict } from "oak-domain/lib/types/Entity"; -import { Logger } from "oak-domain/lib/types/Logger"; -import { Checker } from '../types/Auth'; -import { RuntimeContext } from '../types/RuntimeContext'; -import { Trigger, Executor } from "../types/Trigger"; -export declare class TriggerExecutor extends Executor { - private triggerMap; - private triggerNameMap; - private volatileEntities; - private logger; - constructor(logger?: Logger); - registerChecker(checker: Checker): void; - registerTrigger(trigger: Trigger): void; - private preCommitTrigger; - preOperation(entity: T, operation: ED[T]['Operation'], context: RuntimeContext): Promise; - private onCommit; - private postCommitTrigger; - postOperation(entity: T, operation: ED[T]['Operation'], context: RuntimeContext): Promise; - checkpoint(context: RuntimeContext, timestamp: number): Promise; -} diff --git a/src/utils/TriggerExecutor.js b/src/utils/TriggerExecutor.js deleted file mode 100644 index af83709ca..000000000 --- a/src/utils/TriggerExecutor.js +++ /dev/null @@ -1,215 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.TriggerExecutor = void 0; -const assert_1 = __importDefault(require("assert")); -const lodash_1 = require("lodash"); -const filter_1 = require("oak-domain/lib/store/filter"); -const Trigger_1 = require("../types/Trigger"); -class TriggerExecutor extends Trigger_1.Executor { - triggerMap; - triggerNameMap; - volatileEntities; - logger; - constructor(logger = console) { - super(); - this.logger = logger; - this.triggerMap = {}; - this.triggerNameMap = {}; - this.volatileEntities = []; - } - registerChecker(checker) { - const { entity, action, checker: checkFn } = checker; - const ActionNameMatrix = { - 'create': '创建', - 'remove': '删除', - }; - let triggerAction = ActionNameMatrix[action] || '更新'; - const triggerName = `${entity}${triggerAction}权限检查`; - const trigger = { - name: triggerName, - entity, - action, - fn: checkFn, - when: 'before', - }; - this.registerTrigger(trigger); - } - registerTrigger(trigger) { - // trigger的两种访问方式: by name, by entity/action - if (this.triggerNameMap.hasOwnProperty(trigger.name)) { - throw new Error(`不可有同名的触发器「${trigger.name}」`); - } - (0, lodash_1.assign)(this.triggerNameMap, { - [trigger.name]: trigger, - }); - const triggers = this.triggerMap[trigger.entity] && this.triggerMap[trigger.entity][trigger.action]; - if (triggers) { - triggers.push(trigger); - } - else if (this.triggerMap[trigger.entity]) { - (0, lodash_1.assign)(this.triggerMap[trigger.entity], { - [trigger.action]: [trigger], - }); - } - else { - (0, lodash_1.assign)(this.triggerMap, { - [trigger.entity]: { - [trigger.action]: [trigger], - } - }); - } - if (trigger.when === 'commit' && trigger.strict === 'makeSure') { - if (this.volatileEntities.indexOf(trigger.entity) === -1) { - this.volatileEntities.push(trigger.entity); - } - } - } - async preCommitTrigger(entity, operation, trigger, context) { - (0, assert_1.default)(trigger.action !== 'select'); - if (trigger.strict === 'makeSure') { - switch (operation.action) { - case 'create': { - if (operation.data.hasOwnProperty(Trigger_1.Executor.dataAttr) || operation.data.hasOwnProperty(Trigger_1.Executor.timestampAttr)) { - throw new Error('同一行数据上不能存在两个跨事务约束'); - } - break; - } - default: { - const { filter } = operation; - // 此时要保证更新或者删除的行上没有跨事务约束 - const filter2 = (0, filter_1.addFilterSegment)({ - $or: [ - { - $$triggerData$$: { - $exists: true, - }, - }, - { - $$triggerTimestamp$$: { - $exists: true, - }, - } - ], - }, filter); - const { rowStore } = context; - const count = await rowStore.count(entity, { - filter: filter2 - }, context); - if (count > 0) { - throw new Error(`对象${entity}的行「${JSON.stringify(operation)}」上已经存在未完成的跨事务约束`); - } - break; - } - } - (0, lodash_1.assign)(operation.data, { - [Trigger_1.Executor.dataAttr]: { - name: trigger.name, - operation, - }, - [Trigger_1.Executor.timestampAttr]: Date.now(), - }); - } - } - async preOperation(entity, operation, context) { - const triggers = this.triggerMap[entity] && this.triggerMap[entity][operation.action]; - if (triggers) { - const preTriggers = triggers.filter(ele => ele.when === 'before' && (!ele.check || ele.check(operation))); - for (const trigger of preTriggers) { - const number = await trigger.fn({ operation: operation }, context); - if (number > 0) { - this.logger.info(`触发器「${trigger.name}」成功触发了「${number}」行数据更改`); - } - } - const commitTriggers = triggers.filter(ele => ele.when === 'commit' && (!ele.check || ele.check(operation))); - for (const trigger of commitTriggers) { - await this.preCommitTrigger(entity, operation, trigger, context); - } - } - } - onCommit(trigger, operation) { - return async (context) => { - await context.begin(); - const number = await trigger.fn({ - operation: operation, - }, context); - const { rowStore } = context; - if (trigger.strict === 'makeSure') { - // 如果是必须完成的trigger,在完成成功后要把trigger相关的属性置null; - let filter = {}; - if (operation.action === 'create') { - filter = operation.data instanceof Array ? { - filter: { - id: { - $in: operation.data.map(ele => ele.id), - }, - }, - } : { - filter: { - id: operation.data.id, - } - }; - } - else if (operation.filter) { - (0, lodash_1.assign)(filter, { filter: operation.filter }); - } - await rowStore.operate(trigger.entity, { - action: 'update', - data: { - $$triggerTimestamp$$: null, - $$triggerData$$: null, - }, - ...filter /** as Filter<'update', DeduceFilter> */, - }, context); - } - await context.commit(); - return; - }; - } - async postCommitTrigger(operation, trigger, context) { - context.on('commit', this.onCommit(trigger, operation)); - } - async postOperation(entity, operation, context) { - const triggers = this.triggerMap[entity] && this.triggerMap[entity][operation.action]; - if (triggers) { - const postTriggers = triggers.filter(ele => ele.when === 'after' && (!ele.check || ele.check(operation))); - for (const trigger of postTriggers) { - const number = await trigger.fn({ operation: operation }, context); - if (number > 0) { - this.logger.info(`触发器「${trigger.name}」成功触发了「${number}」行数据更改`); - } - } - const commitTriggers = triggers.filter(ele => ele.when === 'commit' && (!ele.check || ele.check(operation))); - for (const trigger of commitTriggers) { - await this.postCommitTrigger(operation, trigger, context); - } - } - } - async checkpoint(context, timestamp) { - let result = 0; - const { rowStore } = context; - for (const entity of this.volatileEntities) { - const { result: rows } = await rowStore.select(entity, { - data: { - id: 1, - $$triggerData$$: 1, - }, - filter: { - $$triggerTimestamp$$: { - $gt: timestamp, - } - }, - }, context); - for (const row of rows) { - const { $$triggerData$$ } = row; - const { name, operation } = $$triggerData$$; - const trigger = this.triggerNameMap[name]; - await this.onCommit(trigger, operation)(context); - } - } - return result; - } -} -exports.TriggerExecutor = TriggerExecutor; diff --git a/src/utils/TriggerExecutor.ts b/src/utils/TriggerExecutor.ts deleted file mode 100644 index 4ada5e97e..000000000 --- a/src/utils/TriggerExecutor.ts +++ /dev/null @@ -1,268 +0,0 @@ -import assert from 'assert'; -import { assign } from "lodash"; -import { addFilterSegment } from "oak-domain/lib/store/filter"; -import { DeduceCreateOperation, DeduceCreateOperationData, EntityDict } from "oak-domain/lib/types/Entity"; -import { Logger } from "oak-domain/lib/types/Logger"; -import { Checker } from '../types/Auth'; -import { RuntimeContext } from '../types/RuntimeContext'; -import { Trigger, Executor, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerInTxn } from "../types/Trigger"; - -export class TriggerExecutor extends Executor { - private triggerMap: { - [T in keyof ED]?: { - [A: string]: Array>; - }; - }; - private triggerNameMap: { - [N: string]: Trigger; - }; - private volatileEntities: Array; - - private logger: Logger; - - constructor(logger: Logger = console) { - super(); - this.logger = logger; - this.triggerMap = {}; - this.triggerNameMap = {}; - this.volatileEntities = []; - } - - registerChecker(checker: Checker): void { - const { entity, action, checker: checkFn } = checker; - const ActionNameMatrix: Record = { - 'create': '创建', - 'remove': '删除', - }; - let triggerAction = ActionNameMatrix[action] || '更新'; - const triggerName = `${entity}${triggerAction}权限检查`; - - const trigger = { - name: triggerName, - entity, - action, - fn: checkFn, - when: 'before', - } as CreateTriggerInTxn; - this.registerTrigger(trigger); - } - - registerTrigger(trigger: Trigger): void { - // trigger的两种访问方式: by name, by entity/action - if (this.triggerNameMap.hasOwnProperty(trigger.name)) { - throw new Error(`不可有同名的触发器「${trigger.name}」`); - } - assign(this.triggerNameMap, { - [trigger.name]: trigger, - }); - - const triggers = this.triggerMap[trigger.entity] && this.triggerMap[trigger.entity]![trigger.action]; - if (triggers) { - triggers.push(trigger); - } - else if (this.triggerMap[trigger.entity]) { - assign(this.triggerMap[trigger.entity], { - [trigger.action]: [trigger], - }); - } - else { - assign(this.triggerMap, { - [trigger.entity]: { - [trigger.action]: [trigger], - } - }); - } - - if (trigger.when === 'commit' && trigger.strict === 'makeSure') { - if (this.volatileEntities.indexOf(trigger.entity) === -1) { - this.volatileEntities.push(trigger.entity); - } - } - } - - private async preCommitTrigger( - entity: T, - operation: ED[T]['Operation'], - trigger: Trigger, - context: RuntimeContext, - ) { - assert(trigger.action !== 'select'); - if ((trigger as CreateTriggerCrossTxn).strict === 'makeSure') { - switch (operation.action) { - case 'create': { - if (operation.data.hasOwnProperty(Executor.dataAttr) || operation.data.hasOwnProperty(Executor.timestampAttr)) { - throw new Error('同一行数据上不能存在两个跨事务约束'); - } - break; - } - default: { - const { filter } = operation; - // 此时要保证更新或者删除的行上没有跨事务约束 - const filter2 = addFilterSegment({ - $or: [ - { - $$triggerData$$: { - $exists: true, - }, - }, - { - $$triggerTimestamp$$: { - $exists: true, - }, - } - ], - }, filter); - const { rowStore } = context; - const count = await rowStore.count(entity, { - filter: filter2 - } as Omit, context); - if (count > 0) { - throw new Error(`对象${entity}的行「${JSON.stringify(operation)}」上已经存在未完成的跨事务约束`); - } - break; - } - } - - assign(operation.data, { - [Executor.dataAttr]: { - name: trigger.name, - operation, - }, - [Executor.timestampAttr]: Date.now(), - }); - } - } - - async preOperation( - entity: T, - operation: ED[T]['Operation'], - context: RuntimeContext - ): Promise { - const triggers = this.triggerMap[entity] && this.triggerMap[entity]![operation.action]; - if (triggers) { - const preTriggers = triggers.filter( - ele => ele.when === 'before' && (!(ele as CreateTrigger).check || (ele as CreateTrigger).check!(operation as DeduceCreateOperation)) - ); - - for (const trigger of preTriggers) { - const number = await (trigger as CreateTrigger).fn({ operation: operation as DeduceCreateOperation }, context); - if (number > 0) { - this.logger.info(`触发器「${trigger.name}」成功触发了「${number}」行数据更改`); - } - } - - const commitTriggers = triggers.filter( - ele => ele.when === 'commit' && (!(ele as CreateTrigger).check || (ele as CreateTrigger).check!(operation as DeduceCreateOperation)) - ); - - for (const trigger of commitTriggers) { - await this.preCommitTrigger(entity, operation, trigger, context); - } - } - } - - private onCommit( - trigger: Trigger, operation: ED[T]['Operation']) { - return async (context: RuntimeContext) => { - await context.begin(); - const number = await (trigger as CreateTrigger).fn({ - operation: operation as DeduceCreateOperation, - }, context); - const { rowStore } = context; - if ((trigger as CreateTriggerCrossTxn).strict === 'makeSure') { - // 如果是必须完成的trigger,在完成成功后要把trigger相关的属性置null; - let filter = {}; - if (operation.action === 'create') { - filter = operation.data instanceof Array ? { - filter: { - id: { - $in: operation.data.map(ele => (ele.id as string)), - }, - }, - } : { - filter: { - id: (operation.data.id as string), - } - }; - } - else if (operation.filter) { - assign(filter, { filter: operation.filter }); - } - - await rowStore.operate(trigger.entity, { - action: 'update', - data: { - $$triggerTimestamp$$: null, - $$triggerData$$: null, - } as any, - ...filter /** as Filter<'update', DeduceFilter> */, - }, context); - } - - await context.commit(); - return; - }; - } - - private async postCommitTrigger( - operation: ED[T]['Operation'], - trigger: Trigger, - context: RuntimeContext - ) { - context.on('commit', this.onCommit(trigger, operation)); - } - - async postOperation( - entity: T, - operation: ED[T]['Operation'], - context: RuntimeContext - ): Promise { - const triggers = this.triggerMap[entity] && this.triggerMap[entity]![operation.action]; - if (triggers) { - const postTriggers = triggers.filter( - ele => ele.when === 'after' && (!(ele as CreateTrigger).check || (ele as CreateTrigger).check!(operation as DeduceCreateOperation)) - ); - - for (const trigger of postTriggers) { - const number = await (trigger as CreateTrigger).fn({ operation: operation as DeduceCreateOperation }, context); - if (number > 0) { - this.logger.info(`触发器「${trigger.name}」成功触发了「${number}」行数据更改`); - } - } - - const commitTriggers = (>>triggers).filter( - ele => ele.when === 'commit' && (!ele.check || ele.check(operation as DeduceCreateOperation)) - ); - - for (const trigger of commitTriggers) { - await this.postCommitTrigger(operation, trigger, context); - } - } - } - - async checkpoint(context: RuntimeContext, timestamp: number): Promise { - let result = 0; - const { rowStore } = context; - for (const entity of this.volatileEntities) { - const { result: rows } = await rowStore.select(entity, { - data: { - id: 1, - $$triggerData$$: 1, - }, - filter: { - $$triggerTimestamp$$: { - $gt: timestamp, - } - }, - } as any, context); - for (const row of rows) { - const { $$triggerData$$ } = row; - const { name, operation } = $$triggerData$$!; - const trigger = this.triggerNameMap[name]; - await this.onCommit(trigger, operation as ED[typeof entity]['Operation'])(context); - } - - } - return result; - } -} diff --git a/src/utils/check.ts b/src/utils/check.ts index 733be18d6..3fff1101e 100644 --- a/src/utils/check.ts +++ b/src/utils/check.ts @@ -1,4 +1,4 @@ -import { AttrIllegalError } from "../types/Auth"; +import { AttrIllegalError } from "oak-domain/lib/types"; export function checkAttributesNotNull>(data: T, attributes: Array, allowEmpty?: true) { const attrs = attributes.filter( diff --git a/test/build-test-domain.ts b/test/build-test-domain.ts new file mode 100644 index 000000000..c0272385b --- /dev/null +++ b/test/build-test-domain.ts @@ -0,0 +1,6 @@ +import { unset } from 'lodash'; +import { buildSchema, analyzeEntities } from 'oak-domain/src/compiler/schemalBuilder'; + +analyzeEntities(`${__dirname}/../node_modules/oak-domain/src/entities`); +analyzeEntities(`${__dirname}/entities`); +buildSchema(`${__dirname}/app-domain`); \ No newline at end of file diff --git a/test/entities/House.ts b/test/entities/House.ts new file mode 100644 index 000000000..76be69e05 --- /dev/null +++ b/test/entities/House.ts @@ -0,0 +1,12 @@ +import { String, Int, Datetime, Image, Boolean, Text } from 'oak-domain/lib/types/DataType'; +import { Schema as Area } from 'oak-domain/lib/entities/Area'; +import { Schema as User } from 'oak-domain/lib/entities/User'; +import { Schema as ExtraFile } from 'oak-domain/lib/entities/ExtraFile'; +import { EntityShape } from 'oak-domain/lib/types/Entity'; + +export interface Schema extends EntityShape { + district: String<16>; + area: Area; + owner: User; + dd: Array; +}; diff --git a/tsconfig.json b/tsconfig.json index 7419fedaa..96eed58ae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -61,6 +61,7 @@ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ + "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true /* Disallow inconsistently-cased references to the same file. */ },