Use node:Sqlite
This commit is contained in:
Generated
+11
-1
@@ -16,7 +16,8 @@
|
|||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"dotenv": "^17.4.2",
|
"dotenv": "^17.4.2",
|
||||||
"hono": "^4.12.26",
|
"hono": "^4.12.26",
|
||||||
"kysely": "^0.29.2",
|
"kysely": "^0.29.4",
|
||||||
|
"kysely-node-native-sqlite": "^1.0.1",
|
||||||
"ws": "^8.21.0",
|
"ws": "^8.21.0",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
@@ -8314,6 +8315,15 @@
|
|||||||
"node": ">=22.0.0"
|
"node": ">=22.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/kysely-node-native-sqlite": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/kysely-node-native-sqlite/-/kysely-node-native-sqlite-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-FHty4bi885waQMMMw2P9F+mqZUdozd1OBWQI72CffsQzbZhcOgsz3jpZRTUM1xAtG1wkz/VQAj3JavQvCdhL2w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peerDependencies": {
|
||||||
|
"kysely": ">=0.27.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/language-subtag-registry": {
|
"node_modules/language-subtag-registry": {
|
||||||
"version": "0.3.23",
|
"version": "0.3.23",
|
||||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
|
||||||
|
|||||||
+2
-1
@@ -51,7 +51,8 @@
|
|||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"dotenv": "^17.4.2",
|
"dotenv": "^17.4.2",
|
||||||
"hono": "^4.12.26",
|
"hono": "^4.12.26",
|
||||||
"kysely": "^0.29.2",
|
"kysely": "^0.29.4",
|
||||||
|
"kysely-node-native-sqlite": "^1.0.1",
|
||||||
"ws": "^8.21.0",
|
"ws": "^8.21.0",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
|
|||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
import { Config } from './services/config.ts';
|
||||||
|
import { Database, MigrationService } from './services/storage/index.ts';
|
||||||
|
import { Logger } from './utils/logger.ts';
|
||||||
|
|
||||||
|
/** Application composition root. */
|
||||||
|
export class App {
|
||||||
|
/**
|
||||||
|
* Construct infrastructure and validate all routes before returning a runnable app.
|
||||||
|
*/
|
||||||
|
static async create(): Promise<App> {
|
||||||
|
const config = Config.fromEnv();
|
||||||
|
const debug = new Logger('sync-server-v2');
|
||||||
|
debug('config loaded: %O', config);
|
||||||
|
|
||||||
|
// Persistence must be ready before routes accept traffic.
|
||||||
|
const database = new Database({ path: config.database.path, debug });
|
||||||
|
const migrations = new MigrationService(database, debug);
|
||||||
|
await migrations.migrateToLatest();
|
||||||
|
|
||||||
|
return new App(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopPromise: Promise<void> | undefined;
|
||||||
|
|
||||||
|
constructor(private readonly database: Database) {}
|
||||||
|
|
||||||
|
async start(): Promise<void> {}
|
||||||
|
|
||||||
|
/** Stop transports before releasing the database they may still use. */
|
||||||
|
async stop(): Promise<void> {
|
||||||
|
this.stopPromise ??= this.database.destroy();
|
||||||
|
await this.stopPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = await App.create();
|
||||||
|
let shuttingDown = false;
|
||||||
|
|
||||||
|
const shutdown = (signal: NodeJS.Signals): void => {
|
||||||
|
if (shuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shuttingDown = true;
|
||||||
|
void app.stop().catch((error) => {
|
||||||
|
console.error('Graceful shutdown failed after ' + signal, error);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
process.once('SIGINT', (): void => shutdown('SIGINT'));
|
||||||
|
process.once('SIGTERM', (): void => shutdown('SIGTERM'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await app.start();
|
||||||
|
} catch (error: unknown) {
|
||||||
|
await app.stop();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import DatabaseConstructor from 'better-sqlite3';
|
import { CompiledQuery, Kysely } from 'kysely';
|
||||||
import { Kysely, SqliteDialect } from 'kysely';
|
import { NodeNativeSqliteDialect } from 'kysely-node-native-sqlite';
|
||||||
|
|
||||||
import type { DatabaseTables } from './tables.ts';
|
import type { DatabaseTables } from './tables.ts';
|
||||||
import type { Logger } from '../../utils/logger.ts';
|
import type { Logger } from '../../utils/logger.ts';
|
||||||
|
|
||||||
@@ -13,13 +14,13 @@ export type DatabaseOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thin wrapper around better-sqlite3 and Kysely.
|
* Thin wrapper around Kysely and NodeNativeSqliteDialect (which uses node:sqlite).
|
||||||
*
|
*
|
||||||
* Owns connection setup, pragma configuration, and graceful teardown.
|
* Owns connection setup, pragma configuration, and graceful teardown.
|
||||||
*/
|
*/
|
||||||
export class Database {
|
export class Database {
|
||||||
private readonly debug: Logger;
|
private readonly debug: Logger;
|
||||||
private readonly sqlite: DatabaseConstructor.Database;
|
private readonly dialect: NodeNativeSqliteDialect;
|
||||||
private readonly kysely: Kysely<DatabaseTables>;
|
private readonly kysely: Kysely<DatabaseTables>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,13 +33,15 @@ export class Database {
|
|||||||
this.debug = options.debug.extend('database');
|
this.debug = options.debug.extend('database');
|
||||||
|
|
||||||
// Create the SQLite database.
|
// Create the SQLite database.
|
||||||
this.sqlite = new DatabaseConstructor(options.path);
|
this.dialect = new NodeNativeSqliteDialect(options.path);
|
||||||
this.configurePragmas();
|
|
||||||
|
|
||||||
// Create the Kysely database.
|
// Create the Kysely database.
|
||||||
this.kysely = new Kysely<DatabaseTables>({
|
this.kysely = new Kysely<DatabaseTables>({
|
||||||
dialect: new SqliteDialect({ database: this.sqlite }),
|
dialect: this.dialect,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Configure the SQLite pragmas.
|
||||||
|
this.configurePragmas();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +68,8 @@ export class Database {
|
|||||||
*/
|
*/
|
||||||
private configurePragmas(): void {
|
private configurePragmas(): void {
|
||||||
this.debug('configuring SQLite pragmas');
|
this.debug('configuring SQLite pragmas');
|
||||||
this.sqlite.pragma('journal_mode = WAL');
|
|
||||||
this.sqlite.pragma('foreign_keys = ON');
|
this.kysely.executeQuery(CompiledQuery.raw('PRAGMA journal_mode = WAL'));
|
||||||
|
this.kysely.executeQuery(CompiledQuery.raw('PRAGMA foreign_keys = ON'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -12,7 +12,8 @@
|
|||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true
|
"declarationMap": true,
|
||||||
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules/**/*", "dist/**/*", "test"]
|
"exclude": ["node_modules/**/*", "dist/**/*", "test"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user