@coffre/db 0.1.1 → 0.1.3
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/log.d.ts +7 -1
- package/dist/log.js +8 -1
- package/dist/migrate.d.ts +11 -2
- package/dist/migrate.js +12 -3
- package/package.json +2 -2
- package/src/log.ts +13 -1
- package/src/migrate.ts +12 -3
package/dist/log.d.ts
CHANGED
|
@@ -68,5 +68,11 @@ export declare function lockLogHead(tx: Transaction): Promise<{
|
|
|
68
68
|
nextSeq: bigint;
|
|
69
69
|
headHash: Buffer;
|
|
70
70
|
}>;
|
|
71
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Append `entries` under `key`. `check`, when given, runs once the head is
|
|
73
|
+
* locked and before anything is written: a writer's own condition on the
|
|
74
|
+
* log as it stands, which no other append can change until this one
|
|
75
|
+
* commits. It throws to refuse.
|
|
76
|
+
*/
|
|
77
|
+
export declare function appendEntries(tx: Transaction, key: LogKey, entries: readonly NewEntry[], check?: (tx: Transaction) => Promise<void>): Promise<Appended>;
|
|
72
78
|
//#endregion
|
package/dist/log.js
CHANGED
|
@@ -60,10 +60,17 @@ async function lockLogHead(tx) {
|
|
|
60
60
|
if (head === void 0) throw new Error("audit_chain_head is missing; refusing to write an unchained entry");
|
|
61
61
|
return head;
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Append `entries` under `key`. `check`, when given, runs once the head is
|
|
65
|
+
* locked and before anything is written: a writer's own condition on the
|
|
66
|
+
* log as it stands, which no other append can change until this one
|
|
67
|
+
* commits. It throws to refuse.
|
|
68
|
+
*/
|
|
69
|
+
async function appendEntries(tx, key, entries, check) {
|
|
64
70
|
if (entries.length === 0) throw new Error("appendEntries called with no entries");
|
|
65
71
|
const { auditChainHead, auditLog } = tablesOf(tx);
|
|
66
72
|
const head = await lockLogHead(tx);
|
|
73
|
+
await check?.(tx);
|
|
67
74
|
const [{ now }] = await tx.select({ now: clockMillis(tx) }).from(auditChainHead);
|
|
68
75
|
const [last] = await tx.select({
|
|
69
76
|
seq: auditLog.seq,
|
package/dist/migrate.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ import { Engine } from "./dialect.js";
|
|
|
5
5
|
* in the built package, where the build copies them.
|
|
6
6
|
*/
|
|
7
7
|
export declare function migrationsFolder(engine: Engine): string;
|
|
8
|
-
/**
|
|
9
|
-
export
|
|
8
|
+
/** A migration run's plan: `applied` of the `total` migrations there before it, the rest applied by it. */
|
|
9
|
+
export type MigrationPlan = {
|
|
10
|
+
applied: number;
|
|
11
|
+
total: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Apply missing migrations, check their history and reassert database
|
|
15
|
+
* privileges. `onPlan` hears how many there are to apply before they are:
|
|
16
|
+
* all of them go in one call, with no word of each.
|
|
17
|
+
*/
|
|
18
|
+
export declare function migrateDatabase(url: string, onPlan?: (plan: MigrationPlan) => void): Promise<void>;
|
|
10
19
|
//#endregion
|
package/dist/migrate.js
CHANGED
|
@@ -102,8 +102,12 @@ async function sqliteMigrator(url) {
|
|
|
102
102
|
close
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
/**
|
|
106
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Apply missing migrations, check their history and reassert database
|
|
107
|
+
* privileges. `onPlan` hears how many there are to apply before they are:
|
|
108
|
+
* all of them go in one call, with no word of each.
|
|
109
|
+
*/
|
|
110
|
+
async function migrateDatabase(url, onPlan) {
|
|
107
111
|
const engine = engineOfUrl(url);
|
|
108
112
|
const expected = await expectedMigrations(engine);
|
|
109
113
|
const migrator = await {
|
|
@@ -114,7 +118,12 @@ async function migrateDatabase(url) {
|
|
|
114
118
|
try {
|
|
115
119
|
await migrator.lock();
|
|
116
120
|
locked = true;
|
|
117
|
-
|
|
121
|
+
const applied = await migrator.applied();
|
|
122
|
+
verifyHistory(expected, applied, false);
|
|
123
|
+
onPlan?.({
|
|
124
|
+
applied: applied?.length ?? 0,
|
|
125
|
+
total: expected.length
|
|
126
|
+
});
|
|
118
127
|
await migrator.migrate(migrationsFolder(engine));
|
|
119
128
|
verifyHistory(expected, await migrator.applied(), true);
|
|
120
129
|
await migrator.restrict();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffre/db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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.3"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@types/node": "26.1.1",
|
package/src/log.ts
CHANGED
|
@@ -111,12 +111,24 @@ export async function lockLogHead(tx: Transaction): Promise<{ nextSeq: bigint; h
|
|
|
111
111
|
return head;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Append `entries` under `key`. `check`, when given, runs once the head is
|
|
116
|
+
* locked and before anything is written: a writer's own condition on the
|
|
117
|
+
* log as it stands, which no other append can change until this one
|
|
118
|
+
* commits. It throws to refuse.
|
|
119
|
+
*/
|
|
120
|
+
export async function appendEntries(
|
|
121
|
+
tx: Transaction,
|
|
122
|
+
key: LogKey,
|
|
123
|
+
entries: readonly NewEntry[],
|
|
124
|
+
check?: (tx: Transaction) => Promise<void>,
|
|
125
|
+
): Promise<Appended> {
|
|
115
126
|
if (entries.length === 0) throw new Error('appendEntries called with no entries');
|
|
116
127
|
const { auditChainHead, auditLog } = tablesOf(tx);
|
|
117
128
|
|
|
118
129
|
// Every append queues here, if its transaction has not already.
|
|
119
130
|
const head = await lockLogHead(tx);
|
|
131
|
+
await check?.(tx);
|
|
120
132
|
const [{ now }] = await tx.select({ now: clockMillis(tx) }).from(auditChainHead);
|
|
121
133
|
const [last] = await tx
|
|
122
134
|
.select({ seq: auditLog.seq, hash: auditLog.hash })
|
package/src/migrate.ts
CHANGED
|
@@ -182,8 +182,15 @@ async function sqliteMigrator(url: string): Promise<Migrator> {
|
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
/**
|
|
186
|
-
export
|
|
185
|
+
/** A migration run's plan: `applied` of the `total` migrations there before it, the rest applied by it. */
|
|
186
|
+
export type MigrationPlan = { applied: number; total: number };
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Apply missing migrations, check their history and reassert database
|
|
190
|
+
* privileges. `onPlan` hears how many there are to apply before they are:
|
|
191
|
+
* all of them go in one call, with no word of each.
|
|
192
|
+
*/
|
|
193
|
+
export async function migrateDatabase(url: string, onPlan?: (plan: MigrationPlan) => void): Promise<void> {
|
|
187
194
|
const engine = engineOfUrl(url);
|
|
188
195
|
const expected = await expectedMigrations(engine);
|
|
189
196
|
const migrator = await { postgres: postgresMigrator, sqlite: sqliteMigrator }[engine](url);
|
|
@@ -193,7 +200,9 @@ export async function migrateDatabase(url: string): Promise<void> {
|
|
|
193
200
|
await migrator.lock();
|
|
194
201
|
locked = true;
|
|
195
202
|
|
|
196
|
-
|
|
203
|
+
const applied = await migrator.applied();
|
|
204
|
+
verifyHistory(expected, applied, false);
|
|
205
|
+
onPlan?.({ applied: applied?.length ?? 0, total: expected.length });
|
|
197
206
|
await migrator.migrate(migrationsFolder(engine));
|
|
198
207
|
verifyHistory(expected, await migrator.applied(), true);
|
|
199
208
|
await migrator.restrict();
|