Merge branch 'release'

This commit is contained in:
Xu Chang 2023-02-08 21:00:56 +08:00
commit fc9c65a7ef
19 changed files with 344 additions and 226 deletions

View File

@ -11,6 +11,7 @@ var types_1 = require("../types");
var lodash_1 = require("../utils/lodash");
var filter_2 = require("./filter");
var uuid_1 = require("../utils/uuid");
var selection_1 = require("./selection");
/**这个用来处理级联的select和update对不同能力的 */
var CascadeStore = /** @class */ (function (_super) {
tslib_1.__extends(CascadeStore, _super);
@ -1252,6 +1253,7 @@ var CascadeStore = /** @class */ (function (_super) {
};
CascadeStore.prototype.cascadeUpdate = function (entity, operation, context, option) {
var e_5, _a, e_6, _b, e_7, _c;
(0, selection_1.reinforceOperation)(this.getSchema(), entity, operation);
var action = operation.action, data = operation.data, filter = operation.filter, id = operation.id;
var opData;
var wholeBeforeFns = [];
@ -1328,6 +1330,7 @@ var CascadeStore = /** @class */ (function (_super) {
return tslib_1.__generator(this, function (_h) {
switch (_h.label) {
case 0:
(0, selection_1.reinforceOperation)(this.getSchema(), entity, operation);
action = operation.action, data = operation.data, filter = operation.filter, id = operation.id;
wholeBeforeFns = [];
wholeAfterFns = [];
@ -1426,6 +1429,7 @@ var CascadeStore = /** @class */ (function (_super) {
});
};
CascadeStore.prototype.cascadeSelect = function (entity, selection, context, option) {
(0, selection_1.reinforceSelection)(this.getSchema(), entity, selection);
var data = selection.data, filter = selection.filter, indexFrom = selection.indexFrom, count = selection.count, sorter = selection.sorter;
var _a = this.destructCascadeSelect(entity, data, context, this.cascadeSelect, this.aggregateSync, option), projection = _a.projection, cascadeSelectionFns = _a.cascadeSelectionFns;
var rows = this.selectAbjointRow(entity, {
@ -1547,6 +1551,7 @@ var CascadeStore = /** @class */ (function (_super) {
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
(0, selection_1.reinforceSelection)(this.getSchema(), entity, selection);
data = selection.data, filter = selection.filter, indexFrom = selection.indexFrom, count = selection.count, sorter = selection.sorter;
_a = this.destructCascadeSelect(entity, data, context, this.cascadeSelectAsync, this.aggregateAsync, option), projection = _a.projection, cascadeSelectionFns = _a.cascadeSelectionFns;
return [4 /*yield*/, this.selectAbjointRowAsync(entity, {

View File

@ -44,20 +44,19 @@ function translateCheckerInAsyncContext(checker) {
var fn = (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var operationFilter, action, filter2, _b, entity2, selection2, rows2, data_1, rows2, data_2;
var _c, _d;
return tslib_1.__generator(this, function (_e) {
switch (_e.label) {
var operationFilter, action, filter2, _b, entity2, selection2, rows2, e, rows2, e;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
operationFilter = operation.filter, action = operation.action;
if (!(typeof filter_2 === 'function')) return [3 /*break*/, 2];
return [4 /*yield*/, filter_2(operation, context, option)];
case 1:
_b = _e.sent();
_b = _c.sent();
return [3 /*break*/, 3];
case 2:
_b = filter_2;
_e.label = 3;
_c.label = 3;
case 3:
filter2 = _b;
if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 4];
@ -65,7 +64,7 @@ function translateCheckerInAsyncContext(checker) {
return [2 /*return*/, 0];
case 4: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {}, true)];
case 5:
if (_e.sent()) {
if (_c.sent()) {
return [2 /*return*/, 0];
}
if (!inconsistentRows_1) return [3 /*break*/, 7];
@ -75,20 +74,10 @@ function translateCheckerInAsyncContext(checker) {
blockTrigger: true,
})];
case 6:
rows2 = _e.sent();
data_1 = {};
rows2.forEach(function (ele) {
var _a;
return Object.assign(data_1, (_a = {},
_a[ele.id] = ele,
_a));
});
throw new Exception_1.OakRowInconsistencyException({
a: 's',
d: (_c = {},
_c[entity2] = data_1,
_c)
}, errMsg_1);
rows2 = _c.sent();
e = new Exception_1.OakRowInconsistencyException(undefined, errMsg_1);
e.addData(entity2, rows2);
throw e;
case 7: return [4 /*yield*/, context.select(entity, {
data: (0, actionDef_1.getFullProjection)(entity, context.getSchema()),
filter: Object.assign({}, operationFilter, {
@ -99,20 +88,10 @@ function translateCheckerInAsyncContext(checker) {
blockTrigger: true,
})];
case 8:
rows2 = _e.sent();
data_2 = {};
rows2.forEach(function (ele) {
var _a;
return Object.assign(data_2, (_a = {},
_a[ele.id] = ele,
_a));
});
throw new Exception_1.OakRowInconsistencyException({
a: 's',
d: (_d = {},
_d[entity] = data_2,
_d)
}, errMsg_1);
rows2 = _c.sent();
e = new Exception_1.OakRowInconsistencyException(undefined, errMsg_1);
e.addData(entity, rows2);
throw e;
}
});
});
@ -228,7 +207,8 @@ function translateCheckerInSyncContext(checker) {
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
return;
}
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3);
var e = new Exception_1.OakRowInconsistencyException(undefined, errMsg_3);
throw e;
}
};
return {
@ -578,8 +558,8 @@ function createRemoveCheckers(schema, authDict) {
var promises = [];
if (OneToManyMatrix[entity]) {
var _loop_5 = function (otm) {
var _g, _h, _j, _k;
var _l = tslib_1.__read(otm, 2), e = _l[0], attr = _l[1];
var _g, _h;
var _j = tslib_1.__read(otm, 2), e = _j[0], attr = _j[1];
var proj = (_g = {
id: 1
},
@ -596,33 +576,20 @@ function createRemoveCheckers(schema, authDict) {
}, { dontCollect: true });
if (result instanceof Promise) {
promises.push(result.then(function (_a) {
var _b, _c;
var _d = tslib_1.__read(_a, 1), row = _d[0];
var _b = tslib_1.__read(_a, 1), row = _b[0];
if (row) {
var record = {
a: 's',
d: (_b = {},
_b[e] = (_c = {},
_c[row.id] = row,
_c),
_b)
};
throw new Exception_1.OakRowInconsistencyException(record, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(e, "\u300D\u5173\u8054\u7684\u884C"));
var err = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(e, "\u300D\u5173\u8054\u7684\u884C"));
err.addData(e, [row]);
throw err;
}
}));
}
else {
var _m = tslib_1.__read(result, 1), row = _m[0];
var _k = tslib_1.__read(result, 1), row = _k[0];
if (row) {
var record = {
a: 's',
d: (_j = {},
_j[e] = (_k = {},
_k[row.id] = row,
_k),
_j)
};
throw new Exception_1.OakRowInconsistencyException(record, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(e, "\u300D\u5173\u8054\u7684\u884C"));
var err = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(e, "\u300D\u5173\u8054\u7684\u884C"));
err.addData(e, [row]);
throw err;
}
}
};
@ -642,15 +609,15 @@ function createRemoveCheckers(schema, authDict) {
}
if (OneToManyOnEntityMatrix[entity]) {
var _loop_6 = function (otm) {
var _o, _p, _q;
var _l, _m, _o;
var proj = {
id: 1,
entity: 1,
entityId: 1,
};
var filter = operation.filter && (_o = {},
_o[entity] = operation.filter,
_o);
var filter = operation.filter && (_l = {},
_l[entity] = operation.filter,
_l);
var result = context.select(otm, {
data: proj,
filter: filter,
@ -659,33 +626,28 @@ function createRemoveCheckers(schema, authDict) {
}, { dontCollect: true });
if (result instanceof Promise) {
promises.push(result.then(function (_a) {
var _b, _c;
var _d = tslib_1.__read(_a, 1), row = _d[0];
var _b = tslib_1.__read(_a, 1), row = _b[0];
if (row) {
var record = {
a: 's',
d: (_b = {},
_b[otm] = (_c = {},
_c[row.id] = row,
_c),
_b)
};
throw new Exception_1.OakRowInconsistencyException(record, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(otm, "\u300D\u5173\u8054\u7684\u884C"));
var e = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(otm, "\u300D\u5173\u8054\u7684\u884C"));
e.addData(otm, [row]);
throw e;
}
}));
}
else {
var _r = tslib_1.__read(result, 1), row = _r[0];
var _p = tslib_1.__read(result, 1), row = _p[0];
if (row) {
var record = {
a: 's',
d: (_p = {},
_p[otm] = (_q = {},
_q[row.id] = row,
_q),
_p)
d: (_m = {},
_m[otm] = (_o = {},
_o[row.id] = row,
_o),
_m)
};
throw new Exception_1.OakRowInconsistencyException(record, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(otm, "\u300D\u5173\u8054\u7684\u884C"));
var e = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(otm, "\u300D\u5173\u8054\u7684\u884C"));
e.addData(otm, [row]);
throw e;
}
}
};

View File

@ -1,7 +1,19 @@
import { StorageSchema } from '../types';
import { EntityDict } from '../types/Entity';
declare type SelectionRewriter<ED extends EntityDict> = (schema: StorageSchema<ED>, entity: keyof ED, selection: ED[keyof ED]['Selection']) => void;
export declare function registerSelectionRewriter<ED extends EntityDict>(rewriter: SelectionRewriter<ED>): void;
declare type OperationRewriter<ED extends EntityDict> = (schema: StorageSchema<ED>, entity: keyof ED, operate: ED[keyof ED]['Operation']) => void;
export declare function registerOperationRewriter<ED extends EntityDict>(rewriter: OperationRewriter<ED>): void;
/**
* selection进行一些完善
* @param selection
*/
export declare function reinforceSelection<ED extends EntityDict>(schema: StorageSchema<ED>, entity: keyof ED, selection: ED[keyof ED]['Selection']): void;
/**
* operation进行一些完善operation算子的注入点
* @param schema
* @param entity
* @param selection
*/
export declare function reinforceOperation<ED extends EntityDict>(schema: StorageSchema<ED>, entity: keyof ED, operation: ED[keyof ED]['Operation']): void;
export {};

View File

@ -1,18 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reinforceSelection = void 0;
exports.reinforceOperation = exports.reinforceSelection = exports.registerOperationRewriter = exports.registerSelectionRewriter = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var types_1 = require("../types");
var Demand_1 = require("../types/Demand");
var filter_1 = require("./filter");
var relation_1 = require("./relation");
var SelectionRewriters = [];
function registerSelectionRewriter(rewriter) {
SelectionRewriters.push(rewriter);
}
exports.registerSelectionRewriter = registerSelectionRewriter;
function getSelectionRewriters() {
return SelectionRewriters;
}
var OperationRewriters = [];
function registerOperationRewriter(rewriter) {
OperationRewriters.push(rewriter);
}
exports.registerOperationRewriter = registerOperationRewriter;
function getOperationRewriters() {
return OperationRewriters;
}
/**
* 对selection进行一些完善避免编程人员的疏漏
* @param selection
*/
function reinforceSelection(schema, entity, selection) {
var filter = selection.filter, data = selection.data, sorter = selection.sorter;
Object.assign(data, {
'$$createAt$$': 1,
}); // 有的页面依赖于其它页面取数据有时两个页面的filter的差异会导致有一个加createAt有一个不加此时可能产生前台取数据不完整的异常。先统一加上
var checkNode = function (projectionNode, attrs) {
attrs.forEach(function (attr) {
var _a;
@ -234,5 +253,16 @@ function reinforceSelection(schema, entity, selection) {
$$createAt$$: 1,
});
}
SelectionRewriters.forEach(function (ele) { return ele(schema, entity, selection); });
}
exports.reinforceSelection = reinforceSelection;
/**
* 对operation进行一些完善作为operation算子的注入点
* @param schema
* @param entity
* @param selection
*/
function reinforceOperation(schema, entity, operation) {
OperationRewriters.forEach(function (ele) { return ele(schema, entity, operation); });
}
exports.reinforceOperation = reinforceOperation;

2
lib/types/Auth.d.ts vendored
View File

@ -61,7 +61,7 @@ export declare type AuthDef<ED extends EntityDict, T extends keyof ED> = {
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
cascadeRemove?: {
[E in keyof ED[T]['OpSchema'] | '@entity']?: ActionOnRemove;
[E in (keyof ED | '@entity')]?: ActionOnRemove;
};
};
export declare type AuthDefDict<ED extends EntityDict> = {

View File

@ -19,7 +19,7 @@ export declare abstract class Connector<ED extends EntityDict, BackCxt extends A
body: any;
headers?: Record<string, any>;
};
abstract serializeException(exception: OakException, headers: IncomingHttpHeaders, body: any): {
abstract serializeException(exception: OakException<ED>, headers: IncomingHttpHeaders, body: any): {
body: any;
headers?: Record<string, any>;
};

View File

@ -165,7 +165,7 @@ export declare type SelectOpResult<ED extends EntityDict> = {
a: 's';
d: {
[T in keyof ED]?: {
[ID: string]: ED[T]['OpSchema'];
[ID: string]: Partial<ED[T]['OpSchema']>;
};
};
};

View File

@ -1,11 +1,14 @@
import { EntityDict, OpRecord } from "./Entity";
export declare class OakException extends Error {
import { EntityDict, OpRecord, SelectOpResult } from "./Entity";
export declare class OakException<ED extends EntityDict> extends Error {
opRecord: SelectOpResult<ED>;
constructor(message?: string);
addData<T extends keyof ED>(entity: T, rows: Partial<ED[T]['OpSchema']>[]): void;
setOpRecords(opRecord: SelectOpResult<ED>): void;
toString(): string;
}
export declare class OakDataException extends OakException {
export declare class OakDataException<ED extends EntityDict> extends OakException<ED> {
}
export declare class OakUniqueViolationException extends OakException {
export declare class OakUniqueViolationException<ED extends EntityDict> extends OakException<ED> {
rows: Array<{
id?: string;
attrs: string[];
@ -15,14 +18,14 @@ export declare class OakUniqueViolationException extends OakException {
attrs: string[];
}>, message?: string);
}
export declare class OakImportDataParseException extends OakException {
export declare class OakImportDataParseException<ED extends EntityDict> extends OakException<ED> {
line: number;
header?: string;
constructor(message: string, line: number, header?: string);
}
export declare class OakOperExistedException extends OakDataException {
export declare class OakOperExistedException<ED extends EntityDict> extends OakDataException<ED> {
}
export declare class OakRowUnexistedException extends OakDataException {
export declare class OakRowUnexistedException<ED extends EntityDict> extends OakDataException<ED> {
private rows;
constructor(rows: Array<{
entity: any;
@ -36,22 +39,20 @@ export declare class OakRowUnexistedException extends OakDataException {
}
export declare class OakExternalException extends Error {
}
export declare class OakUserException extends OakException {
export declare class OakUserException<ED extends EntityDict> extends OakException<ED> {
}
/**
*
*
*/
export declare class OakRowInconsistencyException<ED extends EntityDict> extends OakUserException {
private data?;
export declare class OakRowInconsistencyException<ED extends EntityDict> extends OakUserException<ED> {
constructor(data?: OpRecord<ED>, message?: string);
getData(): OpRecord<ED> | undefined;
toString(): string;
}
/**
* attributes表示非法的属性
*/
export declare class OakInputIllegalException extends OakUserException {
export declare class OakInputIllegalException<ED extends EntityDict> extends OakUserException<ED> {
private attributes;
private entity;
constructor(entity: string, attributes: string[], message?: string);
@ -63,24 +64,24 @@ export declare class OakInputIllegalException extends OakUserException {
/**
*
*/
export declare class OakUserUnpermittedException extends OakUserException {
export declare class OakUserUnpermittedException<ED extends EntityDict> extends OakUserException<ED> {
}
/**
*
*/
export declare class OakUnloggedInException extends OakUserException {
export declare class OakUnloggedInException<ED extends EntityDict> extends OakUserException<ED> {
constructor(message?: string);
}
/**
*
*/
export declare class OakRowLockedException extends OakUserException {
export declare class OakRowLockedException<ED extends EntityDict> extends OakUserException<ED> {
constructor(message?: string);
}
/**
*
*/
export declare class OakCongruentRowExists<ED extends EntityDict, T extends keyof ED> extends OakUserException {
export declare class OakCongruentRowExists<ED extends EntityDict, T extends keyof ED> extends OakUserException<ED> {
private data;
private entity;
constructor(entity: T, data: ED[T]['OpSchema'], message?: string);
@ -88,11 +89,12 @@ export declare class OakCongruentRowExists<ED extends EntityDict, T extends keyo
getEntity(): T;
toString(): string;
}
export declare class OakDeadlock extends OakUserException {
export declare class OakDeadlock<ED extends EntityDict> extends OakUserException<ED> {
constructor(message?: string | undefined);
}
export declare function makeException(data: {
export declare function makeException<ED extends EntityDict>(data: {
name: string;
message?: string;
opRecords: SelectOpResult<ED>;
[A: string]: any;
}): OakException | OakExternalException | undefined;
}): OakException<EntityDict> | undefined;

View File

@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserUnpermittedException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakUserException = exports.OakExternalException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakImportDataParseException = exports.OakUniqueViolationException = exports.OakDataException = exports.OakException = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var OakException = /** @class */ (function (_super) {
tslib_1.__extends(OakException, _super);
function OakException(message) {
@ -17,12 +18,36 @@ var OakException = /** @class */ (function (_super) {
else {
_this.__proto__ = _newTarget.prototype;
}
_this.opRecord = {
a: 's',
d: {},
};
return _this;
}
OakException.prototype.addData = function (entity, rows) {
var d = this.opRecord.d;
var addSingleRow = function (rowRoot, row) {
var id = row.id;
if (rowRoot[id]) {
Object.assign(rowRoot[id], row);
}
else {
rowRoot[id] = row;
}
};
if (!d[entity]) {
d[entity] = {};
}
rows.forEach(function (row) { return addSingleRow(d[entity], row); });
};
OakException.prototype.setOpRecords = function (opRecord) {
this.opRecord = opRecord;
};
OakException.prototype.toString = function () {
return JSON.stringify({
name: this.constructor.name,
message: this.message,
opRecord: this.opRecord,
});
};
return OakException;
@ -109,17 +134,13 @@ var OakRowInconsistencyException = /** @class */ (function (_super) {
tslib_1.__extends(OakRowInconsistencyException, _super);
function OakRowInconsistencyException(data, message) {
var _this = _super.call(this, message) || this;
_this.data = data;
(0, assert_1.default)(!data, '现在使用addData接口来传数据');
return _this;
}
OakRowInconsistencyException.prototype.getData = function () {
return this.data;
};
OakRowInconsistencyException.prototype.toString = function () {
return JSON.stringify({
name: this.constructor.name,
message: this.message,
data: this.data,
});
};
return OakRowInconsistencyException;
@ -235,46 +256,69 @@ function makeException(data) {
var name = data.name;
switch (name) {
case 'OakException': {
return new OakException(data.message);
var e = new OakException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUserException': {
return new OakUserException(data.message);
}
case 'OakExternalException': {
return new OakExternalException(data.message);
var e = new OakUserException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakRowInconsistencyException': {
return new OakRowInconsistencyException(data.data, data.message);
var e = new OakRowInconsistencyException(data.data, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakInputIllegalException': {
return new OakInputIllegalException(data.entity, data.attributes, data.message);
var e = new OakInputIllegalException(data.entity, data.attributes, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUserUnpermittedException': {
return new OakUserUnpermittedException(data.message);
var e = new OakUserUnpermittedException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUnloggedInException': {
return new OakUnloggedInException(data.message);
var e = new OakUnloggedInException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakCongruentRowExists': {
return new OakCongruentRowExists(data.entity, data.data, data.message);
var e = new OakCongruentRowExists(data.entity, data.data, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakRowLockedException': {
return new OakRowLockedException(data.message);
var e = new OakRowLockedException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakRowUnexistedException': {
return new OakRowUnexistedException(data.rows);
var e = new OakRowUnexistedException(data.rows);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakDeadlock': {
return new OakDeadlock(data.message);
var e = new OakDeadlock(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakDataException': {
return new OakDataException(data.message);
var e = new OakDataException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUniqueViolationException': {
return new OakUniqueViolationException(data.rows, data.message);
var e = new OakUniqueViolationException(data.rows, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakImportDataParseException': {
return new OakImportDataParseException(data.message, data.line, data.header);
var e = new OakImportDataParseException(data.message, data.line, data.header);
e.setOpRecords(data.opRecords);
return e;
}
default:
return;

View File

@ -8,7 +8,7 @@ export declare class SimpleConnector<ED extends EntityDict, BackCxt extends Asyn
private serverUrl;
private makeException;
private contextBuilder;
constructor(serverUrl: string, makeException: (exceptionData: any) => OakException, contextBuilder: (str: string | undefined) => (store: AsyncRowStore<ED, BackCxt>) => Promise<BackCxt>);
constructor(serverUrl: string, makeException: (exceptionData: any) => OakException<ED>, contextBuilder: (str: string | undefined) => (store: AsyncRowStore<ED, BackCxt>) => Promise<BackCxt>);
callAspect(name: string, params: any, context: FrontCxt): Promise<{
result: any;
opRecords: OpRecord<ED>[];
@ -23,7 +23,7 @@ export declare class SimpleConnector<ED extends EntityDict, BackCxt extends Asyn
body: any;
headers?: Record<string, any> | undefined;
};
serializeException(exception: OakException, headers: IncomingHttpHeaders, body: any): {
serializeException(exception: OakException<ED>, headers: IncomingHttpHeaders, body: any): {
body: any;
headers?: Record<string, any> | undefined;
};

View File

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

View File

@ -16,6 +16,7 @@ import { getRelevantIds } from "./filter";
import { CreateOperation as CreateOperOperation } from '../base-app-domain/Oper/Schema';
import { CreateOperation as CreateModiOperation, UpdateOperation as UpdateModiOperation } from '../base-app-domain/Modi/Schema';
import { generateNewIdAsync } from "../utils/uuid";
import { reinforceOperation, reinforceSelection } from "./selection";
/**这个用来处理级联的select和update对不同能力的 */
export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> extends RowStore<ED> {
@ -1311,6 +1312,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
operation: ED[T]['Operation'],
context: Cxt,
option: OP): OperationResult<ED> {
reinforceOperation(this.getSchema(), entity, operation);
const { action, data, filter, id } = operation;
let opData: any;
const wholeBeforeFns: Array<() => any> = [];
@ -1375,6 +1377,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
operation: ED[T]['Operation'],
context: Cxt,
option: OP): Promise<OperationResult<ED>> {
reinforceOperation(this.getSchema(), entity, operation);
const { action, data, filter, id } = operation;
let opData: any;
const wholeBeforeFns: Array<() => Promise<any>> = [];
@ -1437,6 +1440,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
selection: ED[T]['Selection'],
context: Cxt,
option: OP): Partial<ED[T]['Schema']>[] {
reinforceSelection(this.getSchema(), entity, selection);
const { data, filter, indexFrom, count, sorter } = selection;
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(
entity,
@ -1576,6 +1580,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
selection: ED[T]['Selection'],
context: Cxt,
option: OP): Promise<Partial<ED[T]['Schema']>[]> {
reinforceSelection(this.getSchema(), entity, selection);
const { data, filter, indexFrom, count, sorter } = selection;
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(
entity,

View File

@ -55,19 +55,10 @@ export function translateCheckerInAsyncContext<
dontCollect: true,
blockTrigger: true,
});
const data = {};
rows2.forEach(
ele => Object.assign(data, {
[ele.id as string]: ele,
})
);
throw new OakRowInconsistencyException({
a: 's',
d: {
[entity2]: data,
}
}, errMsg);
const e = new OakRowInconsistencyException<ED>(undefined, errMsg);
e.addData(entity2, rows2);
throw e;
}
else {
const rows2 = await context.select(entity, {
@ -79,19 +70,10 @@ export function translateCheckerInAsyncContext<
dontCollect: true,
blockTrigger: true,
});
const data = {};
rows2.forEach(
ele => Object.assign(data, {
[ele.id as string]: ele,
})
);
throw new OakRowInconsistencyException({
a: 's',
d: {
[entity]: data,
}
}, errMsg);
const e = new OakRowInconsistencyException<ED>(undefined, errMsg);
e.addData(entity, rows2);
throw e;
}
}
}) as UpdateTriggerInTxn<ED, keyof ED, Cxt>['fn'];
@ -191,7 +173,8 @@ export function translateCheckerInSyncContext<
if (checkFilterContains<ED, T, Cxt>(entity, context, filter2, operationFilter, true)) {
return;
}
throw new OakRowInconsistencyException(undefined, errMsg);
const e = new OakRowInconsistencyException(undefined, errMsg);
throw e;
}
};
return {
@ -568,15 +551,9 @@ export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt
result.then(
([row]) => {
if (row) {
const record = {
a: 's',
d: {
[e]: {
[row.id!]: row,
}
}
} as SelectOpResult<ED>;
throw new OakRowInconsistencyException(record, `您无法删除存在有效数据「${e as string}」关联的行`);
const err = new OakRowInconsistencyException<ED>(undefined, `您无法删除存在有效数据「${e as string}」关联的行`);
err.addData(e, [row]);
throw err;
}
}
)
@ -585,15 +562,9 @@ export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt
else {
const [row] = result;
if (row) {
const record = {
a: 's',
d: {
[e]: {
[row.id!]: row,
}
}
} as SelectOpResult<ED>;
throw new OakRowInconsistencyException(record, `您无法删除存在有效数据「${e as string}」关联的行`);
const err = new OakRowInconsistencyException<ED>(undefined, `您无法删除存在有效数据「${e as string}」关联的行`);
err.addData(e, [row]);
throw err;
}
}
}
@ -619,15 +590,9 @@ export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt
result.then(
([row]) => {
if (row) {
const record = {
a: 's',
d: {
[otm]: {
[row.id!]: row,
}
}
} as SelectOpResult<ED>;
throw new OakRowInconsistencyException(record, `您无法删除存在有效数据「${otm as string}」关联的行`);
const e = new OakRowInconsistencyException<ED>(undefined, `您无法删除存在有效数据「${otm as string}」关联的行`);
e.addData(otm, [row]);
throw e;
}
}
)
@ -644,7 +609,9 @@ export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt
}
}
} as SelectOpResult<ED>;
throw new OakRowInconsistencyException(record, `您无法删除存在有效数据「${otm as string}」关联的行`);
const e = new OakRowInconsistencyException<ED>(undefined, `您无法删除存在有效数据「${otm as string}」关联的行`);
e.addData(otm, [row]);
throw e;
}
}
}

View File

@ -5,12 +5,39 @@ import { EntityDict } from '../types/Entity';
import { getRelevantIds } from './filter';
import { judgeRelation } from './relation';
type SelectionRewriter<ED extends EntityDict> = (schema: StorageSchema<ED>, entity: keyof ED, selection: ED[keyof ED]['Selection']) => void;
const SelectionRewriters: SelectionRewriter<any>[] = [];
export function registerSelectionRewriter<ED extends EntityDict>(rewriter: SelectionRewriter<ED>) {
SelectionRewriters.push(rewriter);
}
function getSelectionRewriters<ED extends EntityDict>() {
return SelectionRewriters as SelectionRewriter<ED>[];
}
type OperationRewriter<ED extends EntityDict> = (schema: StorageSchema<ED>, entity: keyof ED, operate: ED[keyof ED]['Operation']) => void;
const OperationRewriters: OperationRewriter<any>[] = [];
export function registerOperationRewriter<ED extends EntityDict>(rewriter: OperationRewriter<ED>) {
OperationRewriters.push(rewriter);
}
function getOperationRewriters<ED extends EntityDict>() {
return OperationRewriters as OperationRewriter<ED>[];
}
/**
* selection进行一些完善
* @param selection
*/
export function reinforceSelection<ED extends EntityDict>(schema: StorageSchema<ED>, entity: keyof ED, selection: ED[keyof ED]['Selection']) {
const { filter, data, sorter } = selection;
Object.assign(data, {
'$$createAt$$': 1,
}); // 有的页面依赖于其它页面取数据有时两个页面的filter的差异会导致有一个加createAt有一个不加此时可能产生前台取数据不完整的异常。先统一加上
const checkNode = (projectionNode: ED[keyof ED]['Selection']['data'], attrs: string[]) => {
attrs.forEach(
@ -232,4 +259,20 @@ export function reinforceSelection<ED extends EntityDict>(schema: StorageSchema<
$$createAt$$: 1,
});
}
SelectionRewriters.forEach(
ele => ele(schema, entity, selection)
);
}
/**
* operation进行一些完善operation算子的注入点
* @param schema
* @param entity
* @param selection
*/
export function reinforceOperation<ED extends EntityDict>(schema: StorageSchema<ED>, entity: keyof ED, operation: ED[keyof ED]['Operation']) {
OperationRewriters.forEach(
ele => ele(schema, entity, operation)
);
}

View File

@ -89,7 +89,7 @@ export type AuthDef<ED extends EntityDict, T extends keyof ED> = {
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
cascadeRemove?: {
[E in keyof ED[T]['OpSchema'] | '@entity']?: ActionOnRemove;
[E in (keyof ED | '@entity')]?: ActionOnRemove;
}
};

View File

@ -20,7 +20,7 @@ export abstract class Connector<ED extends EntityDict, BackCxt extends AsyncCont
headers?: Record<string, any>;
};
abstract serializeException(exception: OakException, headers: IncomingHttpHeaders, body: any): {
abstract serializeException(exception: OakException<ED>, headers: IncomingHttpHeaders, body: any): {
body: any;
headers?: Record<string, any>;
};

View File

@ -216,7 +216,7 @@ export type SelectOpResult<ED extends EntityDict> = {
a: 's',
d: {
[T in keyof ED]?: {
[ID: string]: ED[T]['OpSchema'];
[ID: string]: Partial<ED[T]['OpSchema']>;
};
};
}

View File

@ -1,6 +1,8 @@
import { EntityDict, OpRecord } from "./Entity";
import assert from "assert";
import { EntityDict, OpRecord, SelectOpResult } from "./Entity";
export class OakException extends Error {
export class OakException<ED extends EntityDict> extends Error {
opRecord: SelectOpResult<ED>;
constructor(message?: string) {
super(message);
this.name = new.target.name;
@ -12,21 +14,49 @@ export class OakException extends Error {
} else {
(this as any).__proto__ = new.target.prototype;
}
this.opRecord = {
a: 's',
d: {},
};
}
addData<T extends keyof ED>(entity: T, rows: Partial<ED[T]['OpSchema']>[]) {
const { d } = this.opRecord;
const addSingleRow = (rowRoot: Record<string, Partial<ED[T]['OpSchema']>>, row: Partial<ED[T]['OpSchema']>) => {
const { id } = row;
if (rowRoot[id!]) {
Object.assign(rowRoot[id!], row);
}
else {
rowRoot[id!] = row;
}
};
if (!d[entity]) {
d[entity] = {};
}
rows.forEach(
row => addSingleRow(d[entity]!, row)
);
}
setOpRecords(opRecord: SelectOpResult<ED>) {
this.opRecord = opRecord;
}
toString() {
return JSON.stringify({
name: this.constructor.name,
message: this.message,
opRecord: this.opRecord,
});
}
}
export class OakDataException extends OakException {
export class OakDataException<ED extends EntityDict> extends OakException<ED> {
// 表示由数据层发现的异常
}
export class OakUniqueViolationException extends OakException {
export class OakUniqueViolationException<ED extends EntityDict> extends OakException<ED> {
rows: Array<{
id?: string;
attrs: string[];
@ -40,7 +70,7 @@ export class OakUniqueViolationException extends OakException {
}
}
export class OakImportDataParseException extends OakException {
export class OakImportDataParseException<ED extends EntityDict> extends OakException<ED> {
line: number;
header?: string;
@ -52,11 +82,11 @@ export class OakImportDataParseException extends OakException {
}
}
export class OakOperExistedException extends OakDataException {
export class OakOperExistedException<ED extends EntityDict> extends OakDataException<ED> {
// 进行操作时发现同样id的Oper对象已经存在
}
export class OakRowUnexistedException extends OakDataException {
export class OakRowUnexistedException<ED extends EntityDict> extends OakDataException<ED> {
private rows: Array<{
entity: any;
selection: any;
@ -80,7 +110,7 @@ export class OakExternalException extends Error {
// 表示由oak生态外部造成的异常比如网络中断
}
export class OakUserException extends OakException {
export class OakUserException<ED extends EntityDict> extends OakException<ED> {
// 继承了这个类的异常统一视为“可接受的、由用户操作造成的异常”
};
@ -89,22 +119,16 @@ export class OakUserException extends OakException {
*
*
*/
export class OakRowInconsistencyException<ED extends EntityDict> extends OakUserException {
private data?: OpRecord<ED>;
export class OakRowInconsistencyException<ED extends EntityDict> extends OakUserException<ED> {
constructor(data?: OpRecord<ED>, message?: string) {
super(message);
this.data = data;
}
getData() {
return this.data;
assert(!data, '现在使用addData接口来传数据');
}
toString(): string {
return JSON.stringify({
name: this.constructor.name,
message: this.message,
data: this.data,
});
}
};
@ -112,7 +136,7 @@ export class OakRowInconsistencyException<ED extends EntityDict> extends OakUser
/**
* attributes表示非法的属性
*/
export class OakInputIllegalException extends OakUserException {
export class OakInputIllegalException<ED extends EntityDict> extends OakUserException<ED> {
private attributes: string[];
private entity: string;
constructor(entity: string, attributes: string[], message?: string) {
@ -148,14 +172,14 @@ export class OakInputIllegalException extends OakUserException {
/**
*
*/
export class OakUserUnpermittedException extends OakUserException {
export class OakUserUnpermittedException<ED extends EntityDict> extends OakUserException<ED> {
};
/**
*
*/
export class OakUnloggedInException extends OakUserException {
export class OakUnloggedInException<ED extends EntityDict> extends OakUserException<ED> {
constructor(message?: string) {
super(message || '您尚未登录');
}
@ -165,7 +189,7 @@ export class OakUnloggedInException extends OakUserException {
/**
*
*/
export class OakRowLockedException extends OakUserException {
export class OakRowLockedException<ED extends EntityDict> extends OakUserException<ED> {
constructor(message?: string) {
super(message || '该行数据正在被更新中,请稍后再试');
}
@ -173,7 +197,7 @@ export class OakUnloggedInException extends OakUserException {
/**
*
*/
export class OakCongruentRowExists<ED extends EntityDict, T extends keyof ED> extends OakUserException {
export class OakCongruentRowExists<ED extends EntityDict, T extends keyof ED> extends OakUserException<ED> {
private data: ED[T]['OpSchema'];
private entity: T;
constructor(entity: T, data: ED[T]['OpSchema'], message?: string) {
@ -200,60 +224,84 @@ export class OakCongruentRowExists<ED extends EntityDict, T extends keyof ED> ex
}
}
export class OakDeadlock extends OakUserException {
export class OakDeadlock<ED extends EntityDict> extends OakUserException<ED> {
constructor(message?: string | undefined) {
super(message || '发现死锁');
}
};
export function makeException(data: {
export function makeException<ED extends EntityDict>(data: {
name: string;
message?: string;
opRecords: SelectOpResult<ED>;
[A: string]: any;
}) {
const { name } = data;
switch (name) {
case 'OakException': {
return new OakException(data.message);
const e = new OakException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUserException': {
return new OakUserException(data.message);
}
case 'OakExternalException': {
return new OakExternalException(data.message);
const e = new OakUserException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakRowInconsistencyException': {
return new OakRowInconsistencyException(data.data, data.message);
const e = new OakRowInconsistencyException(data.data, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakInputIllegalException': {
return new OakInputIllegalException(data.entity, data.attributes, data.message);
const e = new OakInputIllegalException(data.entity, data.attributes, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUserUnpermittedException': {
return new OakUserUnpermittedException(data.message);
const e = new OakUserUnpermittedException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUnloggedInException': {
return new OakUnloggedInException(data.message);
const e = new OakUnloggedInException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakCongruentRowExists': {
return new OakCongruentRowExists(data.entity, data.data, data.message);
const e = new OakCongruentRowExists(data.entity, data.data, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakRowLockedException': {
return new OakRowLockedException(data.message);
const e = new OakRowLockedException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakRowUnexistedException': {
return new OakRowUnexistedException(data.rows);
const e = new OakRowUnexistedException(data.rows);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakDeadlock': {
return new OakDeadlock(data.message);
const e = new OakDeadlock(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakDataException': {
return new OakDataException(data.message);
const e = new OakDataException(data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakUniqueViolationException': {
return new OakUniqueViolationException(data.rows, data.message);
const e = new OakUniqueViolationException(data.rows, data.message);
e.setOpRecords(data.opRecords);
return e;
}
case 'OakImportDataParseException': {
return new OakImportDataParseException(data.message!, data.line, data.header);
const e = new OakImportDataParseException(data.message!, data.line, data.header);
e.setOpRecords(data.opRecords);
return e;
}
default:
return;

View File

@ -25,10 +25,10 @@ function makeContentTypeAndBody(data: any) {
export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>> extends Connector<ED, BackCxt, FrontCxt> {
static ROUTER = '/aspect';
private serverUrl: string;
private makeException: (exceptionData: any) => OakException;
private makeException: (exceptionData: any) => OakException<ED>;
private contextBuilder: (str: string | undefined) => (store: AsyncRowStore<ED, BackCxt>) => Promise<BackCxt>;
constructor(serverUrl: string, makeException: (exceptionData: any) => OakException, contextBuilder: (str: string | undefined) => (store: AsyncRowStore<ED, BackCxt>) => Promise<BackCxt>) {
constructor(serverUrl: string, makeException: (exceptionData: any) => OakException<ED>, contextBuilder: (str: string | undefined) => (store: AsyncRowStore<ED, BackCxt>) => Promise<BackCxt>) {
super();
this.serverUrl = `${serverUrl}${SimpleConnector.ROUTER}`;
this.makeException = makeException;
@ -100,7 +100,7 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
};
}
serializeException(exception: OakException, headers: IncomingHttpHeaders, body: any): { body: any; headers?: Record<string, any> | undefined; } {
serializeException(exception: OakException<ED>, headers: IncomingHttpHeaders, body: any): { body: any; headers?: Record<string, any> | undefined; } {
return {
body: {
exception: exception.toString(),