修正了log结构,更正了查询数据时的一些细节

This commit is contained in:
Xu Chang 2024-09-19 15:06:02 +08:00
parent 311555e008
commit 8adec9d3c1
16 changed files with 114 additions and 132 deletions

View File

@ -1,7 +1,5 @@
export declare const actionDefDict: {
log: {
iState: import("../types").ActionDef<string, string>;
};
log: {};
modi: {
iState: import("../types").ActionDef<string, string>;
};

View File

@ -1,12 +1,6 @@
import { ActionDef } from "../../types/Action";
import { GenericAction } from "../../actions/action";
export type IState = 'normal' | 'rollbacked' | string;
export type State = IState | string;
export type IAction = 'undo' | 'redo' | string;
export type ParticularAction = IAction;
export declare const actions: string[];
export declare const IActionDef: ActionDef<IAction, IState>;
export type Action = GenericAction | ParticularAction | string;
export declare const actionDefDict: {
iState: ActionDef<string, string>;
};
export declare const actionDefDict: {};

View File

@ -1,14 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.actionDefDict = exports.IActionDef = exports.actions = void 0;
exports.actionDefDict = exports.actions = void 0;
exports.actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "undo", "redo"];
exports.IActionDef = {
stm: {
undo: ['normal', 'rollbacked'],
redo: ['rollbacked', 'normal'],
},
is: 'normal',
};
exports.actionDefDict = {
iState: exports.IActionDef
};
exports.actionDefDict = {};

View File

@ -1,7 +1,7 @@
import { Q_DateValue, Q_NumberValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey, SubQueryPredicateMetadata } from "../../types/Demand";
import { OneOf } from "../../types/Polyfill";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, AggregationResult, EntityShape } from "../../types/Entity";
import { Action, ParticularAction, IState } from "./Action";
import { Action, ParticularAction } from "./Action";
import { String } from "../../types/DataType";
import * as Oper from "../Oper/Schema";
import * as ModiEntity from "../ModiEntity/Schema";
@ -9,13 +9,13 @@ import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & {
entity: String<32>;
entityId: String<64>;
iState?: IState | null;
iState: "normal" | "rollbacked";
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
entity: String<32>;
entityId: String<64>;
iState?: IState | null;
iState: "normal" | "rollbacked";
oper$log?: Array<Oper.Schema>;
oper$log$$aggr?: AggregationResult<Oper.Schema>;
modiEntity$entity?: Array<ModiEntity.Schema>;
@ -32,7 +32,7 @@ type AttrFilter = {
$$updateAt$$: Q_DateValue;
entity: Q_StringValue;
entityId: Q_StringValue;
iState: Q_EnumValue<IState>;
iState: Q_EnumValue<"normal" | "rollbacked">;
oper$log: Oper.Filter & SubQueryPredicateMetadata;
modiEntity$entity: ModiEntity.Filter & SubQueryPredicateMetadata;
operEntity$entity: OperEntity.Filter & SubQueryPredicateMetadata;

View File

@ -19,6 +19,7 @@ exports.desc = {
}
},
iState: {
notNull: true,
type: "enum",
enumeration: ["normal", "rollbacked"]
}

View File

@ -6,10 +6,4 @@ exports.style = {
undo: '',
redo: '',
},
color: {
iState: {
normal: '#229954',
rollbacked: '#2C3E50',
},
},
};

View File

@ -1,16 +1,11 @@
import { ActionDef } from '../types/Action';
import { String } from '../types/DataType';
import { EntityShape } from '../types/Entity';
import { EntityDesc } from '../types/EntityDesc';
export interface Schema extends EntityShape {
entity: String<32>;
entityId: String<64>;
iState: 'normal' | 'rollbacked';
}
export type IState = 'normal' | 'rollbacked';
export type State = IState;
export type IAction = 'undo' | 'redo';
export type Action = IAction;
export declare const IActionDef: ActionDef<IAction, IState>;
export declare const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState;
}>;
export declare const entityDesc: EntityDesc<Schema, Action>;

View File

