neon 8.4.5 → 8.6.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 (79) hide show
  1. package/README.md +18 -9
  2. package/dist/_chunks/{env-4WGRW2nw.js → env-BNm69Qh8.js} +2 -5
  3. package/dist/commands/config.js +11 -28
  4. package/dist/commands/dev.js +93 -27
  5. package/dist/commands/env.js +2 -3
  6. package/dist/commands/init.js +1 -2
  7. package/dist/commands/link.js +1 -1
  8. package/dist/commands/manifest.js +1 -3
  9. package/dist/commands/subscribe.js +16 -16
  10. package/dist/credential_io.js +1 -2
  11. package/dist/dev/env.js +1 -2
  12. package/dist/dev/runtime.js +8 -0
  13. package/dist/env_file.js +9 -1
  14. package/dist/index.js +1 -1
  15. package/dist/init/auth.js +1 -4
  16. package/dist/init/choices.js +21 -7
  17. package/dist/init/copy.js +21 -7
  18. package/dist/init/run.js +25 -16
  19. package/dist/plugins/run.js +2 -1
  20. package/dist/psql/command/cmd_io.js +1 -2
  21. package/dist/psql/command/cmd_pipeline.js +1 -2
  22. package/dist/psql/core/common.js +1 -2
  23. package/dist/psql/core/startup.js +1 -2
  24. package/dist/psql/index.js +1 -2
  25. package/dist/psql/types/index.js +1 -2
  26. package/dist/skills/catalog.js +5 -0
  27. package/dist/utils/hooks.js +0 -2
  28. package/dist/utils/staging.js +1 -14
  29. package/{LICENSE → dist/vendor/postgres-meta/LICENSE} +0 -1
  30. package/dist/vendor/postgres-meta/constants.js +14 -0
  31. package/dist/vendor/postgres-meta/lib/PostgresMeta.js +49 -0
  32. package/dist/vendor/postgres-meta/lib/PostgresMetaColumnPrivileges.js +85 -0
  33. package/dist/vendor/postgres-meta/lib/PostgresMetaColumns.js +235 -0
  34. package/dist/vendor/postgres-meta/lib/PostgresMetaConfig.js +16 -0
  35. package/dist/vendor/postgres-meta/lib/PostgresMetaExtensions.js +79 -0
  36. package/dist/vendor/postgres-meta/lib/PostgresMetaForeignTables.js +81 -0
  37. package/dist/vendor/postgres-meta/lib/PostgresMetaFunctions.js +173 -0
  38. package/dist/vendor/postgres-meta/lib/PostgresMetaIndexes.js +42 -0
  39. package/dist/vendor/postgres-meta/lib/PostgresMetaMaterializedViews.js +84 -0
  40. package/dist/vendor/postgres-meta/lib/PostgresMetaPolicies.js +120 -0
  41. package/dist/vendor/postgres-meta/lib/PostgresMetaPublications.js +193 -0
  42. package/dist/vendor/postgres-meta/lib/PostgresMetaRelationships.js +87 -0
  43. package/dist/vendor/postgres-meta/lib/PostgresMetaRoles.js +203 -0
  44. package/dist/vendor/postgres-meta/lib/PostgresMetaSchemas.js +105 -0
  45. package/dist/vendor/postgres-meta/lib/PostgresMetaTablePrivileges.js +91 -0
  46. package/dist/vendor/postgres-meta/lib/PostgresMetaTables.js +183 -0
  47. package/dist/vendor/postgres-meta/lib/PostgresMetaTriggers.js +156 -0
  48. package/dist/vendor/postgres-meta/lib/PostgresMetaTypes.js +22 -0
  49. package/dist/vendor/postgres-meta/lib/PostgresMetaVersion.js +20 -0
  50. package/dist/vendor/postgres-meta/lib/PostgresMetaViews.js +83 -0
  51. package/dist/vendor/postgres-meta/lib/constants.js +8 -0
  52. package/dist/vendor/postgres-meta/lib/db.js +147 -0
  53. package/dist/vendor/postgres-meta/lib/generators.js +106 -0
  54. package/dist/vendor/postgres-meta/lib/helpers.js +26 -0
  55. package/dist/vendor/postgres-meta/lib/index.js +1 -0
  56. package/dist/vendor/postgres-meta/lib/sql/column_privileges.sql.js +154 -0
  57. package/dist/vendor/postgres-meta/lib/sql/columns.sql.js +123 -0
  58. package/dist/vendor/postgres-meta/lib/sql/common.js +1 -0
  59. package/dist/vendor/postgres-meta/lib/sql/config.sql.js +32 -0
  60. package/dist/vendor/postgres-meta/lib/sql/extensions.sql.js +20 -0
  61. package/dist/vendor/postgres-meta/lib/sql/foreign_tables.sql.js +20 -0
  62. package/dist/vendor/postgres-meta/lib/sql/functions.sql.js +141 -0
  63. package/dist/vendor/postgres-meta/lib/sql/indexes.sql.js +51 -0
  64. package/dist/vendor/postgres-meta/lib/sql/materialized_views.sql.js +21 -0
  65. package/dist/vendor/postgres-meta/lib/sql/policies.sql.js +53 -0
  66. package/dist/vendor/postgres-meta/lib/sql/publications.sql.js +46 -0
  67. package/dist/vendor/postgres-meta/lib/sql/roles.sql.js +40 -0
  68. package/dist/vendor/postgres-meta/lib/sql/schemas.sql.js +26 -0
  69. package/dist/vendor/postgres-meta/lib/sql/table.sql.js +109 -0
  70. package/dist/vendor/postgres-meta/lib/sql/table_privileges.sql.js +85 -0
  71. package/dist/vendor/postgres-meta/lib/sql/table_relationships.sql.js +52 -0
  72. package/dist/vendor/postgres-meta/lib/sql/triggers.sql.js +64 -0
  73. package/dist/vendor/postgres-meta/lib/sql/types.sql.js +65 -0
  74. package/dist/vendor/postgres-meta/lib/sql/version.sql.js +15 -0
  75. package/dist/vendor/postgres-meta/lib/sql/views.sql.js +22 -0
  76. package/dist/vendor/postgres-meta/lib/sql/views_key_dependencies.sql.js +198 -0
  77. package/dist/vendor/postgres-meta/lib/types.js +1 -0
  78. package/dist/vendor/postgres-meta/templates/typescript.js +608 -0
  79. package/package.json +12 -5
