Merge branch 'dev' into release

This commit is contained in:
Xu Chang 2023-12-16 22:16:32 +08:00
commit e0eb69df75
7 changed files with 327 additions and 119 deletions

4
es/store.d.ts vendored
View File

@ -91,8 +91,8 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
private formAggregation;
protected selectSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Partial<ED[T]['Schema']>[];
protected selectAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Promise<Partial<ED[T]["Schema"]>[]>;
protected aggregateSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
protected aggregateAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
protected aggregateAbjointRowSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
protected aggregateAbjointRowAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
protected countSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: OP): number;
protected countAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: OP): Promise<number>;
private addToTxnNode;

View File

@ -1,4 +1,4 @@
import { cloneDeep, get, groupBy, set, unset, differenceBy, intersectionBy, pull, pick } from 'oak-domain/lib/utils/lodash';
import { cloneDeep, get, groupBy, set, unset, uniqBy, uniq, differenceBy, intersectionBy, pull, pick } from 'oak-domain/lib/utils/lodash';
import { assert } from 'oak-domain/lib/utils/assert';
import { DeleteAtAttribute, CreateAtAttribute, UpdateAtAttribute } from "oak-domain/lib/types/Entity";
import { EXPRESSION_PREFIX, SUB_QUERY_PREDICATE_KEYWORD } from 'oak-domain/lib/types/Demand';
@ -445,6 +445,12 @@ export default class TreeStore extends CascadeStore {
return ['number', 'string'].includes(typeof data) && data >= value[0] && data <= value[1] || obscurePass(data, option);
};
}
case '$mod': {
return (row) => {
const data = get(row, path);
return typeof data === 'number' && data % value[0] === value[1] || obscurePass(data, option);
};
}
case '$startsWith': {
return (row) => {
const data = get(row, path);
@ -561,7 +567,7 @@ export default class TreeStore extends CascadeStore {
const attr2 = attr.startsWith('.') ? attr.slice(1) : attr;
const path2 = path ? `${path}.${attr2}` : attr2;
if (typeof p[attr] !== 'object') {
fns2.push(this.translatePredicate(path2, '$eq', filter[attr]));
fns2.push(this.translatePredicate(path2, '$eq', p[attr]));
}
else {
translatePredicateInner(p[attr], path2, fns2);
@ -1332,7 +1338,7 @@ export default class TreeStore extends CascadeStore {
});
}
// 先计算projectionformResult只处理abjoint的行不需要考虑expression和一对多多对一关系
const rows2 = [];
let rows2 = [];
const incompletedRowIds = [];
const { data: projection } = selection;
for (const row of rows) {
@ -1385,20 +1391,22 @@ export default class TreeStore extends CascadeStore {
}
}
// 这三个属性在前台cache中可能表达特殊语义的需要返回
if (row[DeleteAtAttribute]) {
Object.assign(result, {
[DeleteAtAttribute]: row[DeleteAtAttribute],
});
}
if (row[UpdateAtAttribute]) {
Object.assign(result, {
[UpdateAtAttribute]: row[UpdateAtAttribute],
});
}
if (row[CreateAtAttribute]) {
Object.assign(result, {
[CreateAtAttribute]: row[CreateAtAttribute],
});
if (!selection.distinct) {
if (row[DeleteAtAttribute]) {
Object.assign(result, {
[DeleteAtAttribute]: row[DeleteAtAttribute],
});
}
if (row[UpdateAtAttribute]) {
Object.assign(result, {
[UpdateAtAttribute]: row[UpdateAtAttribute],
});
}
if (row[CreateAtAttribute]) {
Object.assign(result, {
[CreateAtAttribute]: row[CreateAtAttribute],
});
}
}
rows2.push(result);
}
@ -1430,13 +1438,15 @@ export default class TreeStore extends CascadeStore {
const sorterFn = this.translateSorter(entity, sorter, context, option);
rows2.sort(sorterFn);
}
// 最后用indexFrom和count来截断
// 用indexFrom和count来截断
if (typeof indexFrom === 'number') {
return rows2.slice(indexFrom, indexFrom + count);
rows2 = rows2.slice(indexFrom, indexFrom + count);
}
else {
return rows2;
// 如果有distinct再计算distinct
if (selection.distinct) {
rows2 = uniqBy(rows2, (ele) => JSON.stringify(ele));
}
return rows2;
}
/**
* 本函数把结果中的相应属性映射成一个字符串用于GroupBy
@ -1481,13 +1491,20 @@ export default class TreeStore extends CascadeStore {
};
}
calcAggregation(entity, rows, aggregationData) {
const ops = Object.keys(aggregationData).filter(ele => ele !== '#aggr');
const ops = Object.keys(aggregationData).filter(ele => ele !== '#aggr' && ele.startsWith('#'));
const result = {};
const results = {};
for (const row of rows) {
for (const op of ops) {
const { values } = this.mappingProjectionOnRow(entity, row, aggregationData[op]);
assert(values.length === 1, `聚合运算中,${op}的目标属性多于1个`);
if (op.startsWith('#max')) {
if (results[op]) {
results[op].push(values[0]);
}
else {
results[op] = [values[0]];
}
/* if (op.startsWith('#max')) {
if (![undefined, null].includes(values[0]) && (!result.hasOwnProperty(op) || result[op] < values[0])) {
result[op] = values[0];
}
@ -1533,20 +1550,52 @@ export default class TreeStore extends CascadeStore {
result[op].count += 1;
}
}
}
} */
}
}
for (const op of ops) {
if (!result[op]) {
if (op.startsWith('#count')) {
result[op] = 0;
}
else {
result[op] = null;
}
const { distinct } = aggregationData;
for (const op in results) {
if (op.startsWith('#max')) {
result[op] = null;
results[op].forEach((ele) => {
if (![undefined, null].includes(ele) && (result[op] === null || result[op] < ele)) {
result[op] = ele;
}
});
}
else if (op.startsWith('#min')) {
result[op] = null;
results[op].forEach((ele) => {
if (![undefined, null].includes(ele) && (result[op] === null || result[op] > ele)) {
result[op] = ele;
}
});
}
else if (op.startsWith('#sum')) {
result[op] = 0;
const data = distinct ? uniq(results[op]) : results[op];
data.forEach((ele) => {
assert(typeof ele === 'number', '只有number类型的属性才可以计算sum');
result[op] += ele;
});
}
else if (op.startsWith('#count')) {
result[op] = 0;
const data = distinct ? uniq(results[op]) : results[op];
data.forEach((ele) => {
if (![undefined, null].includes(ele)) {
result[op] += 1;
}
});
}
else if (op.startsWith('#avg')) {
result[op] = result[op].total / result[op].count;
result[op] = 0;
const data = (distinct ? uniq(results[op]) : results[op]).filter(ele => ![undefined, null].includes(ele));
data.forEach((ele) => {
assert(typeof ele === 'number', '只有number类型的属性才可以计算avg');
result[op] += ele;
});
result[op] = result[op] / data.length;
}
}
return result;
@ -1583,7 +1632,7 @@ export default class TreeStore extends CascadeStore {
result.forEach((ele) => this.formExprInResult(entity, selection.data, ele, {}, context));
return result;
}
aggregateSync(entity, aggregation, context, option) {
aggregateAbjointRowSync(entity, aggregation, context, option) {
assert(context.getCurrentTxnId());
const { data, filter, sorter, indexFrom, count } = aggregation;
const p = {};
@ -1605,7 +1654,7 @@ export default class TreeStore extends CascadeStore {
// 最后计算Aggregation
return this.formAggregation(entity, result, aggregation.data);
}
async aggregateAsync(entity, aggregation, context, option) {
async aggregateAbjointRowAsync(entity, aggregation, context, option) {
assert(context.getCurrentTxnId());
const { data, filter, sorter, indexFrom, count } = aggregation;
const p = {};

4
lib/store.d.ts vendored
View File

@ -91,8 +91,8 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
private formAggregation;
protected selectSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Partial<ED[T]['Schema']>[];
protected selectAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Promise<Partial<ED[T]["Schema"]>[]>;
protected aggregateSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
protected aggregateAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
protected aggregateAbjointRowSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
protected aggregateAbjointRowAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
protected countSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: OP): number;
protected countAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: OP): Promise<number>;
private addToTxnNode;

View File

@ -447,6 +447,12 @@ class TreeStore extends CascadeStore_1.CascadeStore {
return ['number', 'string'].includes(typeof data) && data >= value[0] && data <= value[1] || obscurePass(data, option);
};
}
case '$mod': {
return (row) => {
const data = (0, lodash_1.get)(row, path);
return typeof data === 'number' && data % value[0] === value[1] || obscurePass(data, option);
};
}
case '$startsWith': {
return (row) => {
const data = (0, lodash_1.get)(row, path);
@ -563,7 +569,7 @@ class TreeStore extends CascadeStore_1.CascadeStore {
const attr2 = attr.startsWith('.') ? attr.slice(1) : attr;
const path2 = path ? `${path}.${attr2}` : attr2;
if (typeof p[attr] !== 'object') {
fns2.push(this.translatePredicate(path2, '$eq', filter[attr]));
fns2.push(this.translatePredicate(path2, '$eq', p[attr]));
}
else {
translatePredicateInner(p[attr], path2, fns2);
@ -1334,7 +1340,7 @@ class TreeStore extends CascadeStore_1.CascadeStore {
});
}
// 先计算projectionformResult只处理abjoint的行不需要考虑expression和一对多多对一关系
const rows2 = [];
let rows2 = [];
const incompletedRowIds = [];
const { data: projection } = selection;
for (const row of rows) {
@ -1387,20 +1393,22 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}
}
// 这三个属性在前台cache中可能表达特殊语义的需要返回
if (row[Entity_1.DeleteAtAttribute]) {
Object.assign(result, {
[Entity_1.DeleteAtAttribute]: row[Entity_1.DeleteAtAttribute],
});
}
if (row[Entity_1.UpdateAtAttribute]) {
Object.assign(result, {
[Entity_1.UpdateAtAttribute]: row[Entity_1.UpdateAtAttribute],
});
}
if (row[Entity_1.CreateAtAttribute]) {
Object.assign(result, {
[Entity_1.CreateAtAttribute]: row[Entity_1.CreateAtAttribute],
});
if (!selection.distinct) {
if (row[Entity_1.DeleteAtAttribute]) {
Object.assign(result, {
[Entity_1.DeleteAtAttribute]: row[Entity_1.DeleteAtAttribute],
});
}
if (row[Entity_1.UpdateAtAttribute]) {
Object.assign(result, {
[Entity_1.UpdateAtAttribute]: row[Entity_1.UpdateAtAttribute],
});
}
if (row[Entity_1.CreateAtAttribute]) {
Object.assign(result, {
[Entity_1.CreateAtAttribute]: row[Entity_1.CreateAtAttribute],
});
}
}
rows2.push(result);
}
@ -1432,13 +1440,15 @@ class TreeStore extends CascadeStore_1.CascadeStore {
const sorterFn = this.translateSorter(entity, sorter, context, option);
rows2.sort(sorterFn);
}
// 最后用indexFrom和count来截断
// 用indexFrom和count来截断
if (typeof indexFrom === 'number') {
return rows2.slice(indexFrom, indexFrom + count);
rows2 = rows2.slice(indexFrom, indexFrom + count);
}
else {
return rows2;
// 如果有distinct再计算distinct
if (selection.distinct) {
rows2 = (0, lodash_1.uniqBy)(rows2, (ele) => JSON.stringify(ele));
}
return rows2;
}
/**
* 本函数把结果中的相应属性映射成一个字符串用于GroupBy
@ -1483,13 +1493,20 @@ class TreeStore extends CascadeStore_1.CascadeStore {
};
}
calcAggregation(entity, rows, aggregationData) {
const ops = Object.keys(aggregationData).filter(ele => ele !== '#aggr');
const ops = Object.keys(aggregationData).filter(ele => ele !== '#aggr' && ele.startsWith('#'));
const result = {};
const results = {};
for (const row of rows) {
for (const op of ops) {
const { values } = this.mappingProjectionOnRow(entity, row, aggregationData[op]);
(0, assert_1.assert)(values.length === 1, `聚合运算中,${op}的目标属性多于1个`);
if (op.startsWith('#max')) {
if (results[op]) {
results[op].push(values[0]);
}
else {
results[op] = [values[0]];
}
/* if (op.startsWith('#max')) {
if (![undefined, null].includes(values[0]) && (!result.hasOwnProperty(op) || result[op] < values[0])) {
result[op] = values[0];
}
@ -1501,7 +1518,7 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}
else if (op.startsWith('#sum')) {
if (![undefined, null].includes(values[0])) {
(0, assert_1.assert)(typeof values[0] === 'number', '只有number类型的属性才可以计算sum');
assert(typeof values[0] === 'number', '只有number类型的属性才可以计算sum');
if (!result.hasOwnProperty(op)) {
result[op] = values[0];
}
@ -1521,9 +1538,9 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}
}
else {
(0, assert_1.assert)(op.startsWith('#avg'));
assert(op.startsWith('#avg'));
if (![undefined, null].includes(values[0])) {
(0, assert_1.assert)(typeof values[0] === 'number', '只有number类型的属性才可以计算avg');
assert(typeof values[0] === 'number', '只有number类型的属性才可以计算avg');
if (!result.hasOwnProperty(op)) {
result[op] = {
total: values[0],
@ -1535,20 +1552,52 @@ class TreeStore extends CascadeStore_1.CascadeStore {
result[op].count += 1;
}
}
}
} */
}
}
for (const op of ops) {
if (!result[op]) {
if (op.startsWith('#count')) {
result[op] = 0;
}
else {
result[op] = null;
}
const { distinct } = aggregationData;
for (const op in results) {
if (op.startsWith('#max')) {
result[op] = null;
results[op].forEach((ele) => {
if (![undefined, null].includes(ele) && (result[op] === null || result[op] < ele)) {
result[op] = ele;
}
});
}
else if (op.startsWith('#min')) {
result[op] = null;
results[op].forEach((ele) => {
if (![undefined, null].includes(ele) && (result[op] === null || result[op] > ele)) {
result[op] = ele;
}
});
}
else if (op.startsWith('#sum')) {
result[op] = 0;
const data = distinct ? (0, lodash_1.uniq)(results[op]) : results[op];
data.forEach((ele) => {
(0, assert_1.assert)(typeof ele === 'number', '只有number类型的属性才可以计算sum');
result[op] += ele;
});
}
else if (op.startsWith('#count')) {
result[op] = 0;
const data = distinct ? (0, lodash_1.uniq)(results[op]) : results[op];
data.forEach((ele) => {
if (![undefined, null].includes(ele)) {
result[op] += 1;
}
});
}
else if (op.startsWith('#avg')) {
result[op] = result[op].total / result[op].count;
result[op] = 0;
const data = (distinct ? (0, lodash_1.uniq)(results[op]) : results[op]).filter(ele => ![undefined, null].includes(ele));
data.forEach((ele) => {
(0, assert_1.assert)(typeof ele === 'number', '只有number类型的属性才可以计算avg');
result[op] += ele;
});
result[op] = result[op] / data.length;
}
}
return result;
@ -1585,7 +1634,7 @@ class TreeStore extends CascadeStore_1.CascadeStore {
result.forEach((ele) => this.formExprInResult(entity, selection.data, ele, {}, context));
return result;
}
aggregateSync(entity, aggregation, context, option) {
aggregateAbjointRowSync(entity, aggregation, context, option) {
(0, assert_1.assert)(context.getCurrentTxnId());
const { data, filter, sorter, indexFrom, count } = aggregation;
const p = {};
@ -1607,7 +1656,7 @@ class TreeStore extends CascadeStore_1.CascadeStore {
// 最后计算Aggregation
return this.formAggregation(entity, result, aggregation.data);
}
async aggregateAsync(entity, aggregation, context, option) {
async aggregateAbjointRowAsync(entity, aggregation, context, option) {
(0, assert_1.assert)(context.getCurrentTxnId());
const { data, filter, sorter, indexFrom, count } = aggregation;
const p = {};

View File

@ -1,15 +1,16 @@
{
"name": "oak-memory-tree-store",
"version": "3.1.1",
"version": "3.1.2",
"description": "oak框架中内存级store的实现",
"author": {
"name": "XuChang"
},
"files": [
"lib/**/*"
"lib/**/*",
"es/**/*"
],
"dependencies": {
"oak-domain": "^4.0.0",
"oak-domain": "^4.0.1",
"uuid": "^8.3.2"
},
"scripts": {

View File

@ -1,5 +1,5 @@
import {
cloneDeep, get, groupBy, set, unset,
cloneDeep, get, groupBy, set, unset, uniqBy, uniq,
differenceBy, intersectionBy, pull, pick
} from 'oak-domain/lib/utils/lodash';
import { assert } from 'oak-domain/lib/utils/assert';
@ -78,7 +78,7 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
private getNextSeq(entity: keyof ED) {
if (this.seq[entity]) {
const seq = this.seq[entity];
this.seq[entity] ++;
this.seq[entity]! ++;
return seq;
}
this.seq[entity] = 2;
@ -87,7 +87,7 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
private setMaxSeq(entity: keyof ED, seq: number) {
if (this.seq[entity]) {
if (this.seq[entity] < seq) {
if (this.seq[entity]! < seq) {
this.seq[entity] = seq;
}
}
@ -582,6 +582,12 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
return ['number', 'string'].includes(typeof data) && data >= value[0] && data <= value[1] || obscurePass(data, option);
};
}
case '$mod': {
return (row) => {
const data = get(row, path);
return typeof data === 'number' && data % value[0] === value[1] || obscurePass(data, option);
};
}
case '$startsWith': {
return (row) => {
const data = get(row, path);
@ -709,7 +715,7 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
const attr2 = attr.startsWith('.') ? attr.slice(1) : attr;
const path2 = path ? `${path}.${attr2}` : attr2;
if (typeof p[attr] !== 'object') {
fns2.push(this.translatePredicate(path2, '$eq', filter[attr]));
fns2.push(this.translatePredicate(path2, '$eq', p[attr]));
}
else {
translatePredicateInner(p[attr], path2, fns2);
@ -1598,7 +1604,7 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
}
// 先计算projectionformResult只处理abjoint的行不需要考虑expression和一对多多对一关系
const rows2: Array<Partial<ED[T]['Schema']>> = [];
let rows2: Array<Partial<ED[T]['Schema']>> = [];
const incompletedRowIds: string[] = [];
const { data: projection } = selection;
for (const row of rows) {
@ -1654,21 +1660,23 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
}
}
// 这三个属性在前台cache中可能表达特殊语义的需要返回
if (row[DeleteAtAttribute]) {
Object.assign(result, {
[DeleteAtAttribute]: row[DeleteAtAttribute],
});
}
if (row[UpdateAtAttribute]) {
Object.assign(result, {
[UpdateAtAttribute]: row[UpdateAtAttribute],
});
}
if (row[CreateAtAttribute]) {
Object.assign(result, {
[CreateAtAttribute]: row[CreateAtAttribute],
});
if (!selection.distinct) {
if (row[DeleteAtAttribute]) {
Object.assign(result, {
[DeleteAtAttribute]: row[DeleteAtAttribute],
});
}
if (row[UpdateAtAttribute]) {
Object.assign(result, {
[UpdateAtAttribute]: row[UpdateAtAttribute],
});
}
if (row[CreateAtAttribute]) {
Object.assign(result, {
[CreateAtAttribute]: row[CreateAtAttribute],
});
}
}
rows2.push(result);
}
@ -1702,13 +1710,17 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
rows2.sort(sorterFn);
}
// 最后用indexFrom和count来截断
// 用indexFrom和count来截断
if (typeof indexFrom === 'number') {
return rows2.slice(indexFrom, indexFrom! + count!);
rows2 = rows2.slice(indexFrom, indexFrom! + count!);
}
else {
return rows2;
// 如果有distinct再计算distinct
if (selection.distinct) {
rows2 = uniqBy(rows2, (ele) => JSON.stringify(ele));
}
return rows2;
}
/**
@ -1769,14 +1781,21 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
aggregationData: ED[T]['Aggregation']['data']
) {
const ops = Object.keys(aggregationData).filter(
ele => ele !== '#aggr'
ele => ele !== '#aggr' && ele.startsWith('#')
) as AggregationOp[];
const result = {} as Record<string, any>;
const results = {} as Record<string, any[]>;
for (const row of rows) {
for (const op of ops) {
const { values } = this.mappingProjectionOnRow(entity, row, (aggregationData as any)[op]);
assert(values.length === 1, `聚合运算中,${op}的目标属性多于1个`);
if (op.startsWith('#max')) {
if (results[op]) {
results[op].push(values[0]);
}
else {
results[op] = [values[0]];
}
/* if (op.startsWith('#max')) {
if (![undefined, null].includes(values[0]) && (!result.hasOwnProperty(op) || result[op] < values[0])) {
result[op] = values[0];
}
@ -1822,21 +1841,64 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
result[op].count += 1;
}
}
}
} */
}
}
for (const op of ops) {
if (!result[op]) {
if (op.startsWith('#count')) {
result[op] = 0;
}
else {
result[op] = null;
}
const { distinct } = aggregationData;
for (const op in results) {
if (op.startsWith('#max')) {
result[op] = null;
results[op].forEach(
(ele) => {
if (![undefined, null].includes(ele) && (result[op] === null || result[op] < ele)) {
result[op] = ele;
}
}
);
}
else if (op.startsWith('#min')) {
result[op] = null;
results[op].forEach(
(ele) => {
if (![undefined, null].includes(ele) && (result[op] === null || result[op] > ele)) {
result[op] = ele;
}
}
);
}
else if (op.startsWith('#sum')) {
result[op] = 0;
const data = distinct ? uniq(results[op]) : results[op];
data.forEach(
(ele) => {
assert(typeof ele === 'number', '只有number类型的属性才可以计算sum');
result[op] += ele;
}
);
}
else if (op.startsWith('#count')) {
result[op] = 0;
const data = distinct ? uniq(results[op]) : results[op];
data.forEach(
(ele) => {
if (![undefined, null].includes(ele)) {
result[op] += 1;
}
}
);
}
else if (op.startsWith('#avg')) {
result[op] = result[op].total / result[op].count;
result[op] = 0;
const data = (distinct ? uniq(results[op]) : results[op]).filter(
ele => ![undefined, null].includes(ele)
);
data.forEach(
(ele) => {
assert(typeof ele === 'number', '只有number类型的属性才可以计算avg');
result[op] += ele;
}
);
result[op] = result[op]/data.length;
}
}
return result as AggregationResult<ED[T]['Schema']>[number];
@ -1895,7 +1957,7 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
return result;
}
protected aggregateSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(
protected aggregateAbjointRowSync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends SyncContext<ED>>(
entity: T,
aggregation: ED[T]['Aggregation'],
context: Cxt,
@ -1926,7 +1988,7 @@ export default class TreeStore<ED extends EntityDict & BaseEntityDict> extends C
return this.formAggregation(entity, result, aggregation.data);
}
protected async aggregateAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(
protected async aggregateAbjointRowAsync<T extends keyof ED, OP extends TreeStoreSelectOption, Cxt extends AsyncContext<ED>>(
entity: T,
aggregation: ED[T]['Aggregation'],
context: Cxt,

View File

@ -172,6 +172,19 @@ describe('基础测试', function () {
},
}, context, {});
assert(modeEntities4.length === 1);
const modeEntities5 = store.select('modiEntity', {
data: {
entity: 1,
},
filter: {
id: {
$in: [id1, id2],
},
},
distinct: true
}, context, {});
// console.log(modeEntities5);
context.commit();
});
@ -831,7 +844,19 @@ describe('基础测试', function () {
}
},
}, context, {});
console.log(result);
// console.log(result);
// distinct
const result2 = store.aggregate('modiEntity', {
data: {
'#count-1': {
entity: 1,
},
distinct: true,
},
}, context, {});
console.log(result2);
context.commit();
});
@ -1293,7 +1318,29 @@ describe('基础测试', function () {
},
}, context, {});
const rows2 = store.select('oper', {
data: {
id: 1,
},
filter: {
id,
data: {
'.$or': [
{
name: 'xc',
},
{
name: {
'.$includes': 'xc',
}
}
],
},
},
}, context, {});
assert(rows1.length === 1);
assert(rows2.length === 1);
context.commit();
});
});