Merge branch 'release'

This commit is contained in:
Xu Chang 2023-03-15 10:42:41 +08:00
commit 3d539b93db
49 changed files with 1603 additions and 1090 deletions

View File

@ -1123,7 +1123,8 @@ function constructFilter(statements, entity) {
case 'Int':
case 'Uint':
case 'Float':
case 'Double': {
case 'Double':
case 'Price': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'));
break;
}
@ -1276,7 +1277,8 @@ function constructProjection(statements, entity) {
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Object': {
case 'Object':
case 'Price': {
properties.push([name_4, false]);
break;
}
@ -1639,7 +1641,8 @@ function constructSorter(statements, entity) {
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File': {
case 'File':
case 'Price': {
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
break;
}
@ -2658,6 +2661,7 @@ var initialStatements = function () { return [
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Text')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Datetime')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('File')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Price')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Image')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('PrimaryKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ForeignKey')),
@ -2934,15 +2938,13 @@ function constructAttributes(entity) {
], true)));
break;
}
case 'Float': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("float")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(typeArguments[0].literal.text)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(typeArguments[1].literal.text))
], true)));
break;
}
case 'Double': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("double")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
case 'Double':
case 'Float':
case 'Decimal': {
if (['Double', 'Float'].includes(text)) {
console.warn("".concat(entity, "\u5BF9\u8C61\u4E2D\u8FD8\u6709").concat(text, "\u7C7B\u578B\u5B9A\u4E49\uFF0C\u73B0\u5728\u7EDF\u4E00\u7528Decimal\u8FDB\u884C\u5B58\u50A8"));
}
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("decimal")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(typeArguments[0].literal.text)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(typeArguments[1].literal.text))
], true)));
@ -2952,6 +2954,10 @@ function constructAttributes(entity) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("boolean")));
break;
}
case 'Price': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("money")));
break;
}
case 'Datetime': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("datetime")));
break;

View File

