@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.
Files changed (63) hide show
  1. package/README.md +111 -0
  2. package/dist/benchmark/index.d.ts +2 -0
  3. package/dist/benchmark/index.d.ts.map +1 -0
  4. package/dist/benchmark/index.js +6 -0
  5. package/dist/benchmark/index.js.map +1 -0
  6. package/dist/peerbit/sqlite3-bundler-friendly.mjs +14481 -0
  7. package/dist/peerbit/sqlite3-node.mjs +12561 -0
  8. package/dist/peerbit/sqlite3-opfs-async-proxy.js +826 -0
  9. package/dist/peerbit/sqlite3-worker1-bundler-friendly.mjs +35 -0
  10. package/dist/peerbit/sqlite3-worker1-promiser.js +193 -0
  11. package/dist/peerbit/sqlite3-worker1-promiser.mjs +187 -0
  12. package/dist/peerbit/sqlite3-worker1.js +46 -0
  13. package/dist/peerbit/sqlite3.js +14520 -0
  14. package/dist/peerbit/sqlite3.min.js +21695 -0
  15. package/dist/peerbit/sqlite3.mjs +14483 -0
  16. package/dist/peerbit/sqlite3.wasm +0 -0
  17. package/dist/peerbit/sqlite3.worker.min.js +17995 -0
  18. package/dist/src/engine.d.ts +90 -0
  19. package/dist/src/engine.d.ts.map +1 -0
  20. package/dist/src/engine.js +414 -0
  21. package/dist/src/engine.js.map +1 -0
  22. package/dist/src/index.d.ts +5 -0
  23. package/dist/src/index.d.ts.map +1 -0
  24. package/dist/src/index.js +15 -0
  25. package/dist/src/index.js.map +1 -0
  26. package/dist/src/schema.d.ts +73 -0
  27. package/dist/src/schema.d.ts.map +1 -0
  28. package/dist/src/schema.js +1075 -0
  29. package/dist/src/schema.js.map +1 -0
  30. package/dist/src/sqlite3-messages.worker.d.ts +86 -0
  31. package/dist/src/sqlite3-messages.worker.d.ts.map +1 -0
  32. package/dist/src/sqlite3-messages.worker.js +9 -0
  33. package/dist/src/sqlite3-messages.worker.js.map +1 -0
  34. package/dist/src/sqlite3.browser.d.ts +4 -0
  35. package/dist/src/sqlite3.browser.d.ts.map +1 -0
  36. package/dist/src/sqlite3.browser.js +181 -0
  37. package/dist/src/sqlite3.browser.js.map +1 -0
  38. package/dist/src/sqlite3.d.ts +4 -0
  39. package/dist/src/sqlite3.d.ts.map +1 -0
  40. package/dist/src/sqlite3.js +51 -0
  41. package/dist/src/sqlite3.js.map +1 -0
  42. package/dist/src/sqlite3.wasm.d.ts +30 -0
  43. package/dist/src/sqlite3.wasm.d.ts.map +1 -0
  44. package/dist/src/sqlite3.wasm.js +180 -0
  45. package/dist/src/sqlite3.wasm.js.map +1 -0
  46. package/dist/src/sqlite3.worker.d.ts +2 -0
  47. package/dist/src/sqlite3.worker.d.ts.map +1 -0
  48. package/dist/src/sqlite3.worker.js +105 -0
  49. package/dist/src/sqlite3.worker.js.map +1 -0
  50. package/dist/src/types.d.ts +23 -0
  51. package/dist/src/types.d.ts.map +1 -0
  52. package/dist/src/types.js +2 -0
  53. package/dist/src/types.js.map +1 -0
  54. package/package.json +80 -0
  55. package/src/engine.ts +639 -0
  56. package/src/index.ts +16 -0
  57. package/src/schema.ts +1607 -0
  58. package/src/sqlite3-messages.worker.ts +123 -0
  59. package/src/sqlite3.browser.ts +245 -0
  60. package/src/sqlite3.ts +56 -0
  61. package/src/sqlite3.wasm.ts +211 -0
  62. package/src/sqlite3.worker.ts +109 -0
  63. 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 };