@ocap/statedb 1.28.9 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/esm/db.d.mts +28 -0
- package/esm/db.mjs +32 -0
- package/esm/index.d.mts +3 -0
- package/esm/index.mjs +4 -0
- package/esm/table.d.mts +38 -0
- package/esm/table.mjs +117 -0
- package/lib/_virtual/rolldown_runtime.cjs +29 -0
- package/lib/db.cjs +34 -0
- package/lib/db.d.cts +28 -0
- package/lib/index.cjs +5 -0
- package/lib/index.d.cts +3 -0
- package/lib/table.cjs +123 -0
- package/lib/table.d.cts +38 -0
- package/package.json +31 -7
- package/lib/db.d.ts +0 -19
- package/lib/db.js +0 -30
- package/lib/index.js +0 -4
- package/lib/table.d.ts +0 -27
- package/lib/table.js +0 -134
package/README.md
CHANGED
package/esm/db.d.mts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
2
|
+
|
|
3
|
+
//#region src/db.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* StateDB 基类
|
|
7
|
+
* 提供状态数据库的基础功能,子类需要实现具体的表
|
|
8
|
+
*/
|
|
9
|
+
declare class StateDB extends Ready {
|
|
10
|
+
/** 数据库名称 */
|
|
11
|
+
name: string;
|
|
12
|
+
/** 数据库版本 */
|
|
13
|
+
version?: string;
|
|
14
|
+
/** 所有表名列表 */
|
|
15
|
+
tables: readonly string[];
|
|
16
|
+
/** 表就绪标记 */
|
|
17
|
+
readyMarks: Record<string, boolean>;
|
|
18
|
+
/** 是否已附加就绪监听器 */
|
|
19
|
+
readyListenersAttached: boolean;
|
|
20
|
+
constructor();
|
|
21
|
+
/**
|
|
22
|
+
* 附加表就绪监听器
|
|
23
|
+
* 当所有表都就绪时,StateDB 才会标记为就绪
|
|
24
|
+
*/
|
|
25
|
+
attachReadyListeners(): void;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { StateDB as default };
|
package/esm/db.mjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { tables } from "@ocap/state";
|
|
2
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
3
|
+
|
|
4
|
+
//#region src/db.ts
|
|
5
|
+
/**
|
|
6
|
+
* StateDB 基类
|
|
7
|
+
* 提供状态数据库的基础功能,子类需要实现具体的表
|
|
8
|
+
*/
|
|
9
|
+
var StateDB = class extends Ready {
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.tables = tables;
|
|
13
|
+
this.readyMarks = Object.fromEntries(tables.map((x) => [x, false]));
|
|
14
|
+
this.readyListenersAttached = false;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 附加表就绪监听器
|
|
18
|
+
* 当所有表都就绪时,StateDB 才会标记为就绪
|
|
19
|
+
*/
|
|
20
|
+
attachReadyListeners() {
|
|
21
|
+
if (this.readyListenersAttached) return;
|
|
22
|
+
for (const table of tables) {
|
|
23
|
+
if (typeof this[table] === "undefined") throw new Error(`Missing table ${table} in statedb adapter: ${this.name}`);
|
|
24
|
+
this[table].onReady(() => this.markReady(table));
|
|
25
|
+
}
|
|
26
|
+
this.readyListenersAttached = true;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var db_default = StateDB;
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { db_default as default };
|
package/esm/index.d.mts
ADDED
package/esm/index.mjs
ADDED
package/esm/table.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
2
|
+
import { HookFunction, IOperationContext, IStateTable } from "@ocap/types";
|
|
3
|
+
|
|
4
|
+
//#region src/table.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* StateDB 表基类
|
|
8
|
+
* 实现 IStateTable 接口,提供状态管理的基础功能
|
|
9
|
+
*/
|
|
10
|
+
declare class StateDBTable<T = unknown> extends Ready implements IStateTable<T> {
|
|
11
|
+
uniqIndex: string | string[] | undefined;
|
|
12
|
+
primaryKey: string;
|
|
13
|
+
name: string;
|
|
14
|
+
constructor(uniqIndex?: string | string[]);
|
|
15
|
+
pre: (name: string, fn: HookFunction) => void;
|
|
16
|
+
post: (name: string, fn: HookFunction) => void;
|
|
17
|
+
create: (id: string, attrs: Partial<T>, context?: IOperationContext) => Promise<T>;
|
|
18
|
+
get: (id: string, context?: IOperationContext) => Promise<T | null>;
|
|
19
|
+
update: (id: string, updates: Partial<T>, context?: IOperationContext) => Promise<T>;
|
|
20
|
+
history: (id: string, context?: IOperationContext) => Promise<T[]>;
|
|
21
|
+
reset: (context?: IOperationContext) => Promise<void>;
|
|
22
|
+
_create(_id: string, _attrs: Partial<T>, _context?: IOperationContext): Promise<T> | T;
|
|
23
|
+
_get(_id: string, _context?: IOperationContext): Promise<T | null> | T | null;
|
|
24
|
+
_update(_id: string, _updates: Partial<T>, _context?: IOperationContext): Promise<T> | T;
|
|
25
|
+
_reset(_context?: IOperationContext): Promise<void> | void;
|
|
26
|
+
_history(_id: string, _context?: IOperationContext): Promise<T[]> | T[];
|
|
27
|
+
updateOrCreate(_exist: unknown, _state: Partial<T>, _context?: IOperationContext): Promise<T> | T;
|
|
28
|
+
/**
|
|
29
|
+
* Generate an ID composed of multiple primary keys
|
|
30
|
+
*/
|
|
31
|
+
generatePrimaryKey(doc: string | Record<string, unknown>): string;
|
|
32
|
+
/** update cache for context */
|
|
33
|
+
updateCache(data: Record<string, unknown>, context: IOperationContext | null | undefined): void;
|
|
34
|
+
/** get data from cache for context */
|
|
35
|
+
getCache(key: string | Record<string, unknown>, context: IOperationContext): T | null;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { StateDBTable as default };
|
package/esm/table.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { isValid } from "@arcblock/did";
|
|
4
|
+
import { toAddress } from "@ocap/util";
|
|
5
|
+
import Kareem from "kareem";
|
|
6
|
+
import omit from "lodash/omit.js";
|
|
7
|
+
import pick from "lodash/pick.js";
|
|
8
|
+
|
|
9
|
+
//#region src/table.ts
|
|
10
|
+
/**
|
|
11
|
+
* StateDB 表基类
|
|
12
|
+
* 实现 IStateTable 接口,提供状态管理的基础功能
|
|
13
|
+
*/
|
|
14
|
+
var StateDBTable = class extends Ready {
|
|
15
|
+
constructor(uniqIndex) {
|
|
16
|
+
super();
|
|
17
|
+
this.name = "";
|
|
18
|
+
this.uniqIndex = uniqIndex;
|
|
19
|
+
this.primaryKey = typeof uniqIndex === "string" ? uniqIndex : "id";
|
|
20
|
+
const hooks = new Kareem();
|
|
21
|
+
Object.defineProperty(this, "pre", { value: (name, fn) => hooks.pre(name, fn) });
|
|
22
|
+
Object.defineProperty(this, "post", { value: (name, fn) => hooks.post(name, fn) });
|
|
23
|
+
[
|
|
24
|
+
"create",
|
|
25
|
+
"get",
|
|
26
|
+
"history",
|
|
27
|
+
"update",
|
|
28
|
+
"reset"
|
|
29
|
+
].forEach((x) => {
|
|
30
|
+
Object.defineProperty(this, x, { value: async (...args) => {
|
|
31
|
+
if (typeof args[0] === "string" && isValid(args[0])) args[0] = toAddress(args[0]);
|
|
32
|
+
hooks.execPreSync(x, args);
|
|
33
|
+
const result = await this[`_${x}`](...args);
|
|
34
|
+
hooks.execPostSync(x, result);
|
|
35
|
+
if ([
|
|
36
|
+
"create",
|
|
37
|
+
"update",
|
|
38
|
+
"reset"
|
|
39
|
+
].includes(x)) {
|
|
40
|
+
const ctx = args.slice(-1).pop();
|
|
41
|
+
if (ctx?.tx) {
|
|
42
|
+
const events = ctx.events || [];
|
|
43
|
+
events.push({
|
|
44
|
+
table: this.name,
|
|
45
|
+
name: x,
|
|
46
|
+
data: omit(result, "$loki"),
|
|
47
|
+
ctx: pick(ctx, Object.keys(ctx).filter((k) => [
|
|
48
|
+
"events",
|
|
49
|
+
"states",
|
|
50
|
+
"statedb"
|
|
51
|
+
].includes(k) === false))
|
|
52
|
+
});
|
|
53
|
+
ctx.events = events;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (result) {
|
|
57
|
+
if (!result._retrievedAt) Object.defineProperty(result, "_retrievedAt", {
|
|
58
|
+
value: process.hrtime.bigint(),
|
|
59
|
+
enumerable: false,
|
|
60
|
+
writable: true,
|
|
61
|
+
configurable: true
|
|
62
|
+
});
|
|
63
|
+
else if (["create", "update"].includes(x)) result._retrievedAt = process.hrtime.bigint();
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
} });
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
_create(_id, _attrs, _context) {
|
|
70
|
+
throw new Error("`_create` must be implemented in sub statedb");
|
|
71
|
+
}
|
|
72
|
+
_get(_id, _context) {
|
|
73
|
+
throw new Error("`_get` must be implemented in sub statedb");
|
|
74
|
+
}
|
|
75
|
+
_update(_id, _updates, _context) {
|
|
76
|
+
throw new Error("`_update` must be implemented in sub statedb");
|
|
77
|
+
}
|
|
78
|
+
_reset(_context) {
|
|
79
|
+
throw new Error("`_reset` must be implemented in sub statedb");
|
|
80
|
+
}
|
|
81
|
+
_history(_id, _context) {
|
|
82
|
+
throw new Error("`_history` must be implemented in sub statedb");
|
|
83
|
+
}
|
|
84
|
+
updateOrCreate(_exist, _state, _context) {
|
|
85
|
+
throw new Error("`updateOrCreate` must be implemented in sub statedb");
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Generate an ID composed of multiple primary keys
|
|
89
|
+
*/
|
|
90
|
+
generatePrimaryKey(doc) {
|
|
91
|
+
if (typeof doc === "string") return doc;
|
|
92
|
+
if (Array.isArray(this.uniqIndex)) {
|
|
93
|
+
const key = this.uniqIndex.map((id) => doc[id]).map((item) => typeof item === "object" ? JSON.stringify(item) : item).join("-");
|
|
94
|
+
return crypto.createHash("md5").update(key).digest("hex");
|
|
95
|
+
}
|
|
96
|
+
return doc[this.uniqIndex];
|
|
97
|
+
}
|
|
98
|
+
/** update cache for context */
|
|
99
|
+
updateCache(data, context) {
|
|
100
|
+
if (!context) return;
|
|
101
|
+
const cacheStates = context.cacheStates || {};
|
|
102
|
+
if (!cacheStates[this.name]) cacheStates[this.name] = {};
|
|
103
|
+
const cacheKey = this.generatePrimaryKey(data);
|
|
104
|
+
cacheStates[this.name][cacheKey] = data;
|
|
105
|
+
context.cacheStates = cacheStates;
|
|
106
|
+
}
|
|
107
|
+
/** get data from cache for context */
|
|
108
|
+
getCache(key, context) {
|
|
109
|
+
const cacheStates = context.cacheStates || {};
|
|
110
|
+
const cacheKey = this.generatePrimaryKey(key);
|
|
111
|
+
return cacheStates[this.name]?.[cacheKey] || null;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var table_default = StateDBTable;
|
|
115
|
+
|
|
116
|
+
//#endregion
|
|
117
|
+
export { table_default as default };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
|
|
29
|
+
exports.__toESM = __toESM;
|
package/lib/db.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
let _ocap_state = require("@ocap/state");
|
|
4
|
+
let _ocap_util_lib_ready = require("@ocap/util/lib/ready");
|
|
5
|
+
|
|
6
|
+
//#region src/db.ts
|
|
7
|
+
/**
|
|
8
|
+
* StateDB 基类
|
|
9
|
+
* 提供状态数据库的基础功能,子类需要实现具体的表
|
|
10
|
+
*/
|
|
11
|
+
var StateDB = class extends _ocap_util_lib_ready.Ready {
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.tables = _ocap_state.tables;
|
|
15
|
+
this.readyMarks = Object.fromEntries(_ocap_state.tables.map((x) => [x, false]));
|
|
16
|
+
this.readyListenersAttached = false;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 附加表就绪监听器
|
|
20
|
+
* 当所有表都就绪时,StateDB 才会标记为就绪
|
|
21
|
+
*/
|
|
22
|
+
attachReadyListeners() {
|
|
23
|
+
if (this.readyListenersAttached) return;
|
|
24
|
+
for (const table of _ocap_state.tables) {
|
|
25
|
+
if (typeof this[table] === "undefined") throw new Error(`Missing table ${table} in statedb adapter: ${this.name}`);
|
|
26
|
+
this[table].onReady(() => this.markReady(table));
|
|
27
|
+
}
|
|
28
|
+
this.readyListenersAttached = true;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var db_default = StateDB;
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
exports.default = db_default;
|
package/lib/db.d.cts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
2
|
+
|
|
3
|
+
//#region src/db.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* StateDB 基类
|
|
7
|
+
* 提供状态数据库的基础功能,子类需要实现具体的表
|
|
8
|
+
*/
|
|
9
|
+
declare class StateDB extends Ready {
|
|
10
|
+
/** 数据库名称 */
|
|
11
|
+
name: string;
|
|
12
|
+
/** 数据库版本 */
|
|
13
|
+
version?: string;
|
|
14
|
+
/** 所有表名列表 */
|
|
15
|
+
tables: readonly string[];
|
|
16
|
+
/** 表就绪标记 */
|
|
17
|
+
readyMarks: Record<string, boolean>;
|
|
18
|
+
/** 是否已附加就绪监听器 */
|
|
19
|
+
readyListenersAttached: boolean;
|
|
20
|
+
constructor();
|
|
21
|
+
/**
|
|
22
|
+
* 附加表就绪监听器
|
|
23
|
+
* 当所有表都就绪时,StateDB 才会标记为就绪
|
|
24
|
+
*/
|
|
25
|
+
attachReadyListeners(): void;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { StateDB as default };
|
package/lib/index.cjs
ADDED
package/lib/index.d.cts
ADDED
package/lib/table.cjs
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
let _ocap_util_lib_ready = require("@ocap/util/lib/ready");
|
|
4
|
+
let node_crypto = require("node:crypto");
|
|
5
|
+
node_crypto = require_rolldown_runtime.__toESM(node_crypto);
|
|
6
|
+
let _arcblock_did = require("@arcblock/did");
|
|
7
|
+
let _ocap_util = require("@ocap/util");
|
|
8
|
+
let kareem = require("kareem");
|
|
9
|
+
kareem = require_rolldown_runtime.__toESM(kareem);
|
|
10
|
+
let lodash_omit = require("lodash/omit");
|
|
11
|
+
lodash_omit = require_rolldown_runtime.__toESM(lodash_omit);
|
|
12
|
+
let lodash_pick = require("lodash/pick");
|
|
13
|
+
lodash_pick = require_rolldown_runtime.__toESM(lodash_pick);
|
|
14
|
+
|
|
15
|
+
//#region src/table.ts
|
|
16
|
+
/**
|
|
17
|
+
* StateDB 表基类
|
|
18
|
+
* 实现 IStateTable 接口,提供状态管理的基础功能
|
|
19
|
+
*/
|
|
20
|
+
var StateDBTable = class extends _ocap_util_lib_ready.Ready {
|
|
21
|
+
constructor(uniqIndex) {
|
|
22
|
+
super();
|
|
23
|
+
this.name = "";
|
|
24
|
+
this.uniqIndex = uniqIndex;
|
|
25
|
+
this.primaryKey = typeof uniqIndex === "string" ? uniqIndex : "id";
|
|
26
|
+
const hooks = new kareem.default();
|
|
27
|
+
Object.defineProperty(this, "pre", { value: (name, fn) => hooks.pre(name, fn) });
|
|
28
|
+
Object.defineProperty(this, "post", { value: (name, fn) => hooks.post(name, fn) });
|
|
29
|
+
[
|
|
30
|
+
"create",
|
|
31
|
+
"get",
|
|
32
|
+
"history",
|
|
33
|
+
"update",
|
|
34
|
+
"reset"
|
|
35
|
+
].forEach((x) => {
|
|
36
|
+
Object.defineProperty(this, x, { value: async (...args) => {
|
|
37
|
+
if (typeof args[0] === "string" && (0, _arcblock_did.isValid)(args[0])) args[0] = (0, _ocap_util.toAddress)(args[0]);
|
|
38
|
+
hooks.execPreSync(x, args);
|
|
39
|
+
const result = await this[`_${x}`](...args);
|
|
40
|
+
hooks.execPostSync(x, result);
|
|
41
|
+
if ([
|
|
42
|
+
"create",
|
|
43
|
+
"update",
|
|
44
|
+
"reset"
|
|
45
|
+
].includes(x)) {
|
|
46
|
+
const ctx = args.slice(-1).pop();
|
|
47
|
+
if (ctx?.tx) {
|
|
48
|
+
const events = ctx.events || [];
|
|
49
|
+
events.push({
|
|
50
|
+
table: this.name,
|
|
51
|
+
name: x,
|
|
52
|
+
data: (0, lodash_omit.default)(result, "$loki"),
|
|
53
|
+
ctx: (0, lodash_pick.default)(ctx, Object.keys(ctx).filter((k) => [
|
|
54
|
+
"events",
|
|
55
|
+
"states",
|
|
56
|
+
"statedb"
|
|
57
|
+
].includes(k) === false))
|
|
58
|
+
});
|
|
59
|
+
ctx.events = events;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (result) {
|
|
63
|
+
if (!result._retrievedAt) Object.defineProperty(result, "_retrievedAt", {
|
|
64
|
+
value: process.hrtime.bigint(),
|
|
65
|
+
enumerable: false,
|
|
66
|
+
writable: true,
|
|
67
|
+
configurable: true
|
|
68
|
+
});
|
|
69
|
+
else if (["create", "update"].includes(x)) result._retrievedAt = process.hrtime.bigint();
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
} });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
_create(_id, _attrs, _context) {
|
|
76
|
+
throw new Error("`_create` must be implemented in sub statedb");
|
|
77
|
+
}
|
|
78
|
+
_get(_id, _context) {
|
|
79
|
+
throw new Error("`_get` must be implemented in sub statedb");
|
|
80
|
+
}
|
|
81
|
+
_update(_id, _updates, _context) {
|
|
82
|
+
throw new Error("`_update` must be implemented in sub statedb");
|
|
83
|
+
}
|
|
84
|
+
_reset(_context) {
|
|
85
|
+
throw new Error("`_reset` must be implemented in sub statedb");
|
|
86
|
+
}
|
|
87
|
+
_history(_id, _context) {
|
|
88
|
+
throw new Error("`_history` must be implemented in sub statedb");
|
|
89
|
+
}
|
|
90
|
+
updateOrCreate(_exist, _state, _context) {
|
|
91
|
+
throw new Error("`updateOrCreate` must be implemented in sub statedb");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Generate an ID composed of multiple primary keys
|
|
95
|
+
*/
|
|
96
|
+
generatePrimaryKey(doc) {
|
|
97
|
+
if (typeof doc === "string") return doc;
|
|
98
|
+
if (Array.isArray(this.uniqIndex)) {
|
|
99
|
+
const key = this.uniqIndex.map((id) => doc[id]).map((item) => typeof item === "object" ? JSON.stringify(item) : item).join("-");
|
|
100
|
+
return node_crypto.default.createHash("md5").update(key).digest("hex");
|
|
101
|
+
}
|
|
102
|
+
return doc[this.uniqIndex];
|
|
103
|
+
}
|
|
104
|
+
/** update cache for context */
|
|
105
|
+
updateCache(data, context) {
|
|
106
|
+
if (!context) return;
|
|
107
|
+
const cacheStates = context.cacheStates || {};
|
|
108
|
+
if (!cacheStates[this.name]) cacheStates[this.name] = {};
|
|
109
|
+
const cacheKey = this.generatePrimaryKey(data);
|
|
110
|
+
cacheStates[this.name][cacheKey] = data;
|
|
111
|
+
context.cacheStates = cacheStates;
|
|
112
|
+
}
|
|
113
|
+
/** get data from cache for context */
|
|
114
|
+
getCache(key, context) {
|
|
115
|
+
const cacheStates = context.cacheStates || {};
|
|
116
|
+
const cacheKey = this.generatePrimaryKey(key);
|
|
117
|
+
return cacheStates[this.name]?.[cacheKey] || null;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var table_default = StateDBTable;
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
exports.default = table_default;
|
package/lib/table.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Ready } from "@ocap/util/lib/ready";
|
|
2
|
+
import { HookFunction, IOperationContext, IStateTable } from "@ocap/types";
|
|
3
|
+
|
|
4
|
+
//#region src/table.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* StateDB 表基类
|
|
8
|
+
* 实现 IStateTable 接口,提供状态管理的基础功能
|
|
9
|
+
*/
|
|
10
|
+
declare class StateDBTable<T = unknown> extends Ready implements IStateTable<T> {
|
|
11
|
+
uniqIndex: string | string[] | undefined;
|
|
12
|
+
primaryKey: string;
|
|
13
|
+
name: string;
|
|
14
|
+
constructor(uniqIndex?: string | string[]);
|
|
15
|
+
pre: (name: string, fn: HookFunction) => void;
|
|
16
|
+
post: (name: string, fn: HookFunction) => void;
|
|
17
|
+
create: (id: string, attrs: Partial<T>, context?: IOperationContext) => Promise<T>;
|
|
18
|
+
get: (id: string, context?: IOperationContext) => Promise<T | null>;
|
|
19
|
+
update: (id: string, updates: Partial<T>, context?: IOperationContext) => Promise<T>;
|
|
20
|
+
history: (id: string, context?: IOperationContext) => Promise<T[]>;
|
|
21
|
+
reset: (context?: IOperationContext) => Promise<void>;
|
|
22
|
+
_create(_id: string, _attrs: Partial<T>, _context?: IOperationContext): Promise<T> | T;
|
|
23
|
+
_get(_id: string, _context?: IOperationContext): Promise<T | null> | T | null;
|
|
24
|
+
_update(_id: string, _updates: Partial<T>, _context?: IOperationContext): Promise<T> | T;
|
|
25
|
+
_reset(_context?: IOperationContext): Promise<void> | void;
|
|
26
|
+
_history(_id: string, _context?: IOperationContext): Promise<T[]> | T[];
|
|
27
|
+
updateOrCreate(_exist: unknown, _state: Partial<T>, _context?: IOperationContext): Promise<T> | T;
|
|
28
|
+
/**
|
|
29
|
+
* Generate an ID composed of multiple primary keys
|
|
30
|
+
*/
|
|
31
|
+
generatePrimaryKey(doc: string | Record<string, unknown>): string;
|
|
32
|
+
/** update cache for context */
|
|
33
|
+
updateCache(data: Record<string, unknown>, context: IOperationContext | null | undefined): void;
|
|
34
|
+
/** get data from cache for context */
|
|
35
|
+
getCache(key: string | Record<string, unknown>, context: IOperationContext): T | null;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { StateDBTable as default };
|
package/package.json
CHANGED
|
@@ -3,13 +3,36 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.29.0",
|
|
7
7
|
"description": "Defines the basic interface for OCAP StateDB",
|
|
8
|
-
"
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./lib/index.cjs",
|
|
10
|
+
"module": "./esm/index.mjs",
|
|
11
|
+
"types": "./esm/index.d.mts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./esm/index.d.mts",
|
|
15
|
+
"import": "./esm/index.mjs",
|
|
16
|
+
"default": "./lib/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./lib/*.js": {
|
|
19
|
+
"types": "./esm/*.d.mts",
|
|
20
|
+
"import": "./esm/*.mjs",
|
|
21
|
+
"default": "./lib/*.cjs"
|
|
22
|
+
},
|
|
23
|
+
"./lib/*": {
|
|
24
|
+
"types": "./esm/*.d.mts",
|
|
25
|
+
"import": "./esm/*.mjs",
|
|
26
|
+
"default": "./lib/*.cjs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
9
29
|
"files": [
|
|
10
|
-
"lib"
|
|
30
|
+
"lib",
|
|
31
|
+
"esm"
|
|
11
32
|
],
|
|
12
33
|
"scripts": {
|
|
34
|
+
"build": "tsdown",
|
|
35
|
+
"prebuild": "rm -rf lib esm",
|
|
13
36
|
"lint": "biome check",
|
|
14
37
|
"lint:fix": "biome check --write",
|
|
15
38
|
"test": "bun test",
|
|
@@ -20,10 +43,11 @@
|
|
|
20
43
|
"license": "MIT",
|
|
21
44
|
"devDependencies": {},
|
|
22
45
|
"dependencies": {
|
|
23
|
-
"@arcblock/did": "1.
|
|
24
|
-
"@ocap/state": "1.
|
|
25
|
-
"@ocap/
|
|
46
|
+
"@arcblock/did": "1.29.0",
|
|
47
|
+
"@ocap/state": "1.29.0",
|
|
48
|
+
"@ocap/types": "1.29.0",
|
|
49
|
+
"@ocap/util": "1.29.0",
|
|
26
50
|
"kareem": "^2.4.1",
|
|
27
|
-
"lodash": "^4.17.
|
|
51
|
+
"lodash": "^4.17.23"
|
|
28
52
|
}
|
|
29
53
|
}
|
package/lib/db.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// Generate by [js2dts@0.3.3](https://github.com/whxaxes/js2dts#readme)
|
|
2
|
-
|
|
3
|
-
declare class Ready {
|
|
4
|
-
emit: any;
|
|
5
|
-
ready: any;
|
|
6
|
-
readyCallbacks: any;
|
|
7
|
-
readyMarks: any;
|
|
8
|
-
constructor();
|
|
9
|
-
markReady(mark?: any): void;
|
|
10
|
-
onReady(cb: any): void;
|
|
11
|
-
}
|
|
12
|
-
declare class StateDB extends Ready {
|
|
13
|
-
readyMarks: any;
|
|
14
|
-
readyListenersAttached: boolean;
|
|
15
|
-
constructor();
|
|
16
|
-
attachReadyListeners(): void;
|
|
17
|
-
}
|
|
18
|
-
declare const _Db: typeof StateDB;
|
|
19
|
-
export = _Db;
|
package/lib/db.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const { Ready } = require('@ocap/util/lib/ready');
|
|
2
|
-
const { tables } = require('@ocap/state');
|
|
3
|
-
|
|
4
|
-
class StateDB extends Ready {
|
|
5
|
-
constructor() {
|
|
6
|
-
super();
|
|
7
|
-
|
|
8
|
-
this.tables = tables;
|
|
9
|
-
this.readyMarks = Object.fromEntries(tables.map((x) => [x, false]));
|
|
10
|
-
this.readyListenersAttached = false;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
attachReadyListeners() {
|
|
14
|
-
if (this.readyListenersAttached) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
for (const table of tables) {
|
|
19
|
-
if (typeof this[table] === 'undefined') {
|
|
20
|
-
throw new Error(`Missing table ${table} in statedb adapter: ${this.name}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
this[table].onReady(() => this.markReady(table));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
this.readyListenersAttached = true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
module.exports = StateDB;
|
package/lib/index.js
DELETED
package/lib/table.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
type Promisable<T> = T | Promise<T>;
|
|
2
|
-
|
|
3
|
-
declare class Ready {
|
|
4
|
-
emit: any;
|
|
5
|
-
ready: any;
|
|
6
|
-
readyCallbacks: any;
|
|
7
|
-
readyMarks: any;
|
|
8
|
-
constructor();
|
|
9
|
-
markReady(mark?: any): void;
|
|
10
|
-
onReady(cb: any): void;
|
|
11
|
-
}
|
|
12
|
-
declare class StateDBTable extends Ready {
|
|
13
|
-
protected _create(id: string, attrs: any, context?: any): Promisable<any>;
|
|
14
|
-
protected _get(id: string, context?: any): Promisable<any>;
|
|
15
|
-
protected _update(id: string, updates: any, context?: any): Promisable<any>;
|
|
16
|
-
protected _history(id: string, context?: any): Promisable<any>;
|
|
17
|
-
protected _reset(context?: any): Promisable<void>;
|
|
18
|
-
|
|
19
|
-
public create(id: string, attrs: any, context?: any): Promisable<any>;
|
|
20
|
-
public get(id: string, context?: any): Promisable<any>;
|
|
21
|
-
public update(id: string, updates: any, context?: any): Promisable<any>;
|
|
22
|
-
public history(id: string, context?: any): Promisable<any>;
|
|
23
|
-
public updateOrCreate(id: string, attrs: any, context?: any): Promisable<any>;
|
|
24
|
-
public reset(context?: any): Promisable<void>;
|
|
25
|
-
}
|
|
26
|
-
declare const Table: typeof StateDBTable;
|
|
27
|
-
export = Table;
|
package/lib/table.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
const crypto = require('node:crypto');
|
|
2
|
-
const Kareem = require('kareem');
|
|
3
|
-
const omit = require('lodash/omit');
|
|
4
|
-
const pick = require('lodash/pick');
|
|
5
|
-
const { Ready } = require('@ocap/util/lib/ready');
|
|
6
|
-
const { isValid } = require('@arcblock/did');
|
|
7
|
-
const { toAddress } = require('@ocap/util');
|
|
8
|
-
|
|
9
|
-
class StateDBTable extends Ready {
|
|
10
|
-
constructor(uniqIndex) {
|
|
11
|
-
super();
|
|
12
|
-
|
|
13
|
-
this.uniqIndex = uniqIndex;
|
|
14
|
-
this.primaryKey = typeof uniqIndex === 'string' ? uniqIndex : 'id';
|
|
15
|
-
|
|
16
|
-
const hooks = new Kareem();
|
|
17
|
-
|
|
18
|
-
Object.defineProperty(this, 'pre', { value: (name, fn) => hooks.pre(name, fn) });
|
|
19
|
-
Object.defineProperty(this, 'post', { value: (name, fn) => hooks.post(name, fn) });
|
|
20
|
-
|
|
21
|
-
['create', 'get', 'history', 'update', 'reset'].forEach((x) => {
|
|
22
|
-
Object.defineProperty(this, x, {
|
|
23
|
-
value: async (...args) => {
|
|
24
|
-
// Ensure the storage layer omits the `did:abt` prefix
|
|
25
|
-
if (typeof args[0] === 'string' && isValid(args[0])) {
|
|
26
|
-
args[0] = toAddress(args[0]);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
hooks.execPreSync(x, args);
|
|
30
|
-
const result = await this[`_${x}`](...args);
|
|
31
|
-
hooks.execPostSync(x, result);
|
|
32
|
-
|
|
33
|
-
if (['create', 'update', 'reset'].includes(x)) {
|
|
34
|
-
const ctx = args.slice(-1).pop();
|
|
35
|
-
if (ctx?.tx) {
|
|
36
|
-
ctx.events = ctx.events || [];
|
|
37
|
-
ctx.events.push({
|
|
38
|
-
table: this.name,
|
|
39
|
-
name: x,
|
|
40
|
-
data: omit(result, '$loki'),
|
|
41
|
-
ctx: pick(
|
|
42
|
-
ctx,
|
|
43
|
-
Object.keys(ctx).filter((k) => ['events', 'states', 'statedb'].includes(k) === false)
|
|
44
|
-
),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (result) {
|
|
50
|
-
if (!result._retrievedAt) {
|
|
51
|
-
Object.defineProperty(result, '_retrievedAt', {
|
|
52
|
-
value: process.hrtime.bigint(),
|
|
53
|
-
enumerable: false,
|
|
54
|
-
writable: true,
|
|
55
|
-
configurable: true,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
// refresh the retrievedAt time for create and update
|
|
59
|
-
else if (['create', 'update'].includes(x)) {
|
|
60
|
-
result._retrievedAt = process.hrtime.bigint();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return result;
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
_create(_id, _attrs, _context) {
|
|
71
|
-
throw new Error('`_create` must be implemented in sub statedb');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
_get(_id, _context) {
|
|
75
|
-
throw new Error('`_get` must be implemented in sub statedb');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
_update(_id, _updates, _context) {
|
|
79
|
-
throw new Error('`_update` must be implemented in sub statedb');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
_reset(_context) {
|
|
83
|
-
throw new Error('`_reset` must be implemented in sub statedb');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
_history(_id, _context) {
|
|
87
|
-
throw new Error('`_history` must be implemented in sub statedb');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
updateOrCreate(_id, _attrs, _context) {
|
|
91
|
-
throw new Error('`updateOrCreate` must be implemented in sub statedb');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Generate an ID composed of multiple primary keys
|
|
96
|
-
*/
|
|
97
|
-
generatePrimaryKey(doc) {
|
|
98
|
-
if (typeof doc === 'string') {
|
|
99
|
-
return doc;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// composite primary key
|
|
103
|
-
if (Array.isArray(this.uniqIndex)) {
|
|
104
|
-
const key = this.uniqIndex
|
|
105
|
-
.map((id) => doc[id])
|
|
106
|
-
.map((item) => (typeof item === 'object' ? JSON.stringify(item) : item))
|
|
107
|
-
.join('-');
|
|
108
|
-
return crypto.createHash('md5').update(key).digest('hex');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return doc[this.uniqIndex];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** update cache for context */
|
|
115
|
-
updateCache(data, context) {
|
|
116
|
-
if (!context) return;
|
|
117
|
-
if (!context.cacheStates?.[this.name]) {
|
|
118
|
-
context.cacheStates = context.cacheStates || {};
|
|
119
|
-
context.cacheStates[this.name] = {};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const cacheKey = this.generatePrimaryKey(data);
|
|
123
|
-
context.cacheStates[this.name][cacheKey] = data;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** get data from cache for context */
|
|
127
|
-
getCache(key, context) {
|
|
128
|
-
const cacheStates = context.cacheStates || {};
|
|
129
|
-
const cacheKey = this.generatePrimaryKey(key);
|
|
130
|
-
return cacheStates[this.name]?.[cacheKey] || null;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
module.exports = StateDBTable;
|