@typesql/pg 0.0.2 → 0.0.4

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 (46) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +23 -2
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +5 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/client.d.ts +5 -2
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +10 -3
  10. package/dist/client.js.map +1 -1
  11. package/dist/index.d.ts +8 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -6
  14. package/dist/index.js.map +1 -1
  15. package/dist/introspect/cli.d.ts +24 -0
  16. package/dist/introspect/cli.d.ts.map +1 -0
  17. package/dist/introspect/cli.js +121 -0
  18. package/dist/introspect/cli.js.map +1 -0
  19. package/dist/introspect/emit.d.ts +30 -0
  20. package/dist/introspect/emit.d.ts.map +1 -0
  21. package/dist/introspect/emit.js +144 -0
  22. package/dist/introspect/emit.js.map +1 -0
  23. package/dist/introspect/index.d.ts +5 -0
  24. package/dist/introspect/index.d.ts.map +1 -0
  25. package/dist/introspect/index.js +5 -0
  26. package/dist/introspect/index.js.map +1 -0
  27. package/dist/introspect/introspect.d.ts +67 -0
  28. package/dist/introspect/introspect.d.ts.map +1 -0
  29. package/dist/introspect/introspect.js +109 -0
  30. package/dist/introspect/introspect.js.map +1 -0
  31. package/dist/introspect/nullability.d.ts +60 -0
  32. package/dist/introspect/nullability.d.ts.map +1 -0
  33. package/dist/introspect/nullability.js +354 -0
  34. package/dist/introspect/nullability.js.map +1 -0
  35. package/dist/type-map.d.ts +42 -14
  36. package/dist/type-map.d.ts.map +1 -1
  37. package/package.json +10 -3
  38. package/src/bin.ts +5 -0
  39. package/src/client.ts +10 -4
  40. package/src/index.ts +7 -4
  41. package/src/introspect/cli.ts +138 -0
  42. package/src/introspect/emit.ts +168 -0
  43. package/src/introspect/index.ts +12 -0
  44. package/src/introspect/introspect.ts +221 -0
  45. package/src/introspect/nullability.ts +356 -0
  46. package/src/type-map.ts +42 -14
