更新了localebuilder中出错处理,在判定attrUpdateMatrix时,增加了对cascade更新条件的判定
This commit is contained in:
parent
8f433f84bf
commit
68289a281e
|
|
@ -133,9 +133,14 @@ class LocaleBuilder {
|
||||||
this.locales[ns] = [module, position.replace(/\\/g, '/'), language, data];
|
this.locales[ns] = [module, position.replace(/\\/g, '/'), language, data];
|
||||||
if (watch) {
|
if (watch) {
|
||||||
fs_1.default.watch(filepath, () => {
|
fs_1.default.watch(filepath, () => {
|
||||||
const data = this.readLocaleFileContent(filepath);
|
try {
|
||||||
this.locales[ns] = [module, position.replace(/\\/g, '/'), language, data];
|
const data = this.readLocaleFileContent(filepath);
|
||||||
this.outputDataFile();
|
this.locales[ns] = [module, position.replace(/\\/g, '/'), language, data];
|
||||||
|
this.outputDataFile();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// 啥都不干
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.makeIntrinsicCheckers = void 0;
|
exports.makeIntrinsicCheckers = void 0;
|
||||||
|
const tslib_1 = require("tslib");
|
||||||
const types_1 = require("../types");
|
const types_1 = require("../types");
|
||||||
const lodash_1 = require("../utils/lodash");
|
const lodash_1 = require("../utils/lodash");
|
||||||
const filter_1 = require("./filter");
|
const filter_1 = require("./filter");
|
||||||
const modi_1 = require("./modi");
|
const modi_1 = require("./modi");
|
||||||
const checker_1 = require("./checker");
|
const checker_1 = require("./checker");
|
||||||
const action_1 = require("../actions/action");
|
const action_1 = require("../actions/action");
|
||||||
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||||
function checkUniqueBetweenRows(rows, uniqAttrs) {
|
function checkUniqueBetweenRows(rows, uniqAttrs) {
|
||||||
// 先检查这些行本身之间有无unique冲突
|
// 先检查这些行本身之间有无unique冲突
|
||||||
const dict = {};
|
const dict = {};
|
||||||
|
|
@ -241,6 +243,60 @@ function createActionTransformerCheckers(actionDefDict) {
|
||||||
}
|
}
|
||||||
return checkers;
|
return checkers;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 检查一次更新是否有关联通过的可能
|
||||||
|
* 例如,更新A的条件是B = 1,此时行上的B并不等于1,但由于更新数据是: { B: 1, A: .. }
|
||||||
|
* 此时如果B更新可以成功则A也可以成功
|
||||||
|
* @param entity
|
||||||
|
* @param data
|
||||||
|
* @param filters
|
||||||
|
* @param context
|
||||||
|
*/
|
||||||
|
function cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, restAttrs, context) {
|
||||||
|
const successAttrs = (0, lodash_1.difference)(Object.keys(data), restAttrs);
|
||||||
|
const successAttrFilter = (0, lodash_1.pick)(data, successAttrs);
|
||||||
|
/**
|
||||||
|
* 先找到能直接更新成功的属性
|
||||||
|
*/
|
||||||
|
const legalAttrResult = restAttrs.map((attr) => {
|
||||||
|
const { filter: f } = matrix[attr];
|
||||||
|
if (!f) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 此时看应用了success的attributes更新后,能否消除掉f中的部分条件
|
||||||
|
const result = (0, filter_1.analyzeFilterRelation)(entity, schema, successAttrFilter, f, true);
|
||||||
|
if (typeof result === 'boolean') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const { sureAttributes } = result;
|
||||||
|
const f2 = (0, lodash_1.omit)(f, sureAttributes);
|
||||||
|
return (0, filter_1.checkFilterContains)(entity, context, f2, filter, true);
|
||||||
|
});
|
||||||
|
const checkResult1 = (lar) => {
|
||||||
|
const legalAttrs = [];
|
||||||
|
const illegalAttrs = [];
|
||||||
|
(0, assert_1.default)(lar.length === restAttrs.length);
|
||||||
|
lar.forEach((ele, idx) => {
|
||||||
|
if (ele) {
|
||||||
|
legalAttrs.push(restAttrs[idx]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
illegalAttrs.push(restAttrs[idx]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (illegalAttrs.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (legalAttrs.length === 0) {
|
||||||
|
throw new types_1.OakAttrCantUpdateException(entity, illegalAttrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
||||||
|
}
|
||||||
|
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, illegalAttrs, context);
|
||||||
|
};
|
||||||
|
if (legalAttrResult.find(ele => ele instanceof Promise)) {
|
||||||
|
return Promise.all(legalAttrResult).then((lar) => checkResult1(lar));
|
||||||
|
}
|
||||||
|
return checkResult1(legalAttrResult);
|
||||||
|
}
|
||||||
function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
|
function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
|
||||||
const checkers = [];
|
const checkers = [];
|
||||||
for (const entity in attrUpdateMatrix) {
|
for (const entity in attrUpdateMatrix) {
|
||||||
|
|
@ -270,19 +326,27 @@ function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
|
||||||
if (!a.includes(action)) {
|
if (!a.includes(action)) {
|
||||||
// 找到不满足的那个attr
|
// 找到不满足的那个attr
|
||||||
const attrsIllegal = attrs.filter((attr) => matrix[attr]?.actions && !matrix[attr]?.actions?.includes(action));
|
const attrsIllegal = attrs.filter((attr) => matrix[attr]?.actions && !matrix[attr]?.actions?.includes(action));
|
||||||
throw new types_1.OakAttrCantUpdateException(entity, attrsIllegal, `${attrsIllegal}不允许被${action}动作更新`);
|
throw new types_1.OakAttrCantUpdateException(entity, attrsIllegal, `${attrsIllegal.join(',')}不允许被${action}动作更新`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (f) {
|
if (f) {
|
||||||
|
const rr = (0, filter_1.contains)(entity, context.getSchema(), data, f);
|
||||||
|
console.log(rr);
|
||||||
const result = (0, filter_1.checkFilterContains)(entity, context, f, filter, true);
|
const result = (0, filter_1.checkFilterContains)(entity, context, f, filter, true);
|
||||||
if (result instanceof Promise) {
|
if (result instanceof Promise) {
|
||||||
return result.then((v) => {
|
return result.then((v) => {
|
||||||
if (!v) {
|
if (!v) {
|
||||||
|
if (attrs.length > 1) {
|
||||||
|
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, attrs, context);
|
||||||
|
}
|
||||||
throw new types_1.OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
throw new types_1.OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
if (attrs.length > 1) {
|
||||||
|
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, attrs, context);
|
||||||
|
}
|
||||||
throw new types_1.OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
throw new types_1.OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,14 @@ import { AsyncContext } from './AsyncRowStore';
|
||||||
import { SyncContext } from './SyncRowStore';
|
import { SyncContext } from './SyncRowStore';
|
||||||
export declare function translateCreateDataToFilter<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(schema: StorageSchema<ED>, entity: T, data: ED[T]['CreateSingle']['data'], allowUnrecoganized: boolean): ED[T]["Selection"]["filter"];
|
export declare function translateCreateDataToFilter<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(schema: StorageSchema<ED>, entity: T, data: ED[T]['CreateSingle']['data'], allowUnrecoganized: boolean): ED[T]["Selection"]["filter"];
|
||||||
export declare function combineFilters<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>, filters: Array<ED[T]['Selection']['filter']>, union?: true): ED[T]["Selection"]["filter"] | undefined;
|
export declare function combineFilters<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>, filters: Array<ED[T]['Selection']['filter']>, union?: true): ED[T]["Selection"]["filter"] | undefined;
|
||||||
|
type DeducedFilter<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
|
||||||
|
entity: T;
|
||||||
|
filter: ED[T]['Selection']['filter'];
|
||||||
|
};
|
||||||
|
type DeducedFilterCombination<ED extends EntityDict & BaseEntityDict> = {
|
||||||
|
$or?: (DeducedFilterCombination<ED> | DeducedFilter<ED, keyof ED>)[];
|
||||||
|
$and?: (DeducedFilterCombination<ED> | DeducedFilter<ED, keyof ED>)[];
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* 在以下判断相容或相斥的过程中,相容/相斥的事实标准是:满足两个条件的查询集合是否被包容/互斥,但如果两个filter在逻辑上相容或者相斥,在事实上不一定相容或者相斥
|
* 在以下判断相容或相斥的过程中,相容/相斥的事实标准是:满足两个条件的查询集合是否被包容/互斥,但如果两个filter在逻辑上相容或者相斥,在事实上不一定相容或者相斥
|
||||||
* 例如:{ a: 1 } 和 { a: { $ne: 1 } } 是明显不相容的查询,但如果数据为空集,则这两个查询并不能否定其相容
|
* 例如:{ a: 1 } 和 { a: { $ne: 1 } } 是明显不相容的查询,但如果数据为空集,则这两个查询并不能否定其相容
|
||||||
|
|
@ -35,6 +43,44 @@ export declare function combineFilters<ED extends EntityDict & BaseEntityDict, T
|
||||||
* @attention: 1)这里的测试不够充分,有些算子之间的相容或相斥可能有遗漏, 2)有新的算子加入需要修改代码
|
* @attention: 1)这里的测试不够充分,有些算子之间的相容或相斥可能有遗漏, 2)有新的算子加入需要修改代码
|
||||||
*/
|
*/
|
||||||
export declare function judgeValueRelation(value1: any, value2: any, contained: boolean): boolean | undefined;
|
export declare function judgeValueRelation(value1: any, value2: any, contained: boolean): boolean | undefined;
|
||||||
|
/**
|
||||||
|
* 根据filter对compared查询的各个条件进行逐项分析
|
||||||
|
* @param entity
|
||||||
|
* @param schema
|
||||||
|
* @param filter
|
||||||
|
* @param compared
|
||||||
|
* @param contained
|
||||||
|
* @returns
|
||||||
|
* sureAttributes中包含被判定肯定相容或肯定不相斥的属性(不用再继续判定了)
|
||||||
|
* uncertainAttributes中包含的是无法判定结果的属性
|
||||||
|
* totalAndDeducedFilters包含的是判定过程中推论的相容的充分条件(and关系)
|
||||||
|
* totalOrDeducedFilters包含的是判定过程中推论的相斥的充分条件(or关系)
|
||||||
|
*/
|
||||||
|
export declare function analyzeFilterRelation<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>, filter: NonNullable<ED[T]['Selection']['filter']>, compared: NonNullable<ED[T]['Selection']['filter']>, contained: boolean): boolean | {
|
||||||
|
totalAndDeducedFilters: (DeducedFilterCombination<ED> | DeducedFilter<ED, T>)[];
|
||||||
|
totalOrDeducedFilters: (DeducedFilterCombination<ED> | DeducedFilter<ED, T>)[];
|
||||||
|
uncertainAttributes: string[];
|
||||||
|
sureAttributes: string[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 判断filter是否包含contained中的查询条件,即filter查询的结果一定是contained查询结果的子集
|
||||||
|
* filter = {
|
||||||
|
* a: 1
|
||||||
|
* b: 2,
|
||||||
|
* c: 3,
|
||||||
|
* },
|
||||||
|
* conditionalFilter = {
|
||||||
|
* a: 1
|
||||||
|
* }
|
||||||
|
* 则包含
|
||||||
|
* @param entity
|
||||||
|
* @param schema
|
||||||
|
* @param filter
|
||||||
|
* @param contained
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export declare function contains<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(entity: T, schema: StorageSchema<ED>, filter: ED[T]['Selection']['filter'], contained: ED[T]['Selection']['filter']): boolean | DeducedFilterCombination<ED>;
|
||||||
/**
|
/**
|
||||||
* 从filter中判断是否有确定的id对象,如果有则返回这些id,没有返回空数组
|
* 从filter中判断是否有确定的id对象,如果有则返回这些id,没有返回空数组
|
||||||
* @param filter
|
* @param filter
|
||||||
|
|
@ -84,3 +130,4 @@ export declare function checkFilterRepel<ED extends EntityDict & BaseEntityDict,
|
||||||
* @param filter
|
* @param filter
|
||||||
*/
|
*/
|
||||||
export declare function translateFilterToObjectPredicate(filter: Record<string, any>): {};
|
export declare function translateFilterToObjectPredicate(filter: Record<string, any>): {};
|
||||||
|
export {};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.translateFilterToObjectPredicate = exports.checkFilterRepel = exports.checkFilterContains = exports.makeTreeDescendantFilter = exports.makeTreeAncestorFilter = exports.same = exports.getRelevantIds = exports.judgeValueRelation = exports.combineFilters = exports.translateCreateDataToFilter = void 0;
|
exports.translateFilterToObjectPredicate = exports.checkFilterRepel = exports.checkFilterContains = exports.makeTreeDescendantFilter = exports.makeTreeAncestorFilter = exports.same = exports.getRelevantIds = exports.contains = exports.analyzeFilterRelation = exports.judgeValueRelation = exports.combineFilters = exports.translateCreateDataToFilter = void 0;
|
||||||
const tslib_1 = require("tslib");
|
const tslib_1 = require("tslib");
|
||||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||||
const types_1 = require("../types");
|
const types_1 = require("../types");
|
||||||
|
|
@ -43,9 +43,24 @@ function addFilterSegment(entity, schema, ...filters) {
|
||||||
if (!filter[attr]) {
|
if (!filter[attr]) {
|
||||||
filter[attr] = value;
|
filter[attr] = value;
|
||||||
}
|
}
|
||||||
// 只优化一种情况,就是两个都等值且相等
|
// 优化两个都等值且相等
|
||||||
else if (filter[attr] === value) {
|
else if (filter[attr] === value) {
|
||||||
}
|
}
|
||||||
|
// value定义的查询被当前查询包含
|
||||||
|
else if (contains(entity, schema, {
|
||||||
|
[attr]: value,
|
||||||
|
}, {
|
||||||
|
[attr]: filter[attr],
|
||||||
|
}) === true) {
|
||||||
|
filter[attr] = value;
|
||||||
|
}
|
||||||
|
// 当前查询被value所定义的查询包含
|
||||||
|
else if (contains(entity, schema, {
|
||||||
|
[attr]: filter[attr],
|
||||||
|
}, {
|
||||||
|
[attr]: value
|
||||||
|
}) == true) {
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
addIntoAnd({
|
addIntoAnd({
|
||||||
[attr]: value,
|
[attr]: value,
|
||||||
|
|
@ -1041,15 +1056,20 @@ function judgeFilterSingleAttrRelation(entity, schema, attr, filter, compared, c
|
||||||
// 到这里说明无法直接判断此attr上的相容或者相斥,也无法把判定推断到更深层的算子之上
|
// 到这里说明无法直接判断此attr上的相容或者相斥,也无法把判定推断到更深层的算子之上
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/** 判断filter条件对compared条件是否相容或相斥
|
/**
|
||||||
|
* 根据filter对compared查询的各个条件进行逐项分析
|
||||||
* @param entity
|
* @param entity
|
||||||
* @param schema
|
* @param schema
|
||||||
* @param filter
|
* @param filter
|
||||||
* @param compared
|
* @param compared
|
||||||
* @param contained: true代表判定filter包容compared(filter的查询结果是compared查询结果的子集), false代表判定filter与compared相斥(filter的查询结果与compared没有交集)
|
* @param contained
|
||||||
* @returns 返回true说明肯定相容(相斥),返回false说明无法判定相容(相斥),返回DeducedFilterCombination说明需要进一步判断此推断的条件
|
* @returns
|
||||||
|
* sureAttributes中包含被判定肯定相容或肯定不相斥的属性(不用再继续判定了)
|
||||||
|
* uncertainAttributes中包含的是无法判定结果的属性
|
||||||
|
* totalAndDeducedFilters包含的是判定过程中推论的相容的充分条件(and关系)
|
||||||
|
* totalOrDeducedFilters包含的是判定过程中推论的相斥的充分条件(or关系)
|
||||||
*/
|
*/
|
||||||
function judgeFilterRelation(entity, schema, filter, compared, contained) {
|
function analyzeFilterRelation(entity, schema, filter, compared, contained) {
|
||||||
const totalAndDeducedFilters = [];
|
const totalAndDeducedFilters = [];
|
||||||
const totalOrDeducedFilters = [];
|
const totalOrDeducedFilters = [];
|
||||||
const uncertainAttributes = [];
|
const uncertainAttributes = [];
|
||||||
|
|
@ -1239,6 +1259,28 @@ function judgeFilterRelation(entity, schema, filter, compared, contained) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
totalAndDeducedFilters,
|
||||||
|
totalOrDeducedFilters,
|
||||||
|
uncertainAttributes,
|
||||||
|
sureAttributes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.analyzeFilterRelation = analyzeFilterRelation;
|
||||||
|
/** 判断filter条件对compared条件是否相容或相斥
|
||||||
|
* @param entity
|
||||||
|
* @param schema
|
||||||
|
* @param filter
|
||||||
|
* @param compared
|
||||||
|
* @param contained: true代表判定filter包容compared(filter的查询结果是compared查询结果的子集), false代表判定filter与compared相斥(filter的查询结果与compared没有交集)
|
||||||
|
* @returns 返回true说明肯定相容(相斥),返回false说明无法判定相容(相斥),返回DeducedFilterCombination说明需要进一步判断此推断的条件
|
||||||
|
*/
|
||||||
|
function judgeFilterRelation(entity, schema, filter, compared, contained) {
|
||||||
|
const result = analyzeFilterRelation(entity, schema, filter, compared, contained);
|
||||||
|
if (typeof result === 'boolean') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const { sureAttributes, uncertainAttributes, totalAndDeducedFilters, totalOrDeducedFilters, } = result;
|
||||||
if (contained) {
|
if (contained) {
|
||||||
if (sureAttributes.length === Object.keys(compared).length) {
|
if (sureAttributes.length === Object.keys(compared).length) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1296,6 +1338,7 @@ function contains(entity, schema, filter, contained) {
|
||||||
return judgeFilterRelation(entity, schema, filter, contained, true);
|
return judgeFilterRelation(entity, schema, filter, contained, true);
|
||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
|
exports.contains = contains;
|
||||||
/**
|
/**
|
||||||
* 判断filter1和filter2是否相斥,即filter1和filter2查询的结果一定没有交集
|
* 判断filter1和filter2是否相斥,即filter1和filter2查询的结果一定没有交集
|
||||||
* filter1 = {
|
* filter1 = {
|
||||||
|
|
|
||||||
|
|
@ -219,9 +219,14 @@ export default class LocaleBuilder {
|
||||||
|
|
||||||
if (watch) {
|
if (watch) {
|
||||||
fs.watch(filepath, () => {
|
fs.watch(filepath, () => {
|
||||||
const data = this.readLocaleFileContent(filepath);
|
try {
|
||||||
this.locales[ns] = [module, position.replace(/\\/g, '/'), language, data];
|
const data = this.readLocaleFileContent(filepath);
|
||||||
this.outputDataFile();
|
this.locales[ns] = [module, position.replace(/\\/g, '/'), language, data];
|
||||||
|
this.outputDataFile();
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
// 啥都不干
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import { ActionDefDict, Checker, EntityDict, StorageSchema, RowChecker, OakUniqueViolationException, CHECKER_MAX_PRIORITY, AttrUpdateMatrix, LogicalChecker, OakAttrCantUpdateException } from "../types";
|
import { ActionDefDict, Checker, EntityDict, StorageSchema, RowChecker, OakUniqueViolationException, CHECKER_MAX_PRIORITY, AttrUpdateMatrix, LogicalChecker, OakAttrCantUpdateException } from "../types";
|
||||||
import { SyncContext } from "./SyncRowStore";
|
import { SyncContext } from "./SyncRowStore";
|
||||||
import { AsyncContext } from "./AsyncRowStore";
|
import { AsyncContext } from "./AsyncRowStore";
|
||||||
import { pick, intersection, difference } from '../utils/lodash';
|
import { pick, intersection, difference, omit } from '../utils/lodash';
|
||||||
import { checkFilterContains, combineFilters } from "./filter";
|
import { analyzeFilterRelation, checkFilterContains, combineFilters, contains } from "./filter";
|
||||||
import { EntityDict as BaseEntityDict } from '../base-app-domain/EntityDict';
|
import { EntityDict as BaseEntityDict } from '../base-app-domain/EntityDict';
|
||||||
import { createModiRelatedCheckers } from "./modi";
|
import { createModiRelatedCheckers } from "./modi";
|
||||||
import { createCreateCheckers, createRemoveCheckers } from "./checker";
|
import { createCreateCheckers, createRemoveCheckers } from "./checker";
|
||||||
import { readOnlyActions } from "../actions/action";
|
import { readOnlyActions } from "../actions/action";
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
|
|
||||||
function checkUniqueBetweenRows(rows: Record<string, any>[], uniqAttrs: string[]) {
|
function checkUniqueBetweenRows(rows: Record<string, any>[], uniqAttrs: string[]) {
|
||||||
|
|
@ -270,7 +271,7 @@ function createActionTransformerCheckers<ED extends EntityDict & BaseEntityDict,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (data){
|
else if (data) {
|
||||||
if (!(data as Readonly<ED[keyof ED]['CreateSingle']['data']>)[attr]) {
|
if (!(data as Readonly<ED[keyof ED]['CreateSingle']['data']>)[attr]) {
|
||||||
Object.assign(data, {
|
Object.assign(data, {
|
||||||
[attr]: is,
|
[attr]: is,
|
||||||
|
|
@ -286,6 +287,82 @@ function createActionTransformerCheckers<ED extends EntityDict & BaseEntityDict,
|
||||||
return checkers;
|
return checkers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查一次更新是否有关联通过的可能
|
||||||
|
* 例如,更新A的条件是B = 1,此时行上的B并不等于1,但由于更新数据是: { B: 1, A: .. }
|
||||||
|
* 此时如果B更新可以成功则A也可以成功
|
||||||
|
* @param entity
|
||||||
|
* @param data
|
||||||
|
* @param filters
|
||||||
|
* @param context
|
||||||
|
*/
|
||||||
|
function cascadelyCheckUpdateFilters<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>>(
|
||||||
|
entity: T,
|
||||||
|
schema: StorageSchema<ED>,
|
||||||
|
data: ED[T]['Update']['data'],
|
||||||
|
filter: ED[T]['Update']['filter'],
|
||||||
|
matrix: NonNullable<AttrUpdateMatrix<ED>[T]>,
|
||||||
|
restAttrs: string[],
|
||||||
|
context: Cxt | FrontCxt
|
||||||
|
): void | Promise<void> {
|
||||||
|
const successAttrs = difference(Object.keys(data), restAttrs);
|
||||||
|
const successAttrFilter = pick(data, successAttrs);
|
||||||
|
/**
|
||||||
|
* 先找到能直接更新成功的属性
|
||||||
|
*/
|
||||||
|
const legalAttrResult = restAttrs.map(
|
||||||
|
(attr) => {
|
||||||
|
const { filter: f } = matrix[attr]!;
|
||||||
|
if (!f) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 此时看应用了success的attributes更新后,能否消除掉f中的部分条件
|
||||||
|
const result = analyzeFilterRelation(entity, schema, successAttrFilter, f, true);
|
||||||
|
if (typeof result === 'boolean') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const { sureAttributes } = result;
|
||||||
|
const f2 = omit(f, sureAttributes);
|
||||||
|
|
||||||
|
return checkFilterContains<ED, keyof ED, Cxt | FrontCxt>(entity, context, f2, filter, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const checkResult1 = (lar: boolean[]) => {
|
||||||
|
const legalAttrs: string[] = [];
|
||||||
|
const illegalAttrs: string[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
assert(lar.length === restAttrs.length);
|
||||||
|
lar.forEach(
|
||||||
|
(ele, idx) => {
|
||||||
|
if (ele) {
|
||||||
|
legalAttrs.push(restAttrs[idx]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
illegalAttrs.push(restAttrs[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (illegalAttrs.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (legalAttrs.length === 0) {
|
||||||
|
throw new OakAttrCantUpdateException(entity as keyof ED, illegalAttrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
||||||
|
}
|
||||||
|
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, illegalAttrs, context);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (legalAttrResult.find(ele => ele instanceof Promise)) {
|
||||||
|
return Promise.all(legalAttrResult).then(
|
||||||
|
(lar) => checkResult1(lar)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkResult1(legalAttrResult as boolean[]);
|
||||||
|
}
|
||||||
|
|
||||||
function createAttrUpdateCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>>(
|
function createAttrUpdateCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>>(
|
||||||
schema: StorageSchema<ED>,
|
schema: StorageSchema<ED>,
|
||||||
attrUpdateMatrix: AttrUpdateMatrix<ED>
|
attrUpdateMatrix: AttrUpdateMatrix<ED>
|
||||||
|
|
@ -323,21 +400,31 @@ function createAttrUpdateCheckers<ED extends EntityDict & BaseEntityDict, Cxt ex
|
||||||
const attrsIllegal = attrs.filter(
|
const attrsIllegal = attrs.filter(
|
||||||
(attr) => matrix[attr]?.actions && !matrix[attr]?.actions?.includes(action!)
|
(attr) => matrix[attr]?.actions && !matrix[attr]?.actions?.includes(action!)
|
||||||
);
|
);
|
||||||
throw new OakAttrCantUpdateException(entity, attrsIllegal, `${attrsIllegal}不允许被${action}动作更新`);
|
throw new OakAttrCantUpdateException(entity, attrsIllegal, `${attrsIllegal.join(',')}不允许被${action}动作更新`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (f) {
|
if (f) {
|
||||||
const result = checkFilterContains<ED, keyof ED, Cxt>(entity, context as any, f, filter, true);
|
const rr = contains<ED, keyof ED>(entity, context.getSchema(), data, f);
|
||||||
|
console.log(rr);
|
||||||
|
const result = checkFilterContains<ED, keyof ED, Cxt | FrontCxt>(entity, context, f, filter, true);
|
||||||
if (result instanceof Promise) {
|
if (result instanceof Promise) {
|
||||||
return result.then(
|
return result.then(
|
||||||
(v) => {
|
(v) => {
|
||||||
if (!v) {
|
if (!v) {
|
||||||
|
if (attrs.length > 1) {
|
||||||
|
return cascadelyCheckUpdateFilters(entity, schema, data as ED[keyof ED]['Update']['data'],
|
||||||
|
filter, matrix, attrs, context);
|
||||||
|
}
|
||||||
throw new OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
throw new OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
if (attrs.length > 1) {
|
||||||
|
return cascadelyCheckUpdateFilters(entity, schema, data as ED[keyof ED]['Update']['data'],
|
||||||
|
filter, matrix, attrs, context);
|
||||||
|
}
|
||||||
throw new OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
throw new OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { AsyncContext } from './AsyncRowStore';
|
||||||
import { judgeRelation } from './relation';
|
import { judgeRelation } from './relation';
|
||||||
import { SyncContext } from './SyncRowStore';
|
import { SyncContext } from './SyncRowStore';
|
||||||
|
|
||||||
export function translateCreateDataToFilter<ED extends EntityDict & BaseEntityDict, T extends keyof ED> (
|
export function translateCreateDataToFilter<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(
|
||||||
schema: StorageSchema<ED>,
|
schema: StorageSchema<ED>,
|
||||||
entity: T,
|
entity: T,
|
||||||
data: ED[T]['CreateSingle']['data'],
|
data: ED[T]['CreateSingle']['data'],
|
||||||
|
|
@ -53,9 +53,24 @@ function addFilterSegment<ED extends EntityDict & BaseEntityDict, T extends keyo
|
||||||
if (!filter[attr]) {
|
if (!filter[attr]) {
|
||||||
filter[attr] = value;
|
filter[attr] = value;
|
||||||
}
|
}
|
||||||
// 只优化一种情况,就是两个都等值且相等
|
// 优化两个都等值且相等
|
||||||
else if (filter[attr] === value) {
|
else if (filter[attr] === value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
// value定义的查询被当前查询包含
|
||||||
|
else if (contains(entity, schema, {
|
||||||
|
[attr]: value,
|
||||||
|
}, {
|
||||||
|
[attr]: filter[attr],
|
||||||
|
}) === true) {
|
||||||
|
filter[attr] = value;
|
||||||
|
}
|
||||||
|
// 当前查询被value所定义的查询包含
|
||||||
|
else if (contains(entity, schema, {
|
||||||
|
[attr]: filter[attr],
|
||||||
|
}, {
|
||||||
|
[attr]: value
|
||||||
|
}) == true) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addIntoAnd({
|
addIntoAnd({
|
||||||
|
|
@ -1194,21 +1209,25 @@ function judgeFilterSingleAttrRelation<ED extends EntityDict & BaseEntityDict, T
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 判断filter条件对compared条件是否相容或相斥
|
/**
|
||||||
|
* 根据filter对compared查询的各个条件进行逐项分析
|
||||||
* @param entity
|
* @param entity
|
||||||
* @param schema
|
* @param schema
|
||||||
* @param filter
|
* @param filter
|
||||||
* @param compared
|
* @param compared
|
||||||
* @param contained: true代表判定filter包容compared(filter的查询结果是compared查询结果的子集), false代表判定filter与compared相斥(filter的查询结果与compared没有交集)
|
* @param contained
|
||||||
* @returns 返回true说明肯定相容(相斥),返回false说明无法判定相容(相斥),返回DeducedFilterCombination说明需要进一步判断此推断的条件
|
* @returns
|
||||||
|
* sureAttributes中包含被判定肯定相容或肯定不相斥的属性(不用再继续判定了)
|
||||||
|
* uncertainAttributes中包含的是无法判定结果的属性
|
||||||
|
* totalAndDeducedFilters包含的是判定过程中推论的相容的充分条件(and关系)
|
||||||
|
* totalOrDeducedFilters包含的是判定过程中推论的相斥的充分条件(or关系)
|
||||||
*/
|
*/
|
||||||
function judgeFilterRelation<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(
|
export function analyzeFilterRelation<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(
|
||||||
entity: T,
|
entity: T,
|
||||||
schema: StorageSchema<ED>,
|
schema: StorageSchema<ED>,
|
||||||
filter: NonNullable<ED[T]['Selection']['filter']>,
|
filter: NonNullable<ED[T]['Selection']['filter']>,
|
||||||
compared: NonNullable<ED[T]['Selection']['filter']>,
|
compared: NonNullable<ED[T]['Selection']['filter']>,
|
||||||
contained: boolean): boolean | DeducedFilterCombination<ED> {
|
contained: boolean) {
|
||||||
|
|
||||||
const totalAndDeducedFilters: (DeducedFilterCombination<ED> | DeducedFilter<ED, T>)[] = [];
|
const totalAndDeducedFilters: (DeducedFilterCombination<ED> | DeducedFilter<ED, T>)[] = [];
|
||||||
const totalOrDeducedFilters: (DeducedFilterCombination<ED> | DeducedFilter<ED, T>)[] = [];
|
const totalOrDeducedFilters: (DeducedFilterCombination<ED> | DeducedFilter<ED, T>)[] = [];
|
||||||
const uncertainAttributes: string[] = [];
|
const uncertainAttributes: string[] = [];
|
||||||
|
|
@ -1405,6 +1424,40 @@ function judgeFilterRelation<ED extends EntityDict & BaseEntityDict, T extends k
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalAndDeducedFilters,
|
||||||
|
totalOrDeducedFilters,
|
||||||
|
uncertainAttributes,
|
||||||
|
sureAttributes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/** 判断filter条件对compared条件是否相容或相斥
|
||||||
|
* @param entity
|
||||||
|
* @param schema
|
||||||
|
* @param filter
|
||||||
|
* @param compared
|
||||||
|
* @param contained: true代表判定filter包容compared(filter的查询结果是compared查询结果的子集), false代表判定filter与compared相斥(filter的查询结果与compared没有交集)
|
||||||
|
* @returns 返回true说明肯定相容(相斥),返回false说明无法判定相容(相斥),返回DeducedFilterCombination说明需要进一步判断此推断的条件
|
||||||
|
*/
|
||||||
|
function judgeFilterRelation<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(
|
||||||
|
entity: T,
|
||||||
|
schema: StorageSchema<ED>,
|
||||||
|
filter: NonNullable<ED[T]['Selection']['filter']>,
|
||||||
|
compared: NonNullable<ED[T]['Selection']['filter']>,
|
||||||
|
contained: boolean): boolean | DeducedFilterCombination<ED> {
|
||||||
|
|
||||||
|
const result = analyzeFilterRelation(entity, schema, filter, compared, contained);
|
||||||
|
if (typeof result === 'boolean') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
sureAttributes,
|
||||||
|
uncertainAttributes,
|
||||||
|
totalAndDeducedFilters,
|
||||||
|
totalOrDeducedFilters,
|
||||||
|
} = result;
|
||||||
|
|
||||||
if (contained) {
|
if (contained) {
|
||||||
if (sureAttributes.length === Object.keys(compared).length) {
|
if (sureAttributes.length === Object.keys(compared).length) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1457,7 +1510,7 @@ function judgeFilterRelation<ED extends EntityDict & BaseEntityDict, T extends k
|
||||||
* @param contained
|
* @param contained
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function contains<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(
|
export function contains<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(
|
||||||
entity: T,
|
entity: T,
|
||||||
schema: StorageSchema<ED>,
|
schema: StorageSchema<ED>,
|
||||||
filter: ED[T]['Selection']['filter'],
|
filter: ED[T]['Selection']['filter'],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue