@supabase/postgrest-typegen 0.2.0 → 0.2.2

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 (66) hide show
  1. package/README.md +12 -0
  2. package/dist/collation.d.ts +2 -0
  3. package/dist/collation.js +15 -0
  4. package/dist/generation/go.js +30 -2
  5. package/dist/generation/index.d.ts +1 -1
  6. package/dist/generation/python.js +24 -10
  7. package/dist/generation/swift.js +52 -3
  8. package/dist/generation/typescript.d.ts +18 -7
  9. package/dist/generation/typescript.js +122 -82
  10. package/dist/introspection/index.js +6 -23
  11. package/dist/introspection/relationships.d.ts +4 -4
  12. package/dist/introspection/relationships.js +4 -11
  13. package/dist/introspection/sql/columns.sql.d.ts +2 -7
  14. package/dist/introspection/sql/columns.sql.js +32 -9
  15. package/dist/introspection/sql/common.d.ts +7 -15
  16. package/dist/introspection/sql/foreign_tables.sql.d.ts +2 -6
  17. package/dist/introspection/sql/foreign_tables.sql.js +0 -5
  18. package/dist/introspection/sql/functions.sql.d.ts +2 -5
  19. package/dist/introspection/sql/functions.sql.js +0 -33
  20. package/dist/introspection/sql/helpers.d.ts +1 -1
  21. package/dist/introspection/sql/helpers.js +2 -2
  22. package/dist/introspection/sql/materialized_views.sql.d.ts +2 -4
  23. package/dist/introspection/sql/materialized_views.sql.js +0 -5
  24. package/dist/introspection/sql/pg-format.d.ts +21 -0
  25. package/dist/introspection/sql/pg-format.js +92 -0
  26. package/dist/introspection/sql/primary_keys.sql.d.ts +2 -4
  27. package/dist/introspection/sql/primary_keys.sql.js +0 -4
  28. package/dist/introspection/sql/schemas.sql.d.ts +2 -6
  29. package/dist/introspection/sql/schemas.sql.js +2 -6
  30. package/dist/introspection/sql/table.sql.d.ts +2 -4
  31. package/dist/introspection/sql/table.sql.js +0 -5
  32. package/dist/introspection/sql/table_relationships.sql.d.ts +2 -2
  33. package/dist/introspection/sql/types.sql.d.ts +5 -5
  34. package/dist/introspection/sql/types.sql.js +6 -17
  35. package/dist/introspection/sql/views.sql.d.ts +2 -4
  36. package/dist/introspection/sql/views.sql.js +6 -5
  37. package/dist/introspection/sql/views_key_dependencies.sql.d.ts +2 -2
  38. package/dist/introspection/sql/views_key_dependencies.sql.js +64 -75
  39. package/dist/sort.js +16 -15
  40. package/dist/types.d.ts +4 -0
  41. package/dist/types.js +11 -0
  42. package/package.json +3 -5
  43. package/src/collation.ts +16 -0
  44. package/src/generation/go.ts +31 -2
  45. package/src/generation/index.ts +1 -0
  46. package/src/generation/python.ts +25 -10
  47. package/src/generation/swift.ts +53 -3
  48. package/src/generation/typescript.ts +187 -107
  49. package/src/introspection/index.ts +7 -32
  50. package/src/introspection/relationships.ts +10 -19
  51. package/src/introspection/sql/columns.sql.ts +34 -18
  52. package/src/introspection/sql/common.ts +7 -17
  53. package/src/introspection/sql/foreign_tables.sql.ts +2 -13
  54. package/src/introspection/sql/functions.sql.ts +2 -44
  55. package/src/introspection/sql/helpers.ts +2 -2
  56. package/src/introspection/sql/materialized_views.sql.ts +2 -11
  57. package/src/introspection/sql/pg-format.ts +101 -0
  58. package/src/introspection/sql/primary_keys.sql.ts +2 -10
  59. package/src/introspection/sql/schemas.sql.ts +4 -14
  60. package/src/introspection/sql/table.sql.ts +2 -11
  61. package/src/introspection/sql/table_relationships.sql.ts +2 -4
  62. package/src/introspection/sql/types.sql.ts +6 -26
  63. package/src/introspection/sql/views.sql.ts +8 -11
  64. package/src/introspection/sql/views_key_dependencies.sql.ts +83 -77
  65. package/src/sort.ts +20 -15
  66. package/src/types.ts +11 -0
