@alstate/sqlite 0.1.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alstate contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # `@alstate/sqlite`
2
+
3
+ Experimental SQLite persistence adapter for `@alstate/core`, implemented with
4
+ Node.js `node:sqlite`.
5
+
6
+ ```ts
7
+ import { SqliteLearningStore } from "@alstate/sqlite";
8
+
9
+ const store = new SqliteLearningStore("learning.db");
10
+ ```
11
+
12
+ Requires Node.js 22.13 or later. The adapter applies schema migrations on open,
13
+ uses transactions for composite writes and rejects stale review revisions.
14
+
15
+ MIT
@@ -0,0 +1,2 @@
1
+ export { SqliteLearningStore } from "./sqlite-learning-store.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { SqliteLearningStore } from "./sqlite-learning-store.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ export declare function migrateDatabase(database: DatabaseSync): void;
3
+ //# sourceMappingURL=migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAmEhD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAkC5D"}
@@ -0,0 +1,96 @@
1
+ const migrations = [
2
+ {
3
+ version: 1,
4
+ name: "learning_engine_schema",
5
+ sql: `
6
+ CREATE TABLE engine_items (
7
+ id INTEGER PRIMARY KEY,
8
+ data_json TEXT NOT NULL CHECK (json_valid(data_json))
9
+ ) STRICT;
10
+
11
+ CREATE TABLE engine_algorithms (
12
+ id INTEGER PRIMARY KEY,
13
+ name TEXT NOT NULL UNIQUE CHECK (length(trim(name)) > 0),
14
+ description TEXT,
15
+ version TEXT NOT NULL CHECK (length(trim(version)) > 0),
16
+ config_json TEXT NOT NULL CHECK (json_valid(config_json))
17
+ ) STRICT;
18
+
19
+ CREATE TABLE engine_states (
20
+ id INTEGER PRIMARY KEY,
21
+ learning_item_id INTEGER NOT NULL,
22
+ algorithm_id INTEGER NOT NULL,
23
+ due_at TEXT NOT NULL,
24
+ state_json TEXT NOT NULL CHECK (json_valid(state_json)),
25
+ UNIQUE (learning_item_id, algorithm_id),
26
+ FOREIGN KEY (learning_item_id)
27
+ REFERENCES engine_items (id) ON DELETE CASCADE,
28
+ FOREIGN KEY (algorithm_id)
29
+ REFERENCES engine_algorithms (id) ON DELETE RESTRICT
30
+ ) STRICT;
31
+
32
+ CREATE INDEX engine_states_due_idx
33
+ ON engine_states (algorithm_id, due_at, learning_item_id);
34
+
35
+ CREATE TABLE engine_reviews (
36
+ id INTEGER PRIMARY KEY,
37
+ learning_item_id INTEGER NOT NULL,
38
+ algorithm_id INTEGER NOT NULL,
39
+ rating TEXT NOT NULL CHECK (length(trim(rating)) > 0),
40
+ review_json TEXT NOT NULL CHECK (json_valid(review_json)),
41
+ response_time_ms INTEGER CHECK (
42
+ response_time_ms IS NULL OR response_time_ms >= 0
43
+ ),
44
+ reviewed_at TEXT NOT NULL,
45
+ FOREIGN KEY (learning_item_id)
46
+ REFERENCES engine_items (id) ON DELETE CASCADE,
47
+ FOREIGN KEY (algorithm_id)
48
+ REFERENCES engine_algorithms (id) ON DELETE RESTRICT
49
+ ) STRICT;
50
+
51
+ CREATE INDEX engine_reviews_item_time_idx
52
+ ON engine_reviews (learning_item_id, reviewed_at DESC, id DESC);
53
+ `,
54
+ },
55
+ {
56
+ version: 2,
57
+ name: "optimistic_review_concurrency",
58
+ sql: `
59
+ ALTER TABLE engine_states
60
+ ADD COLUMN revision INTEGER NOT NULL DEFAULT 0
61
+ CHECK (revision >= 0);
62
+ `,
63
+ },
64
+ ];
65
+ export function migrateDatabase(database) {
66
+ database.exec(`
67
+ CREATE TABLE IF NOT EXISTS engine_schema_migrations (
68
+ version INTEGER PRIMARY KEY,
69
+ name TEXT NOT NULL UNIQUE,
70
+ applied_at TEXT NOT NULL
71
+ ) STRICT;
72
+ `);
73
+ const applied = new Set(database
74
+ .prepare("SELECT version FROM engine_schema_migrations")
75
+ .all().map((row) => row.version));
76
+ const record = database.prepare(`
77
+ INSERT INTO engine_schema_migrations (version, name, applied_at)
78
+ VALUES (?, ?, ?)
79
+ `);
80
+ for (const migration of migrations) {
81
+ if (applied.has(migration.version)) {
82
+ continue;
83
+ }
84
+ database.exec("BEGIN IMMEDIATE");
85
+ try {
86
+ database.exec(migration.sql);
87
+ record.run(migration.version, migration.name, new Date().toISOString());
88
+ database.exec("COMMIT");
89
+ }
90
+ catch (error) {
91
+ database.exec("ROLLBACK");
92
+ throw error;
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG;IACjB;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,wBAAwB;QAC9B,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgDJ;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,+BAA+B;QACrC,GAAG,EAAE;;;;KAIJ;KACF;CACO,CAAC;AAEX,MAAM,UAAU,eAAe,CAAC,QAAsB;IACpD,QAAQ,CAAC,IAAI,CAAC;;;;;;GAMb,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAEnB,QAAQ;SACL,OAAO,CAAC,8CAA8C,CAAC;SACvD,GAAG,EACP,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAC5B,CAAC;IACF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC;;;GAG/B,CAAC,CAAC;IAEH,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YACxE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1B,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { AlgorithmRegistration, DueStoredItem, LearningStore, NewItemWithState, RegisteredAlgorithm, StateUpdate, NewReviewRecord } from "@alstate/core";
2
+ import { type AlgorithmId, type JsonObject, type LearningItem, type LearningItemId, type LearningState, type PageQuery, type ReviewRecord } from "@alstate/core";
3
+ export declare class SqliteLearningStore implements LearningStore {
4
+ #private;
5
+ constructor(path?: string);
6
+ registerAlgorithm(registration: AlgorithmRegistration): Promise<RegisteredAlgorithm>;
7
+ createItem(input: NewItemWithState): Promise<LearningItem>;
8
+ findItem(id: LearningItemId, registeredAlgorithmId: AlgorithmId): Promise<LearningItem | null>;
9
+ listItems(registeredAlgorithmId: AlgorithmId, query?: PageQuery): Promise<readonly LearningItem[]>;
10
+ updateItem(id: LearningItemId, registeredAlgorithmId: AlgorithmId, data: JsonObject): Promise<LearningItem | null>;
11
+ deleteItem(id: LearningItemId, registeredAlgorithmId: AlgorithmId): Promise<boolean>;
12
+ findState(itemId: LearningItemId, registeredAlgorithmId: AlgorithmId): Promise<LearningState | null>;
13
+ listDue(input: {
14
+ readonly algorithmId: AlgorithmId;
15
+ readonly dueAtOrBefore: Date;
16
+ readonly limit?: number;
17
+ }): Promise<readonly DueStoredItem[]>;
18
+ commitReview(input: {
19
+ readonly state: StateUpdate;
20
+ readonly review: NewReviewRecord;
21
+ }): Promise<ReviewRecord>;
22
+ listReviews(itemId: LearningItemId, registeredAlgorithmId: AlgorithmId, query?: PageQuery): Promise<readonly ReviewRecord[]>;
23
+ close(): void;
24
+ private transaction;
25
+ }
26
+ //# sourceMappingURL=sqlite-learning-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-learning-store.d.ts","sourceRoot":"","sources":["../src/sqlite-learning-store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,eAAe,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAKvB,qBAAa,mBAAoB,YAAW,aAAa;;IAGvD,YAAmB,IAAI,GAAE,MAAmB,EAU3C;IAEY,iBAAiB,CAC5B,YAAY,EAAE,qBAAqB,GAClC,OAAO,CAAC,mBAAmB,CAAC,CAuC9B;IAEY,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBtE;IAEY,QAAQ,CACnB,EAAE,EAAE,cAAc,EAClB,qBAAqB,EAAE,WAAW,GACjC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAU9B;IAEY,SAAS,CACpB,qBAAqB,EAAE,WAAW,EAClC,KAAK,GAAE,SAAc,GACpB,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAsBlC;IAEY,UAAU,CACrB,EAAE,EAAE,cAAc,EAClB,qBAAqB,EAAE,WAAW,EAClC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAc9B;IAEY,UAAU,CACrB,EAAE,EAAE,cAAc,EAClB,qBAAqB,EAAE,WAAW,GACjC,OAAO,CAAC,OAAO,CAAC,CAYlB;IAEY,SAAS,CACpB,MAAM,EAAE,cAAc,EACtB,qBAAqB,EAAE,WAAW,GACjC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAS/B;IAEY,OAAO,CAAC,KAAK,EAAE;QAC1B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;QAClC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC;QAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAyCpC;IAEY,YAAY,CAAC,KAAK,EAAE;QAC/B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;QAC5B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;KAClC,GAAG,OAAO,CAAC,YAAY,CAAC,CA+CxB;IAEY,WAAW,CACtB,MAAM,EAAE,cAAc,EACtB,qBAAqB,EAAE,WAAW,EAClC,KAAK,GAAE,SAAc,GACpB,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAuBlC;IAEM,KAAK,IAAI,IAAI,CAEnB;IAED,OAAO,CAAC,WAAW;CAWpB"}
@@ -0,0 +1,390 @@
1
+ import { mkdirSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { DatabaseSync, } from "node:sqlite";
4
+ import { AlgorithmMismatchError, ConcurrentReviewError, } from "@alstate/core";
5
+ import { algorithmId, learningItemId, learningStateId, reviewRecordId, } from "@alstate/core";
6
+ import { migrateDatabase } from "./migrations.js";
7
+ export class SqliteLearningStore {
8
+ #database;
9
+ constructor(path = ":memory:") {
10
+ if (path !== ":memory:") {
11
+ mkdirSync(dirname(path), { recursive: true });
12
+ }
13
+ this.#database = new DatabaseSync(path, {
14
+ enableForeignKeyConstraints: true,
15
+ enableDoubleQuotedStringLiterals: false,
16
+ });
17
+ this.#database.exec("PRAGMA busy_timeout = 5000");
18
+ migrateDatabase(this.#database);
19
+ }
20
+ async registerAlgorithm(registration) {
21
+ requireNonBlank(registration.name, "algorithm name");
22
+ requireNonBlank(registration.version, "algorithm version");
23
+ const existing = this.#database
24
+ .prepare(`
25
+ SELECT id, name, version, description, config_json
26
+ FROM engine_algorithms
27
+ WHERE name = ?
28
+ `)
29
+ .get(registration.name);
30
+ if (existing !== undefined) {
31
+ const stored = mapAlgorithm(existing);
32
+ if (stored.version !== registration.version ||
33
+ canonicalJson(stored.configuration) !==
34
+ canonicalJson(registration.configuration)) {
35
+ throw new AlgorithmMismatchError(registration.name);
36
+ }
37
+ return stored;
38
+ }
39
+ const result = this.#database
40
+ .prepare(`
41
+ INSERT INTO engine_algorithms
42
+ (name, version, description, config_json)
43
+ VALUES (?, ?, ?, ?)
44
+ `)
45
+ .run(registration.name, registration.version, registration.description ?? null, JSON.stringify(registration.configuration));
46
+ return Object.freeze({
47
+ id: algorithmId(toSafeInteger(result.lastInsertRowid)),
48
+ ...registration,
49
+ });
50
+ }
51
+ async createItem(input) {
52
+ return this.transaction(() => {
53
+ const itemResult = this.#database
54
+ .prepare("INSERT INTO engine_items (data_json) VALUES (?)")
55
+ .run(JSON.stringify(input.data));
56
+ const id = learningItemId(toSafeInteger(itemResult.lastInsertRowid));
57
+ this.#database
58
+ .prepare(`
59
+ INSERT INTO engine_states
60
+ (learning_item_id, algorithm_id, due_at, state_json)
61
+ VALUES (?, ?, ?, ?)
62
+ `)
63
+ .run(id, input.algorithmId, isoDate(input.dueAt, "initial due time"), JSON.stringify(input.stateData));
64
+ return freezeItem({ id, data: input.data });
65
+ });
66
+ }
67
+ async findItem(id, registeredAlgorithmId) {
68
+ const row = this.#database
69
+ .prepare(`
70
+ SELECT item.id, item.data_json
71
+ FROM engine_items item
72
+ JOIN engine_states state ON state.learning_item_id = item.id
73
+ WHERE item.id = ? AND state.algorithm_id = ?
74
+ `)
75
+ .get(id, registeredAlgorithmId);
76
+ return row === undefined ? null : mapItem(row);
77
+ }
78
+ async listItems(registeredAlgorithmId, query = {}) {
79
+ validatePage(query);
80
+ const parameters = [registeredAlgorithmId];
81
+ let sql = `
82
+ SELECT item.id, item.data_json
83
+ FROM engine_items item
84
+ JOIN engine_states state ON state.learning_item_id = item.id
85
+ WHERE state.algorithm_id = ?
86
+ ORDER BY item.id
87
+ `;
88
+ if (query.limit !== undefined) {
89
+ sql += " LIMIT ?";
90
+ parameters.push(query.limit);
91
+ }
92
+ else if (query.offset !== undefined) {
93
+ sql += " LIMIT -1";
94
+ }
95
+ if (query.offset !== undefined) {
96
+ sql += " OFFSET ?";
97
+ parameters.push(query.offset);
98
+ }
99
+ const rows = this.#database.prepare(sql).all(...parameters);
100
+ return Object.freeze(rows.map(mapItem));
101
+ }
102
+ async updateItem(id, registeredAlgorithmId, data) {
103
+ const result = this.#database
104
+ .prepare(`
105
+ UPDATE engine_items SET data_json = ?
106
+ WHERE id = ? AND EXISTS (
107
+ SELECT 1 FROM engine_states state
108
+ WHERE state.learning_item_id = engine_items.id
109
+ AND state.algorithm_id = ?
110
+ )
111
+ `)
112
+ .run(JSON.stringify(data), id, registeredAlgorithmId);
113
+ return toSafeInteger(result.changes) === 0
114
+ ? null
115
+ : freezeItem({ id, data });
116
+ }
117
+ async deleteItem(id, registeredAlgorithmId) {
118
+ const result = this.#database
119
+ .prepare(`
120
+ DELETE FROM engine_items
121
+ WHERE id = ? AND EXISTS (
122
+ SELECT 1 FROM engine_states state
123
+ WHERE state.learning_item_id = engine_items.id
124
+ AND state.algorithm_id = ?
125
+ )
126
+ `)
127
+ .run(id, registeredAlgorithmId);
128
+ return toSafeInteger(result.changes) > 0;
129
+ }
130
+ async findState(itemId, registeredAlgorithmId) {
131
+ const row = this.#database
132
+ .prepare(`
133
+ SELECT id, learning_item_id, algorithm_id, revision, due_at, state_json
134
+ FROM engine_states
135
+ WHERE learning_item_id = ? AND algorithm_id = ?
136
+ `)
137
+ .get(itemId, registeredAlgorithmId);
138
+ return row === undefined ? null : mapState(row);
139
+ }
140
+ async listDue(input) {
141
+ validateLimit(input.limit);
142
+ const parameters = [
143
+ input.algorithmId,
144
+ isoDate(input.dueAtOrBefore, "due query time"),
145
+ ];
146
+ let sql = `
147
+ SELECT
148
+ item.id AS item_id,
149
+ item.data_json,
150
+ state.id AS state_id,
151
+ state.algorithm_id,
152
+ state.revision,
153
+ state.due_at,
154
+ state.state_json
155
+ FROM engine_states state
156
+ JOIN engine_items item ON item.id = state.learning_item_id
157
+ WHERE state.algorithm_id = ? AND state.due_at <= ?
158
+ ORDER BY state.due_at, item.id
159
+ `;
160
+ if (input.limit !== undefined) {
161
+ sql += " LIMIT ?";
162
+ parameters.push(input.limit);
163
+ }
164
+ const rows = this.#database.prepare(sql).all(...parameters);
165
+ return Object.freeze(rows.map((row) => {
166
+ const id = learningItemId(requireNumber(row, "item_id"));
167
+ return Object.freeze({
168
+ item: freezeItem({ id, data: parseObject(row, "data_json") }),
169
+ state: freezeState({
170
+ id: learningStateId(requireNumber(row, "state_id")),
171
+ learningItemId: id,
172
+ algorithmId: algorithmId(requireNumber(row, "algorithm_id")),
173
+ revision: requireNumber(row, "revision"),
174
+ dueAt: new Date(requireString(row, "due_at")),
175
+ data: parseObject(row, "state_json"),
176
+ }),
177
+ });
178
+ }));
179
+ }
180
+ async commitReview(input) {
181
+ return this.transaction(() => {
182
+ if (input.state.state.learningItemId !== input.review.learningItemId ||
183
+ input.state.state.algorithmId !== input.review.algorithmId) {
184
+ throw new TypeError("Review identity must match the state being updated.");
185
+ }
186
+ const update = this.#database
187
+ .prepare(`
188
+ UPDATE engine_states
189
+ SET due_at = ?, state_json = ?, revision = revision + 1
190
+ WHERE id = ? AND revision = ?
191
+ `)
192
+ .run(isoDate(input.state.dueAt, "next due time"), JSON.stringify(input.state.data), input.state.state.id, input.state.state.revision);
193
+ if (toSafeInteger(update.changes) !== 1) {
194
+ throw new ConcurrentReviewError(input.review.learningItemId);
195
+ }
196
+ const review = input.review;
197
+ validateResponseTime(review.responseTimeMs);
198
+ const result = this.#database
199
+ .prepare(`
200
+ INSERT INTO engine_reviews
201
+ (
202
+ learning_item_id, algorithm_id, rating, review_json,
203
+ response_time_ms, reviewed_at
204
+ )
205
+ VALUES (?, ?, ?, ?, ?, ?)
206
+ `)
207
+ .run(review.learningItemId, review.algorithmId, requireNonBlank(review.rating, "rating"), JSON.stringify(review.data), review.responseTimeMs ?? null, isoDate(review.reviewedAt, "review time"));
208
+ return freezeReview({
209
+ id: reviewRecordId(toSafeInteger(result.lastInsertRowid)),
210
+ ...review,
211
+ });
212
+ });
213
+ }
214
+ async listReviews(itemId, registeredAlgorithmId, query = {}) {
215
+ validatePage(query);
216
+ const parameters = [itemId, registeredAlgorithmId];
217
+ let sql = `
218
+ SELECT
219
+ id, learning_item_id, algorithm_id, rating, review_json,
220
+ response_time_ms, reviewed_at
221
+ FROM engine_reviews
222
+ WHERE learning_item_id = ? AND algorithm_id = ?
223
+ ORDER BY reviewed_at DESC, id DESC
224
+ `;
225
+ if (query.limit !== undefined) {
226
+ sql += " LIMIT ?";
227
+ parameters.push(query.limit);
228
+ }
229
+ else if (query.offset !== undefined) {
230
+ sql += " LIMIT -1";
231
+ }
232
+ if (query.offset !== undefined) {
233
+ sql += " OFFSET ?";
234
+ parameters.push(query.offset);
235
+ }
236
+ const rows = this.#database.prepare(sql).all(...parameters);
237
+ return Object.freeze(rows.map(mapReview));
238
+ }
239
+ close() {
240
+ this.#database.close();
241
+ }
242
+ transaction(work) {
243
+ this.#database.exec("BEGIN IMMEDIATE");
244
+ try {
245
+ const result = work();
246
+ this.#database.exec("COMMIT");
247
+ return result;
248
+ }
249
+ catch (error) {
250
+ this.#database.exec("ROLLBACK");
251
+ throw error;
252
+ }
253
+ }
254
+ }
255
+ function mapAlgorithm(row) {
256
+ const description = row["description"];
257
+ return Object.freeze({
258
+ id: algorithmId(requireNumber(row, "id")),
259
+ name: requireString(row, "name"),
260
+ version: requireString(row, "version"),
261
+ ...(description === null
262
+ ? {}
263
+ : { description: requireString(row, "description") }),
264
+ configuration: parseObject(row, "config_json"),
265
+ });
266
+ }
267
+ function mapItem(row) {
268
+ return freezeItem({
269
+ id: learningItemId(requireNumber(row, "id")),
270
+ data: parseObject(row, "data_json"),
271
+ });
272
+ }
273
+ function mapState(row) {
274
+ return freezeState({
275
+ id: learningStateId(requireNumber(row, "id")),
276
+ learningItemId: learningItemId(requireNumber(row, "learning_item_id")),
277
+ algorithmId: algorithmId(requireNumber(row, "algorithm_id")),
278
+ revision: requireNumber(row, "revision"),
279
+ dueAt: new Date(requireString(row, "due_at")),
280
+ data: parseObject(row, "state_json"),
281
+ });
282
+ }
283
+ function mapReview(row) {
284
+ const responseTime = row["response_time_ms"];
285
+ return freezeReview({
286
+ id: reviewRecordId(requireNumber(row, "id")),
287
+ learningItemId: learningItemId(requireNumber(row, "learning_item_id")),
288
+ algorithmId: algorithmId(requireNumber(row, "algorithm_id")),
289
+ rating: requireString(row, "rating"),
290
+ data: parseObject(row, "review_json"),
291
+ reviewedAt: new Date(requireString(row, "reviewed_at")),
292
+ ...(responseTime === null
293
+ ? {}
294
+ : { responseTimeMs: requireNumber(row, "response_time_ms") }),
295
+ });
296
+ }
297
+ function freezeItem(item) {
298
+ return Object.freeze({ ...item, data: Object.freeze({ ...item.data }) });
299
+ }
300
+ function freezeState(state) {
301
+ const dueAt = validDate(state.dueAt, "stored due time");
302
+ return Object.freeze({
303
+ ...state,
304
+ dueAt,
305
+ data: Object.freeze({ ...state.data }),
306
+ });
307
+ }
308
+ function freezeReview(record) {
309
+ const reviewedAt = validDate(record.reviewedAt, "stored review time");
310
+ return Object.freeze({
311
+ ...record,
312
+ reviewedAt,
313
+ data: Object.freeze({ ...record.data }),
314
+ });
315
+ }
316
+ function parseObject(row, column) {
317
+ const value = JSON.parse(requireString(row, column));
318
+ if (value === null || Array.isArray(value) || typeof value !== "object") {
319
+ throw new TypeError(`Database column '${column}' must contain an object.`);
320
+ }
321
+ return value;
322
+ }
323
+ function requireNumber(row, column) {
324
+ const value = row[column];
325
+ if (typeof value !== "number") {
326
+ throw new TypeError(`Database column '${column}' must be a number.`);
327
+ }
328
+ return value;
329
+ }
330
+ function requireString(row, column) {
331
+ const value = row[column];
332
+ if (typeof value !== "string") {
333
+ throw new TypeError(`Database column '${column}' must be a string.`);
334
+ }
335
+ return value;
336
+ }
337
+ function toSafeInteger(value) {
338
+ const number = typeof value === "bigint" ? Number(value) : value;
339
+ if (!Number.isSafeInteger(number)) {
340
+ throw new TypeError("SQLite returned an unsafe integer.");
341
+ }
342
+ return number;
343
+ }
344
+ function requireNonBlank(value, field) {
345
+ if (value.trim().length === 0) {
346
+ throw new TypeError(`${field} must not be blank.`);
347
+ }
348
+ return value;
349
+ }
350
+ function validDate(value, field) {
351
+ if (Number.isNaN(value.getTime())) {
352
+ throw new TypeError(`${field} must be a valid date.`);
353
+ }
354
+ return new Date(value);
355
+ }
356
+ function isoDate(value, field) {
357
+ return validDate(value, field).toISOString();
358
+ }
359
+ function validatePage(query) {
360
+ validateLimit(query.limit);
361
+ if (query.offset !== undefined &&
362
+ (!Number.isSafeInteger(query.offset) || query.offset < 0)) {
363
+ throw new TypeError("offset must be a non-negative safe integer.");
364
+ }
365
+ }
366
+ function validateLimit(limit) {
367
+ if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 0)) {
368
+ throw new TypeError("limit must be a non-negative safe integer.");
369
+ }
370
+ }
371
+ function validateResponseTime(value) {
372
+ if (value !== undefined && (!Number.isFinite(value) || value < 0)) {
373
+ throw new TypeError("responseTimeMs must be a non-negative number.");
374
+ }
375
+ }
376
+ function canonicalJson(value) {
377
+ return JSON.stringify(sortJson(value));
378
+ }
379
+ function sortJson(value) {
380
+ if (Array.isArray(value)) {
381
+ return value.map(sortJson);
382
+ }
383
+ if (value !== null && typeof value === "object") {
384
+ return Object.fromEntries(Object.entries(value)
385
+ .sort(([left], [right]) => left.localeCompare(right))
386
+ .map(([key, entry]) => [key, sortJson(entry)]));
387
+ }
388
+ return value;
389
+ }
390
+ //# sourceMappingURL=sqlite-learning-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-learning-store.js","sourceRoot":"","sources":["../src/sqlite-learning-store.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@alstate/sqlite",
3
+ "version": "0.1.0",
4
+ "description": "SQLite persistence adapter for Alstate.",
5
+ "keywords": ["learning", "scheduling", "sqlite", "spaced-repetition"],
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": ["dist", "README.md", "LICENSE"],
16
+ "sideEffects": false,
17
+ "scripts": {
18
+ "build": "tsc --project tsconfig.build.json",
19
+ "clean": "node --eval \"require('node:fs').rmSync('dist', { recursive: true, force: true }); require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
20
+ "test": "tsc --project tsconfig.test.json && node --test \".test-dist/test/**/*.test.js\"",
21
+ "typecheck": "tsc --project tsconfig.json --noEmit"
22
+ },
23
+ "dependencies": { "@alstate/core": "0.1.0" },
24
+ "engines": { "node": ">=22.13.0" },
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/laiqfun/alstate.git",
29
+ "directory": "packages/sqlite"
30
+ },
31
+ "homepage": "https://github.com/laiqfun/alstate#readme",
32
+ "bugs": { "url": "https://github.com/laiqfun/alstate/issues" },
33
+ "publishConfig": { "access": "public" }
34
+ }