Skip to content

Commit 27b22f4

Browse files
authored
builtins: generate in 1 command (#164)
1 parent 5b26b82 commit 27b22f4

File tree

8 files changed

+298
-71
lines changed

8 files changed

+298
-71
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,15 @@ jobs:
5353
node-version: '20'
5454
- run: npm install
5555
- run: npm run test-ts
56+
57+
generate:
58+
timeout-minutes: 5
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: actions/checkout@v4
62+
- uses: actions/setup-node@v4
63+
with:
64+
node-version: '20'
65+
- run: npm install
66+
- run: npm run generate
67+
- run: git diff --exit-code lib/

generator/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# PostgreSQL Type OID Generator
2+
3+
Generates PostgreSQL builtin type OIDs for `node-pg-types`.
4+
5+
## Usage
6+
7+
```sh
8+
npm install
9+
npm run generate
10+
```
11+
12+
This will:
13+
14+
- Start all specified Postgres versions in containers
15+
- Run the generator in another container
16+
- Query for builtin type OIDs
17+
- Generate `../lib/builtins.js`
18+
- Tear down the containers
19+
20+
## Adding PostgreSQL Versions
21+
22+
To query additional PostgreSQL versions, edit the files in this directory:
23+
24+
1. Update the version list in `generate.js`
25+
2. Add the new PostgreSQL service to `docker-compose.yml`
26+
3. Add the service dependency to the generator service instructing it to wait for the PostgreSQL service to be ready
27+
28+
Types from multiple PostgreSQL versions are automatically merged.

generator/docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
services:
2+
postgres-11:
3+
image: postgres:11-alpine
4+
environment:
5+
POSTGRES_PASSWORD: postgres
6+
healthcheck:
7+
test: ["CMD-SHELL", "pg_isready"]
8+
interval: 5s
9+
timeout: 5s
10+
retries: 5
11+
12+
generator:
13+
image: node:20-alpine
14+
working_dir: /app
15+
command: node generator/generate.js
16+
depends_on:
17+
postgres-11:
18+
condition: service_healthy
19+
volumes:
20+
- ../:/app
21+
environment:
22+
OUTPUT_PATH: /app/lib

generator/generate.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env node
2+
3+
const { Client } = require('pg')
4+
const fs = require('fs')
5+
const path = require('path')
6+
7+
const query = `
8+
SELECT json_object_agg(UPPER(PT.typname), PT.oid::int4 ORDER BY pt.oid)
9+
FROM pg_type PT
10+
WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)
11+
AND typtype = 'b' -- Only basic types
12+
AND typelem = 0 -- Ignore aliases
13+
AND typisdefined -- Ignore undefined types
14+
`
15+
16+
const postgresVersions = ['11']
17+
18+
async function queryPostgresVersion (version) {
19+
const host = `postgres-${version}`
20+
console.log(`Querying PostgreSQL ${version} at ${host}...`)
21+
22+
const client = new Client({
23+
host: host,
24+
port: 5432,
25+
user: process.env.PGUSER || 'postgres',
26+
password: process.env.PGPASSWORD || 'postgres',
27+
database: process.env.PGDATABASE || 'postgres'
28+
})
29+
30+
try {
31+
await client.connect()
32+
const result = await client.query(query)
33+
const types = result.rows[0].json_object_agg
34+
console.log(`Found ${Object.keys(types).length} types in PostgreSQL ${version}`)
35+
return types
36+
} finally {
37+
await client.end()
38+
}
39+
}
40+
41+
async function generate () {
42+
console.log('Starting PostgreSQL type generation...')
43+
44+
// Query all available PostgreSQL versions in parallel
45+
const typeResults = await Promise.all(
46+
postgresVersions.map(version => queryPostgresVersion(version))
47+
)
48+
49+
// Merge all types from different versions
50+
let allTypes = {}
51+
for (const types of typeResults) {
52+
allTypes = { ...allTypes, ...types }
53+
}
54+
55+
console.log(`Total unique types found: ${Object.keys(allTypes).length}`)
56+
57+
// Determine output directory
58+
const outputDir = process.env.OUTPUT_PATH || path.join(__dirname, '..', 'lib')
59+
60+
// Generate main builtins file
61+
const header = `/**
62+
PostgreSQL builtin type OIDs
63+
64+
DO NOT EDIT THIS FILE BY HAND!
65+
This file is generated automatically by the generator in generator/generate.js
66+
To modify the types, edit the generator script and run: npm run generate
67+
68+
Generated by querying PostgreSQL ${postgresVersions.join(', ')} to ensure comprehensive
69+
type coverage for parsing.
70+
71+
Query used:
72+
${query.trim()}
73+
*/`
74+
75+
const entries = Object.entries(allTypes)
76+
.sort(([, a], [, b]) => a - b)
77+
.map(([name, oid]) => ` ${name}: ${oid}`)
78+
.join(',\n')
79+
80+
const content = `${header}
81+
82+
module.exports = {
83+
${entries}
84+
}
85+
`
86+
87+
// Write main builtins file
88+
const outputPath = path.join(outputDir, 'builtins.js')
89+
await fs.promises.writeFile(outputPath, content)
90+
91+
// Generate TypeScript definitions
92+
const tsHeader = `/**
93+
PostgreSQL builtin type OIDs (TypeScript definitions)
94+
95+
DO NOT EDIT THIS FILE BY HAND!
96+
This file is generated automatically by the generator in generator/generate.js
97+
To modify the types, edit the generator script and run: npm run generate
98+
99+
Generated by querying PostgreSQL ${postgresVersions.join(', ')} to ensure comprehensive
100+
type coverage for parsing.
101+
102+
Query used:
103+
${query.trim()}
104+
*/`
105+
106+
const tsEntries = Object.entries(allTypes)
107+
.sort(([, a], [, b]) => a - b)
108+
.map(([name, oid]) => ` ${name} = ${oid}`)
109+
.join(',\n')
110+
111+
const tsContent = `${tsHeader}
112+
113+
export enum builtins {
114+
${tsEntries}
115+
}
116+
`
117+
118+
// Write TypeScript definitions file
119+
const tsOutputPath = path.join(outputDir, 'builtins.d.ts')
120+
await fs.promises.writeFile(tsOutputPath, tsContent)
121+
122+
console.log('Generated lib/builtins.js and lib/builtins.d.ts successfully')
123+
}
124+
125+
async function main () {
126+
try {
127+
await generate()
128+
} catch (err) {
129+
console.error('Error generating types:', err)
130+
process.exit(1)
131+
}
132+
}
133+
134+
main()

index.d.ts

Lines changed: 4 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,8 @@
1-
export enum builtins {
2-
BOOL = 16,
3-
BYTEA = 17,
4-
CHAR = 18,
5-
INT8 = 20,
6-
INT2 = 21,
7-
INT4 = 23,
8-
REGPROC = 24,
9-
TEXT = 25,
10-
OID = 26,
11-
TID = 27,
12-
XID = 28,
13-
CID = 29,
14-
JSON = 114,
15-
XML = 142,
16-
PG_NODE_TREE = 194,
17-
SMGR = 210,
18-
PATH = 602,
19-
POLYGON = 604,
20-
CIDR = 650,
21-
FLOAT4 = 700,
22-
FLOAT8 = 701,
23-
ABSTIME = 702,
24-
RELTIME = 703,
25-
TINTERVAL = 704,
26-
CIRCLE = 718,
27-
MACADDR8 = 774,
28-
MONEY = 790,
29-
MACADDR = 829,
30-
INET = 869,
31-
ACLITEM = 1033,
32-
BPCHAR = 1042,
33-
VARCHAR = 1043,
34-
DATE = 1082,
35-
TIME = 1083,
36-
TIMESTAMP = 1114,
37-
TIMESTAMPTZ = 1184,
38-
INTERVAL = 1186,
39-
TIMETZ = 1266,
40-
BIT = 1560,
41-
VARBIT = 1562,
42-
NUMERIC = 1700,
43-
REFCURSOR = 1790,
44-
REGPROCEDURE = 2202,
45-
REGOPER = 2203,
46-
REGOPERATOR = 2204,
47-
REGCLASS = 2205,
48-
REGTYPE = 2206,
49-
UUID = 2950,
50-
TXID_SNAPSHOT = 2970,
51-
PG_LSN = 3220,
52-
PG_NDISTINCT = 3361,
53-
PG_DEPENDENCIES = 3402,
54-
TSVECTOR = 3614,
55-
TSQUERY = 3615,
56-
GTSVECTOR = 3642,
57-
REGCONFIG = 3734,
58-
REGDICTIONARY = 3769,
59-
JSONB = 3802,
60-
REGNAMESPACE = 4089,
61-
REGROLE = 4096
62-
}
1+
import * as _builtins from './lib/builtins';
632

64-
export type TypeId = builtins;
65-
export type TypesBuiltins = typeof builtins;
3+
export const builtins: typeof _builtins.builtins;
4+
export type TypeId = _builtins.builtins;
5+
export type TypesBuiltins = typeof _builtins.builtins;
666

677
export type TypeParser<I extends (string | Buffer), T> = (value: I) => T;
688

lib/builtins.d.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
PostgreSQL builtin type OIDs (TypeScript definitions)
3+
4+
DO NOT EDIT THIS FILE BY HAND!
5+
This file is generated automatically by the generator in generator/generate.js
6+
To modify the types, edit the generator script and run: npm run generate
7+
8+
Generated by querying PostgreSQL 11 to ensure comprehensive
9+
type coverage for parsing.
10+
11+
Query used:
12+
SELECT json_object_agg(UPPER(PT.typname), PT.oid::int4 ORDER BY pt.oid)
13+
FROM pg_type PT
14+
WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)
15+
AND typtype = 'b' -- Only basic types
16+
AND typelem = 0 -- Ignore aliases
17+
AND typisdefined -- Ignore undefined types
18+
*/
19+
20+
export enum builtins {
21+
BOOL = 16,
22+
BYTEA = 17,
23+
CHAR = 18,
24+
INT8 = 20,
25+
INT2 = 21,
26+
INT4 = 23,
27+
REGPROC = 24,
28+
TEXT = 25,
29+
OID = 26,
30+
TID = 27,
31+
XID = 28,
32+
CID = 29,
33+
JSON = 114,
34+
XML = 142,
35+
PG_NODE_TREE = 194,
36+
SMGR = 210,
37+
PATH = 602,
38+
POLYGON = 604,
39+
CIDR = 650,
40+
FLOAT4 = 700,
41+
FLOAT8 = 701,
42+
ABSTIME = 702,
43+
RELTIME = 703,
44+
TINTERVAL = 704,
45+
CIRCLE = 718,
46+
MACADDR8 = 774,
47+
MONEY = 790,
48+
MACADDR = 829,
49+
INET = 869,
50+
ACLITEM = 1033,
51+
BPCHAR = 1042,
52+
VARCHAR = 1043,
53+
DATE = 1082,
54+
TIME = 1083,
55+
TIMESTAMP = 1114,
56+
TIMESTAMPTZ = 1184,
57+
INTERVAL = 1186,
58+
TIMETZ = 1266,
59+
BIT = 1560,
60+
VARBIT = 1562,
61+
NUMERIC = 1700,
62+
REFCURSOR = 1790,
63+
REGPROCEDURE = 2202,
64+
REGOPER = 2203,
65+
REGOPERATOR = 2204,
66+
REGCLASS = 2205,
67+
REGTYPE = 2206,
68+
UUID = 2950,
69+
TXID_SNAPSHOT = 2970,
70+
PG_LSN = 3220,
71+
PG_NDISTINCT = 3361,
72+
PG_DEPENDENCIES = 3402,
73+
TSVECTOR = 3614,
74+
TSQUERY = 3615,
75+
GTSVECTOR = 3642,
76+
REGCONFIG = 3734,
77+
REGDICTIONARY = 3769,
78+
JSONB = 3802,
79+
REGNAMESPACE = 4089,
80+
REGROLE = 4096
81+
}

lib/builtins.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
/**
2-
* Following query was used to generate this file:
2+
PostgreSQL builtin type OIDs
33
4-
SELECT json_object_agg(UPPER(PT.typname), PT.oid::int4 ORDER BY pt.oid)
5-
FROM pg_type PT
6-
WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)
7-
AND typtype = 'b' -- Only basic types
8-
AND typelem = 0 -- Ignore aliases
9-
AND typisdefined -- Ignore undefined types
4+
DO NOT EDIT THIS FILE BY HAND!
5+
This file is generated automatically by the generator in generator/generate.js
6+
To modify the types, edit the generator script and run: npm run generate
7+
8+
Generated by querying PostgreSQL 11 to ensure comprehensive
9+
type coverage for parsing.
10+
11+
Query used:
12+
SELECT json_object_agg(UPPER(PT.typname), PT.oid::int4 ORDER BY pt.oid)
13+
FROM pg_type PT
14+
WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)
15+
AND typtype = 'b' -- Only basic types
16+
AND typelem = 0 -- Ignore aliases
17+
AND typisdefined -- Ignore undefined types
1018
*/
1119

1220
module.exports = {

0 commit comments

Comments
 (0)