@ -21,6 +21,7 @@ var indexes = [
];
var locale = {
zh_CN: {
name: '更新',
attr: {
targetEntity: '目标对象',
entity: '关联对象',

View File

@ -6,6 +6,7 @@ var config = {
};
var locale = {
zh_CN: {
name: '更新对象连接',
attr: {
modi: '更新',
entity: '关联对象',

View File

@ -6,6 +6,7 @@ var configuration = {
};
var locale = {
zh_CN: {
name: '操作',
attr: {
action: '动作',
data: '数据',

View File

@ -6,6 +6,7 @@ var config = {
};
var locale = {
zh_CN: {
name: '操作对象连接',
attr: {
oper: '操作',
entity: '关联对象',

View File

@ -8,6 +8,7 @@ var UserActionDef = {
};
var locale = {
zh_CN: {
name: '用户',
attr: {
name: '姓名',
nickname: '昵称',

View File

@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
;
var locale = {
zh_CN: {
name: '用户授权',
attr: {
relation: '关系',
entity: '关联对象',

View File

@ -64,93 +64,91 @@ var AsyncContext = /** @class */ (function () {
};
AsyncContext.prototype.commit = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, _b, e, e_1_1;
var e_1, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
var commitEvents, commitEvents_1, commitEvents_1_1, e, e_1_1;
var e_1, _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.uuid) return [3 /*break*/, 10];
if (!this.uuid) return [3 /*break*/, 9];
return [4 /*yield*/, this.rowStore.commit(this.uuid)];
case 1:
_d.sent();
_b.sent();
this.uuid = undefined;
_d.label = 2;
commitEvents = this.events.commit;
this.resetEvents();
_b.label = 2;
case 2:
_d.trys.push([2, 7, 8, 9]);
_a = tslib_1.__values(this.events.commit), _b = _a.next();
_d.label = 3;
_b.trys.push([2, 7, 8, 9]);
commitEvents_1 = tslib_1.__values(commitEvents), commitEvents_1_1 = commitEvents_1.next();
_b.label = 3;
case 3:
if (!!_b.done) return [3 /*break*/, 6];
e = _b.value;
if (!!commitEvents_1_1.done) return [3 /*break*/, 6];
e = commitEvents_1_1.value;
return [4 /*yield*/, e()];
case 4:
_d.sent();
_d.label = 5;
_b.sent();
_b.label = 5;
case 5:
_b = _a.next();
commitEvents_1_1 = commitEvents_1.next();
return [3 /*break*/, 3];
case 6: return [3 /*break*/, 9];
case 7:
e_1_1 = _d.sent();
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 9];
case 8:
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
if (commitEvents_1_1 && !commitEvents_1_1.done && (_a = commitEvents_1.return)) _a.call(commitEvents_1);
}
finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/];
case 9:
this.resetEvents();
_d.label = 10;
case 10: return [2 /*return*/];
case 9: return [2 /*return*/];
}
});
});
};
AsyncContext.prototype.rollback = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, _b, e, e_2_1;
var e_2, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
var rollbackEvents, rollbackEvents_1, rollbackEvents_1_1, e, e_2_1;
var e_2, _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.uuid) return [3 /*break*/, 10];
if (!this.uuid) return [3 /*break*/, 9];
return [4 /*yield*/, this.rowStore.rollback(this.uuid)];
case 1:
_d.sent();
_b.sent();
// console.log('rollback', this.uuid);
this.uuid = undefined;
_d.label = 2;
rollbackEvents = this.events.rollback;
this.resetEvents();
_b.label = 2;
case 2:
_d.trys.push([2, 7, 8, 9]);
_a = tslib_1.__values(this.events.rollback), _b = _a.next();
_d.label = 3;
_b.trys.push([2, 7, 8, 9]);
rollbackEvents_1 = tslib_1.__values(rollbackEvents), rollbackEvents_1_1 = rollbackEvents_1.next();
_b.label = 3;
case 3:
if (!!_b.done) return [3 /*break*/, 6];
e = _b.value;
if (!!rollbackEvents_1_1.done) return [3 /*break*/, 6];
e = rollbackEvents_1_1.value;
return [4 /*yield*/, e()];
case 4:
_d.sent();
_d.label = 5;
_b.sent();
_b.label = 5;
case 5:
_b = _a.next();
rollbackEvents_1_1 = rollbackEvents_1.next();
return [3 /*break*/, 3];
case 6: return [3 /*break*/, 9];
case 7:
e_2_1 = _d.sent();
e_2_1 = _b.sent();
e_2 = { error: e_2_1 };
return [3 /*break*/, 9];
case 8:
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
if (rollbackEvents_1_1 && !rollbackEvents_1_1.done && (_a = rollbackEvents_1.return)) _a.call(rollbackEvents_1);
}
finally { if (e_2) throw e_2.error; }
return [7 /*endfinally*/];
case 9:
this.resetEvents();
_d.label = 10;
case 10: return [2 /*return*/];
case 9: return [2 /*return*/];
}
});
});

View File

@ -339,12 +339,18 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2, pathPrefix) {
};
var filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2);
if (!paths.length) {
// 不可能是create
return function (oper, userId) { return filterMaker(userId); };
}
/**
* 针对第一层做一下特别优化比如对象A指向对象B多对一如果A的cascadePath是 'B'
* 当create A时会带有Bid此时生成该B对象上的相关表达式查询返回可以避免必须将此判定在对象创建之后再做
* 另一使用场景是在查询A时如果带有Bid在对象跳一对多子对象场景下很常见可以提前判定这个查询对某些用户一定返回空集
*
* 20230306:
* 在前台的权限判断中会将list上的filter当成内在的限制对create动作进行判断此时有一种可能是filter并不能直接判断出外键但会限制外键的查询范围
* 例如在jichuang项目中就存在park/list上平台的用户去访问时其查询条件是{ system: { platformId: 1 }}而用户的关系落在system.platform.platformProvider上
* 此时如直接通过data上的外键判断就会失败需要通过对filter上相应的语义解构进行进一步的判断
*/
var _a = tslib_1.__read(paths, 1), attr = _a[0];
var relation = (0, relation_1.judgeRelation)(schema, entity2, attr);
@ -352,54 +358,129 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2, pathPrefix) {
var filterMaker2 = paths.length > 1
? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1))
: (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation));
var translateCreateFilterMaker = function (entity, filter, userId) {
var counters = [];
if (filter) {
if (relation === 2) {
if (filter.entity === entity && filter.entityId) {
// 这里对entityId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: filter.entityId }),
});
}
if (filter[attr]) {
counters.push({
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), filter[attr]),
});
}
}
else {
(0, assert_1.default)(typeof relation === 'string');
if (filter["".concat(attr, "Id")]) {
var filterMaker3 = paths.length > 1 ? translateFilterMakerIter(relation, 1) : translateRelationFilter(relation);
// 这里对attrId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker3(userId), { id: filter["".concat(attr, "Id")] }),
});
}
if (filter[attr]) {
counters.push({
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), filter[attr]),
});
}
}
if (filter.$and) {
var countersAnd = filter.$and.map(function (ele) { return translateCreateFilterMaker(entity, ele, userId); });
// and 只要有一个满足就行
var ca2 = countersAnd.filter(function (ele) { return !(ele instanceof Exception_1.OakUserUnpermittedException); });
counters.push.apply(counters, tslib_1.__spreadArray([], tslib_1.__read(ca2), false));
}
if (filter.$or) {
var countersOr = filter.$and.map(function (ele) { return translateCreateFilterMaker(entity, ele, userId); });
// or也只要有一个满足就行不能否定
var co2 = countersOr.filter(function (ele) { return !(ele instanceof Exception_1.OakUserUnpermittedException); });
counters.push.apply(counters, tslib_1.__spreadArray([], tslib_1.__read(co2), false));
}
}
if (counters.length === 0) {
// 一个counter都找不出来说明当前路径上不满足
return new Exception_1.OakUserUnpermittedException();
}
else if (counters.length === 1) {
return counters[0];
}
// 是or关系只要其中有一个满足就可以通过
return {
$$or: counters,
};
};
return function (operation, userId) {
var action = operation.action;
if (action === 'create') {
var data = operation.data;
var getForeignKeyId_1 = function (d) {
if (data) {
// 有data的情形根据data判定
var getForeignKeyId_1 = function (d) {
if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') {
return d.entityId;
}
throw new Exception_1.OakUserUnpermittedException();
}
else {
(0, assert_1.default)(typeof relation === 'string');
if (typeof d["".concat(attr, "Id")] === 'string') {
return d["".concat(attr, "Id")];
}
throw new Exception_1.OakUserUnpermittedException();
}
};
if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') {
return d.entitId;
if (data instanceof Array) {
var fkIds = (0, lodash_1.uniq)(data.map(function (d) { return getForeignKeyId_1(d); }));
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
}
throw new Exception_1.OakUserUnpermittedException();
var fkId_1 = getForeignKeyId_1(data);
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId_1 }),
};
}
else {
(0, assert_1.default)(typeof relation === 'string');
if (typeof d["".concat(attr, "Id")] === 'string') {
return d["".concat(attr, "Id")];
}
throw new Exception_1.OakUserUnpermittedException();
}
};
if (relation === 2) {
(0, assert_1.default)(typeof relation === 'string');
if (data instanceof Array) {
var fkIds = (0, lodash_1.uniq)(data.map(function (d) { return getForeignKeyId_1(d); }));
return {
$entity: attr,
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
}
var fkId_1 = getForeignKeyId_1(data);
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId_1 }),
};
}
(0, assert_1.default)(typeof relation === 'string');
if (data instanceof Array) {
var fkIds = (0, lodash_1.uniq)(data.map(function (d) { return getForeignKeyId_1(d); }));
var fkId = getForeignKeyId_1(data);
return {
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId }),
};
}
var fkId = getForeignKeyId_1(data);
return {
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId }),
};
else {
// todo
var filter_4 = operation.filter;
if (filter_4) {
var counter = translateCreateFilterMaker(entity2, filter_4, userId);
if (counter instanceof Exception_1.OakUserUnpermittedException) {
throw counter;
}
return counter;
}
throw new Exception_1.OakUserUnpermittedException();
}
}
var filter = operation.filter;
if (relation === 2 && (filter === null || filter === void 0 ? void 0 : filter.entity) === attr && (filter === null || filter === void 0 ? void 0 : filter.entityId)) {
@ -450,8 +531,77 @@ function translateActionAuthFilterMaker(schema, relationItem, entity, pathPrefix
var filterMaker = translateCascadeRelationFilterMaker(schema, relationItem, entity, pathPrefix);
return filterMaker;
}
function execCreateCounter(context, counter) {
if (counter === null || counter === void 0 ? void 0 : counter.$$and) {
// 每个counter都要满足才能过
var counters = counter === null || counter === void 0 ? void 0 : counter.$$and;
(0, assert_1.default)(counters.length > 0);
var counterResults = counters.map(function (ele) { return execCreateCounter(context, ele); });
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(function (cr2) {
var unpermitted = cr2.find(function (ele) { return ele instanceof Exception_1.OakUserUnpermittedException; });
if (unpermitted) {
return unpermitted;
}
return undefined;
});
}
else {
var unpermitted = counterResults.find(function (ele) { return ele instanceof Exception_1.OakUserUnpermittedException; });
if (unpermitted) {
return unpermitted;
}
else {
return undefined;
}
}
}
else if (counter === null || counter === void 0 ? void 0 : counter.$$or) {
// 只要有一个counter能过就算过
var counters = counter === null || counter === void 0 ? void 0 : counter.$$or;
(0, assert_1.default)(counters.length > 0);
var counterResults = counters.map(function (ele) { return execCreateCounter(context, ele); });
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(function (cr2) {
var permittedIdx = cr2.indexOf(undefined);
if (permittedIdx !== -1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
});
}
else {
var permittedIndex = counterResults.indexOf(undefined);
if (permittedIndex !== -1) {
return undefined;
}
else {
return new Exception_1.OakUserUnpermittedException();
}
}
}
else if (counter === null || counter === void 0 ? void 0 : counter.$entity) {
var _a = counter, $entity = _a.$entity, $filter = _a.$filter, _b = _a.$count, $count_1 = _b === void 0 ? 1 : _b;
var count = context.count($entity, {
filter: $filter,
}, { dontCollect: true });
if (count instanceof Promise) {
return count.then(function (c2) {
if (c2 >= $count_1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
});
}
else {
return count >= $count_1 ? undefined : new Exception_1.OakUserUnpermittedException();
}
}
}
function makePotentialFilter(operation, context, filterMaker) {
var e_1, _a;
var e_1, _a, e_2, _b;
var userId = context.getCurrentUserId();
(0, assert_1.default)(userId);
var filters = filterMaker instanceof Array ? filterMaker.map(function (ele) {
@ -470,103 +620,81 @@ function makePotentialFilter(operation, context, filterMaker) {
*/
var filtersOr = [];
var isAsyncOr = false;
var _loop_1 = function (f) {
var e_2, _b;
if (f instanceof Array) {
var isAsyncAnd = true;
var filtersAnd = [];
var _loop_2 = function (ff) {
if (ff === null || ff === void 0 ? void 0 : ff.$entity) {
var _e = ff, $entity = _e.$entity, $filter = _e.$filter, _f = _e.$count, $count_1 = _f === void 0 ? 1 : _f;
var count = context.count($entity, {
filter: $filter,
}, {});
if (count instanceof Promise) {
isAsyncAnd = true;
filtersAnd.push(count.then(function (c2) {
if (c2 >= $count_1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
}));
}
else {
filtersAnd.push(count >= $count_1 ? undefined : new Exception_1.OakUserUnpermittedException());
}
}
else if (ff) {
filtersAnd.push(ff);
}
};
try {
for (var f_1 = (e_2 = void 0, tslib_1.__values(f)), f_1_1 = f_1.next(); !f_1_1.done; f_1_1 = f_1.next()) {
var ff = f_1_1.value;
_loop_2(ff);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (f_1_1 && !f_1_1.done && (_b = f_1.return)) _b.call(f_1);
}
finally { if (e_2) throw e_2.error; }
}
if (isAsyncAnd = true) {
isAsyncOr = true;
filtersOr.push(isAsyncAnd ? Promise.all(filtersAnd).then(function (fa) {
var e_3, _a;
var faR = [];
try {
for (var fa_1 = (e_3 = void 0, tslib_1.__values(fa)), fa_1_1 = fa_1.next(); !fa_1_1.done; fa_1_1 = fa_1.next()) {
var faItem = fa_1_1.value;
if (faItem instanceof Exception_1.OakUserUnpermittedException) {
return faItem;
}
else if (faItem) {
faR.push(faItem);
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (fa_1_1 && !fa_1_1.done && (_a = fa_1.return)) _a.call(fa_1);
}
finally { if (e_3) throw e_3.error; }
}
if (faR.length > 0) {
return {
$and: faR,
};
}
}) : {
$and: filtersAnd,
});
}
}
else {
if (f === null || f === void 0 ? void 0 : f.$entity) {
var _c = f, $entity = _c.$entity, $filter = _c.$filter, _d = _c.$count, $count_2 = _d === void 0 ? 1 : _d;
var count = context.count($entity, {
filter: $filter,
}, {});
if (count instanceof Promise) {
isAsyncOr = true;
filtersOr.push(count.then(function (c2) { return c2 >= $count_2 ? undefined : new Exception_1.OakUserUnpermittedException(); }));
}
else {
filtersOr.push(count >= $count_2 ? undefined : new Exception_1.OakUserUnpermittedException());
}
}
else if (f) {
filtersOr.push(f);
}
}
};
try {
for (var filters_1 = tslib_1.__values(filters), filters_1_1 = filters_1.next(); !filters_1_1.done; filters_1_1 = filters_1.next()) {
var f = filters_1_1.value;
_loop_1(f);
if (f instanceof Array) {
var isAsyncAnd = false;
(0, assert_1.default)(f.length > 0);
var filtersAnd = [];
try {
for (var f_1 = (e_2 = void 0, tslib_1.__values(f)), f_1_1 = f_1.next(); !f_1_1.done; f_1_1 = f_1.next()) {
var ff = f_1_1.value;
if ((ff === null || ff === void 0 ? void 0 : ff.$$and) || (ff === null || ff === void 0 ? void 0 : ff.$$or) || (ff === null || ff === void 0 ? void 0 : ff.$entity)) {
// 每个counter都要满足才能过
var result = execCreateCounter(context, ff);
if (result instanceof Promise) {
isAsyncAnd = true;
}
filtersAnd.push(result);
}
else if (ff) {
filtersAnd.push(ff);
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (f_1_1 && !f_1_1.done && (_b = f_1.return)) _b.call(f_1);
}
finally { if (e_2) throw e_2.error; }
}
if (isAsyncAnd = true) {
isAsyncOr = true;
filtersOr.push(isAsyncAnd ? Promise.all(filtersAnd).then(function (fa) {
var e_3, _a;
var faR = [];
try {
for (var fa_1 = (e_3 = void 0, tslib_1.__values(fa)), fa_1_1 = fa_1.next(); !fa_1_1.done; fa_1_1 = fa_1.next()) {
var faItem = fa_1_1.value;
if (faItem instanceof Exception_1.OakUserUnpermittedException) {
return faItem;
}
else if (faItem) {
faR.push(faItem);
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (fa_1_1 && !fa_1_1.done && (_a = fa_1.return)) _a.call(fa_1);
}
finally { if (e_3) throw e_3.error; }
}
if (faR.length > 0) {
return {
$and: faR,
};
}
}) : {
$and: filtersAnd,
});
}
}
else {
if ((f === null || f === void 0 ? void 0 : f.$$and) || (f === null || f === void 0 ? void 0 : f.$$or) || (f === null || f === void 0 ? void 0 : f.$entity)) {
var counterResults = execCreateCounter(context, f);
if (counterResults instanceof Promise) {
isAsyncOr = true;
}
filtersOr.push(counterResults);
}
else if (f) {
filtersOr.push(f);
}
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@ -603,18 +731,30 @@ function makePotentialFilter(operation, context, filterMaker) {
*/
function createAuthCheckers(schema, authDict) {
var checkers = [];
var _loop_3 = function (entity) {
var _loop_1 = function (entity) {
var _a;
if (authDict[entity]) {
var _b = authDict[entity], relationAuth = _b.relationAuth, actionAuth = _b.actionAuth;
if (relationAuth) {
var raFilterMakerDict_1 = {};
var userEntityName = "user".concat((0, string_1.firstLetterUpperCase)(entity));
var allAuthItem = [];
for (var r in relationAuth) {
var authItem = relationAuth[r];
Object.assign(raFilterMakerDict_1, (_a = {},
_a[r] = translateActionAuthFilterMaker(schema, relationAuth[r], userEntityName, entity),
_a[r] = translateActionAuthFilterMaker(schema, authItem, userEntityName, entity),
_a));
if (authItem instanceof Array) {
allAuthItem.push.apply(allAuthItem, tslib_1.__spreadArray([], tslib_1.__read(authItem), false));
}
else {
allAuthItem.push(authItem);
}
}
// 如果不指定relation则使用所有的authItem的or组合
Object.assign(raFilterMakerDict_1, {
'@@all': translateActionAuthFilterMaker(schema, allAuthItem, userEntityName, entity),
});
var entityIdAttr_1 = "".concat(entity, "Id");
checkers.push({
entity: userEntityName,
@ -624,8 +764,12 @@ function createAuthCheckers(schema, authDict) {
var data = operation.data;
(0, assert_1.default)(!(data instanceof Array));
var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b];
if (!relation) {
// 不指定relation测试是否有创建权限
return makePotentialFilter(operation, context, raFilterMakerDict_1['@@all']);
}
if (!raFilterMakerDict_1[relation]) {
return;
throw new Exception_1.OakUserUnpermittedException();
}
var filter = makePotentialFilter(operation, context, raFilterMakerDict_1[relation]);
return filter;
@ -694,7 +838,7 @@ function createAuthCheckers(schema, authDict) {
// todo 等实现的时候再写
}
if (actionAuth) {
var _loop_4 = function (a) {
var _loop_2 = function (a) {
var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity);
checkers.push({
entity: entity,
@ -709,13 +853,13 @@ function createAuthCheckers(schema, authDict) {
});
};
for (var a in actionAuth) {
_loop_4(a);
_loop_2(a);
}
}
}
};
for (var entity in schema) {
_loop_3(entity);
_loop_1(entity);
}
return checkers;
}
@ -784,7 +928,7 @@ function createRemoveCheckers(schema, authDict) {
}
// 当删除一时,要确认多上面没有指向一的数据
var entities = (0, lodash_1.union)(Object.keys(OneToManyMatrix), Object.keys(OneToManyOnEntityMatrix));
var _loop_5 = function (entity) {
var _loop_3 = function (entity) {
checkers.push({
entity: entity,
action: 'remove',
@ -793,7 +937,7 @@ function createRemoveCheckers(schema, authDict) {
var e_6, _a, e_7, _b;
var promises = [];
if (OneToManyMatrix[entity]) {
var _loop_7 = function (otm) {
var _loop_5 = function (otm) {
var _g, _h;
var _j = tslib_1.__read(otm, 2), e = _j[0], attr = _j[1];
var proj = (_g = {
@ -832,7 +976,7 @@ function createRemoveCheckers(schema, authDict) {
try {
for (var _c = (e_6 = void 0, tslib_1.__values(OneToManyMatrix[entity])), _d = _c.next(); !_d.done; _d = _c.next()) {
var otm = _d.value;
_loop_7(otm);
_loop_5(otm);
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
@ -844,7 +988,7 @@ function createRemoveCheckers(schema, authDict) {
}
}
if (OneToManyOnEntityMatrix[entity]) {
var _loop_8 = function (otm) {
var _loop_6 = function (otm) {
var _l, _m, _o;
var proj = {
id: 1,
@ -890,7 +1034,7 @@ function createRemoveCheckers(schema, authDict) {
try {
for (var _e = (e_7 = void 0, tslib_1.__values(OneToManyOnEntityMatrix[entity])), _f = _e.next(); !_f.done; _f = _e.next()) {
var otm = _f.value;
_loop_8(otm);
_loop_6(otm);
}
}
catch (e_7_1) { e_7 = { error: e_7_1 }; }
@ -910,7 +1054,7 @@ function createRemoveCheckers(schema, authDict) {
try {
for (var entities_1 = tslib_1.__values(entities), entities_1_1 = entities_1.next(); !entities_1_1.done; entities_1_1 = entities_1.next()) {
var entity = entities_1_1.value;
_loop_5(entity);
_loop_3(entity);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
@ -920,13 +1064,13 @@ function createRemoveCheckers(schema, authDict) {
}
finally { if (e_4) throw e_4.error; }
}
var _loop_6 = function (entity) {
var _loop_4 = function (entity) {
var e_8, _b;
var cascadeRemove = authDict[entity].cascadeRemove;
if (cascadeRemove) {
var entitiesOnEntityAttr = [];
var hasAllEntity = false;
var _loop_9 = function (attr) {
var _loop_7 = function (attr) {
if (attr === '@entity') {
hasAllEntity = true;
return "continue";
@ -1001,13 +1145,13 @@ function createRemoveCheckers(schema, authDict) {
}
};
for (var attr in cascadeRemove) {
_loop_9(attr);
_loop_7(attr);
}
if (hasAllEntity) {
var attributes = schema[entity].attributes;
var ref = attributes.entity.ref;
var restEntities = (0, lodash_1.difference)(ref, entitiesOnEntityAttr);
var _loop_10 = function (e) {
var _loop_8 = function (e) {
checkers.push({
entity: e,
action: 'remove',
@ -1043,7 +1187,7 @@ function createRemoveCheckers(schema, authDict) {
try {
for (var restEntities_1 = (e_8 = void 0, tslib_1.__values(restEntities)), restEntities_1_1 = restEntities_1.next(); !restEntities_1_1.done; restEntities_1_1 = restEntities_1.next()) {
var e = restEntities_1_1.value;
_loop_10(e);
_loop_8(e);
}
}
catch (e_8_1) { e_8 = { error: e_8_1 }; }
@ -1058,7 +1202,7 @@ function createRemoveCheckers(schema, authDict) {
};
// 注入声明的cascade删除时的外键处理动作
for (var entity in authDict) {
_loop_6(entity);
_loop_4(entity);
}
return checkers;
}

View File

@ -8,11 +8,14 @@ export declare type Text = string;
export declare type Image = string;
export declare type File = string;
export declare type Datetime = number | Date;
export declare type Day = number | Date;
export declare type Time = number | Date;
export declare type Boolean = boolean;
export declare type Price = number;
export declare type PrimaryKey = string;
export declare type ForeignKey<E extends string> = string;
export declare type Sequence = string;
export { Geo, SingleGeo } from './Geo';
export declare type DataTypes = number | string | Datetime | Geo | Object | SingleGeo;
export declare type DataTypes = number | string | Datetime | Day | Time | Geo | Object | SingleGeo;
export declare const types: string[];
export declare const unIndexedTypes: string[];

View File

@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unIndexedTypes = exports.types = void 0;
exports.types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Boolean', 'Image', 'File', 'Geo', 'SingleGeo'];
exports.types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Day', 'Time',
'Boolean', 'Image', 'File', 'Geo', 'SingleGeo', 'Price'];
exports.unIndexedTypes = ['Text', 'Image', 'File', 'Object'];

View File

@ -13,6 +13,7 @@ declare type LocaleOfValue<V extends Record<string, string>> = {
};
export declare type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = {
[L in Language]?: {
name: string;
attr: LocaleOfSchema<Sc> & {
[A in keyof V]: string;
};

11
lib/types/Style.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
import { EntityDict } from './Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
declare type ThemeColor = 'default' | 'success' | 'warning' | 'error';
export declare type ColorDict<ED extends BaseEntityDict & EntityDict> = {
[T in keyof ED]?: {
[A in keyof ED[T]['OpSchema']]?: {
[E in ED[T]['OpSchema'][A]]?: ThemeColor | `#${string}`;
};
};
};
export {};

2
lib/types/Style.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -1,5 +1,6 @@
import { RecurrenceRule, RecurrenceSpecDateRange, RecurrenceSpecObjLit } from 'node-schedule';
import { EntityDict } from './Entity';
import { AsyncContext } from "../store/AsyncRowStore";
import { AsyncContext } from '../store/AsyncRowStore';
declare type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>;
export declare type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string;
@ -7,7 +8,7 @@ export declare type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>>
};
export declare type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string;
cron: string;
cron: RecurrenceRule | RecurrenceSpecDateRange | RecurrenceSpecObjLit | Date | string | number;
fn: RoutineFn<ED, Cxt>;
};
export {};

View File

@ -19,3 +19,4 @@ export * from './Connector';
export * from './Timer';
export * from './Port';
export * from './Endpoint';
export * from './Style';

View File

@ -22,3 +22,4 @@ tslib_1.__exportStar(require("./Connector"), exports);
tslib_1.__exportStar(require("./Timer"), exports);
tslib_1.__exportStar(require("./Port"), exports);
tslib_1.__exportStar(require("./Endpoint"), exports);
tslib_1.__exportStar(require("./Style"), exports);

View File

@ -29,4 +29,6 @@ export interface DataTypeParams {
precision?: number;
scale?: number;
signed?: boolean;
max?: number;
min?: number;
}

View File

@ -10,7 +10,7 @@ function makeContentTypeAndBody(data) {
if (process.env.OAK_PLATFORM !== 'wechatMp') {
if (data instanceof FormData) {
return {
contentType: 'multipart/form-data',
// contentType: 'multipart/form-data',
body: data,
};
}
@ -39,11 +39,12 @@ var SimpleConnector = /** @class */ (function (_super) {
_a = makeContentTypeAndBody(params), contentType = _a.contentType, body = _a.body;
return [4 /*yield*/, global.fetch(this.serverUrl, {
method: 'POST',
headers: {
'Content-Type': contentType,
headers: Object.assign({
'oak-cxt': cxtStr,
'oak-aspect': name,
},
}, contentType && {
'Content-Type': contentType,
}),
body: body,
})];
case 1:
@ -106,7 +107,7 @@ var SimpleConnector = /** @class */ (function (_super) {
});
};
SimpleConnector.prototype.serializeResult = function (result, context, headers, body) {
if (result instanceof stream_1.Stream) {
if (result instanceof stream_1.Stream || result instanceof Buffer) {
return {
body: result,
};

1
lib/utils/cron.d.ts vendored
View File

@ -1 +0,0 @@
export declare function schedule(cron: string, fn: (date: Date) => any): void;

View File

@ -1,18 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.schedule = void 0;
var tslib_1 = require("tslib");
var cronjs_matcher_1 = require("@datasert/cronjs-matcher");
var dayjs_1 = tslib_1.__importDefault(require("dayjs"));
function schedule(cron, fn) {
var futureMatches = (0, cronjs_matcher_1.getFutureMatches)(cron, {
matchCount: 1,
});
var date = (0, dayjs_1.default)(futureMatches[0]);
var interval = date.diff((0, dayjs_1.default)(), 'ms');
setTimeout(function () {
fn(new Date());
schedule(cron, fn);
}, interval);
}
exports.schedule = schedule;

5
lib/utils/mask.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare const maskIdCard: (idCardNumber: string) => string;
declare const maskMobile: (mobile: string) => string;
declare const maskName: (name: string) => string;
declare const maskStar: (str: string, front: number, end: number, star: string) => string;
export { maskIdCard, maskMobile, maskName, maskStar, };

35
lib/utils/mask.js Normal file
View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.maskStar = exports.maskName = exports.maskMobile = exports.maskIdCard = void 0;
var maskIdCard = function (idCardNumber) {
if (!idCardNumber instanceof String) {
throw new Error("身份证号码必须是String类型");
}
var begin = idCardNumber.slice(0, 4);
var end = idCardNumber.slice(idCardNumber.length - 4, 4);
for (var i = 0; i < idCardNumber.length - 8; i++) {
begin = begin.concat("*");
}
return begin.concat(end);
};
exports.maskIdCard = maskIdCard;
var maskMobile = function (mobile) {
var begin = mobile.slice(0, 3);
var end = mobile.slice(7, 11);
return begin.concat("****").concat(end);
};
exports.maskMobile = maskMobile;
var maskName = function (name) {
return name.slice(0, name.length - 1).concat("*");
};
exports.maskName = maskName;
var maskStar = function (str, frontLen, endLen, star) {
if (star === void 0) { star = '*'; }
var len = str.length - frontLen - endLen;
var xing = '';
for (var i = 0; i < len; i++) {
xing += star;
}
return str.substring(0, frontLen) + xing + str.substring(str.length - endLen);
};
exports.maskStar = maskStar;

5
lib/utils/money.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare const ToCent: (float: number) => number;
declare const ToYuan: (int: number) => number;
declare const StringToCent: (value: string, allowNegative?: true) => number | undefined;
declare const CentToString: (value: number) => string | undefined;
export { ToCent, ToYuan, StringToCent, CentToString, };

24
lib/utils/money.js Normal file
View File

@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CentToString = exports.StringToCent = exports.ToYuan = exports.ToCent = void 0;
var ToCent = function (float) {
return Math.round(float * 100);
};
exports.ToCent = ToCent;
var ToYuan = function (int) {
return Math.round(int) / 100;
};
exports.ToYuan = ToYuan;
var StringToCent = function (value, allowNegative) {
var numValue = parseInt(value, 10);
if (typeof numValue === 'number' && (numValue >= 0 || allowNegative)) {
return ToCent(numValue);
}
};
exports.StringToCent = StringToCent;
var CentToString = function (value) {
if (typeof value === 'number') {
return "".concat(ToYuan(value));
}
};
exports.CentToString = CentToString;

View File

@ -16,6 +16,7 @@ export declare const isNickname: ValidatorFunction;
export declare const isSizedCaptcha: ValidatorFunction;
export declare const isDigital: ValidatorFunction;
export declare const isPhone: ValidatorFunction;
export declare const isTel: ValidatorFunction;
export declare const isNumber: ValidatorFunction;
export declare const isMoney: ValidatorMoneyFunction;
export declare const isVehicleNumber: ValidatorFunction;

View File

@ -3,7 +3,7 @@
*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkAttributesScope = exports.checkAttributesNotNull = exports.isVehicleNumber = exports.isMoney = exports.isNumber = exports.isPhone = exports.isDigital = exports.isSizedCaptcha = exports.isNickname = exports.isUrl = exports.isSoldierNumber = exports.isBirthNumber = exports.isTwCardNumber = exports.isAmCardNumber = exports.isHkCardNumber = exports.isPassportNumber = exports.isIdCardNumber = exports.isCaptcha = exports.isPassword = exports.isMobile = void 0;
exports.checkAttributesScope = exports.checkAttributesNotNull = exports.isVehicleNumber = exports.isMoney = exports.isNumber = exports.isTel = exports.isPhone = exports.isDigital = exports.isSizedCaptcha = exports.isNickname = exports.isUrl = exports.isSoldierNumber = exports.isBirthNumber = exports.isTwCardNumber = exports.isAmCardNumber = exports.isHkCardNumber = exports.isPassportNumber = exports.isIdCardNumber = exports.isCaptcha = exports.isPassword = exports.isMobile = void 0;
var types_1 = require("../types");
var isMobile = function (text) {
return ((text) && (typeof text === "string") && ((/^1[3|4|5|6|7|8|9]\d{9}$/.test(text))));
@ -79,14 +79,19 @@ var isPhone = function (phone) {
return /^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/.test(phone);
};
exports.isPhone = isPhone;
var isTel = function (text) {
// 1、133xxxx4545 2、0571-630xx239 3、400-123-1400
var reg = /^(((\d{3,4}-)?[0-9]{7,8})|(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}|((400)-(\d{3})-(\d{4})(.)(\d{1,4})|(400)-(\d{3})-(\d{4}$)|(400)(\d{3})(\d{4}$)|(400)-(\d{4})-(\d{3}$)))$/.test(text);
return reg;
};
exports.isTel = isTel;
var isNumber = function (str) {
return /^[0-9]*$/.test(str);
};
exports.isNumber = isNumber;
var isMoney = function (str, zero) {
// zero为true包含零
// 金额,最多可以有两位小数 zero为true包含零
if (zero) {
// 金额,最多可以有两位小数
return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(str);
}
return /(^[1-9](\d+)?(\.\d{1,2})?$)|(^\d\.\d{1,2}$)/.test(str);

View File

@ -1,6 +1,6 @@
{
"name": "oak-domain",
"version": "2.6.3",
"version": "2.6.4",
"author": {
"name": "XuChang"
},
@ -27,6 +27,7 @@
"@types/luxon": "^2.0.9",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.25",
"@types/node-schedule": "^2.1.0",
"@types/react": "^17.0.2",
"@types/uuid": "^8.3.0",
"@types/wechat-miniprogram": "^3.4.1",
@ -40,9 +41,9 @@
"typescript": "^4.7.4"
},
"dependencies": {
"@datasert/cronjs-matcher": "^1.2.0",
"dayjs": "^1.11.5",
"lodash": "^4.17.21",
"node-schedule": "^2.1.1",
"uuid": "^9.0.0"
}
}

View File

@ -1642,7 +1642,8 @@ function constructFilter(statements: Array<ts.Statement>, entity: string) {
case 'Int':
case 'Uint':
case 'Float':
case 'Double': {
case 'Double':
case 'Price': {
type2 = factory.createTypeReferenceNode(
factory.createIdentifier('Q_NumberValue'),
);
@ -1897,7 +1898,8 @@ function constructProjection(statements: Array<ts.Statement>, entity: string) {
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Object': {
case 'Object':
case 'Price': {
properties.push(
[name, false]
)
@ -2410,7 +2412,8 @@ function constructSorter(statements: Array<ts.Statement>, entity: string) {
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File': {
case 'File':
case 'Price': {
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
break;
}
@ -4417,6 +4420,11 @@ const initialStatements = () => [
undefined,
factory.createIdentifier('File')
),
factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier('Price')
),
factory.createImportSpecifier(
false,
undefined,
@ -5332,40 +5340,16 @@ function constructAttributes(entity: string): ts.PropertyAssignment[] {
);
break;
}
case 'Float': {
case 'Double':
case 'Float':
case 'Decimal': {
if (['Double', 'Float'].includes(text)) {
console.warn(`${entity}对象中还有${text}类型定义现在统一用Decimal进行存储`);
}
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("float")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("precision"),
factory.createNumericLiteral(
(<ts.NumericLiteral>(<ts.LiteralTypeNode>typeArguments![0]).literal).text
)
),
factory.createPropertyAssignment(
factory.createIdentifier("scale"),
factory.createNumericLiteral(
(<ts.NumericLiteral>(<ts.LiteralTypeNode>typeArguments![1]).literal).text
)
)
],
true
)
)
);
break;
}
case 'Double': {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("double")
factory.createStringLiteral("decimal")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
@ -5399,6 +5383,15 @@ function constructAttributes(entity: string): ts.PropertyAssignment[] {
);
break;
}
case 'Price': {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("money")
),
);
break;
}
case 'Datetime': {
attrAssignments.push(
factory.createPropertyAssignment(

View File

@ -43,6 +43,7 @@ const locale: LocaleDef<Schema, Action, '', {
iState: IState,
}> = {
zh_CN: {
name: '更新',
attr: {
targetEntity: '目标对象',
entity: '关联对象',

View File

@ -15,6 +15,7 @@ const config: Configuration = {
const locale: LocaleDef<Schema, '', '', {}> = {
zh_CN: {
name: '更新对象连接',
attr: {
modi: '更新',
entity: '关联对象',

View File

@ -17,6 +17,7 @@ const configuration: Configuration = {
const locale: LocaleDef<Schema, '', '', {}> = {
zh_CN: {
name: '操作',
attr: {
action: '动作',
data: '数据',

View File

@ -15,6 +15,7 @@ const config: Configuration = {
const locale: LocaleDef<Schema, '', '', {}> = {
zh_CN: {
name: '操作对象连接',
attr: {
oper: '操作',
entity: '关联对象',

View File

@ -25,6 +25,7 @@ const locale: LocaleDef<Schema, Action, '', {
userState: UserState;
}> = {
zh_CN: {
name: '用户',
attr: {
name: '姓名',
nickname: '昵称',

View File

@ -15,6 +15,7 @@ const locale: LocaleDef<
{}
> = {
zh_CN: {
name: '用户授权',
attr: {
relation: '关系',
entity: '关联对象',

View File

@ -30,7 +30,7 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
setHeaders(headers: IncomingHttpHeaders) {
this.headers = headers;
}
getHeader(key: string): string | string[] | undefined {
if (this.headers) {
return this.headers[key];
@ -43,13 +43,13 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
this.scene = scene;
}
private resetEvents() {
private resetEvents() {
this.events = {
commit: [],
rollback: [],
};
}
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void {
this.uuid && this.events[event].push(callback);
}
@ -70,24 +70,26 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
if (this.uuid) {
await this.rowStore.commit(this.uuid!);
this.uuid = undefined;
for(const e of this.events.commit) {
const { commit: commitEvents } = this.events;
this.resetEvents();
for (const e of commitEvents) {
await e();
}
this.resetEvents();
}
}
async rollback(): Promise<void> {
if(this.uuid) {
if (this.uuid) {
await this.rowStore.rollback(this.uuid!);
// console.log('rollback', this.uuid);
this.uuid = undefined;
for(const e of this.events.rollback) {
const { rollback: rollbackEvents } = this.events;
this.resetEvents();
for (const e of rollbackEvents) {
await e();
}
this.resetEvents();
}
}
operate<T extends keyof ED, OP extends OperateOption>(
entity: T,
operation: ED[T]['Operation'],
@ -95,21 +97,21 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
) {
return this.rowStore.operate(entity, operation, this, option);
}
select<T extends keyof ED, OP extends SelectOption> (
select<T extends keyof ED, OP extends SelectOption>(
entity: T,
selection: ED[T]['Selection'],
option: OP
) {
return this.rowStore.select(entity, selection, this, option);
}
aggregate<T extends keyof ED, OP extends SelectOption> (
aggregate<T extends keyof ED, OP extends SelectOption>(
entity: T,
aggregation: ED[T]['Aggregation'],
option: OP
) {
return this.rowStore.aggregate(entity, aggregation, this, option);
}
count<T extends keyof ED, OP extends SelectOption> (
count<T extends keyof ED, OP extends SelectOption>(
entity: T,
selection: Pick<ED[T]['Selection'], 'filter' | 'count'>,
option: OP
@ -120,7 +122,7 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
mergeMultipleResults(toBeMerged: OperationResult<ED>[]) {
return this.rowStore.mergeMultipleResults(toBeMerged);
}
getCurrentTxnId() {
return this.uuid;
}
@ -140,7 +142,7 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
abstract isRoot(): boolean;
abstract getCurrentUserId(allowUnloggedIn?: boolean): string | undefined;
abstract toString(): string;
abstract allowUserUpdate(): boolean;
@ -154,21 +156,21 @@ export interface AsyncRowStore<ED extends EntityDict, Cxt extends Context> exten
option: OP
): Promise<OperationResult<ED>>;
select<T extends keyof ED, OP extends SelectOption> (
select<T extends keyof ED, OP extends SelectOption>(
entity: T,
selection: ED[T]['Selection'],
context: Cxt,
option: OP
): Promise<Partial<ED[T]['Schema']>[]>;
aggregate<T extends keyof ED, OP extends SelectOption> (
aggregate<T extends keyof ED, OP extends SelectOption>(
entity: T,
aggregation: ED[T]['Aggregation'],
context: Cxt,
option: OP
): Promise<AggregationResult<ED[T]['Schema']>>;
count<T extends keyof ED, OP extends SelectOption> (
count<T extends keyof ED, OP extends SelectOption>(
entity: T,
selection: Pick<ED[T]['Selection'], 'filter' | 'count'>,
context: Cxt,

File diff suppressed because it is too large Load Diff

View File

@ -220,12 +220,22 @@ export function translateCheckerInSyncContext<
}
}
type FilterMakeFn<ED extends EntityDict & BaseEntityDict> = (operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'], userId: string) => ED[keyof ED]['Selection']['filter'] | {
type CreateRelationSingleCounter<ED extends EntityDict & BaseEntityDict> = {
$entity: keyof ED;
$filter?: ED[keyof ED]['Selection']['filter'];
$count?: number;
};
type CreateRelationMultipleCounter<ED extends EntityDict & BaseEntityDict> = {
[K in '$$and' | '$$or']?: (CreateRelationSingleCounter<ED> | CreateRelationMultipleCounter<ED>)[];
}
type CreateRelationCounter<ED extends EntityDict & BaseEntityDict> = CreateRelationSingleCounter<ED> | CreateRelationMultipleCounter<ED>;
type FilterMakeFn<ED extends EntityDict & BaseEntityDict> =
(operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'], userId: string) => ED[keyof ED]['Selection']['filter'] | CreateRelationCounter<ED>;
function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityDict>(
schema: StorageSchema<ED>,
lch: CascadeRelationItem,
@ -315,12 +325,18 @@ function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityD
const filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2);
if (!paths.length) {
// 不可能是create
return (oper, userId) => filterMaker(userId);
}
/**
* A指向对象BA的cascadePath是 'B'
* create A时BidB对象上的相关表达式查询返回
* 使A时Bid
*
* 20230306:
* list上的filter当成内在的限制对create动作进行判断filter并不能直接判断出外键
* jichuang项目中park/list上访{ system: { platformId: 1 }}system.platform.platformProvider上
* data上的外键判断就会失败filter上相应的语义解构
*/
const [attr] = paths;
const relation = judgeRelation(schema, entity2, attr);
@ -328,54 +344,145 @@ function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityD
const filterMaker2 = paths.length > 1
? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1))
: (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation));
const translateCreateFilterMaker = (
entity: keyof ED,
filter: ED[keyof ED]['Selection']['filter'],
userId: string
): CreateRelationCounter<ED> | OakUserUnpermittedException<ED> => {
const counters: CreateRelationCounter<ED>[] = [];
if (filter) {
if (relation === 2) {
if (filter.entity === entity && filter.entityId) {
// 这里对entityId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: attr,
$filter: addFilterSegment(filterMaker2(userId), { id: filter.entityId }),
});
}
if (filter[attr]) {
counters.push({
$entity: attr,
$filter: addFilterSegment(filterMaker2(userId), filter[attr]),
});
}
}
else {
assert(typeof relation === 'string');
if (filter[`${attr}Id`]) {
const filterMaker3 = paths.length > 1 ? translateFilterMakerIter(relation, 1) : translateRelationFilter(relation);
// 这里对attrId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: relation,
$filter: addFilterSegment(filterMaker3(userId), { id: filter[`${attr}Id`] }),
});
}
if (filter[attr]) {
counters.push({
$entity: relation,
$filter: addFilterSegment(filterMaker2(userId), filter[attr]),
});
}
}
if (filter.$and) {
const countersAnd = filter.$and.map(
(ele: ED[keyof ED]['Selection']['filter']) => translateCreateFilterMaker(entity, ele, userId)
) as ReturnType<typeof translateCreateFilterMaker>[];
// and 只要有一个满足就行
const ca2 = countersAnd.filter(
ele => !(ele instanceof OakUserUnpermittedException)
) as CreateRelationCounter<ED>[];
counters.push(...ca2);
}
if (filter.$or) {
const countersOr = filter.$and.map(
(ele: ED[keyof ED]['Selection']['filter']) => translateCreateFilterMaker(entity, ele, userId)
) as ReturnType<typeof translateCreateFilterMaker>[];
// or也只要有一个满足就行不能否定
const co2 = countersOr.filter(
ele => !(ele instanceof OakUserUnpermittedException)
) as CreateRelationCounter<ED>[];
counters.push(...co2);
}
}
if (counters.length === 0) {
// 一个counter都找不出来说明当前路径上不满足
return new OakUserUnpermittedException();
}
else if (counters.length === 1) {
return counters[0];
}
// 是or关系只要其中有一个满足就可以通过
return {
$$or: counters,
};
};
return (operation, userId) => {
const { action } = operation as ED[keyof ED]['Operation'];
if (action === 'create') {
const { data } = operation as ED[keyof ED]['Create'];
const getForeignKeyId = (d: ED[keyof ED]['CreateSingle']['data']) => {
if (data) {
// 有data的情形根据data判定
const getForeignKeyId = (d: ED[keyof ED]['CreateSingle']['data']) => {
if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') {
return d.entityId as string;
}
throw new OakUserUnpermittedException();
}
else {
assert(typeof relation === 'string');
if (typeof d[`${attr}Id`] === 'string') {
return d[`${attr}Id`] as string;
}
throw new OakUserUnpermittedException();
}
};
if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') {
return d.entitId as string;
if (data instanceof Array) {
const fkIds = uniq(data.map(d => getForeignKeyId(d)));
return {
$entity: attr,
$filter: addFilterSegment(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
}
throw new OakUserUnpermittedException();
const fkId = getForeignKeyId(data);
return {
$entity: attr,
$filter: addFilterSegment(filterMaker2(userId), { id: fkId }),
};
}
else {
assert(typeof relation === 'string');
if (typeof d[`${attr}Id`] === 'string') {
return d[`${attr}Id`] as string;
}
throw new OakUserUnpermittedException();
}
};
if (relation === 2) {
assert(typeof relation === 'string');
if (data instanceof Array) {
const fkIds = uniq(data.map(d => getForeignKeyId(d)));
return {
$entity: attr,
$entity: relation,
$filter: addFilterSegment(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
}
const fkId = getForeignKeyId(data);
return {
$entity: attr,
$entity: relation,
$filter: addFilterSegment(filterMaker2(userId), { id: fkId }),
};
}
assert(typeof relation === 'string');
if (data instanceof Array) {
const fkIds = uniq(data.map(d => getForeignKeyId(d)));
return {
$entity: relation,
$filter: addFilterSegment(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
else {
// todo
const { filter } = operation as ED[keyof ED]['Selection'];
if (filter) {
const counter = translateCreateFilterMaker(entity2, filter, userId);
if (counter instanceof OakUserUnpermittedException) {
throw counter;
}
return counter;
}
throw new OakUserUnpermittedException();
}
const fkId = getForeignKeyId(data);
return {
$entity: relation,
$filter: addFilterSegment(filterMaker2(userId), { id: fkId }),
};
}
const { filter } = operation;
if (relation === 2 && filter?.entity === attr && filter?.entityId) {
@ -437,7 +544,94 @@ function translateActionAuthFilterMaker<ED extends EntityDict & BaseEntityDict>(
return filterMaker;
}
function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>> (
function execCreateCounter<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(
context: Cxt,
counter: CreateRelationCounter<ED>,
): SyncOrAsync<undefined | OakUserUnpermittedException<ED>> {
if ((<CreateRelationMultipleCounter<ED>>counter)?.$$and) {
// 每个counter都要满足才能过
const counters = (<CreateRelationMultipleCounter<ED>>counter)?.$$and!;
assert(counters.length > 0);
const counterResults = counters.map(
ele => execCreateCounter(context, ele)
);
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(
(cr2) => {
const unpermitted = cr2.find(
(ele) => ele instanceof OakUserUnpermittedException
);
if (unpermitted) {
return unpermitted;
}
return undefined;
}
);
}
else {
const unpermitted = counterResults.find(
(ele) => ele instanceof OakUserUnpermittedException
);
if (unpermitted) {
return unpermitted;
}
else {
return undefined;
}
}
}
else if ((<CreateRelationMultipleCounter<ED>>counter)?.$$or) {
// 只要有一个counter能过就算过
const counters = (<CreateRelationMultipleCounter<ED>>counter)?.$$or!;
assert(counters.length > 0);
const counterResults = counters.map(
ele => execCreateCounter(context, ele)
);
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(
(cr2) => {
const permittedIdx = cr2.indexOf(undefined);
if (permittedIdx !== -1) {
return undefined;
}
return new OakUserUnpermittedException();
}
);
}
else {
const permittedIndex = counterResults.indexOf(undefined);
if (permittedIndex !== -1) {
return undefined;
}
else {
return new OakUserUnpermittedException();
}
}
}
else if ((<CreateRelationSingleCounter<ED>>counter)?.$entity) {
const { $entity, $filter, $count = 1 } = counter as CreateRelationSingleCounter<ED>;
const count = context.count($entity, {
filter: $filter,
}, { dontCollect: true });
if (count instanceof Promise) {
return count.then(
(c2) => {
if (c2 >= $count) {
return undefined;
}
return new OakUserUnpermittedException();
}
);
}
else {
return count >= $count ? undefined : new OakUserUnpermittedException();
}
}
}
function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(
operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'],
context: Cxt,
filterMaker: FilterMakeFn<ED> | (FilterMakeFn<ED> | FilterMakeFn<ED>[])[]): SyncOrAsync<ED[keyof ED]['Selection']['filter']> {
@ -466,30 +660,17 @@ function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends
let isAsyncOr = false;
for (const f of filters) {
if (f instanceof Array) {
let isAsyncAnd = true;
let isAsyncAnd = false;
assert(f.length > 0);
const filtersAnd: (SyncOrAsync<ED[keyof ED]['Selection']['filter'] | OakUserUnpermittedException<ED>>)[] = [];
for (const ff of f) {
if (ff?.$entity) {
const { $entity, $filter, $count = 1 } = ff!;
const count = context.count($entity, {
filter: $filter,
}, {});
if (count instanceof Promise) {
if ((<CreateRelationMultipleCounter<ED>>ff)?.$$and || (<CreateRelationMultipleCounter<ED>>ff)?.$$or || (<CreateRelationSingleCounter<ED>>ff)?.$entity) {
// 每个counter都要满足才能过
const result = execCreateCounter<ED, Cxt>(context, ff as CreateRelationMultipleCounter<ED>);
if (result instanceof Promise) {
isAsyncAnd = true;
filtersAnd.push(
count.then(
(c2) => {
if (c2 >= $count) {
return undefined;
}
return new OakUserUnpermittedException();
}
)
);
}
else {
filtersAnd.push(count >= $count ? undefined : new OakUserUnpermittedException());
}
filtersAnd.push(result);
}
else if (ff) {
filtersAnd.push(ff as ED[keyof ED]['Selection']['filter']);
@ -520,22 +701,12 @@ function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends
}
}
else {
if (f?.$entity) {
const { $entity, $filter, $count = 1 } = f!;
const count = context.count($entity, {
filter: $filter,
}, {});
if (count instanceof Promise) {
if ((<CreateRelationMultipleCounter<ED>>f)?.$$and || (<CreateRelationMultipleCounter<ED>>f)?.$$or || (<CreateRelationSingleCounter<ED>>f)?.$entity) {
const counterResults = execCreateCounter<ED, Cxt>(context, f as CreateRelationCounter<ED>);
if (counterResults instanceof Promise) {
isAsyncOr = true;
filtersOr.push(
count.then(
(c2) => c2 >= $count ? undefined : new OakUserUnpermittedException()
)
);
}
else {
filtersOr.push(count >= $count ? undefined : new OakUserUnpermittedException());
}
filtersOr.push(counterResults);
}
else if (f) {
filtersOr.push(f as ED[keyof ED]['Selection']['filter']);
@ -584,11 +755,26 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
if (relationAuth) {
const raFilterMakerDict = {} as Record<string, FilterMakeFn<ED> | (FilterMakeFn<ED> | FilterMakeFn<ED>[])[]>;
const userEntityName = `user${firstLetterUpperCase(entity)}`;
const allAuthItem: (CascadeRelationItem | CascadeRelationItem[])[] = [];
for (const r in relationAuth) {
const authItem = relationAuth[r as NonNullable<ED[keyof ED]['Relation']>]!;
Object.assign(raFilterMakerDict, {
[r]: translateActionAuthFilterMaker(schema, relationAuth[r as NonNullable<ED[keyof ED]['Relation']>]!, userEntityName, entity),
[r]: translateActionAuthFilterMaker(schema, authItem, userEntityName, entity),
});
if (authItem instanceof Array) {
allAuthItem.push(...authItem);
}
else {
allAuthItem.push(authItem);
}
}
// 如果不指定relation则使用所有的authItem的or组合
Object.assign(raFilterMakerDict, {
'@@all': translateActionAuthFilterMaker(schema, allAuthItem, userEntityName, entity),
});
const entityIdAttr = `${entity}Id`;
checkers.push({
entity: userEntityName as keyof ED,
@ -598,11 +784,15 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
const { data } = operation as ED[keyof ED]['Create'];
assert(!(data instanceof Array));
const { relation, [entityIdAttr]: entityId } = data;
if (!relation) {
// 不指定relation测试是否有创建权限
return makePotentialFilter(operation, context, raFilterMakerDict['@@all']);
}
if (!raFilterMakerDict[relation]) {
return;
throw new OakUserUnpermittedException();
}
const filter = makePotentialFilter(operation, context, raFilterMakerDict[relation]);
return filter;
},
errMsg: '越权操作',

View File

@ -9,13 +9,17 @@ export type Text = string;
export type Image = string;
export type File = string;
export type Datetime = number | Date;
export type Day = number | Date;
export type Time = number | Date;
export type Boolean = boolean;
export type Price = number;
export type PrimaryKey = string;
export type ForeignKey<E extends string> = string;
export type Sequence = string; // 自增长序列为了让人阅读方便为了支持分布式这里用string底层实现可自定义
export { Geo, SingleGeo } from './Geo';
export type DataTypes = number | string | Datetime | Geo | Object | SingleGeo;
export type DataTypes = number | string | Datetime | Day | Time | Geo | Object | SingleGeo;
export const types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Boolean', 'Image', 'File', 'Geo', 'SingleGeo'];
export const types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Day', 'Time',
'Boolean', 'Image', 'File', 'Geo', 'SingleGeo', 'Price'];
export const unIndexedTypes = ['Text', 'Image', 'File', 'Object'];

View File

@ -18,6 +18,7 @@ type LocaleOfValue<V extends Record<string, string>> = {
export type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = {
[L in Language]?: {
name: string;
attr: LocaleOfSchema<Sc> & {
[A in keyof V]: string; // 目前写在V里面的应该只有枚举变量和state
};

12
src/types/Style.ts Normal file
View File

@ -0,0 +1,12 @@
import { EntityDict } from './Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
type ThemeColor = 'default' | 'success' | 'warning' | 'error';
export type ColorDict<ED extends BaseEntityDict & EntityDict> = {
[T in keyof ED]?: {
[A in keyof ED[T]['OpSchema']]?: {
[E in ED[T]['OpSchema'][A]]?: ThemeColor | `#${string}`;
};
};
};

View File

@ -1,7 +1,10 @@
import { RecurrenceRule, RecurrenceSpecDateRange, RecurrenceSpecObjLit } from 'node-schedule';
import { EntityDict } from './Entity';
import { AsyncContext } from "../store/AsyncRowStore";
import { AsyncContext } from '../store/AsyncRowStore';
type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>;
type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (
context: Cxt
) => Promise<string>;
export type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string;
@ -10,6 +13,6 @@ export type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
export type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string;
cron: string;
cron: RecurrenceRule | RecurrenceSpecDateRange | RecurrenceSpecObjLit | Date | string | number;
fn: RoutineFn<ED, Cxt>;
};

View File

@ -19,3 +19,4 @@ export * from './Connector';
export * from './Timer';
export * from './Port';
export * from './Endpoint';
export * from './Style';

View File

@ -218,4 +218,6 @@ export interface DataTypeParams {
precision?: number;
scale?: number;
signed?: boolean;
max?: number;
min?: number;
};

View File

@ -10,7 +10,7 @@ function makeContentTypeAndBody(data: any) {
if (process.env.OAK_PLATFORM !== 'wechatMp') {
if (data instanceof FormData) {
return {
contentType: 'multipart/form-data',
// contentType: 'multipart/form-data',
body: data,
};
}
@ -41,11 +41,15 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
const { contentType, body } = makeContentTypeAndBody(params);
const response = await global.fetch(this.serverUrl, {
method: 'POST',
headers: {
'Content-Type': contentType,
'oak-cxt': cxtStr,
'oak-aspect': name as string,
},
headers: Object.assign(
{
'oak-cxt': cxtStr,
'oak-aspect': name as string,
},
contentType && {
'Content-Type': contentType as string,
}
) as RequestInit['headers'],
body,
});
if (response.status > 299) {
@ -61,7 +65,7 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
result,
opRecords,
} = await response.json();
if (exception) {
throw this.makeException(exception);
}
@ -87,7 +91,7 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
return SimpleConnector.ROUTER;
}
async parseRequest(headers: IncomingHttpHeaders, body: any, store: AsyncRowStore<ED, BackCxt>): Promise<{ name: string; params: any; context: BackCxt; }> {
async parseRequest(headers: IncomingHttpHeaders, body: any, store: AsyncRowStore<ED, BackCxt>): Promise<{ name: string; params: any; context: BackCxt; }> {
const { 'oak-cxt': oakCxtStr, 'oak-aspect': aspectName } = headers;
assert(typeof oakCxtStr === 'string' || oakCxtStr === undefined);
assert(typeof aspectName === 'string');
@ -99,9 +103,9 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
context,
};
}
serializeResult(result: any, context: BackCxt, headers: IncomingHttpHeaders, body: any): { body: any; headers?: Record<string, any> | undefined; } {
if (result instanceof Stream) {
if (result instanceof Stream || result instanceof Buffer) {
return {
body: result,
};
@ -117,7 +121,7 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
};
}
serializeException(exception: OakException<ED>, 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(),

View File

@ -1,17 +0,0 @@
import { getFutureMatches } from '@datasert/cronjs-matcher';
import DayJs from 'dayjs';
export function schedule(cron: string, fn: (date: Date) => any) {
const futureMatches = getFutureMatches(cron, {
matchCount: 1,
});
const date = DayJs(futureMatches[0]);
const interval = date.diff(DayJs(), 'ms');
setTimeout(
() => {
fn(new Date());
schedule(cron, fn);
},
interval
);
}

40
src/utils/mask.ts Normal file
View File

@ -0,0 +1,40 @@
const maskIdCard: (idCardNumber: string) => string = (idCardNumber) => {
if(!idCardNumber as any instanceof String) {
throw new Error("身份证号码必须是String类型");
}
let begin = idCardNumber.slice(0, 4);
let end = idCardNumber.slice(idCardNumber.length - 4, 4);
for(let i = 0; i < idCardNumber.length - 8; i ++) {
begin = begin.concat("*");
}
return begin.concat(end);
}
const maskMobile: (mobile: string) => string = (mobile) => {
let begin = mobile.slice(0, 3);
let end = mobile.slice(7, 11);
return begin.concat("****").concat(end);
}
const maskName: (name: string) => string = (name) => {
return name.slice(0, name.length - 1).concat("*");
}
const maskStar: (str: string, front: number, end: number, star: string) => string = (str, frontLen, endLen, star = '*') => {
const len = str.length - frontLen - endLen;
let xing = '';
for (let i = 0; i < len; i++) {
xing += star;
}
return str.substring(0, frontLen) + xing + str.substring(str.length - endLen);
}
export {
maskIdCard,
maskMobile,
maskName,
maskStar,
}

27
src/utils/money.ts Normal file
View File

@ -0,0 +1,27 @@
const ToCent: (float: number) => number = (float) => {
return Math.round(float * 100);
}
const ToYuan: (int: number) => number = ( int) => {
return Math.round(int) / 100;
}
const StringToCent: (value: string, allowNegative?: true) => number | undefined = (value, allowNegative) => {
const numValue = parseInt(value, 10);
if (typeof numValue === 'number' && (numValue >= 0 || allowNegative)) {
return ToCent(numValue);
}
}
const CentToString: (value: number) => string | undefined = (value) => {
if (typeof value === 'number') {
return `${ToYuan(value)}`;
}
}
export {
ToCent,
ToYuan,
StringToCent,
CentToString,
}

View File

@ -83,16 +83,26 @@ export const isPhone: ValidatorFunction = (phone) => {
return /^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/.test(phone);
};
export const isTel: ValidatorFunction = (text) => {
// 1、133xxxx4545 2、0571-630xx239 3、400-123-1400
const reg =
/^(((\d{3,4}-)?[0-9]{7,8})|(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}|((400)-(\d{3})-(\d{4})(.)(\d{1,4})|(400)-(\d{3})-(\d{4}$)|(400)(\d{3})(\d{4}$)|(400)-(\d{4})-(\d{3}$)))$/.test(
text
);
return reg;
};
export const isNumber: ValidatorFunction = (str) => {
return /^[0-9]*$/.test(str);
}
export const isMoney: ValidatorMoneyFunction = (str, zero) => {
// zero为true包含零
// 金额,最多可以有两位小数 zero为true包含零
if (zero) {
// 金额,最多可以有两位小数
return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(str);
return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(
str
);
}
return /(^[1-9](\d+)?(\.\d{1,2})?$)|(^\d\.\d{1,2}$)/.test(str);
}