Merge branch 'release'

This commit is contained in:
Xu Chang 2024-06-14 19:33:23 +08:00
commit 9b6d3d875d
11 changed files with 192 additions and 71 deletions

View File

@ -162,6 +162,7 @@ class CascadeStore extends RowStore_1.RowStore {
checkSortAttr(attr, sortAttr[attr], projNode[attr]);
}
}
assignNecessaryProjectionAttrs(projNode, necessaryAttrs);
};
sorterNode.forEach((node) => {
const { $attr } = node;

View File

@ -304,9 +304,17 @@ class TriggerExecutor {
return execPreTrigger(idx + 1);
}
}
const number = await trigger.fn({ operation: operation }, context, option);
if (number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`前触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
const closeRoot = trigger.asRoot && context.openRootMode();
try {
const number = await trigger.fn({ operation: operation }, context, option);
if (number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`前触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
}
closeRoot && closeRoot();
}
catch (err) {
closeRoot && closeRoot();
throw err;
}
return execPreTrigger(idx + 1);
};
@ -338,26 +346,41 @@ class TriggerExecutor {
(0, assert_1.default)(trigger && trigger.when === 'commit');
(0, assert_1.default)(ids.length > 0);
const { fn } = trigger;
const callback = await fn({ ids }, context, option);
if (trigger.strict === 'makeSure') {
// 这里开root模式否则还可能有权限问题
context.openRootMode();
await context.operate(entity, {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'update',
data: {
[Entity_1.TriggerDataAttribute]: null,
[Entity_1.TriggerUuidAttribute]: null,
},
filter: {
id: {
$in: ids,
}
const closeRoot = trigger.asRoot && context.openRootMode();
try {
const callback = await fn({ ids }, context, option);
if (trigger.strict === 'makeSure') {
// 这里开root模式否则还可能有权限问题
const closeRoot2 = context.openRootMode();
try {
await context.operate(entity, {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'update',
data: {
[Entity_1.TriggerDataAttribute]: null,
[Entity_1.TriggerUuidAttribute]: null,
},
filter: {
id: {
$in: ids,
}
}
}, { includedDeleted: true, blockTrigger: true });
closeRoot2 && closeRoot2();
}
}, { includedDeleted: true, blockTrigger: true });
catch (err2) {
closeRoot2 && closeRoot2();
throw err2;
}
}
if (typeof callback === 'function') {
await callback(context, option);
}
closeRoot && closeRoot();
}
if (typeof callback === 'function') {
await callback(context, option);
catch (err) {
closeRoot && closeRoot();
throw err;
}
}
/**
@ -407,12 +430,20 @@ class TriggerExecutor {
return;
}
const trigger = postTriggers[idx];
const number = await trigger.fn({
operation: operation,
result: result,
}, context, option);
if (number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`后触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
const closeRoot = trigger.asRoot && context.openRootMode();
try {
const number = await trigger.fn({
operation: operation,
result: result,
}, context, option);
if (number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`后触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
}
closeRoot && closeRoot();
}
catch (err) {
closeRoot && closeRoot();
throw err;
}
return execPostTrigger(idx + 1);
};

View File

@ -21,6 +21,7 @@ interface TriggerBase<ED extends EntityDict, T extends keyof ED> {
checkerType?: CheckerType;
entity: T;
name: string;
asRoot?: true;
priority?: number;
}
export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> extends TriggerBase<ED, T> {

View File

@ -2,3 +2,4 @@ import { EntityDict } from '../types/Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { StorageSchema } from '../types/Storage';
export declare function makeProjection<ED extends BaseEntityDict & EntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>): ED[T]["Selection"]["data"];
export declare function traverseProjection<ED extends BaseEntityDict & EntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>, projection: ED[T]['Selection']['data'], callback: <T2 extends keyof ED>(entity2: T2, projection2: ED[T2]['Selection']['data']) => void): void;

View File

@ -1,7 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeProjection = void 0;
exports.traverseProjection = exports.makeProjection = void 0;
const Entity_1 = require("../types/Entity");
const relation_1 = require("../store/relation");
function makeProjection(entity, schema) {
const { attributes } = schema[entity];
const attrs = Object.keys(attributes);
@ -13,3 +14,22 @@ function makeProjection(entity, schema) {
return projection;
}
exports.makeProjection = makeProjection;
function traverseProjection(entity, schema, projection, callback) {
const access = (entity2, proj) => {
callback(entity2, proj);
for (const attr in proj) {
const rel = (0, relation_1.judgeRelation)(schema, entity2, attr);
if (rel === 2) {
access(attr, proj[attr]);
}
else if (typeof rel === 'string') {
access(rel, proj[attr]);
}
else if (rel instanceof Array) {
access(rel[0], proj[attr].data);
}
}
};
access(entity, projection);
}
exports.traverseProjection = traverseProjection;

View File

@ -1,6 +1,6 @@
{
"name": "oak-domain",
"version": "5.0.9",
"version": "5.0.10",
"author": {
"name": "XuChang"
},

View File

@ -215,6 +215,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
checkSortAttr(attr, sortAttr[attr], projNode[attr]);
}
}
assignNecessaryProjectionAttrs(projNode, necessaryAttrs);
}
sorterNode!.forEach(
(node) => {

View File

@ -386,9 +386,17 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt extends
return execPreTrigger(idx + 1);
}
}
const number = await (trigger as CreateTriggerInTxn<ED, T, Cxt>).fn({ operation: operation as ED[T]['Create'] }, context, option as OperateOption);
if (number as number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`前触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
const closeRoot = trigger.asRoot && context.openRootMode();
try {
const number = await (trigger as CreateTriggerInTxn<ED, T, Cxt>).fn({ operation: operation as ED[T]['Create'] }, context, option as OperateOption);
if (number as number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`前触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
}
closeRoot && closeRoot();
}
catch (err: any) {
closeRoot && closeRoot();
throw err;
}
return execPreTrigger(idx + 1);
};
@ -429,27 +437,43 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt extends
assert(trigger && trigger.when === 'commit');
assert(ids.length > 0);
const { fn } = trigger as VolatileTrigger<ED, T, Cxt>;
const callback = await fn({ ids }, context, option);
if (trigger.strict === 'makeSure') {
// 这里开root模式否则还可能有权限问题
context.openRootMode();
await context.operate(entity, {
id: await generateNewIdAsync(),
action: 'update',
data: {
[TriggerDataAttribute]: null,
[TriggerUuidAttribute]: null,
},
filter: {
id: {
$in: ids,
}
}
}, { includedDeleted: true, blockTrigger: true });
}
if (typeof callback === 'function') {
await callback(context, option);
const closeRoot = trigger.asRoot && context.openRootMode();
try {
const callback = await fn({ ids }, context, option);
if (trigger.strict === 'makeSure') {
// 这里开root模式否则还可能有权限问题
const closeRoot2 = context.openRootMode();
try {
await context.operate(entity, {
id: await generateNewIdAsync(),
action: 'update',
data: {
[TriggerDataAttribute]: null,
[TriggerUuidAttribute]: null,
},
filter: {
id: {
$in: ids,
}
}
}, { includedDeleted: true, blockTrigger: true });
closeRoot2 && closeRoot2();
}
catch (err2: any) {
closeRoot2 && closeRoot2();
throw err2;
}
}
if (typeof callback === 'function') {
await callback(context, option);
}
closeRoot && closeRoot();
}
catch(err: any) {
closeRoot && closeRoot();
throw err;
}
}
@ -514,12 +538,21 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt extends
return;
}
const trigger = postTriggers[idx];
const number = await (trigger as SelectTriggerAfter<ED, T, Cxt>).fn({
operation: operation as ED[T]['Selection'],
result: result!,
}, context, option as SelectOption);
if (number as number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`后触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
const closeRoot = trigger.asRoot && context.openRootMode();
try {
const number = await (trigger as SelectTriggerAfter<ED, T, Cxt>).fn({
operation: operation as ED[T]['Selection'],
result: result!,
}, context, option as SelectOption);
if (number as number > 0 && process.env.NODE_ENV === 'development') {
this.logger.info(`后触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
}
closeRoot && closeRoot();
}
catch (err: any) {
closeRoot && closeRoot();
throw err;
}
return execPostTrigger(idx + 1);
};

View File

@ -1,4 +1,4 @@
import { EntityDict } from '../types/Entity';
import { EntityDict, TriggerUuidAttribute } from '../types/Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { AsyncContext } from '../store/AsyncRowStore';
import { vaccumEntities } from './vaccum';
@ -22,9 +22,14 @@ export type VaccumOperOption<ED extends EntityDict & BaseEntityDict> = {
export async function vaccumOper<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>>(option: VaccumOperOption<ED>, context: Cxt) {
const { aliveLine, excludeOpers, ...rest } = option;
const operFilter: ED['oper']['Selection']['filter'] = {};
const notFilters: ED['oper']['Selection']['filter'][] = [
{
[TriggerUuidAttribute]: {
$exists: false,
}
} as any,
];
if (excludeOpers) {
const notFilters: ED['oper']['Selection']['filter'][] = [];
for (const key in excludeOpers) {
if (excludeOpers[key]!.length > 0) {
notFilters.push({
@ -40,27 +45,28 @@ export async function vaccumOper<ED extends EntityDict & BaseEntityDict, Cxt ext
});
}
}
if (notFilters.length > 0) {
operFilter.$not = {
$or: notFilters as NonNullable<ED['oper']['Selection']['filter']>[],
};
}
}
return vaccumEntities({
return vaccumEntities<ED, Cxt>({
entities: [{
entity: 'operEntity',
aliveLine: aliveLine + 10000,
filter: {
oper: combineFilters('operEntity', context.getSchema(), [operFilter, {
oper: {
$$createAt$$: {
$lt: aliveLine,
}
}]),
},
$not: combineFilters('oper', context.getSchema(), notFilters),
},
},
}, {
entity: 'oper',
aliveLine,
filter: operFilter,
filter: {
$$createAt$$: {
$lt: aliveLine,
},
$not: combineFilters('oper', context.getSchema(), notFilters),
},
}],
...rest,
}, context);

View File

@ -32,6 +32,7 @@ interface TriggerBase<ED extends EntityDict, T extends keyof ED> {
checkerType?: CheckerType;
entity: T;
name: string;
asRoot?: true;
priority?: number;
};

View File

@ -1,6 +1,7 @@
import { EntityDict, PrimaryKeyAttribute, CreateAtAttribute, UpdateAtAttribute, DeleteAtAttribute } from '../types/Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { StorageSchema } from '../types/Storage';
import { judgeRelation } from '../store/relation';
export function makeProjection<ED extends BaseEntityDict & EntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>) {
const { attributes } = schema[entity];
@ -17,4 +18,29 @@ export function makeProjection<ED extends BaseEntityDict & EntityDict, T extends
);
return projection;
}
export function traverseProjection<ED extends BaseEntityDict & EntityDict, T extends keyof ED>(
entity: T,
schema: StorageSchema<ED>,
projection: ED[T]['Selection']['data'],
callback: <T2 extends keyof ED>(entity2: T2, projection2: ED[T2]['Selection']['data']) => void) {
const access = <T2 extends keyof ED>(entity2: T2, proj: ED[T2]['Selection']['data']) => {
callback(entity2, proj);
for (const attr in proj) {
const rel = judgeRelation(schema, entity2, attr);
if (rel === 2) {
access(attr, proj[attr]);
}
else if (typeof rel === 'string') {
access(rel, proj[attr]);
}
else if (rel instanceof Array) {
access(rel[0], proj[attr]!.data);
}
}
}
access(entity, projection);
}