@ -1,14 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.entityDesc = exports.IActionDef = void 0;
exports.entityDesc = void 0;
;
exports.IActionDef = {
stm: {
undo: ['normal', 'rollbacked'],
redo: ['rollbacked', 'normal'],
},
is: 'normal',
};
exports.entityDesc = {
locales: {
zh_CN: {
@ -35,11 +28,5 @@ exports.entityDesc = {
undo: '',
redo: '',
},
color: {
iState: {
normal: '#229954',
rollbacked: '#2C3E50',
},
},
},
};

View File

@ -22,8 +22,8 @@ class CascadeStore extends RowStore_1.RowStore {
selectionRewriters = [];
operationRewriters = [];
async reinforceSelectionAsync(entity, selection, context, option, isAggr) {
if (!isAggr && !selection.distinct && !option.dontCollect) {
this.reinforceSelectionInner(entity, selection, context);
if (!isAggr && !selection.distinct) {
this.reinforceSelectionInner(entity, selection, context, option);
}
const rewriterPromises = this.selectionRewriters.map(ele => ele(this.getSchema(), entity, selection, context, option, isAggr));
if (rewriterPromises.length > 0) {
@ -32,14 +32,14 @@ class CascadeStore extends RowStore_1.RowStore {
}
reinforceSelectionSync(entity, selection, context, option, isAggr) {
if (!isAggr && !selection.distinct) {
this.reinforceSelectionInner(entity, selection, context);
this.reinforceSelectionInner(entity, selection, context, option);
}
this.selectionRewriters.forEach(ele => {
const result = ele(this.getSchema(), entity, selection, context, option, isAggr);
(0, assert_1.default)(!(result instanceof Promise));
});
}
reinforceSelectionInner(entity, selection, context) {
reinforceSelectionInner(entity, selection, context, option) {
const { filter, data, sorter } = selection;
const assignNecessaryProjectionAttrs = (projectionNode, attrs) => {
attrs.forEach((attr) => {
@ -240,7 +240,7 @@ class CascadeStore extends RowStore_1.RowStore {
else {
assignNecessaryProjectionAttrs(data, ['entity', 'entityId']);
}
this.reinforceSelectionInner(rel[0], projectionNode[attr], context);
this.reinforceSelectionInner(rel[0], projectionNode[attr], context, option);
}
}
}
@ -272,7 +272,7 @@ class CascadeStore extends RowStore_1.RowStore {
// 如果对象上有relation关系在此将本用户相关的relation和actionAuth全部取出
// 还要将actionAuth上没有relation关系但destEntity为本对象的行也全部取出这些是指向userId的可能路径
// 放在这里有点怪异,暂先这样
if (context instanceof AsyncRowStore_1.AsyncContext) {
if (context instanceof AsyncRowStore_1.AsyncContext && !option.dontCollect) {
const userId = context.getCurrentUserId(true);
if (userId && !entities_1.SYSTEM_RESERVE_ENTITIES.includes(entity2)) {
if (this.getSchema()[entity2].relation && !projectionNode.userRelation$entity) {
@ -335,10 +335,12 @@ class CascadeStore extends RowStore_1.RowStore {
const cascadeSelectionFns = [];
const supportMtoJoin = this.supportManyToOneJoin();
const { toModi } = this.getSchema()[entity];
const projection = {};
(0, assert_1.default)(typeof projection2 === 'object');
for (const attr in projection2) {
const relation = (0, relation_1.judgeRelation)(this.storageSchema, entity, attr);
if (relation === 1 || relation == 0) {
projection[attr] = projection2[attr];
}
else if (relation === 2) {
// 基于entity/entityId的多对一
@ -368,6 +370,7 @@ class CascadeStore extends RowStore_1.RowStore {
subCascadeSelectionFns.forEach(ele => cascadeSelectionFns.push((result) => {
return ele(result.map(ele2 => ele2[attr]).filter(ele2 => !!ele2));
}));
projection[attr] = subProjection;
}
else {
cascadeSelectionFns.push((result) => {
@ -455,6 +458,7 @@ class CascadeStore extends RowStore_1.RowStore {
subCascadeSelectionFns.forEach(ele => cascadeSelectionFns.push((result) => {
return ele(result.map(ele2 => ele2[attr]).filter(ele2 => !!ele2));
}));
projection[attr] = subProjection;
}
else {
cascadeSelectionFns.push((result) => {
@ -644,7 +648,7 @@ class CascadeStore extends RowStore_1.RowStore {
}
}
return {
projection: projection2,
projection,
cascadeSelectionFns,
};
}
@ -702,7 +706,7 @@ class CascadeStore extends RowStore_1.RowStore {
option2.modiParentEntity = entity;
}
}
if (toLog && action !== 'create') {
if (toLog && action !== 'create' && !option.dontCreateOper) {
// 此对象及其下辖的cascade更新都需要记录log)
(0, assert_1.default)(typeof filter.id === 'string');
(0, assert_1.default)(!option2.logId, 'undo无法支持嵌套');
@ -714,6 +718,7 @@ class CascadeStore extends RowStore_1.RowStore {
id: (0, uuid_1.generateNewId)(),
data: {
id: logId,
iState: 'normal',
},
action: 'create',
}

View File

@ -79,7 +79,7 @@ function createUniqueCheckers(schema) {
entity,
action: 'create',
type: 'logicalData',
priority: types_1.CHECKER_MAX_PRIORITY, // 优先级要放在最低所有前置的checker/trigger将数据完整之后再在这里检测
priority: types_1.CHECKER_MAX_PRIORITY,
checker: (operation, context) => {
const { data } = operation;
if (data instanceof Array) {
@ -95,9 +95,9 @@ function createUniqueCheckers(schema) {
}
}, {
entity,
action: 'update', // 只检查update其它状态转换的action应该不会涉及unique约束的属性
action: 'update',
type: 'logicalData',
priority: types_1.CHECKER_MAX_PRIORITY, // 优先级要放在最低所有前置的checker/trigger将数据完整之后再在这里检测
priority: types_1.CHECKER_MAX_PRIORITY,
checker: (operation, context) => {
const { data, filter: operationFilter } = operation;
if (data) {
@ -227,7 +227,7 @@ function createActionTransformerCheckers(actionDefDict) {
action: 'create',
type: 'logical',
entity,
priority: 10, // 优先级要高先于真正的data检查进行
priority: 10,
checker: (operation) => {
const { data } = operation;
if (data instanceof Array) {

View File

@ -46,7 +46,6 @@ async function undoLog(log, context) {
filter: filter,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -61,7 +60,6 @@ async function undoLog(log, context) {
data: undoData[id],
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -81,7 +79,6 @@ async function undoLog(log, context) {
}
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -89,20 +86,24 @@ async function undoLog(log, context) {
}
}
}
await context.operate('oper', {
await context.operate('log', {
id: 'dummy',
action: 'undo',
data: {
iState: 'rollbacked',
oper$log: {
id: 'dummy',
action: 'undo',
data: {
iState: 'rollbacked',
},
},
},
filter: {
id: {
$in: oper$log.map(ele => ele.id)
}
}
id: log.id,
},
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -124,7 +125,6 @@ async function redoLog(log, context) {
data: data,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -137,7 +137,6 @@ async function redoLog(log, context) {
filter: filter,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -150,27 +149,30 @@ async function redoLog(log, context) {
filter: filter,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
}
}
}
await context.operate('oper', {
await context.operate('log', {
id: 'dummy',
action: 'redo',
data: {
iState: 'normal',
oper$log: {
id: 'dummy',
action: 'redo',
data: {
iState: 'normal',
},
},
},
filter: {
id: {
$in: oper$log.map(ele => ele.id)
}
}
id: log.id,
},
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -201,11 +203,12 @@ exports.logTriggers = [
},
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
id: ids[0],
},
}, {});
}, { dontCollect: true });
const logs = await context.select('log', {
data: {
id: 1,
@ -217,8 +220,13 @@ exports.logTriggers = [
action: 1,
targetEntity: 1,
filter: 1,
iState: 1,
},
},
iState: 1,
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
iState: 'normal',
@ -271,11 +279,12 @@ exports.logTriggers = [
iState: 1,
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
id: ids[0],
},
}, {});
}, { dontCollect: true });
const logs = await context.select('log', {
data: {
id: 1,
@ -287,8 +296,13 @@ exports.logTriggers = [
action: 1,
targetEntity: 1,
filter: 1,
iState: 1,
},
},
iState: 1,
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
iState: 'rollbacked',

View File

@ -1,4 +1,3 @@
/// <reference types="node" />
/**
* assert打包体积过大
*/

View File

@ -60,7 +60,7 @@ function destructRelationPath(schema, entity, path, relationFilter, recursive) {
},
filter: relationFilter,
} // as ED['userRelation']['Selection']
}, // as ED[keyof ED]['Selection']['data'],
},
getData: (d) => {
return d.userRelation$entity;
},

View File

@ -6,24 +6,14 @@ import { EntityDesc } from '../types/EntityDesc';
export interface Schema extends EntityShape {
entity: String<32>; // 关联的目标对象
entityId: String<64>; // 关联的目标对象id
iState: 'normal' | 'rollbacked';
};
export type IState = 'normal' | 'rollbacked';
export type State = IState;
export type IAction = 'undo' | 'redo';
export type Action = IAction;
export const IActionDef: ActionDef<IAction, IState> = {
stm: {
undo: ['normal', 'rollbacked'],
redo: ['rollbacked', 'normal'],
},
is: 'normal',
};
export const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState,
}> = {
export const entityDesc: EntityDesc<Schema, Action> = {
locales: {
zh_CN: {
name: '日志',
@ -49,11 +39,5 @@ export const entityDesc: EntityDesc<Schema, Action, '', {
undo: '',
redo: '',
},
color: {
iState: {
normal: '#229954',
rollbacked: '#2C3E50',
},
},
},
};

View File

@ -37,8 +37,8 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
option: Op,
isAggr?: true) {
if (!isAggr && !selection.distinct && !option.dontCollect) {
this.reinforceSelectionInner(entity, selection, context);
if (!isAggr && !selection.distinct) {
this.reinforceSelectionInner(entity, selection, context, option);
}
const rewriterPromises = this.selectionRewriters.map(
@ -58,7 +58,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
isAggr?: true
) {
if (!isAggr && !selection.distinct) {
this.reinforceSelectionInner(entity, selection, context);
this.reinforceSelectionInner(entity, selection, context, option);
}
this.selectionRewriters.forEach(
@ -69,10 +69,11 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
);
}
private reinforceSelectionInner<Cxt extends AsyncContext<ED> | SyncContext<ED>>(
private reinforceSelectionInner<Cxt extends AsyncContext<ED> | SyncContext<ED>, Op extends SelectOption>(
entity: keyof ED,
selection: ED[keyof ED]['Selection'] | ED[keyof ED]['Aggregation'],
context: Cxt,
option: Op
) {
const { filter, data, sorter } = selection;
@ -299,7 +300,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
else {
assignNecessaryProjectionAttrs(data, ['entity', 'entityId']);
}
this.reinforceSelectionInner(rel[0], projectionNode[attr], context);
this.reinforceSelectionInner(rel[0], projectionNode[attr], context, option);
}
}
}
@ -333,7 +334,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
// 如果对象上有relation关系在此将本用户相关的relation和actionAuth全部取出
// 还要将actionAuth上没有relation关系但destEntity为本对象的行也全部取出这些是指向userId的可能路径
// 放在这里有点怪异,暂先这样
if (context instanceof AsyncContext) {
if (context instanceof AsyncContext && !option.dontCollect) {
const userId = context.getCurrentUserId(true);
if (userId && !SYSTEM_RESERVE_ENTITIES.includes(entity2 as string)) {
if (this.getSchema()[entity2].relation && !projectionNode.userRelation$entity) {
@ -463,11 +464,13 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
const supportMtoJoin = this.supportManyToOneJoin();
const { toModi } = this.getSchema()[entity];
const projection: ED[T]['Selection']['data'] = {};
assert(typeof projection2 === 'object');
for (const attr in projection2) {
const relation = judgeRelation(this.storageSchema, entity, attr);
if (relation === 1 || relation == 0) {
projection[attr] = projection2[attr];
}
else if (relation === 2) {
// 基于entity/entityId的多对一
@ -508,6 +511,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
)
);
projection[attr] = subProjection as any;
}
else {
cascadeSelectionFns.push(
@ -621,6 +625,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
)
);
projection[attr] = subProjection as any;
}
else {
cascadeSelectionFns.push(
@ -855,7 +860,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
return {
projection: projection2,
projection,
cascadeSelectionFns,
}
}
@ -928,7 +933,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
}
if (toLog && action !== 'create') {
if (toLog && action !== 'create' && !option.dontCreateOper) {
// 此对象及其下辖的cascade更新都需要记录log)
assert(typeof filter!.id === 'string');
assert(!option2.logId, 'undo无法支持嵌套');
@ -940,6 +945,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
id: generateNewId(),
data: {
id: logId,
iState: 'normal',
},
action: 'create',
}

View File

@ -48,7 +48,6 @@ async function undoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
filter: filter!,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -63,7 +62,6 @@ async function undoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
data: (undoData as any)[id],
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -83,7 +81,6 @@ async function undoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
}
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -92,20 +89,24 @@ async function undoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
}
}
await context.operate('oper', {
await context.operate('log', {
id: 'dummy',
action: 'undo',
data: {
iState: 'rollbacked',
oper$log: {
id: 'dummy',
action: 'undo',
data: {
iState: 'rollbacked',
},
},
},
filter: {
id: {
$in: oper$log!.map(ele => ele.id!)
}
}
id: log.id,
},
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -128,7 +129,6 @@ async function redoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
data: data!,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -141,7 +141,6 @@ async function redoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
filter: filter!,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -154,7 +153,6 @@ async function redoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
filter: filter!,
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
break;
@ -162,20 +160,24 @@ async function redoLog(log: BaseEntityDict['log']['Schema'], context: AsyncConte
}
}
await context.operate('oper', {
await context.operate('log', {
id: 'dummy',
action: 'redo',
data: {
iState: 'normal',
oper$log: {
id: 'dummy',
action: 'redo',
data: {
iState: 'normal',
},
},
},
filter: {
id: {
$in: oper$log!.map(ele => ele.id!)
}
}
id: log.id,
},
}, {
blockTrigger: true,
dontCollect: true,
dontCreateOper: true,
});
}
@ -207,11 +209,12 @@ export const logTriggers: Trigger<EntityDict & BaseEntityDict, 'log', AsyncConte
},
entity: 1,
entityId: 1,
[SeqAttribute]: 1,
},
filter: {
id: ids[0],
},
}, {});
}, { dontCollect: true });
const logs = await context.select('log', {
data: {
@ -224,8 +227,13 @@ export const logTriggers: Trigger<EntityDict & BaseEntityDict, 'log', AsyncConte
action: 1,
targetEntity: 1,
filter: 1,
iState: 1,
},
},
iState: 1,
entity: 1,
entityId: 1,
[SeqAttribute]: 1,
},
filter: {
iState: 'normal',
@ -281,11 +289,12 @@ export const logTriggers: Trigger<EntityDict & BaseEntityDict, 'log', AsyncConte
iState: 1,
entity: 1,
entityId: 1,
[SeqAttribute]: 1,
},
filter: {
id: ids[0],
},
}, {});
}, { dontCollect: true });
const logs = await context.select('log', {
data: {
@ -298,8 +307,13 @@ export const logTriggers: Trigger<EntityDict & BaseEntityDict, 'log', AsyncConte
action: 1,
targetEntity: 1,
filter: 1,
iState: 1,
},
},
iState: 1,
entity: 1,
entityId: 1,
[SeqAttribute]: 1,
},
filter: {
iState: 'rollbacked',