@coffre/db 0.1.13 → 0.1.15
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/dist/migrate.d.ts +19 -4
- package/dist/migrate.js +34 -6
- package/dist/schema-version.d.ts +8 -0
- package/dist/schema-version.js +44 -1
- package/package.json +2 -2
- package/src/migrate.ts +37 -6
- package/src/schema-version.ts +17 -0
package/dist/migrate.d.ts
CHANGED
|
@@ -8,15 +8,30 @@ export declare function restrictDatabase(client: Pick<PoolClient, 'query'>): Pro
|
|
|
8
8
|
* in the built package, where the build copies them.
|
|
9
9
|
*/
|
|
10
10
|
export declare function migrationsFolder(engine: Engine): string;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* A migration run's plan: `applied` of the `total` migrations there before
|
|
13
|
+
* it, and the tags of the rest, which it applies.
|
|
14
|
+
*/
|
|
12
15
|
export type MigrationPlan = {
|
|
13
16
|
applied: number;
|
|
14
17
|
total: number;
|
|
18
|
+
pending: string[];
|
|
15
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Which of this version's migrations a database has applied, and which it
|
|
22
|
+
* has not, without changing it or waiting on a migration under way. A
|
|
23
|
+
* history that is not a prefix of this version's is refused, as
|
|
24
|
+
* `migrateDatabase` refuses it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function migrationStatus(url: string): Promise<{
|
|
27
|
+
applied: string[];
|
|
28
|
+
pending: string[];
|
|
29
|
+
}>;
|
|
16
30
|
/**
|
|
17
31
|
* Apply missing migrations, check their history and reassert database
|
|
18
|
-
* privileges. `onPlan` hears
|
|
19
|
-
*
|
|
32
|
+
* privileges. `onPlan` hears what there is to apply before it is, under
|
|
33
|
+
* the migration lock, and may stop the run by throwing: all of it then goes
|
|
34
|
+
* in one call, with no word of each.
|
|
20
35
|
*/
|
|
21
|
-
export declare function migrateDatabase(url: string, onPlan?: (plan: MigrationPlan) => void): Promise<void>;
|
|
36
|
+
export declare function migrateDatabase(url: string, onPlan?: (plan: MigrationPlan) => void | Promise<void>): Promise<void>;
|
|
22
37
|
//#endregion
|
package/dist/migrate.js
CHANGED
|
@@ -105,9 +105,35 @@ async function sqliteMigrator(url) {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
|
+
* Which of this version's migrations a database has applied, and which it
|
|
109
|
+
* has not, without changing it or waiting on a migration under way. A
|
|
110
|
+
* history that is not a prefix of this version's is refused, as
|
|
111
|
+
* `migrateDatabase` refuses it.
|
|
112
|
+
*/
|
|
113
|
+
async function migrationStatus(url) {
|
|
114
|
+
const engine = engineOfUrl(url);
|
|
115
|
+
const expected = await expectedMigrations(engine);
|
|
116
|
+
const migrator = await {
|
|
117
|
+
postgres: postgresMigrator,
|
|
118
|
+
sqlite: sqliteMigrator
|
|
119
|
+
}[engine](url);
|
|
120
|
+
try {
|
|
121
|
+
const history = await migrator.applied();
|
|
122
|
+
verifyHistory(expected, history, false);
|
|
123
|
+
const applied = history?.length ?? 0;
|
|
124
|
+
return {
|
|
125
|
+
applied: expected.slice(0, applied).map((entry) => entry.tag),
|
|
126
|
+
pending: expected.slice(applied).map((entry) => entry.tag)
|
|
127
|
+
};
|
|
128
|
+
} finally {
|
|
129
|
+
await migrator.close();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
108
133
|
* Apply missing migrations, check their history and reassert database
|
|
109
|
-
* privileges. `onPlan` hears
|
|
110
|
-
*
|
|
134
|
+
* privileges. `onPlan` hears what there is to apply before it is, under
|
|
135
|
+
* the migration lock, and may stop the run by throwing: all of it then goes
|
|
136
|
+
* in one call, with no word of each.
|
|
111
137
|
*/
|
|
112
138
|
async function migrateDatabase(url, onPlan) {
|
|
113
139
|
const engine = engineOfUrl(url);
|
|
@@ -122,9 +148,11 @@ async function migrateDatabase(url, onPlan) {
|
|
|
122
148
|
locked = true;
|
|
123
149
|
const applied = await migrator.applied();
|
|
124
150
|
verifyHistory(expected, applied, false);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
151
|
+
const done = applied?.length ?? 0;
|
|
152
|
+
await onPlan?.({
|
|
153
|
+
applied: done,
|
|
154
|
+
total: expected.length,
|
|
155
|
+
pending: expected.slice(done).map((entry) => entry.tag)
|
|
128
156
|
});
|
|
129
157
|
await migrator.migrate(migrationsFolder(engine));
|
|
130
158
|
verifyHistory(expected, await migrator.applied(), true);
|
|
@@ -138,4 +166,4 @@ async function migrateDatabase(url, onPlan) {
|
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
168
|
//#endregion
|
|
141
|
-
export { migrateDatabase, migrationsFolder, restrictDatabase };
|
|
169
|
+
export { migrateDatabase, migrationStatus, migrationsFolder, restrictDatabase };
|
package/dist/schema-version.d.ts
CHANGED
|
@@ -10,4 +10,12 @@ import { Engine } from "./dialect.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const REQUIRED_MIGRATIONS: Record<Engine, number>;
|
|
12
12
|
export declare function requiredMigrations(db: Queryable): number;
|
|
13
|
+
/**
|
|
14
|
+
* Every migration this version ships, oldest first, per engine: read from
|
|
15
|
+
* the journals at build time, so a Worker, which has no files, knows them
|
|
16
|
+
* too. A database that has applied fewer is behind this code, whatever
|
|
17
|
+
* `REQUIRED_MIGRATIONS` lets it run on.
|
|
18
|
+
*/
|
|
19
|
+
export declare const KNOWN_MIGRATIONS: Record<Engine, readonly string[]>;
|
|
20
|
+
export declare function knownMigrations(db: Queryable): readonly string[];
|
|
13
21
|
//#endregion
|
package/dist/schema-version.js
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
1
1
|
import { engineOf } from "./dialect.js";
|
|
2
|
+
//#region src/migrations/postgres/meta/_journal.json
|
|
3
|
+
var entries$1 = [{
|
|
4
|
+
"idx": 0,
|
|
5
|
+
"version": "7",
|
|
6
|
+
"when": 1790930587507,
|
|
7
|
+
"tag": "0000_baseline",
|
|
8
|
+
"breakpoints": true
|
|
9
|
+
}, {
|
|
10
|
+
"idx": 1,
|
|
11
|
+
"version": "7",
|
|
12
|
+
"when": 1791062292678,
|
|
13
|
+
"tag": "0001_remove_syncs",
|
|
14
|
+
"breakpoints": true
|
|
15
|
+
}];
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/migrations/sqlite/meta/_journal.json
|
|
18
|
+
var entries = [{
|
|
19
|
+
"idx": 0,
|
|
20
|
+
"version": "6",
|
|
21
|
+
"when": 1790874462505,
|
|
22
|
+
"tag": "0000_baseline",
|
|
23
|
+
"breakpoints": true
|
|
24
|
+
}, {
|
|
25
|
+
"idx": 1,
|
|
26
|
+
"version": "6",
|
|
27
|
+
"when": 1791062293531,
|
|
28
|
+
"tag": "0001_remove_syncs",
|
|
29
|
+
"breakpoints": true
|
|
30
|
+
}];
|
|
31
|
+
//#endregion
|
|
2
32
|
//#region src/schema-version.ts
|
|
3
33
|
/**
|
|
4
34
|
* Minimum migration prefix required by this application image, per engine:
|
|
@@ -14,5 +44,18 @@ const REQUIRED_MIGRATIONS = {
|
|
|
14
44
|
function requiredMigrations(db) {
|
|
15
45
|
return REQUIRED_MIGRATIONS[engineOf(db)];
|
|
16
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Every migration this version ships, oldest first, per engine: read from
|
|
49
|
+
* the journals at build time, so a Worker, which has no files, knows them
|
|
50
|
+
* too. A database that has applied fewer is behind this code, whatever
|
|
51
|
+
* `REQUIRED_MIGRATIONS` lets it run on.
|
|
52
|
+
*/
|
|
53
|
+
const KNOWN_MIGRATIONS = {
|
|
54
|
+
postgres: entries$1.map((entry) => entry.tag),
|
|
55
|
+
sqlite: entries.map((entry) => entry.tag)
|
|
56
|
+
};
|
|
57
|
+
function knownMigrations(db) {
|
|
58
|
+
return KNOWN_MIGRATIONS[engineOf(db)];
|
|
59
|
+
}
|
|
17
60
|
//#endregion
|
|
18
|
-
export { REQUIRED_MIGRATIONS, requiredMigrations };
|
|
61
|
+
export { KNOWN_MIGRATIONS, REQUIRED_MIGRATIONS, knownMigrations, requiredMigrations };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffre/db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "coffre's database: the schema, its migrations and the connections, on Postgres or SQLite.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"drizzle-orm": "0.45.2",
|
|
75
75
|
"pg": "8.16.3",
|
|
76
76
|
"pg-connection-string": "2.14.0",
|
|
77
|
-
"@coffre/core": "0.1.
|
|
77
|
+
"@coffre/core": "0.1.15"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@types/node": "26.1.1",
|
package/src/migrate.ts
CHANGED
|
@@ -185,15 +185,45 @@ async function sqliteMigrator(url: string): Promise<Migrator> {
|
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
/**
|
|
189
|
-
|
|
188
|
+
/**
|
|
189
|
+
* A migration run's plan: `applied` of the `total` migrations there before
|
|
190
|
+
* it, and the tags of the rest, which it applies.
|
|
191
|
+
*/
|
|
192
|
+
export type MigrationPlan = { applied: number; total: number; pending: string[] };
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Which of this version's migrations a database has applied, and which it
|
|
196
|
+
* has not, without changing it or waiting on a migration under way. A
|
|
197
|
+
* history that is not a prefix of this version's is refused, as
|
|
198
|
+
* `migrateDatabase` refuses it.
|
|
199
|
+
*/
|
|
200
|
+
export async function migrationStatus(url: string): Promise<{ applied: string[]; pending: string[] }> {
|
|
201
|
+
const engine = engineOfUrl(url);
|
|
202
|
+
const expected = await expectedMigrations(engine);
|
|
203
|
+
const migrator = await { postgres: postgresMigrator, sqlite: sqliteMigrator }[engine](url);
|
|
204
|
+
try {
|
|
205
|
+
const history = await migrator.applied();
|
|
206
|
+
verifyHistory(expected, history, false);
|
|
207
|
+
const applied = history?.length ?? 0;
|
|
208
|
+
return {
|
|
209
|
+
applied: expected.slice(0, applied).map((entry) => entry.tag),
|
|
210
|
+
pending: expected.slice(applied).map((entry) => entry.tag),
|
|
211
|
+
};
|
|
212
|
+
} finally {
|
|
213
|
+
await migrator.close();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
190
216
|
|
|
191
217
|
/**
|
|
192
218
|
* Apply missing migrations, check their history and reassert database
|
|
193
|
-
* privileges. `onPlan` hears
|
|
194
|
-
*
|
|
219
|
+
* privileges. `onPlan` hears what there is to apply before it is, under
|
|
220
|
+
* the migration lock, and may stop the run by throwing: all of it then goes
|
|
221
|
+
* in one call, with no word of each.
|
|
195
222
|
*/
|
|
196
|
-
export async function migrateDatabase(
|
|
223
|
+
export async function migrateDatabase(
|
|
224
|
+
url: string,
|
|
225
|
+
onPlan?: (plan: MigrationPlan) => void | Promise<void>,
|
|
226
|
+
): Promise<void> {
|
|
197
227
|
const engine = engineOfUrl(url);
|
|
198
228
|
const expected = await expectedMigrations(engine);
|
|
199
229
|
const migrator = await { postgres: postgresMigrator, sqlite: sqliteMigrator }[engine](url);
|
|
@@ -205,7 +235,8 @@ export async function migrateDatabase(url: string, onPlan?: (plan: MigrationPlan
|
|
|
205
235
|
|
|
206
236
|
const applied = await migrator.applied();
|
|
207
237
|
verifyHistory(expected, applied, false);
|
|
208
|
-
|
|
238
|
+
const done = applied?.length ?? 0;
|
|
239
|
+
await onPlan?.({ applied: done, total: expected.length, pending: expected.slice(done).map((entry) => entry.tag) });
|
|
209
240
|
await migrator.migrate(migrationsFolder(engine));
|
|
210
241
|
verifyHistory(expected, await migrator.applied(), true);
|
|
211
242
|
await migrator.restrict();
|
package/src/schema-version.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Queryable } from './database.ts';
|
|
2
2
|
import { engineOf, type Engine } from './dialect.ts';
|
|
3
|
+
import postgresJournal from './migrations/postgres/meta/_journal.json' with { type: 'json' };
|
|
4
|
+
import sqliteJournal from './migrations/sqlite/meta/_journal.json' with { type: 'json' };
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Minimum migration prefix required by this application image, per engine:
|
|
@@ -13,3 +15,18 @@ export const REQUIRED_MIGRATIONS: Record<Engine, number> = { postgres: 1, sqlite
|
|
|
13
15
|
export function requiredMigrations(db: Queryable): number {
|
|
14
16
|
return REQUIRED_MIGRATIONS[engineOf(db)];
|
|
15
17
|
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Every migration this version ships, oldest first, per engine: read from
|
|
21
|
+
* the journals at build time, so a Worker, which has no files, knows them
|
|
22
|
+
* too. A database that has applied fewer is behind this code, whatever
|
|
23
|
+
* `REQUIRED_MIGRATIONS` lets it run on.
|
|
24
|
+
*/
|
|
25
|
+
export const KNOWN_MIGRATIONS: Record<Engine, readonly string[]> = {
|
|
26
|
+
postgres: postgresJournal.entries.map((entry) => entry.tag),
|
|
27
|
+
sqlite: sqliteJournal.entries.map((entry) => entry.tag),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function knownMigrations(db: Queryable): readonly string[] {
|
|
31
|
+
return KNOWN_MIGRATIONS[engineOf(db)];
|
|
32
|
+
}
|