@juit/pgproxy-utils 1.2.1 → 1.3.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/dist/database.cjs +71 -12
- package/dist/database.cjs.map +1 -1
- package/dist/database.mjs +72 -12
- package/dist/database.mjs.map +1 -1
- package/dist/extract.cjs +68 -21
- package/dist/extract.cjs.map +1 -1
- package/dist/extract.d.ts +0 -1
- package/dist/extract.mjs +69 -21
- package/dist/extract.mjs.map +1 -1
- package/dist/migrate.cjs +101 -47
- package/dist/migrate.cjs.map +1 -1
- package/dist/migrate.mjs +102 -47
- package/dist/migrate.mjs.map +1 -1
- package/dist/serialize.cjs +0 -1
- package/dist/serialize.cjs.map +1 -1
- package/dist/serialize.d.ts +0 -1
- package/dist/serialize.mjs +0 -1
- package/dist/serialize.mjs.map +1 -1
- package/package.json +5 -5
- package/src/database.ts +5 -7
- package/src/extract.ts +3 -9
- package/src/migrate.ts +81 -82
- package/src/serialize.ts +0 -1
package/src/migrate.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import crypto from 'node:crypto'
|
|
2
2
|
import { basename } from 'node:path'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { PGClient, SQL } from '@juit/pgproxy-client'
|
|
5
5
|
import { $blu, $grn, $gry, $ms, $und, $ylw, find, fs, log, merge, resolve } from '@plugjs/plug'
|
|
6
6
|
|
|
7
|
-
import type { InferSelectType } from '@juit/pgproxy-persister'
|
|
8
|
-
|
|
9
7
|
/* ========================================================================== *
|
|
10
8
|
* INTERNALS *
|
|
11
9
|
* ========================================================================== */
|
|
@@ -19,14 +17,12 @@ type Migration = {
|
|
|
19
17
|
name: string,
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
interface
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
sha256sum: { type: Buffer },
|
|
29
|
-
},
|
|
20
|
+
interface AppliedMigration {
|
|
21
|
+
group: string,
|
|
22
|
+
number: number,
|
|
23
|
+
name: string,
|
|
24
|
+
timestamp: Date,
|
|
25
|
+
sha256sum: Buffer,
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
/* ========================================================================== *
|
|
@@ -98,80 +94,83 @@ export async function migrate(
|
|
|
98
94
|
|
|
99
95
|
/* Start our gigantic migrations transaction */
|
|
100
96
|
const now = Date.now()
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const prevHash = Buffer.from(prev.sha256sum).toString('hex').substring(0, 6)
|
|
152
|
-
throw new Error(`Migration ${group}@${num} (${name}) has checksum "${currHash}" but was recorded as "${prevHash}"`)
|
|
153
|
-
}
|
|
97
|
+
await using client = new PGClient(url)
|
|
98
|
+
await using connection = await client.connect()
|
|
99
|
+
|
|
100
|
+
const info = await connection.query<{ name: string }>('SELECT current_database() AS name')
|
|
101
|
+
log.notice(`Migrating database ${$ylw((info.rows[0]!.name))} ${$gry(`(group=${group})`)}`)
|
|
102
|
+
|
|
103
|
+
// const model = connection.in('$migrations')
|
|
104
|
+
|
|
105
|
+
log.info('Beginning migrations transaction')
|
|
106
|
+
await connection.begin()
|
|
107
|
+
|
|
108
|
+
/* First of all, make sure we have our "$migrations" table */
|
|
109
|
+
log.info(`Ensuring presence of ${$blu('$migrations')} table`)
|
|
110
|
+
await connection.query(`
|
|
111
|
+
SET LOCAL client_min_messages TO WARNING;
|
|
112
|
+
CREATE TABLE IF NOT EXISTS "$migrations" (
|
|
113
|
+
"group" VARCHAR(32) NOT NULL DEFAULT 'default',
|
|
114
|
+
"number" INTEGER NOT NULL,
|
|
115
|
+
"name" TEXT NOT NULL,
|
|
116
|
+
"timestamp" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
117
|
+
"sha256sum" BYTEA NOT NULL,
|
|
118
|
+
PRIMARY KEY ("group", "number")
|
|
119
|
+
);`)
|
|
120
|
+
|
|
121
|
+
/* Lock our migrations table */
|
|
122
|
+
log.info(`Lock exclusive use of ${$blu('$migrations')} table`)
|
|
123
|
+
await connection.query('LOCK TABLE "$migrations"')
|
|
124
|
+
|
|
125
|
+
/* Gather all applied migrations */
|
|
126
|
+
log.info(`Looking for entries in ${$blu('$migrations')} table ${$gry(`(group=${group})`)}`)
|
|
127
|
+
const result = await connection.query<AppliedMigration>(
|
|
128
|
+
SQL`SELECT * FROM "$migrations" WHERE "group" = ${group}`,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
/* Reduce all existing migration, keying them by number */
|
|
132
|
+
const applied = result.rows.reduce((applied, row) => {
|
|
133
|
+
const { group, number, name, timestamp, sha256sum } = row
|
|
134
|
+
applied[number] = { group, number, name, timestamp, sha256sum }
|
|
135
|
+
return applied
|
|
136
|
+
}, {} as Record<number, AppliedMigration>)
|
|
137
|
+
|
|
138
|
+
/* Apply our migrations */
|
|
139
|
+
let count = 0
|
|
140
|
+
for (const { number, name, contents, sha256sum } of migrationFiles) {
|
|
141
|
+
const num = `${number}`.padStart(3, '0')
|
|
142
|
+
const prev = applied[number]
|
|
143
|
+
if (prev) {
|
|
144
|
+
if (sha256sum.equals(prev.sha256sum)) {
|
|
145
|
+
const timestamp = prev.timestamp.toISOString().substring(0, 19).replace('T', ' ')
|
|
146
|
+
log.notice(`Skipping migration ${$gry(`${group}@`)}${$grn(num)}: ${$blu(name)}`, $gry(`applied on ${$und(timestamp)}`))
|
|
154
147
|
} else {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
148
|
+
log.error(`Failed migration ${$gry(`${group}@`)}${$grn(num)}: ${$ylw(name)}`)
|
|
149
|
+
const currHash = sha256sum.toString('hex').substring(0, 6)
|
|
150
|
+
const prevHash = Buffer.from(prev.sha256sum).toString('hex').substring(0, 6)
|
|
151
|
+
throw new Error(`Migration ${group}@${num} (${name}) has checksum "${currHash}" but was recorded as "${prevHash}"`)
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
try {
|
|
155
|
+
log.notice(`Applying migration ${$gry(`${group}@`)}${$grn(num)}: ${$blu(name)}`)
|
|
156
|
+
await connection.query(contents)
|
|
157
|
+
await connection.query(SQL`INSERT INTO "$migrations" ("group", "number", "name", "sha256sum")
|
|
158
|
+
VALUES (${group}, ${number}, ${name}, ${sha256sum})`)
|
|
159
|
+
count ++
|
|
160
|
+
} catch (error: any) {
|
|
161
|
+
log.error(`Failed migration ${$gry(`${group}@`)}${$grn(num)}: ${$ylw(name)}`)
|
|
162
|
+
const message = error.message.split('\n').map((s: string) => ` ${s}`).join('\n')
|
|
163
|
+
error.message = `Failed migration ${group}@${num} (${name}):\n${message}`
|
|
164
|
+
throw error
|
|
166
165
|
}
|
|
167
166
|
}
|
|
167
|
+
}
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
/* Commit our migrations */
|
|
170
|
+
log.info('Committing migrations transaction')
|
|
171
|
+
await connection.commit()
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}).finally(() => persister.destroy())
|
|
173
|
+
/* All done */
|
|
174
|
+
log.notice(`Applied ${$ylw(count)} migrations ${$ms(Date.now() - now)}`)
|
|
175
|
+
return count
|
|
177
176
|
}
|
package/src/serialize.ts
CHANGED