This commit is contained in:
pqcqaq 2024-09-20 13:51:43 +08:00
commit 8592efe4e4
19 changed files with 164 additions and 139 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',
}
@ -1225,7 +1230,7 @@ class CascadeStore extends RowStore_1.RowStore {
};
const closeRootMode = context.openRootMode();
await this.cascadeUpdateAsync('oper', createOper, context, {
dontCollect: true,
dontCollect: !option.logId, // 如果是在创建log则把oper收集回去
});
closeRootMode();
}
@ -1269,6 +1274,10 @@ class CascadeStore extends RowStore_1.RowStore {
});
});
}
if (ids.length === 0) {
// 如果没有行需要更新/删除,直接返回
return {};
}
if (data) {
this.preProcessDataUpdated(action, data, true);
}
@ -1398,7 +1407,7 @@ class CascadeStore extends RowStore_1.RowStore {
};
const closeRootMode = context.openRootMode();
await this.cascadeUpdateAsync('oper', createOper, context, {
dontCollect: true,
dontCollect: !option.logId, // 如果是在创建log则把oper收集回去
});
closeRootMode();
}

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',
@ -345,7 +359,7 @@ exports.logTriggers = [
iState: 'rollbacked',
},
}, {});
return (result.oper.remove || 0) + (result2.log.remove || 0);
return (result.oper?.remove || 0) + (result2.log?.remove || 0);
}
}
];

View File

@ -21,7 +21,9 @@ export interface Connector<ED extends EntityDict & BaseEntityDict, FrontCxt exte
headers?: Record<string, any>;
}>;
serializeException: (exception: OakException<ED>, headers: IncomingHttpHeaders, body: any) => {
body: any;
body: {
exception: string;
};
headers?: Record<string, any>;
};
getSubscribeRouter: () => string;

16
lib/types/Sync.d.ts vendored
View File

@ -51,7 +51,7 @@ export interface SyncRemoteConfigBase<ED extends EntityDict & BaseEntityDict, Cx
pushEntities?: Array<PushEntityDef<ED, keyof ED, Cxt>>;
pullEntities?: Array<PullEntityDef<ED, keyof ED, Cxt>>;
}
interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncRemoteConfigBase<ED, Cxt> {
export interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncRemoteConfigBase<ED, Cxt> {
getPushInfo: (context: Cxt, option: {
remoteEntityId: string;
userId: string;
@ -60,6 +60,20 @@ interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends A
selfId: string;
remoteEntityId: string;
}) => Promise<RemotePullInfo>;
/**
*
*/
onFailed?: (result: {
remoteEntity: keyof ED;
remoteEntityId: string;
data: {
entity: keyof ED;
action: ED[keyof ED]['Action'];
data: ED[keyof ED]['Operation']['data'];
rowIds: string[];
}[];
reason: Error;
}, context: Cxt) => Promise<void>;
}
export interface SyncSelfConfigBase<ED extends EntityDict & BaseEntityDict> {
endpoint?: string;

View File

@ -60,8 +60,9 @@ export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, Fro
headers?: Record<string, any> | undefined;
}>;
serializeException(exception: OakException<ED>, headers: IncomingHttpHeaders, body: any): {
body: any;
headers?: Record<string, any> | undefined;
body: {
exception: string;
};
};
getBridgeRouter(): string;
/**

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',
}
@ -1500,7 +1506,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
};
const closeRootMode = context.openRootMode();
await this.cascadeUpdateAsync('oper', createOper, context, {
dontCollect: true,
dontCollect: !option.logId, // 如果是在创建log则把oper收集回去
});
closeRootMode();
}
@ -1548,6 +1554,10 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
);
}
if (ids.length === 0) {
// 如果没有行需要更新/删除,直接返回
return {};
}
if (data) {
this.preProcessDataUpdated(action, data, true);
}
@ -1686,7 +1696,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
}
const closeRootMode = context.openRootMode();
await this.cascadeUpdateAsync('oper', createOper, context, {
dontCollect: true,
dontCollect: !option.logId, // 如果是在创建log则把oper收集回去
});
closeRootMode();
}

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',
@ -361,7 +375,7 @@ export const logTriggers: Trigger<EntityDict & BaseEntityDict, 'log', AsyncConte
},
}, {});
return (result.oper!.remove || 0) + (result2.log!.remove || 0);
return (result.oper?.remove || 0) + (result2.log?.remove || 0);
}
} as CreateTriggerInTxn<EntityDict & BaseEntityDict, 'log', AsyncContext<EntityDict & BaseEntityDict>>
];

View File

@ -39,7 +39,9 @@ export interface Connector<ED extends EntityDict & BaseEntityDict, FrontCxt exte
headers: IncomingHttpHeaders,
body: any
) => {
body: any;
body: {
exception: string;
};
headers?: Record<string, any>;
};

View File

@ -63,7 +63,7 @@ export interface SyncRemoteConfigBase<ED extends EntityDict & BaseEntityDict, Cx
pullEntities?: Array<PullEntityDef<ED, keyof ED, Cxt>>; // 从这个entity上可能会接收到的同步entites
};
interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncRemoteConfigBase<ED, Cxt> {
export interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncRemoteConfigBase<ED, Cxt> {
getPushInfo: (context: Cxt, option: {
remoteEntityId: string;
userId: string;
@ -72,6 +72,21 @@ interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends A
selfId: string,
remoteEntityId: string,
}) => Promise<RemotePullInfo>;
/**
*
*/
onFailed?: (result: {
remoteEntity: keyof ED;
remoteEntityId: string;
data: {
entity: keyof ED;
action: ED[keyof ED]['Action'],
data: ED[keyof ED]['Operation']['data'];
rowIds: string[];
}[];
reason: Error;
}, context: Cxt) => Promise<void>;
};
export interface SyncSelfConfigBase<ED extends EntityDict & BaseEntityDict> {

View File

@ -223,7 +223,7 @@ export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, Fro
exception: OakException<ED>,
headers: IncomingHttpHeaders,
body: any
): { body: any; headers?: Record<string, any> | undefined } {
) {
return {
body: {
exception: exception.toString(),