cojson-storage-sqlite 0.14.1 → 0.14.18
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +25 -0
- package/dist/betterSqliteDriver.d.ts +10 -0
- package/dist/betterSqliteDriver.d.ts.map +1 -0
- package/dist/betterSqliteDriver.js +21 -0
- package/dist/betterSqliteDriver.js.map +1 -0
- package/dist/sqliteNode.d.ts +3 -7
- package/dist/sqliteNode.d.ts.map +1 -1
- package/dist/sqliteNode.js +9 -98
- package/dist/sqliteNode.js.map +1 -1
- package/package.json +3 -3
- package/src/betterSqliteDriver.ts +28 -0
- package/src/sqliteNode.ts +10 -169
- package/dist/sqliteClient.d.ts +0 -40
- package/dist/sqliteClient.d.ts.map +0 -1
- package/dist/sqliteClient.js +0 -90
- package/dist/sqliteClient.js.map +0 -1
- package/src/sqliteClient.ts +0 -180
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# cojson-storage-sqlite
|
|
2
2
|
|
|
3
|
+
## 0.14.18
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [0d5ee3e]
|
|
8
|
+
- Updated dependencies [be7c4c2]
|
|
9
|
+
- cojson@0.14.18
|
|
10
|
+
- cojson-storage@0.14.18
|
|
11
|
+
|
|
12
|
+
## 0.14.16
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [5e253cc]
|
|
17
|
+
- cojson@0.14.16
|
|
18
|
+
- cojson-storage@0.14.16
|
|
19
|
+
|
|
20
|
+
## 0.14.15
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [23daa7c]
|
|
25
|
+
- cojson-storage@0.14.15
|
|
26
|
+
- cojson@0.14.15
|
|
27
|
+
|
|
3
28
|
## 0.14.1
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SQLiteDatabaseDriver } from "cojson-storage";
|
|
2
|
+
export declare class BetterSqliteDriver implements SQLiteDatabaseDriver {
|
|
3
|
+
private readonly db;
|
|
4
|
+
constructor(filename: string);
|
|
5
|
+
run(sql: string, params: unknown[]): void;
|
|
6
|
+
query<T>(sql: string, params: unknown[]): T[];
|
|
7
|
+
get<T>(sql: string, params: unknown[]): T | undefined;
|
|
8
|
+
transaction(callback: () => unknown): unknown;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=betterSqliteDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"betterSqliteDriver.d.ts","sourceRoot":"","sources":["../src/betterSqliteDriver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,qBAAa,kBAAmB,YAAW,oBAAoB;IAC7D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;gBAEnB,QAAQ,EAAE,MAAM;IAM5B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAIlC,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE;IAI7C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,SAAS;IAIrD,WAAW,CAAC,QAAQ,EAAE,MAAM,OAAO;CAGpC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
export class BetterSqliteDriver {
|
|
3
|
+
constructor(filename) {
|
|
4
|
+
const db = new Database(filename);
|
|
5
|
+
this.db = db;
|
|
6
|
+
db.pragma("journal_mode = WAL");
|
|
7
|
+
}
|
|
8
|
+
run(sql, params) {
|
|
9
|
+
this.db.prepare(sql).run(params);
|
|
10
|
+
}
|
|
11
|
+
query(sql, params) {
|
|
12
|
+
return this.db.prepare(sql).all(params);
|
|
13
|
+
}
|
|
14
|
+
get(sql, params) {
|
|
15
|
+
return this.db.prepare(sql).get(params);
|
|
16
|
+
}
|
|
17
|
+
transaction(callback) {
|
|
18
|
+
return this.db.transaction(callback)();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=betterSqliteDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"betterSqliteDriver.js","sourceRoot":"","sources":["../src/betterSqliteDriver.ts"],"names":[],"mappings":"AAAA,OAAO,QAAwC,MAAM,gBAAgB,CAAC;AAGtE,MAAM,OAAO,kBAAkB;IAG7B,YAAY,QAAgB;QAC1B,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,MAAiB;QAChC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAI,GAAW,EAAE,MAAiB;QACrC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAQ,CAAC;IACjD,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,MAAiB;QACnC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAkB,CAAC;IAC3D,CAAC;IAED,WAAW,CAAC,QAAuB;QACjC,OAAO,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;IACzC,CAAC;CACF"}
|
package/dist/sqliteNode.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export declare class SQLiteNode {
|
|
4
|
-
private readonly syncManager;
|
|
5
|
-
private readonly dbClient;
|
|
6
|
-
constructor(db: DatabaseT, fromLocalNode: IncomingSyncStream, toLocalNode: OutgoingSyncQueue);
|
|
1
|
+
import type { Peer } from "cojson";
|
|
2
|
+
import { SQLiteNodeBase } from "cojson-storage";
|
|
3
|
+
export declare class SQLiteNode extends SQLiteNodeBase {
|
|
7
4
|
static asPeer({ filename, localNodeName, }: {
|
|
8
5
|
filename: string;
|
|
9
6
|
localNodeName?: string;
|
|
10
7
|
}): Promise<Peer>;
|
|
11
|
-
static open(filename: string, fromLocalNode: IncomingSyncStream, toLocalNode: OutgoingSyncQueue): Promise<SQLiteNode>;
|
|
12
8
|
}
|
|
13
9
|
//# sourceMappingURL=sqliteNode.d.ts.map
|
package/dist/sqliteNode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqliteNode.d.ts","sourceRoot":"","sources":["../src/sqliteNode.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"sqliteNode.d.ts","sourceRoot":"","sources":["../src/sqliteNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,qBAAa,UAAW,SAAQ,cAAc;WAC/B,MAAM,CAAC,EAClB,QAAQ,EACR,aAAuB,GACxB,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC,IAAI,CAAC;CASlB"}
|
package/dist/sqliteNode.js
CHANGED
|
@@ -1,102 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { SQLiteClient } from "./sqliteClient.js";
|
|
5
|
-
export class SQLiteNode {
|
|
6
|
-
constructor(db, fromLocalNode, toLocalNode) {
|
|
7
|
-
this.dbClient = new SQLiteClient(db, toLocalNode);
|
|
8
|
-
this.syncManager = new StorageManagerSync(this.dbClient, toLocalNode);
|
|
9
|
-
const processMessages = async () => {
|
|
10
|
-
let lastTimer = performance.now();
|
|
11
|
-
let runningTimer = false;
|
|
12
|
-
for await (const msg of fromLocalNode) {
|
|
13
|
-
try {
|
|
14
|
-
if (msg === "Disconnected" || msg === "PingTimeout") {
|
|
15
|
-
throw new Error("Unexpected Disconnected message");
|
|
16
|
-
}
|
|
17
|
-
if (!runningTimer) {
|
|
18
|
-
runningTimer = true;
|
|
19
|
-
lastTimer = performance.now();
|
|
20
|
-
setTimeout(() => {
|
|
21
|
-
runningTimer = false;
|
|
22
|
-
}, 10);
|
|
23
|
-
}
|
|
24
|
-
this.syncManager.handleSyncMessage(msg);
|
|
25
|
-
// Since the DB APIs are synchronous there may be the case
|
|
26
|
-
// where a bulk of messages are processed without interruptions
|
|
27
|
-
// which may block other peers from sending messages.
|
|
28
|
-
// To avoid this we schedule a timer to downgrade the priority of the storage peer work
|
|
29
|
-
if (performance.now() - lastTimer > 500) {
|
|
30
|
-
lastTimer = performance.now();
|
|
31
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch (e) {
|
|
35
|
-
logger.error("Error reading from localNode, handling msg", {
|
|
36
|
-
msg,
|
|
37
|
-
err: e,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
processMessages().catch((e) => logger.error("Error in processMessages in sqlite", { err: e }));
|
|
43
|
-
}
|
|
1
|
+
import { SQLiteNodeBase } from "cojson-storage";
|
|
2
|
+
import { BetterSqliteDriver } from "./betterSqliteDriver.js";
|
|
3
|
+
export class SQLiteNode extends SQLiteNodeBase {
|
|
44
4
|
static async asPeer({ filename, localNodeName = "local", }) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
db.pragma("journal_mode = WAL");
|
|
52
|
-
const oldVersion = db.pragma("user_version")[0].user_version;
|
|
53
|
-
if (oldVersion === 0) {
|
|
54
|
-
db.prepare(`CREATE TABLE IF NOT EXISTS transactions (
|
|
55
|
-
ses INTEGER,
|
|
56
|
-
idx INTEGER,
|
|
57
|
-
tx TEXT NOT NULL,
|
|
58
|
-
PRIMARY KEY (ses, idx)
|
|
59
|
-
) WITHOUT ROWID;`).run();
|
|
60
|
-
db.prepare(`CREATE TABLE IF NOT EXISTS sessions (
|
|
61
|
-
rowID INTEGER PRIMARY KEY,
|
|
62
|
-
coValue INTEGER NOT NULL,
|
|
63
|
-
sessionID TEXT NOT NULL,
|
|
64
|
-
lastIdx INTEGER,
|
|
65
|
-
lastSignature TEXT,
|
|
66
|
-
UNIQUE (sessionID, coValue)
|
|
67
|
-
);`).run();
|
|
68
|
-
db.prepare("CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);").run();
|
|
69
|
-
db.prepare(`CREATE TABLE IF NOT EXISTS coValues (
|
|
70
|
-
rowID INTEGER PRIMARY KEY,
|
|
71
|
-
id TEXT NOT NULL UNIQUE,
|
|
72
|
-
header TEXT NOT NULL UNIQUE
|
|
73
|
-
);`).run();
|
|
74
|
-
db.prepare("CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);").run();
|
|
75
|
-
db.pragma("user_version = 1");
|
|
76
|
-
}
|
|
77
|
-
if (oldVersion <= 1) {
|
|
78
|
-
// fix embarrassing off-by-one error for transaction indices
|
|
79
|
-
const txs = db
|
|
80
|
-
.prepare("SELECT * FROM transactions")
|
|
81
|
-
.all();
|
|
82
|
-
for (const tx of txs) {
|
|
83
|
-
db.prepare("DELETE FROM transactions WHERE ses = ? AND idx = ?").run(tx.ses, tx.idx);
|
|
84
|
-
tx.idx -= 1;
|
|
85
|
-
db.prepare("INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)").run(tx.ses, tx.idx, tx.tx);
|
|
86
|
-
}
|
|
87
|
-
db.pragma("user_version = 2");
|
|
88
|
-
}
|
|
89
|
-
if (oldVersion <= 2) {
|
|
90
|
-
db.prepare(`CREATE TABLE IF NOT EXISTS signatureAfter (
|
|
91
|
-
ses INTEGER,
|
|
92
|
-
idx INTEGER,
|
|
93
|
-
signature TEXT NOT NULL,
|
|
94
|
-
PRIMARY KEY (ses, idx)
|
|
95
|
-
) WITHOUT ROWID;`).run();
|
|
96
|
-
db.prepare("ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;").run();
|
|
97
|
-
db.pragma("user_version = 3");
|
|
98
|
-
}
|
|
99
|
-
return new SQLiteNode(db, fromLocalNode, toLocalNode);
|
|
5
|
+
const db = new BetterSqliteDriver(filename);
|
|
6
|
+
return SQLiteNodeBase.create({
|
|
7
|
+
db,
|
|
8
|
+
localNodeName,
|
|
9
|
+
maxBlockingTime: 500,
|
|
10
|
+
});
|
|
100
11
|
}
|
|
101
12
|
}
|
|
102
13
|
//# sourceMappingURL=sqliteNode.js.map
|
package/dist/sqliteNode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqliteNode.js","sourceRoot":"","sources":["../src/sqliteNode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sqliteNode.js","sourceRoot":"","sources":["../src/sqliteNode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,OAAO,UAAW,SAAQ,cAAc;IAC5C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAClB,QAAQ,EACR,aAAa,GAAG,OAAO,GAIxB;QACC,MAAM,EAAE,GAAG,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAE5C,OAAO,cAAc,CAAC,MAAM,CAAC;YAC3B,EAAE;YACF,aAAa;YACb,eAAe,EAAE,GAAG;SACrB,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cojson-storage-sqlite",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.14.
|
|
4
|
+
"version": "0.14.18",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"better-sqlite3": "^11.7.0",
|
|
10
|
-
"cojson": "0.14.
|
|
11
|
-
"cojson-storage": "0.14.
|
|
10
|
+
"cojson": "0.14.18",
|
|
11
|
+
"cojson-storage": "0.14.18"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@types/better-sqlite3": "^7.6.12",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Database, { type Database as DatabaseT } from "better-sqlite3";
|
|
2
|
+
import type { SQLiteDatabaseDriver } from "cojson-storage";
|
|
3
|
+
|
|
4
|
+
export class BetterSqliteDriver implements SQLiteDatabaseDriver {
|
|
5
|
+
private readonly db: DatabaseT;
|
|
6
|
+
|
|
7
|
+
constructor(filename: string) {
|
|
8
|
+
const db = new Database(filename);
|
|
9
|
+
this.db = db;
|
|
10
|
+
db.pragma("journal_mode = WAL");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run(sql: string, params: unknown[]) {
|
|
14
|
+
this.db.prepare(sql).run(params);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
query<T>(sql: string, params: unknown[]): T[] {
|
|
18
|
+
return this.db.prepare(sql).all(params) as T[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get<T>(sql: string, params: unknown[]): T | undefined {
|
|
22
|
+
return this.db.prepare(sql).get(params) as T | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
transaction(callback: () => unknown) {
|
|
26
|
+
return this.db.transaction(callback)();
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/sqliteNode.ts
CHANGED
|
@@ -1,69 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
type OutgoingSyncQueue,
|
|
5
|
-
type Peer,
|
|
6
|
-
cojsonInternals,
|
|
7
|
-
logger,
|
|
8
|
-
} from "cojson";
|
|
9
|
-
import { StorageManagerSync, type TransactionRow } from "cojson-storage";
|
|
10
|
-
import { SQLiteClient } from "./sqliteClient.js";
|
|
11
|
-
|
|
12
|
-
export class SQLiteNode {
|
|
13
|
-
private readonly syncManager: StorageManagerSync;
|
|
14
|
-
private readonly dbClient: SQLiteClient;
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
db: DatabaseT,
|
|
18
|
-
fromLocalNode: IncomingSyncStream,
|
|
19
|
-
toLocalNode: OutgoingSyncQueue,
|
|
20
|
-
) {
|
|
21
|
-
this.dbClient = new SQLiteClient(db, toLocalNode);
|
|
22
|
-
this.syncManager = new StorageManagerSync(this.dbClient, toLocalNode);
|
|
23
|
-
|
|
24
|
-
const processMessages = async () => {
|
|
25
|
-
let lastTimer = performance.now();
|
|
26
|
-
let runningTimer = false;
|
|
27
|
-
|
|
28
|
-
for await (const msg of fromLocalNode) {
|
|
29
|
-
try {
|
|
30
|
-
if (msg === "Disconnected" || msg === "PingTimeout") {
|
|
31
|
-
throw new Error("Unexpected Disconnected message");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!runningTimer) {
|
|
35
|
-
runningTimer = true;
|
|
36
|
-
lastTimer = performance.now();
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
runningTimer = false;
|
|
39
|
-
}, 10);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
this.syncManager.handleSyncMessage(msg);
|
|
43
|
-
|
|
44
|
-
// Since the DB APIs are synchronous there may be the case
|
|
45
|
-
// where a bulk of messages are processed without interruptions
|
|
46
|
-
// which may block other peers from sending messages.
|
|
47
|
-
|
|
48
|
-
// To avoid this we schedule a timer to downgrade the priority of the storage peer work
|
|
49
|
-
if (performance.now() - lastTimer > 500) {
|
|
50
|
-
lastTimer = performance.now();
|
|
51
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
52
|
-
}
|
|
53
|
-
} catch (e) {
|
|
54
|
-
logger.error("Error reading from localNode, handling msg", {
|
|
55
|
-
msg,
|
|
56
|
-
err: e,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
processMessages().catch((e) =>
|
|
63
|
-
logger.error("Error in processMessages in sqlite", { err: e }),
|
|
64
|
-
);
|
|
65
|
-
}
|
|
1
|
+
import type { Peer } from "cojson";
|
|
2
|
+
import { SQLiteNodeBase } from "cojson-storage";
|
|
3
|
+
import { BetterSqliteDriver } from "./betterSqliteDriver.js";
|
|
66
4
|
|
|
5
|
+
export class SQLiteNode extends SQLiteNodeBase {
|
|
67
6
|
static async asPeer({
|
|
68
7
|
filename,
|
|
69
8
|
localNodeName = "local",
|
|
@@ -71,110 +10,12 @@ export class SQLiteNode {
|
|
|
71
10
|
filename: string;
|
|
72
11
|
localNodeName?: string;
|
|
73
12
|
}): Promise<Peer> {
|
|
74
|
-
const
|
|
75
|
-
localNodeName,
|
|
76
|
-
"storage",
|
|
77
|
-
{ peer1role: "client", peer2role: "storage", crashOnClose: true },
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
await SQLiteNode.open(
|
|
81
|
-
filename,
|
|
82
|
-
localNodeAsPeer.incoming,
|
|
83
|
-
localNodeAsPeer.outgoing,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
return { ...storageAsPeer, priority: 100 };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
static async open(
|
|
90
|
-
filename: string,
|
|
91
|
-
fromLocalNode: IncomingSyncStream,
|
|
92
|
-
toLocalNode: OutgoingSyncQueue,
|
|
93
|
-
) {
|
|
94
|
-
const db = Database(filename);
|
|
95
|
-
db.pragma("journal_mode = WAL");
|
|
13
|
+
const db = new BetterSqliteDriver(filename);
|
|
96
14
|
|
|
97
|
-
|
|
98
|
-
db
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
db.prepare(
|
|
103
|
-
`CREATE TABLE IF NOT EXISTS transactions (
|
|
104
|
-
ses INTEGER,
|
|
105
|
-
idx INTEGER,
|
|
106
|
-
tx TEXT NOT NULL,
|
|
107
|
-
PRIMARY KEY (ses, idx)
|
|
108
|
-
) WITHOUT ROWID;`,
|
|
109
|
-
).run();
|
|
110
|
-
|
|
111
|
-
db.prepare(
|
|
112
|
-
`CREATE TABLE IF NOT EXISTS sessions (
|
|
113
|
-
rowID INTEGER PRIMARY KEY,
|
|
114
|
-
coValue INTEGER NOT NULL,
|
|
115
|
-
sessionID TEXT NOT NULL,
|
|
116
|
-
lastIdx INTEGER,
|
|
117
|
-
lastSignature TEXT,
|
|
118
|
-
UNIQUE (sessionID, coValue)
|
|
119
|
-
);`,
|
|
120
|
-
).run();
|
|
121
|
-
|
|
122
|
-
db.prepare(
|
|
123
|
-
"CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);",
|
|
124
|
-
).run();
|
|
125
|
-
|
|
126
|
-
db.prepare(
|
|
127
|
-
`CREATE TABLE IF NOT EXISTS coValues (
|
|
128
|
-
rowID INTEGER PRIMARY KEY,
|
|
129
|
-
id TEXT NOT NULL UNIQUE,
|
|
130
|
-
header TEXT NOT NULL UNIQUE
|
|
131
|
-
);`,
|
|
132
|
-
).run();
|
|
133
|
-
|
|
134
|
-
db.prepare(
|
|
135
|
-
"CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);",
|
|
136
|
-
).run();
|
|
137
|
-
|
|
138
|
-
db.pragma("user_version = 1");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (oldVersion <= 1) {
|
|
142
|
-
// fix embarrassing off-by-one error for transaction indices
|
|
143
|
-
const txs = db
|
|
144
|
-
.prepare("SELECT * FROM transactions")
|
|
145
|
-
.all() as TransactionRow[];
|
|
146
|
-
|
|
147
|
-
for (const tx of txs) {
|
|
148
|
-
db.prepare("DELETE FROM transactions WHERE ses = ? AND idx = ?").run(
|
|
149
|
-
tx.ses,
|
|
150
|
-
tx.idx,
|
|
151
|
-
);
|
|
152
|
-
tx.idx -= 1;
|
|
153
|
-
db.prepare(
|
|
154
|
-
"INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)",
|
|
155
|
-
).run(tx.ses, tx.idx, tx.tx);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
db.pragma("user_version = 2");
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (oldVersion <= 2) {
|
|
162
|
-
db.prepare(
|
|
163
|
-
`CREATE TABLE IF NOT EXISTS signatureAfter (
|
|
164
|
-
ses INTEGER,
|
|
165
|
-
idx INTEGER,
|
|
166
|
-
signature TEXT NOT NULL,
|
|
167
|
-
PRIMARY KEY (ses, idx)
|
|
168
|
-
) WITHOUT ROWID;`,
|
|
169
|
-
).run();
|
|
170
|
-
|
|
171
|
-
db.prepare(
|
|
172
|
-
"ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;",
|
|
173
|
-
).run();
|
|
174
|
-
|
|
175
|
-
db.pragma("user_version = 3");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return new SQLiteNode(db, fromLocalNode, toLocalNode);
|
|
15
|
+
return SQLiteNodeBase.create({
|
|
16
|
+
db,
|
|
17
|
+
localNodeName,
|
|
18
|
+
maxBlockingTime: 500,
|
|
19
|
+
});
|
|
179
20
|
}
|
|
180
21
|
}
|
package/dist/sqliteClient.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { Database as DatabaseT } from "better-sqlite3";
|
|
2
|
-
import { type CojsonInternalTypes, type OutgoingSyncQueue, type SessionID } from "cojson";
|
|
3
|
-
import type { DBClientInterfaceSync, SessionRow, SignatureAfterRow, StoredCoValueRow, StoredSessionRow, TransactionRow } from "cojson-storage";
|
|
4
|
-
type RawCoID = CojsonInternalTypes.RawCoID;
|
|
5
|
-
type Signature = CojsonInternalTypes.Signature;
|
|
6
|
-
type Transaction = CojsonInternalTypes.Transaction;
|
|
7
|
-
export type RawCoValueRow = {
|
|
8
|
-
id: CojsonInternalTypes.RawCoID;
|
|
9
|
-
header: string;
|
|
10
|
-
};
|
|
11
|
-
export type RawTransactionRow = {
|
|
12
|
-
ses: number;
|
|
13
|
-
idx: number;
|
|
14
|
-
tx: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function getErrorMessage(error: unknown): string;
|
|
17
|
-
export declare class SQLiteClient implements DBClientInterfaceSync {
|
|
18
|
-
private readonly db;
|
|
19
|
-
private readonly toLocalNode;
|
|
20
|
-
constructor(db: DatabaseT, toLocalNode: OutgoingSyncQueue);
|
|
21
|
-
getCoValue(coValueId: RawCoID): StoredCoValueRow | undefined;
|
|
22
|
-
getCoValueSessions(coValueRowId: number): StoredSessionRow[];
|
|
23
|
-
getSingleCoValueSession(coValueRowId: number, sessionID: SessionID): StoredSessionRow | undefined;
|
|
24
|
-
getNewTransactionInSession(sessionRowId: number, fromIdx: number, toIdx: number): TransactionRow[];
|
|
25
|
-
getSignatures(sessionRowId: number, firstNewTxIdx: number): SignatureAfterRow[];
|
|
26
|
-
addCoValue(msg: CojsonInternalTypes.NewContentMessage): number;
|
|
27
|
-
addSessionUpdate({ sessionUpdate, sessionRow, }: {
|
|
28
|
-
sessionUpdate: SessionRow;
|
|
29
|
-
sessionRow?: StoredSessionRow;
|
|
30
|
-
}): number;
|
|
31
|
-
addTransaction(sessionRowID: number, nextIdx: number, newTransaction: Transaction): void;
|
|
32
|
-
addSignatureAfter({ sessionRowID, idx, signature, }: {
|
|
33
|
-
sessionRowID: number;
|
|
34
|
-
idx: number;
|
|
35
|
-
signature: Signature;
|
|
36
|
-
}): void;
|
|
37
|
-
transaction(operationsCallback: () => unknown): undefined;
|
|
38
|
-
}
|
|
39
|
-
export {};
|
|
40
|
-
//# sourceMappingURL=sqliteClient.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqliteClient.d.ts","sourceRoot":"","sources":["../src/sqliteClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,SAAS,EAEf,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EACV,qBAAqB,EACrB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACf,MAAM,gBAAgB,CAAC;AAExB,KAAK,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC;AAC3C,KAAK,SAAS,GAAG,mBAAmB,CAAC,SAAS,CAAC;AAC/C,KAAK,WAAW,GAAG,mBAAmB,CAAC,WAAW,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,mBAAmB,CAAC,OAAO,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,UAE7C;AAED,qBAAa,YAAa,YAAW,qBAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;gBAEpC,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,iBAAiB;IAKzD,UAAU,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS;IAyB5D,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAM5D,uBAAuB,CACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,SAAS,GACnB,gBAAgB,GAAG,SAAS;IAQ/B,0BAA0B,CACxB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,cAAc,EAAE;IAkBnB,aAAa,CACX,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,iBAAiB,EAAE;IAQtB,UAAU,CAAC,GAAG,EAAE,mBAAmB,CAAC,iBAAiB,GAAG,MAAM;IAQ9D,gBAAgB,CAAC,EACf,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,UAAU,CAAC;QAC1B,UAAU,CAAC,EAAE,gBAAgB,CAAC;KAC/B,GAAG,MAAM;IAkBV,cAAc,CACZ,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,WAAW;IAS7B,iBAAiB,CAAC,EAChB,YAAY,EACZ,GAAG,EACH,SAAS,GACV,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE;IAQ9D,WAAW,CAAC,kBAAkB,EAAE,MAAM,OAAO;CAI9C"}
|
package/dist/sqliteClient.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { logger, } from "cojson";
|
|
2
|
-
export function getErrorMessage(error) {
|
|
3
|
-
return error instanceof Error ? error.message : "Unknown error";
|
|
4
|
-
}
|
|
5
|
-
export class SQLiteClient {
|
|
6
|
-
constructor(db, toLocalNode) {
|
|
7
|
-
this.db = db;
|
|
8
|
-
this.toLocalNode = toLocalNode;
|
|
9
|
-
}
|
|
10
|
-
getCoValue(coValueId) {
|
|
11
|
-
const coValueRow = this.db
|
|
12
|
-
.prepare("SELECT * FROM coValues WHERE id = ?")
|
|
13
|
-
.get(coValueId);
|
|
14
|
-
if (!coValueRow)
|
|
15
|
-
return;
|
|
16
|
-
try {
|
|
17
|
-
const parsedHeader = (coValueRow?.header &&
|
|
18
|
-
JSON.parse(coValueRow.header));
|
|
19
|
-
return {
|
|
20
|
-
...coValueRow,
|
|
21
|
-
header: parsedHeader,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
const headerValue = coValueRow?.header ?? "";
|
|
26
|
-
logger.warn(`Invalid JSON in header: ${headerValue}`, {
|
|
27
|
-
id: coValueId,
|
|
28
|
-
err: e,
|
|
29
|
-
});
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
getCoValueSessions(coValueRowId) {
|
|
34
|
-
return this.db
|
|
35
|
-
.prepare("SELECT * FROM sessions WHERE coValue = ?")
|
|
36
|
-
.all(coValueRowId);
|
|
37
|
-
}
|
|
38
|
-
getSingleCoValueSession(coValueRowId, sessionID) {
|
|
39
|
-
return this.db
|
|
40
|
-
.prepare("SELECT * FROM sessions WHERE coValue = ? AND sessionID = ?")
|
|
41
|
-
.get(coValueRowId, sessionID);
|
|
42
|
-
}
|
|
43
|
-
getNewTransactionInSession(sessionRowId, fromIdx, toIdx) {
|
|
44
|
-
const txs = this.db
|
|
45
|
-
.prepare("SELECT * FROM transactions WHERE ses = ? AND idx >= ? AND idx <= ?")
|
|
46
|
-
.all(sessionRowId, fromIdx, toIdx);
|
|
47
|
-
try {
|
|
48
|
-
return txs.map((transactionRow) => ({
|
|
49
|
-
...transactionRow,
|
|
50
|
-
tx: JSON.parse(transactionRow.tx),
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
catch (e) {
|
|
54
|
-
logger.warn("Invalid JSON in transaction", { err: e });
|
|
55
|
-
return [];
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
getSignatures(sessionRowId, firstNewTxIdx) {
|
|
59
|
-
return this.db
|
|
60
|
-
.prepare("SELECT * FROM signatureAfter WHERE ses = ? AND idx >= ?")
|
|
61
|
-
.all(sessionRowId, firstNewTxIdx);
|
|
62
|
-
}
|
|
63
|
-
addCoValue(msg) {
|
|
64
|
-
return this.db
|
|
65
|
-
.prepare("INSERT INTO coValues (id, header) VALUES (?, ?)")
|
|
66
|
-
.run(msg.id, JSON.stringify(msg.header)).lastInsertRowid;
|
|
67
|
-
}
|
|
68
|
-
addSessionUpdate({ sessionUpdate, sessionRow, }) {
|
|
69
|
-
return this.db
|
|
70
|
-
.prepare(`INSERT INTO sessions (coValue, sessionID, lastIdx, lastSignature, bytesSinceLastSignature) VALUES (?, ?, ?, ?, ?)
|
|
71
|
-
ON CONFLICT(coValue, sessionID) DO UPDATE SET lastIdx=excluded.lastIdx, lastSignature=excluded.lastSignature, bytesSinceLastSignature=excluded.bytesSinceLastSignature
|
|
72
|
-
RETURNING rowID`)
|
|
73
|
-
.get(sessionUpdate.coValue, sessionUpdate.sessionID, sessionUpdate.lastIdx, sessionUpdate.lastSignature, sessionUpdate.bytesSinceLastSignature).rowID;
|
|
74
|
-
}
|
|
75
|
-
addTransaction(sessionRowID, nextIdx, newTransaction) {
|
|
76
|
-
this.db
|
|
77
|
-
.prepare("INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)")
|
|
78
|
-
.run(sessionRowID, nextIdx, JSON.stringify(newTransaction));
|
|
79
|
-
}
|
|
80
|
-
addSignatureAfter({ sessionRowID, idx, signature, }) {
|
|
81
|
-
this.db
|
|
82
|
-
.prepare("INSERT INTO signatureAfter (ses, idx, signature) VALUES (?, ?, ?)")
|
|
83
|
-
.run(sessionRowID, idx, signature);
|
|
84
|
-
}
|
|
85
|
-
transaction(operationsCallback) {
|
|
86
|
-
this.db.transaction(operationsCallback)();
|
|
87
|
-
return undefined;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
//# sourceMappingURL=sqliteClient.js.map
|
package/dist/sqliteClient.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqliteClient.js","sourceRoot":"","sources":["../src/sqliteClient.ts"],"names":[],"mappings":"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"}
|
package/src/sqliteClient.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import type { Database as DatabaseT } from "better-sqlite3";
|
|
2
|
-
import {
|
|
3
|
-
type CojsonInternalTypes,
|
|
4
|
-
type OutgoingSyncQueue,
|
|
5
|
-
type SessionID,
|
|
6
|
-
logger,
|
|
7
|
-
} from "cojson";
|
|
8
|
-
import type {
|
|
9
|
-
DBClientInterfaceSync,
|
|
10
|
-
SessionRow,
|
|
11
|
-
SignatureAfterRow,
|
|
12
|
-
StoredCoValueRow,
|
|
13
|
-
StoredSessionRow,
|
|
14
|
-
TransactionRow,
|
|
15
|
-
} from "cojson-storage";
|
|
16
|
-
|
|
17
|
-
type RawCoID = CojsonInternalTypes.RawCoID;
|
|
18
|
-
type Signature = CojsonInternalTypes.Signature;
|
|
19
|
-
type Transaction = CojsonInternalTypes.Transaction;
|
|
20
|
-
|
|
21
|
-
export type RawCoValueRow = {
|
|
22
|
-
id: CojsonInternalTypes.RawCoID;
|
|
23
|
-
header: string;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type RawTransactionRow = {
|
|
27
|
-
ses: number;
|
|
28
|
-
idx: number;
|
|
29
|
-
tx: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export function getErrorMessage(error: unknown) {
|
|
33
|
-
return error instanceof Error ? error.message : "Unknown error";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class SQLiteClient implements DBClientInterfaceSync {
|
|
37
|
-
private readonly db: DatabaseT;
|
|
38
|
-
private readonly toLocalNode: OutgoingSyncQueue;
|
|
39
|
-
|
|
40
|
-
constructor(db: DatabaseT, toLocalNode: OutgoingSyncQueue) {
|
|
41
|
-
this.db = db;
|
|
42
|
-
this.toLocalNode = toLocalNode;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
getCoValue(coValueId: RawCoID): StoredCoValueRow | undefined {
|
|
46
|
-
const coValueRow = this.db
|
|
47
|
-
.prepare("SELECT * FROM coValues WHERE id = ?")
|
|
48
|
-
.get(coValueId) as RawCoValueRow & { rowID: number };
|
|
49
|
-
|
|
50
|
-
if (!coValueRow) return;
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
const parsedHeader = (coValueRow?.header &&
|
|
54
|
-
JSON.parse(coValueRow.header)) as CojsonInternalTypes.CoValueHeader;
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
...coValueRow,
|
|
58
|
-
header: parsedHeader,
|
|
59
|
-
};
|
|
60
|
-
} catch (e) {
|
|
61
|
-
const headerValue = coValueRow?.header ?? "";
|
|
62
|
-
logger.warn(`Invalid JSON in header: ${headerValue}`, {
|
|
63
|
-
id: coValueId,
|
|
64
|
-
err: e,
|
|
65
|
-
});
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
getCoValueSessions(coValueRowId: number): StoredSessionRow[] {
|
|
71
|
-
return this.db
|
|
72
|
-
.prepare<number>("SELECT * FROM sessions WHERE coValue = ?")
|
|
73
|
-
.all(coValueRowId) as StoredSessionRow[];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
getSingleCoValueSession(
|
|
77
|
-
coValueRowId: number,
|
|
78
|
-
sessionID: SessionID,
|
|
79
|
-
): StoredSessionRow | undefined {
|
|
80
|
-
return this.db
|
|
81
|
-
.prepare<[number, string]>(
|
|
82
|
-
"SELECT * FROM sessions WHERE coValue = ? AND sessionID = ?",
|
|
83
|
-
)
|
|
84
|
-
.get(coValueRowId, sessionID) as StoredSessionRow | undefined;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
getNewTransactionInSession(
|
|
88
|
-
sessionRowId: number,
|
|
89
|
-
fromIdx: number,
|
|
90
|
-
toIdx: number,
|
|
91
|
-
): TransactionRow[] {
|
|
92
|
-
const txs = this.db
|
|
93
|
-
.prepare<[number, number, number]>(
|
|
94
|
-
"SELECT * FROM transactions WHERE ses = ? AND idx >= ? AND idx <= ?",
|
|
95
|
-
)
|
|
96
|
-
.all(sessionRowId, fromIdx, toIdx) as RawTransactionRow[];
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
return txs.map((transactionRow) => ({
|
|
100
|
-
...transactionRow,
|
|
101
|
-
tx: JSON.parse(transactionRow.tx) as Transaction,
|
|
102
|
-
}));
|
|
103
|
-
} catch (e) {
|
|
104
|
-
logger.warn("Invalid JSON in transaction", { err: e });
|
|
105
|
-
return [];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
getSignatures(
|
|
110
|
-
sessionRowId: number,
|
|
111
|
-
firstNewTxIdx: number,
|
|
112
|
-
): SignatureAfterRow[] {
|
|
113
|
-
return this.db
|
|
114
|
-
.prepare<[number, number]>(
|
|
115
|
-
"SELECT * FROM signatureAfter WHERE ses = ? AND idx >= ?",
|
|
116
|
-
)
|
|
117
|
-
.all(sessionRowId, firstNewTxIdx) as SignatureAfterRow[];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
addCoValue(msg: CojsonInternalTypes.NewContentMessage): number {
|
|
121
|
-
return this.db
|
|
122
|
-
.prepare<[CojsonInternalTypes.RawCoID, string]>(
|
|
123
|
-
"INSERT INTO coValues (id, header) VALUES (?, ?)",
|
|
124
|
-
)
|
|
125
|
-
.run(msg.id, JSON.stringify(msg.header)).lastInsertRowid as number;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
addSessionUpdate({
|
|
129
|
-
sessionUpdate,
|
|
130
|
-
sessionRow,
|
|
131
|
-
}: {
|
|
132
|
-
sessionUpdate: SessionRow;
|
|
133
|
-
sessionRow?: StoredSessionRow;
|
|
134
|
-
}): number {
|
|
135
|
-
return (
|
|
136
|
-
this.db
|
|
137
|
-
.prepare<[number, string, number, string, number | undefined]>(
|
|
138
|
-
`INSERT INTO sessions (coValue, sessionID, lastIdx, lastSignature, bytesSinceLastSignature) VALUES (?, ?, ?, ?, ?)
|
|
139
|
-
ON CONFLICT(coValue, sessionID) DO UPDATE SET lastIdx=excluded.lastIdx, lastSignature=excluded.lastSignature, bytesSinceLastSignature=excluded.bytesSinceLastSignature
|
|
140
|
-
RETURNING rowID`,
|
|
141
|
-
)
|
|
142
|
-
.get(
|
|
143
|
-
sessionUpdate.coValue,
|
|
144
|
-
sessionUpdate.sessionID,
|
|
145
|
-
sessionUpdate.lastIdx,
|
|
146
|
-
sessionUpdate.lastSignature,
|
|
147
|
-
sessionUpdate.bytesSinceLastSignature,
|
|
148
|
-
) as { rowID: number }
|
|
149
|
-
).rowID;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
addTransaction(
|
|
153
|
-
sessionRowID: number,
|
|
154
|
-
nextIdx: number,
|
|
155
|
-
newTransaction: Transaction,
|
|
156
|
-
) {
|
|
157
|
-
this.db
|
|
158
|
-
.prepare<[number, number, string]>(
|
|
159
|
-
"INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)",
|
|
160
|
-
)
|
|
161
|
-
.run(sessionRowID, nextIdx, JSON.stringify(newTransaction));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
addSignatureAfter({
|
|
165
|
-
sessionRowID,
|
|
166
|
-
idx,
|
|
167
|
-
signature,
|
|
168
|
-
}: { sessionRowID: number; idx: number; signature: Signature }) {
|
|
169
|
-
this.db
|
|
170
|
-
.prepare<[number, number, string]>(
|
|
171
|
-
"INSERT INTO signatureAfter (ses, idx, signature) VALUES (?, ?, ?)",
|
|
172
|
-
)
|
|
173
|
-
.run(sessionRowID, idx, signature);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
transaction(operationsCallback: () => unknown) {
|
|
177
|
-
this.db.transaction(operationsCallback)();
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
}
|