@@ -1,14 +1,6 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryPropsWithSchemaFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const COLUMNS_SQL = (
5
- props: SQLQueryPropsWithSchemaFilter & {
6
- tableIdFilter?: string;
7
- tableIdentifierFilter?: string;
8
- columnNameFilter?: string;
9
- idsFilter?: string;
10
- },
11
- ) => /* SQL */ `
3
+ export const COLUMNS_SQL = (props: SchemaFilterProps) => /* SQL */ `
12
4
  -- Adapted from information_schema.columns
13
5
 
14
6
  SELECT
@@ -45,14 +37,44 @@ SELECT
45
37
  WHEN 'd' THEN 'BY DEFAULT'
46
38
  ELSE NULL
47
39
  END AS identity_generation,
48
- a.attgenerated IN ('s') AS is_generated,
40
+ -- 's' = stored, 'v' = virtual (PostgreSQL 18+); neither accepts writes.
41
+ a.attgenerated IN ('s', 'v') AS is_generated,
49
42
  NOT (
50
43
  a.attnotnull
51
44
  OR t.typtype = 'd' AND t.typnotnull
52
45
  ) AS is_nullable,
53
46
  (
54
47
  c.relkind IN ('r', 'p')
55
- OR c.relkind IN ('v', 'f') AND pg_column_is_updatable(c.oid, a.attnum, FALSE)
48
+ -- Columns of views made writable by INSTEAD OF triggers or unconditional
49
+ -- INSTEAD rules can be written through PostgREST even though the view is
50
+ -- not auto-updatable, so they must not degrade to \`?: never\` in generated
51
+ -- Insert/Update types. pg_column_is_updatable cannot express this: it
52
+ -- requires the relation to support both UPDATE and DELETE, so a view with
53
+ -- only an INSTEAD OF INSERT or only an INSTEAD OF UPDATE trigger reports
54
+ -- every column as non-updatable regardless of include_triggers. Triggers
55
+ -- and rules rewrite whole rows, so their presence makes every column
56
+ -- writable (tgtype bits: 64 = INSTEAD, 4 = INSERT, 16 = UPDATE;
57
+ -- pg_rewrite ev_type: '2' = UPDATE, '3' = INSERT; ev_qual is '<>' for
58
+ -- unconditional rules, and only unconditional INSTEAD rules make a view
59
+ -- writable). Which events a view accepts is gated per view via
60
+ -- is_insert_enabled / is_update_enabled.
61
+ OR c.relkind IN ('v', 'f') AND (
62
+ pg_column_is_updatable(c.oid, a.attnum, FALSE)
63
+ OR EXISTS (
64
+ SELECT 1 FROM pg_trigger tg
65
+ WHERE tg.tgrelid = c.oid
66
+ AND tg.tgtype & 64 <> 0
67
+ AND tg.tgtype & 20 <> 0
68
+ AND NOT tg.tgisinternal
69
+ )
70
+ OR EXISTS (
71
+ SELECT 1 FROM pg_rewrite rw
72
+ WHERE rw.ev_class = c.oid
73
+ AND rw.is_instead
74
+ AND rw.ev_type IN ('2', '3')
75
+ AND rw.ev_qual :: text = '<>'
76
+ )
77
+ )
56
78
  ) AS is_updatable,
57
79
  uniques.table_id IS NOT NULL AS is_unique,
58
80
  check_constraints.definition AS "check",
@@ -110,10 +132,6 @@ FROM
110
132
  ) AS check_constraints ON check_constraints.table_id = c.oid AND check_constraints.ordinal_position = a.attnum
111
133
  WHERE
112
134
  ${props.schemaFilter ? `nc.nspname ${props.schemaFilter} AND` : ""}
113
- ${props.idsFilter ? `(c.oid || '.' || a.attnum) ${props.idsFilter} AND` : ""}
114
- ${props.columnNameFilter ? `(c.relname || '.' || a.attname) ${props.columnNameFilter} AND` : ""}
115
- ${props.tableIdFilter ? `c.oid ${props.tableIdFilter} AND` : ""}
116
- ${props.tableIdentifierFilter ? `nc.nspname || '.' || c.relname ${props.tableIdentifierFilter} AND` : ""}
117
135
  NOT pg_is_other_temp_schema(nc.oid)
118
136
  AND a.attnum > 0
119
137
  AND NOT a.attisdropped
@@ -126,6 +144,4 @@ WHERE
126
144
  'SELECT, INSERT, UPDATE, REFERENCES'
127
145
  )
128
146
  )
129
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
130
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
131
147
  `;
@@ -1,18 +1,8 @@
1
- /**
2
- * Shared prop shapes for the SQL builders, ported from
3
- * `postgres-meta/src/lib/sql/common.ts`. Only the variants used by the
4
- * typegen introspection path are kept.
5
- */
6
- export type SQLQueryProps = {
7
- limit?: number;
8
- offset?: number;
9
- };
10
-
11
- export type SQLQueryPropsWithSchemaFilter = SQLQueryProps & {
12
- schemaFilter?: string;
13
- };
14
-
15
- export type SQLQueryPropsWithSchemaFilterAndIdsFilter = SQLQueryProps & {
16
- schemaFilter?: string;
17
- idsFilter?: string;
1
+ /** The only option the introspection passes to its SQL builders. */
2
+ export type SchemaFilterProps = {
3
+ /**
4
+ * An `IN (…)` or `NOT IN (…)` fragment from `filterByList`, or the empty
5
+ * string for no filter.
6
+ */
7
+ schemaFilter: string;
18
8
  };
@@ -1,13 +1,6 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryProps } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const FOREIGN_TABLES_SQL = (
5
- props: SQLQueryProps & {
6
- schemaFilter?: string;
7
- idsFilter?: string;
8
- tableIdentifierFilter?: string;
9
- },
10
- ) => /* SQL */ `
3
+ export const FOREIGN_TABLES_SQL = (props: SchemaFilterProps) => /* SQL */ `
11
4
  SELECT
12
5
  c.oid :: int8 AS id,
13
6
  n.nspname AS schema,
@@ -18,9 +11,5 @@ FROM
18
11
  JOIN pg_namespace n ON n.oid = c.relnamespace
19
12
  WHERE
20
13
  ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
21
- ${props.idsFilter ? `c.oid ${props.idsFilter} AND` : ""}
22
- ${props.tableIdentifierFilter ? `(n.nspname || '.' || c.relname) ${props.tableIdentifierFilter} AND` : ""}
23
14
  c.relkind = 'f'
24
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
25
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
26
15
  `;
@@ -1,15 +1,6 @@
1
- // oxlint-disable typescript/restrict-template-expressions -- verbatim port of postgres-meta's
2
- // builder, which interpolates the `args` string[] into the SQL (relying on Array#toString). The
3
- // expression sits inside a template literal where a targeted disable comment would corrupt the SQL.
4
- import { literal } from "pg-format";
5
- import type { SQLQueryPropsWithSchemaFilterAndIdsFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
6
2
 
7
- export const FUNCTIONS_SQL = (
8
- props: SQLQueryPropsWithSchemaFilterAndIdsFilter & {
9
- nameFilter?: string;
10
- args?: string[];
11
- },
12
- ) => /* SQL */ `
3
+ export const FUNCTIONS_SQL = (props: SchemaFilterProps) => /* SQL */ `
13
4
  -- CTE with sane arg_modes, arg_names, and arg_types.
14
5
  -- All three are always of the same length.
15
6
  -- All three include all args, including OUT and TABLE args.
@@ -36,37 +27,6 @@ with functions as (
36
27
  ${props.schemaFilter ? `join pg_namespace n on p.pronamespace = n.oid` : ""}
37
28
  where
38
29
  ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
39
- ${props.idsFilter ? `p.oid ${props.idsFilter} AND` : ""}
40
- ${props.nameFilter ? `p.proname ${props.nameFilter} AND` : ""}
41
- ${
42
- props.args === undefined
43
- ? ""
44
- : props.args.length > 0
45
- ? `p.proargtypes::text = ${
46
- props.args.length
47
- ? `(
48
- SELECT STRING_AGG(type_oid::text, ' ') FROM (
49
- SELECT (
50
- split_args.arr[
51
- array_length(
52
- split_args.arr,
53
- 1
54
- )
55
- ]::regtype::oid
56
- ) AS type_oid FROM (
57
- SELECT STRING_TO_ARRAY(
58
- UNNEST(
59
- ARRAY[${props.args}]
60
- ),
61
- ' '
62
- ) AS arr
63
- ) AS split_args
64
- ) args
65
- )`
66
- : "''"
67
- } AND`
68
- : ""
69
- }
70
30
  p.prokind = 'f'
71
31
  )
72
32
  select
@@ -154,6 +114,4 @@ from
154
114
  group by
155
115
  t1.oid
156
116
  ) f_args on f_args.oid = f.oid
157
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
158
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
159
117
  `;
@@ -1,4 +1,4 @@
1
- import { literal } from "pg-format";
1
+ import { literal } from "./pg-format.ts";
2
2
 
3
3
  /**
4
4
  * Schemas that postgres-meta excludes by default when `includeSystemSchemas`
@@ -13,7 +13,7 @@ export const DEFAULT_SYSTEM_SCHEMAS = [
13
13
  /**
14
14
  * Build a SQL `IN (...)` / `NOT IN (...)` fragment for an include/exclude list,
15
15
  * ported verbatim from `postgres-meta/src/lib/helpers.ts`. Values are escaped
16
- * with pg-format's `literal`. Returns an empty string when there is nothing to
16
+ * with the inlined pg-format `literal`. Returns an empty string when there is nothing to
17
17
  * filter, so callers interpolate it conditionally.
18
18
  */
19
19
  export const filterByList = (
@@ -1,11 +1,6 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryPropsWithSchemaFilterAndIdsFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const MATERIALIZED_VIEWS_SQL = (
5
- props: SQLQueryPropsWithSchemaFilterAndIdsFilter & {
6
- materializedViewIdentifierFilter?: string;
7
- },
8
- ) => /* SQL */ `
3
+ export const MATERIALIZED_VIEWS_SQL = (props: SchemaFilterProps) => /* SQL */ `
9
4
  select
10
5
  c.oid::int8 as id,
11
6
  n.nspname as schema,
@@ -17,9 +12,5 @@ from
17
12
  join pg_namespace n on n.oid = c.relnamespace
18
13
  where
19
14
  ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
20
- ${props.idsFilter ? `c.oid ${props.idsFilter} AND` : ""}
21
- ${props.materializedViewIdentifierFilter ? `(n.nspname || '.' || c.relname) ${props.materializedViewIdentifierFilter} AND` : ""}
22
15
  c.relkind = 'm'
23
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
24
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
25
16
  `;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Minimal inline port of the `pg-format` helpers this package uses, so the
3
+ * package carries no runtime dependency for them (the CommonJS-only
4
+ * `pg-format` package is awkward to consume from ESM/bundled CLIs).
5
+ *
6
+ * Mirrors `pg-format@1.0.4` byte-for-byte for the inputs postgres-meta feeds
7
+ * it — in particular numbers are quoted (`literal(10)` is `'10'`), because
8
+ * that is what postgres-meta's SQL emits and this package is byte-parity
9
+ * constrained against it. The `supabase/supabase` `packages/pg-meta` port
10
+ * deliberately diverges here (unquoted numbers); do not "fix" this to match it.
11
+ *
12
+ * Originally ported from PostgreSQL's `src/interfaces/libpq/fe-exec.c`.
13
+ */
14
+
15
+ /** Convert a JS ISO string to Postgres' default ISO 8601 form. */
16
+ function formatDate(date: string): string {
17
+ return date.replace("T", " ").replace("Z", "+00");
18
+ }
19
+
20
+ function arrayToList(
21
+ useSpace: boolean,
22
+ array: unknown[],
23
+ formatter: (value: unknown) => string,
24
+ ): string {
25
+ let sql = useSpace ? " (" : "(";
26
+ for (const [index, element] of array.entries()) {
27
+ sql += (index === 0 ? "" : ", ") + formatter(element);
28
+ }
29
+ sql += ")";
30
+ return sql;
31
+ }
32
+
33
+ /**
34
+ * Quote a value as a SQL literal. `null`/`undefined` become `NULL`, booleans
35
+ * `'t'`/`'f'`, dates ISO 8601 strings, arrays comma-separated lists (nested
36
+ * arrays become parenthesised groups), plain objects `'…'::jsonb`, and
37
+ * everything else — including numbers — a single-quoted string with embedded
38
+ * quotes doubled. Strings containing a backslash use the `E'…'` form.
39
+ */
40
+ export function literal(value?: unknown): string {
41
+ let text: string;
42
+ let explicitCast: string | undefined;
43
+
44
+ if (value === undefined || value === null) {
45
+ return "NULL";
46
+ }
47
+ if (value === false) {
48
+ return "'f'";
49
+ }
50
+ if (value === true) {
51
+ return "'t'";
52
+ }
53
+ if (value instanceof Date) {
54
+ return `'${formatDate(value.toISOString())}'`;
55
+ }
56
+ if (Array.isArray(value)) {
57
+ const parts: string[] = [];
58
+ for (const [index, element] of value.entries()) {
59
+ if (Array.isArray(element)) {
60
+ parts.push(arrayToList(index !== 0, element, literal));
61
+ } else {
62
+ parts.push(literal(element));
63
+ }
64
+ }
65
+ return parts.toString();
66
+ }
67
+ if (typeof value === "string") {
68
+ text = value;
69
+ } else if (typeof value === "number" || typeof value === "bigint") {
70
+ text = value.toString();
71
+ } else {
72
+ explicitCast = "jsonb";
73
+ text = JSON.stringify(value);
74
+ }
75
+
76
+ let hasBackslash = false;
77
+ let quoted = "'";
78
+
79
+ for (const c of text) {
80
+ if (c === "'") {
81
+ quoted += c + c;
82
+ } else if (c === "\\") {
83
+ quoted += c + c;
84
+ hasBackslash = true;
85
+ } else {
86
+ quoted += c;
87
+ }
88
+ }
89
+
90
+ quoted += "'";
91
+
92
+ if (hasBackslash) {
93
+ quoted = `E${quoted}`;
94
+ }
95
+
96
+ if (explicitCast) {
97
+ quoted += `::${explicitCast}`;
98
+ }
99
+
100
+ return quoted;
101
+ }
@@ -1,11 +1,6 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryPropsWithSchemaFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const PRIMARY_KEYS_SQL = (
5
- props: SQLQueryPropsWithSchemaFilter & {
6
- tableIdentifierFilter?: string;
7
- },
8
- ) => /* SQL */ `
3
+ export const PRIMARY_KEYS_SQL = (props: SchemaFilterProps) => /* SQL */ `
9
4
  SELECT
10
5
  c.oid :: int8 AS table_id,
11
6
  n.nspname AS schema,
@@ -18,7 +13,6 @@ FROM
18
13
  JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY(i.indkey)
19
14
  WHERE
20
15
  ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
21
- ${props.tableIdentifierFilter ? `n.nspname || '.' || c.relname ${props.tableIdentifierFilter} AND` : ""}
22
16
  i.indisprimary
23
17
  AND c.relkind IN ('r', 'p')
24
18
  AND NOT pg_is_other_temp_schema(n.oid)
@@ -33,6 +27,4 @@ WHERE
33
27
  ORDER BY
34
28
  c.oid,
35
29
  array_position(i.indkey, a.attnum)
36
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
37
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
38
30
  `;
@@ -1,13 +1,6 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryProps } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const SCHEMAS_SQL = (
5
- props: SQLQueryProps & {
6
- nameFilter?: string;
7
- idsFilter?: string;
8
- includeSystemSchemas?: boolean;
9
- },
10
- ) => /* SQL */ `
3
+ export const SCHEMAS_SQL = (props: SchemaFilterProps) => /* SQL */ `
11
4
  -- Adapted from information_schema.schemata
12
5
  select
13
6
  n.oid::int8 as id,
@@ -18,15 +11,12 @@ from
18
11
  pg_roles u
19
12
  where
20
13
  n.nspowner = u.oid
21
- ${props.idsFilter ? `and n.oid ${props.idsFilter}` : ""}
22
- ${props.nameFilter ? `and n.nspname ${props.nameFilter}` : ""}
23
- ${!props.includeSystemSchemas ? `and not pg_catalog.starts_with(n.nspname, 'pg_')` : ""}
14
+ ${props.schemaFilter ? `and n.nspname ${props.schemaFilter}` : ""}
15
+ and not pg_catalog.starts_with(n.nspname, 'pg_')
24
16
  and (
25
17
  pg_has_role(n.nspowner, 'USAGE')
26
18
  or has_schema_privilege(n.oid, 'CREATE, USAGE')
27
19
  )
28
20
  and not pg_catalog.starts_with(n.nspname, 'pg_temp_')
29
21
  and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_')
30
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
31
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
32
22
  `;
@@ -1,11 +1,6 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryPropsWithSchemaFilterAndIdsFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const TABLES_SQL = (
5
- props: SQLQueryPropsWithSchemaFilterAndIdsFilter & {
6
- tableIdentifierFilter?: string;
7
- },
8
- ) => /* SQL */ `
3
+ export const TABLES_SQL = (props: SchemaFilterProps) => /* SQL */ `
9
4
  SELECT
10
5
  c.oid :: int8 AS id,
11
6
  nc.nspname AS schema,
@@ -30,8 +25,6 @@ FROM
30
25
  JOIN pg_class c ON nc.oid = c.relnamespace
31
26
  WHERE
32
27
  ${props.schemaFilter ? `nc.nspname ${props.schemaFilter} AND` : ""}
33
- ${props.idsFilter ? `c.oid ${props.idsFilter} AND` : ""}
34
- ${props.tableIdentifierFilter ? `nc.nspname || '.' || c.relname ${props.tableIdentifierFilter} AND` : ""}
35
28
  c.relkind IN ('r', 'p')
36
29
  AND NOT pg_is_other_temp_schema(nc.oid)
37
30
  AND (
@@ -42,6 +35,4 @@ WHERE
42
35
  )
43
36
  OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
44
37
  )
45
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
46
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
47
38
  `;
@@ -1,8 +1,6 @@
1
- import type { SQLQueryPropsWithSchemaFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
2
2
 
3
- export const TABLE_RELATIONSHIPS_SQL = (
4
- props: SQLQueryPropsWithSchemaFilter,
5
- ) => /* SQL */ `
3
+ export const TABLE_RELATIONSHIPS_SQL = (props: SchemaFilterProps) => /* SQL */ `
6
4
  -- Adapted from
7
5
  -- https://github.com/PostgREST/postgrest/blob/f9f0f79fa914ac00c11fbf7f4c558e14821e67e2/src/PostgREST/SchemaCache.hs#L722
8
6
  WITH
@@ -1,12 +1,8 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryPropsWithSchemaFilterAndIdsFilter } from "./common.ts";
3
-
4
- export const TYPES_SQL = (
5
- props: SQLQueryPropsWithSchemaFilterAndIdsFilter & {
6
- includeTableTypes?: boolean;
7
- includeArrayTypes?: boolean;
8
- },
9
- ) => /* SQL */ `
1
+ /**
2
+ * Every type of every schema, including the row types of tables and views
3
+ * and the array types, since a column of any schema may use them.
4
+ */
5
+ export const TYPES_SQL = /* SQL */ `
10
6
  select
11
7
  t.oid::int8 as id,
12
8
  t.typname as name,
@@ -48,27 +44,11 @@ from
48
44
  t.typrelid = 0
49
45
  or (
50
46
  select
51
- c.relkind ${props.includeTableTypes ? `in ('c', 'r', 'v', 'm', 'p')` : `= 'c'`}
47
+ c.relkind in ('c', 'r', 'v', 'm', 'p', 'f')
52
48
  from
53
49
  pg_class c
54
50
  where
55
51
  c.oid = t.typrelid
56
52
  )
57
53
  )
