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.
- package/README.md +18 -9
- package/dist/_chunks/{env-4WGRW2nw.js → env-BNm69Qh8.js} +2 -5
- package/dist/commands/config.js +11 -28
- package/dist/commands/dev.js +93 -27
- package/dist/commands/env.js +2 -3
- package/dist/commands/init.js +1 -2
- package/dist/commands/link.js +1 -1
- package/dist/commands/manifest.js +1 -3
- package/dist/commands/subscribe.js +16 -16
- package/dist/credential_io.js +1 -2
- package/dist/dev/env.js +1 -2
- package/dist/dev/runtime.js +8 -0
- package/dist/env_file.js +9 -1
- package/dist/index.js +1 -1
- package/dist/init/auth.js +1 -4
- package/dist/init/choices.js +21 -7
- package/dist/init/copy.js +21 -7
- package/dist/init/run.js +25 -16
- package/dist/plugins/run.js +2 -1
- package/dist/psql/command/cmd_io.js +1 -2
- package/dist/psql/command/cmd_pipeline.js +1 -2
- package/dist/psql/core/common.js +1 -2
- package/dist/psql/core/startup.js +1 -2
- package/dist/psql/index.js +1 -2
- package/dist/psql/types/index.js +1 -2
- package/dist/skills/catalog.js +5 -0
- package/dist/utils/hooks.js +0 -2
- package/dist/utils/staging.js +1 -14
- package/{LICENSE → dist/vendor/postgres-meta/LICENSE} +0 -1
- package/dist/vendor/postgres-meta/constants.js +14 -0
- package/dist/vendor/postgres-meta/lib/PostgresMeta.js +49 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaColumnPrivileges.js +85 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaColumns.js +235 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaConfig.js +16 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaExtensions.js +79 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaForeignTables.js +81 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaFunctions.js +173 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaIndexes.js +42 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaMaterializedViews.js +84 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaPolicies.js +120 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaPublications.js +193 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaRelationships.js +87 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaRoles.js +203 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaSchemas.js +105 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaTablePrivileges.js +91 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaTables.js +183 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaTriggers.js +156 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaTypes.js +22 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaVersion.js +20 -0
- package/dist/vendor/postgres-meta/lib/PostgresMetaViews.js +83 -0
- package/dist/vendor/postgres-meta/lib/constants.js +8 -0
- package/dist/vendor/postgres-meta/lib/db.js +147 -0
- package/dist/vendor/postgres-meta/lib/generators.js +106 -0
- package/dist/vendor/postgres-meta/lib/helpers.js +26 -0
- package/dist/vendor/postgres-meta/lib/index.js +1 -0
- package/dist/vendor/postgres-meta/lib/sql/column_privileges.sql.js +154 -0
- package/dist/vendor/postgres-meta/lib/sql/columns.sql.js +123 -0
- package/dist/vendor/postgres-meta/lib/sql/common.js +1 -0
- package/dist/vendor/postgres-meta/lib/sql/config.sql.js +32 -0
- package/dist/vendor/postgres-meta/lib/sql/extensions.sql.js +20 -0
- package/dist/vendor/postgres-meta/lib/sql/foreign_tables.sql.js +20 -0
- package/dist/vendor/postgres-meta/lib/sql/functions.sql.js +141 -0
- package/dist/vendor/postgres-meta/lib/sql/indexes.sql.js +51 -0
- package/dist/vendor/postgres-meta/lib/sql/materialized_views.sql.js +21 -0
- package/dist/vendor/postgres-meta/lib/sql/policies.sql.js +53 -0
- package/dist/vendor/postgres-meta/lib/sql/publications.sql.js +46 -0
- package/dist/vendor/postgres-meta/lib/sql/roles.sql.js +40 -0
- package/dist/vendor/postgres-meta/lib/sql/schemas.sql.js +26 -0
- package/dist/vendor/postgres-meta/lib/sql/table.sql.js +109 -0
- package/dist/vendor/postgres-meta/lib/sql/table_privileges.sql.js +85 -0
- package/dist/vendor/postgres-meta/lib/sql/table_relationships.sql.js +52 -0
- package/dist/vendor/postgres-meta/lib/sql/triggers.sql.js +64 -0
- package/dist/vendor/postgres-meta/lib/sql/types.sql.js +65 -0
- package/dist/vendor/postgres-meta/lib/sql/version.sql.js +15 -0
- package/dist/vendor/postgres-meta/lib/sql/views.sql.js +22 -0
- package/dist/vendor/postgres-meta/lib/sql/views_key_dependencies.sql.js +198 -0
- package/dist/vendor/postgres-meta/lib/types.js +1 -0
- package/dist/vendor/postgres-meta/templates/typescript.js +608 -0
- package/package.json +12 -5
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { coalesceRowsToArray, filterByList, filterByValue } from "./helpers.js";
|
|
2
|
+
import { COLUMNS_SQL } from "./sql/columns.sql.js";
|
|
3
|
+
import { MATERIALIZED_VIEWS_SQL } from "./sql/materialized_views.sql.js";
|
|
4
|
+
//#region src/vendor/postgres-meta/lib/PostgresMetaMaterializedViews.ts
|
|
5
|
+
var PostgresMetaMaterializedViews = class {
|
|
6
|
+
constructor(query) {
|
|
7
|
+
this.query = query;
|
|
8
|
+
}
|
|
9
|
+
async list({ includedSchemas, excludedSchemas, limit, offset, includeColumns = false } = {}) {
|
|
10
|
+
const schemaFilter = filterByList(includedSchemas, excludedSchemas, void 0);
|
|
11
|
+
let sql = generateEnrichedMaterializedViewsSql({
|
|
12
|
+
includeColumns,
|
|
13
|
+
schemaFilter,
|
|
14
|
+
limit,
|
|
15
|
+
offset
|
|
16
|
+
});
|
|
17
|
+
return await this.query(sql);
|
|
18
|
+
}
|
|
19
|
+
async retrieve({ id, name, schema = "public" }) {
|
|
20
|
+
if (id) {
|
|
21
|
+
const idsFilter = filterByValue([id]);
|
|
22
|
+
const sql = generateEnrichedMaterializedViewsSql({
|
|
23
|
+
includeColumns: true,
|
|
24
|
+
idsFilter
|
|
25
|
+
});
|
|
26
|
+
const { data, error } = await this.query(sql);
|
|
27
|
+
if (error) return {
|
|
28
|
+
data,
|
|
29
|
+
error
|
|
30
|
+
};
|
|
31
|
+
else if (data.length === 0) return {
|
|
32
|
+
data: null,
|
|
33
|
+
error: { message: `Cannot find a materialized view with ID ${id}` }
|
|
34
|
+
};
|
|
35
|
+
else return {
|
|
36
|
+
data: data[0],
|
|
37
|
+
error
|
|
38
|
+
};
|
|
39
|
+
} else if (name) {
|
|
40
|
+
const materializedViewIdentifierFilter = filterByValue([`${schema}.${name}`]);
|
|
41
|
+
const sql = generateEnrichedMaterializedViewsSql({
|
|
42
|
+
includeColumns: true,
|
|
43
|
+
materializedViewIdentifierFilter
|
|
44
|
+
});
|
|
45
|
+
const { data, error } = await this.query(sql);
|
|
46
|
+
if (error) return {
|
|
47
|
+
data,
|
|
48
|
+
error
|
|
49
|
+
};
|
|
50
|
+
else if (data.length === 0) return {
|
|
51
|
+
data: null,
|
|
52
|
+
error: { message: `Cannot find a materialized view named ${name} in schema ${schema}` }
|
|
53
|
+
};
|
|
54
|
+
else return {
|
|
55
|
+
data: data[0],
|
|
56
|
+
error
|
|
57
|
+
};
|
|
58
|
+
} else return {
|
|
59
|
+
data: null,
|
|
60
|
+
error: { message: "Invalid parameters on materialized view retrieve" }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const generateEnrichedMaterializedViewsSql = ({ includeColumns, schemaFilter, materializedViewIdentifierFilter, idsFilter, limit, offset }) => `
|
|
65
|
+
with materialized_views as (${MATERIALIZED_VIEWS_SQL({
|
|
66
|
+
schemaFilter,
|
|
67
|
+
limit,
|
|
68
|
+
offset,
|
|
69
|
+
materializedViewIdentifierFilter,
|
|
70
|
+
idsFilter
|
|
71
|
+
})})
|
|
72
|
+
${includeColumns ? `, columns as (${COLUMNS_SQL({
|
|
73
|
+
schemaFilter,
|
|
74
|
+
limit,
|
|
75
|
+
offset,
|
|
76
|
+
tableIdentifierFilter: materializedViewIdentifierFilter,
|
|
77
|
+
tableIdFilter: idsFilter
|
|
78
|
+
})})` : ""}
|
|
79
|
+
select
|
|
80
|
+
*
|
|
81
|
+
${includeColumns ? `, ${coalesceRowsToArray("columns", "columns.table_id = materialized_views.id")}` : ""}
|
|
82
|
+
from materialized_views`;
|
|
83
|
+
//#endregion
|
|
84
|
+
export { PostgresMetaMaterializedViews as default };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { DEFAULT_SYSTEM_SCHEMAS } from "./constants.js";
|
|
2
|
+
import { filterByList, filterByValue } from "./helpers.js";
|
|
3
|
+
import { POLICIES_SQL } from "./sql/policies.sql.js";
|
|
4
|
+
import { ident } from "pg-format";
|
|
5
|
+
//#region src/vendor/postgres-meta/lib/PostgresMetaPolicies.ts
|
|
6
|
+
var PostgresMetaPolicies = class {
|
|
7
|
+
constructor(query) {
|
|
8
|
+
this.query = query;
|
|
9
|
+
}
|
|
10
|
+
async list({ includeSystemSchemas = false, includedSchemas, excludedSchemas, limit, offset } = {}) {
|
|
11
|
+
const schemaFilter = filterByList(includedSchemas, excludedSchemas, !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : void 0);
|
|
12
|
+
let sql = POLICIES_SQL({
|
|
13
|
+
schemaFilter,
|
|
14
|
+
limit,
|
|
15
|
+
offset
|
|
16
|
+
});
|
|
17
|
+
return await this.query(sql);
|
|
18
|
+
}
|
|
19
|
+
async retrieve({ id, name, table, schema = "public" }) {
|
|
20
|
+
const schemaFilter = schema ? filterByList([schema], []) : void 0;
|
|
21
|
+
if (id) {
|
|
22
|
+
const idsFilter = filterByValue([`${id}`]);
|
|
23
|
+
const sql = POLICIES_SQL({ idsFilter });
|
|
24
|
+
const { data, error } = await this.query(sql);
|
|
25
|
+
if (error) return {
|
|
26
|
+
data,
|
|
27
|
+
error
|
|
28
|
+
};
|
|
29
|
+
else if (data.length === 0) return {
|
|
30
|
+
data: null,
|
|
31
|
+
error: { message: `Cannot find a policy with ID ${id}` }
|
|
32
|
+
};
|
|
33
|
+
else return {
|
|
34
|
+
data: data[0],
|
|
35
|
+
error
|
|
36
|
+
};
|
|
37
|
+
} else if (name && table) {
|
|
38
|
+
const functionNameIdentifierFilter = filterByValue([`${table}.${name}`]);
|
|
39
|
+
const sql = POLICIES_SQL({
|
|
40
|
+
schemaFilter,
|
|
41
|
+
functionNameIdentifierFilter
|
|
42
|
+
});
|
|
43
|
+
const { data, error } = await this.query(sql);
|
|
44
|
+
if (error) return {
|
|
45
|
+
data,
|
|
46
|
+
error
|
|
47
|
+
};
|
|
48
|
+
else if (data.length === 0) return {
|
|
49
|
+
data: null,
|
|
50
|
+
error: { message: `Cannot find a policy named ${name} for table ${schema}.${table}` }
|
|
51
|
+
};
|
|
52
|
+
else return {
|
|
53
|
+
data: data[0],
|
|
54
|
+
error
|
|
55
|
+
};
|
|
56
|
+
} else return {
|
|
57
|
+
data: null,
|
|
58
|
+
error: { message: "Invalid parameters on policy retrieve" }
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async create({ name, table, schema = "public", definition, check, action = "PERMISSIVE", command = "ALL", roles = ["public"] }) {
|
|
62
|
+
const definitionClause = definition === void 0 ? "" : `USING (${definition})`;
|
|
63
|
+
const checkClause = check === void 0 ? "" : `WITH CHECK (${check})`;
|
|
64
|
+
const sql = `
|
|
65
|
+
CREATE POLICY ${ident(name)} ON ${ident(schema)}.${ident(table)}
|
|
66
|
+
AS ${action}
|
|
67
|
+
FOR ${command}
|
|
68
|
+
TO ${roles.map(ident).join(",")}
|
|
69
|
+
${definitionClause} ${checkClause};`;
|
|
70
|
+
const { error } = await this.query(sql);
|
|
71
|
+
if (error) return {
|
|
72
|
+
data: null,
|
|
73
|
+
error
|
|
74
|
+
};
|
|
75
|
+
return await this.retrieve({
|
|
76
|
+
name,
|
|
77
|
+
table,
|
|
78
|
+
schema
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async update(id, { name, definition, check, roles }) {
|
|
82
|
+
const { data: old, error } = await this.retrieve({ id });
|
|
83
|
+
if (error) return {
|
|
84
|
+
data: null,
|
|
85
|
+
error
|
|
86
|
+
};
|
|
87
|
+
const alter = `ALTER POLICY ${ident(old.name)} ON ${ident(old.schema)}.${ident(old.table)}`;
|
|
88
|
+
const nameSql = name === void 0 ? "" : `${alter} RENAME TO ${ident(name)};`;
|
|
89
|
+
const sql = `BEGIN; ${definition === void 0 ? "" : `${alter} USING (${definition});`} ${check === void 0 ? "" : `${alter} WITH CHECK (${check});`} ${roles === void 0 ? "" : `${alter} TO ${roles.map(ident).join(",")};`} ${nameSql} COMMIT;`;
|
|
90
|
+
{
|
|
91
|
+
const { error } = await this.query(sql);
|
|
92
|
+
if (error) return {
|
|
93
|
+
data: null,
|
|
94
|
+
error
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return await this.retrieve({ id });
|
|
98
|
+
}
|
|
99
|
+
async remove(id) {
|
|
100
|
+
const { data: policy, error } = await this.retrieve({ id });
|
|
101
|
+
if (error) return {
|
|
102
|
+
data: null,
|
|
103
|
+
error
|
|
104
|
+
};
|
|
105
|
+
const sql = `DROP POLICY ${ident(policy.name)} ON ${ident(policy.schema)}.${ident(policy.table)};`;
|
|
106
|
+
{
|
|
107
|
+
const { error } = await this.query(sql);
|
|
108
|
+
if (error) return {
|
|
109
|
+
data: null,
|
|
110
|
+
error
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
data: policy,
|
|
115
|
+
error: null
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
//#endregion
|
|
120
|
+
export { PostgresMetaPolicies as default };
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { filterByValue } from "./helpers.js";
|
|
2
|
+
import { PUBLICATIONS_SQL } from "./sql/publications.sql.js";
|
|
3
|
+
import { ident, literal } from "pg-format";
|
|
4
|
+
//#region src/vendor/postgres-meta/lib/PostgresMetaPublications.ts
|
|
5
|
+
var PostgresMetaPublications = class {
|
|
6
|
+
constructor(query) {
|
|
7
|
+
this.query = query;
|
|
8
|
+
}
|
|
9
|
+
async list({ limit, offset }) {
|
|
10
|
+
let sql = PUBLICATIONS_SQL({
|
|
11
|
+
limit,
|
|
12
|
+
offset
|
|
13
|
+
});
|
|
14
|
+
return await this.query(sql);
|
|
15
|
+
}
|
|
16
|
+
async retrieve({ id, name }) {
|
|
17
|
+
if (id) {
|
|
18
|
+
const idsFilter = filterByValue([id]);
|
|
19
|
+
const sql = PUBLICATIONS_SQL({ idsFilter });
|
|
20
|
+
const { data, error } = await this.query(sql);
|
|
21
|
+
if (error) return {
|
|
22
|
+
data,
|
|
23
|
+
error
|
|
24
|
+
};
|
|
25
|
+
else if (data.length === 0) return {
|
|
26
|
+
data: null,
|
|
27
|
+
error: { message: `Cannot find a publication with ID ${id}` }
|
|
28
|
+
};
|
|
29
|
+
else return {
|
|
30
|
+
data: data[0],
|
|
31
|
+
error
|
|
32
|
+
};
|
|
33
|
+
} else if (name) {
|
|
34
|
+
const nameFilter = filterByValue([name]);
|
|
35
|
+
const sql = PUBLICATIONS_SQL({ nameFilter });
|
|
36
|
+
const { data, error } = await this.query(sql);
|
|
37
|
+
if (error) return {
|
|
38
|
+
data,
|
|
39
|
+
error
|
|
40
|
+
};
|
|
41
|
+
else if (data.length === 0) return {
|
|
42
|
+
data: null,
|
|
43
|
+
error: { message: `Cannot find a publication named ${name}` }
|
|
44
|
+
};
|
|
45
|
+
else return {
|
|
46
|
+
data: data[0],
|
|
47
|
+
error
|
|
48
|
+
};
|
|
49
|
+
} else return {
|
|
50
|
+
data: null,
|
|
51
|
+
error: { message: "Invalid parameters on publication retrieve" }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async create({ name, publish_insert = false, publish_update = false, publish_delete = false, publish_truncate = false, tables = null }) {
|
|
55
|
+
let tableClause;
|
|
56
|
+
if (tables === void 0 || tables === null) tableClause = "FOR ALL TABLES";
|
|
57
|
+
else if (tables.length === 0) tableClause = "";
|
|
58
|
+
else tableClause = `FOR TABLE ${tables.map((t) => {
|
|
59
|
+
if (!t.includes(".")) return ident(t);
|
|
60
|
+
const [schema, ...rest] = t.split(".");
|
|
61
|
+
const table = rest.join(".");
|
|
62
|
+
return `${ident(schema)}.${ident(table)}`;
|
|
63
|
+
}).join(",")}`;
|
|
64
|
+
let publishOps = [];
|
|
65
|
+
if (publish_insert) publishOps.push("insert");
|
|
66
|
+
if (publish_update) publishOps.push("update");
|
|
67
|
+
if (publish_delete) publishOps.push("delete");
|
|
68
|
+
if (publish_truncate) publishOps.push("truncate");
|
|
69
|
+
const sql = `
|
|
70
|
+
CREATE PUBLICATION ${ident(name)} ${tableClause}
|
|
71
|
+
WITH (publish = '${publishOps.join(",")}');`;
|
|
72
|
+
const { error } = await this.query(sql);
|
|
73
|
+
if (error) return {
|
|
74
|
+
data: null,
|
|
75
|
+
error
|
|
76
|
+
};
|
|
77
|
+
return await this.retrieve({ name });
|
|
78
|
+
}
|
|
79
|
+
async update(id, { name, owner, publish_insert, publish_update, publish_delete, publish_truncate, tables }) {
|
|
80
|
+
const sql = `
|
|
81
|
+
do $$
|
|
82
|
+
declare
|
|
83
|
+
id oid := ${literal(id)};
|
|
84
|
+
old record;
|
|
85
|
+
new_name text := ${name === void 0 ? null : literal(name)};
|
|
86
|
+
new_owner text := ${owner === void 0 ? null : literal(owner)};
|
|
87
|
+
new_publish_insert bool := ${publish_insert ?? null};
|
|
88
|
+
new_publish_update bool := ${publish_update ?? null};
|
|
89
|
+
new_publish_delete bool := ${publish_delete ?? null};
|
|
90
|
+
new_publish_truncate bool := ${publish_truncate ?? null};
|
|
91
|
+
new_tables text := ${tables === void 0 ? null : literal(tables === null ? "all tables" : tables.map((t) => {
|
|
92
|
+
if (!t.includes(".")) return ident(t);
|
|
93
|
+
const [schema, ...rest] = t.split(".");
|
|
94
|
+
const table = rest.join(".");
|
|
95
|
+
return `${ident(schema)}.${ident(table)}`;
|
|
96
|
+
}).join(","))};
|
|
97
|
+
begin
|
|
98
|
+
select * into old from pg_publication where oid = id;
|
|
99
|
+
if old is null then
|
|
100
|
+
raise exception 'Cannot find publication with id %', id;
|
|
101
|
+
end if;
|
|
102
|
+
|
|
103
|
+
if new_tables is null then
|
|
104
|
+
null;
|
|
105
|
+
elsif new_tables = 'all tables' then
|
|
106
|
+
if old.puballtables then
|
|
107
|
+
null;
|
|
108
|
+
else
|
|
109
|
+
-- Need to recreate because going from list of tables <-> all tables with alter is not possible.
|
|
110
|
+
execute(format('drop publication %1$I; create publication %1$I for all tables;', old.pubname));
|
|
111
|
+
end if;
|
|
112
|
+
else
|
|
113
|
+
if old.puballtables then
|
|
114
|
+
-- Need to recreate because going from list of tables <-> all tables with alter is not possible.
|
|
115
|
+
execute(format('drop publication %1$I; create publication %1$I;', old.pubname));
|
|
116
|
+
elsif exists(select from pg_publication_rel where prpubid = id) then
|
|
117
|
+
execute(
|
|
118
|
+
format(
|
|
119
|
+
'alter publication %I drop table %s',
|
|
120
|
+
old.pubname,
|
|
121
|
+
(select string_agg(prrelid::regclass::text, ', ') from pg_publication_rel where prpubid = id)
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
end if;
|
|
125
|
+
|
|
126
|
+
-- At this point the publication must have no tables.
|
|
127
|
+
|
|
128
|
+
if new_tables != '' then
|
|
129
|
+
execute(format('alter publication %I add table %s', old.pubname, new_tables));
|
|
130
|
+
end if;
|
|
131
|
+
end if;
|
|
132
|
+
|
|
133
|
+
execute(
|
|
134
|
+
format(
|
|
135
|
+
'alter publication %I set (publish = %L);',
|
|
136
|
+
old.pubname,
|
|
137
|
+
concat_ws(
|
|
138
|
+
', ',
|
|
139
|
+
case when coalesce(new_publish_insert, old.pubinsert) then 'insert' end,
|
|
140
|
+
case when coalesce(new_publish_update, old.pubupdate) then 'update' end,
|
|
141
|
+
case when coalesce(new_publish_delete, old.pubdelete) then 'delete' end,
|
|
142
|
+
case when coalesce(new_publish_truncate, old.pubtruncate) then 'truncate' end
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
execute(format('alter publication %I owner to %I;', old.pubname, coalesce(new_owner, old.pubowner::regrole::name)));
|
|
148
|
+
|
|
149
|
+
-- Using the same name in the rename clause gives an error, so only do it if the new name is different.
|
|
150
|
+
if new_name is not null and new_name != old.pubname then
|
|
151
|
+
execute(format('alter publication %I rename to %I;', old.pubname, coalesce(new_name, old.pubname)));
|
|
152
|
+
end if;
|
|
153
|
+
|
|
154
|
+
-- We need to retrieve the publication later, so we need a way to uniquely identify which publication this is.
|
|
155
|
+
-- We can't rely on id because it gets changed if it got recreated.
|
|
156
|
+
-- We use a temp table to store the unique name - DO blocks can't return a value.
|
|
157
|
+
create temp table pg_meta_publication_tmp (name) on commit drop as values (coalesce(new_name, old.pubname));
|
|
158
|
+
end $$;
|
|
159
|
+
|
|
160
|
+
with publications as (${PUBLICATIONS_SQL({})}) select * from publications where name = (select name from pg_meta_publication_tmp);
|
|
161
|
+
`;
|
|
162
|
+
const { data, error } = await this.query(sql);
|
|
163
|
+
if (error) return {
|
|
164
|
+
data: null,
|
|
165
|
+
error
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
data: data[0],
|
|
169
|
+
error
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async remove(id) {
|
|
173
|
+
const { data: publication, error } = await this.retrieve({ id });
|
|
174
|
+
if (error) return {
|
|
175
|
+
data: null,
|
|
176
|
+
error
|
|
177
|
+
};
|
|
178
|
+
const sql = `DROP PUBLICATION IF EXISTS ${ident(publication.name)};`;
|
|
179
|
+
{
|
|
180
|
+
const { error } = await this.query(sql);
|
|
181
|
+
if (error) return {
|
|
182
|
+
data: null,
|
|
183
|
+
error
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
data: publication,
|
|
188
|
+
error: null
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
//#endregion
|
|
193
|
+
export { PostgresMetaPublications as default };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { DEFAULT_SYSTEM_SCHEMAS } from "./constants.js";
|
|
2
|
+
import { filterByList } from "./helpers.js";
|
|
3
|
+
import { TABLE_RELATIONSHIPS_SQL } from "./sql/table_relationships.sql.js";
|
|
4
|
+
import { VIEWS_KEY_DEPENDENCIES_SQL } from "./sql/views_key_dependencies.sql.js";
|
|
5
|
+
//#region src/vendor/postgres-meta/lib/PostgresMetaRelationships.ts
|
|
6
|
+
var PostgresMetaRelationships = class {
|
|
7
|
+
constructor(query) {
|
|
8
|
+
this.query = query;
|
|
9
|
+
}
|
|
10
|
+
async list({ includeSystemSchemas = false, includedSchemas, excludedSchemas } = {}) {
|
|
11
|
+
const schemaFilter = filterByList(includedSchemas, excludedSchemas, !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : void 0);
|
|
12
|
+
let allTableM2oAndO2oRelationships;
|
|
13
|
+
{
|
|
14
|
+
const sql = TABLE_RELATIONSHIPS_SQL({ schemaFilter });
|
|
15
|
+
const { data, error } = await this.query(sql);
|
|
16
|
+
if (error) return {
|
|
17
|
+
data: null,
|
|
18
|
+
error
|
|
19
|
+
};
|
|
20
|
+
allTableM2oAndO2oRelationships = data;
|
|
21
|
+
}
|
|
22
|
+
let allViewM2oAndO2oRelationships;
|
|
23
|
+
{
|
|
24
|
+
const viewsKeyDependenciesSql = VIEWS_KEY_DEPENDENCIES_SQL({ schemaFilter });
|
|
25
|
+
const { data: viewsKeyDependencies, error } = await this.query(viewsKeyDependenciesSql);
|
|
26
|
+
if (error) return {
|
|
27
|
+
data: null,
|
|
28
|
+
error
|
|
29
|
+
};
|
|
30
|
+
allViewM2oAndO2oRelationships = allTableM2oAndO2oRelationships.flatMap((r) => {
|
|
31
|
+
const expandKeyDepCols = (colDeps) => {
|
|
32
|
+
const tableColumns = colDeps.map(({ table_column }) => table_column);
|
|
33
|
+
const cartesianProduct = (allEntries) => {
|
|
34
|
+
return allEntries.reduce((results, entries) => results.map((result) => entries.map((entry) => result.concat(entry))).reduce((subResults, result) => subResults.concat(result), []), [[]]);
|
|
35
|
+
};
|
|
36
|
+
return cartesianProduct(colDeps.map((cd) => cd.view_columns)).map((viewColumns) => ({
|
|
37
|
+
tableColumns,
|
|
38
|
+
viewColumns
|
|
39
|
+
}));
|
|
40
|
+
};
|
|
41
|
+
const viewToTableKeyDeps = viewsKeyDependencies.filter((vkd) => vkd.table_schema === r.schema && vkd.table_name === r.relation && vkd.constraint_name === r.foreign_key_name && vkd.constraint_type === "f");
|
|
42
|
+
const tableToViewKeyDeps = viewsKeyDependencies.filter((vkd) => vkd.table_schema === r.referenced_schema && vkd.table_name === r.referenced_relation && vkd.constraint_name === r.foreign_key_name && vkd.constraint_type === "f_ref");
|
|
43
|
+
const viewToTableRelationships = viewToTableKeyDeps.flatMap((vtkd) => expandKeyDepCols(vtkd.column_dependencies).map(({ viewColumns }) => ({
|
|
44
|
+
foreign_key_name: r.foreign_key_name,
|
|
45
|
+
schema: vtkd.view_schema,
|
|
46
|
+
relation: vtkd.view_name,
|
|
47
|
+
columns: viewColumns,
|
|
48
|
+
is_one_to_one: r.is_one_to_one,
|
|
49
|
+
referenced_schema: r.referenced_schema,
|
|
50
|
+
referenced_relation: r.referenced_relation,
|
|
51
|
+
referenced_columns: r.referenced_columns
|
|
52
|
+
})));
|
|
53
|
+
const tableToViewRelationships = tableToViewKeyDeps.flatMap((tvkd) => expandKeyDepCols(tvkd.column_dependencies).map(({ viewColumns }) => ({
|
|
54
|
+
foreign_key_name: r.foreign_key_name,
|
|
55
|
+
schema: r.schema,
|
|
56
|
+
relation: r.relation,
|
|
57
|
+
columns: r.columns,
|
|
58
|
+
is_one_to_one: r.is_one_to_one,
|
|
59
|
+
referenced_schema: tvkd.view_schema,
|
|
60
|
+
referenced_relation: tvkd.view_name,
|
|
61
|
+
referenced_columns: viewColumns
|
|
62
|
+
})));
|
|
63
|
+
const viewToViewRelationships = viewToTableKeyDeps.flatMap((vtkd) => expandKeyDepCols(vtkd.column_dependencies).flatMap(({ viewColumns }) => tableToViewKeyDeps.flatMap((tvkd) => expandKeyDepCols(tvkd.column_dependencies).map(({ viewColumns: referencedViewColumns }) => ({
|
|
64
|
+
foreign_key_name: r.foreign_key_name,
|
|
65
|
+
schema: vtkd.view_schema,
|
|
66
|
+
relation: vtkd.view_name,
|
|
67
|
+
columns: viewColumns,
|
|
68
|
+
is_one_to_one: r.is_one_to_one,
|
|
69
|
+
referenced_schema: tvkd.view_schema,
|
|
70
|
+
referenced_relation: tvkd.view_name,
|
|
71
|
+
referenced_columns: referencedViewColumns
|
|
72
|
+
})))));
|
|
73
|
+
return [
|
|
74
|
+
...viewToTableRelationships,
|
|
75
|
+
...tableToViewRelationships,
|
|
76
|
+
...viewToViewRelationships
|
|
77
|
+
];
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
data: allTableM2oAndO2oRelationships.concat(allViewM2oAndO2oRelationships),
|
|
82
|
+
error: null
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
export { PostgresMetaRelationships as default };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { filterByValue } from "./helpers.js";
|
|
2
|
+
import { ROLES_SQL } from "./sql/roles.sql.js";
|
|
3
|
+
import { ident, literal } from "pg-format";
|
|
4
|
+
//#region src/vendor/postgres-meta/lib/PostgresMetaRoles.ts
|
|
5
|
+
function changeRoleConfig2Object(config) {
|
|
6
|
+
if (!config) return null;
|
|
7
|
+
return config.reduce((acc, cur) => {
|
|
8
|
+
const [key, value] = cur.split("=");
|
|
9
|
+
acc[key] = value;
|
|
10
|
+
return acc;
|
|
11
|
+
}, {});
|
|
12
|
+
}
|
|
13
|
+
var PostgresMetaRoles = class {
|
|
14
|
+
constructor(query) {
|
|
15
|
+
this.query = query;
|
|
16
|
+
}
|
|
17
|
+
async list({ includeDefaultRoles = false, limit, offset } = {}) {
|
|
18
|
+
const sql = ROLES_SQL({
|
|
19
|
+
limit,
|
|
20
|
+
offset,
|
|
21
|
+
includeDefaultRoles
|
|
22
|
+
});
|
|
23
|
+
const result = await this.query(sql);
|
|
24
|
+
if (result.data) result.data = result.data.map((role) => {
|
|
25
|
+
role.config = changeRoleConfig2Object(role.config);
|
|
26
|
+
return role;
|
|
27
|
+
});
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
async retrieve({ id, name }) {
|
|
31
|
+
if (id) {
|
|
32
|
+
const idsFilter = filterByValue([id]);
|
|
33
|
+
const sql = ROLES_SQL({ idsFilter });
|
|
34
|
+
const { data, error } = await this.query(sql);
|
|
35
|
+
if (error) return {
|
|
36
|
+
data,
|
|
37
|
+
error
|
|
38
|
+
};
|
|
39
|
+
else if (data.length === 0) return {
|
|
40
|
+
data: null,
|
|
41
|
+
error: { message: `Cannot find a role with ID ${id}` }
|
|
42
|
+
};
|
|
43
|
+
else {
|
|
44
|
+
data[0].config = changeRoleConfig2Object(data[0].config);
|
|
45
|
+
return {
|
|
46
|
+
data: data[0],
|
|
47
|
+
error
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
} else if (name) {
|
|
51
|
+
const nameFilter = filterByValue([name]);
|
|
52
|
+
const sql = ROLES_SQL({ nameFilter });
|
|
53
|
+
const { data, error } = await this.query(sql);
|
|
54
|
+
if (error) return {
|
|
55
|
+
data,
|
|
56
|
+
error
|
|
57
|
+
};
|
|
58
|
+
else if (data.length === 0) return {
|
|
59
|
+
data: null,
|
|
60
|
+
error: { message: `Cannot find a role named ${name}` }
|
|
61
|
+
};
|
|
62
|
+
else {
|
|
63
|
+
data[0].config = changeRoleConfig2Object(data[0].config);
|
|
64
|
+
return {
|
|
65
|
+
data: data[0],
|
|
66
|
+
error
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
} else return {
|
|
70
|
+
data: null,
|
|
71
|
+
error: { message: "Invalid parameters on role retrieve" }
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async create({ name, is_superuser = false, can_create_db = false, can_create_role = false, inherit_role = true, can_login = false, is_replication_role = false, can_bypass_rls = false, connection_limit = -1, password, valid_until, member_of, members, admins, config }) {
|
|
75
|
+
const isSuperuserClause = is_superuser ? "SUPERUSER" : "NOSUPERUSER";
|
|
76
|
+
const canCreateDbClause = can_create_db ? "CREATEDB" : "NOCREATEDB";
|
|
77
|
+
const canCreateRoleClause = can_create_role ? "CREATEROLE" : "NOCREATEROLE";
|
|
78
|
+
const inheritRoleClause = inherit_role ? "INHERIT" : "NOINHERIT";
|
|
79
|
+
const canLoginClause = can_login ? "LOGIN" : "NOLOGIN";
|
|
80
|
+
const isReplicationRoleClause = is_replication_role ? "REPLICATION" : "NOREPLICATION";
|
|
81
|
+
const canBypassRlsClause = can_bypass_rls ? "BYPASSRLS" : "NOBYPASSRLS";
|
|
82
|
+
const connectionLimitClause = `CONNECTION LIMIT ${connection_limit}`;
|
|
83
|
+
const passwordClause = password === void 0 ? "" : `PASSWORD ${literal(password)}`;
|
|
84
|
+
const validUntilClause = valid_until === void 0 ? "" : `VALID UNTIL ${literal(valid_until)}`;
|
|
85
|
+
const memberOfClause = member_of === void 0 ? "" : `IN ROLE ${member_of.join(",")}`;
|
|
86
|
+
const membersClause = members === void 0 ? "" : `ROLE ${members.join(",")}`;
|
|
87
|
+
const adminsClause = admins === void 0 ? "" : `ADMIN ${admins.join(",")}`;
|
|
88
|
+
let configClause = "";
|
|
89
|
+
if (config !== void 0) configClause = Object.keys(config).map((k) => {
|
|
90
|
+
const v = config[k];
|
|
91
|
+
if (!k || !v) return "";
|
|
92
|
+
return `ALTER ROLE ${name} SET ${k} = ${v};`;
|
|
93
|
+
}).join("\n");
|
|
94
|
+
const sql = `
|
|
95
|
+
BEGIN;
|
|
96
|
+
CREATE ROLE ${ident(name)}
|
|
97
|
+
WITH
|
|
98
|
+
${isSuperuserClause}
|
|
99
|
+
${canCreateDbClause}
|
|
100
|
+
${canCreateRoleClause}
|
|
101
|
+
${inheritRoleClause}
|
|
102
|
+
${canLoginClause}
|
|
103
|
+
${isReplicationRoleClause}
|
|
104
|
+
${canBypassRlsClause}
|
|
105
|
+
${connectionLimitClause}
|
|
106
|
+
${passwordClause}
|
|
107
|
+
${validUntilClause}
|
|
108
|
+
${memberOfClause}
|
|
109
|
+
${membersClause}
|
|
110
|
+
${adminsClause};
|
|
111
|
+
${configClause ? configClause : ""}
|
|
112
|
+
COMMIT;`;
|
|
113
|
+
const { error } = await this.query(sql);
|
|
114
|
+
if (error) return {
|
|
115
|
+
data: null,
|
|
116
|
+
error
|
|
117
|
+
};
|
|
118
|
+
return await this.retrieve({ name });
|
|
119
|
+
}
|
|
120
|
+
async update(id, { name, is_superuser, can_create_db, can_create_role, inherit_role, can_login, is_replication_role, can_bypass_rls, connection_limit, password, valid_until, config }) {
|
|
121
|
+
const { data: old, error } = await this.retrieve({ id });
|
|
122
|
+
if (error) return {
|
|
123
|
+
data: null,
|
|
124
|
+
error
|
|
125
|
+
};
|
|
126
|
+
const nameSql = name === void 0 ? "" : `ALTER ROLE ${ident(old.name)} RENAME TO ${ident(name)};`;
|
|
127
|
+
let isSuperuserClause = "";
|
|
128
|
+
if (is_superuser !== void 0) isSuperuserClause = is_superuser ? "SUPERUSER" : "NOSUPERUSER";
|
|
129
|
+
let canCreateDbClause = "";
|
|
130
|
+
if (can_create_db !== void 0) canCreateDbClause = can_create_db ? "CREATEDB" : "NOCREATEDB";
|
|
131
|
+
let canCreateRoleClause = "";
|
|
132
|
+
if (can_create_role !== void 0) canCreateRoleClause = can_create_role ? "CREATEROLE" : "NOCREATEROLE";
|
|
133
|
+
let inheritRoleClause = "";
|
|
134
|
+
if (inherit_role !== void 0) inheritRoleClause = inherit_role ? "INHERIT" : "NOINHERIT";
|
|
135
|
+
let canLoginClause = "";
|
|
136
|
+
if (can_login !== void 0) canLoginClause = can_login ? "LOGIN" : "NOLOGIN";
|
|
137
|
+
let isReplicationRoleClause = "";
|
|
138
|
+
if (is_replication_role !== void 0) isReplicationRoleClause = is_replication_role ? "REPLICATION" : "NOREPLICATION";
|
|
139
|
+
let canBypassRlsClause = "";
|
|
140
|
+
if (can_bypass_rls !== void 0) canBypassRlsClause = can_bypass_rls ? "BYPASSRLS" : "NOBYPASSRLS";
|
|
141
|
+
const connectionLimitClause = connection_limit === void 0 ? "" : `CONNECTION LIMIT ${connection_limit}`;
|
|
142
|
+
const passwordClause = password === void 0 ? "" : `PASSWORD ${literal(password)}`;
|
|
143
|
+
const validUntilClause = valid_until === void 0 ? "" : `VALID UNTIL ${literal(valid_until)}`;
|
|
144
|
+
let configClause = "";
|
|
145
|
+
if (config !== void 0) configClause = config.map((c) => {
|
|
146
|
+
const { op, path, value } = c;
|
|
147
|
+
const k = path;
|
|
148
|
+
const v = value || null;
|
|
149
|
+
if (!k) throw new Error(`Invalid config value ${value}`);
|
|
150
|
+
switch (op) {
|
|
151
|
+
case "add":
|
|
152
|
+
case "replace": return `ALTER ROLE ${ident(old.name)} SET ${ident(k)} = ${literal(v)};`;
|
|
153
|
+
case "remove": return `ALTER ROLE ${ident(old.name)} RESET ${ident(k)};`;
|
|
154
|
+
default: throw new Error(`Invalid config op ${op}`);
|
|
155
|
+
}
|
|
156
|
+
}).filter(Boolean).join("");
|
|
157
|
+
const sql = `
|
|
158
|
+
BEGIN;
|
|
159
|
+
ALTER ROLE ${ident(old.name)}
|
|
160
|
+
${isSuperuserClause}
|
|
161
|
+
${canCreateDbClause}
|
|
162
|
+
${canCreateRoleClause}
|
|
163
|
+
${inheritRoleClause}
|
|
164
|
+
${canLoginClause}
|
|
165
|
+
${isReplicationRoleClause}
|
|
166
|
+
${canBypassRlsClause}
|
|
167
|
+
${connectionLimitClause}
|
|
168
|
+
${passwordClause}
|
|
169
|
+
${validUntilClause};
|
|
170
|
+
${configClause ? configClause : ""}
|
|
171
|
+
${nameSql}
|
|
172
|
+
COMMIT;`;
|
|
173
|
+
{
|
|
174
|
+
const { error } = await this.query(sql);
|
|
175
|
+
if (error) return {
|
|
176
|
+
data: null,
|
|
177
|
+
error
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return await this.retrieve({ id });
|
|
181
|
+
}
|
|
182
|
+
async remove(id) {
|
|
183
|
+
const { data: role, error } = await this.retrieve({ id });
|
|
184
|
+
if (error) return {
|
|
185
|
+
data: null,
|
|
186
|
+
error
|
|
187
|
+
};
|
|
188
|
+
const sql = `DROP ROLE ${ident(role.name)};`;
|
|
189
|
+
{
|
|
190
|
+
const { error } = await this.query(sql);
|
|
191
|
+
if (error) return {
|
|
192
|
+
data: null,
|
|
193
|
+
error
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
data: role,
|
|
198
|
+
error: null
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
//#endregion
|
|
203
|
+
export { changeRoleConfig2Object, PostgresMetaRoles as default };
|