Compare commits

...

16 Commits
3.3.11 ... dev

5 changed files with 174 additions and 60 deletions

View File

@ -5,6 +5,7 @@ import { EXPRESSION_PREFIX, SUB_QUERY_PREDICATE_KEYWORD } from 'oak-domain/lib/t
import { OakCongruentRowExists, OakException } from 'oak-domain/lib/types/Exception';
import { isRefAttrNode } from 'oak-domain/lib/types/Demand';
import { judgeRelation } from 'oak-domain/lib/store/relation';
// Expression引入下方声明改为any防止报错
import { execOp, isExpression, opMultipleParams } from 'oak-domain/lib/types/Expression';
import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
import { CascadeStore, polishSelection } from 'oak-domain/lib/store/CascadeStore';
@ -146,13 +147,12 @@ export default class TreeStore extends CascadeStore {
this.seq = {};
}
constructRow(node, context, option) {
let data = cloneDeep(node.$current);
if (context.getCurrentTxnId() && node.$txnId === context.getCurrentTxnId()) {
if (!node.$next) {
// 如果要求返回delete数据返回带$$deleteAt$$的行
// bug fixed这里如果是自己create再删除data也是null
if (data && option?.includedDeleted) {
return Object.assign({}, data, {
if (node.$current && option?.includedDeleted) {
return Object.assign({}, node.$current, {
[DeleteAtAttribute]: 1,
});
}
@ -160,19 +160,21 @@ export default class TreeStore extends CascadeStore {
}
else if (!node.$current) {
// 本事务创建的若在cache中$$createAt$$和$$updateAt$$置为1
return Object.assign({}, data, node.$next, context instanceof SyncContext && {
return Object.assign({}, node.$current, node.$next, context instanceof SyncContext && {
[CreateAtAttribute]: 1,
[UpdateAtAttribute]: 1,
});
}
else {
// 本事务更新的若在cache中$$updateAt$$置为1
return Object.assign({}, data, node.$next, context instanceof SyncContext && {
return Object.assign({}, node.$current, node.$next, context instanceof SyncContext && {
[UpdateAtAttribute]: 1,
});
}
}
return data;
return {
...node.$current,
};
}
testFilterFns(node, nodeDict, exprResolveFns, fns) {
const { self, otm, mto } = fns;
@ -290,12 +292,16 @@ export default class TreeStore extends CascadeStore {
* @param context
* @returns
*/
translateExpressionNode(entity, expression, context, option) {
translateExpressionNode(entity,
// expression: Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']> | ExpressionConstant,
expression, context, option) {
if (isExpression(expression)) {
const op = Object.keys(expression)[0];
const option2 = expression[op];
if (opMultipleParams(op)) {
const paramsTranslated = option2.map(ele => this.translateExpressionNode(entity, ele, context, option2));
const paramsTranslated = option2.map(
// const paramsTranslated = (option2 as (Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']>)[]).map(
ele => this.translateExpressionNode(entity, ele, context, option2));
return (row, nodeDict) => {
let later = false;
let results = paramsTranslated.map((ele) => {
@ -385,7 +391,9 @@ export default class TreeStore extends CascadeStore {
return expression;
}
}
translateExpression(entity, expression, context, option) {
translateExpression(entity,
// expression: Expression<keyof ED[T]['Schema']>,
expression, context, option) {
const expr = this.translateExpressionNode(entity, expression, context, option);
return (row, nodeDict) => {
if (typeof expr !== 'function') {
@ -566,6 +574,21 @@ export default class TreeStore extends CascadeStore {
}).length > 0;
};
}
case '$length': {
// json中的数组长度查询
const length = value;
return (row) => {
const data = path ? get(row, path) : row;
assert(data instanceof Array, '$length operator can only used on array attribute');
if (typeof length === 'number') {
return data.length === length;
}
else {
const op = Object.keys(length)[0];
return this.translatePredicate(entity, 'length', op, length[op], option)(data);
}
};
}
default: {
throw new Error(`predicate ${predicate} is not recoganized`);
}
@ -1902,16 +1925,19 @@ export default class TreeStore extends CascadeStore {
}, context, option2);
this.addToOperationResult(result, entity, 'create');
}
else if (this.store[entity][id].$current?.[UpdateAtAttribute] <= d[entity][id][UpdateAtAttribute]) {
this.updateAbjointRow(entity, {
id: 'dummy',
action: 'update',
data: d[entity][id],
filter: {
id,
},
}, context, option2);
this.addToOperationResult(result, entity, 'update');
else if (this.store[entity]?.[id]) {
const row = this.constructRow(this.store[entity][id], context);
if (row[UpdateAtAttribute] <= d[entity][id][UpdateAtAttribute]) {
this.updateAbjointRow(entity, {
id: 'dummy',
action: 'update',
data: d[entity][id],
filter: {
id,
},
}, context, option2);
this.addToOperationResult(result, entity, 'update');
}
}
}
}

View File

@ -7,6 +7,7 @@ const Demand_1 = require("oak-domain/lib/types/Demand");
const Exception_1 = require("oak-domain/lib/types/Exception");
const Demand_2 = require("oak-domain/lib/types/Demand");
const relation_1 = require("oak-domain/lib/store/relation");
// Expression引入下方声明改为any防止报错
const Expression_1 = require("oak-domain/lib/types/Expression");
const SyncRowStore_1 = require("oak-domain/lib/store/SyncRowStore");
const CascadeStore_1 = require("oak-domain/lib/store/CascadeStore");
@ -148,13 +149,12 @@ class TreeStore extends CascadeStore_1.CascadeStore {
this.seq = {};
}
constructRow(node, context, option) {
let data = (0, lodash_1.cloneDeep)(node.$current);
if (context.getCurrentTxnId() && node.$txnId === context.getCurrentTxnId()) {
if (!node.$next) {
// 如果要求返回delete数据返回带$$deleteAt$$的行
// bug fixed这里如果是自己create再删除data也是null
if (data && option?.includedDeleted) {
return Object.assign({}, data, {
if (node.$current && option?.includedDeleted) {
return Object.assign({}, node.$current, {
[Entity_1.DeleteAtAttribute]: 1,
});
}
@ -162,19 +162,21 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}
else if (!node.$current) {
// 本事务创建的若在cache中$$createAt$$和$$updateAt$$置为1
return Object.assign({}, data, node.$next, context instanceof SyncRowStore_1.SyncContext && {
return Object.assign({}, node.$current, node.$next, context instanceof SyncRowStore_1.SyncContext && {
[Entity_1.CreateAtAttribute]: 1,
[Entity_1.UpdateAtAttribute]: 1,
});
}
else {
// 本事务更新的若在cache中$$updateAt$$置为1
return Object.assign({}, data, node.$next, context instanceof SyncRowStore_1.SyncContext && {
return Object.assign({}, node.$current, node.$next, context instanceof SyncRowStore_1.SyncContext && {
[Entity_1.UpdateAtAttribute]: 1,
});
}
}
return data;
return {
...node.$current,
};
}
testFilterFns(node, nodeDict, exprResolveFns, fns) {
const { self, otm, mto } = fns;
@ -292,12 +294,16 @@ class TreeStore extends CascadeStore_1.CascadeStore {
* @param context
* @returns
*/
translateExpressionNode(entity, expression, context, option) {
translateExpressionNode(entity,
// expression: Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']> | ExpressionConstant,
expression, context, option) {
if ((0, Expression_1.isExpression)(expression)) {
const op = Object.keys(expression)[0];
const option2 = expression[op];
if ((0, Expression_1.opMultipleParams)(op)) {
const paramsTranslated = option2.map(ele => this.translateExpressionNode(entity, ele, context, option2));
const paramsTranslated = option2.map(
// const paramsTranslated = (option2 as (Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']>)[]).map(
ele => this.translateExpressionNode(entity, ele, context, option2));
return (row, nodeDict) => {
let later = false;
let results = paramsTranslated.map((ele) => {
@ -387,7 +393,9 @@ class TreeStore extends CascadeStore_1.CascadeStore {
return expression;
}
}
translateExpression(entity, expression, context, option) {
translateExpression(entity,
// expression: Expression<keyof ED[T]['Schema']>,
expression, context, option) {
const expr = this.translateExpressionNode(entity, expression, context, option);
return (row, nodeDict) => {
if (typeof expr !== 'function') {
@ -568,6 +576,21 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}).length > 0;
};
}
case '$length': {
// json中的数组长度查询
const length = value;
return (row) => {
const data = path ? (0, lodash_1.get)(row, path) : row;
(0, assert_1.assert)(data instanceof Array, '$length operator can only used on array attribute');
if (typeof length === 'number') {
return data.length === length;
}
else {
const op = Object.keys(length)[0];
return this.translatePredicate(entity, 'length', op, length[op], option)(data);
}
};
}
default: {
throw new Error(`predicate ${predicate} is not recoganized`);
}
@ -1904,16 +1927,19 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}, context, option2);
this.addToOperationResult(result, entity, 'create');
}
else if (this.store[entity][id].$current?.[Entity_1.UpdateAtAttribute] <= d[entity][id][Entity_1.UpdateAtAttribute]) {
this.updateAbjointRow(entity, {
id: 'dummy',
action: 'update',
data: d[entity][id],
filter: {
id,
},
}, context, option2);
this.addToOperationResult(result, entity, 'update');
else if (this.store[entity]?.[id]) {
const row = this.constructRow(this.store[entity][id], context);
if (row[Entity_1.UpdateAtAttribute] <= d[entity][id][Entity_1.UpdateAtAttribute]) {
this.updateAbjointRow(entity, {
id: 'dummy',
action: 'update',
data: d[entity][id],
filter: {
id,
},
}, context, option2);
this.addToOperationResult(result, entity, 'update');
}
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "oak-memory-tree-store",
"version": "3.3.11",
"version": "3.3.15",
"description": "oak框架中内存级store的实现",
"author": {
"name": "XuChang"
@ -10,7 +10,7 @@
"es/**/*"
],
"dependencies": {
"oak-domain": "^5.1.21",
"oak-domain": "file:../oak-domain",
"uuid": "^8.3.2"
},
"scripts": {

View File

@ -15,6 +15,7 @@ import { StorageSchema } from 'oak-domain/lib/types/Storage';
import { ExprResolveFn, NodeDict, RowNode } from "./types/type";
import { isRefAttrNode, Q_BooleanValue, Q_FullTextValue, Q_NumberValue, Q_StringValue } from 'oak-domain/lib/types/Demand';
import { judgeRelation } from 'oak-domain/lib/store/relation';
// Expression引入下方声明改为any防止报错
import { execOp, Expression, ExpressionConstant, isExpression, opMultipleParams } from 'oak-domain/lib/types/Expression';
import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
@ -219,13 +220,12 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
}
private constructRow<Cxt extends Context, OP extends TreeStoreSelectOption>(node: RowNode, context: Cxt, option?: OP) {
let data = cloneDeep(node.$current);
if (context.getCurrentTxnId() && node.$txnId === context.getCurrentTxnId()) {
if (!node.$next) {
// 如果要求返回delete数据返回带$$deleteAt$$的行
// bug fixed这里如果是自己create再删除data也是null
if (data && option?.includedDeleted) {
return Object.assign({}, data, {
if (node.$current && option?.includedDeleted) {
return Object.assign({}, node.$current, {
[DeleteAtAttribute]: 1,
});
}
@ -233,19 +233,21 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
}
else if (!node.$current) {
// 本事务创建的若在cache中$$createAt$$和$$updateAt$$置为1
return Object.assign({}, data, node.$next, context instanceof SyncContext && {
return Object.assign({}, node.$current, node.$next, context instanceof SyncContext && {
[CreateAtAttribute]: 1,
[UpdateAtAttribute]: 1,
});
}
else {
// 本事务更新的若在cache中$$updateAt$$置为1
return Object.assign({}, data, node.$next, context instanceof SyncContext && {
return Object.assign({}, node.$current, node.$next, context instanceof SyncContext && {
[UpdateAtAttribute]: 1,
});
})
}
}
return data;
return {
...node.$current,
};
}
private testFilterFns(
@ -397,7 +399,8 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
*/
private translateExpressionNode<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends Context>(
entity: T,
expression: Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']> | ExpressionConstant,
// expression: Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']> | ExpressionConstant,
expression: any,
context: Cxt,
option?: OP): ExprNodeTranslator | ExpressionConstant {
@ -406,7 +409,8 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
const option2 = (expression as any)[op];
if (opMultipleParams(op)) {
const paramsTranslated = (option2 as (Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']>)[]).map(
const paramsTranslated = (option2 as any[]).map(
// const paramsTranslated = (option2 as (Expression<keyof ED[T]['Schema']> | RefAttr<keyof ED[T]['Schema']>)[]).map(
ele => this.translateExpressionNode(entity, ele, context, option2)
);
@ -514,7 +518,8 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
private translateExpression<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends Context>(
entity: T,
expression: Expression<keyof ED[T]['Schema']>,
// expression: Expression<keyof ED[T]['Schema']>,
expression: any,
context: Cxt, option?: OP): (row: Partial<ED[T]['OpSchema']>, nodeDict: NodeDict) => ExpressionConstant | ExprLaterCheckFn {
const expr = this.translateExpressionNode(entity, expression, context, option);
@ -707,6 +712,21 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
}).length > 0;
};
}
case '$length': {
// json中的数组长度查询
const length = value;
return (row) => {
const data = path ? get(row, path) : row;
assert(data instanceof Array, '$length operator can only used on array attribute');
if (typeof length === 'number') {
return data.length === length;
}
else {
const op = Object.keys(length)[0];
return this.translatePredicate(entity, 'length', op, length[op], option)(data);
}
}
}
default: {
throw new Error(`predicate ${predicate} is not recoganized`);
}
@ -2279,16 +2299,19 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
} as ED[keyof ED]['CreateSingle'], context, option2);
this.addToOperationResult(result, entity, 'create');
}
else if (this.store[entity]![id].$current?.[UpdateAtAttribute]! <= d[entity]![id]![UpdateAtAttribute]!) {
this.updateAbjointRow(entity, {
id: 'dummy',
action: 'update',
data: d[entity]![id] as any,
filter: {
id,
} as any,
}, context, option2);
this.addToOperationResult(result, entity, 'update');
else if (this.store[entity]?.[id]) {
const row = this.constructRow(this.store[entity]![id]!, context);
if ((row![UpdateAtAttribute] as number) <= (d[entity]![id]![UpdateAtAttribute] as number)) {
this.updateAbjointRow(entity, {
id: 'dummy',
action: 'update',
data: d[entity]![id] as any,
filter: {
id,
} as any,
}, context, option2);
this.addToOperationResult(result, entity, 'update');
}
}
}
}

View File

@ -1317,6 +1317,43 @@ describe('基础测试', function () {
}
}, context, {});
const row12 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: {
$length: 3,
},
}
}
}, context, {});
const row13 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: {
$length: {
$gt: 3,
},
},
}
}
}, context, {});
context.commit();
assert(row.length === 1);
assert(row2.length === 0);
@ -1329,6 +1366,8 @@ describe('基础测试', function () {
assert(row9.length === 1);
assert(row10.length === 1);
assert(row11.length === 0);
assert(row12.length === 1);
assert(row13.length === 0);
// console.log(JSON.stringify(row7));
});