@onreza/sqlx-js 0.0.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +496 -0
  3. package/ROADMAP.md +28 -0
  4. package/dist/bin/sqlx-js.d.ts +2 -0
  5. package/dist/bin/sqlx-js.js +180 -0
  6. package/dist/src/bun-runtime.d.ts +7 -0
  7. package/dist/src/bun-runtime.js +45 -0
  8. package/dist/src/bun.d.ts +22 -0
  9. package/dist/src/bun.js +9 -0
  10. package/dist/src/cache.d.ts +36 -0
  11. package/dist/src/cache.js +104 -0
  12. package/dist/src/codegen.d.ts +2 -0
  13. package/dist/src/codegen.js +74 -0
  14. package/dist/src/commands/migrate.d.ts +63 -0
  15. package/dist/src/commands/migrate.js +283 -0
  16. package/dist/src/commands/prepare.d.ts +23 -0
  17. package/dist/src/commands/prepare.js +314 -0
  18. package/dist/src/commands/schema.d.ts +14 -0
  19. package/dist/src/commands/schema.js +72 -0
  20. package/dist/src/commands/watch.d.ts +21 -0
  21. package/dist/src/commands/watch.js +94 -0
  22. package/dist/src/config.d.ts +6 -0
  23. package/dist/src/config.js +23 -0
  24. package/dist/src/index.d.ts +23 -0
  25. package/dist/src/index.js +10 -0
  26. package/dist/src/pg/analyze.d.ts +13 -0
  27. package/dist/src/pg/analyze.js +479 -0
  28. package/dist/src/pg/extensions.d.ts +2 -0
  29. package/dist/src/pg/extensions.js +15 -0
  30. package/dist/src/pg/narrow.d.ts +3 -0
  31. package/dist/src/pg/narrow.js +146 -0
  32. package/dist/src/pg/oids.d.ts +10 -0
  33. package/dist/src/pg/oids.js +137 -0
  34. package/dist/src/pg/param-map.d.ts +12 -0
  35. package/dist/src/pg/param-map.js +180 -0
  36. package/dist/src/pg/schema.d.ts +61 -0
  37. package/dist/src/pg/schema.js +225 -0
  38. package/dist/src/pg/wire.d.ts +134 -0
  39. package/dist/src/pg/wire.js +705 -0
  40. package/dist/src/postgres-runtime.d.ts +11 -0
  41. package/dist/src/postgres-runtime.js +150 -0
  42. package/dist/src/runtime.d.ts +69 -0
  43. package/dist/src/runtime.js +446 -0
  44. package/dist/src/scan/scanner.d.ts +12 -0
  45. package/dist/src/scan/scanner.js +283 -0
  46. package/dist/src/schema-snapshot.d.ts +104 -0
  47. package/dist/src/schema-snapshot.js +473 -0
  48. package/dist/src/typed.d.ts +25 -0
  49. package/dist/src/typed.js +1 -0
  50. package/package.json +78 -0
