@fedify/sqlite 1.8.1-pr.318.1225
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/LICENSE +20 -0
- package/README.md +38 -0
- package/adapter.ts +44 -0
- package/deno.json +27 -0
- package/dist/_virtual/rolldown_runtime.js +30 -0
- package/dist/adapter.d.ts +48 -0
- package/dist/kv.d.ts +72 -0
- package/dist/kv.js +183 -0
- package/dist/mod.d.ts +3 -0
- package/dist/mod.js +6 -0
- package/dist/node_modules/.pnpm/@js-temporal_polyfill@0.5.1/node_modules/@js-temporal/polyfill/dist/index.esm.js +5795 -0
- package/dist/node_modules/.pnpm/jsbi@4.3.2/node_modules/jsbi/dist/jsbi-cjs.js +1139 -0
- package/dist/sqlite.bun.d.ts +24 -0
- package/dist/sqlite.bun.js +39 -0
- package/dist/sqlite.node.d.ts +24 -0
- package/dist/sqlite.node.js +41 -0
- package/kv.test.ts +312 -0
- package/kv.ts +278 -0
- package/mod.ts +5 -0
- package/package.json +69 -0
- package/sqlite.bun.ts +45 -0
- package/sqlite.node.ts +48 -0
- package/tsdown.config.ts +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2024–2025 Hong Minhee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
@fedify/sqlite: SQLite drivers for Fedify
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
This package provides a SQLite-based key–value store implementation.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
### Node.js
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
12
|
+
import { SqliteKvStore } from '@fedify/sqlite';
|
|
13
|
+
|
|
14
|
+
const db = new DatabaseSync('./data.db');
|
|
15
|
+
const store = new SqliteKvStore(db);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Bun
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Database } from 'bun:sqlite';
|
|
22
|
+
import { SqliteKvStore } from '@fedify/sqlite';
|
|
23
|
+
|
|
24
|
+
const db = new Database('./data.db');
|
|
25
|
+
const store = new SqliteKvStore(db);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Deno
|
|
29
|
+
|
|
30
|
+
For Deno, you can directly import from `@fedify/sqlite` when using the import map in `deno.json`:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { DB } from 'https://deno.land/x/sqlite@v3.7.0/mod.ts';
|
|
34
|
+
import { SqliteKvStore } from '@fedify/sqlite';
|
|
35
|
+
|
|
36
|
+
const db = new DB('./data.db');
|
|
37
|
+
const store = new SqliteKvStore(db);
|
|
38
|
+
```
|
package/adapter.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite database adapter.
|
|
3
|
+
*
|
|
4
|
+
* An abstract interface for SQLite database for different runtime environments.
|
|
5
|
+
*/
|
|
6
|
+
export interface SqliteDatabaseAdapter {
|
|
7
|
+
/**
|
|
8
|
+
* Prepares a SQL statement.
|
|
9
|
+
* @param sql - The SQL statement to prepare.
|
|
10
|
+
*/
|
|
11
|
+
prepare(sql: string): SqliteStatementAdapter;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Executes a SQL statement.
|
|
15
|
+
* @param sql - The SQL statement to execute.
|
|
16
|
+
*/
|
|
17
|
+
exec(sql: string): void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Closes the database connection.
|
|
21
|
+
*/
|
|
22
|
+
close(): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SqliteStatementAdapter {
|
|
26
|
+
/**
|
|
27
|
+
* Executes a SQL statement and returns the number of changes made to the database.
|
|
28
|
+
* @param params - The parameters to bind to the SQL statement.
|
|
29
|
+
*/
|
|
30
|
+
run(...params: unknown[]): { changes: number; lastInsertRowid: number };
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Executes a SQL statement and returns the first row of the result set.
|
|
34
|
+
* @param params - The parameters to bind to the SQL statement.
|
|
35
|
+
* @returns The first row of the result set, or `undefined` if the result set is empty.
|
|
36
|
+
*/
|
|
37
|
+
get(...params: unknown[]): unknown | undefined;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Executes a SQL statement and returns all rows of the result set.
|
|
41
|
+
* @param params - The parameters to bind to the SQL statement.
|
|
42
|
+
*/
|
|
43
|
+
all(...params: unknown[]): unknown[];
|
|
44
|
+
}
|
package/deno.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fedify/sqlite",
|
|
3
|
+
"version": "1.8.1-pr.318.1225+27a86736",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./mod.ts",
|
|
7
|
+
"./kv": "./kv.ts"
|
|
8
|
+
},
|
|
9
|
+
"imports": {
|
|
10
|
+
"@fedify/sqlite": "./mod.ts",
|
|
11
|
+
"@fedify/sqlite/": "./",
|
|
12
|
+
"#sqlite": "./sqlite.node.ts"
|
|
13
|
+
},
|
|
14
|
+
"exclude": [
|
|
15
|
+
"node_modules",
|
|
16
|
+
"sqlite.bun.ts"
|
|
17
|
+
],
|
|
18
|
+
"publish": {
|
|
19
|
+
"exclude": [
|
|
20
|
+
"!dist/"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"tasks": {
|
|
24
|
+
"check": "deno fmt --check && deno lint && deno check *.ts",
|
|
25
|
+
"test": "deno test --allow-net --allow-env --doc --no-check=leaks"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
3
|
+
|
|
4
|
+
//#region rolldown:runtime
|
|
5
|
+
var __create = Object.create;
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __commonJS = (cb, mod) => function() {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
16
|
+
key = keys[i];
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
18
|
+
get: ((k) => from[k]).bind(null, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
25
|
+
value: mod,
|
|
26
|
+
enumerable: true
|
|
27
|
+
}) : target, mod));
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { __commonJS, __toESM };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
|
|
3
|
+
//#region adapter.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SQLite database adapter.
|
|
7
|
+
*
|
|
8
|
+
* An abstract interface for SQLite database for different runtime environments.
|
|
9
|
+
*/
|
|
10
|
+
interface SqliteDatabaseAdapter {
|
|
11
|
+
/**
|
|
12
|
+
* Prepares a SQL statement.
|
|
13
|
+
* @param sql - The SQL statement to prepare.
|
|
14
|
+
*/
|
|
15
|
+
prepare(sql: string): SqliteStatementAdapter;
|
|
16
|
+
/**
|
|
17
|
+
* Executes a SQL statement.
|
|
18
|
+
* @param sql - The SQL statement to execute.
|
|
19
|
+
*/
|
|
20
|
+
exec(sql: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Closes the database connection.
|
|
23
|
+
*/
|
|
24
|
+
close(): void;
|
|
25
|
+
}
|
|
26
|
+
interface SqliteStatementAdapter {
|
|
27
|
+
/**
|
|
28
|
+
* Executes a SQL statement and returns the number of changes made to the database.
|
|
29
|
+
* @param params - The parameters to bind to the SQL statement.
|
|
30
|
+
*/
|
|
31
|
+
run(...params: unknown[]): {
|
|
32
|
+
changes: number;
|
|
33
|
+
lastInsertRowid: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Executes a SQL statement and returns the first row of the result set.
|
|
37
|
+
* @param params - The parameters to bind to the SQL statement.
|
|
38
|
+
* @returns The first row of the result set, or `undefined` if the result set is empty.
|
|
39
|
+
*/
|
|
40
|
+
get(...params: unknown[]): unknown | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Executes a SQL statement and returns all rows of the result set.
|
|
43
|
+
* @param params - The parameters to bind to the SQL statement.
|
|
44
|
+
*/
|
|
45
|
+
all(...params: unknown[]): unknown[];
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { SqliteDatabaseAdapter, SqliteStatementAdapter };
|
package/dist/kv.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import { PlatformDatabase } from "#sqlite";
|
|
3
|
+
import { KvKey, KvStore, KvStoreSetOptions } from "@fedify/fedify";
|
|
4
|
+
|
|
5
|
+
//#region kv.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Options for the SQLite key–value store.
|
|
8
|
+
*/
|
|
9
|
+
interface SqliteKvStoreOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The table name to use for the key–value store.
|
|
12
|
+
* Only letters, digits, and underscores are allowed.
|
|
13
|
+
* `"fedify_kv"` by default.
|
|
14
|
+
* @default `"fedify_kv"`
|
|
15
|
+
*/
|
|
16
|
+
tableName?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the table has been initialized. `false` by default.
|
|
19
|
+
* @default `false`
|
|
20
|
+
*/
|
|
21
|
+
initialized?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A key–value store that uses SQLite as the underlying storage.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { createFederation } from "@fedify/fedify";
|
|
29
|
+
* import { SqliteKvStore } from "@fedify/sqlite";
|
|
30
|
+
* import { DatabaseSync } from "node:sqlite";
|
|
31
|
+
*
|
|
32
|
+
* const db = new DatabaseSync(":memory:");
|
|
33
|
+
* const federation = createFederation({
|
|
34
|
+
* // ...
|
|
35
|
+
* kv: new SqliteKvStore(db),
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare class SqliteKvStore implements KvStore {
|
|
40
|
+
#private;
|
|
41
|
+
readonly db: PlatformDatabase;
|
|
42
|
+
readonly options: SqliteKvStoreOptions;
|
|
43
|
+
constructor(db: PlatformDatabase, options?: SqliteKvStoreOptions);
|
|
44
|
+
/**
|
|
45
|
+
* {@inheritDoc KvStore.get}
|
|
46
|
+
*/
|
|
47
|
+
get<T = unknown>(key: KvKey): Promise<T | undefined>;
|
|
48
|
+
/**
|
|
49
|
+
* {@inheritDoc KvStore.set}
|
|
50
|
+
*/
|
|
51
|
+
set(key: KvKey, value: unknown, options?: KvStoreSetOptions): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* {@inheritDoc KvStore.delete}
|
|
54
|
+
*/
|
|
55
|
+
delete(key: KvKey): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* {@inheritDoc KvStore.cas}
|
|
58
|
+
*/
|
|
59
|
+
cas(key: KvKey, expectedValue: unknown, newValue: unknown, options?: KvStoreSetOptions): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Creates the table used by the key–value store if it does not already exist.
|
|
62
|
+
* Does nothing if the table already exists.
|
|
63
|
+
*/
|
|
64
|
+
initialize(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Drops the table used by the key–value store. Does nothing if the table
|
|
67
|
+
* does not exist.
|
|
68
|
+
*/
|
|
69
|
+
drop(): void;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { SqliteKvStore, SqliteKvStoreOptions };
|
package/dist/kv.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
|
|
2
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
3
|
+
|
|
4
|
+
import { qi } from "./node_modules/.pnpm/@js-temporal_polyfill@0.5.1/node_modules/@js-temporal/polyfill/dist/index.esm.js";
|
|
5
|
+
import { SqliteDatabase } from "#sqlite";
|
|
6
|
+
import { getLogger } from "@logtape/logtape";
|
|
7
|
+
import { isEqual } from "es-toolkit";
|
|
8
|
+
|
|
9
|
+
//#region kv.ts
|
|
10
|
+
const logger = getLogger([
|
|
11
|
+
"fedify",
|
|
12
|
+
"sqlite",
|
|
13
|
+
"kv"
|
|
14
|
+
]);
|
|
15
|
+
/**
|
|
16
|
+
* A key–value store that uses SQLite as the underlying storage.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { createFederation } from "@fedify/fedify";
|
|
21
|
+
* import { SqliteKvStore } from "@fedify/sqlite";
|
|
22
|
+
* import { DatabaseSync } from "node:sqlite";
|
|
23
|
+
*
|
|
24
|
+
* const db = new DatabaseSync(":memory:");
|
|
25
|
+
* const federation = createFederation({
|
|
26
|
+
* // ...
|
|
27
|
+
* kv: new SqliteKvStore(db),
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
var SqliteKvStore = class SqliteKvStore {
|
|
32
|
+
static #defaultTableName = "fedify_kv";
|
|
33
|
+
static #tableNameRegex = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
34
|
+
#db;
|
|
35
|
+
#tableName;
|
|
36
|
+
#initialized;
|
|
37
|
+
constructor(db, options = {}) {
|
|
38
|
+
this.db = db;
|
|
39
|
+
this.options = options;
|
|
40
|
+
this.#db = new SqliteDatabase(db);
|
|
41
|
+
this.#initialized = options.initialized ?? false;
|
|
42
|
+
this.#tableName = options.tableName ?? SqliteKvStore.#defaultTableName;
|
|
43
|
+
if (!SqliteKvStore.#tableNameRegex.test(this.#tableName)) throw new Error(`Invalid table name for the key–value store: ${this.#tableName}`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* {@inheritDoc KvStore.get}
|
|
47
|
+
*/
|
|
48
|
+
async get(key) {
|
|
49
|
+
this.initialize();
|
|
50
|
+
const encodedKey = this.#encodeKey(key);
|
|
51
|
+
const now = qi.Now.instant().epochMilliseconds;
|
|
52
|
+
const result = this.#db.prepare(`
|
|
53
|
+
SELECT value
|
|
54
|
+
FROM "${this.#tableName}"
|
|
55
|
+
WHERE key = ? AND (expires IS NULL OR expires > ?)
|
|
56
|
+
`).get(encodedKey, now);
|
|
57
|
+
if (!result) return void 0;
|
|
58
|
+
return this.#decodeValue(result.value);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* {@inheritDoc KvStore.set}
|
|
62
|
+
*/
|
|
63
|
+
async set(key, value, options) {
|
|
64
|
+
this.initialize();
|
|
65
|
+
if (value === void 0) return;
|
|
66
|
+
const encodedKey = this.#encodeKey(key);
|
|
67
|
+
const encodedValue = this.#encodeValue(value);
|
|
68
|
+
const now = qi.Now.instant().epochMilliseconds;
|
|
69
|
+
const expiresAt = options?.ttl !== void 0 ? now + options.ttl.total({ unit: "milliseconds" }) : null;
|
|
70
|
+
this.#db.prepare(`INSERT INTO "${this.#tableName}" (key, value, created, expires)
|
|
71
|
+
VALUES (?, ?, ?, ?)
|
|
72
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
73
|
+
value = excluded.value,
|
|
74
|
+
expires = excluded.expires`).run(encodedKey, encodedValue, now, expiresAt);
|
|
75
|
+
this.#expire();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* {@inheritDoc KvStore.delete}
|
|
80
|
+
*/
|
|
81
|
+
async delete(key) {
|
|
82
|
+
this.initialize();
|
|
83
|
+
const encodedKey = this.#encodeKey(key);
|
|
84
|
+
this.#db.prepare(`
|
|
85
|
+
DELETE FROM "${this.#tableName}" WHERE key = ?
|
|
86
|
+
`).run(encodedKey);
|
|
87
|
+
this.#expire();
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* {@inheritDoc KvStore.cas}
|
|
92
|
+
*/
|
|
93
|
+
async cas(key, expectedValue, newValue, options) {
|
|
94
|
+
this.initialize();
|
|
95
|
+
const encodedKey = this.#encodeKey(key);
|
|
96
|
+
const now = qi.Now.instant().epochMilliseconds;
|
|
97
|
+
const expiresAt = options?.ttl !== void 0 ? now + options.ttl.total({ unit: "milliseconds" }) : null;
|
|
98
|
+
try {
|
|
99
|
+
this.#db.exec("BEGIN IMMEDIATE");
|
|
100
|
+
const currentResult = this.#db.prepare(`
|
|
101
|
+
SELECT value
|
|
102
|
+
FROM "${this.#tableName}"
|
|
103
|
+
WHERE key = ? AND (expires IS NULL OR expires > ?)
|
|
104
|
+
`).get(encodedKey, now);
|
|
105
|
+
const currentValue = currentResult === void 0 ? void 0 : this.#decodeValue(currentResult.value);
|
|
106
|
+
if (!isEqual(currentValue, expectedValue)) {
|
|
107
|
+
this.#db.exec("ROLLBACK");
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
if (newValue === void 0) this.#db.prepare(`
|
|
111
|
+
DELETE FROM "${this.#tableName}" WHERE key = ?
|
|
112
|
+
`).run(encodedKey);
|
|
113
|
+
else {
|
|
114
|
+
const newValueJson = this.#encodeValue(newValue);
|
|
115
|
+
this.#db.prepare(`
|
|
116
|
+
INSERT INTO "${this.#tableName}" (key, value, created, expires)
|
|
117
|
+
VALUES (?, ?, ?, ?)
|
|
118
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
119
|
+
value = excluded.value,
|
|
120
|
+
expires = excluded.expires
|
|
121
|
+
`).run(encodedKey, newValueJson, now, expiresAt);
|
|
122
|
+
}
|
|
123
|
+
this.#db.exec("COMMIT");
|
|
124
|
+
this.#expire();
|
|
125
|
+
return true;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.#db.exec("ROLLBACK");
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Creates the table used by the key–value store if it does not already exist.
|
|
133
|
+
* Does nothing if the table already exists.
|
|
134
|
+
*/
|
|
135
|
+
initialize() {
|
|
136
|
+
if (this.#initialized) return;
|
|
137
|
+
logger.debug("Initializing the key–value store table {tableName}...", { tableName: this.#tableName });
|
|
138
|
+
this.#db.exec(`
|
|
139
|
+
CREATE TABLE IF NOT EXISTS "${this.#tableName}" (
|
|
140
|
+
key TEXT PRIMARY KEY,
|
|
141
|
+
value TEXT NOT NULL,
|
|
142
|
+
created INTEGER NOT NULL,
|
|
143
|
+
expires INTEGER
|
|
144
|
+
)
|
|
145
|
+
`);
|
|
146
|
+
this.#db.exec(`
|
|
147
|
+
CREATE INDEX IF NOT EXISTS "idx_${this.#tableName}_expires"
|
|
148
|
+
ON "${this.#tableName}" (expires)
|
|
149
|
+
`);
|
|
150
|
+
this.#initialized = true;
|
|
151
|
+
logger.debug("Initialized the key–value store table {tableName}.", { tableName: this.#tableName });
|
|
152
|
+
}
|
|
153
|
+
#expire() {
|
|
154
|
+
const now = qi.Now.instant().epochMilliseconds;
|
|
155
|
+
this.#db.prepare(`
|
|
156
|
+
DELETE FROM "${this.#tableName}"
|
|
157
|
+
WHERE expires IS NOT NULL AND expires <= ?
|
|
158
|
+
`).run(now);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Drops the table used by the key–value store. Does nothing if the table
|
|
162
|
+
* does not exist.
|
|
163
|
+
*/
|
|
164
|
+
drop() {
|
|
165
|
+
this.#db.exec(`DROP TABLE IF EXISTS "${this.#tableName}"`);
|
|
166
|
+
this.#initialized = false;
|
|
167
|
+
}
|
|
168
|
+
#encodeKey(key) {
|
|
169
|
+
return JSON.stringify(key);
|
|
170
|
+
}
|
|
171
|
+
#decodeKey(key) {
|
|
172
|
+
return JSON.parse(key);
|
|
173
|
+
}
|
|
174
|
+
#encodeValue(value) {
|
|
175
|
+
return JSON.stringify(value);
|
|
176
|
+
}
|
|
177
|
+
#decodeValue(value) {
|
|
178
|
+
return JSON.parse(value);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
//#endregion
|
|
183
|
+
export { SqliteKvStore };
|
package/dist/mod.d.ts
ADDED