@proteinjs/db 1.29.2 → 1.30.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proteinjs/db",
3
- "version": "1.29.2",
3
+ "version": "1.30.0",
4
4
  "main": "./dist/generated/index.js",
5
5
  "types": "./dist/generated/index.d.ts",
6
6
  "exports": {
@@ -41,7 +41,7 @@
41
41
  "test": "jest --passWithNoTests"
42
42
  },
43
43
  "dependencies": {
44
- "@proteinjs/db-query": "^1.6.1",
44
+ "@proteinjs/db-query": "^1.6.3",
45
45
  "@proteinjs/logger": "^1.0.21",
46
46
  "@proteinjs/reflection": "^1.1.12",
47
47
  "@proteinjs/serializer": "^1.1.10",
@@ -66,5 +66,5 @@
66
66
  "ts-jest": "29.1.1",
67
67
  "typescript": "5.2.2"
68
68
  },
69
- "gitHead": "bfe0871836b28eb4a3250090336b9417e73d4b69"
69
+ "gitHead": "fd3dd48fae93c6da8c0b3decd6dd30a506a9109a"
70
70
  }
@@ -1,5 +1,5 @@
1
1
  import { Moment, moment } from './opt/moment';
2
- import { getDb } from './Db';
2
+ import { Db, getDb, getDbAsSystem } from './Db';
3
3
  import { Table } from './Table';
4
4
  import { SourceRecordRepo } from './source/SourceRecordRepo';
5
5
  import { MigrationRunnerService, getMigrationRunnerService } from './services/MigrationRunnerService';
@@ -32,16 +32,41 @@ export class MigrationRunner implements MigrationRunnerService {
32
32
  */
33
33
  runMigration(id: string): Promise<void> {
34
34
  const migrationTable: Table<Migration> = new MigrationTable();
35
- const migration = new SourceRecordRepo().getSourceRecord<Migration>(migrationTable.name, id);
36
- if (!migration) {
37
- throw new Error(`Unable to find migration source record for id: ${id}`);
35
+ const migration = this.resolveMigration(migrationTable, id);
36
+ return this.runAndRecord(migrationTable, migration, getDb);
37
+ }
38
+
39
+ /**
40
+ * Boot-path API: at server boot no user session exists, so `getDb()` (which `runMigration`
41
+ * records through) fail-closes on the migration table's doors. This method reads and records
42
+ * run state through `getDbAsSystem()` instead — it is the seam a future migrations-auto-run
43
+ * rides (deploy-coupled migrations call it during server startup).
44
+ *
45
+ * 'ensure' = idempotent: a row already in 'success' status is logged and skipped. A prior
46
+ * 'failure' row is retried by design — a fixed migration should run on the next boot.
47
+ */
48
+ async ensureMigrationRun(id: string): Promise<void> {
49
+ const migrationTable: Table<Migration> = new MigrationTable();
50
+ const db = getDbAsSystem();
51
+ const migrationRow = await db.get(migrationTable, { id });
52
+ if (migrationRow?.status === 'success') {
53
+ this.logger.info({ message: `Migration (${id}) already applied, skipping` });
54
+ return;
38
55
  }
39
56
 
40
- return this.runAndRecord(migrationTable, migration);
57
+ const migration = this.resolveMigration(migrationTable, id);
58
+ await this.runAndRecord(migrationTable, migration, () => db);
41
59
  }
42
60
 
43
- private async runAndRecord(migrationTable: Table<Migration>, migration: Migration): Promise<void> {
44
- const db = getDb();
61
+ // The db is taken as a provider, resolved inside this async body: on the service path,
62
+ // constructing the Db is itself run infrastructure — its failure must REJECT the detached
63
+ // promise, not throw synchronously from runMigration (only a bogus id may reach the client).
64
+ private async runAndRecord(
65
+ migrationTable: Table<Migration>,
66
+ migration: Migration,
67
+ getRunDb: () => Db
68
+ ): Promise<void> {
69
+ const db = getRunDb();
45
70
  migration.status = 'running';
46
71
  migration.startTime = moment();
47
72
  await db.update(migrationTable, migration);
@@ -66,6 +91,15 @@ export class MigrationRunner implements MigrationRunnerService {
66
91
  });
67
92
  }
68
93
 
94
+ private resolveMigration(migrationTable: Table<Migration>, id: string): Migration {
95
+ const migration = new SourceRecordRepo().getSourceRecord<Migration>(migrationTable.name, id);
96
+ if (!migration) {
97
+ throw new Error(`Unable to find migration source record for id: ${id}`);
98
+ }
99
+
100
+ return migration;
101
+ }
102
+
69
103
  private duration(start: Moment, end: Moment): string {
70
104
  const duration = moment.duration(end.diff(start));
71
105
  const parts: string[] = [];