@@ -0,0 +1,67 @@
1
+ import type { PgQueryable } from "../client.js";
2
+ import { type NullabilityOptions } from "./nullability.js";
3
+ export type RelationKind = "table" | "partitioned table" | "view" | "materialized view" | "foreign table";
4
+ export interface IntrospectedColumn {
5
+ readonly name: string;
6
+ /**
7
+ * Canonical Postgres type name as typesql spells it: `int4`, `timestamptz`, `varchar`, an enum
8
+ * name, `${T}[]` for arrays. Domains are replaced by their base type; `citext` is `text`.
9
+ */
10
+ readonly type: string;
11
+ /** The column's type as Postgres prints it (`character varying(40)`, a domain name, ...). */
12
+ readonly declaredType: string;
13
+ /** The domain the column is declared with, if any (`public.positive`). */
14
+ readonly domain: string | null;
15
+ readonly nullable: boolean;
16
+ /** Optional on INSERT: a DEFAULT, serial, identity or generated column. Always false for views. */
17
+ readonly hasDefault: boolean;
18
+ /** `GENERATED ALWAYS AS IDENTITY` / `GENERATED BY DEFAULT AS IDENTITY`. */
19
+ readonly identity: "always" | "by default" | null;
20
+ /** The expression of a `GENERATED ALWAYS AS (…) STORED` column. */
21
+ readonly generated: string | null;
22
+ /** The DEFAULT expression. */
23
+ readonly default: string | null;
24
+ readonly comment: string | null;
25
+ }
26
+ export interface IntrospectedRelation {
27
+ readonly schema: string;
28
+ readonly name: string;
29
+ readonly kind: RelationKind;
30
+ readonly comment: string | null;
31
+ readonly columns: readonly IntrospectedColumn[];
32
+ }
33
+ export interface IntrospectedEnum {
34
+ readonly schema: string;
35
+ readonly name: string;
36
+ /** Labels in sort order. */
37
+ readonly values: readonly string[];
38
+ }
39
+ export interface IntrospectedDatabase {
40
+ /** `server_version`, e.g. `17.2`. */
41
+ readonly version: string;
42
+ /** Schemas that were read, in order. */
43
+ readonly schemas: readonly string[];
44
+ readonly relations: readonly IntrospectedRelation[];
45
+ /** Enums of the read schemas and enums their columns use. */
46
+ readonly enums: readonly IntrospectedEnum[];
47
+ }
48
+ export interface IntrospectOptions {
49
+ /** Schemas to read. Default: every schema except `pg_catalog`, `information_schema` and `pg_*`. */
50
+ readonly schemas?: readonly string[];
51
+ /**
52
+ * Relations to leave out: names (`kysely_migration`) or `schema.name`, with `*` matching any
53
+ * run of characters (`kysely_migration*`, `audit.*`).
54
+ */
55
+ readonly exclude?: readonly string[];
56
+ /**
57
+ * View columns to treat as NOT NULL when the analysis cannot prove it, called with the view's
58
+ * name and the column's name.
59
+ */
60
+ readonly viewNotNull?: NullabilityOptions["notNull"];
61
+ }
62
+ /**
63
+ * Read tables, views, materialized views, foreign tables and enums of a live database through
64
+ * any node-postgres-style client (`Client`, `Pool`, `PoolClient`).
65
+ */
66
+ export declare function introspect(client: PgQueryable, options?: IntrospectOptions): Promise<IntrospectedDatabase>;
67
+ //# sourceMappingURL=introspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/introspect/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,mBAAmB,GAAG,MAAM,GAAG,mBAAmB,GAAG,eAAe,CAAC;AAE1G,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6FAA6F;IAC7F,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,mGAAmG;IACnG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC;IAClD,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACpD,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,iBAAiB;IAChC,mGAAmG;IACnG,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;CACtD;AAuDD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+FpH"}
@@ -0,0 +1,109 @@
1
+ import { ViewNullability } from "./nullability.js";
2
+ const globToRegExp = (glob) => new RegExp(`^${glob.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`);
3
+ const KINDS = {
4
+ r: "table",
5
+ p: "partitioned table",
6
+ v: "view",
7
+ m: "materialized view",
8
+ f: "foreign table",
9
+ };
10
+ /** Postgres type names typesql spells differently. */
11
+ const TYPE_ALIASES = { citext: "text" };
12
+ function resolver(types) {
13
+ const resolve = (oid) => {
14
+ const t = types.get(oid);
15
+ if (!t)
16
+ return { type: "unknown", notnull: false, enumOid: null, domain: null };
17
+ if (t.typtype === "d") {
18
+ const base = resolve(t.basetype);
19
+ return { ...base, notnull: base.notnull || t.notnull, domain: `${t.schema}.${t.name}` };
20
+ }
21
+ const elem = t.elem !== "0" ? types.get(t.elem) : undefined;
22
+ if (elem && elem.array === t.oid) {
23
+ const inner = resolve(elem.oid);
24
+ return { type: inner.type.endsWith("[]") ? inner.type : `${inner.type}[]`, notnull: false, enumOid: inner.enumOid, domain: null };
25
+ }
26
+ return { type: TYPE_ALIASES[t.name] ?? t.name, notnull: false, enumOid: t.typtype === "e" ? t.oid : null, domain: null };
27
+ };
28
+ return resolve;
29
+ }
30
+ /** Default schema filter: everything but the system schemas. */
31
+ const USER_SCHEMAS = `n.nspname NOT IN ('pg_catalog', 'information_schema') AND n.nspname NOT LIKE 'pg\\_%'`;
32
+ /**
33
+ * Read tables, views, materialized views, foreign tables and enums of a live database through
34
+ * any node-postgres-style client (`Client`, `Pool`, `PoolClient`).
35
+ */
36
+ export async function introspect(client, options = {}) {
37
+ const q = async (text, values) => (await client.query(text, values)).rows;
38
+ const [{ version }] = (await q(`SELECT current_setting('server_version') AS version`));
39
+ const schemaRows = options.schemas
40
+ ? await q(`SELECT n.nspname AS name FROM unnest($1::text[]) WITH ORDINALITY AS s(name, i)
41
+ JOIN pg_namespace n ON n.nspname = s.name ORDER BY s.i`, [[...options.schemas]])
42
+ : await q(`SELECT n.nspname AS name FROM pg_namespace n WHERE ${USER_SCHEMAS}
43
+ ORDER BY n.nspname <> 'public', n.nspname`);
44
+ const schemas = schemaRows.map((r) => r.name);
45
+ const missing = (options.schemas ?? []).filter((s) => !schemas.includes(s));
46
+ if (missing.length > 0)
47
+ throw new Error(`schema ${missing.map((s) => JSON.stringify(s)).join(", ")} does not exist`);
48
+ const types = new Map((await q(`SELECT t.oid::int8::text AS oid, t.typname AS name, n.nspname AS schema, t.typtype,
49
+ t.typbasetype::int8::text AS basetype, t.typelem::int8::text AS elem,
50
+ t.typarray::int8::text AS array, t.typnotnull AS notnull
51
+ FROM pg_type t JOIN pg_namespace n ON n.oid = t.typnamespace`)).map((t) => [t.oid, t]));
52
+ const resolve = resolver(types);
53
+ const excluded = (options.exclude ?? []).map(globToRegExp);
54
+ const relRows = (await q(`SELECT c.oid::int8::text AS oid, n.nspname AS schema, c.relname AS name, c.relkind,
55
+ obj_description(c.oid, 'pg_class') AS comment
56
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
57
+ WHERE c.relkind IN ('r', 'p', 'v', 'm', 'f') AND n.nspname = ANY($1::text[])
58
+ ORDER BY array_position($1::text[], n.nspname::text), c.relname`, [schemas])).filter((r) => !excluded.some((re) => re.test(r.name) || re.test(`${r.schema}.${r.name}`)));
59
+ const colRows = await q(`SELECT a.attrelid::int8::text AS relid, a.attname AS name, a.atttypid::int8::text AS typid,
60
+ format_type(a.atttypid, a.atttypmod) AS declared, a.attnotnull AS notnull,
61
+ a.attidentity AS identity, a.attgenerated AS generated,
62
+ pg_get_expr(d.adbin, d.adrelid) AS default, col_description(a.attrelid, a.attnum) AS comment
63
+ FROM pg_attribute a
64
+ LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
65
+ WHERE a.attrelid = ANY($1::oid[]) AND a.attnum > 0 AND NOT a.attisdropped
66
+ ORDER BY a.attrelid, a.attnum`, [relRows.map((r) => r.oid)]);
67
+ const colsByRel = new Map();
68
+ for (const c of colRows)
69
+ colsByRel.set(c.relid, [...(colsByRel.get(c.relid) ?? []), c]);
70
+ const views = new ViewNullability((text, values) => client.query(text, values), {
71
+ ...(options.viewNotNull && { notNull: options.viewNotNull }),
72
+ });
73
+ const usedEnums = new Set();
74
+ const relations = [];
75
+ for (const rel of relRows) {
76
+ const kind = KINDS[rel.relkind];
77
+ const isView = kind === "view" || kind === "materialized view";
78
+ const viewNotNull = isView ? await views.notNull(rel.oid) : [];
79
+ const columns = (colsByRel.get(rel.oid) ?? []).map((c, i) => {
80
+ const t = resolve(c.typid);
81
+ if (t.enumOid)
82
+ usedEnums.add(t.enumOid);
83
+ const generated = c.generated !== "" ? c.default : null;
84
+ const identity = c.identity === "a" ? "always" : c.identity === "d" ? "by default" : null;
85
+ return {
86
+ name: c.name,
87
+ type: t.type,
88
+ declaredType: c.declared,
89
+ domain: t.domain,
90
+ nullable: isView ? !viewNotNull[i] : !(c.notnull || t.notnull),
91
+ hasDefault: !isView && (c.default !== null || identity !== null || generated !== null),
92
+ identity,
93
+ generated,
94
+ default: generated === null ? c.default : null,
95
+ comment: c.comment,
96
+ };
97
+ });
98
+ relations.push({ schema: rel.schema, name: rel.name, kind, comment: rel.comment, columns });
99
+ }
100
+ const enumRows = await q(`SELECT t.oid::int8::text AS oid, n.nspname AS schema, t.typname AS name,
101
+ array_agg(e.enumlabel::text ORDER BY e.enumsortorder) AS values
102
+ FROM pg_type t JOIN pg_namespace n ON n.oid = t.typnamespace JOIN pg_enum e ON e.enumtypid = t.oid
103
+ WHERE n.nspname = ANY($1::text[]) OR t.oid = ANY($2::oid[])
104
+ GROUP BY t.oid, n.nspname, t.typname
105
+ ORDER BY t.typname, n.nspname`, [schemas, [...usedEnums]]);
106
+ const enums = enumRows.map(({ schema, name, values }) => ({ schema, name, values }));
107
+ return { version, schemas, relations, enums };
108
+ }
109
+ //# sourceMappingURL=introspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/introspect/introspect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAA2B,MAAM,kBAAkB,CAAC;AAmE5E,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE,CAC5C,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE1G,MAAM,KAAK,GAA2C;IACpD,CAAC,EAAE,OAAO;IACV,CAAC,EAAE,mBAAmB;IACtB,CAAC,EAAE,MAAM;IACT,CAAC,EAAE,mBAAmB;IACtB,CAAC,EAAE,eAAe;CACnB,CAAC;AAEF,sDAAsD;AACtD,MAAM,YAAY,GAAqC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAoB1E,SAAS,QAAQ,CAAC,KAAmC;IACnD,MAAM,OAAO,GAAG,CAAC,GAAW,EAAgB,EAAE;QAC5C,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAChF,IAAI,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACjC,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1F,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5D,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACpI,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3H,CAAC,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gEAAgE;AAChE,MAAM,YAAY,GAAG,uFAAuF,CAAC;AAE7G;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAmB,EAAE,OAAO,GAAsB,EAAE;IACnF,MAAM,CAAC,GAAG,KAAK,EAAK,IAAY,EAAE,MAAkB,EAAgB,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAW,CAAC;IAEtH,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAsB,qDAAqD,CAAC,CAA0B,CAAC;IACrI,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO;QAChC,CAAC,CAAC,MAAM,CAAC,CACL;kEAC0D,EAC1D,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CACvB;QACH,CAAC,CAAC,MAAM,CAAC,CACL,sDAAsD,YAAY;oDACtB,CAC7C,CAAC;IACN,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAErH,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,CAAC,MAAM,CAAC,CACN;;;sEAGgE,CACjE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAC1B,CAAC;IACF,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEhC,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,CACtB;;;;sEAIkE,EAClE,CAAC,OAAO,CAAC,CACV,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,MAAM,CAAC,CAIrB;;;;;;;oCAOgC,EAChC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAC5B,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0B,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExF,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;QAC9E,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;KAC7D,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,mBAAmB,CAAC;QAC/D,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAsB,EAAE;YAC9E,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,CAAC,OAAO;gBAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;YACxD,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1F,OAAO;gBACL,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,YAAY,EAAE,CAAC,CAAC,QAAQ;gBACxB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC;gBAC9D,UAAU,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC;gBACtF,QAAQ;gBACR,SAAS;gBACT,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;gBAC9C,OAAO,EAAE,CAAC,CAAC,OAAO;aACnB,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,CACtB;;;;;oCAKgC,EAChC,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAC1B,CAAC;IACF,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACrF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAChD,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Nullability of view columns, derived from the view's query tree.
3
+ *
4
+ * Postgres records no NOT NULL information for view (or materialized view) columns. Its rewrite
5
+ * rule (`pg_rewrite.ev_action`, the `_RETURN` rule) holds the parsed query, though, and from
6
+ * PostgreSQL 16 every column reference in it carries `varnullingrels`, the outer joins that can
7
+ * null it. A view column is NOT NULL here only when its expression provably cannot be NULL: a
8
+ * NOT NULL table column that no outer join nulls, a non-NULL constant, a cast or a strict
9
+ * operator over such values, a CASE whose every branch is NOT NULL, `count(*)`, ... Anything
10
+ * else (function calls outside a short list, scalar subqueries, set-returning function columns)
11
+ * is nullable. On PostgreSQL 15 and older every column reference counts as nullable.
12
+ *
13
+ * This module has no imports so that scripts/pg-catalog-from-pg.mjs can load it with Node's
14
+ * type stripping.
15
+ */
16
+ /** Runs a query: node-postgres' `client.query(text, values)` fits. */
17
+ export type QueryFn = (text: string, values?: unknown[]) => Promise<{
18
+ readonly rows: readonly any[];
19
+ }>;
20
+ export interface NullabilityOptions {
21
+ /**
22
+ * Columns known never to be NULL that the analysis cannot prove (typically columns of a
23
+ * set-returning function). Called with the view's name and the column's name.
24
+ */
25
+ readonly notNull?: (view: string, column: string) => boolean;
26
+ }
27
+ /** A node of a parsed `pg_node_tree`: `{ _: "VAR", varno: "1", … }`. */
28
+ export interface Node {
29
+ readonly _: string;
30
+ readonly [field: string]: NodeValue;
31
+ }
32
+ export type NodeValue = Node | readonly NodeValue[] | string | null;
33
+ /** Parse a node tree into plain values: nodes as objects, lists as arrays, `<>` as null. */
34
+ export declare function parseNodeTree(text: string): NodeValue;
35
+ /** Per-column NOT NULL of views and materialized views; caches what it reads. */
36
+ export declare class ViewNullability {
37
+ private readonly query;
38
+ private readonly options;
39
+ private readonly views;
40
+ private readonly atts;
41
+ private procs;
42
+ private operators;
43
+ constructor(query: QueryFn, options?: NullabilityOptions);
44
+ /** NOT NULL flags of the view's columns, in column order. `relid` is the view's `pg_class.oid`. */
45
+ notNull(relid: string | number): Promise<boolean[]>;
46
+ private analyze;
47
+ private loadProcs;
48
+ private loadOperators;
49
+ /** A built-in operator that returns a value for non-NULL operands. */
50
+ private strictOperator;
51
+ private columns;
52
+ /** Is output column `attno` (1-based) of a (sub)query NOT NULL? */
53
+ private queryColumn;
54
+ private variable;
55
+ /** Column `attno` of a single set-returning function in FROM (`WITH ORDINALITY` adds a NOT NULL counter). */
56
+ private functionColumn;
57
+ private all;
58
+ private expr;
59
+ }
60
+ //# sourceMappingURL=nullability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nullability.d.ts","sourceRoot":"","sources":["../../src/introspect/nullability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,sEAAsE;AACtE,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,CAAA;CAAE,CAAC,CAAC;AAEvG,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9D;AAED,wEAAwE;AACxE,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AACD,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,SAAS,SAAS,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC;AA8BpE,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CA2BrD;AAwDD,iFAAiF;AACjF,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyC;IAC/D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqC;IAC1D,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,SAAS,CAA2C;IAE5D,YAAY,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,kBAAuB,EAG3D;IAED,mGAAmG;IACnG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAQlD;YAEa,OAAO;IAoBrB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,aAAa;IAQrB,sEAAsE;YACxD,cAAc;IAK5B,OAAO,CAAC,OAAO;IAsBf,mEAAmE;YACrD,WAAW;YAeX,QAAQ;IAgCtB,6GAA6G;YAC/F,cAAc;YAYd,GAAG;YAKH,IAAI;CAsDnB"}
@@ -0,0 +1,354 @@
1
+ /**
2
+ * Nullability of view columns, derived from the view's query tree.
3
+ *
4
+ * Postgres records no NOT NULL information for view (or materialized view) columns. Its rewrite
5
+ * rule (`pg_rewrite.ev_action`, the `_RETURN` rule) holds the parsed query, though, and from
6
+ * PostgreSQL 16 every column reference in it carries `varnullingrels`, the outer joins that can
7
+ * null it. A view column is NOT NULL here only when its expression provably cannot be NULL: a
8
+ * NOT NULL table column that no outer join nulls, a non-NULL constant, a cast or a strict
9
+ * operator over such values, a CASE whose every branch is NOT NULL, `count(*)`, ... Anything
10
+ * else (function calls outside a short list, scalar subqueries, set-returning function columns)
11
+ * is nullable. On PostgreSQL 15 and older every column reference counts as nullable.
12
+ *
13
+ * This module has no imports so that scripts/pg-catalog-from-pg.mjs can load it with Node's
14
+ * type stripping.
15
+ */
16
+ /** Tokens of the text form of a node tree (`outfuncs.c`). `[ … ]` datum bytes are skipped. */
17
+ function tokenize(s) {
18
+ const out = [];
19
+ let i = 0;
20
+ while (i < s.length) {
21
+ const c = s[i];
22
+ if (c === " " || c === "\n" || c === "\t") {
23
+ i++;
24
+ continue;
25
+ }
26
+ if (c === "(" || c === ")" || c === "{" || c === "}") {
27
+ out.push(c);
28
+ i++;
29
+ continue;
30
+ }
31
+ if (c === "[") {
32
+ i = s.indexOf("]", i) + 1;
33
+ continue;
34
+ }
35
+ if (c === '"') {
36
+ let v = "";
37
+ i++;
38
+ while (i < s.length && s[i] !== '"') {
39
+ if (s[i] === "\\")
40
+ i++;
41
+ v += s[i++];
42
+ }
43
+ i++;
44
+ out.push({ str: v });
45
+ continue;
46
+ }
47
+ let v = "";
48
+ while (i < s.length && !" \n\t(){}".includes(s[i])) {
49
+ if (s[i] === "\\")
50
+ i++;
51
+ v += s[i++];
52
+ }
53
+ out.push(v);
54
+ }
55
+ return out;
56
+ }
57
+ /** Parse a node tree into plain values: nodes as objects, lists as arrays, `<>` as null. */
58
+ export function parseNodeTree(text) {
59
+ const toks = tokenize(text);
60
+ let p = 0;
61
+ const isLabel = (t) => typeof t === "string" && t.startsWith(":");
62
+ const value = () => {
63
+ const t = toks[p++];
64
+ if (t === "{") {
65
+ const node = { _: toks[p++] };
66
+ while (p < toks.length && toks[p] !== "}") {
67
+ const label = toks[p++];
68
+ if (!isLabel(label))
69
+ continue; // a datum's length before its skipped bytes
70
+ if (toks[p] === "}" || isLabel(toks[p])) {
71
+ node[label.slice(1)] = null;
72
+ continue;
73
+ }
74
+ node[label.slice(1)] = value();
75
+ }
76
+ p++;
77
+ return node;
78
+ }
79
+ if (t === "(") {
80
+ const list = [];
81
+ while (p < toks.length && toks[p] !== ")")
82
+ list.push(value());
83
+ p++;
84
+ return list;
85
+ }
86
+ if (t === undefined || t === "<>")
87
+ return null;
88
+ return typeof t === "object" ? t.str : t;
89
+ };
90
+ return value();
91
+ }
92
+ const list = (x) => (Array.isArray(x) ? x : []);
93
+ const node = (x) => (x !== null && typeof x === "object" && !Array.isArray(x) ? x : null);
94
+ const str = (x) => (typeof x === "string" ? x : null);
95
+ // ───────────────────────────── function knowledge ─────────────────────────────
96
+ /** `pg_catalog` functions that return a non-NULL value for non-NULL arguments. */
97
+ const NON_NULL_FUNCTIONS = new Set([
98
+ "current_database", "current_user", "session_user", "current_schema", "pg_get_userbyid", "pg_my_temp_schema",
99
+ "nameconcatoid", "pg_has_role", "has_table_privilege", "has_column_privilege", "has_any_column_privilege",
100
+ "has_function_privilege", "has_schema_privilege", "has_sequence_privilege", "has_type_privilege",
101
+ "pg_relation_is_updatable", "pg_column_is_updatable", "pg_is_other_temp_schema",
102
+ "now", "statement_timestamp", "transaction_timestamp", "clock_timestamp",
103
+ "lower", "upper", "length", "char_length", "octet_length", "concat", "concat_ws", "md5", "btrim", "ltrim", "rtrim",
104
+ "abs", "round", "trunc", "floor", "ceil", "ceiling", "date_trunc", "age",
105
+ ]);
106
+ /** `pg_stat_get_*` accessors returning a number report 0 when no statistics exist, except these. */
107
+ const NULLABLE_STAT_FUNCTIONS = new Set([
108
+ "pg_stat_get_db_checksum_failures", "pg_stat_get_backend_pid", "pg_stat_get_backend_dbid", "pg_stat_get_backend_userid",
109
+ ]);
110
+ const isNonNullStatFunction = (name, ret) => name.startsWith("pg_stat_get_") && (ret === "int8" || ret === "int4" || ret === "float8") && !NULLABLE_STAT_FUNCTIONS.has(name);
111
+ /** Aggregates that never return NULL. */
112
+ const NON_NULL_AGGREGATES = new Set(["count"]);
113
+ /** Window functions that never return NULL. */
114
+ const NON_NULL_WINDOW_FUNCTIONS = new Set(["count", "row_number", "rank", "dense_rank", "percent_rank", "cume_dist"]);
115
+ /**
116
+ * Set-returning functions in FROM and their output columns (1-based) that are never NULL. A
117
+ * strict set-returning function returns no rows for NULL arguments, so the arguments do not
118
+ * matter. `jsonb_each` values are `jsonb` (a JSON null is `'null'::jsonb`, not SQL NULL);
119
+ * the `_text` variants turn a JSON null into SQL NULL.
120
+ */
121
+ const NON_NULL_SRF_COLUMNS = {
122
+ generate_series: [1], generate_subscripts: [1],
123
+ jsonb_each: [1, 2], json_each: [1, 2], jsonb_each_text: [1], json_each_text: [1],
124
+ jsonb_object_keys: [1], json_object_keys: [1], jsonb_array_elements: [1], json_array_elements: [1],
125
+ regexp_matches: [1], regexp_split_to_table: [1],
126
+ };
127
+ /**
128
+ * `pg_catalog` operators that can return NULL for non-NULL operands: JSON field and path access
129
+ * (a missing key) and jsonpath matches (an unknown result). Other built-in operators are strict
130
+ * and return a value for non-NULL operands; operators outside `pg_catalog` count as nullable.
131
+ */
132
+ const NULLABLE_OPERATORS = new Set(["->", "->>", "#>", "#>>", "@@", "@?"]);
133
+ // ───────────────────────────── analysis ─────────────────────────────
134
+ /** Per-column NOT NULL of views and materialized views; caches what it reads. */
135
+ export class ViewNullability {
136
+ query;
137
+ options;
138
+ views = new Map();
139
+ atts = new Map();
140
+ procs = null;
141
+ operators = null;
142
+ constructor(query, options = {}) {
143
+ this.query = query;
144
+ this.options = options;
145
+ }
146
+ /** NOT NULL flags of the view's columns, in column order. `relid` is the view's `pg_class.oid`. */
147
+ notNull(relid) {
148
+ const key = String(relid);
149
+ let cached = this.views.get(key);
150
+ if (!cached) {
151
+ cached = this.analyze(key);
152
+ this.views.set(key, cached);
153
+ }
154
+ return cached;
155
+ }
156
+ async analyze(relid) {
157
+ const { rows } = await this.query(`SELECT r.ev_action, c.relname FROM pg_rewrite r JOIN pg_class c ON c.oid = r.ev_class
158
+ WHERE r.ev_class = $1 AND r.rulename = '_RETURN'`, [relid]);
159
+ const row = rows[0];
160
+ if (!row)
161
+ return [];
162
+ const query = node(list(parseNodeTree(row.ev_action))[0]);
163
+ if (!query)
164
+ return [];
165
+ const out = [];
166
+ for (const te of list(query["targetList"])) {
167
+ const entry = node(te);
168
+ if (!entry || entry["resjunk"] === "true")
169
+ continue;
170
+ const name = str(entry["resname"]) ?? "";
171
+ out.push((await this.expr(entry["expr"], query)) || (this.options.notNull?.(row.relname, name) ?? false));
172
+ }
173
+ return out;
174
+ }
175
+ loadProcs() {
176
+ this.procs ??= this.query(`SELECT p.oid::int8::text AS oid, p.proname AS name, t.typname AS ret, p.pronamespace = 'pg_catalog'::regnamespace AS system
177
+ FROM pg_proc p JOIN pg_type t ON t.oid = p.prorettype`).then(({ rows }) => new Map(rows.map((r) => [r.oid, r])));
178
+ return this.procs;
179
+ }
180
+ loadOperators() {
181
+ this.operators ??= this.query(`SELECT o.oid::int8::text AS oid, o.oprname AS name, '' AS ret, o.oprnamespace = 'pg_catalog'::regnamespace AS system
182
+ FROM pg_operator o`).then(({ rows }) => new Map(rows.map((r) => [r.oid, r])));
183
+ return this.operators;
184
+ }
185
+ /** A built-in operator that returns a value for non-NULL operands. */
186
+ async strictOperator(e) {
187
+ const op = (await this.loadOperators()).get(str(e["opno"]) ?? "");
188
+ return op?.system === true && !NULLABLE_OPERATORS.has(op.name);
189
+ }
190
+ columns(relid) {
191
+ let cached = this.atts.get(relid);
192
+ if (!cached) {
193
+ cached = this.query(
194
+ // NOT NULL: the column's constraint, or a NOT NULL domain anywhere in its domain chain.
195
+ `SELECT a.attnum, c.relkind,
196
+ a.attnotnull OR coalesce((
197
+ WITH RECURSIVE chain(oid, nn) AS (
198
+ SELECT t.oid, t.typnotnull FROM pg_type t WHERE t.oid = a.atttypid AND t.typtype = 'd'
199
+ UNION ALL
200
+ SELECT b.oid, b.typnotnull FROM chain JOIN pg_type d ON d.oid = chain.oid
201
+ JOIN pg_type b ON b.oid = d.typbasetype AND b.typtype = 'd')
202
+ SELECT bool_or(nn) FROM chain), false) AS notnull
203
+ FROM pg_attribute a JOIN pg_class c ON c.oid = a.attrelid
204
+ WHERE a.attrelid = $1 AND a.attnum > 0 AND NOT a.attisdropped`, [relid]).then(({ rows }) => rows);
205
+ this.atts.set(relid, cached);
206
+ }
207
+ return cached;
208
+ }
209
+ /** Is output column `attno` (1-based) of a (sub)query NOT NULL? */
210
+ async queryColumn(query, attno) {
211
+ if (query["setOperations"]) {
212
+ // UNION / INTERSECT / EXCEPT: every arm (a subquery in the range table) must be NOT NULL.
213
+ for (const r of list(query["rtable"])) {
214
+ const rte = node(r);
215
+ const sub = node(rte?.["subquery"]);
216
+ if (rte?.["rtekind"] === "1" && sub && !(await this.queryColumn(sub, attno)))
217
+ return false;
218
+ }
219
+ return true;
220
+ }
221
+ const entries = list(query["targetList"]).map(node).filter((t) => t !== null && t["resjunk"] !== "true");
222
+ const te = entries[attno - 1];
223
+ return te ? this.expr(te["expr"], query) : false;
224
+ }
225
+ async variable(v, query) {
226
+ // No varnullingrels (PostgreSQL ≤ 15): outer joins are not visible, so nothing is proven.
227
+ if (!("varnullingrels" in v) || v["varlevelsup"] !== "0")
228
+ return false;
229
+ if (list(v["varnullingrels"]).length > 1)
230
+ return false; // `(b 3)`: an outer join can null it
231
+ // ROLLUP / CUBE / GROUPING SETS null the grouped columns (PostgreSQL ≤ 17 does not mark them).
232
+ if (list(query["groupingSets"]).length > 0)
233
+ return false;
234
+ const rte = node(list(query["rtable"])[Number(v["varno"]) - 1]);
235
+ const attno = Number(v["varattno"]);
236
+ if (!rte || !(attno > 0))
237
+ return false;
238
+ switch (rte["rtekind"]) {
239
+ case "0": { // relation
240
+ const relid = str(rte["relid"]);
241
+ const att = (await this.columns(relid)).find((a) => a.attnum === attno);
242
+ if (!att)
243
+ return false;
244
+ if (att.relkind === "v" || att.relkind === "m")
245
+ return (await this.notNull(relid))[attno - 1] ?? false;
246
+ return att.notnull;
247
+ }
248
+ case "1": { // subquery
249
+ const sub = node(rte["subquery"]);
250
+ return sub ? this.queryColumn(sub, attno) : false;
251
+ }
252
+ case "2": // join alias variable
253
+ return this.expr(list(rte["joinaliasvars"])[attno - 1] ?? null, query);
254
+ case "3": // function in FROM
255
+ return this.functionColumn(rte, attno);
256
+ case "9": // PostgreSQL 18 GROUP BY expressions
257
+ return this.expr(list(rte["groupexprs"])[attno - 1] ?? null, query);
258
+ default:
259
+ return false;
260
+ }
261
+ }
262
+ /** Column `attno` of a single set-returning function in FROM (`WITH ORDINALITY` adds a NOT NULL counter). */
263
+ async functionColumn(rte, attno) {
264
+ const functions = list(rte["functions"]);
265
+ const only = node(functions[0]);
266
+ if (functions.length !== 1 || !only)
267
+ return false;
268
+ const count = Number(str(only["funccolcount"]));
269
+ if (rte["funcordinality"] === "true" && attno === count + 1)
270
+ return true;
271
+ const call = node(only["funcexpr"]);
272
+ if (call?._ !== "FUNCEXPR")
273
+ return false;
274
+ const proc = (await this.loadProcs()).get(str(call["funcid"]) ?? "");
275
+ return proc?.system === true && (NON_NULL_SRF_COLUMNS[proc.name]?.includes(attno) ?? false);
276
+ }
277
+ async all(args, query) {
278
+ for (const a of list(args))
279
+ if (!(await this.expr(a, query)))
280
+ return false;
281
+ return true;
282
+ }
283
+ async expr(value, query) {
284
+ const e = node(value);
285
+ if (!e)
286
+ return false;
287
+ switch (e._) {
288
+ case "VAR":
289
+ return this.variable(e, query);
290
+ case "CONST":
291
+ return e["constisnull"] === "false";
292
+ case "RELABELTYPE":
293
+ case "COERCEVIAIO":
294
+ case "COERCETODOMAIN":
295
+ case "ARRAYCOERCEEXPR":
296
+ case "COLLATEEXPR":
297
+ return this.expr(e["arg"], query);
298
+ case "FUNCEXPR": {
299
+ if (e["funcretset"] !== "false")
300
+ return false;
301
+ const proc = (await this.loadProcs()).get(str(e["funcid"]) ?? "");
302
+ // format_type(type, typmod) is not strict: a NULL typmod still gives a name.
303
+ if (proc?.system && proc.name === "format_type")
304
+ return this.expr(list(e["args"])[0] ?? null, query);
305
+ // Explicit and implicit casts (funcformat 1, 2) keep a non-NULL input non-NULL.
306
+ const castLike = e["funcformat"] === "1" || e["funcformat"] === "2";
307
+ const known = proc?.system === true && (NON_NULL_FUNCTIONS.has(proc.name) || isNonNullStatFunction(proc.name, proc.ret));
308
+ return (castLike || known) && this.all(e["args"], query);
309
+ }
310
+ case "BOOLEXPR":
311
+ return this.all(e["args"], query);
312
+ case "OPEXPR":
313
+ return (await this.strictOperator(e)) && this.all(e["args"], query);
314
+ case "SCALARARRAYOPEXPR": {
315
+ // `x = ANY (arr)` is NULL when there is no match and `arr` holds a NULL: only an
316
+ // `ARRAY[…]` of NOT NULL elements is safe.
317
+ const [left, right] = list(e["args"]);
318
+ const array = node(right);
319
+ return (await this.strictOperator(e)) && array?._ === "ARRAYEXPR"
320
+ && (await this.expr(left ?? null, query)) && this.all(array["elements"], query);
321
+ }
322
+ case "DISTINCTEXPR":
323
+ case "NULLTEST":
324
+ case "BOOLEANTEST":
325
+ case "ARRAYEXPR":
326
+ case "ROW":
327
+ return true;
328
+ case "COALESCEEXPR":
329
+ case "MINMAXEXPR":
330
+ for (const a of list(e["args"]))
331
+ if (await this.expr(a, query))
332
+ return true;
333
+ return false;
334
+ case "CASEEXPR":
335
+ for (const w of list(e["args"]))
336
+ if (!(await this.expr(node(w)?.["result"], query)))
337
+ return false;
338
+ return this.expr(e["defresult"], query);
339
+ case "SUBLINK": // EXISTS (0) and ARRAY (6) sublinks are never NULL
340
+ return e["subLinkType"] === "0" || e["subLinkType"] === "6";
341
+ case "AGGREF": {
342
+ const proc = (await this.loadProcs()).get(str(e["aggfnoid"]) ?? "");
343
+ return proc?.system === true && NON_NULL_AGGREGATES.has(proc.name);
344
+ }
345
+ case "WINDOWFUNC": {
346
+ const proc = (await this.loadProcs()).get(str(e["winfnoid"]) ?? "");
347
+ return proc?.system === true && NON_NULL_WINDOW_FUNCTIONS.has(proc.name);
348
+ }
349
+ default:
350
+ return false;
351
+ }
352
+ }
353
+ }
354
+ //# sourceMappingURL=nullability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nullability.js","sourceRoot":"","sources":["../../src/introspect/nullability.ts"],"names":[],"mappings":"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"}