@@ -0,0 +1,141 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/functions.sql.ts
2
+ const FUNCTIONS_SQL = (props) => `
3
+ -- CTE with sane arg_modes, arg_names, and arg_types.
4
+ -- All three are always of the same length.
5
+ -- All three include all args, including OUT and TABLE args.
6
+ with functions as (
7
+ select
8
+ p.*,
9
+ -- proargmodes is null when all arg modes are IN
10
+ coalesce(
11
+ p.proargmodes,
12
+ array_fill('i'::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))])
13
+ ) as arg_modes,
14
+ -- proargnames is null when all args are unnamed
15
+ coalesce(
16
+ p.proargnames,
17
+ array_fill(''::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))])
18
+ ) as arg_names,
19
+ -- proallargtypes is null when all arg modes are IN
20
+ coalesce(p.proallargtypes, p.proargtypes) as arg_types,
21
+ array_cat(
22
+ array_fill(false, array[pronargs - pronargdefaults]),
23
+ array_fill(true, array[pronargdefaults])) as arg_has_defaults
24
+ from
25
+ pg_proc as p
26
+ ${props.schemaFilter ? `join pg_namespace n on p.pronamespace = n.oid` : ""}
27
+ where
28
+ ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
29
+ ${props.idsFilter ? `p.oid ${props.idsFilter} AND` : ""}
30
+ ${props.nameFilter ? `p.proname ${props.nameFilter} AND` : ""}
31
+ ${props.args === void 0 ? "" : props.args.length > 0 ? `p.proargtypes::text = ${props.args.length ? `(
32
+ SELECT STRING_AGG(type_oid::text, ' ') FROM (
33
+ SELECT (
34
+ split_args.arr[
35
+ array_length(
36
+ split_args.arr,
37
+ 1
38
+ )
39
+ ]::regtype::oid
40
+ ) AS type_oid FROM (
41
+ SELECT STRING_TO_ARRAY(
42
+ UNNEST(
43
+ ARRAY[${props.args}]
44
+ ),
45
+ ' '
46
+ ) AS arr
47
+ ) AS split_args
48
+ ) args
49
+ )` : "''"} AND` : ""}
50
+ p.prokind = 'f'
51
+ )
52
+ select
53
+ f.oid::int8 as id,
54
+ n.nspname as schema,
55
+ f.proname as name,
56
+ l.lanname as language,
57
+ case
58
+ when l.lanname = 'internal' then ''
59
+ else f.prosrc
60
+ end as definition,
61
+ case
62
+ when l.lanname = 'internal' then f.prosrc
63
+ else pg_get_functiondef(f.oid)
64
+ end as complete_statement,
65
+ coalesce(f_args.args, '[]') as args,
66
+ pg_get_function_arguments(f.oid) as argument_types,
67
+ pg_get_function_identity_arguments(f.oid) as identity_argument_types,
68
+ f.prorettype::int8 as return_type_id,
69
+ pg_get_function_result(f.oid) as return_type,
70
+ nullif(rt.typrelid::int8, 0) as return_type_relation_id,
71
+ f.proretset as is_set_returning_function,
72
+ case
73
+ when f.proretset then nullif(f.prorows, 0)
74
+ else null
75
+ end as prorows,
76
+ case
77
+ when f.provolatile = 'i' then 'IMMUTABLE'
78
+ when f.provolatile = 's' then 'STABLE'
79
+ when f.provolatile = 'v' then 'VOLATILE'
80
+ end as behavior,
81
+ f.prosecdef as security_definer,
82
+ f_config.config_params as config_params
83
+ from
84
+ functions f
85
+ left join pg_namespace n on f.pronamespace = n.oid
86
+ left join pg_language l on f.prolang = l.oid
87
+ left join pg_type rt on rt.oid = f.prorettype
88
+ left join (
89
+ select
90
+ oid,
91
+ jsonb_object_agg(param, value) filter (where param is not null) as config_params
92
+ from
93
+ (
94
+ select
95
+ oid,
96
+ (string_to_array(unnest(proconfig), '='))[1] as param,
97
+ (string_to_array(unnest(proconfig), '='))[2] as value
98
+ from
99
+ functions
100
+ ) as t
101
+ group by
102
+ oid
103
+ ) f_config on f_config.oid = f.oid
104
+ left join (
105
+ select
106
+ oid,
107
+ jsonb_agg(jsonb_build_object(
108
+ 'mode', t2.mode,
109
+ 'name', name,
110
+ 'type_id', type_id,
111
+ 'has_default', has_default
112
+ )) as args
113
+ from
114
+ (
115
+ select
116
+ oid,
117
+ unnest(arg_modes) as mode,
118
+ unnest(arg_names) as name,
119
+ unnest(arg_types)::int8 as type_id,
120
+ unnest(arg_has_defaults) as has_default
121
+ from
122
+ functions
123
+ ) as t1,
124
+ lateral (
125
+ select
126
+ case
127
+ when t1.mode = 'i' then 'in'
128
+ when t1.mode = 'o' then 'out'
129
+ when t1.mode = 'b' then 'inout'
130
+ when t1.mode = 'v' then 'variadic'
131
+ else 'table'
132
+ end as mode
133
+ ) as t2
134
+ group by
135
+ t1.oid
136
+ ) f_args on f_args.oid = f.oid
137
+ ${props.limit ? `limit ${props.limit}` : ""}
138
+ ${props.offset ? `offset ${props.offset}` : ""}
139
+ `;
140
+ //#endregion
141
+ export { FUNCTIONS_SQL };
@@ -0,0 +1,51 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/indexes.sql.ts
2
+ const INDEXES_SQL = (props) => `
3
+ SELECT
4
+ idx.indexrelid::int8 AS id,
5
+ idx.indrelid::int8 AS table_id,
6
+ n.nspname AS schema,
7
+ idx.indnatts AS number_of_attributes,
8
+ idx.indnkeyatts AS number_of_key_attributes,
9
+ idx.indisunique AS is_unique,
10
+ idx.indisprimary AS is_primary,
11
+ idx.indisexclusion AS is_exclusion,
12
+ idx.indimmediate AS is_immediate,
13
+ idx.indisclustered AS is_clustered,
14
+ idx.indisvalid AS is_valid,
15
+ idx.indcheckxmin AS check_xmin,
16
+ idx.indisready AS is_ready,
17
+ idx.indislive AS is_live,
18
+ idx.indisreplident AS is_replica_identity,
19
+ idx.indkey::smallint[] AS key_attributes,
20
+ idx.indcollation::integer[] AS collation,
21
+ idx.indclass::integer[] AS class,
22
+ idx.indoption::smallint[] AS options,
23
+ idx.indpred AS index_predicate,
24
+ obj_description(idx.indexrelid, 'pg_class') AS comment,
25
+ ix.indexdef as index_definition,
26
+ am.amname AS access_method,
27
+ jsonb_agg(
28
+ jsonb_build_object(
29
+ 'attribute_number', a.attnum,
30
+ 'attribute_name', a.attname,
31
+ 'data_type', format_type(a.atttypid, a.atttypmod)
32
+ )
33
+ ORDER BY a.attnum
34
+ ) AS index_attributes
35
+ FROM
36
+ pg_index idx
37
+ JOIN pg_class c ON c.oid = idx.indexrelid
38
+ JOIN pg_namespace n ON c.relnamespace = n.oid
39
+ JOIN pg_am am ON c.relam = am.oid
40
+ JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY(idx.indkey)
41
+ JOIN pg_indexes ix ON c.relname = ix.indexname
42
+ WHERE
43
+ ${props.schemaFilter ? `n.nspname ${props.schemaFilter}` : "true"}
44
+ ${props.idsFilter ? `AND idx.indexrelid ${props.idsFilter}` : ""}
45
+ GROUP BY
46
+ idx.indexrelid, idx.indrelid, n.nspname, idx.indnatts, idx.indnkeyatts, idx.indisunique, idx.indisprimary, idx.indisexclusion, idx.indimmediate, idx.indisclustered, idx.indisvalid, idx.indcheckxmin, idx.indisready, idx.indislive, idx.indisreplident, idx.indkey, idx.indcollation, idx.indclass, idx.indoption, idx.indexprs, idx.indpred, ix.indexdef, am.amname
47
+ ${props.limit ? `limit ${props.limit}` : ""}
48
+ ${props.offset ? `offset ${props.offset}` : ""}
49
+ `;
50
+ //#endregion
51
+ export { INDEXES_SQL };
@@ -0,0 +1,21 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/materialized_views.sql.ts
2
+ const MATERIALIZED_VIEWS_SQL = (props) => `
3
+ select
4
+ c.oid::int8 as id,
5
+ n.nspname as schema,
6
+ c.relname as name,
7
+ c.relispopulated as is_populated,
8
+ obj_description(c.oid) as comment
9
+ from
10
+ pg_class c
11
+ join pg_namespace n on n.oid = c.relnamespace
12
+ where
13
+ ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
14
+ ${props.idsFilter ? `c.oid ${props.idsFilter} AND` : ""}
15
+ ${props.materializedViewIdentifierFilter ? `(n.nspname || '.' || c.relname) ${props.materializedViewIdentifierFilter} AND` : ""}
16
+ c.relkind = 'm'
17
+ ${props.limit ? `limit ${props.limit}` : ""}
18
+ ${props.offset ? `offset ${props.offset}` : ""}
19
+ `;
20
+ //#endregion
21
+ export { MATERIALIZED_VIEWS_SQL };
@@ -0,0 +1,53 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/policies.sql.ts
2
+ const POLICIES_SQL = (props) => `
3
+ SELECT
4
+ pol.oid :: int8 AS id,
5
+ n.nspname AS schema,
6
+ c.relname AS table,
7
+ c.oid :: int8 AS table_id,
8
+ pol.polname AS name,
9
+ CASE
10
+ WHEN pol.polpermissive THEN 'PERMISSIVE' :: text
11
+ ELSE 'RESTRICTIVE' :: text
12
+ END AS action,
13
+ CASE
14
+ WHEN pol.polroles = '{0}' :: oid [] THEN array_to_json(
15
+ string_to_array('public' :: text, '' :: text) :: name []
16
+ )
17
+ ELSE array_to_json(
18
+ ARRAY(
19
+ SELECT
20
+ pg_roles.rolname
21
+ FROM
22
+ pg_roles
23
+ WHERE
24
+ pg_roles.oid = ANY (pol.polroles)
25
+ ORDER BY
26
+ pg_roles.rolname
27
+ )
28
+ )
29
+ END AS roles,
30
+ CASE
31
+ pol.polcmd
32
+ WHEN 'r' :: "char" THEN 'SELECT' :: text
33
+ WHEN 'a' :: "char" THEN 'INSERT' :: text
34
+ WHEN 'w' :: "char" THEN 'UPDATE' :: text
35
+ WHEN 'd' :: "char" THEN 'DELETE' :: text
36
+ WHEN '*' :: "char" THEN 'ALL' :: text
37
+ ELSE NULL :: text
38
+ END AS command,
39
+ pg_get_expr(pol.polqual, pol.polrelid) AS definition,
40
+ pg_get_expr(pol.polwithcheck, pol.polrelid) AS check
41
+ FROM
42
+ pg_policy pol
43
+ JOIN pg_class c ON c.oid = pol.polrelid
44
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
45
+ WHERE
46
+ ${props.schemaFilter ? `n.nspname ${props.schemaFilter}` : "true"}
47
+ ${props.idsFilter ? `AND pol.oid ${props.idsFilter}` : ""}
48
+ ${props.functionNameIdentifierFilter ? `AND (c.relname || '.' || pol.polname) ${props.functionNameIdentifierFilter}` : ""}
49
+ ${props.limit ? `limit ${props.limit}` : ""}
50
+ ${props.offset ? `offset ${props.offset}` : ""}
51
+ `;
52
+ //#endregion
53
+ export { POLICIES_SQL };
@@ -0,0 +1,46 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/publications.sql.ts
2
+ const PUBLICATIONS_SQL = (props) => `
3
+ SELECT
4
+ p.oid :: int8 AS id,
5
+ p.pubname AS name,
6
+ p.pubowner::regrole::text AS owner,
7
+ p.pubinsert AS publish_insert,
8
+ p.pubupdate AS publish_update,
9
+ p.pubdelete AS publish_delete,
10
+ p.pubtruncate AS publish_truncate,
11
+ CASE
12
+ WHEN p.puballtables THEN NULL
13
+ ELSE pr.tables
14
+ END AS tables
15
+ FROM
16
+ pg_catalog.pg_publication AS p
17
+ LEFT JOIN LATERAL (
18
+ SELECT
19
+ COALESCE(
20
+ array_agg(
21
+ json_build_object(
22
+ 'id',
23
+ c.oid :: int8,
24
+ 'name',
25
+ c.relname,
26
+ 'schema',
27
+ nc.nspname
28
+ )
29
+ ),
30
+ '{}'
31
+ ) AS tables
32
+ FROM
33
+ pg_catalog.pg_publication_rel AS pr
34
+ JOIN pg_class AS c ON pr.prrelid = c.oid
35
+ join pg_namespace as nc on c.relnamespace = nc.oid
36
+ WHERE
37
+ pr.prpubid = p.oid
38
+ ) AS pr ON 1 = 1
39
+ WHERE
40
+ ${props.idsFilter ? `p.oid ${props.idsFilter}` : "true"}
41
+ ${props.nameFilter ? `AND p.pubname ${props.nameFilter}` : ""}
42
+ ${props.limit ? `limit ${props.limit}` : ""}
43
+ ${props.offset ? `offset ${props.offset}` : ""}
44
+ `;
45
+ //#endregion
46
+ export { PUBLICATIONS_SQL };
@@ -0,0 +1,40 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/roles.sql.ts
2
+ const ROLES_SQL = (props) => `
3
+ -- TODO: Consider using pg_authid vs. pg_roles for unencrypted password field
4
+ SELECT
5
+ oid :: int8 AS id,
6
+ rolname AS name,
7
+ rolsuper AS is_superuser,
8
+ rolcreatedb AS can_create_db,
9
+ rolcreaterole AS can_create_role,
10
+ rolinherit AS inherit_role,
11
+ rolcanlogin AS can_login,
12
+ rolreplication AS is_replication_role,
13
+ rolbypassrls AS can_bypass_rls,
14
+ (
15
+ SELECT
16
+ COUNT(*)
17
+ FROM
18
+ pg_stat_activity
19
+ WHERE
20
+ pg_roles.rolname = pg_stat_activity.usename
21
+ ) AS active_connections,
22
+ CASE WHEN rolconnlimit = -1 THEN current_setting('max_connections') :: int8
23
+ ELSE rolconnlimit
24
+ END AS connection_limit,
25
+ rolpassword AS password,
26
+ rolvaliduntil AS valid_until,
27
+ rolconfig AS config
28
+ FROM
29
+ pg_roles
30
+ WHERE
31
+ ${props.idsFilter ? `oid ${props.idsFilter}` : "true"}
32
+ -- All default/predefined roles start with pg_: https://www.postgresql.org/docs/15/predefined-roles.html
33
+ -- The pg_ prefix is also reserved.
34
+ ${!props.includeDefaultRoles ? `AND NOT pg_catalog.starts_with(rolname, 'pg_')` : ""}
35
+ ${props.nameFilter ? `AND rolname ${props.nameFilter}` : ""}
36
+ ${props.limit ? `limit ${props.limit}` : ""}
37
+ ${props.offset ? `offset ${props.offset}` : ""}
38
+ `;
39
+ //#endregion
40
+ export { ROLES_SQL };
@@ -0,0 +1,26 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/schemas.sql.ts
2
+ const SCHEMAS_SQL = (props) => `
3
+ -- Adapted from information_schema.schemata
4
+ select
5
+ n.oid::int8 as id,
6
+ n.nspname as name,
7
+ u.rolname as owner
8
+ from
9
+ pg_namespace n,
10
+ pg_roles u
11
+ where
12
+ n.nspowner = u.oid
13
+ ${props.idsFilter ? `and n.oid ${props.idsFilter}` : ""}
14
+ ${props.nameFilter ? `and n.nspname ${props.nameFilter}` : ""}
15
+ ${!props.includeSystemSchemas ? `and not pg_catalog.starts_with(n.nspname, 'pg_')` : ""}
16
+ and (
17
+ pg_has_role(n.nspowner, 'USAGE')
18
+ or has_schema_privilege(n.oid, 'CREATE, USAGE')
19
+ )
20
+ and not pg_catalog.starts_with(n.nspname, 'pg_temp_')
21
+ and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_')
22
+ ${props.limit ? `limit ${props.limit}` : ""}
23
+ ${props.offset ? `offset ${props.offset}` : ""}
24
+ `;
25
+ //#endregion
26
+ export { SCHEMAS_SQL };
@@ -0,0 +1,109 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/table.sql.ts
2
+ const TABLES_SQL = (props) => `
3
+ SELECT
4
+ c.oid :: int8 AS id,
5
+ nc.nspname AS schema,
6
+ c.relname AS name,
7
+ c.relrowsecurity AS rls_enabled,
8
+ c.relforcerowsecurity AS rls_forced,
9
+ CASE
10
+ WHEN c.relreplident = 'd' THEN 'DEFAULT'
11
+ WHEN c.relreplident = 'i' THEN 'INDEX'
12
+ WHEN c.relreplident = 'f' THEN 'FULL'
13
+ ELSE 'NOTHING'
14
+ END AS replica_identity,
15
+ pg_total_relation_size(format('%I.%I', nc.nspname, c.relname)) :: int8 AS bytes,
16
+ pg_size_pretty(
17
+ pg_total_relation_size(format('%I.%I', nc.nspname, c.relname))
18
+ ) AS size,
19
+ pg_stat_get_live_tuples(c.oid) AS live_rows_estimate,
20
+ pg_stat_get_dead_tuples(c.oid) AS dead_rows_estimate,
21
+ obj_description(c.oid) AS comment,
22
+ coalesce(pk.primary_keys, '[]') as primary_keys,
23
+ coalesce(
24
+ jsonb_agg(relationships) filter (where relationships is not null),
25
+ '[]'
26
+ ) as relationships
27
+ FROM
28
+ pg_namespace nc
29
+ JOIN pg_class c ON nc.oid = c.relnamespace
30
+ left join (
31
+ select
32
+ c.oid::int8 as table_id,
33
+ jsonb_agg(
34
+ jsonb_build_object(
35
+ 'table_id', c.oid::int8,
36
+ 'schema', n.nspname,
37
+ 'table_name', c.relname,
38
+ 'name', a.attname
39
+ )
40
+ order by array_position(i.indkey, a.attnum)
41
+ ) as primary_keys
42
+ from
43
+ pg_index i
44
+ join pg_class c on i.indrelid = c.oid
45
+ join pg_namespace n on c.relnamespace = n.oid
46
+ join pg_attribute a on a.attrelid = c.oid and a.attnum = any(i.indkey)
47
+ where
48
+ ${props.schemaFilter ? `n.nspname ${props.schemaFilter} AND` : ""}
49
+ ${props.tableIdentifierFilter ? `n.nspname || '.' || c.relname ${props.tableIdentifierFilter} AND` : ""}
50
+ i.indisprimary
51
+ group by c.oid
52
+ ) as pk
53
+ on pk.table_id = c.oid
54
+ left join (
55
+ select
56
+ c.oid :: int8 as id,
57
+ c.conname as constraint_name,
58
+ nsa.nspname as source_schema,
59
+ csa.relname as source_table_name,
60
+ sa.attname as source_column_name,
61
+ nta.nspname as target_table_schema,
62
+ cta.relname as target_table_name,
63
+ ta.attname as target_column_name
64
+ from
65
+ pg_constraint c
66
+ join (
67
+ pg_attribute sa
68
+ join pg_class csa on sa.attrelid = csa.oid
69
+ join pg_namespace nsa on csa.relnamespace = nsa.oid
70
+ ) on sa.attrelid = c.conrelid and sa.attnum = any (c.conkey)
71
+ join (
72
+ pg_attribute ta
73
+ join pg_class cta on ta.attrelid = cta.oid
74
+ join pg_namespace nta on cta.relnamespace = nta.oid
75
+ ) on ta.attrelid = c.confrelid and ta.attnum = any (c.confkey)
76
+ where
77
+ ${props.schemaFilter ? `nsa.nspname ${props.schemaFilter} OR nta.nspname ${props.schemaFilter} AND` : ""}
78
+ ${props.tableIdentifierFilter ? `(nsa.nspname || '.' || csa.relname) ${props.tableIdentifierFilter} OR (nta.nspname || '.' || cta.relname) ${props.tableIdentifierFilter} AND` : ""}
79
+ c.contype = 'f'
80
+ ) as relationships
81
+ on (relationships.source_schema = nc.nspname and relationships.source_table_name = c.relname)
82
+ or (relationships.target_table_schema = nc.nspname and relationships.target_table_name = c.relname)
83
+ WHERE
84
+ ${props.schemaFilter ? `nc.nspname ${props.schemaFilter} AND` : ""}
85
+ ${props.idsFilter ? `c.oid ${props.idsFilter} AND` : ""}
86
+ ${props.tableIdentifierFilter ? `nc.nspname || '.' || c.relname ${props.tableIdentifierFilter} AND` : ""}
87
+ c.relkind IN ('r', 'p')
88
+ AND NOT pg_is_other_temp_schema(nc.oid)
89
+ AND (
90
+ pg_has_role(c.relowner, 'USAGE')
91
+ OR has_table_privilege(
92
+ c.oid,
93
+ 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'
94
+ )
95
+ OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
96
+ )
97
+ group by
98
+ c.oid,
99
+ c.relname,
100
+ c.relrowsecurity,
101
+ c.relforcerowsecurity,
102
+ c.relreplident,
103
+ nc.nspname,
104
+ pk.primary_keys
105
+ ${props.limit ? `limit ${props.limit}` : ""}
106
+ ${props.offset ? `offset ${props.offset}` : ""}
107
+ `;
108
+ //#endregion
109
+ export { TABLES_SQL };
@@ -0,0 +1,85 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/table_privileges.sql.ts
2
+ const TABLE_PRIVILEGES_SQL = (props) => `
3
+ -- Despite the name \`table_privileges\`, this includes other kinds of relations:
4
+ -- views, matviews, etc. "Relation privileges" just doesn't roll off the tongue.
5
+ --
6
+ -- For each relation, get its relacl in a jsonb format,
7
+ -- e.g.
8
+ --
9
+ -- '{postgres=arwdDxt/postgres}'
10
+ --
11
+ -- becomes
12
+ --
13
+ -- [
14
+ -- {
15
+ -- "grantee": "postgres",
16
+ -- "grantor": "postgres",
17
+ -- "is_grantable": false,
18
+ -- "privilege_type": "INSERT"
19
+ -- },
20
+ -- ...
21
+ -- ]
22
+ select
23
+ c.oid as relation_id,
24
+ nc.nspname as schema,
25
+ c.relname as name,
26
+ case
27
+ when c.relkind = 'r' then 'table'
28
+ when c.relkind = 'v' then 'view'
29
+ when c.relkind = 'm' then 'materialized_view'
30
+ when c.relkind = 'f' then 'foreign_table'
31
+ when c.relkind = 'p' then 'partitioned_table'
32
+ end as kind,
33
+ coalesce(
34
+ jsonb_agg(
35
+ jsonb_build_object(
36
+ 'grantor', grantor.rolname,
37
+ 'grantee', grantee.rolname,
38
+ 'privilege_type', _priv.privilege_type,
39
+ 'is_grantable', _priv.is_grantable
40
+ )
41
+ ) filter (where _priv is not null),
42
+ '[]'
43
+ ) as privileges
44
+ from pg_class c
45
+ join pg_namespace as nc
46
+ on nc.oid = c.relnamespace
47
+ left join lateral (
48
+ select grantor, grantee, privilege_type, is_grantable
49
+ from aclexplode(coalesce(c.relacl, acldefault('r', c.relowner)))
50
+ ) as _priv on true
51
+ left join pg_roles as grantor
52
+ on grantor.oid = _priv.grantor
53
+ left join (
54
+ select
55
+ pg_roles.oid,
56
+ pg_roles.rolname
57
+ from pg_roles
58
+ union all
59
+ select
60
+ (0)::oid as oid, 'PUBLIC'
61
+ ) as grantee (oid, rolname)
62
+ on grantee.oid = _priv.grantee
63
+ where c.relkind in ('r', 'v', 'm', 'f', 'p')
64
+ ${props.schemaFilter ? `and nc.nspname ${props.schemaFilter}` : ""}
65
+ ${props.idsFilter ? `and c.oid ${props.idsFilter}` : ""}
66
+ ${props.nameIdentifierFilter ? `and (nc.nspname || '.' || c.relname) ${props.nameIdentifierFilter}` : ""}
67
+ and not pg_is_other_temp_schema(c.relnamespace)
68
+ and (
69
+ pg_has_role(c.relowner, 'USAGE')
70
+ or has_table_privilege(
71
+ c.oid,
72
+ 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, MAINTAIN'
73
+ )
74
+ or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
75
+ )
76
+ group by
77
+ c.oid,
78
+ nc.nspname,
79
+ c.relname,
80
+ c.relkind
81
+ ${props.limit ? `limit ${props.limit}` : ""}
82
+ ${props.offset ? `offset ${props.offset}` : ""}
83
+ `;
84
+ //#endregion
85
+ export { TABLE_PRIVILEGES_SQL };
@@ -0,0 +1,52 @@
1
+ //#region src/vendor/postgres-meta/lib/sql/table_relationships.sql.ts
2
+ const TABLE_RELATIONSHIPS_SQL = (props) => `
3
+ -- Adapted from
4
+ -- https://github.com/PostgREST/postgrest/blob/f9f0f79fa914ac00c11fbf7f4c558e14821e67e2/src/PostgREST/SchemaCache.hs#L722
5
+ WITH
6
+ pks_uniques_cols AS (
7
+ SELECT
8
+ connamespace,
9
+ conrelid,
10
+ jsonb_agg(column_info.cols) as cols
11
+ FROM pg_constraint
12
+ JOIN lateral (
13
+ SELECT array_agg(cols.attname order by cols.attnum) as cols
14
+ FROM ( select unnest(conkey) as col) _
15
+ JOIN pg_attribute cols on cols.attrelid = conrelid and cols.attnum = col
16
+ ) column_info ON TRUE
17
+ WHERE
18
+ contype IN ('p', 'u') and
19
+ connamespace::regnamespace::text <> 'pg_catalog'
20
+ ${props.schemaFilter ? `and connamespace::regnamespace::text ${props.schemaFilter}` : ""}
21
+ GROUP BY connamespace, conrelid
22
+ )
23
+ SELECT
24
+ traint.conname AS foreign_key_name,
25
+ ns1.nspname AS schema,
26
+ tab.relname AS relation,
27
+ column_info.cols AS columns,
28
+ ns2.nspname AS referenced_schema,
29
+ other.relname AS referenced_relation,
30
+ column_info.refs AS referenced_columns,
31
+ (column_info.cols IN (SELECT * FROM jsonb_array_elements(pks_uqs.cols))) AS is_one_to_one
32
+ FROM pg_constraint traint
33
+ JOIN LATERAL (
34
+ SELECT
35
+ jsonb_agg(cols.attname order by ord) AS cols,
36
+ jsonb_agg(refs.attname order by ord) AS refs
37
+ FROM unnest(traint.conkey, traint.confkey) WITH ORDINALITY AS _(col, ref, ord)
38
+ JOIN pg_attribute cols ON cols.attrelid = traint.conrelid AND cols.attnum = col
39
+ JOIN pg_attribute refs ON refs.attrelid = traint.confrelid AND refs.attnum = ref
40
+ WHERE ${props.schemaFilter ? `traint.connamespace::regnamespace::text ${props.schemaFilter}` : "true"}
41
+ ) AS column_info ON TRUE
42
+ JOIN pg_namespace ns1 ON ns1.oid = traint.connamespace
43
+ JOIN pg_class tab ON tab.oid = traint.conrelid
44
+ JOIN pg_class other ON other.oid = traint.confrelid
45
+ JOIN pg_namespace ns2 ON ns2.oid = other.relnamespace
46
+ LEFT JOIN pks_uniques_cols pks_uqs ON pks_uqs.connamespace = traint.connamespace AND pks_uqs.conrelid = traint.conrelid
47
+ WHERE traint.contype = 'f'
48
+ AND traint.conparentid = 0
49
+ ${props.schemaFilter ? `and ns1.nspname ${props.schemaFilter}` : ""}
50
+ `;
51
+ //#endregion
52
+ export { TABLE_RELATIONSHIPS_SQL };