oak-memory-tree-store/test/test.ts

1579 lines
46 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { v4 } from 'uuid';
import { describe, it } from 'mocha';
import { EntityDict, storageSchema } from 'oak-domain/lib/base-app-domain';
import { generateNewId } from 'oak-domain/lib/utils/uuid';
import { randomPrefixedString } from 'oak-domain/lib/utils/string';
import assert from 'assert';
import TreeStore, { TreeStoreSelectOption } from '../src/store';
import { FrontendRuntimeContext, FrontendStore } from './Context';
describe('基础测试', function () {
this.timeout(1000000);
it('[1.0]简单查询', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const id1 = generateNewId();
const id2 = generateNewId();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: id1,
entity: 'user',
entityId: 'user-id-2',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-2',
action: 'create',
data: {},
}
}
}, {
id: id2,
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
// console.log(created);
const modiEntities = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
modi: {
id: 1,
targetEntity: 1,
entity: 1,
entityId: 1,
action: 1,
data: 1,
}
},
filter: {
id: {
$in: [id1, id2],
},
},
sorter: [
{
$attr: {
modi: {
id: 1,
}
},
$direction: 'asc',
}
]
}, context, {});
assert(modiEntities.length === 2);
const modeEntities2 = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
modi: {
id: 1,
targetEntity: 1,
entity: 1,
entityId: 1,
action: 1,
data: 1,
}
},
filter: {
id: {
$in: [id1, id2],
},
entityId: 'user-id-2',
},
}, context, {});
assert(modeEntities2.length === 1);
// console.log(modiEntities);
const modeEntities3 = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
modi: {
id: 1,
targetEntity: 1,
entity: 1,
entityId: 1,
action: 1,
data: 1,
}
},
filter: {
id: {
$in: [id1, id2],
},
$or: [
{
entityId: 'user-id-2',
},
{
modi: {
entityId: 'user-id-1',
},
}
]
},
}, context, {});
assert(modeEntities3.length === 2);
const modeEntities4 = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
modi: {
id: 1,
targetEntity: 1,
entity: 1,
entityId: 1,
action: 1,
data: 1,
}
},
filter: {
id: {
$in: [id1, id2],
},
$or: [
{
entityId: 'user-id-2',
},
{
modi: {
entityId: 'user-id-2',
},
}
]
},
}, 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();
});
it('[1.1]子查询', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
/**
* 这个子查询没有跨结点的表达式,所以应该可以提前计算子查询的值
* 这个可以跟一下store.ts中translateFilter函数里子查询的分支代码
* by Xc
*/
const rows = store.select('modi', {
data: {
id: 1,
targetEntity: 1,
entity: 1,
},
filter: {
modiEntity$modi: {
entity: 'user',
entityId: 'user-id-1',
}
},
}, context, {});
// console.log(rows);
assert(rows.length === 2);
context.commit();
});
it('[1.2]行内属性上的表达式', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const id1 = generateNewId();
const id2 = generateNewId();
store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: id1,
entity: 'user-id-1',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}, {
id: id2,
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
const modiEntities = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
},
filter: {
// '#id': 'node-123',
id: {
$in: [id1, id2],
},
$expr: {
$ne: [{
'#attr': 'entity',
}, {
"#attr": 'entityId',
}]
}
},
}, context, {});
// console.log(modiEntities);
assert(modiEntities.length === 1);
const modiEntities2 = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
},
filter: {
id: {
$in: [id1, id2],
},
$expr: {
$eq: [
{
$mod: [{
'#attr': '$$seq$$',
}, 2]
},
0
],
},
},
}, context, {});
// memory-store中的$$seq$$是随机生成的这里只能debug看下对不对目前看是对的
context.commit();
});
it('[1.3]跨filter结点的表达式', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}, {
id: generateNewId(),
entity: 'user3',
entityId: 'user3-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user2',
entityId: 'user2-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
const applications = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
entityId: 1,
},
filter: {
$expr: {
$startsWith: [
{
"#refAttr": 'entityId',
"#refId": 'node-1',
},
{
"#attr": 'entity',
}
]
},
modi: {
"#id": 'node-1',
}
},
sorter: [
{
$attr: {
modi: {
entity: 1,
}
},
$direction: 'asc',
}
]
}, context, {});
// console.log(applications);
// assert(applications.length === 1);
context.commit();
});
it('[1.4]跨filter子查询的表达式', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}, {
id: generateNewId(),
entity: 'user3',
entityId: 'user3-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user2',
entityId: 'user2-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
let modies = store.select('modi', {
data: {
id: 1,
targetEntity: 1,
},
filter: {
"#id": 'node-1',
modiEntity$modi: {
$expr: {
$eq: [
{
"#attr": 'entity',
},
{
'#refId': 'node-1',
"#refAttr": 'entity',
}
]
},
'#id': 'node-2',
'#sqp': 'not in',
}
},
sorter: [
{
$attr: {
entity: 1,
},
$direction: 'asc',
}
]
}, context, {});
assert(modies.length === 1);
// console.log(modies);
context.commit();
});
it('[1.5]projection中的跨结点表达式', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}, {
id: generateNewId(),
entity: 'user3',
entityId: 'user3-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user2',
entityId: 'user2-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
let modiEntities = store.select('modiEntity', {
data: {
"#id": 'node-1',
id: 1,
entity: 1,
modi: {
id: 1,
$expr: {
$eq: [
{
"#attr": 'entity',
},
{
'#refId': 'node-1',
"#refAttr": 'entity',
}
]
},
}
},
}, context, {});
// console.log(modiEntities);
assert(modiEntities.length === 2);
modiEntities.forEach(
(me) => {
assert(me.entity === 'user' && me?.modi?.$expr === true ||
me.entity === 'user3' && me?.modi?.$expr === false);
}
)
const modiEntities2 = store.select('modiEntity', {
data: {
$expr: {
$eq: [
{
"#attr": 'entity',
},
{
'#refId': 'node-1',
"#refAttr": 'entity',
}
]
},
id: 1,
entity: 1,
modi: {
"#id": 'node-1',
id: 1,
targetEntity: 1,
entity: 1,
}
},
}, context, {});
// console.log(modiEntities2);
assert(modiEntities2.length === 2);
modiEntities2.forEach(
(me) => assert(me.entity === 'user' && me.$expr === true ||
me.entity === 'user3' && me.$expr === false)
);
context.commit();
});
it('[1.6]projection中的一对多跨结点表达式', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}]
}, context, {});
const modies = store.select('modi', {
data: {
"#id": 'node-1',
id: 1,
targetEntity: 1,
entity: 1,
modiEntity$modi: {
$entity: 'modiEntity',
data: {
id: 1,
entity: 1,
// modiId: 1,
$expr: {
$eq: [
{
"#attr": 'entity',
},
{
'#refId': 'node-1',
"#refAttr": 'entity',
}
]
},
$expr2: {
'#refId': 'node-1',
"#refAttr": 'id',
}
}
},
},
}, context, {});
// console.log(JSON.stringify(modies));
assert(modies.length === 1);
const [modi] = modies;
const { modiEntity$modi: modiEntities } = modi;
assert(modiEntities!.length === 1 && modiEntities![0]?.$expr === true && modiEntities![0]?.$expr2 === modi.id);
context.commit();
});
it('[1.7]事务性测试', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const created = store.operate('modiEntity', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
}
}
}, {
id: generateNewId(),
entity: 'user3',
entityId: 'user3-id-1',
modi: {
id: generateNewId(),
action: 'create',
data: {
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user2',
entityId: 'user2-id-1',
action: 'update',
data: {},
}
}
}]
}, context, {});
context.commit();
context.begin();
const modies = store.select('modi', {
data: {
id: 1,
entity: 1,
modiEntity$modi: {
$entity: 'modiEntity',
data: {
id: 1,
entity: 1,
modiId: 1,
}
},
},
}, context, {});
assert(modies.length === 2 && modies[0].modiEntity$modi!.length === 1);
store.operate('modiEntity', {
id: generateNewId(),
action: 'remove',
data: {},
filter: {
modiId: modies[0]!.id,
}
}, context, {});
const me2 = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
},
}, context, {});
assert(me2.length === 1 && !me2.find(ele => !!ele.$$deleteAt$$));
context.rollback();
context.begin();
const me3 = store.select('modiEntity', {
data: {
id: 1,
entity: 1,
},
}, context, {});
assert(me3.length === 2 && !me3.find(ele => !!ele.$$deleteAt$$));
context.commit();
});
it('[1.8]aggregate', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
store.operate('modi', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
modiEntity$modi: {
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}]
}
}, {
id: generateNewId(),
targetEntity: 'ddd2',
entity: 'user',
entityId: 'user-id-2',
action: 'create',
data: {},
modiEntity$modi: {
action: 'create',
data: [
{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-2',
},
{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-2',
},
{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-2',
}
],
},
}],
}, context, {});
context.commit();
context.begin();
const result = store.aggregate('modiEntity', {
data: {
'#count-1': {
id: 1,
},
'#avg-1': {
$$createAt$$: 1,
},
'#aggr': {
modi: {
targetEntity: 1,
}
}
},
}, context, {});
// console.log(result);
// distinct
const result2 = store.aggregate('modiEntity', {
data: {
'#count-1': {
entity: 1,
},
distinct: true,
},
}, context, {});
console.log(result2);
context.commit();
});
it('[1.9]selection+aggregate', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
store.operate('modi', {
id: generateNewId(),
action: 'create',
data: [{
id: generateNewId(),
targetEntity: 'ddd',
entity: 'user',
entityId: 'user-id-1',
action: 'create',
data: {},
modiEntity$modi: {
action: 'create',
data: [{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}, {
id: generateNewId(),
entity: 'user',
entityId: 'user-id-1',
}]
}
}, {
id: generateNewId(),
targetEntity: 'ddd2',
entity: 'user',
entityId: 'user-id-2',
action: 'create',
data: {},
modiEntity$modi: {
action: 'create',
data: [
{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-2',
},
{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-2',
},
{
id: generateNewId(),
entity: 'user',
entityId: 'user-id-2',
}
],
},
}],
}, context, {});
context.commit();
context.begin();
const result = store.select('modi', {
data: {
id: 1,
modiEntity$modi$$aggr: {
$entity: 'modiEntity',
data: {
'#count-1': {
id: 1,
},
'#avg-1': {
$$createAt$$: 1,
},
'#aggr': {
modi: {
targetEntity: 1,
}
}
},
filter: {
entity: 'user',
},
}
}
}, context, {});
console.log(result);
context.commit();
});
it('[1.10]select json', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const id = generateNewId();
store.operate('oper', {
id: generateNewId(),
action: 'create',
data: {
id,
action: 'test',
data: {
name: 'xc',
books: [{
title: 'mathmatics',
price: 1,
}, {
title: 'english',
price: 2,
}]
},
targetEntity: 'bbb',
}
}, context, {});
const row = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
books: [undefined, {
title: 1,
price: 1,
}],
},
},
}, context, {});
context.commit();
console.log(JSON.stringify(row));
});
it('[1.11]json as filter', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const id = generateNewId();
store.operate('oper', {
id: generateNewId(),
action: 'create',
data: {
id,
action: 'test',
data: {
name: 'xc',
books: [{
title: 'mathmatics',
price: 1,
}, {
title: 'english',
price: 2,
}]
},
targetEntity: 'bbb',
}
}, context, {});
const row = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
books: [undefined, {
title: 1,
price: 1,
}],
},
},
filter: {
data: {
name: 'xc',
}
}
}, context, {});
const row2 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
books: [undefined, {
title: 1,
price: 1,
}],
},
},
filter: {
data: {
name: 'xc2',
}
}
}, context, {});
context.commit();
// console.log(JSON.stringify(row));
assert(row.length === 1);
assert(row2.length === 0);
});
it('[1.12]complicated json filter', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const id = generateNewId();
store.operate('oper', {
id: generateNewId(),
action: 'create',
data: {
id,
action: 'test',
data: {
name: 'xc',
price: [100, 400, 1000],
},
targetEntity: 'bbb',
}
}, context, {});
const row = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: [undefined, 400],
}
}
}, context, {});
const row2 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: [undefined, 200],
}
}
}, context, {});
const row3 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: [undefined, {
$gt: 300,
}],
}
}
}, context, {});
const row4 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: {
$contains: [200, 500],
},
}
}
}, context, {});
const row5 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: {
$contains: [100, 400],
},
}
}
}, context, {});
const row6 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
price: {
$contains: ['xc'],
},
}
}
}, context, {});
const row7 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
name: {
$includes: 'xc',
},
price: {
$overlaps: [200, 400, 800],
},
}
}
}, context, {});
/**
* 带logic条件查询
*/
const row8 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
data: {
$or: [
{
name: {
$includes: 'xc',
}
},
{
name: {
$includes: 'xzw',
}
}
],
price: {
$overlaps: [200, 400, 800],
},
}
}
}, context, {});
/**
* object属性的等值查询
*/
const row9 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
action: 'test',
targetEntity: 'bbb',
data: JSON.stringify({
name: 'xc',
price: [100, 400, 1000],
})
}
}, context, {});
/**
* object 的 $exists查询
*/
const row10 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
action: 'test',
targetEntity: 'bbb',
data: {
$exists: true,
}
}
}, context, {});
const row11 = store.select('oper', {
data: {
id: 1,
data: {
name: 1,
price: 1,
},
},
filter: {
id,
action: 'test',
targetEntity: 'bbb',
data: {
$exists: false,
}
}
}, 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);
assert(row3.length === 1);
assert(row4.length === 0);
assert(row5.length === 1);
assert(row6.length === 0);
assert(row7.length === 1);
assert(row8.length === 1);
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));
});
it('[1.13]json escapes', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const id = generateNewId();
store.operate('oper', {
id: generateNewId(),
action: 'create',
data: {
id,
action: 'test',
data: {
$or: [{
name: 'xc',
}, {
name: {
$includes: 'xc',
}
}],
},
targetEntity: 'bbb',
}
}, context, {});
const rows1 = store.select('oper', {
data: {
id: 1,
},
filter: {
id,
data: {
'.$or': {
$contains: {
name: 'xc',
},
},
},
},
}, 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();
});
});
describe('性能测试', function () {
this.timeout(80000);
it('[2.1]子查询性能测试', () => {
const store = new FrontendStore(storageSchema);
const context = new FrontendRuntimeContext(store);
context.begin();
const users: EntityDict['user']['CreateSingle']['data'][] = [];
let iter = 10;
while (iter--) {
const id = generateNewId();
const user: EntityDict['user']['CreateSingle']['data'] = {
id,
name: randomPrefixedString('user'),
nickname: randomPrefixedString('nick'),
};
users.push(user);
// 每人再介绍10个人
let iter2 = 10;
while (iter2--) {
const idd = v4();
const user: EntityDict['user']['CreateSingle']['data'] = {
id: idd,
name: randomPrefixedString('user'),
nickname: randomPrefixedString('nick'),
refId: id,
};
users.push(user);
// 每人再介绍10个人
let iter3 = 10;
while (iter3--) {
const user: EntityDict['user']['CreateSingle']['data'] = {
id: v4(),
name: randomPrefixedString('user'),
nickname: randomPrefixedString('nick'),
refId: idd,
};
users.push(user);
}
}
}
context.operate('user', {
id: generateNewId(),
action: 'create',
data: users,
}, {});
/* const relationId = generateNewId();
context.operate('relation', {
id: generateNewId(),
action: 'create',
data: {
id: relationId,
name: 'bbbccc',
},
}, {});
const userRelations: EntityDict['userRelation']['CreateSingle']['data'][] = [];
iter = 50;
while (iter --) {
userRelations.push({
id: generateNewId(),
userId: users[iter].id,
entity: 'modi',
entityId: '111',
relationId,
});
}
context.operate('userRelation', {
id: generateNewId(),
action: 'create',
data: userRelations,
}, {}); */
context.commit();
/**
* 构造一个场景,三层子查询
* 在原算法下外层每一行去内层匹配相当于数据库中的三层nestloopjoin对user表进行遍历达到了2211次1 + 1110 + 110 * 10
* 耗时3s
*
* 新算法使用hashjoin每次将内表建立成hash桶再进行匹配
* 耗时20ms
*/
{
// 新算法
const start = Date.now();
context.begin();
const users2 = store.select<'user', TreeStoreSelectOption>('user', {
data: {
id: 1,
name: 1,
},
filter: {
user$ref: {
user$ref: {
name: {
$exists: true,
},
},
},
},
}, context, { });
context.commit();
const duration = Date.now() - start;
console.log(users2.length, duration);
}
{
// 旧算法
const start = Date.now();
context.begin();
const users2 = store.select<'user', TreeStoreSelectOption>('user', {
data: {
id: 1,
name: 1,
},
filter: {
user$ref: {
user$ref: {
name: {
$exists: true,
},
},
},
},
}, context, { disableSubQueryHashjoin: true });
context.commit();
const duration = Date.now() - start;
console.log(users2.length, duration);
}
});
})