实现sync动作

This commit is contained in:
Xu Chang 2022-03-21 20:58:16 +08:00
parent 7984af515f
commit ae86d5707c
4 changed files with 131 additions and 30 deletions

2
lib/store.d.ts vendored
View File

@ -67,7 +67,7 @@ export default class TreeStore<ED extends {
protected updateAbjointRow<T extends keyof ED>(entity: T, operation: DeduceCreateSingleOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Context<ED>, params?: OperateParams): Promise<void>;
private doOperation;
operate<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Context<ED>, params?: OperateParams): Promise<OperationResult>;
protected formProjection<T extends keyof ED>(entity: T, row: ED[T]['OpSchema'], data: ED[T]['Selection']['data'], result: Partial<ED[T]['Schema']>, nodeDict: NodeDict, context: Context<ED>): Promise<void>;
protected formProjection<T extends keyof ED>(entity: T, row: Partial<ED[T]['OpSchema']>, data: ED[T]['Selection']['data'], result: Partial<ED[T]['Schema']>, nodeDict: NodeDict, context: Context<ED>): Promise<void>;
private formResult;
select<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: Context<ED>, params?: Object): Promise<SelectionResult<ED, T>>;
count<T extends keyof ED>(entity: T, selection: Omit<ED[T]['Selection'], "action" | "data" | "sorter">, context: Context<ED>, params?: Object): Promise<number>;

View File

@ -618,26 +618,32 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}
async updateAbjointRow(entity, operation, context, params) {
const { data, action } = operation;
const now = Date.now();
switch (action) {
case 'create': {
const { id } = data;
const row = (0, lodash_1.get)(this.store, `${entity}.${id}`);
if (row) {
throw new OakError_1.OakError(RowStore_1.RowStore.$$LEVEL, RowStore_1.RowStore.$$CODES.primaryKeyConfilict);
}
const node = {
const node = (this.store[entity])[id];
const row = node && this.constructRow(node, context) || {};
/* if (row) {
throw new OakError(RowStore.$$LEVEL, RowStore.$$CODES.primaryKeyConfilict);
} */
const data2 = (0, lodash_1.assign)(row, data, {
$$createAt$$: data.$$createAt$$ || now,
$$updateAt$$: data.$$updateAt$$ || now,
});
const node2 = {
$uuid: context.uuid,
$current: null,
$next: data,
$next: data2,
$path: `${entity}.${id}`,
};
(0, lodash_1.set)(this.store, `${entity}.${id}`, node);
this.addToTxnNode(node, context, 'create');
(0, lodash_1.set)(this.store, `${entity}.${id}`, node2);
this.addToTxnNode(node2, context, 'create');
if (!params || !params.notCollect) {
context.opRecords.push({
a: 'c',
e: entity,
d: data,
d: data2,
});
}
break;
@ -668,13 +674,17 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}
}
else {
node.$next = data;
const row = node && this.constructRow(node, context) || {};
const data2 = (0, lodash_1.assign)(row, data, {
$$updateAt$$: data.$$updateAt$$ || now,
});
node.$next = data2;
this.addToTxnNode(node, context, 'update');
if (!params || !params.notCollect) {
context.opRecords.push({
a: 'u',
e: entity,
d: data,
d: data2,
f: operation.filter,
});
}
@ -915,6 +925,46 @@ class TreeStore extends CascadeStore_1.CascadeStore {
}, context, {
notCollect: true,
});
break;
}
case 'u': {
const { e, d, f } = record;
await this.doOperation(e, {
action: 'update',
data: d,
filter: f,
}, context, {
notCollect: true,
});
break;
}
case 'r': {
const { e, f } = record;
await this.doOperation(e, {
action: 'remove',
data: {},
filter: f,
}, context, {
notCollect: true,
});
break;
}
case 's': {
const { d } = record;
for (const entity in d) {
for (const id in d[entity]) {
await this.doOperation(entity, {
action: 'create',
data: d[entity][id],
}, context, {
notCollect: true,
});
}
}
break;
}
default: {
(0, assert_1.default)(false);
}
}
}

View File

