@peerbit/indexer-sqlite3 0.0.1-cccc078
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 +111 -0
- package/dist/benchmark/index.d.ts +2 -0
- package/dist/benchmark/index.d.ts.map +1 -0
- package/dist/benchmark/index.js +6 -0
- package/dist/benchmark/index.js.map +1 -0
- package/dist/peerbit/sqlite3-bundler-friendly.mjs +14481 -0
- package/dist/peerbit/sqlite3-node.mjs +12561 -0
- package/dist/peerbit/sqlite3-opfs-async-proxy.js +826 -0
- package/dist/peerbit/sqlite3-worker1-bundler-friendly.mjs +35 -0
- package/dist/peerbit/sqlite3-worker1-promiser.js +193 -0
- package/dist/peerbit/sqlite3-worker1-promiser.mjs +187 -0
- package/dist/peerbit/sqlite3-worker1.js +46 -0
- package/dist/peerbit/sqlite3.js +14520 -0
- package/dist/peerbit/sqlite3.min.js +21695 -0
- package/dist/peerbit/sqlite3.mjs +14483 -0
- package/dist/peerbit/sqlite3.wasm +0 -0
- package/dist/peerbit/sqlite3.worker.min.js +17995 -0
- package/dist/src/engine.d.ts +90 -0
- package/dist/src/engine.d.ts.map +1 -0
- package/dist/src/engine.js +414 -0
- package/dist/src/engine.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/schema.d.ts +73 -0
- package/dist/src/schema.d.ts.map +1 -0
- package/dist/src/schema.js +1075 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/sqlite3-messages.worker.d.ts +86 -0
- package/dist/src/sqlite3-messages.worker.d.ts.map +1 -0
- package/dist/src/sqlite3-messages.worker.js +9 -0
- package/dist/src/sqlite3-messages.worker.js.map +1 -0
- package/dist/src/sqlite3.browser.d.ts +4 -0
- package/dist/src/sqlite3.browser.d.ts.map +1 -0
- package/dist/src/sqlite3.browser.js +181 -0
- package/dist/src/sqlite3.browser.js.map +1 -0
- package/dist/src/sqlite3.d.ts +4 -0
- package/dist/src/sqlite3.d.ts.map +1 -0
- package/dist/src/sqlite3.js +51 -0
- package/dist/src/sqlite3.js.map +1 -0
- package/dist/src/sqlite3.wasm.d.ts +30 -0
- package/dist/src/sqlite3.wasm.d.ts.map +1 -0
- package/dist/src/sqlite3.wasm.js +180 -0
- package/dist/src/sqlite3.wasm.js.map +1 -0
- package/dist/src/sqlite3.worker.d.ts +2 -0
- package/dist/src/sqlite3.worker.d.ts.map +1 -0
- package/dist/src/sqlite3.worker.js +105 -0
- package/dist/src/sqlite3.worker.js.map +1 -0
- package/dist/src/types.d.ts +23 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +80 -0
- package/src/engine.ts +639 -0
- package/src/index.ts +16 -0
- package/src/schema.ts +1607 -0
- package/src/sqlite3-messages.worker.ts +123 -0
- package/src/sqlite3.browser.ts +245 -0
- package/src/sqlite3.ts +56 -0
- package/src/sqlite3.wasm.ts +211 -0
- package/src/sqlite3.worker.ts +109 -0
- package/src/types.ts +39 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { fromBase64, toBase64 } from "@peerbit/crypto";
|
|
2
|
+
|
|
3
|
+
interface Message {
|
|
4
|
+
id: string;
|
|
5
|
+
databaseId: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Database messages
|
|
9
|
+
interface CreateDatabase extends Message {
|
|
10
|
+
type: "create";
|
|
11
|
+
directory?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface Exec extends Message {
|
|
15
|
+
type: "exec";
|
|
16
|
+
sql: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Status extends Message {
|
|
20
|
+
type: "status";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface Close extends Message {
|
|
24
|
+
type: "close";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Open extends Message {
|
|
28
|
+
type: "open";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface Prepare extends Message {
|
|
32
|
+
type: "prepare";
|
|
33
|
+
sql: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type Uint8ArrayType = { type: "uint8array"; base64: string };
|
|
37
|
+
|
|
38
|
+
type SimpleType = { type: "simple"; value: any };
|
|
39
|
+
|
|
40
|
+
export const resolveValue = (value: Uint8ArrayType | SimpleType) =>
|
|
41
|
+
value.type === "simple" ? value.value : fromBase64(value.base64);
|
|
42
|
+
export const encodeValue = (value: any): Uint8ArrayType | SimpleType => {
|
|
43
|
+
if (value instanceof Uint8Array) {
|
|
44
|
+
return { type: "uint8array", base64: toBase64(value) };
|
|
45
|
+
}
|
|
46
|
+
return { type: "simple", value };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
interface Run extends Statement {
|
|
50
|
+
type: "run";
|
|
51
|
+
sql: string;
|
|
52
|
+
values: (Uint8ArrayType | SimpleType)[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Statement messages
|
|
56
|
+
interface Statement extends Message {
|
|
57
|
+
statementId: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface Bind extends Statement {
|
|
61
|
+
type: "bind";
|
|
62
|
+
values: (Uint8ArrayType | SimpleType)[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface Step extends Statement {
|
|
66
|
+
type: "step";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface Get extends Statement {
|
|
70
|
+
type: "get";
|
|
71
|
+
values?: any[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface Reset extends Statement {
|
|
75
|
+
type: "reset";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface RunStatement extends Statement {
|
|
79
|
+
type: "run-statement";
|
|
80
|
+
values: any[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface All extends Statement {
|
|
84
|
+
type: "all";
|
|
85
|
+
values: (Uint8ArrayType | SimpleType)[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface Finalize extends Statement {
|
|
89
|
+
type: "finalize";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Response messages
|
|
93
|
+
interface ErrorResponse {
|
|
94
|
+
type: "error";
|
|
95
|
+
id: string;
|
|
96
|
+
message: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface Response {
|
|
100
|
+
type: "response";
|
|
101
|
+
id: string;
|
|
102
|
+
result: any;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type DatabaseMessages =
|
|
106
|
+
| CreateDatabase
|
|
107
|
+
| Exec
|
|
108
|
+
| Prepare
|
|
109
|
+
| Close
|
|
110
|
+
| Open
|
|
111
|
+
| Run
|
|
112
|
+
| Status;
|
|
113
|
+
export type StatementMessages =
|
|
114
|
+
| Bind
|
|
115
|
+
| Step
|
|
116
|
+
| Get
|
|
117
|
+
| Reset
|
|
118
|
+
| All
|
|
119
|
+
| Finalize
|
|
120
|
+
| RunStatement;
|
|
121
|
+
export type ResponseMessages = ErrorResponse | Response;
|
|
122
|
+
|
|
123
|
+
export type IsReady = { type: "ready" };
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import pDefer from "p-defer";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
import type { BindableValue } from "./schema.js";
|
|
4
|
+
import * as messages from "./sqlite3-messages.worker.js";
|
|
5
|
+
import { create as createDatabase } from "./sqlite3.wasm.js";
|
|
6
|
+
import {
|
|
7
|
+
type Database as IDatabase,
|
|
8
|
+
type Statement as IStatement,
|
|
9
|
+
type StatementGetResult,
|
|
10
|
+
} from "./types.js";
|
|
11
|
+
|
|
12
|
+
class ProxyStatement implements IStatement {
|
|
13
|
+
resolvers: {
|
|
14
|
+
[hash in string]: {
|
|
15
|
+
resolve: (...args: any) => void;
|
|
16
|
+
reject: (...args: any) => void;
|
|
17
|
+
};
|
|
18
|
+
} = {};
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
readonly send: <T>(
|
|
22
|
+
message: messages.DatabaseMessages | messages.StatementMessages,
|
|
23
|
+
) => Promise<T>,
|
|
24
|
+
readonly databaseId: string,
|
|
25
|
+
readonly statementId: string,
|
|
26
|
+
) {}
|
|
27
|
+
|
|
28
|
+
async bind(values: any[]) {
|
|
29
|
+
await this.send({
|
|
30
|
+
type: "bind",
|
|
31
|
+
values: values.map(messages.encodeValue),
|
|
32
|
+
id: uuid(),
|
|
33
|
+
databaseId: this.databaseId,
|
|
34
|
+
statementId: this.statementId,
|
|
35
|
+
});
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async finalize() {
|
|
40
|
+
await this.send({
|
|
41
|
+
type: "finalize",
|
|
42
|
+
id: uuid(),
|
|
43
|
+
databaseId: this.databaseId,
|
|
44
|
+
statementId: this.statementId,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get(values?: BindableValue[]) {
|
|
49
|
+
return this.send<StatementGetResult>({
|
|
50
|
+
type: "get",
|
|
51
|
+
values: values ? values.map(messages.encodeValue) : undefined,
|
|
52
|
+
id: uuid(),
|
|
53
|
+
databaseId: this.databaseId,
|
|
54
|
+
statementId: this.statementId,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async run(values: BindableValue[]) {
|
|
59
|
+
await this.send({
|
|
60
|
+
type: "run-statement",
|
|
61
|
+
values: values.map(messages.encodeValue),
|
|
62
|
+
id: uuid(),
|
|
63
|
+
databaseId: this.databaseId,
|
|
64
|
+
statementId: this.statementId,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async reset() {
|
|
69
|
+
await this.send({
|
|
70
|
+
type: "reset",
|
|
71
|
+
id: uuid(),
|
|
72
|
+
databaseId: this.databaseId,
|
|
73
|
+
statementId: this.statementId,
|
|
74
|
+
});
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async all(values: BindableValue[]) {
|
|
79
|
+
let id = uuid();
|
|
80
|
+
const results = await this.send({
|
|
81
|
+
type: "all",
|
|
82
|
+
values: values.map(messages.encodeValue),
|
|
83
|
+
id,
|
|
84
|
+
databaseId: this.databaseId,
|
|
85
|
+
statementId: this.statementId,
|
|
86
|
+
});
|
|
87
|
+
return results;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
class ProxyDatabase implements IDatabase {
|
|
92
|
+
statements: Map<string, ProxyStatement> = new Map();
|
|
93
|
+
resolvers: {
|
|
94
|
+
[hash in string]: {
|
|
95
|
+
resolve: (...args: any) => void;
|
|
96
|
+
reject: (...args: any) => void;
|
|
97
|
+
};
|
|
98
|
+
} = {};
|
|
99
|
+
databaseId: string;
|
|
100
|
+
constructor(
|
|
101
|
+
readonly send: <T>(
|
|
102
|
+
message: messages.DatabaseMessages | messages.StatementMessages,
|
|
103
|
+
) => Promise<T>,
|
|
104
|
+
) {}
|
|
105
|
+
|
|
106
|
+
async init(directory?: string) {
|
|
107
|
+
this.databaseId = uuid();
|
|
108
|
+
return this.send({
|
|
109
|
+
type: "create",
|
|
110
|
+
directory,
|
|
111
|
+
databaseId: this.databaseId,
|
|
112
|
+
id: uuid(),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async exec(sql: string) {
|
|
117
|
+
return this.send({
|
|
118
|
+
type: "exec",
|
|
119
|
+
sql,
|
|
120
|
+
id: uuid(),
|
|
121
|
+
databaseId: this.databaseId,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async prepare(sql: string) {
|
|
126
|
+
const statementId = await this.send<string>({
|
|
127
|
+
type: "prepare",
|
|
128
|
+
sql,
|
|
129
|
+
id: uuid(),
|
|
130
|
+
databaseId: this.databaseId,
|
|
131
|
+
});
|
|
132
|
+
const statement = new ProxyStatement(
|
|
133
|
+
this.send,
|
|
134
|
+
this.databaseId,
|
|
135
|
+
statementId,
|
|
136
|
+
);
|
|
137
|
+
this.statements.set(statementId, statement);
|
|
138
|
+
return statement;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async open() {
|
|
142
|
+
return this.send({ type: "open", id: uuid(), databaseId: this.databaseId });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async close() {
|
|
146
|
+
return this.send({
|
|
147
|
+
type: "close",
|
|
148
|
+
id: uuid(),
|
|
149
|
+
databaseId: this.databaseId,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async status() {
|
|
154
|
+
return this.send<"open" | "closed">({
|
|
155
|
+
type: "status",
|
|
156
|
+
id: uuid(),
|
|
157
|
+
databaseId: this.databaseId,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* async get(sql: string) {
|
|
162
|
+
return this.send({ type: 'get', sql, id: uuid() });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async run(sql: string, bind: any[]) {
|
|
166
|
+
return this.send({ type: 'run', sql, bind, id: uuid() });
|
|
167
|
+
} */
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
interface DatabaseCreator {
|
|
171
|
+
create(directory?: string): Promise<ProxyDatabase>;
|
|
172
|
+
close(): Promise<void> | void;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let initialized: DatabaseCreator | undefined = undefined;
|
|
176
|
+
const init = async (): Promise<DatabaseCreator> => {
|
|
177
|
+
if (initialized) {
|
|
178
|
+
return initialized;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let worker = new Worker(
|
|
182
|
+
new URL("/peerbit/sqlite3.worker.min.js", import.meta.url),
|
|
183
|
+
{ type: "module" },
|
|
184
|
+
);
|
|
185
|
+
let resolvers: {
|
|
186
|
+
[hash in string]: {
|
|
187
|
+
resolve: (...args: any) => void;
|
|
188
|
+
reject: (...args: any) => void;
|
|
189
|
+
};
|
|
190
|
+
} = {};
|
|
191
|
+
|
|
192
|
+
let send = <T>(
|
|
193
|
+
message: messages.DatabaseMessages | messages.StatementMessages,
|
|
194
|
+
) => {
|
|
195
|
+
const promise = new Promise<T>((resolve, reject) => {
|
|
196
|
+
resolvers[message.id] = { resolve, reject };
|
|
197
|
+
});
|
|
198
|
+
worker.postMessage(message);
|
|
199
|
+
|
|
200
|
+
return promise.finally(() => delete resolvers[message.id]);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
let isReady = pDefer();
|
|
204
|
+
|
|
205
|
+
worker.onmessage = async (ev) => {
|
|
206
|
+
const message = ev.data as messages.ResponseMessages | messages.IsReady;
|
|
207
|
+
|
|
208
|
+
if (message.type === "ready") {
|
|
209
|
+
isReady.resolve();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const resolver = resolvers[message.id];
|
|
214
|
+
if (message.type === "error") {
|
|
215
|
+
resolver.reject(message.message);
|
|
216
|
+
} else if (message.type === "response") {
|
|
217
|
+
resolver.resolve(message.result);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const create = async (directory?: string) => {
|
|
222
|
+
const db = new ProxyDatabase(send);
|
|
223
|
+
await isReady.promise;
|
|
224
|
+
await db.init(directory);
|
|
225
|
+
await db.open();
|
|
226
|
+
return db;
|
|
227
|
+
};
|
|
228
|
+
return (initialized = {
|
|
229
|
+
create,
|
|
230
|
+
close: () => {
|
|
231
|
+
initialized = undefined;
|
|
232
|
+
worker.terminate();
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const create = (directory?: string): Promise<IDatabase> => {
|
|
238
|
+
if (directory) {
|
|
239
|
+
// persist the database
|
|
240
|
+
return init().then((creator) => creator.create(directory));
|
|
241
|
+
} else {
|
|
242
|
+
return createDatabase();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
export { create };
|
package/src/sqlite3.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import DB from "better-sqlite3";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import type {
|
|
4
|
+
Database as IDatabase,
|
|
5
|
+
Statement as IStatement,
|
|
6
|
+
} from "./types.js";
|
|
7
|
+
|
|
8
|
+
let create = async (directory?: string) => {
|
|
9
|
+
let db: DB.Database | undefined = undefined;
|
|
10
|
+
let close = () => {
|
|
11
|
+
if (db) {
|
|
12
|
+
db.close();
|
|
13
|
+
db = undefined;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
let open = () => {
|
|
17
|
+
if (db) {
|
|
18
|
+
return db;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let dbFileName: string;
|
|
22
|
+
if (directory) {
|
|
23
|
+
// if directory is provided, check if directory exist, if not create it
|
|
24
|
+
if (!fs.existsSync(directory)) {
|
|
25
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
dbFileName = `${directory}/db.sqlite`;
|
|
28
|
+
} else {
|
|
29
|
+
dbFileName = ":memory:";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
db = new DB(dbFileName, {
|
|
33
|
+
fileMustExist: false,
|
|
34
|
+
readonly: false /* , verbose: (message) => console.log(message) */,
|
|
35
|
+
});
|
|
36
|
+
/* db.pragma('journal_mode = WAL'); */
|
|
37
|
+
db.pragma("foreign_keys = on");
|
|
38
|
+
db.defaultSafeIntegers(true);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
exec: (sql: string) => {
|
|
43
|
+
if (!db) throw new Error("Database not open");
|
|
44
|
+
return db.exec(sql);
|
|
45
|
+
},
|
|
46
|
+
prepare(sql: string) {
|
|
47
|
+
if (!db) throw new Error("Database not open");
|
|
48
|
+
return db.prepare(sql) as any as IStatement; // TODO types
|
|
49
|
+
},
|
|
50
|
+
close,
|
|
51
|
+
open,
|
|
52
|
+
status: () => (db ? "open" : "closed"),
|
|
53
|
+
} as IDatabase; // TODO fix this
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export { create };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { BinaryReader, BinaryWriter } from "@dao-xyz/borsh";
|
|
2
|
+
import { fromBase64URL, toBase64URL } from "@peerbit/crypto";
|
|
3
|
+
import {
|
|
4
|
+
type OpfsSAHPoolDatabase,
|
|
5
|
+
type SAHPoolUtil,
|
|
6
|
+
type Database as SQLDatabase,
|
|
7
|
+
type PreparedStatement as SQLStatement,
|
|
8
|
+
default as sqlite3InitModule,
|
|
9
|
+
} from "@sqlite.org/sqlite-wasm";
|
|
10
|
+
import type { BindableValue } from "./schema.js";
|
|
11
|
+
import {
|
|
12
|
+
type Statement as IStatement,
|
|
13
|
+
type StatementGetResult,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
/* import { v4 as uuid } from 'uuid';
|
|
17
|
+
*/
|
|
18
|
+
export const encodeName = (name: string): string => {
|
|
19
|
+
// since "/" and perhaps other characters might not be allowed we do encode
|
|
20
|
+
const writer = new BinaryWriter();
|
|
21
|
+
writer.string(name);
|
|
22
|
+
return toBase64URL(writer.finalize());
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const decodeName = (name: string): string => {
|
|
26
|
+
// since "/" and perhaps other characters might not be allowed we do encode
|
|
27
|
+
const writer = new BinaryReader(fromBase64URL(name));
|
|
28
|
+
return writer.string();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
class Statement implements IStatement {
|
|
32
|
+
constructor(private statement: SQLStatement) {}
|
|
33
|
+
|
|
34
|
+
async bind(values: any[]) {
|
|
35
|
+
await this.statement.bind(values);
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async finalize() {
|
|
40
|
+
if ((await this.statement.finalize()) > 0) {
|
|
41
|
+
throw new Error("Error finalizing statement");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get(values?: BindableValue[]) {
|
|
46
|
+
if (values) {
|
|
47
|
+
this.statement.bind(values);
|
|
48
|
+
}
|
|
49
|
+
let step = this.statement.step();
|
|
50
|
+
if (!step) {
|
|
51
|
+
// no data available
|
|
52
|
+
this.statement.reset();
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const results = this.statement.get({});
|
|
56
|
+
this.statement.reset();
|
|
57
|
+
return results as StatementGetResult;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
run(values: BindableValue[]) {
|
|
61
|
+
this.statement.bind(values as any);
|
|
62
|
+
this.statement.stepReset();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async reset() {
|
|
66
|
+
await this.statement.reset();
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
all(values: BindableValue[]) {
|
|
71
|
+
if (values && values.length > 0) {
|
|
72
|
+
this.statement.bind(values as any);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let results = [];
|
|
76
|
+
while (this.statement.step()) {
|
|
77
|
+
results.push(this.statement.get({}));
|
|
78
|
+
}
|
|
79
|
+
this.statement.reset();
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
step() {
|
|
84
|
+
return this.statement.step();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* export class Database implements IDatabase {
|
|
89
|
+
|
|
90
|
+
statements: Map<string, Statement> = new Map();
|
|
91
|
+
private db: SQLDatabase
|
|
92
|
+
constructor(private readonly _close?: () => Promise<any> | any) { }
|
|
93
|
+
|
|
94
|
+
async exec(sql: string) {
|
|
95
|
+
return this.db.exec(sql);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async prepare(sql: string) {
|
|
99
|
+
const statement = this.db.prepare(sql);
|
|
100
|
+
const wrappedStatement = new Statement(statement);
|
|
101
|
+
this.statements.set(sql, wrappedStatement)
|
|
102
|
+
return wrappedStatement
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async close() {
|
|
106
|
+
await Promise.all([...this.statements.values()].map(x => x.finalize?.()))
|
|
107
|
+
await this.db.close();
|
|
108
|
+
await this._close?.()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async get(sql: string) {
|
|
112
|
+
return this.db.exec({ sql, rowMode: 'array' });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async run(sql: string, bind: any[]) {
|
|
116
|
+
return this.db.exec(sql, { bind, rowMode: 'array' });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
// eslint-disable-next-line no-console
|
|
123
|
+
const log = (...args: any) => console.log(...args);
|
|
124
|
+
// eslint-disable-next-line no-console
|
|
125
|
+
const error = (...args: any) => console.error(...args);
|
|
126
|
+
|
|
127
|
+
/* let initOpfsResult: Promise<{ sqlite3: Awaited<ReturnType<typeof sqlite3InitModule>>,poolUtil: }> | undefined = undefined;
|
|
128
|
+
const initOpfs = async () => {
|
|
129
|
+
|
|
130
|
+
let sqlite3: Awaited<ReturnType<typeof sqlite3InitModule>> = await sqlite3InitModule({
|
|
131
|
+
locateFile: (path, prefix) => {
|
|
132
|
+
|
|
133
|
+
return path;
|
|
134
|
+
}, print: log, printErr: error
|
|
135
|
+
});
|
|
136
|
+
let poolUtil = await sqlite3.installOpfsSAHPoolVfs({
|
|
137
|
+
directory: encodeName("helloworld")
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return initOpfsResult || (initOpfsResult = { sqlite3, poolUtil })
|
|
141
|
+
} */
|
|
142
|
+
|
|
143
|
+
let poolUtil: SAHPoolUtil = undefined;
|
|
144
|
+
let sqlite3: Awaited<ReturnType<typeof sqlite3InitModule>> | undefined =
|
|
145
|
+
undefined;
|
|
146
|
+
|
|
147
|
+
const create = async (directory?: string) => {
|
|
148
|
+
let statements: Map<string, Statement> = new Map();
|
|
149
|
+
|
|
150
|
+
sqlite3 =
|
|
151
|
+
sqlite3 || (await sqlite3InitModule({ print: log, printErr: error }));
|
|
152
|
+
let sqliteDb: OpfsSAHPoolDatabase | SQLDatabase | undefined = undefined;
|
|
153
|
+
let close: (() => Promise<any> | any) | undefined = async () => {
|
|
154
|
+
await Promise.all([...statements.values()].map((x) => x.finalize?.()));
|
|
155
|
+
statements.clear();
|
|
156
|
+
|
|
157
|
+
await sqliteDb?.close();
|
|
158
|
+
sqliteDb = undefined;
|
|
159
|
+
};
|
|
160
|
+
let open = async () => {
|
|
161
|
+
if (sqliteDb) {
|
|
162
|
+
return sqliteDb;
|
|
163
|
+
}
|
|
164
|
+
if (directory) {
|
|
165
|
+
// directory has to be absolute path. Remove leading dot if any
|
|
166
|
+
// TODO show warning if directory is not absolute?
|
|
167
|
+
directory = directory.replace(/^\./, "");
|
|
168
|
+
|
|
169
|
+
let dbFileName = `${directory}/db.sqlite`;
|
|
170
|
+
|
|
171
|
+
poolUtil =
|
|
172
|
+
poolUtil ||
|
|
173
|
+
(await sqlite3.installOpfsSAHPoolVfs({
|
|
174
|
+
directory: "peerbit/sqlite", // encodeName("peerbit")
|
|
175
|
+
}));
|
|
176
|
+
|
|
177
|
+
await poolUtil.reserveMinimumCapacity(100);
|
|
178
|
+
sqliteDb = new poolUtil.OpfsSAHPoolDb(dbFileName);
|
|
179
|
+
} else {
|
|
180
|
+
sqliteDb = new sqlite3.oo1.DB(":memory:");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
sqliteDb.exec("PRAGMA journal_mode = WAL");
|
|
184
|
+
sqliteDb.exec("PRAGMA foreign_keys = on");
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
close,
|
|
189
|
+
exec: (sql: string) => {
|
|
190
|
+
return sqliteDb.exec(sql);
|
|
191
|
+
},
|
|
192
|
+
open,
|
|
193
|
+
prepare: (sql: string) => {
|
|
194
|
+
const statement = sqliteDb.prepare(sql);
|
|
195
|
+
const wrappedStatement = new Statement(statement);
|
|
196
|
+
statements.set(sql, wrappedStatement);
|
|
197
|
+
return wrappedStatement;
|
|
198
|
+
},
|
|
199
|
+
get(sql: string) {
|
|
200
|
+
return sqliteDb.exec({ sql, rowMode: "array" });
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
run(sql: string, bind: any[]) {
|
|
204
|
+
return sqliteDb.exec(sql, { bind, rowMode: "array" });
|
|
205
|
+
},
|
|
206
|
+
status: () => (sqliteDb?.isOpen() ? "open" : "closed"),
|
|
207
|
+
statements,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export { create };
|