History

Initialize persistence service directly from Effect SQLite adapter

Cursor Agent committed 8 months ago

Commit aa2d6e71 parent 91128181 file · +37 −11Browse files

Unified · Split

apps/server/src/persistenceService.ts+37−11
@@ -66,7 +66,6 @@ import { · 65 unmodified lines
66 threadsUpdateResultSchema,66 threadsUpdateResultSchema,
67} from "@t3tools/contracts";67} from "@t3tools/contracts";
68 68
69import { StateDb } from "./stateDb";
70import {69import {
71 countMessagesForThread as countMessagesForThreadEffect,70 countMessagesForThread as countMessagesForThreadEffect,
72 deleteDocumentByIdAndKind as deleteDocumentByIdAndKindEffect,71 deleteDocumentByIdAndKind as deleteDocumentByIdAndKindEffect,
@@ -101,7 +100,8 @@ import { · 28 unmodified lines
101 readMetadataValue as readMetadataValueEffect,100 readMetadataValue as readMetadataValueEffect,
102 writeMetadataValue as writeMetadataValueEffect,101 writeMetadataValue as writeMetadataValueEffect,
103} from "./persistence/metadataRepo";102} from "./persistence/metadataRepo";
104import type { EffectSqliteDatabaseAdapter } from "./sqliteAdapter";103import { openSqliteDatabase, type EffectSqliteDatabaseAdapter, type SqliteDatabase } from "./sqliteAdapter";
104import { runStateMigrations } from "./stateMigrations";
105 105
106const METADATA_KEY_PROJECTS_JSON_IMPORTED = "migration.projects_json_imported";106const METADATA_KEY_PROJECTS_JSON_IMPORTED = "migration.projects_json_imported";
107const METADATA_KEY_APP_SETTINGS = "app.settings.v1";107const METADATA_KEY_APP_SETTINGS = "app.settings.v1";
@@ -466,22 +466,32 @@ function mergeTurnSummaryFiles( · 358 unmodified lines
466}466}
467 467
468export class PersistenceService extends EventEmitter<PersistenceServiceEvents> {468export class PersistenceService extends EventEmitter<PersistenceServiceEvents> {
469 private readonly stateDb: StateDb;469 private readonly db: SqliteDatabase;
470 private readonly db: StateDb["db"];
471 private readonly sessionThreadIds = new Map<string, string>();470 private readonly sessionThreadIds = new Map<string, string>();
472 private readonly runtimeThreadIds = new Map<string, string>();471 private readonly runtimeThreadIds = new Map<string, string>();
473 472
474 constructor(options: PersistenceServiceOptions) {473 constructor(options: PersistenceServiceOptions) {
475 super();474 super();
476 this.stateDb = new StateDb({ dbPath: options.dbPath });475 const dbPath = path.resolve(options.dbPath);
477 this.db = this.stateDb.db;476 fs.mkdirSync(path.dirname(dbPath), { recursive: true });
477 this.db = openSqliteDatabase(dbPath);
478 try {
479 runStateMigrations(this.db);
480 } catch (error) {
481 try {
482 this.db.close();
483 } catch {
484 // Best effort close on failed initialization.
485 }
486 throw error;
487 }
478 if (options.legacyProjectsJsonPath) {488 if (options.legacyProjectsJsonPath) {
479 this.importProjectsJsonIfNeeded(options.legacyProjectsJsonPath);489 this.importProjectsJsonIfNeeded(options.legacyProjectsJsonPath);
480 }490 }
481 }491 }
482 492
483 close(): void {493 close(): void {
484 this.stateDb.close();494 this.db.close();
485 }495 }
486 496
487 getAppSettings(): AppSettings {497 getAppSettings(): AppSettings {
@@ -1379,7 +1389,7 @@ export class PersistenceService extends EventEmitter<PersistenceServiceEvents> { · 891 unmodified lines
1379 }1389 }
1380 1390
1381 let importedCount = 0;1391 let importedCount = 0;
1382 this.stateDb.transaction(() => {1392 this.runDbTransaction(() => {
1383 try {1393 try {
1384 const raw = fs.readFileSync(normalizedPath, "utf8");1394 const raw = fs.readFileSync(normalizedPath, "utf8");
1385 const payload = JSON.parse(raw) as { projects?: unknown };1395 const payload = JSON.parse(raw) as { projects?: unknown };
@@ -1431,9 +1441,25 @@ export class PersistenceService extends EventEmitter<PersistenceServiceEvents> { · 45 unmodified lines
1431 });1441 });
1432 }1442 }
1433 1443
1444 private runDbTransaction<T>(fn: () => T): T {
1445 this.db.exec("BEGIN IMMEDIATE;");
1446 try {
1447 const result = fn();
1448 this.db.exec("COMMIT;");
1449 return result;
1450 } catch (error) {
1451 try {
1452 this.db.exec("ROLLBACK;");
1453 } catch {
1454 // Preserve the original transactional failure.
1455 }
1456 throw error;
1457 }
1458 }
1459
1434 private withTransaction<T>(fn: (pendingEvents: StateEvent[]) => T): T {1460 private withTransaction<T>(fn: (pendingEvents: StateEvent[]) => T): T {
1435 const pendingEvents: StateEvent[] = [];1461 const pendingEvents: StateEvent[] = [];
1436 const result = this.stateDb.transaction(() => fn(pendingEvents));1462 const result = this.runDbTransaction(() => fn(pendingEvents));
1437 for (const event of pendingEvents) {1463 for (const event of pendingEvents) {
1438 try {1464 try {
1439 this.emit("stateEvent", event);1465 this.emit("stateEvent", event);
@@ -1983,7 +2009,7 @@ export class PersistenceService extends EventEmitter<PersistenceServiceEvents> { · 543 unmodified lines
1983 write();2009 write();
1984 return;2010 return;
1985 }2011 }
1986 this.stateDb.transaction(write);2012 this.runDbTransaction(write);
1987 }2013 }
1988 2014
1989 private runWithEffectSql<A>(2015 private runWithEffectSql<A>(
@@ -1997,6 +2023,6 @@ export class PersistenceService extends EventEmitter<PersistenceServiceEvents> { · 7 unmodified lines
1997 }2023 }
1998}2024}
1999 2025
2000function isEffectSqliteDatabase(db: StateDb["db"]): db is EffectSqliteDatabaseAdapter {2026function isEffectSqliteDatabase(db: SqliteDatabase): db is EffectSqliteDatabaseAdapter {
2001 return "runWithSqlClient" in db && typeof db.runWithSqlClient === "function";2027 return "runWithSqlClient" in db && typeof db.runWithSqlClient === "function";
2002}2028}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t