@ -1,6 +1,6 @@
import { assign, cloneDeep, get, last, set, unset } from 'lodash';
import assert from 'assert';
import { EntityDef, SelectionResult, DeduceCreateSingleOperation, DeduceFilter, DeduceSelection, EntityShape, DeduceRemoveOperation, DeduceUpdateOperation, DeduceSorter, DeduceSorterAttr, OperationResult, OperateParams, OpRecord } from "oak-domain/lib/types/Entity";
import { EntityDef, SelectionResult, DeduceCreateSingleOperation, DeduceFilter, DeduceSelection, EntityShape, DeduceRemoveOperation, DeduceUpdateOperation, DeduceSorter, DeduceSorterAttr, OperationResult, OperateParams, OpRecord, DeduceCreateOperationData, DeduceUpdateOperationData, UpdateOpResult, RemoveOpResult, SelectOpResult } from "oak-domain/lib/types/Entity";
import { ExpressionKey, EXPRESSION_PREFIX, NodeId, RefAttr } from 'oak-domain/lib/types/Demand';
import { CascadeStore } from 'oak-domain/lib/schema/CascadeStore';
import { StorageSchema } from 'oak-domain/lib/types/Storage';
@ -260,7 +260,7 @@ export default class TreeStore<ED extends {
private translateExpression<T extends keyof ED>(
entity: T,
expression: Expression<keyof ED[T]['Schema']>,
context: Context<ED>): (row: ED[T]['OpSchema'], nodeDict: NodeDict) => Promise<ExpressionConstant | ExprLaterCheckFn> {
context: Context<ED>): (row: Partial<ED[T]['OpSchema']>, nodeDict: NodeDict) => Promise<ExpressionConstant | ExprLaterCheckFn> {
const expr = this.translateExpressionNode(entity, expression, context);
return async (row, nodeDict) => {
@ -767,26 +767,32 @@ export default class TreeStore<ED extends {
params?: OperateParams): Promise<void> {
const { data, action } = operation;
const now = Date.now();
switch (action) {
case 'create': {
const { id } = data as DeduceCreateSingleOperation<ED[T]['Schema']>['data'];
const row = get(this.store, `${entity}.${id!}`);
if (row) {
const { id } = data as DeduceCreateOperationData<ED[T]["Schema"]>;
const node = (this.store[entity]!)[id as string];
const row = node && this.constructRow(node, context) || {};
/* if (row) {
throw new OakError(RowStore.$$LEVEL, RowStore.$$CODES.primaryKeyConfilict);
}
const node: RowNode = {
} */
const data2 = assign(row, data as DeduceCreateOperationData<ED[T]["Schema"]>, {
$$createAt$$: data.$$createAt$$ || now,
$$updateAt$$: data.$$updateAt$$ || now,
});
const node2: RowNode = {
$uuid: context.uuid!,
$current: null,
$next: data as DeduceCreateSingleOperation<ED[T]['Schema']>['data'],
$next: data2,
$path: `${entity}.${id!}`,
};
set(this.store, `${entity}.${id!}`, node);
this.addToTxnNode(node, context, 'create');
set(this.store, `${entity}.${id!}`, node2);
this.addToTxnNode(node2, context, 'create');
if (!params || !params.notCollect) {
context.opRecords.push({
a: 'c',
e: entity,
d: data,
d: data2,
});
}
break;
@ -819,13 +825,17 @@ export default class TreeStore<ED extends {
}
}
else {
node.$next = data as EntityShape;
const row = node && this.constructRow(node, context) || {};
const data2 = assign(row, data as DeduceUpdateOperationData<ED[T]['Schema']>, {
$$updateAt$$: data.$$updateAt$$ || now,
});
node.$next = data2;
this.addToTxnNode(node, context, 'update');
if (!params || !params.notCollect) {
context.opRecords.push({
a: 'u',
e: entity,
d: data,
d: data2,
f: (operation as DeduceUpdateOperation<ED[T]['Schema']>).filter,
});
}
@ -875,7 +885,7 @@ export default class TreeStore<ED extends {
protected async formProjection<T extends keyof ED>(
entity: T,
row: ED[T]['OpSchema'],
row: Partial<ED[T]['OpSchema']>,
data: ED[T]['Selection']['data'],
result: Partial<ED[T]['Schema']>,
nodeDict: NodeDict,
@ -959,7 +969,7 @@ export default class TreeStore<ED extends {
private async formResult<T extends keyof ED>(
entity: T,
rows: Array<ED[T]['OpSchema']>,
rows: Array<Partial<ED[T]['Schema']>>,
selection: Omit<ED[T]['Selection'], 'filter'>,
context: Context<ED>,
nodeDict?: NodeDict) {
@ -1098,10 +1108,50 @@ export default class TreeStore<ED extends {
const { e, d } = record;
await this.doOperation(e, {
action: 'create',
data: d as ED[keyof ED]['Schema'] & { id: string },
data: d,
}, context, {
notCollect: true,
});
break;
}
case 'u': {
const { e, d, f } = record as UpdateOpResult<ED, keyof ED>;
await this.doOperation(e, {
action: 'update',
data: d,
filter: f,
}, context, {
notCollect: true,
});
break;
}
case 'r': {
const { e, f } = record as RemoveOpResult<ED, keyof ED>;
await this.doOperation(e, {
action: 'remove',
data: {},
filter: f,
}, context, {
notCollect: true,
});
break;
}
case 's': {
const { d } = record as SelectOpResult<ED>;
for (const entity in d) {
for (const id in d[entity]) {
await this.doOperation(entity, {
action: 'create',
data: d[entity]![id],
}, context, {
notCollect: true,
});
}
}
break;
}
default: {
assert(false);
}
}
}

View File

@ -5,6 +5,7 @@ import { EntityDict } from './app-domain/EntityDict';
import { Context } from '../src/context';
import { storageSchema } from './app-domain/Storage';
import assert from 'assert';
import { CreateSingleOperation } from './app-domain/System/Schema';
describe('基础测试', function () {
this.timeout(1000000);
@ -26,8 +27,8 @@ describe('基础测试', function () {
name: 'systest',
description: 'aaaaa',
config: {},
}
}
} as CreateSingleOperation['data']
},
}, {
id: 'aaa2',
name: 'test2',