@ocap/indexdb-sqlite 1.29.5
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 +84 -0
- package/esm/_virtual/rolldown_runtime.mjs +21 -0
- package/esm/db/base.d.mts +76 -0
- package/esm/db/base.mjs +666 -0
- package/esm/db/index.d.mts +80 -0
- package/esm/db/index.mjs +551 -0
- package/esm/index.d.mts +3 -0
- package/esm/index.mjs +8 -0
- package/esm/interfaces.d.mts +328 -0
- package/esm/interfaces.mjs +1 -0
- package/esm/kysely.d.mts +43 -0
- package/esm/kysely.mjs +62 -0
- package/esm/migrations/001-genesis.d.mts +14 -0
- package/esm/migrations/001-genesis.mjs +107 -0
- package/esm/migrations/index.d.mts +16 -0
- package/esm/migrations/index.mjs +44 -0
- package/esm/package.mjs +70 -0
- package/esm/table/base.d.mts +107 -0
- package/esm/table/base.mjs +262 -0
- package/esm/table/transaction.d.mts +18 -0
- package/esm/table/transaction.mjs +22 -0
- package/lib/_virtual/rolldown_runtime.cjs +43 -0
- package/lib/db/base.cjs +670 -0
- package/lib/db/base.d.cts +76 -0
- package/lib/db/index.cjs +552 -0
- package/lib/db/index.d.cts +80 -0
- package/lib/index.cjs +10 -0
- package/lib/index.d.cts +3 -0
- package/lib/interfaces.cjs +0 -0
- package/lib/interfaces.d.cts +328 -0
- package/lib/kysely.cjs +63 -0
- package/lib/kysely.d.cts +43 -0
- package/lib/migrations/001-genesis.cjs +114 -0
- package/lib/migrations/001-genesis.d.cts +14 -0
- package/lib/migrations/index.cjs +46 -0
- package/lib/migrations/index.d.cts +16 -0
- package/lib/package.cjs +76 -0
- package/lib/table/base.cjs +265 -0
- package/lib/table/base.d.cts +107 -0
- package/lib/table/transaction.cjs +24 -0
- package/lib/table/transaction.d.cts +18 -0
- package/package.json +75 -0
package/lib/package.cjs
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
|
|
2
|
+
//#region package.json
|
|
3
|
+
var package_default = {
|
|
4
|
+
name: "@ocap/indexdb-sqlite",
|
|
5
|
+
description: "OCAP indexdb adapter that uses SQLite as backend",
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
author: "wangshijun <shijun@arcblock.io> (https://www.arcblock.io)",
|
|
8
|
+
bugs: {
|
|
9
|
+
"url": "https://github.com/ArcBlock/blockchain/issues",
|
|
10
|
+
"email": "shijun@arcblock.io"
|
|
11
|
+
},
|
|
12
|
+
publishConfig: { "access": "public" },
|
|
13
|
+
contributors: ["wangshijun <shijun@arcblock.io> (https://www.arcblock.io)"],
|
|
14
|
+
devDependencies: { "@ocap/indexdb-test": "workspace:*" },
|
|
15
|
+
homepage: "https://github.com/ArcBlock/blockchain/tree/master/indexdb/sqlite",
|
|
16
|
+
keywords: [
|
|
17
|
+
"ocap",
|
|
18
|
+
"indexdb",
|
|
19
|
+
"sqlite",
|
|
20
|
+
"kysely"
|
|
21
|
+
],
|
|
22
|
+
license: "Apache-2.0",
|
|
23
|
+
type: "module",
|
|
24
|
+
main: "./lib/index.cjs",
|
|
25
|
+
module: "./esm/index.mjs",
|
|
26
|
+
types: "./esm/index.d.mts",
|
|
27
|
+
exports: {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./esm/index.d.mts",
|
|
30
|
+
"import": "./esm/index.mjs",
|
|
31
|
+
"default": "./lib/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"./lib/*.js": {
|
|
34
|
+
"types": "./esm/*.d.mts",
|
|
35
|
+
"import": "./esm/*.mjs",
|
|
36
|
+
"default": "./lib/*.cjs"
|
|
37
|
+
},
|
|
38
|
+
"./lib/*": {
|
|
39
|
+
"types": "./esm/*.d.mts",
|
|
40
|
+
"import": "./esm/*.mjs",
|
|
41
|
+
"default": "./lib/*.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
files: ["lib", "esm"],
|
|
45
|
+
repository: {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/ArcBlock/blockchain/tree/master/indexdb/sqlite"
|
|
48
|
+
},
|
|
49
|
+
scripts: {
|
|
50
|
+
"build": "tsdown",
|
|
51
|
+
"prebuild": "rm -rf lib esm",
|
|
52
|
+
"lint": "biome check",
|
|
53
|
+
"lint:fix": "biome check --write",
|
|
54
|
+
"test": "bun test",
|
|
55
|
+
"coverage": "npm run test -- --coverage"
|
|
56
|
+
},
|
|
57
|
+
dependencies: {
|
|
58
|
+
"@arcblock/did": "workspace:*",
|
|
59
|
+
"@ocap/indexdb": "workspace:*",
|
|
60
|
+
"@ocap/types": "workspace:*",
|
|
61
|
+
"@ocap/util": "workspace:*",
|
|
62
|
+
"debug": "^4.4.3",
|
|
63
|
+
"better-sqlite3": "^11.8.1",
|
|
64
|
+
"kysely": "^0.27.0",
|
|
65
|
+
"kysely-bun-sqlite": "^0.4.0",
|
|
66
|
+
"lodash": "^4.17.23"
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
Object.defineProperty(exports, 'default', {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
get: function () {
|
|
74
|
+
return package_default;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
let node_crypto = require("node:crypto");
|
|
4
|
+
node_crypto = require_rolldown_runtime.__toESM(node_crypto);
|
|
5
|
+
let _ocap_indexdb = require("@ocap/indexdb");
|
|
6
|
+
|
|
7
|
+
//#region src/table/base.ts
|
|
8
|
+
/**
|
|
9
|
+
* SQLite Index Table base class
|
|
10
|
+
* Extends IndexDBTable to provide SQLite-specific implementation
|
|
11
|
+
*/
|
|
12
|
+
var SqliteTable = class extends _ocap_indexdb.BaseIndex {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
super(config.name, config.uniqIndex);
|
|
15
|
+
this.name = config.name;
|
|
16
|
+
this.db = config.db;
|
|
17
|
+
this.schema = config.schema || {};
|
|
18
|
+
this.markReady();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the Kysely executor (use transaction if available)
|
|
22
|
+
*/
|
|
23
|
+
getExecutor(context) {
|
|
24
|
+
return context?.txn || this.db;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate primary key from document
|
|
28
|
+
* Handles both simple string keys and composite keys
|
|
29
|
+
*/
|
|
30
|
+
generatePrimaryKey(doc) {
|
|
31
|
+
if (typeof doc === "string") return doc;
|
|
32
|
+
if (Array.isArray(this.uniqIndex)) {
|
|
33
|
+
const key = this.uniqIndex.map((id) => doc[id]).map((item) => typeof item === "object" ? JSON.stringify(item) : item).join("-");
|
|
34
|
+
return node_crypto.default.createHash("md5").update(key).digest("hex");
|
|
35
|
+
}
|
|
36
|
+
return doc[this.uniqIndex];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Map column name for reserved keywords
|
|
40
|
+
*/
|
|
41
|
+
mapColumnName(name) {
|
|
42
|
+
return this.schema.columnMapping?.[name] ?? name;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Reverse map column name
|
|
46
|
+
*/
|
|
47
|
+
unmapColumnName(name) {
|
|
48
|
+
const mapping = this.schema.columnMapping;
|
|
49
|
+
if (!mapping) return name;
|
|
50
|
+
for (const [original, mapped] of Object.entries(mapping)) if (mapped === name) return original;
|
|
51
|
+
return name;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Serialize data for database insert
|
|
55
|
+
* - Converts objects/arrays to JSON strings
|
|
56
|
+
* - Converts booleans to integers (0/1) for SQLite
|
|
57
|
+
* - Maps column names for reserved keywords
|
|
58
|
+
* - Adds numeric fields for sorting
|
|
59
|
+
* - Stores unknown fields in the 'data' column as JSON
|
|
60
|
+
*/
|
|
61
|
+
serializeForDb(data) {
|
|
62
|
+
const result = {};
|
|
63
|
+
const jsonFields = new Set(this.schema.jsonFields || []);
|
|
64
|
+
const booleanFields = new Set(this.schema.booleanFields || []);
|
|
65
|
+
const numericFields = this.schema.numericFields || {};
|
|
66
|
+
const knownColumns = this.schema.knownColumns ? new Set(this.schema.knownColumns) : null;
|
|
67
|
+
const unknownFields = {};
|
|
68
|
+
for (const [key, value] of Object.entries(data)) {
|
|
69
|
+
const mappedKey = this.mapColumnName(key);
|
|
70
|
+
if (knownColumns && !knownColumns.has(key) && key !== "data") {
|
|
71
|
+
unknownFields[key] = value;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (value === void 0) result[mappedKey] = null;
|
|
75
|
+
else if (booleanFields.has(key) && typeof value === "boolean") result[mappedKey] = value ? 1 : 0;
|
|
76
|
+
else if (jsonFields.has(key) || value !== null && typeof value === "object") result[mappedKey] = JSON.stringify(value);
|
|
77
|
+
else result[mappedKey] = value;
|
|
78
|
+
if (numericFields[key] && value) result[numericFields[key]] = this.toSortableNumeric(String(value));
|
|
79
|
+
}
|
|
80
|
+
if (Object.keys(unknownFields).length > 0) {
|
|
81
|
+
let existingData = {};
|
|
82
|
+
if (result.data && typeof result.data === "string") try {
|
|
83
|
+
existingData = JSON.parse(result.data);
|
|
84
|
+
} catch {
|
|
85
|
+
existingData = {};
|
|
86
|
+
}
|
|
87
|
+
else if (data.data && typeof data.data === "object") existingData = data.data;
|
|
88
|
+
result.data = JSON.stringify({
|
|
89
|
+
...existingData,
|
|
90
|
+
...unknownFields
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Serialize data for database update
|
|
97
|
+
* Preserves unknown fields from existing document's data column
|
|
98
|
+
*/
|
|
99
|
+
serializeForDbUpdate(updates, existing) {
|
|
100
|
+
const result = {};
|
|
101
|
+
const jsonFields = new Set(this.schema.jsonFields || []);
|
|
102
|
+
const booleanFields = new Set(this.schema.booleanFields || []);
|
|
103
|
+
const numericFields = this.schema.numericFields || {};
|
|
104
|
+
const knownColumns = this.schema.knownColumns ? new Set(this.schema.knownColumns) : null;
|
|
105
|
+
const unknownFields = {};
|
|
106
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
107
|
+
const mappedKey = this.mapColumnName(key);
|
|
108
|
+
if (knownColumns && !knownColumns.has(key) && key !== "data") {
|
|
109
|
+
unknownFields[key] = value;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (value === void 0) result[mappedKey] = null;
|
|
113
|
+
else if (booleanFields.has(key) && typeof value === "boolean") result[mappedKey] = value ? 1 : 0;
|
|
114
|
+
else if (jsonFields.has(key) || value !== null && typeof value === "object") result[mappedKey] = JSON.stringify(value);
|
|
115
|
+
else result[mappedKey] = value;
|
|
116
|
+
if (numericFields[key] && value) result[numericFields[key]] = this.toSortableNumeric(String(value));
|
|
117
|
+
}
|
|
118
|
+
if (knownColumns) {
|
|
119
|
+
const existingUnknownFields = {};
|
|
120
|
+
for (const [key, value] of Object.entries(existing)) if (!knownColumns.has(key) && key !== "data") existingUnknownFields[key] = value;
|
|
121
|
+
const mergedUnknownFields = {
|
|
122
|
+
...existingUnknownFields,
|
|
123
|
+
...unknownFields
|
|
124
|
+
};
|
|
125
|
+
if (Object.keys(mergedUnknownFields).length > 0) {
|
|
126
|
+
let baseData = {};
|
|
127
|
+
if (result.data && typeof result.data === "string") try {
|
|
128
|
+
baseData = JSON.parse(result.data);
|
|
129
|
+
} catch {
|
|
130
|
+
baseData = {};
|
|
131
|
+
}
|
|
132
|
+
else if (updates.data && typeof updates.data === "object") baseData = updates.data;
|
|
133
|
+
result.data = JSON.stringify({
|
|
134
|
+
...baseData,
|
|
135
|
+
...mergedUnknownFields
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Convert a big number string to a sortable numeric string
|
|
143
|
+
* Pads with leading zeros to ensure lexicographic sorting works
|
|
144
|
+
*/
|
|
145
|
+
toSortableNumeric(value) {
|
|
146
|
+
return (value.replace(/^0+/, "") || "0").padStart(40, "0");
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Deserialize data from database read
|
|
150
|
+
* - Parses JSON strings back to objects
|
|
151
|
+
* - Converts integers (0/1) back to booleans
|
|
152
|
+
* - Unmaps column names
|
|
153
|
+
* - Extracts unknown fields from 'data' column back to top level
|
|
154
|
+
*/
|
|
155
|
+
deserializeFromDb(data) {
|
|
156
|
+
if (!data) return null;
|
|
157
|
+
const result = {};
|
|
158
|
+
const jsonFields = new Set(this.schema.jsonFields || []);
|
|
159
|
+
const booleanFields = new Set(this.schema.booleanFields || []);
|
|
160
|
+
const numericFieldValues = new Set(Object.values(this.schema.numericFields || {}));
|
|
161
|
+
const knownColumns = this.schema.knownColumns ? new Set(this.schema.knownColumns) : null;
|
|
162
|
+
for (const [key, value] of Object.entries(data)) {
|
|
163
|
+
if (numericFieldValues.has(key)) continue;
|
|
164
|
+
const unmappedKey = this.unmapColumnName(key);
|
|
165
|
+
if (booleanFields.has(unmappedKey) && typeof value === "number") result[unmappedKey] = value === 1;
|
|
166
|
+
else if (jsonFields.has(unmappedKey) && typeof value === "string") try {
|
|
167
|
+
result[unmappedKey] = JSON.parse(value);
|
|
168
|
+
} catch {
|
|
169
|
+
result[unmappedKey] = value;
|
|
170
|
+
}
|
|
171
|
+
else result[unmappedKey] = value;
|
|
172
|
+
}
|
|
173
|
+
if (knownColumns && result.data && typeof result.data === "object") {
|
|
174
|
+
const dataObj = result.data;
|
|
175
|
+
for (const [key, value] of Object.entries(dataObj)) if (!knownColumns.has(key)) result[key] = value;
|
|
176
|
+
}
|
|
177
|
+
delete result.$loki;
|
|
178
|
+
delete result.meta;
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Internal get implementation - called by BaseIndex.get() via hooks
|
|
183
|
+
*/
|
|
184
|
+
async _get(key) {
|
|
185
|
+
if (!key) return null;
|
|
186
|
+
let query;
|
|
187
|
+
if (Array.isArray(this.uniqIndex)) if (typeof key === "object") {
|
|
188
|
+
const keyObj = key;
|
|
189
|
+
query = Object.fromEntries(this.uniqIndex.map((k) => [this.mapColumnName(k), keyObj[k]]));
|
|
190
|
+
} else return null;
|
|
191
|
+
else {
|
|
192
|
+
const id = typeof key === "string" ? key : key[this.primaryKey];
|
|
193
|
+
query = { [this.mapColumnName(this.primaryKey)]: id };
|
|
194
|
+
}
|
|
195
|
+
let qb = this.db.selectFrom(this.name).selectAll();
|
|
196
|
+
for (const [k, v] of Object.entries(query)) {
|
|
197
|
+
if (v === void 0) continue;
|
|
198
|
+
qb = qb.where(k, "=", v);
|
|
199
|
+
}
|
|
200
|
+
const result = await qb.executeTakeFirst();
|
|
201
|
+
return this.deserializeFromDb(result);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Internal insert implementation - called by BaseIndex.insert() via hooks
|
|
205
|
+
*/
|
|
206
|
+
async _insert(doc) {
|
|
207
|
+
const data = doc;
|
|
208
|
+
const serialized = this.serializeForDb(data);
|
|
209
|
+
await this.db.insertInto(this.name).values(serialized).execute();
|
|
210
|
+
return data;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Internal update implementation - called by BaseIndex.update() via hooks
|
|
214
|
+
*/
|
|
215
|
+
async _update(key, updates) {
|
|
216
|
+
const existing = await this._get(key);
|
|
217
|
+
if (!existing) throw new Error(`${this.name} does not exist: ${JSON.stringify(key)}`);
|
|
218
|
+
let query;
|
|
219
|
+
if (Array.isArray(this.uniqIndex)) {
|
|
220
|
+
const keyObj = typeof key === "object" ? key : existing;
|
|
221
|
+
query = Object.fromEntries(this.uniqIndex.map((k) => [this.mapColumnName(k), keyObj[k]]));
|
|
222
|
+
} else {
|
|
223
|
+
const id = typeof key === "string" ? key : key[this.primaryKey];
|
|
224
|
+
query = { [this.mapColumnName(this.primaryKey)]: id };
|
|
225
|
+
}
|
|
226
|
+
const updateAttrs = { ...updates };
|
|
227
|
+
if (Array.isArray(this.uniqIndex)) for (const k of this.uniqIndex) delete updateAttrs[k];
|
|
228
|
+
else delete updateAttrs[this.primaryKey];
|
|
229
|
+
if (Object.keys(updateAttrs).length > 0) {
|
|
230
|
+
const serialized = this.serializeForDbUpdate(updateAttrs, existing);
|
|
231
|
+
let qb = this.db.updateTable(this.name).set(serialized);
|
|
232
|
+
for (const [k, v] of Object.entries(query)) {
|
|
233
|
+
if (v === void 0) continue;
|
|
234
|
+
qb = qb.where(k, "=", v);
|
|
235
|
+
}
|
|
236
|
+
await qb.execute();
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
...existing,
|
|
240
|
+
...updateAttrs
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Count documents matching a query
|
|
245
|
+
*/
|
|
246
|
+
async count(query) {
|
|
247
|
+
let qb = this.db.selectFrom(this.name).select(this.db.fn.countAll().as("count"));
|
|
248
|
+
if (query && typeof query === "object") for (const [k, v] of Object.entries(query)) {
|
|
249
|
+
const mappedKey = this.mapColumnName(k);
|
|
250
|
+
if (v && typeof v === "object" && "$in" in v) qb = qb.where(mappedKey, "in", v.$in);
|
|
251
|
+
else qb = qb.where(mappedKey, "=", v);
|
|
252
|
+
}
|
|
253
|
+
return (await qb.executeTakeFirst())?.count ?? 0;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Internal reset implementation - called by BaseIndex.reset() via hooks
|
|
257
|
+
*/
|
|
258
|
+
async _reset() {
|
|
259
|
+
await this.db.deleteFrom(this.name).execute();
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
var base_default = SqliteTable;
|
|
263
|
+
|
|
264
|
+
//#endregion
|
|
265
|
+
exports.default = base_default;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Database, SqliteOperationContext } from "../interfaces.cjs";
|
|
2
|
+
import { BaseIndex } from "@ocap/indexdb";
|
|
3
|
+
import { IIndexTable } from "@ocap/types";
|
|
4
|
+
import { Kysely, Transaction } from "kysely";
|
|
5
|
+
|
|
6
|
+
//#region src/table/base.d.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Table schema configuration
|
|
10
|
+
*/
|
|
11
|
+
interface TableSchema {
|
|
12
|
+
/** Column names that contain JSON data */
|
|
13
|
+
jsonFields?: string[];
|
|
14
|
+
/** Column names that contain boolean data (stored as integer 0/1 in SQLite) */
|
|
15
|
+
booleanFields?: string[];
|
|
16
|
+
/** Column name mapping (e.g., 'from' -> 'from_' for reserved keywords) */
|
|
17
|
+
columnMapping?: Record<string, string>;
|
|
18
|
+
/** Numeric column mapping (field name -> numeric field name for sorting) */
|
|
19
|
+
numericFields?: Record<string, string>;
|
|
20
|
+
/** Known column names for this table (used to filter unknown fields) */
|
|
21
|
+
knownColumns?: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Table configuration
|
|
25
|
+
*/
|
|
26
|
+
interface SqliteTableConfig {
|
|
27
|
+
name: string;
|
|
28
|
+
uniqIndex: string | string[];
|
|
29
|
+
db: Kysely<Database>;
|
|
30
|
+
schema?: TableSchema;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* SQLite Index Table base class
|
|
34
|
+
* Extends IndexDBTable to provide SQLite-specific implementation
|
|
35
|
+
*/
|
|
36
|
+
declare class SqliteTable<T = unknown> extends BaseIndex<T> implements IIndexTable<T> {
|
|
37
|
+
name: string;
|
|
38
|
+
db: Kysely<Database>;
|
|
39
|
+
schema: TableSchema;
|
|
40
|
+
constructor(config: SqliteTableConfig);
|
|
41
|
+
/**
|
|
42
|
+
* Get the Kysely executor (use transaction if available)
|
|
43
|
+
*/
|
|
44
|
+
protected getExecutor(context?: SqliteOperationContext): Kysely<Database> | Transaction<Database>;
|
|
45
|
+
/**
|
|
46
|
+
* Generate primary key from document
|
|
47
|
+
* Handles both simple string keys and composite keys
|
|
48
|
+
*/
|
|
49
|
+
generatePrimaryKey(doc: string | Record<string, unknown>): string;
|
|
50
|
+
/**
|
|
51
|
+
* Map column name for reserved keywords
|
|
52
|
+
*/
|
|
53
|
+
protected mapColumnName(name: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Reverse map column name
|
|
56
|
+
*/
|
|
57
|
+
protected unmapColumnName(name: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Serialize data for database insert
|
|
60
|
+
* - Converts objects/arrays to JSON strings
|
|
61
|
+
* - Converts booleans to integers (0/1) for SQLite
|
|
62
|
+
* - Maps column names for reserved keywords
|
|
63
|
+
* - Adds numeric fields for sorting
|
|
64
|
+
* - Stores unknown fields in the 'data' column as JSON
|
|
65
|
+
*/
|
|
66
|
+
protected serializeForDb(data: Record<string, unknown>): Record<string, unknown>;
|
|
67
|
+
/**
|
|
68
|
+
* Serialize data for database update
|
|
69
|
+
* Preserves unknown fields from existing document's data column
|
|
70
|
+
*/
|
|
71
|
+
protected serializeForDbUpdate(updates: Record<string, unknown>, existing: Record<string, unknown>): Record<string, unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Convert a big number string to a sortable numeric string
|
|
74
|
+
* Pads with leading zeros to ensure lexicographic sorting works
|
|
75
|
+
*/
|
|
76
|
+
protected toSortableNumeric(value: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Deserialize data from database read
|
|
79
|
+
* - Parses JSON strings back to objects
|
|
80
|
+
* - Converts integers (0/1) back to booleans
|
|
81
|
+
* - Unmaps column names
|
|
82
|
+
* - Extracts unknown fields from 'data' column back to top level
|
|
83
|
+
*/
|
|
84
|
+
protected deserializeFromDb(data: Record<string, unknown> | undefined | null): Record<string, unknown> | null;
|
|
85
|
+
/**
|
|
86
|
+
* Internal get implementation - called by BaseIndex.get() via hooks
|
|
87
|
+
*/
|
|
88
|
+
_get(key: string | Record<string, unknown>): Promise<T | null>;
|
|
89
|
+
/**
|
|
90
|
+
* Internal insert implementation - called by BaseIndex.insert() via hooks
|
|
91
|
+
*/
|
|
92
|
+
_insert(doc: T | Record<string, unknown>): Promise<T>;
|
|
93
|
+
/**
|
|
94
|
+
* Internal update implementation - called by BaseIndex.update() via hooks
|
|
95
|
+
*/
|
|
96
|
+
_update(key: string | Record<string, unknown>, updates: Partial<T>): Promise<T>;
|
|
97
|
+
/**
|
|
98
|
+
* Count documents matching a query
|
|
99
|
+
*/
|
|
100
|
+
count(query?: unknown): Promise<number>;
|
|
101
|
+
/**
|
|
102
|
+
* Internal reset implementation - called by BaseIndex.reset() via hooks
|
|
103
|
+
*/
|
|
104
|
+
_reset(): Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { SqliteTableConfig, TableSchema, SqliteTable as default };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_table_base = require('./base.cjs');
|
|
4
|
+
let _ocap_indexdb = require("@ocap/indexdb");
|
|
5
|
+
|
|
6
|
+
//#region src/table/transaction.ts
|
|
7
|
+
/**
|
|
8
|
+
* Transaction table for SQLite IndexDB
|
|
9
|
+
* Extends base table to call formatTxBeforeInsert on insert
|
|
10
|
+
*/
|
|
11
|
+
var TransactionTable = class extends require_table_base.default {
|
|
12
|
+
/**
|
|
13
|
+
* Override _insert to format transaction before inserting
|
|
14
|
+
* This populates assets, tokens, factories, etc. from itxJson
|
|
15
|
+
*/
|
|
16
|
+
async _insert(row) {
|
|
17
|
+
const formatted = (0, _ocap_indexdb.formatTxBeforeInsert)(row);
|
|
18
|
+
return super._insert(formatted);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var transaction_default = TransactionTable;
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
exports.default = transaction_default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import SqliteTable from "./base.cjs";
|
|
2
|
+
import { TIndexedTransaction } from "@ocap/types";
|
|
3
|
+
|
|
4
|
+
//#region src/table/transaction.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transaction table for SQLite IndexDB
|
|
8
|
+
* Extends base table to call formatTxBeforeInsert on insert
|
|
9
|
+
*/
|
|
10
|
+
declare class TransactionTable extends SqliteTable<TIndexedTransaction> {
|
|
11
|
+
/**
|
|
12
|
+
* Override _insert to format transaction before inserting
|
|
13
|
+
* This populates assets, tokens, factories, etc. from itxJson
|
|
14
|
+
*/
|
|
15
|
+
_insert(row: TIndexedTransaction | Record<string, unknown>): Promise<TIndexedTransaction>;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { TransactionTable as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ocap/indexdb-sqlite",
|
|
3
|
+
"description": "OCAP indexdb adapter that uses SQLite as backend",
|
|
4
|
+
"version": "1.29.5",
|
|
5
|
+
"author": "wangshijun <shijun@arcblock.io> (https://www.arcblock.io)",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/ArcBlock/blockchain/issues",
|
|
8
|
+
"email": "shijun@arcblock.io"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"contributors": [
|
|
14
|
+
"wangshijun <shijun@arcblock.io> (https://www.arcblock.io)"
|
|
15
|
+
],
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@ocap/indexdb-test": "1.29.5"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/ArcBlock/blockchain/tree/master/indexdb/sqlite",
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ocap",
|
|
22
|
+
"indexdb",
|
|
23
|
+
"sqlite",
|
|
24
|
+
"kysely"
|
|
25
|
+
],
|
|
26
|
+
"license": "Apache-2.0",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./lib/index.cjs",
|
|
29
|
+
"module": "./esm/index.mjs",
|
|
30
|
+
"types": "./esm/index.d.mts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./esm/index.d.mts",
|
|
34
|
+
"import": "./esm/index.mjs",
|
|
35
|
+
"default": "./lib/index.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./lib/*.js": {
|
|
38
|
+
"types": "./esm/*.d.mts",
|
|
39
|
+
"import": "./esm/*.mjs",
|
|
40
|
+
"default": "./lib/*.cjs"
|
|
41
|
+
},
|
|
42
|
+
"./lib/*": {
|
|
43
|
+
"types": "./esm/*.d.mts",
|
|
44
|
+
"import": "./esm/*.mjs",
|
|
45
|
+
"default": "./lib/*.cjs"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"lib",
|
|
50
|
+
"esm"
|
|
51
|
+
],
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "https://github.com/ArcBlock/blockchain/tree/master/indexdb/sqlite"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsdown",
|
|
58
|
+
"prebuild": "rm -rf lib esm",
|
|
59
|
+
"lint": "biome check",
|
|
60
|
+
"lint:fix": "biome check --write",
|
|
61
|
+
"test": "bun test",
|
|
62
|
+
"coverage": "npm run test -- --coverage"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@arcblock/did": "1.29.5",
|
|
66
|
+
"@ocap/indexdb": "1.29.5",
|
|
67
|
+
"@ocap/types": "1.29.5",
|
|
68
|
+
"@ocap/util": "1.29.5",
|
|
69
|
+
"debug": "^4.4.3",
|
|
70
|
+
"better-sqlite3": "^11.8.1",
|
|
71
|
+
"kysely": "^0.27.0",
|
|
72
|
+
"kysely-bun-sqlite": "^0.4.0",
|
|
73
|
+
"lodash": "^4.17.23"
|
|
74
|
+
}
|
|
75
|
+
}
|