oak-domain/lib/store/triggers.js

408 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.triggers = exports.actionAuthTriggers = void 0;
const tslib_1 = require("tslib");
const types_1 = require("../types");
const uuid_1 = require("../utils/uuid");
const assert_1 = tslib_1.__importDefault(require("assert"));
const filter_1 = require("./filter");
exports.actionAuthTriggers = [
{
name: '当actionAuth的deActions被置空后删除此条数据',
entity: 'actionAuth',
action: 'update',
fn: async ({ operation }, context, option) => {
const { data, filter } = operation;
if (data.deActions && data.deActions.length === 0) {
await context.operate('actionAuth', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'remove',
data: {},
filter,
}, option);
return 1;
}
return 0;
},
when: 'after',
}
];
/**
* 回滚某条日志的修改
* @param log
* @param context
*/
async function undoLog(log, context) {
const { iState, oper$log } = log;
for (const oper of oper$log) {
const { action, targetEntity, filter, undoData, iState } = oper;
(0, assert_1.default)(iState === 'normal', '非正常状态的oper怎能回滚');
switch (action) {
case 'create': {
await context.operate(targetEntity, {
id: 'dummy',
action: 'remove',
data: {},
filter: filter,
}, {
blockTrigger: true,
dontCreateOper: true,
});
break;
}
case 'remove': {
const ids = (0, filter_1.getRelevantIds)(filter);
(0, assert_1.default)(ids.length > 0);
for (const id of ids) {
await context.operate(targetEntity, {
id: 'dummy',
action: 'create',
data: undoData[id],
}, {
blockTrigger: true,
dontCreateOper: true,
});
}
break;
}
default: {
// 全按update处理
const ids = (0, filter_1.getRelevantIds)(filter);
(0, assert_1.default)(ids.length > 0);
for (const id of ids) {
await context.operate(targetEntity, {
id: 'dummy',
action: 'update',
data: undoData[id],
filter: {
id,
}
}, {
blockTrigger: true,
dontCreateOper: true,
});
}
break;
}
}
}
await context.operate('log', {
id: 'dummy',
action: 'undo',
data: {
iState: 'rollbacked',
oper$log: [{
id: 'dummy',
action: 'undo',
data: {
iState: 'rollbacked',
},
}],
},
filter: {
id: log.id,
},
}, {
blockTrigger: true,
dontCreateOper: true,
});
}
/**
* 重做某条日志的修改
* @param log
* @param context
*/
async function redoLog(log, context) {
const { oper$log } = log;
for (const oper of oper$log) {
const { action, targetEntity, filter, data, iState } = oper;
(0, assert_1.default)(iState === 'rollbacked', '非正常状态的oper怎能回滚');
switch (action) {
case 'create': {
await context.operate(targetEntity, {
id: 'dummy',
action: 'create',
data: data,
}, {
blockTrigger: true,
dontCreateOper: true,
});
break;
}
case 'remove': {
await context.operate(targetEntity, {
id: 'dummy',
action: 'remove',
data: {},
filter: filter,
}, {
blockTrigger: true,
dontCreateOper: true,
});
break;
}
default: {
await context.operate(targetEntity, {
id: 'dummy',
action,
data,
filter: filter,
}, {
blockTrigger: true,
dontCreateOper: true,
});
break;
}
}
}
await context.operate('log', {
id: 'dummy',
action: 'redo',
data: {
iState: 'normal',
oper$log: [{
id: 'dummy',
action: 'redo',
data: {
iState: 'normal',
},
}],
},
filter: {
id: log.id,
},
}, {
blockTrigger: true,
dontCreateOper: true,
});
}
exports.triggers = [
{
name: '当log被undo时同一entity上所有在其之后的log全部回滚',
entity: 'log',
action: 'undo',
when: 'after',
fn: async ({ operation }, context) => {
const { filter } = operation;
(0, assert_1.default)(filter);
const ids = (0, filter_1.getRelevantIds)(filter);
(0, assert_1.default)(ids.length === 1);
const [log] = await context.select('log', {
data: {
id: 1,
oper$log: {
$entity: 'oper',
data: {
id: 1,
undoData: 1,
action: 1,
targetEntity: 1,
filter: 1,
[types_1.SeqAttribute]: 1,
},
},
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
id: ids[0],
},
}, { dontCollect: true });
const logs = await context.select('log', {
data: {
id: 1,
oper$log: {
$entity: 'oper',
data: {
id: 1,
undoData: 1,
action: 1,
targetEntity: 1,
filter: 1,
iState: 1,
},
},
iState: 1,
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
iState: 'normal',
entity: log.entity,
entityId: log.entityId,
[types_1.SeqAttribute]: {
$gte: log[types_1.SeqAttribute],
},
},
sorter: [
{
$attr: {
[types_1.SeqAttribute]: 1,
},
$direction: 'desc',
}
]
}, { dontCollect: true });
(0, assert_1.default)(logs.length > 0);
for (const log2 of logs) {
await undoLog(log2, context);
}
return logs.length;
}
},
{
name: '当log被redo时同一entity上所有在其之前的log全部重做',
entity: 'log',
action: 'redo',
when: 'after',
fn: async ({ operation }, context) => {
const { filter } = operation;
(0, assert_1.default)(filter);
const ids = (0, filter_1.getRelevantIds)(filter);
(0, assert_1.default)(ids.length === 1);
const [log] = await context.select('log', {
data: {
id: 1,
oper$log: {
$entity: 'oper',
data: {
id: 1,
data: 1,
action: 1,
targetEntity: 1,
filter: 1,
[types_1.SeqAttribute]: 1,
},
},
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,
oper$log: {
$entity: 'oper',
data: {
id: 1,
data: 1,
action: 1,
targetEntity: 1,
filter: 1,
iState: 1,
},
},
iState: 1,
entity: 1,
entityId: 1,
[types_1.SeqAttribute]: 1,
},
filter: {
iState: 'rollbacked',
entity: log.entity,
entityId: log.entityId,
[types_1.SeqAttribute]: {
$lte: log[types_1.SeqAttribute],
},
},
sorter: [
{
$attr: {
[types_1.SeqAttribute]: 1,
},
$direction: 'asc',
}
]
}, { dontCollect: true, forUpdate: true });
(0, assert_1.default)(logs.length > 0);
for (const log2 of logs) {
await redoLog(log2, context);
}
return logs.length;
}
},
{
name: '当插入新的日志时过去的rollbacked状态的日志可以删除',
entity: 'log',
action: 'create',
when: 'after',
fn: async ({ operation }, context, option) => {
const { data } = operation;
(0, assert_1.default)(!(data instanceof Array));
const { entity, entityId } = data;
const result = await context.operate('oper', {
id: 'dummy',
action: 'remove',
data: {},
filter: {
iState: 'rollbacked',
log: {
entity: entity,
entityId: entityId,
},
},
}, {});
const result2 = await context.operate('log', {
id: 'dummy',
action: 'remove',
data: {},
filter: {
entity: entity,
entityId: entityId,
iState: 'rollbacked',
},
}, {});
return (result.oper?.remove || 0) + (result2.log?.remove || 0);
}
},
// 在删除log时删除与此log关联的oper
{
name: '当删除log时删除与此log关联的oper',
entity: 'log',
action: 'remove',
when: 'before',
fn: async ({ operation }, context) => {
const { filter } = operation;
(0, assert_1.default)(filter);
// 查询这次删除操作涉及到的所有log
const result = await context.operate('oper', {
id: "dummy",
action: 'remove',
data: {},
filter: {
log: filter,
}
}, {});
return result.oper?.remove || 0;
}
},
// 当删除userRelation时一并删除掉关联的userEntityClaim这个设计似乎不是太好
{
name: '当删除userRelation时一并删除掉关联的userEntityClaim',
action: 'remove',
entity: 'userRelation',
when: 'before',
fn: async ({ operation }, context, option) => {
const { filter } = operation;
const close = context.openRootMode();
const result = await context.operate('userEntityClaim', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'remove',
data: {},
filter: {
userRelation: filter,
},
}, option);
close();
return result.userEntityClaim?.remove || 0;
}
},
];