58
- ${
59
- !props.includeArrayTypes
60
- ? `and not exists (
61
- select
62
- from
63
- pg_type el
64
- where
65
- el.oid = t.typelem
66
- and el.typarray = t.oid
67
- )`
68
- : ""
69
- }
70
- ${props.schemaFilter ? `and n.nspname ${props.schemaFilter}` : ""}
71
- ${props.idsFilter ? `and t.oid ${props.idsFilter}` : ""}
72
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
73
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
74
54
  `;
@@ -1,26 +1,23 @@
1
- import { literal } from "pg-format";
2
- import type { SQLQueryPropsWithSchemaFilterAndIdsFilter } from "./common.ts";
1
+ import type { SchemaFilterProps } from "./common.ts";
3
2
 
4
- export const VIEWS_SQL = (
5
- props: SQLQueryPropsWithSchemaFilterAndIdsFilter & {
6
- viewIdentifierFilter?: string;
7
- },
8
- ) => /* SQL */ `
3
+ export const VIEWS_SQL = (props: SchemaFilterProps) => /* SQL */ `
9
4
  SELECT
10
5
  c.oid :: int8 AS id,
11
6
  n.nspname AS schema,
12
7
  c.relname AS name,
13
8
  -- See definition of information_schema.views
14
9
  (pg_relation_is_updatable(c.oid, false) & 20) = 20 AS is_updatable,
10
+ -- Passing include_triggers => true also counts views made writable by
11
+ -- INSTEAD OF triggers (and INSTEAD rules), which PostgREST can write
12
+ -- through even when the view is not auto-updatable. Bit 8 is INSERT,
13
+ -- bit 4 is UPDATE (see information_schema.views).
14
+ (pg_relation_is_updatable(c.oid, true) & 8) = 8 AS is_insert_enabled,
15
+ (pg_relation_is_updatable(c.oid, true) & 4) = 4 AS is_update_enabled,
15
16
  obj_description(c.oid) AS comment
16
17
  FROM
17
18
  pg_class c
18
19
  JOIN pg_namespace n ON n.oid = c.relnamespace
19
20
  WHERE
20
21
  ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
21
- ${props.idsFilter ? `c.oid ${props.idsFilter} AND` : ""}
22
- ${props.viewIdentifierFilter ? `(n.nspname || '.' || c.relname) ${props.viewIdentifierFilter} AND` : ""}
23
22
  c.relkind = 'v'
24
- ${props.limit ? `limit ${literal(props.limit)}` : ""}
25
- ${props.offset ? `offset ${literal(props.offset)}` : ""}
26
23
  `;