@juit/pgproxy-utils 1.2.0 → 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/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 { Persister } from '@juit/pgproxy-persister'
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 MigrationSchema {
23
- $migrations: {
24
- group: { type: string, hasDefault: true },
25
- number: { type: number },
26
- name: { type: string },
27
- timestamp: { type: Date, hasDefault: true },
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
- const persister = new Persister<MigrationSchema>(url)
102
- return await persister.connect(async (connection) => {
103
- const info = await connection.query<{ name: string }>('SELECT current_database() AS name')
104
- log.notice(`Migrating database ${$ylw((info.rows[0]!.name))}`)
105
-
106
- const model = connection.in('$migrations')
107
-
108
- log.info('Beginning migrations transaction')
109
- await connection.begin()
110
-
111
- /* First of all, make sure we have our "$migrations" table */
112
- log.info(`Ensuring presence of ${$blu('$migrations')} table`)
113
- await connection.query(`
114
- SET LOCAL client_min_messages TO WARNING;
115
- CREATE TABLE IF NOT EXISTS "$migrations" (
116
- "group" VARCHAR(32) NOT NULL DEFAULT 'default',
117
- "number" INTEGER NOT NULL,
118
- "name" TEXT NOT NULL,
119
- "timestamp" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
120
- "sha256sum" BYTEA NOT NULL,
121
- PRIMARY KEY ("group", "number")
122
- );`)
123
-
124
- /* Lock our migrations table */
125
- log.info(`Lock exclusive use of ${$blu('$migrations')} table`)
126
- await connection.query('LOCK TABLE "$migrations"')
127
-
128
- /* Gather all applied migrations */
129
- log.info(`Looking for entries in ${$blu('$migrations')} table`)
130
- const result = await model.read({ group })
131
-
132
- /* Reduce all existing migration, keying them by number */
133
- const applied = result.reduce((applied, row) => {
134
- const { group, number, name, timestamp, sha256sum } = row
135
- applied[number] = { group, number, name, timestamp, sha256sum }
136
- return applied
137
- }, {} as Record<number, InferSelectType<MigrationSchema['$migrations']>>)
138
-
139
- /* Apply our migrations */
140
- let count = 0
141
- for (const { number, name, contents, sha256sum } of migrationFiles) {
142
- const num = `${number}`.padStart(3, '0')
143
- const prev = applied[number]
144
- if (prev) {
145
- if (sha256sum.equals(prev.sha256sum)) {
146
- const timestamp = prev.timestamp.toISOString().substring(0, 19).replace('T', ' ')
147
- log.notice(`Skipping migration ${$gry(`${group}@`)}${$grn(num)}: ${$blu(name)}`, $gry(`applied on ${$und(timestamp)}`))
148
- } else {
149
- log.error(`Failed migration ${$gry(`${group}@`)}${$grn(num)}: ${$ylw(name)}`)
150
- const currHash = sha256sum.toString('hex').substring(0, 6)
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
- try {
156
- log.notice(`Applying migration ${$gry(`${group}@`)}${$grn(num)}: ${$blu(name)}`)
157
- await connection.query(contents)
158
- await model.create({ 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
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
- /* Commit our migrations */
170
- log.info('Committing migrations transaction')
171
- await connection.commit()
169
+ /* Commit our migrations */
170
+ log.info('Committing migrations transaction')
171
+ await connection.commit()
172
172
 
173
- /* All done */
174
- log.notice(`Applied ${$ylw(count)} migrations ${$ms(Date.now() - now)}`)
175
- return count
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
@@ -1,4 +1,3 @@
1
- import '@juit/pgproxy-client-psql'
2
1
  import { PGOIDs } from '@juit/pgproxy-types'
3
2
  import ts from 'typescript'
4
3