@@ -0,0 +1,137 @@
1
+ const SCALAR = {
2
+ 16: { ts: "boolean" },
3
+ 17: { ts: "Uint8Array" },
4
+ 18: { ts: "string" },
5
+ 19: { ts: "string" },
6
+ 20: { ts: "bigint", bigint: true },
7
+ 21: { ts: "number" },
8
+ 23: { ts: "number" },
9
+ 25: { ts: "string" },
10
+ 26: { ts: "number" },
11
+ 27: { ts: "string" },
12
+ 28: { ts: "string" },
13
+ 29: { ts: "string" },
14
+ 114: { ts: "unknown" },
15
+ 142: { ts: "string" },
16
+ 600: { ts: "string" },
17
+ 601: { ts: "string" },
18
+ 602: { ts: "string" },
19
+ 603: { ts: "string" },
20
+ 604: { ts: "string" },
21
+ 628: { ts: "string" },
22
+ 650: { ts: "string" },
23
+ 700: { ts: "number" },
24
+ 701: { ts: "number" },
25
+ 718: { ts: "string" },
26
+ 774: { ts: "string" },
27
+ 790: { ts: "string" },
28
+ 829: { ts: "string" },
29
+ 869: { ts: "string" },
30
+ 1042: { ts: "string" },
31
+ 1043: { ts: "string" },
32
+ 1082: { ts: "Date" },
33
+ 1083: { ts: "string" },
34
+ 1114: { ts: "Date" },
35
+ 1184: { ts: "Date" },
36
+ 1186: { ts: "string" },
37
+ 1266: { ts: "string" },
38
+ 1560: { ts: "string" },
39
+ 1562: { ts: "string" },
40
+ 1700: { ts: "string" },
41
+ 2950: { ts: "string" },
42
+ 2205: { ts: "string" },
43
+ 2206: { ts: "string" },
44
+ 3220: { ts: "string" },
45
+ 3614: { ts: "string" },
46
+ 3615: { ts: "string" },
47
+ 3802: { ts: "unknown" },
48
+ 3904: { ts: "string" },
49
+ 3906: { ts: "string" },
50
+ 3908: { ts: "string" },
51
+ 3910: { ts: "string" },
52
+ 3912: { ts: "string" },
53
+ 3926: { ts: "string" },
54
+ 4089: { ts: "string" },
55
+ 4096: { ts: "string" },
56
+ 4451: { ts: "string" },
57
+ 4536: { ts: "string" },
58
+ };
59
+ const ARRAY = {
60
+ 143: 142,
61
+ 199: 114,
62
+ 629: 628,
63
+ 651: 650,
64
+ 719: 718,
65
+ 775: 774,
66
+ 791: 790,
67
+ 1000: 16,
68
+ 1001: 17,
69
+ 1002: 18,
70
+ 1003: 19,
71
+ 1005: 21,
72
+ 1007: 23,
73
+ 1009: 25,
74
+ 1014: 1042,
75
+ 1015: 1043,
76
+ 1016: 20,
77
+ 1017: 600,
78
+ 1018: 601,
79
+ 1019: 602,
80
+ 1020: 603,
81
+ 1021: 700,
82
+ 1022: 701,
83
+ 1027: 604,
84
+ 1028: 26,
85
+ 1040: 829,
86
+ 1041: 869,
87
+ 1115: 1114,
88
+ 1182: 1082,
89
+ 1183: 1083,
90
+ 1185: 1184,
91
+ 1187: 1186,
92
+ 1231: 1700,
93
+ 1270: 1266,
94
+ 1561: 1560,
95
+ 1563: 1562,
96
+ 2951: 2950,
97
+ 3221: 3220,
98
+ 3643: 3614,
99
+ 3644: 3615,
100
+ 3807: 3802,
101
+ 3905: 3904,
102
+ 3907: 3906,
103
+ 3909: 3908,
104
+ 3911: 3910,
105
+ 3913: 3912,
106
+ 3927: 3926,
107
+ 6150: 4451,
108
+ 6157: 4536,
109
+ };
110
+ export function oidToTs(oid) {
111
+ const direct = SCALAR[oid];
112
+ if (direct)
113
+ return direct;
114
+ const inner = ARRAY[oid];
115
+ if (inner !== undefined) {
116
+ const t = SCALAR[inner];
117
+ return { ts: `(${t?.ts ?? "unknown"})[]`, bigint: t?.bigint };
118
+ }
119
+ return { ts: "unknown" };
120
+ }
121
+ export function isBuiltinOid(oid) {
122
+ return SCALAR[oid] !== undefined || ARRAY[oid] !== undefined;
123
+ }
124
+ export function builtinArrayOids() {
125
+ return Object.keys(ARRAY).map(Number);
126
+ }
127
+ export function arrayElementOid(oid) {
128
+ return ARRAY[oid];
129
+ }
130
+ export function makeResolver(custom) {
131
+ return (oid) => {
132
+ const c = custom(oid);
133
+ if (c !== undefined)
134
+ return c;
135
+ return oidToTs(oid).ts;
136
+ };
137
+ }
@@ -0,0 +1,12 @@
1
+ export type ParamTarget = {
2
+ schema?: string;
3
+ table: string;
4
+ column: string;
5
+ };
6
+ export type ParamMap = Map<number, ParamTarget>;
7
+ export type ParamMapResult = {
8
+ targets: ParamMap;
9
+ forceNullable: Set<number>;
10
+ dmlBound: Set<number>;
11
+ };
12
+ export declare function buildParamMap(sql: string): Promise<ParamMapResult>;
@@ -0,0 +1,180 @@
1
+ import { parse } from "libpg-query";
2
+ export async function buildParamMap(sql) {
3
+ const targets = new Map();
4
+ const forceNullable = new Set();
5
+ const dmlBound = new Set();
6
+ const ast = await parse(sql);
7
+ const stmt = ast?.stmts?.[0]?.stmt;
8
+ if (!stmt)
9
+ return { targets, forceNullable, dmlBound };
10
+ if (stmt.InsertStmt)
11
+ walkInsert(stmt.InsertStmt, targets, dmlBound);
12
+ else if (stmt.UpdateStmt)
13
+ walkUpdate(stmt.UpdateStmt, targets, dmlBound);
14
+ else if (stmt.SelectStmt)
15
+ walkWhere(stmt.SelectStmt.whereClause, defaultRel(stmt.SelectStmt), targets);
16
+ else if (stmt.DeleteStmt)
17
+ walkWhere(stmt.DeleteStmt.whereClause, relOf(stmt.DeleteStmt.relation), targets);
18
+ walkForceNullable(stmt, false, forceNullable);
19
+ return { targets, forceNullable, dmlBound };
20
+ }
21
+ function walkInsert(ins, map, dmlBound) {
22
+ const rel = relOf(ins.relation);
23
+ if (!rel)
24
+ return;
25
+ const cols = (ins.cols ?? [])
26
+ .map((c) => c?.ResTarget?.name)
27
+ .filter((n) => typeof n === "string");
28
+ const valuesLists = ins.selectStmt?.SelectStmt?.valuesLists ?? [];
29
+ for (const row of valuesLists) {
30
+ const items = row?.List?.items ?? [];
31
+ for (let i = 0; i < items.length; i++) {
32
+ const colName = cols[i];
33
+ if (!colName)
34
+ continue;
35
+ const pn = paramNumber(items[i]);
36
+ if (pn !== null) {
37
+ map.set(pn, { ...rel, column: colName });
38
+ dmlBound.add(pn);
39
+ }
40
+ }
41
+ }
42
+ if (ins.returningList) {
43
+ for (const rt of ins.returningList) {
44
+ collectFromExpr(rt?.ResTarget?.val, rel, map);
45
+ }
46
+ }
47
+ walkWhere(ins.whereClause, rel, map);
48
+ }
49
+ function walkUpdate(upd, map, dmlBound) {
50
+ const rel = relOf(upd.relation);
51
+ if (!rel)
52
+ return;
53
+ for (const rt of upd.targetList ?? []) {
54
+ const colName = rt?.ResTarget?.name;
55
+ if (typeof colName !== "string")
56
+ continue;
57
+ const pn = paramNumber(rt.ResTarget.val);
58
+ if (pn !== null) {
59
+ map.set(pn, { ...rel, column: colName });
60
+ dmlBound.add(pn);
61
+ }
62
+ }
63
+ walkWhere(upd.whereClause, rel, map);
64
+ }
65
+ function walkWhere(node, defaultRel, map) {
66
+ if (!node || !defaultRel)
67
+ return;
68
+ if (node.BoolExpr) {
69
+ for (const a of node.BoolExpr.args ?? [])
70
+ walkWhere(a, defaultRel, map);
71
+ return;
72
+ }
73
+ if (node.A_Expr) {
74
+ collectFromExpr(node, defaultRel, map);
75
+ return;
76
+ }
77
+ }
78
+ function collectFromExpr(node, defaultRel, map) {
79
+ if (!node || !defaultRel)
80
+ return;
81
+ if (node.A_Expr) {
82
+ const e = node.A_Expr;
83
+ const opName = e.name?.[0]?.String?.sval;
84
+ if (e.kind === "AEXPR_OP" && opName === "=") {
85
+ tryBind(e.lexpr, e.rexpr, defaultRel, map);
86
+ tryBind(e.rexpr, e.lexpr, defaultRel, map);
87
+ }
88
+ if (e.kind === "AEXPR_IN") {
89
+ const colName = colNameOf(e.lexpr);
90
+ if (colName) {
91
+ const list = Array.isArray(e.rexpr) ? e.rexpr : [];
92
+ for (const item of list) {
93
+ const pn = paramNumber(item);
94
+ if (pn !== null)
95
+ map.set(pn, { ...defaultRel, column: colName });
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ function tryBind(colSide, valSide, defaultRel, map) {
102
+ const colName = colNameOf(colSide);
103
+ const pn = paramNumber(valSide);
104
+ if (colName !== null && pn !== null)
105
+ map.set(pn, { ...defaultRel, column: colName });
106
+ }
107
+ function colNameOf(node) {
108
+ if (!node?.ColumnRef)
109
+ return null;
110
+ const fields = node.ColumnRef.fields;
111
+ if (!Array.isArray(fields) || fields.length === 0)
112
+ return null;
113
+ if (fields.some((f) => f.A_Star !== undefined))
114
+ return null;
115
+ return fields[fields.length - 1]?.String?.sval ?? null;
116
+ }
117
+ function paramNumber(node) {
118
+ if (node?.ParamRef && typeof node.ParamRef.number === "number")
119
+ return node.ParamRef.number;
120
+ if (node?.TypeCast)
121
+ return paramNumber(node.TypeCast.arg);
122
+ return null;
123
+ }
124
+ function relOf(relation) {
125
+ if (!relation)
126
+ return null;
127
+ const name = relation.relname;
128
+ if (typeof name !== "string")
129
+ return null;
130
+ return { schema: relation.schemaname || undefined, table: name };
131
+ }
132
+ function defaultRel(select) {
133
+ const from = select?.fromClause;
134
+ if (!Array.isArray(from) || from.length !== 1)
135
+ return null;
136
+ const node = from[0];
137
+ if (node?.RangeVar)
138
+ return relOf(node.RangeVar);
139
+ return null;
140
+ }
141
+ function walkForceNullable(node, forceContext, out) {
142
+ if (node === null || node === undefined)
143
+ return;
144
+ if (Array.isArray(node)) {
145
+ for (const item of node)
146
+ walkForceNullable(item, forceContext, out);
147
+ return;
148
+ }
149
+ if (typeof node !== "object")
150
+ return;
151
+ if (node.ParamRef && typeof node.ParamRef.number === "number") {
152
+ if (forceContext)
153
+ out.add(node.ParamRef.number);
154
+ return;
155
+ }
156
+ if (node.TypeCast) {
157
+ walkForceNullable(node.TypeCast.arg, forceContext, out);
158
+ return;
159
+ }
160
+ if (node.CoalesceExpr) {
161
+ for (const a of node.CoalesceExpr.args ?? [])
162
+ walkForceNullable(a, true, out);
163
+ return;
164
+ }
165
+ if (node.NullTest) {
166
+ walkForceNullable(node.NullTest.arg, true, out);
167
+ return;
168
+ }
169
+ if (node.A_Expr) {
170
+ const kind = node.A_Expr.kind;
171
+ if (kind === "AEXPR_NULLIF" || kind === "AEXPR_DISTINCT" || kind === "AEXPR_NOT_DISTINCT") {
172
+ walkForceNullable(node.A_Expr.lexpr, true, out);
173
+ walkForceNullable(node.A_Expr.rexpr, true, out);
174
+ return;
175
+ }
176
+ }
177
+ for (const key of Object.keys(node)) {
178
+ walkForceNullable(node[key], forceContext, out);
179
+ }
180
+ }
@@ -0,0 +1,61 @@
1
+ import { PgClient } from "./wire.js";
2
+ export type ColumnInfo = {
3
+ attrelid: number;
4
+ attnum: number;
5
+ notNull: boolean;
6
+ name?: string;
7
+ };
8
+ export type EnumInfo = {
9
+ kind: "enum";
10
+ name: string;
11
+ values: string[];
12
+ };
13
+ export type EnumArrayInfo = {
14
+ kind: "enumArray";
15
+ element: EnumInfo;
16
+ };
17
+ export type ScalarInfo = {
18
+ kind: "scalar";
19
+ name: string;
20
+ tsType: string;
21
+ };
22
+ export type ScalarArrayInfo = {
23
+ kind: "scalarArray";
24
+ name: string;
25
+ element: ScalarInfo;
26
+ };
27
+ export type CustomTypeInfo = EnumInfo | EnumArrayInfo | ScalarInfo | ScalarArrayInfo;
28
+ export declare class SchemaCache {
29
+ private client;
30
+ private byOidNum;
31
+ private nameToOid;
32
+ private oidToName;
33
+ private columnsByOid;
34
+ private fullyLoaded;
35
+ private customTypes;
36
+ private typesProbed;
37
+ private typeRegistry;
38
+ constructor(client: PgClient);
39
+ setTypeRegistry(registry: Record<string, string>): void;
40
+ loadAttributes(refs: {
41
+ tableOid: number;
42
+ attno: number;
43
+ }[]): Promise<void>;
44
+ loadTableNames(names: {
45
+ schema?: string;
46
+ name: string;
47
+ }[]): Promise<void>;
48
+ isNotNull(tableOid: number, attno: number): boolean | undefined;
49
+ resolveTable(schema: string | undefined, name: string): number | undefined;
50
+ tableNameByOid(oid: number): {
51
+ schema: string;
52
+ name: string;
53
+ } | undefined;
54
+ loadTableNamesByOid(oids: number[]): Promise<void>;
55
+ columnNameByAttno(tableOid: number, attno: number): string | undefined;
56
+ loadColumnsForTables(tableOids: number[]): Promise<void>;
57
+ columnsOf(tableOid: number): Map<string, ColumnInfo> | undefined;
58
+ loadCustomTypes(typeOids: number[]): Promise<void>;
59
+ private resolveBaseTs;
60
+ customType(oid: number): CustomTypeInfo | undefined;
61
+ }
@@ -0,0 +1,225 @@
1
+ import { decodeText } from "./wire.js";
2
+ import { isBuiltinOid, oidToTs } from "./oids.js";
3
+ export class SchemaCache {
4
+ client;
5
+ byOidNum = new Map();
6
+ nameToOid = new Map();
7
+ oidToName = new Map();
8
+ columnsByOid = new Map();
9
+ fullyLoaded = new Set();
10
+ customTypes = new Map();
11
+ typesProbed = new Set();
12
+ typeRegistry = {};
13
+ constructor(client) {
14
+ this.client = client;
15
+ }
16
+ setTypeRegistry(registry) {
17
+ this.typeRegistry = registry;
18
+ }
19
+ async loadAttributes(refs) {
20
+ const need = refs.filter((r) => r.tableOid !== 0 && r.attno !== 0 && !this.byOidNum.has(key(r.tableOid, r.attno)));
21
+ if (need.length === 0)
22
+ return;
23
+ const seen = new Set();
24
+ const pairs = [];
25
+ for (const r of need) {
26
+ const k = key(r.tableOid, r.attno);
27
+ if (seen.has(k))
28
+ continue;
29
+ seen.add(k);
30
+ pairs.push(`(${r.tableOid},${r.attno})`);
31
+ }
32
+ const sql = `SELECT attrelid::int8, attnum::int4, attnotnull, attname FROM pg_attribute WHERE (attrelid, attnum) IN (${pairs.join(",")})`;
33
+ const r = await this.client.simpleQueryAll(sql);
34
+ for (const row of r.rows) {
35
+ const attrelid = Number(decodeText(row[0]));
36
+ const attnum = Number(decodeText(row[1]));
37
+ const notNull = decodeText(row[2]) === "t";
38
+ const name = decodeText(row[3]) ?? undefined;
39
+ this.byOidNum.set(key(attrelid, attnum), { attrelid, attnum, notNull, name });
40
+ }
41
+ }
42
+ async loadTableNames(names) {
43
+ const need = [];
44
+ for (const n of names) {
45
+ const schema = n.schema ?? "public";
46
+ const key = `${schema}.${n.name}`;
47
+ if (!this.nameToOid.has(key))
48
+ need.push({ schema, name: n.name });
49
+ }
50
+ if (need.length === 0)
51
+ return;
52
+ const where = need.map((n) => `(n.nspname = ${quote(n.schema)} AND c.relname = ${quote(n.name)})`).join(" OR ");
53
+ const sql = `SELECT c.oid::int8, n.nspname, c.relname FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE ${where}`;
54
+ const r = await this.client.simpleQueryAll(sql);
55
+ for (const row of r.rows) {
56
+ const oid = Number(decodeText(row[0]));
57
+ const schema = decodeText(row[1]);
58
+ const name = decodeText(row[2]);
59
+ const k = `${schema}.${name}`;
60
+ const arr = this.nameToOid.get(k) ?? [];
61
+ arr.push(oid);
62
+ this.nameToOid.set(k, arr);
63
+ this.oidToName.set(oid, { schema, name });
64
+ }
65
+ }
66
+ isNotNull(tableOid, attno) {
67
+ return this.byOidNum.get(key(tableOid, attno))?.notNull;
68
+ }
69
+ resolveTable(schema, name) {
70
+ const k = `${schema ?? "public"}.${name}`;
71
+ const arr = this.nameToOid.get(k);
72
+ return arr?.[0];
73
+ }
74
+ tableNameByOid(oid) {
75
+ return this.oidToName.get(oid);
76
+ }
77
+ async loadTableNamesByOid(oids) {
78
+ const need = [...new Set(oids.filter((o) => o > 0 && !this.oidToName.has(o)))];
79
+ if (need.length === 0)
80
+ return;
81
+ const sql = `SELECT c.oid::int8, n.nspname, c.relname FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.oid IN (${need.join(",")})`;
82
+ const r = await this.client.simpleQueryAll(sql);
83
+ for (const row of r.rows) {
84
+ const oid = Number(decodeText(row[0]));
85
+ const schema = decodeText(row[1]);
86
+ const name = decodeText(row[2]);
87
+ const k = `${schema}.${name}`;
88
+ const arr = this.nameToOid.get(k) ?? [];
89
+ if (!arr.includes(oid))
90
+ arr.push(oid);
91
+ this.nameToOid.set(k, arr);
92
+ this.oidToName.set(oid, { schema, name });
93
+ }
94
+ }
95
+ columnNameByAttno(tableOid, attno) {
96
+ return this.byOidNum.get(key(tableOid, attno))?.name;
97
+ }
98
+ async loadColumnsForTables(tableOids) {
99
+ const need = tableOids.filter((oid) => !this.fullyLoaded.has(oid));
100
+ if (need.length === 0)
101
+ return;
102
+ const list = [...new Set(need)].join(",");
103
+ const sql = `SELECT attrelid::int8, attnum::int4, attname, attnotnull FROM pg_attribute WHERE attrelid IN (${list}) AND attnum > 0 AND NOT attisdropped`;
104
+ const r = await this.client.simpleQueryAll(sql);
105
+ const grouped = new Map();
106
+ for (const row of r.rows) {
107
+ const attrelid = Number(decodeText(row[0]));
108
+ const attnum = Number(decodeText(row[1]));
109
+ const attname = decodeText(row[2]);
110
+ const notNull = decodeText(row[3]) === "t";
111
+ const info = { attrelid, attnum, notNull, name: attname };
112
+ this.byOidNum.set(key(attrelid, attnum), info);
113
+ const m = grouped.get(attrelid) ?? new Map();
114
+ m.set(attname, info);
115
+ grouped.set(attrelid, m);
116
+ }
117
+ for (const oid of need) {
118
+ const m = grouped.get(oid) ?? new Map();
119
+ this.columnsByOid.set(oid, m);
120
+ this.fullyLoaded.add(oid);
121
+ }
122
+ }
123
+ columnsOf(tableOid) {
124
+ return this.columnsByOid.get(tableOid);
125
+ }
126
+ async loadCustomTypes(typeOids) {
127
+ const need = typeOids.filter((oid) => oid > 0 && !this.typesProbed.has(oid));
128
+ if (need.length === 0)
129
+ return;
130
+ for (const oid of need)
131
+ this.typesProbed.add(oid);
132
+ const list1 = [...new Set(need)].join(",");
133
+ const sql1 = `SELECT oid::int8, typname, typtype, typcategory, typelem::int8, typbasetype::int8 FROM pg_type WHERE oid IN (${list1})`;
134
+ const r1 = await this.client.simpleQueryAll(sql1);
135
+ const enumOids = [];
136
+ const arrayInfos = [];
137
+ const domainInfos = [];
138
+ for (const row of r1.rows) {
139
+ const oid = Number(decodeText(row[0]));
140
+ const name = decodeText(row[1]);
141
+ const typtype = decodeText(row[2]);
142
+ const typcategory = decodeText(row[3]);
143
+ const typelem = Number(decodeText(row[4]));
144
+ const typbasetype = Number(decodeText(row[5]));
145
+ if (typtype === "e") {
146
+ enumOids.push(oid);
147
+ this.customTypes.set(oid, { kind: "enum", name, values: [] });
148
+ }
149
+ else if (typcategory === "A" && typelem > 0) {
150
+ arrayInfos.push({ arrayOid: oid, arrayName: name, elemOid: typelem });
151
+ }
152
+ else if (typtype === "b" && this.typeRegistry[name]) {
153
+ this.customTypes.set(oid, { kind: "scalar", name, tsType: this.typeRegistry[name] });
154
+ }
155
+ else if (typtype === "d" && typbasetype > 0) {
156
+ domainInfos.push({ oid, name, baseOid: typbasetype });
157
+ }
158
+ }
159
+ const elemsToProbe = arrayInfos.map((a) => a.elemOid).filter((o) => !this.typesProbed.has(o));
160
+ const basesToProbe = domainInfos.map((d) => d.baseOid).filter((o) => !this.typesProbed.has(o) && !isBuiltinOid(o));
161
+ const recurse = [...new Set([...elemsToProbe, ...basesToProbe])];
162
+ if (recurse.length > 0)
163
+ await this.loadCustomTypes(recurse);
164
+ for (const { oid, name, baseOid } of domainInfos) {
165
+ const resolved = this.resolveBaseTs(baseOid);
166
+ if (resolved) {
167
+ this.customTypes.set(oid, { kind: "scalar", name, tsType: resolved });
168
+ }
169
+ }
170
+ for (const { arrayOid, arrayName, elemOid } of arrayInfos) {
171
+ const elem = this.customTypes.get(elemOid);
172
+ if (elem && elem.kind === "enum") {
173
+ this.customTypes.set(arrayOid, { kind: "enumArray", element: elem });
174
+ }
175
+ else if (elem && elem.kind === "scalar") {
176
+ this.customTypes.set(arrayOid, { kind: "scalarArray", name: arrayName, element: elem });
177
+ }
178
+ }
179
+ if (enumOids.length > 0) {
180
+ const list2 = enumOids.join(",");
181
+ const sql2 = `SELECT enumtypid::int8, enumlabel FROM pg_enum WHERE enumtypid IN (${list2}) ORDER BY enumtypid, enumsortorder`;
182
+ const r2 = await this.client.simpleQueryAll(sql2);
183
+ for (const row of r2.rows) {
184
+ const oid = Number(decodeText(row[0]));
185
+ const label = decodeText(row[1]);
186
+ const t = this.customTypes.get(oid);
187
+ if (t && t.kind === "enum")
188
+ t.values.push(label);
189
+ }
190
+ }
191
+ }
192
+ resolveBaseTs(baseOid) {
193
+ if (baseOid === 0)
194
+ return undefined;
195
+ if (isBuiltinOid(baseOid))
196
+ return oidToTs(baseOid).ts;
197
+ const info = this.customTypes.get(baseOid);
198
+ if (!info)
199
+ return undefined;
200
+ if (info.kind === "scalar")
201
+ return info.tsType;
202
+ if (info.kind === "scalarArray")
203
+ return `(${info.element.tsType})[]`;
204
+ if (info.kind === "enum") {
205
+ if (info.values.length === 0)
206
+ return "string";
207
+ return info.values.map((v) => JSON.stringify(v)).join(" | ");
208
+ }
209
+ if (info.kind === "enumArray") {
210
+ if (info.element.values.length === 0)
211
+ return "string[]";
212
+ return `(${info.element.values.map((v) => JSON.stringify(v)).join(" | ")})[]`;
213
+ }
214
+ return undefined;
215
+ }
216
+ customType(oid) {
217
+ return this.customTypes.get(oid);
218
+ }
219
+ }
220
+ function key(oid, attno) {
221
+ return `${oid}/${attno}`;
222
+ }
223
+ function quote(s) {
224
+ return `'${s.replace(/'/g, "''")}'`;
225
+ }