@homeflare/alchemy 0.45.0 → 0.46.1
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/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/fake-schema-drop.d.ts +13 -0
- package/dist/postgres/fake-schema-drop.d.ts.map +1 -0
- package/dist/postgres/fake-schema-sql.d.ts +5 -0
- package/dist/postgres/fake-schema-sql.d.ts.map +1 -1
- package/dist/postgres/fake-sql.d.ts +4 -0
- package/dist/postgres/fake-sql.d.ts.map +1 -1
- package/dist/postgres/index.d.ts +2 -1
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +461 -278
- package/dist/postgres/index.js.map +19 -15
- package/dist/postgres/psql-executor.d.ts.map +1 -1
- package/dist/postgres/schema-closure-sql.d.ts +45 -0
- package/dist/postgres/schema-closure-sql.d.ts.map +1 -0
- package/dist/postgres/schema-delete.d.ts +17 -8
- package/dist/postgres/schema-delete.d.ts.map +1 -1
- package/dist/postgres/schema-drop-sql.d.ts +66 -0
- package/dist/postgres/schema-drop-sql.d.ts.map +1 -0
- package/dist/postgres/schema-errors.d.ts +19 -1
- package/dist/postgres/schema-errors.d.ts.map +1 -1
- package/dist/postgres/schema-sequence-error.d.ts +29 -0
- package/dist/postgres/schema-sequence-error.d.ts.map +1 -0
- package/dist/postgres/schema-sql.d.ts +16 -0
- package/dist/postgres/schema-sql.d.ts.map +1 -1
- package/dist/postgres/schema-test-kit.d.ts +3 -1
- package/dist/postgres/schema-test-kit.d.ts.map +1 -1
- package/dist/postgres/search-path.d.ts +38 -0
- package/dist/postgres/search-path.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/index.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
- package/dist/proxmox/index.d.ts +1 -0
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +283 -130
- package/dist/proxmox/index.js.map +31 -27
- package/dist/proxmox/qemu-dns.d.ts +2 -0
- package/dist/proxmox/qemu-dns.d.ts.map +1 -0
- package/dist/proxmox/qemu-errors.d.ts +1 -0
- package/dist/proxmox/qemu-errors.d.ts.map +1 -1
- package/dist/proxmox/qemu-form.d.ts.map +1 -1
- package/dist/proxmox/qemu-judge.d.ts.map +1 -1
- package/dist/proxmox/qemu-lifecycle.d.ts +15 -10
- package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/qemu-props.d.ts +10 -0
- package/dist/proxmox/qemu-props.d.ts.map +1 -1
- package/dist/proxmox/qemu-resize.d.ts +10 -0
- package/dist/proxmox/qemu-resize.d.ts.map +1 -0
- package/dist/proxmox/qemu-size.d.ts +20 -0
- package/dist/proxmox/qemu-size.d.ts.map +1 -0
- package/dist/proxmox/qemu-spec.d.ts +25 -0
- package/dist/proxmox/qemu-spec.d.ts.map +1 -0
- package/dist/verify/fake-engine.d.ts +4 -2
- package/dist/verify/fake-engine.d.ts.map +1 -1
- package/docs/postgres-schema.md +22 -1
- package/docs/proxmox-qemu-resize.md +62 -0
- package/package.json +1 -1
- package/src/postgres/connection.ts +10 -14
- package/src/postgres/database-bigint-serialization.test.ts +2 -2
- package/src/postgres/database-sql.ts +6 -6
- package/src/postgres/fake-grants-read.ts +3 -3
- package/src/postgres/fake-role-sql.ts +2 -2
- package/src/postgres/fake-schema-drop.ts +75 -0
- package/src/postgres/fake-schema-sql.ts +10 -1
- package/src/postgres/fake-sql.ts +10 -3
- package/src/postgres/grants-database.test.ts +5 -5
- package/src/postgres/grants-existence.ts +7 -7
- package/src/postgres/grants-ownership.ts +5 -5
- package/src/postgres/grants-psql-lifecycle.test.ts +7 -3
- package/src/postgres/grants-read-defaults.ts +5 -5
- package/src/postgres/grants-read.ts +16 -16
- package/src/postgres/index.ts +2 -0
- package/src/postgres/psql-executor-escaping.test.ts +3 -1
- package/src/postgres/psql-executor.test.ts +11 -5
- package/src/postgres/psql-executor.ts +4 -1
- package/src/postgres/role-adopt.test.ts +3 -1
- package/src/postgres/role-membership-options.test.ts +3 -1
- package/src/postgres/role-membership-repair.test.ts +3 -3
- package/src/postgres/role-membership-sql.ts +4 -4
- package/src/postgres/role-password-transports.test.ts +4 -2
- package/src/postgres/role-sql.ts +1 -1
- package/src/postgres/schema-closure-sql.ts +108 -0
- package/src/postgres/schema-delete-proofs.test.ts +7 -7
- package/src/postgres/schema-delete.ts +88 -46
- package/src/postgres/schema-drop-2bp01.test.ts +29 -17
- package/src/postgres/schema-drop-real.test.ts +190 -0
- package/src/postgres/schema-drop-sql.ts +135 -0
- package/src/postgres/schema-drop.test.ts +241 -0
- package/src/postgres/schema-errors.ts +26 -0
- package/src/postgres/schema-handlers.test.ts +21 -14
- package/src/postgres/schema-lifecycle.test.ts +6 -60
- package/src/postgres/schema-sequence-error.ts +38 -0
- package/src/postgres/schema-socket.test.ts +20 -6
- package/src/postgres/schema-sql.ts +16 -11
- package/src/postgres/schema-takeover.test.ts +7 -4
- package/src/postgres/schema-test-kit.ts +18 -4
- package/src/postgres/search-path.test.ts +100 -0
- package/src/postgres/search-path.ts +62 -0
- package/src/proxmox/generated/constraints/index.ts +1 -1
- package/src/proxmox/generated/constraints/pve-access.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +6 -1
- package/src/proxmox/generated/constraints/pve-nodes-storage.ts +1 -1
- package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
- package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
- package/src/proxmox/index.ts +1 -0
- package/src/proxmox/qemu-dns.test.ts +73 -0
- package/src/proxmox/qemu-dns.ts +32 -0
- package/src/proxmox/qemu-errors.ts +1 -0
- package/src/proxmox/qemu-form.ts +6 -3
- package/src/proxmox/qemu-judge.ts +2 -1
- package/src/proxmox/qemu-lifecycle.ts +28 -47
- package/src/proxmox/qemu-props.ts +14 -2
- package/src/proxmox/qemu-resize-lock.test.ts +121 -0
- package/src/proxmox/qemu-resize-recovery.test.ts +81 -0
- package/src/proxmox/qemu-resize.test.ts +199 -0
- package/src/proxmox/qemu-resize.ts +86 -0
- package/src/proxmox/qemu-size.test.ts +64 -0
- package/src/proxmox/qemu-size.ts +95 -0
- package/src/proxmox/qemu-spec.ts +44 -0
- package/src/proxmox/qemu-volume.ts +5 -5
- package/src/verify/fake-engine.ts +6 -3
package/dist/postgres/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// src/postgres/connection.ts
|
|
2
2
|
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
3
3
|
import * as Context from "effect/Context";
|
|
4
|
-
import * as
|
|
4
|
+
import * as Effect4 from "effect/Effect";
|
|
5
5
|
import * as Layer from "effect/Layer";
|
|
6
6
|
|
|
7
7
|
// src/postgres/psql-executor.ts
|
|
8
|
-
import * as
|
|
8
|
+
import * as Effect3 from "effect/Effect";
|
|
9
9
|
import {
|
|
10
10
|
ConnectionError,
|
|
11
11
|
SqlError,
|
|
@@ -49,15 +49,15 @@ var isDuplicateDatabaseRace = (error) => {
|
|
|
49
49
|
const cause = error.reason.cause;
|
|
50
50
|
return typeof cause === "object" && cause !== null && cause.code === "42P04";
|
|
51
51
|
};
|
|
52
|
-
var ROLE_EXISTS_SQL = "SELECT 1 AS present FROM pg_roles WHERE rolname = $1";
|
|
52
|
+
var ROLE_EXISTS_SQL = "SELECT 1 AS present FROM pg_catalog.pg_roles WHERE rolname = $1";
|
|
53
53
|
var roleExists = (pg, role) => Effect.map(pg.unsafe(ROLE_EXISTS_SQL, [role]), (rows) => rows.length > 0);
|
|
54
|
-
var DATABASE_EXISTS_SQL = "SELECT 1 AS present FROM pg_database WHERE datname = $1";
|
|
54
|
+
var DATABASE_EXISTS_SQL = "SELECT 1 AS present FROM pg_catalog.pg_database WHERE datname = $1";
|
|
55
55
|
var databaseExists = (pg, name) => Effect.map(pg.unsafe(DATABASE_EXISTS_SQL, [name]), (rows) => rows.length > 0);
|
|
56
56
|
var SELECT_DATABASE_SQL = `SELECT
|
|
57
57
|
d.oid AS oid,
|
|
58
58
|
d.datname AS name,
|
|
59
|
-
pg_get_userbyid(d.datdba) AS owner,
|
|
60
|
-
pg_encoding_to_char(d.encoding) AS encoding,
|
|
59
|
+
pg_catalog.pg_get_userbyid(d.datdba) AS owner,
|
|
60
|
+
pg_catalog.pg_encoding_to_char(d.encoding) AS encoding,
|
|
61
61
|
CASE d.datlocprovider
|
|
62
62
|
WHEN 'b' THEN 'builtin' WHEN 'i' THEN 'icu' WHEN 'c' THEN 'libc'
|
|
63
63
|
ELSE 'libc'
|
|
@@ -68,8 +68,8 @@ var SELECT_DATABASE_SQL = `SELECT
|
|
|
68
68
|
d.datconnlimit AS "connectionLimit",
|
|
69
69
|
d.datistemplate AS "isTemplate",
|
|
70
70
|
t.spcname AS tablespace
|
|
71
|
-
FROM pg_database d
|
|
72
|
-
JOIN pg_tablespace t ON t.oid = d.dattablespace
|
|
71
|
+
FROM pg_catalog.pg_database d
|
|
72
|
+
JOIN pg_catalog.pg_tablespace t ON t.oid = d.dattablespace
|
|
73
73
|
WHERE d.datname = $1`;
|
|
74
74
|
var selectDatabase = (pg, name) => Effect.map(pg.unsafe(SELECT_DATABASE_SQL, [name]), (rows) => rows[0]);
|
|
75
75
|
var firstDrift = (props, live) => {
|
|
@@ -90,6 +90,26 @@ var firstDrift = (props, live) => {
|
|
|
90
90
|
return;
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
+
// src/postgres/search-path.ts
|
|
94
|
+
import * as Effect2 from "effect/Effect";
|
|
95
|
+
var PIN_SEARCH_PATH_SQL = "SET search_path = pg_catalog, pg_temp";
|
|
96
|
+
var PIN_SCRIPT_PREFIX = `${PIN_SEARCH_PATH_SQL};
|
|
97
|
+
`;
|
|
98
|
+
var pinnedSocketExecutor = (pg) => Effect2.gen(function* () {
|
|
99
|
+
const connection = yield* pg.reserve;
|
|
100
|
+
const run = (sql, params) => Effect2.provideService(pg.unsafe(sql, params), pg.transactionService, [connection, 0]);
|
|
101
|
+
yield* run(PIN_SEARCH_PATH_SQL);
|
|
102
|
+
return {
|
|
103
|
+
unsafe: run,
|
|
104
|
+
transaction: (statements) => Effect2.gen(function* () {
|
|
105
|
+
yield* run("BEGIN");
|
|
106
|
+
for (const sql of statements)
|
|
107
|
+
yield* run(sql);
|
|
108
|
+
yield* run("COMMIT");
|
|
109
|
+
}).pipe(Effect2.onError(() => run("ROLLBACK").pipe(Effect2.ignore)), Effect2.asVoid)
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
|
|
93
113
|
// src/postgres/psql-executor.ts
|
|
94
114
|
var inlineParams = (sql, params) => params.length === 0 ? sql : sql.replace(/\$(\d+)/g, (_match, index) => {
|
|
95
115
|
const value = params[Number(index) - 1];
|
|
@@ -113,8 +133,8 @@ var failure = (operation, result) => {
|
|
|
113
133
|
const reason = state === undefined ? new ConnectionError(fields) : state.startsWith("42") ? new SqlSyntaxError(fields) : new UnknownError(fields);
|
|
114
134
|
return new SqlError({ reason });
|
|
115
135
|
};
|
|
116
|
-
var runScript = (run, target, stdin, operation) =>
|
|
117
|
-
const result = yield*
|
|
136
|
+
var runScript = (run, target, stdin, operation) => Effect3.gen(function* () {
|
|
137
|
+
const result = yield* Effect3.tryPromise({
|
|
118
138
|
try: () => run({
|
|
119
139
|
argv: [
|
|
120
140
|
"psql",
|
|
@@ -131,18 +151,18 @@ var runScript = (run, target, stdin, operation) => Effect2.gen(function* () {
|
|
|
131
151
|
"-d",
|
|
132
152
|
target.database
|
|
133
153
|
],
|
|
134
|
-
stdin
|
|
154
|
+
stdin: `${PIN_SCRIPT_PREFIX}${stdin}`
|
|
135
155
|
}),
|
|
136
156
|
catch: (cause) => new SqlError({ reason: new ConnectionError({ cause, operation: "psql exec" }) })
|
|
137
157
|
});
|
|
138
158
|
if (result.code !== 0) {
|
|
139
|
-
return yield*
|
|
159
|
+
return yield* Effect3.fail(failure(operation, result));
|
|
140
160
|
}
|
|
141
161
|
return result;
|
|
142
162
|
});
|
|
143
163
|
var makePsqlExecutor = (run, target) => ({
|
|
144
|
-
unsafe: (sql, params = []) =>
|
|
145
|
-
const inlined = yield*
|
|
164
|
+
unsafe: (sql, params = []) => Effect3.gen(function* () {
|
|
165
|
+
const inlined = yield* Effect3.try({
|
|
146
166
|
try: () => inlineParams(sql, params),
|
|
147
167
|
catch: (cause) => new SqlError({ reason: new UnknownError({ cause, operation: "psql inline params" }) })
|
|
148
168
|
});
|
|
@@ -150,13 +170,13 @@ var makePsqlExecutor = (run, target) => ({
|
|
|
150
170
|
const result = yield* runScript(run, target, rows ? wrapRows(inlined) : `${inlined};`, redactPasswordLiterals(inlined).slice(0, 40));
|
|
151
171
|
if (!rows)
|
|
152
172
|
return [];
|
|
153
|
-
const parsed = yield*
|
|
173
|
+
const parsed = yield* Effect3.try({
|
|
154
174
|
try: () => JSON.parse(result.stdout.trim() || "[]").map(normalizeRow),
|
|
155
175
|
catch: (cause) => new SqlError({ reason: new UnknownError({ cause, operation: "psql parse output" }) })
|
|
156
176
|
});
|
|
157
177
|
return parsed;
|
|
158
178
|
}),
|
|
159
|
-
transaction: (statements) =>
|
|
179
|
+
transaction: (statements) => Effect3.gen(function* () {
|
|
160
180
|
const script = ["BEGIN", ...statements, "COMMIT"].join(`;
|
|
161
181
|
`);
|
|
162
182
|
yield* runScript(run, target, `${script};`, "BEGIN");
|
|
@@ -166,13 +186,13 @@ var makePsqlExecutor = (run, target) => ({
|
|
|
166
186
|
// src/postgres/connection.ts
|
|
167
187
|
class PostgresConnection extends Context.Service()("Postgres.Connection") {
|
|
168
188
|
}
|
|
169
|
-
var postgresConnection = (config) => Layer.succeed(PostgresConnection,
|
|
170
|
-
var postgresRunnerConnection = (config) => Layer.succeed(PostgresConnection,
|
|
189
|
+
var postgresConnection = (config) => Layer.succeed(PostgresConnection, Effect4.succeed(config));
|
|
190
|
+
var postgresRunnerConnection = (config) => Layer.succeed(PostgresConnection, Effect4.succeed(config));
|
|
171
191
|
var PostgresPool = Context.Reference("homeflare/postgres/Pool", {
|
|
172
192
|
defaultValue: () => PgClient.layer
|
|
173
193
|
});
|
|
174
194
|
var isRunner = (c) => ("run" in c);
|
|
175
|
-
var withPg = (build, database) =>
|
|
195
|
+
var withPg = (build, database) => Effect4.gen(function* () {
|
|
176
196
|
const resolveConfig = yield* PostgresConnection;
|
|
177
197
|
const config = yield* resolveConfig;
|
|
178
198
|
const target = database === undefined ? config : { ...config, database };
|
|
@@ -183,13 +203,7 @@ var withPg = (build, database) => Effect3.gen(function* () {
|
|
|
183
203
|
});
|
|
184
204
|
}
|
|
185
205
|
const pool = yield* PostgresPool;
|
|
186
|
-
return yield*
|
|
187
|
-
unsafe: (sql, params) => pg.unsafe(sql, params),
|
|
188
|
-
transaction: (statements) => pg.withTransaction(Effect3.gen(function* () {
|
|
189
|
-
for (const sql of statements)
|
|
190
|
-
yield* pg.unsafe(sql).pipe(Effect3.asVoid);
|
|
191
|
-
}))
|
|
192
|
-
}, { database: target.database })), pool(target));
|
|
206
|
+
return yield* Effect4.provide(Effect4.scoped(Effect4.flatMap(PgClient.PgClient, (pg) => Effect4.flatMap(pinnedSocketExecutor(pg), (executor) => build(executor, { database: target.database })))), pool(target));
|
|
193
207
|
});
|
|
194
208
|
// src/postgres/database-attrs.ts
|
|
195
209
|
var POSTGRES_NAME_MAX_BYTES = 63;
|
|
@@ -203,7 +217,7 @@ import { Resource } from "alchemy";
|
|
|
203
217
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
204
218
|
import { isResolved } from "alchemy/Diff";
|
|
205
219
|
import * as Provider from "alchemy/Provider";
|
|
206
|
-
import * as
|
|
220
|
+
import * as Effect5 from "effect/Effect";
|
|
207
221
|
|
|
208
222
|
// src/postgres/errors.ts
|
|
209
223
|
import * as Data from "effect/Data";
|
|
@@ -255,23 +269,23 @@ var liveDrift = (props, live) => {
|
|
|
255
269
|
}
|
|
256
270
|
return firstDrift(props, live);
|
|
257
271
|
};
|
|
258
|
-
var reconcileWithClient = (pg, props, template) =>
|
|
272
|
+
var reconcileWithClient = (pg, props, template) => Effect5.gen(function* () {
|
|
259
273
|
const observed = yield* selectDatabase(pg, props.name);
|
|
260
274
|
if (observed === undefined) {
|
|
261
275
|
const ownerPresent = yield* roleExists(pg, props.owner);
|
|
262
276
|
if (!ownerPresent) {
|
|
263
|
-
return yield*
|
|
277
|
+
return yield* Effect5.fail(new PostgresDatabaseOwnerMissing({ database: props.name, owner: props.owner }));
|
|
264
278
|
}
|
|
265
|
-
yield* pg.unsafe(buildCreateDatabaseSql(props, template)).pipe(
|
|
279
|
+
yield* pg.unsafe(buildCreateDatabaseSql(props, template)).pipe(Effect5.asVoid, Effect5.catchTag("SqlError", (error) => isDuplicateDatabaseRace(error) ? Effect5.succeed(undefined) : Effect5.fail(error)));
|
|
266
280
|
const created = yield* selectDatabase(pg, props.name);
|
|
267
281
|
if (created === undefined) {
|
|
268
|
-
return yield*
|
|
282
|
+
return yield* Effect5.fail(new PostgresDatabaseCreateVanished({ database: props.name }));
|
|
269
283
|
}
|
|
270
284
|
return created;
|
|
271
285
|
}
|
|
272
286
|
const drift = liveDrift(props, observed);
|
|
273
287
|
if (drift !== undefined) {
|
|
274
|
-
return yield*
|
|
288
|
+
return yield* Effect5.fail(new PostgresDatabaseDrift({
|
|
275
289
|
database: props.name,
|
|
276
290
|
prop: drift.prop,
|
|
277
291
|
declared: drift.declared,
|
|
@@ -281,36 +295,36 @@ var reconcileWithClient = (pg, props, template) => Effect4.gen(function* () {
|
|
|
281
295
|
return observed;
|
|
282
296
|
});
|
|
283
297
|
var readWithClient = (pg, name) => selectDatabase(pg, name);
|
|
284
|
-
var diffPostgresDatabase = (news, output) =>
|
|
298
|
+
var diffPostgresDatabase = (news, output) => Effect5.gen(function* () {
|
|
285
299
|
if (output === undefined || !isResolved(news))
|
|
286
300
|
return;
|
|
287
301
|
if (news.name !== output.name) {
|
|
288
|
-
return yield*
|
|
302
|
+
return yield* Effect5.fail(new PostgresDatabaseRenameRefused({ from: output.name, to: news.name }));
|
|
289
303
|
}
|
|
290
304
|
const nameRefusal = nameByteRefusal(news.name);
|
|
291
305
|
if (nameRefusal !== undefined) {
|
|
292
|
-
return yield*
|
|
306
|
+
return yield* Effect5.fail(new PostgresDatabaseNameRefused({ name: news.name, ...nameRefusal }));
|
|
293
307
|
}
|
|
294
308
|
const changed = news.owner !== output.owner || firstDrift(news, output) !== undefined;
|
|
295
309
|
return changed ? { action: "update" } : { action: "noop" };
|
|
296
310
|
});
|
|
297
311
|
var postgresDatabaseHandlers = PostgresDatabase.Provider.of({
|
|
298
|
-
list: () =>
|
|
312
|
+
list: () => Effect5.succeed([]),
|
|
299
313
|
nuke: { skip: true },
|
|
300
|
-
read: ({ olds, output }) =>
|
|
314
|
+
read: ({ olds, output }) => Effect5.gen(function* () {
|
|
301
315
|
const name = output?.name ?? olds.name;
|
|
302
316
|
const live = yield* withPg((pg) => readWithClient(pg, name));
|
|
303
317
|
return live === undefined ? undefined : Unowned(live);
|
|
304
318
|
}),
|
|
305
319
|
diff: ({ news, output }) => diffPostgresDatabase(news, output),
|
|
306
|
-
reconcile: ({ news }) =>
|
|
320
|
+
reconcile: ({ news }) => Effect5.gen(function* () {
|
|
307
321
|
const nameRefusal = nameByteRefusal(news.name);
|
|
308
322
|
if (nameRefusal !== undefined) {
|
|
309
|
-
return yield*
|
|
323
|
+
return yield* Effect5.fail(new PostgresDatabaseNameRefused({ name: news.name, ...nameRefusal }));
|
|
310
324
|
}
|
|
311
325
|
return yield* withPg((pg, ctx) => reconcileWithClient(pg, news, ctx.template));
|
|
312
326
|
}),
|
|
313
|
-
delete: ({ olds }) =>
|
|
327
|
+
delete: ({ olds }) => Effect5.fail(new PostgresDatabaseDropRefused({ database: olds.name }))
|
|
314
328
|
});
|
|
315
329
|
var PostgresDatabaseProvider = () => Provider.succeed(PostgresDatabase, postgresDatabaseHandlers);
|
|
316
330
|
// src/postgres/schema-attrs.ts
|
|
@@ -320,34 +334,35 @@ var schemaNameByteRefusal = (name) => {
|
|
|
320
334
|
return byteLength > POSTGRES_NAME_MAX_BYTES ? { byteLength, limit: POSTGRES_NAME_MAX_BYTES } : undefined;
|
|
321
335
|
};
|
|
322
336
|
// src/postgres/schema-sql.ts
|
|
323
|
-
import * as
|
|
337
|
+
import * as Effect6 from "effect/Effect";
|
|
324
338
|
var buildCreateSchemaSql = (props) => `CREATE SCHEMA ${quoteIdent(props.name)}${props.owner === undefined ? "" : ` AUTHORIZATION ${quoteIdent(props.owner)}`}`;
|
|
325
339
|
var buildCommentSchemaSql = (name, comment) => `COMMENT ON SCHEMA ${quoteIdent(name)} IS ${quoteStringLiteral(comment)}`;
|
|
326
340
|
var buildDropSchemaSql = (name, cascade) => `DROP SCHEMA IF EXISTS ${quoteIdent(name)}${cascade ? " CASCADE" : ""}`;
|
|
327
341
|
var SELECT_SCHEMA_SQL = `SELECT
|
|
328
342
|
n.oid AS oid,
|
|
329
343
|
n.nspname AS name,
|
|
330
|
-
pg_get_userbyid(n.nspowner) AS owner,
|
|
331
|
-
obj_description(n.oid, 'pg_namespace') AS comment,
|
|
344
|
+
pg_catalog.pg_get_userbyid(n.nspowner) AS owner,
|
|
345
|
+
pg_catalog.obj_description(n.oid, 'pg_namespace') AS comment,
|
|
332
346
|
current_database() AS database
|
|
333
|
-
FROM pg_namespace n
|
|
347
|
+
FROM pg_catalog.pg_namespace n
|
|
334
348
|
WHERE n.nspname = $1`;
|
|
335
|
-
var selectSchema = (pg, name) =>
|
|
349
|
+
var selectSchema = (pg, name) => Effect6.map(pg.unsafe(SELECT_SCHEMA_SQL, [name]), (rows) => rows[0]);
|
|
336
350
|
var CURRENT_DATABASE_SQL = "SELECT current_database() AS database";
|
|
337
|
-
var currentDatabase = (pg) =>
|
|
351
|
+
var currentDatabase = (pg) => Effect6.map(pg.unsafe(CURRENT_DATABASE_SQL), (rows) => rows[0]?.database ?? "");
|
|
338
352
|
var CURRENT_USER_SQL = "SELECT current_user AS role";
|
|
339
|
-
var currentUser = (pg) =>
|
|
340
|
-
var
|
|
341
|
-
|
|
342
|
-
SELECT 1 FROM pg_class c WHERE c.relnamespace = (SELECT oid FROM ns)
|
|
353
|
+
var currentUser = (pg) => Effect6.map(pg.unsafe(CURRENT_USER_SQL), (rows) => rows[0]?.role ?? "");
|
|
354
|
+
var emptyPredicate = (ns) => `NOT EXISTS (
|
|
355
|
+
SELECT 1 FROM pg_catalog.pg_class c WHERE c.relnamespace = ${ns}
|
|
343
356
|
) AND NOT EXISTS (
|
|
344
|
-
SELECT 1 FROM pg_proc p WHERE p.pronamespace =
|
|
357
|
+
SELECT 1 FROM pg_catalog.pg_proc p WHERE p.pronamespace = ${ns}
|
|
345
358
|
) AND NOT EXISTS (
|
|
346
|
-
SELECT 1 FROM pg_type t WHERE t.typnamespace =
|
|
359
|
+
SELECT 1 FROM pg_catalog.pg_type t WHERE t.typnamespace = ${ns}
|
|
347
360
|
) AND NOT EXISTS (
|
|
348
|
-
SELECT 1 FROM pg_operator o WHERE o.oprnamespace =
|
|
349
|
-
)
|
|
350
|
-
var
|
|
361
|
+
SELECT 1 FROM pg_catalog.pg_operator o WHERE o.oprnamespace = ${ns}
|
|
362
|
+
)`;
|
|
363
|
+
var SCHEMA_EMPTY_SQL = `WITH ns AS (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
364
|
+
SELECT ${emptyPredicate("(SELECT oid FROM ns)")} AS empty`;
|
|
365
|
+
var schemaIsEmpty = (pg, name) => Effect6.map(pg.unsafe(SCHEMA_EMPTY_SQL, [name]), (rows) => rows[0]?.empty ?? true);
|
|
351
366
|
var isDependentObjectsError = (error) => {
|
|
352
367
|
const cause = error.reason.cause;
|
|
353
368
|
return typeof cause === "object" && cause !== null && cause.code === "2BP01";
|
|
@@ -360,10 +375,10 @@ var isDuplicateSchemaError = (error) => {
|
|
|
360
375
|
import { Resource as Resource2 } from "alchemy";
|
|
361
376
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
362
377
|
import * as Provider2 from "alchemy/Provider";
|
|
363
|
-
import * as
|
|
378
|
+
import * as Effect12 from "effect/Effect";
|
|
364
379
|
|
|
365
380
|
// src/postgres/schema-identity.ts
|
|
366
|
-
import * as
|
|
381
|
+
import * as Effect7 from "effect/Effect";
|
|
367
382
|
|
|
368
383
|
// src/postgres/schema-errors.ts
|
|
369
384
|
import * as Data2 from "effect/Data";
|
|
@@ -404,6 +419,12 @@ class PostgresSchemaDropNotEmptyError extends Data2.TaggedError("PostgresSchemaD
|
|
|
404
419
|
}
|
|
405
420
|
}
|
|
406
421
|
|
|
422
|
+
class PostgresSchemaCascadeCrossSchemaRefused extends Data2.TaggedError("PostgresSchemaCascadeCrossSchemaRefused") {
|
|
423
|
+
get message() {
|
|
424
|
+
return `Postgres.Schema "${this.schema}": cascade: true refused — ${String(this.dependents)} ` + "dependent object(s) outside this schema would be dropped with it. No DROP was issued. " + "Remove or move those dependents first.";
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
407
428
|
class PostgresSchemaWrongDatabase extends Data2.TaggedError("PostgresSchemaWrongDatabase") {
|
|
408
429
|
get message() {
|
|
409
430
|
return `Postgres.Schema "${this.schema}": declared in database "${this.declared}" but the ` + `connection answers current_database() "${this.connected}". The handlers open the declared ` + "database themselves, so this points at broken provider wiring — fix it before touching any " + "schema, or the next create would land in the wrong database.";
|
|
@@ -436,15 +457,15 @@ class PostgresSchemaIdentityRefused extends Data2.TaggedError("PostgresSchemaIde
|
|
|
436
457
|
}
|
|
437
458
|
|
|
438
459
|
// src/postgres/schema-identity.ts
|
|
439
|
-
var assertSchemaTarget = (props, output) =>
|
|
460
|
+
var assertSchemaTarget = (props, output) => Effect7.gen(function* () {
|
|
440
461
|
if (output === undefined)
|
|
441
462
|
return;
|
|
442
463
|
if (props.name !== output.name)
|
|
443
|
-
return yield*
|
|
464
|
+
return yield* Effect7.fail(new PostgresSchemaRenameRefused({ from: output.name, to: props.name }));
|
|
444
465
|
if (props.database !== output.database)
|
|
445
|
-
return yield*
|
|
466
|
+
return yield* Effect7.fail(new PostgresSchemaDatabaseRefused({ from: output.database, to: props.database }));
|
|
446
467
|
});
|
|
447
|
-
var assertSchemaIdentity = (live, output) => live.oid === output.oid ?
|
|
468
|
+
var assertSchemaIdentity = (live, output) => live.oid === output.oid ? Effect7.void : Effect7.fail(new PostgresSchemaIdentityRefused({
|
|
448
469
|
schema: live.name,
|
|
449
470
|
storedOid: output.oid,
|
|
450
471
|
liveOid: live.oid
|
|
@@ -452,14 +473,14 @@ var assertSchemaIdentity = (live, output) => live.oid === output.oid ? Effect6.v
|
|
|
452
473
|
|
|
453
474
|
// src/postgres/schema-diff.ts
|
|
454
475
|
import { isResolved as isResolved2 } from "alchemy/Diff";
|
|
455
|
-
import * as
|
|
456
|
-
var diffPostgresSchema = (news, output, olds) =>
|
|
476
|
+
import * as Effect8 from "effect/Effect";
|
|
477
|
+
var diffPostgresSchema = (news, output, olds) => Effect8.gen(function* () {
|
|
457
478
|
if (output === undefined || !isResolved2(news))
|
|
458
479
|
return;
|
|
459
480
|
yield* assertSchemaTarget(news, output);
|
|
460
481
|
const nameRefusal = schemaNameByteRefusal(news.name);
|
|
461
482
|
if (nameRefusal !== undefined) {
|
|
462
|
-
return yield*
|
|
483
|
+
return yield* Effect8.fail(new PostgresSchemaNameRefused({ name: news.name, ...nameRefusal }));
|
|
463
484
|
}
|
|
464
485
|
const comment = normalizedComment(news.comment);
|
|
465
486
|
const changed = news.owner !== undefined && news.owner !== output.owner || comment !== undefined && comment !== (output.comment ?? undefined) || (news.cascade ?? false) !== (olds?.cascade ?? false);
|
|
@@ -467,11 +488,11 @@ var diffPostgresSchema = (news, output, olds) => Effect7.gen(function* () {
|
|
|
467
488
|
});
|
|
468
489
|
|
|
469
490
|
// src/postgres/schema-reconcile.ts
|
|
470
|
-
import * as
|
|
491
|
+
import * as Effect10 from "effect/Effect";
|
|
471
492
|
|
|
472
493
|
// src/postgres/schema-assert.ts
|
|
473
|
-
import * as
|
|
474
|
-
var assertDatabase = (props, pg) =>
|
|
494
|
+
import * as Effect9 from "effect/Effect";
|
|
495
|
+
var assertDatabase = (props, pg) => Effect9.flatMap(currentDatabase(pg), (connected) => connected === props.database ? Effect9.void : Effect9.fail(new PostgresSchemaWrongDatabase({
|
|
475
496
|
schema: props.name,
|
|
476
497
|
declared: props.database,
|
|
477
498
|
connected
|
|
@@ -491,7 +512,7 @@ var liveDrift2 = (props, live, executingRole) => {
|
|
|
491
512
|
}
|
|
492
513
|
return;
|
|
493
514
|
};
|
|
494
|
-
var refuse = (props, drift) =>
|
|
515
|
+
var refuse = (props, drift) => Effect9.fail(new PostgresSchemaDrift({
|
|
495
516
|
schema: props.name,
|
|
496
517
|
prop: drift.prop,
|
|
497
518
|
declared: drift.declared,
|
|
@@ -499,11 +520,11 @@ var refuse = (props, drift) => Effect8.fail(new PostgresSchemaDrift({
|
|
|
499
520
|
}));
|
|
500
521
|
var assertOwner = (props, row, executingRole) => {
|
|
501
522
|
const drift = ownerDrift(props, row, executingRole);
|
|
502
|
-
return drift === undefined ?
|
|
523
|
+
return drift === undefined ? Effect9.void : refuse(props, drift);
|
|
503
524
|
};
|
|
504
525
|
var assertLive = (props, row, executingRole) => {
|
|
505
526
|
const drift = liveDrift2(props, row, executingRole);
|
|
506
|
-
return drift === undefined ?
|
|
527
|
+
return drift === undefined ? Effect9.succeed(row) : refuse(props, drift);
|
|
507
528
|
};
|
|
508
529
|
var deleteForeignRefusal = (props, live, output) => {
|
|
509
530
|
if (output !== undefined && output.oid === live.oid && output.owner === live.owner) {
|
|
@@ -520,7 +541,7 @@ var deleteForeignRefusal = (props, live, output) => {
|
|
|
520
541
|
};
|
|
521
542
|
|
|
522
543
|
// src/postgres/schema-reconcile.ts
|
|
523
|
-
var reconcileWithClient2 = (pg, props, output) =>
|
|
544
|
+
var reconcileWithClient2 = (pg, props, output) => Effect10.gen(function* () {
|
|
524
545
|
yield* assertSchemaTarget(props, output);
|
|
525
546
|
yield* assertDatabase(props, pg);
|
|
526
547
|
const executingRole = props.owner !== undefined ? props.owner : yield* currentUser(pg);
|
|
@@ -529,55 +550,215 @@ var reconcileWithClient2 = (pg, props, output) => Effect9.gen(function* () {
|
|
|
529
550
|
if (props.owner !== undefined) {
|
|
530
551
|
const ownerPresent = yield* roleExists(pg, props.owner);
|
|
531
552
|
if (!ownerPresent) {
|
|
532
|
-
return yield*
|
|
553
|
+
return yield* Effect10.fail(new PostgresSchemaOwnerMissing({ schema: props.name, owner: props.owner }));
|
|
533
554
|
}
|
|
534
555
|
}
|
|
535
556
|
const createRefusal = (error) => isDuplicateSchemaError(error) ? new PostgresSchemaExistsRefused({ schema: props.name, database: props.database }) : error;
|
|
536
|
-
yield* pg.unsafe(buildCreateSchemaSql(props)).pipe(
|
|
557
|
+
yield* pg.unsafe(buildCreateSchemaSql(props)).pipe(Effect10.asVoid, Effect10.catchTag("SqlError", (error) => Effect10.fail(createRefusal(error))));
|
|
537
558
|
const created = yield* selectSchema(pg, props.name);
|
|
538
559
|
if (created === undefined) {
|
|
539
|
-
return yield*
|
|
560
|
+
return yield* Effect10.fail(new PostgresSchemaCreateVanished({ schema: props.name }));
|
|
540
561
|
}
|
|
541
562
|
yield* assertOwner(props, created, executingRole);
|
|
542
563
|
const comment = normalizedComment(props.comment);
|
|
543
564
|
if (comment !== undefined && comment !== (created.comment ?? undefined)) {
|
|
544
|
-
yield* pg.unsafe(buildCommentSchemaSql(props.name, comment)).pipe(
|
|
565
|
+
yield* pg.unsafe(buildCommentSchemaSql(props.name, comment)).pipe(Effect10.asVoid);
|
|
545
566
|
const commented = yield* selectSchema(pg, props.name);
|
|
546
567
|
if (commented === undefined) {
|
|
547
|
-
return yield*
|
|
568
|
+
return yield* Effect10.fail(new PostgresSchemaCreateVanished({ schema: props.name }));
|
|
548
569
|
}
|
|
549
570
|
return yield* assertLive(props, commented, executingRole);
|
|
550
571
|
}
|
|
551
572
|
return yield* assertLive(props, created, executingRole);
|
|
552
573
|
}
|
|
553
574
|
if (output === undefined) {
|
|
554
|
-
return yield*
|
|
575
|
+
return yield* Effect10.fail(new PostgresSchemaExistsRefused({ schema: props.name, database: props.database }));
|
|
555
576
|
}
|
|
556
577
|
yield* assertSchemaIdentity(observed, output);
|
|
557
578
|
return yield* assertLive(props, observed, executingRole);
|
|
558
579
|
});
|
|
559
580
|
|
|
560
581
|
// src/postgres/schema-delete.ts
|
|
561
|
-
import * as
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
582
|
+
import * as Effect11 from "effect/Effect";
|
|
583
|
+
|
|
584
|
+
// src/postgres/schema-closure-sql.ts
|
|
585
|
+
var cls = (name) => `'pg_catalog.${name}'::pg_catalog.regclass`;
|
|
586
|
+
var direct = (table, column) => `WHEN ${cls(table)} THEN (SELECT x.${column} FROM pg_catalog.${table} x WHERE x.oid = d.objid)`;
|
|
587
|
+
var viaRelation = (table, column) => `WHEN ${cls(table)} THEN (SELECT c.relnamespace FROM pg_catalog.${table} x JOIN pg_catalog.pg_class c ON c.oid = x.${column} WHERE x.oid = d.objid)`;
|
|
588
|
+
var viaFamily = (table, column) => `WHEN ${cls(table)} THEN (SELECT f.opfnamespace FROM pg_catalog.${table} x JOIN pg_catalog.pg_opfamily f ON f.oid = x.${column} WHERE x.oid = d.objid)`;
|
|
589
|
+
var RELATION_HOME = `WHEN ${cls("pg_class")} THEN COALESCE(
|
|
590
|
+
(SELECT o.relnamespace FROM pg_catalog.pg_class o
|
|
591
|
+
WHERE o.reltoastrelid <> 0
|
|
592
|
+
AND o.reltoastrelid IN (d.objid, (SELECT i.indrelid FROM pg_catalog.pg_index i WHERE i.indexrelid = d.objid))),
|
|
593
|
+
(SELECT x.relnamespace FROM pg_catalog.pg_class x WHERE x.oid = d.objid))`;
|
|
594
|
+
var HOME_OF_DEPENDENT = `CASE d.classid
|
|
595
|
+
WHEN ${cls("pg_namespace")} THEN d.objid
|
|
596
|
+
${RELATION_HOME}
|
|
597
|
+
${direct("pg_type", "typnamespace")}
|
|
598
|
+
${direct("pg_proc", "pronamespace")}
|
|
599
|
+
${direct("pg_operator", "oprnamespace")}
|
|
600
|
+
${direct("pg_collation", "collnamespace")}
|
|
601
|
+
${direct("pg_conversion", "connamespace")}
|
|
602
|
+
${direct("pg_opclass", "opcnamespace")}
|
|
603
|
+
${direct("pg_opfamily", "opfnamespace")}
|
|
604
|
+
${direct("pg_ts_config", "cfgnamespace")}
|
|
605
|
+
${direct("pg_ts_dict", "dictnamespace")}
|
|
606
|
+
${direct("pg_ts_parser", "prsnamespace")}
|
|
607
|
+
${direct("pg_ts_template", "tmplnamespace")}
|
|
608
|
+
${direct("pg_statistic_ext", "stxnamespace")}
|
|
609
|
+
${direct("pg_constraint", "connamespace")}
|
|
610
|
+
${direct("pg_default_acl", "defaclnamespace")}
|
|
611
|
+
${direct("pg_extension", "extnamespace")}
|
|
612
|
+
${viaRelation("pg_trigger", "tgrelid")}
|
|
613
|
+
${viaRelation("pg_rewrite", "ev_class")}
|
|
614
|
+
${viaRelation("pg_attrdef", "adrelid")}
|
|
615
|
+
${viaRelation("pg_policy", "polrelid")}
|
|
616
|
+
${viaRelation("pg_publication_rel", "prrelid")}
|
|
617
|
+
${viaFamily("pg_amop", "amopfamily")}
|
|
618
|
+
${viaFamily("pg_amproc", "amprocfamily")}
|
|
619
|
+
END`;
|
|
620
|
+
var OUTSIDE_DEPENDENTS_SQL = `v_count := (
|
|
621
|
+
WITH RECURSIVE reach (classid, objid, inside) AS (
|
|
622
|
+
SELECT ${cls("pg_namespace")}::pg_catalog.oid, v_ns, true
|
|
623
|
+
UNION
|
|
624
|
+
SELECT d.classid, d.objid, (${HOME_OF_DEPENDENT}) IS NOT DISTINCT FROM v_ns
|
|
625
|
+
FROM pg_catalog.pg_depend d
|
|
626
|
+
JOIN reach r ON d.refclassid = r.classid AND d.refobjid = r.objid AND r.inside
|
|
627
|
+
WHERE d.deptype <> 'p'
|
|
628
|
+
)
|
|
629
|
+
SELECT (SELECT pg_catalog.count(*) FROM reach WHERE NOT inside)
|
|
630
|
+
+ (SELECT pg_catalog.count(*) FROM pg_catalog.pg_depend e
|
|
631
|
+
JOIN reach r ON e.classid = r.classid AND e.objid = r.objid AND r.inside
|
|
632
|
+
WHERE e.deptype IN ('e', 'i') AND e.refobjid <> 0
|
|
633
|
+
AND NOT EXISTS (SELECT 1 FROM reach o
|
|
634
|
+
WHERE o.inside AND o.classid = e.refclassid AND o.objid = e.refobjid))
|
|
635
|
+
)`;
|
|
636
|
+
|
|
637
|
+
// src/postgres/schema-drop-sql.ts
|
|
638
|
+
var IDENTITY_CHANGED = "HF001";
|
|
639
|
+
var NOT_EMPTY = "HF002";
|
|
640
|
+
var CROSS_SCHEMA_DEPENDENTS = "HF003";
|
|
641
|
+
var CASCADE_SEQUENCES = "HF004";
|
|
642
|
+
var LOCK_TIMEOUT = "10s";
|
|
643
|
+
var buildAtomicDropSql = (drop) => {
|
|
644
|
+
const body = `DECLARE
|
|
645
|
+
v_name text := ${quoteStringLiteral(drop.name)};
|
|
646
|
+
v_oid oid := ${String(Math.trunc(drop.oid))};
|
|
647
|
+
v_owner text := ${quoteStringLiteral(drop.owner)};
|
|
648
|
+
v_cascade boolean := ${drop.cascade ? "true" : "false"};
|
|
649
|
+
v_ns oid;
|
|
650
|
+
v_count bigint;
|
|
651
|
+
v_comment text;
|
|
652
|
+
v_rel text;
|
|
653
|
+
BEGIN
|
|
654
|
+
SELECT n.oid INTO v_ns FROM pg_catalog.pg_namespace n WHERE n.nspname = v_name;
|
|
655
|
+
IF v_ns IS NULL THEN RETURN; END IF;
|
|
656
|
+
PERFORM pg_catalog.set_config('lock_timeout', '${LOCK_TIMEOUT}', true);
|
|
657
|
+
PERFORM pg_catalog.pg_advisory_xact_lock(v_ns::pg_catalog.int8);
|
|
658
|
+
v_comment := pg_catalog.obj_description(v_ns, 'pg_namespace');
|
|
659
|
+
EXECUTE pg_catalog.format('COMMENT ON SCHEMA %I IS %L', v_name, v_comment);
|
|
660
|
+
SELECT n.oid INTO v_ns FROM pg_catalog.pg_namespace n
|
|
661
|
+
WHERE n.nspname = v_name AND n.oid = v_oid
|
|
662
|
+
AND pg_catalog.pg_get_userbyid(n.nspowner) = v_owner;
|
|
663
|
+
IF v_ns IS NULL THEN
|
|
664
|
+
RAISE EXCEPTION 'schema identity changed' USING ERRCODE = '${IDENTITY_CHANGED}';
|
|
665
|
+
END IF;
|
|
666
|
+
IF NOT v_cascade THEN
|
|
667
|
+
IF NOT (${emptyPredicate("v_ns")}) THEN
|
|
668
|
+
RAISE EXCEPTION 'schema not empty' USING ERRCODE = '${NOT_EMPTY}';
|
|
669
|
+
END IF;
|
|
670
|
+
ELSE
|
|
671
|
+
SELECT count(*) INTO v_count FROM pg_catalog.pg_class c
|
|
672
|
+
WHERE c.relnamespace = v_ns AND c.relkind = 'S';
|
|
673
|
+
IF v_count > 0 THEN
|
|
674
|
+
RAISE EXCEPTION 'cascade sequences: %', v_count USING ERRCODE = '${CASCADE_SEQUENCES}';
|
|
675
|
+
END IF;
|
|
676
|
+
FOR v_rel IN SELECT c.oid::pg_catalog.regclass::pg_catalog.text FROM pg_catalog.pg_class c
|
|
677
|
+
WHERE c.relnamespace = v_ns AND c.relkind IN ('r', 'p', 'v', 'm', 'f') ORDER BY c.oid LOOP
|
|
678
|
+
EXECUTE pg_catalog.format('LOCK TABLE %s IN ACCESS EXCLUSIVE MODE', v_rel);
|
|
679
|
+
END LOOP;
|
|
680
|
+
${OUTSIDE_DEPENDENTS_SQL};
|
|
681
|
+
IF v_count > 0 THEN
|
|
682
|
+
RAISE EXCEPTION 'cross-schema dependents: %', v_count USING ERRCODE = '${CROSS_SCHEMA_DEPENDENTS}';
|
|
683
|
+
END IF;
|
|
684
|
+
END IF;
|
|
685
|
+
PERFORM 1 FROM pg_catalog.pg_namespace n WHERE n.oid = v_oid AND n.nspname = v_name;
|
|
686
|
+
IF NOT FOUND THEN
|
|
687
|
+
RAISE EXCEPTION 'schema identity changed' USING ERRCODE = '${IDENTITY_CHANGED}';
|
|
688
|
+
END IF;
|
|
689
|
+
EXECUTE ${quoteStringLiteral(buildDropSchemaSql(drop.name, drop.cascade))};
|
|
690
|
+
END`;
|
|
691
|
+
return `DO ${quoteStringLiteral(body)}`;
|
|
692
|
+
};
|
|
693
|
+
var sqlStateOf = (error) => {
|
|
694
|
+
const cause = error.reason.cause;
|
|
695
|
+
const code = typeof cause === "object" && cause !== null ? cause.code : "";
|
|
696
|
+
return typeof code === "string" ? code : undefined;
|
|
697
|
+
};
|
|
698
|
+
var dependentsCount = (error) => {
|
|
699
|
+
const cause = error.reason.cause;
|
|
700
|
+
const message = typeof cause === "object" && cause !== null ? cause.message : "";
|
|
701
|
+
const parsed = /dependents:\s*(\d+)/.exec(message ?? "")?.[1];
|
|
702
|
+
return Math.max(1, Number(parsed ?? 1));
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
// src/postgres/schema-sequence-error.ts
|
|
706
|
+
import * as Data3 from "effect/Data";
|
|
707
|
+
|
|
708
|
+
class PostgresSchemaCascadeSequencesRefused extends Data3.TaggedError("PostgresSchemaCascadeSequencesRefused") {
|
|
709
|
+
get message() {
|
|
710
|
+
return `Postgres.Schema "${this.schema}": cascade: true refused — the schema holds ` + `${String(this.sequences)} sequence(s) (serial/identity columns own one), which cannot be ` + "locked, so a concurrent dependent could escape the cascade proof. No DROP was issued. " + "Drop the schema contents first, then declare cascade: false.";
|
|
568
711
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
712
|
+
}
|
|
713
|
+
var sequencesCount = (error) => {
|
|
714
|
+
const cause = error.reason.cause;
|
|
715
|
+
const message = typeof cause === "object" && cause !== null ? cause.message : "";
|
|
716
|
+
return Math.max(1, Number(/sequences:\s*(\d+)/.exec(message ?? "")?.[1] ?? 1));
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
// src/postgres/schema-delete.ts
|
|
720
|
+
var dropAtomic = (pg, props, live) => {
|
|
721
|
+
const cascade = props.cascade === true;
|
|
722
|
+
const classify = (error) => {
|
|
723
|
+
const state = sqlStateOf(error);
|
|
724
|
+
if (state === NOT_EMPTY || !cascade && isDependentObjectsError(error)) {
|
|
725
|
+
return Effect11.fail(new PostgresSchemaDropNotEmptyError({ schema: props.name }));
|
|
726
|
+
}
|
|
727
|
+
if (state === CROSS_SCHEMA_DEPENDENTS) {
|
|
728
|
+
return Effect11.fail(new PostgresSchemaCascadeCrossSchemaRefused({
|
|
729
|
+
schema: props.name,
|
|
730
|
+
dependents: dependentsCount(error)
|
|
731
|
+
}));
|
|
732
|
+
}
|
|
733
|
+
if (state === CASCADE_SEQUENCES) {
|
|
734
|
+
return Effect11.fail(new PostgresSchemaCascadeSequencesRefused({
|
|
735
|
+
schema: props.name,
|
|
736
|
+
sequences: sequencesCount(error)
|
|
737
|
+
}));
|
|
738
|
+
}
|
|
739
|
+
if (state === IDENTITY_CHANGED) {
|
|
740
|
+
return Effect11.flatMap(selectSchema(pg, props.name), (now) => now === undefined ? Effect11.void : Effect11.fail(new PostgresSchemaDeleteForeignRefused({
|
|
741
|
+
schema: props.name,
|
|
742
|
+
database: props.database,
|
|
743
|
+
liveOid: now.oid,
|
|
744
|
+
liveOwner: now.owner,
|
|
745
|
+
lastOid: live.oid,
|
|
746
|
+
lastOwner: live.owner
|
|
747
|
+
})));
|
|
748
|
+
}
|
|
749
|
+
return Effect11.fail(error);
|
|
750
|
+
};
|
|
751
|
+
return pg.unsafe(buildAtomicDropSql({ name: props.name, oid: live.oid, owner: live.owner, cascade })).pipe(Effect11.asVoid, Effect11.catchTag("SqlError", classify));
|
|
752
|
+
};
|
|
753
|
+
var deleteWithClient = (pg, props, output) => Effect11.gen(function* () {
|
|
573
754
|
yield* assertDatabase(props, pg);
|
|
574
755
|
const live = yield* selectSchema(pg, props.name);
|
|
575
756
|
if (live === undefined)
|
|
576
757
|
return;
|
|
577
758
|
const refusal = deleteForeignRefusal(props, live, output);
|
|
578
759
|
if (refusal !== undefined)
|
|
579
|
-
return yield*
|
|
580
|
-
yield*
|
|
760
|
+
return yield* Effect11.fail(refusal);
|
|
761
|
+
yield* dropAtomic(pg, props, live);
|
|
581
762
|
});
|
|
582
763
|
|
|
583
764
|
// src/postgres/schema.ts
|
|
@@ -587,9 +768,9 @@ var PostgresSchema = Resource2("Postgres.Schema", {
|
|
|
587
768
|
var isPostgresSchema = (value) => (typeof value === "object" || typeof value === "function") && value !== null && value.Type === "Postgres.Schema";
|
|
588
769
|
var readWithClient2 = (pg, name) => selectSchema(pg, name);
|
|
589
770
|
var postgresSchemaHandlers = PostgresSchema.Provider.of({
|
|
590
|
-
list: () =>
|
|
771
|
+
list: () => Effect12.succeed([]),
|
|
591
772
|
nuke: { skip: true },
|
|
592
|
-
read: ({ olds, output }) =>
|
|
773
|
+
read: ({ olds, output }) => Effect12.gen(function* () {
|
|
593
774
|
const name = output?.name ?? olds.name;
|
|
594
775
|
const database = output?.database ?? olds.database;
|
|
595
776
|
const present = yield* withPg((pg) => databaseExists(pg, database));
|
|
@@ -597,7 +778,7 @@ var postgresSchemaHandlers = PostgresSchema.Provider.of({
|
|
|
597
778
|
return;
|
|
598
779
|
const live = yield* withPg((pg) => readWithClient2(pg, name), database);
|
|
599
780
|
if (live !== undefined && live.database !== database) {
|
|
600
|
-
return yield*
|
|
781
|
+
return yield* Effect12.fail(new PostgresSchemaWrongDatabase({
|
|
601
782
|
schema: name,
|
|
602
783
|
declared: database,
|
|
603
784
|
connected: live.database
|
|
@@ -608,15 +789,15 @@ var postgresSchemaHandlers = PostgresSchema.Provider.of({
|
|
|
608
789
|
return live === undefined ? undefined : Unowned2(live);
|
|
609
790
|
}),
|
|
610
791
|
diff: ({ news, output, olds }) => diffPostgresSchema(news, output, olds),
|
|
611
|
-
reconcile: ({ news, output }) =>
|
|
792
|
+
reconcile: ({ news, output }) => Effect12.gen(function* () {
|
|
612
793
|
const nameRefusal = schemaNameByteRefusal(news.name);
|
|
613
794
|
if (nameRefusal !== undefined) {
|
|
614
|
-
return yield*
|
|
795
|
+
return yield* Effect12.fail(new PostgresSchemaNameRefused({ name: news.name, ...nameRefusal }));
|
|
615
796
|
}
|
|
616
797
|
yield* assertSchemaTarget(news, output);
|
|
617
798
|
return yield* withPg((pg) => reconcileWithClient2(pg, news, output), news.database);
|
|
618
799
|
}),
|
|
619
|
-
delete: ({ olds, output }) =>
|
|
800
|
+
delete: ({ olds, output }) => Effect12.gen(function* () {
|
|
620
801
|
const present = yield* withPg((pg) => databaseExists(pg, olds.database));
|
|
621
802
|
if (!present)
|
|
622
803
|
return;
|
|
@@ -706,7 +887,7 @@ var revokePublicTablesSql = (schema) => `REVOKE ALL ON ALL TABLES IN SCHEMA ${qu
|
|
|
706
887
|
import { Resource as Resource3 } from "alchemy";
|
|
707
888
|
import { Unowned as Unowned3 } from "alchemy/AdoptPolicy";
|
|
708
889
|
import * as Provider3 from "alchemy/Provider";
|
|
709
|
-
import * as
|
|
890
|
+
import * as Effect18 from "effect/Effect";
|
|
710
891
|
|
|
711
892
|
// src/postgres/grants-declare.ts
|
|
712
893
|
var cleanWords = (words) => [...new Set(words)].sort();
|
|
@@ -781,7 +962,7 @@ var removedNames = (output, declared) => {
|
|
|
781
962
|
};
|
|
782
963
|
|
|
783
964
|
// src/postgres/grants-ops.ts
|
|
784
|
-
import * as
|
|
965
|
+
import * as Effect17 from "effect/Effect";
|
|
785
966
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
786
967
|
|
|
787
968
|
// src/postgres/grants-refuse.ts
|
|
@@ -1038,72 +1219,72 @@ var grantsDiffer = (declared, live) => {
|
|
|
1038
1219
|
};
|
|
1039
1220
|
|
|
1040
1221
|
// src/postgres/grants-existence.ts
|
|
1041
|
-
import * as
|
|
1222
|
+
import * as Effect13 from "effect/Effect";
|
|
1042
1223
|
|
|
1043
1224
|
// src/postgres/grants-errors.ts
|
|
1044
|
-
import * as
|
|
1225
|
+
import * as Data4 from "effect/Data";
|
|
1045
1226
|
|
|
1046
|
-
class PostgresGrantsPrivilegeRefused extends
|
|
1227
|
+
class PostgresGrantsPrivilegeRefused extends Data4.TaggedError("PostgresGrantsPrivilegeRefused") {
|
|
1047
1228
|
get message() {
|
|
1048
1229
|
return `Postgres.Grants: "${this.prop}" declares "${this.word}", which is not in the vocabulary ` + "PostgreSQL 18 grants on that object class (see grants-attrs.ts for the three sets, traced " + "to acl.h at REL_18_6). Column grants take select/insert/update/references only — TRUNCATE, " + "TRIGGER and MAINTAIN are table-wide.";
|
|
1049
1230
|
}
|
|
1050
1231
|
}
|
|
1051
1232
|
|
|
1052
|
-
class PostgresGrantsNameRefused extends
|
|
1233
|
+
class PostgresGrantsNameRefused extends Data4.TaggedError("PostgresGrantsNameRefused") {
|
|
1053
1234
|
get message() {
|
|
1054
1235
|
return `Postgres.Grants: the name "${this.name}" is ${String(this.byteLength)} UTF-8 bytes, over the ` + `${String(this.limit)}-byte limit (NAMEDATALEN 64, minus the terminator). PostgreSQL would ` + "accept the statement and silently truncate the name with only a NOTICE, so this plan refuses " + "it instead of granting on an object no later read will ever find again.";
|
|
1055
1236
|
}
|
|
1056
1237
|
}
|
|
1057
1238
|
|
|
1058
|
-
class PostgresGrantsDuplicateObject extends
|
|
1239
|
+
class PostgresGrantsDuplicateObject extends Data4.TaggedError("PostgresGrantsDuplicateObject") {
|
|
1059
1240
|
get message() {
|
|
1060
1241
|
return `Postgres.Grants: "${this.prop}" declares "${this.name}" twice. Merge the entries into one — ` + "the declaration must state each object at most once, and each privilege word in exactly one " + "form: plain, or WITH GRANT OPTION (`select` and `select*` cannot both hold, the server keeps " + "one aclitem per grantee per grantor).";
|
|
1061
1242
|
}
|
|
1062
1243
|
}
|
|
1063
1244
|
|
|
1064
|
-
class PostgresGrantsRetargetRefused extends
|
|
1245
|
+
class PostgresGrantsRetargetRefused extends Data4.TaggedError("PostgresGrantsRetargetRefused") {
|
|
1065
1246
|
get message() {
|
|
1066
1247
|
return `Postgres.Grants: the declared ${this.prop} changed from "${this.from}" to "${this.to}". A ` + "retarget is refused at plan — declare a new logical id for the new target and delete the old " + "one (its retain policy keeps the grants until a destroy revokes them).";
|
|
1067
1248
|
}
|
|
1068
1249
|
}
|
|
1069
1250
|
|
|
1070
|
-
class PostgresGrantsDatabaseMismatch extends
|
|
1251
|
+
class PostgresGrantsDatabaseMismatch extends Data4.TaggedError("PostgresGrantsDatabaseMismatch") {
|
|
1071
1252
|
get message() {
|
|
1072
1253
|
return `Postgres.Grants: the declaration names database "${this.declared}" but ` + `current_database() is "${this.connected}". The handlers open the declared database and ` + "prove it before any GRANT or REVOKE — a mismatch means that open did not land there.";
|
|
1073
1254
|
}
|
|
1074
1255
|
}
|
|
1075
1256
|
|
|
1076
|
-
class PostgresGrantsSchemaMissing extends
|
|
1257
|
+
class PostgresGrantsSchemaMissing extends Data4.TaggedError("PostgresGrantsSchemaMissing") {
|
|
1077
1258
|
get message() {
|
|
1078
1259
|
return `Postgres.Grants: schema "${this.schema}" is not in pg_namespace. Grants are written into a ` + "schema that already exists — declare a Postgres.Schema (or create it by hand) before the " + "grant set that scopes to it.";
|
|
1079
1260
|
}
|
|
1080
1261
|
}
|
|
1081
1262
|
|
|
1082
|
-
class PostgresGrantsDatabaseMissing extends
|
|
1263
|
+
class PostgresGrantsDatabaseMissing extends Data4.TaggedError("PostgresGrantsDatabaseMissing") {
|
|
1083
1264
|
get message() {
|
|
1084
1265
|
return `Postgres.Grants: database "${this.database}" is not in pg_database. Grants are written into ` + "a database that already exists — declare a Postgres.Database (or create it by hand) before " + "the grant set that scopes to it.";
|
|
1085
1266
|
}
|
|
1086
1267
|
}
|
|
1087
1268
|
|
|
1088
|
-
class PostgresGrantsRoleMissing extends
|
|
1269
|
+
class PostgresGrantsRoleMissing extends Data4.TaggedError("PostgresGrantsRoleMissing") {
|
|
1089
1270
|
get message() {
|
|
1090
1271
|
return `Postgres.Grants: role "${this.role}" is not in pg_roles. GRANT and ALTER DEFAULT PRIVILEGES ` + "would fail against it — create the role (a group role per seat, membership owned by a human) " + "before declaring its grants.";
|
|
1091
1272
|
}
|
|
1092
1273
|
}
|
|
1093
1274
|
|
|
1094
|
-
class PostgresGrantsTableMissing extends
|
|
1275
|
+
class PostgresGrantsTableMissing extends Data4.TaggedError("PostgresGrantsTableMissing") {
|
|
1095
1276
|
get message() {
|
|
1096
1277
|
return `Postgres.Grants: table "${this.schema}"."${this.table}" does not exist. The declaration ` + "names a relation before it is created; create the table (or fix the name) before granting.";
|
|
1097
1278
|
}
|
|
1098
1279
|
}
|
|
1099
1280
|
|
|
1100
|
-
class PostgresGrantsColumnMissing extends
|
|
1281
|
+
class PostgresGrantsColumnMissing extends Data4.TaggedError("PostgresGrantsColumnMissing") {
|
|
1101
1282
|
get message() {
|
|
1102
1283
|
return `Postgres.Grants: column "${this.column}" of "${this.schema}"."${this.table}" does not ` + "exist. Declare the column (or fix its name) before granting on it.";
|
|
1103
1284
|
}
|
|
1104
1285
|
}
|
|
1105
1286
|
|
|
1106
|
-
class PostgresGrantsRepairRefused extends
|
|
1287
|
+
class PostgresGrantsRepairRefused extends Data4.TaggedError("PostgresGrantsRepairRefused") {
|
|
1107
1288
|
get message() {
|
|
1108
1289
|
return `Postgres.Grants: the repair on schema "${this.schema}" for role "${this.role}" re-read as ` + `still drifted; these statements would run again: ${this.remaining.join(" ; ")}. A grant made ` + "by another role survives this resource’s REVOKE (only its grantor or the object’s " + "owner can revoke it) — revoke it as that grantor or the owner, or declare the privilege so " + "the set matches.";
|
|
1109
1290
|
}
|
|
@@ -1112,39 +1293,39 @@ class PostgresGrantsRepairRefused extends Data3.TaggedError("PostgresGrantsRepai
|
|
|
1112
1293
|
// src/postgres/grants-existence.ts
|
|
1113
1294
|
var TABLES_PRESENT_SQL = `SELECT
|
|
1114
1295
|
c.relname AS table
|
|
1115
|
-
FROM pg_class c
|
|
1116
|
-
WHERE c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $1)
|
|
1117
|
-
AND c.relname::text IN (SELECT json_array_elements_text($2::json))`;
|
|
1118
|
-
var findMissingTable = (pg, schema, tables) => tables.length === 0 ?
|
|
1296
|
+
FROM pg_catalog.pg_class c
|
|
1297
|
+
WHERE c.relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
1298
|
+
AND c.relname::text IN (SELECT pg_catalog.json_array_elements_text($2::json))`;
|
|
1299
|
+
var findMissingTable = (pg, schema, tables) => tables.length === 0 ? Effect13.succeed(undefined) : Effect13.map(pg.unsafe(TABLES_PRESENT_SQL, [schema, JSON.stringify(tables)]), (rows) => {
|
|
1119
1300
|
const present = new Set(rows.map((row) => row.table));
|
|
1120
1301
|
return tables.find((table) => !present.has(table));
|
|
1121
1302
|
});
|
|
1122
1303
|
var COLUMNS_PRESENT_SQL = `SELECT
|
|
1123
1304
|
c.relname AS table,
|
|
1124
1305
|
a.attname AS column
|
|
1125
|
-
FROM pg_attribute a
|
|
1126
|
-
JOIN pg_class c ON c.oid = a.attrelid
|
|
1127
|
-
WHERE c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $1)
|
|
1306
|
+
FROM pg_catalog.pg_attribute a
|
|
1307
|
+
JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
|
|
1308
|
+
WHERE c.relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
1128
1309
|
AND a.attnum > 0
|
|
1129
1310
|
AND NOT a.attisdropped
|
|
1130
1311
|
AND (c.relname, a.attname) IN (
|
|
1131
|
-
SELECT x->>0, x->>1 FROM json_array_elements($2::json) x
|
|
1312
|
+
SELECT x->>0, x->>1 FROM pg_catalog.json_array_elements($2::json) x
|
|
1132
1313
|
)`;
|
|
1133
|
-
var findMissingColumn = (pg, schema, columns) => columns.length === 0 ?
|
|
1314
|
+
var findMissingColumn = (pg, schema, columns) => columns.length === 0 ? Effect13.succeed(undefined) : Effect13.map(pg.unsafe(COLUMNS_PRESENT_SQL, [
|
|
1134
1315
|
schema,
|
|
1135
1316
|
JSON.stringify(columns.map(({ table, column }) => [table, column]))
|
|
1136
1317
|
]), (rows) => {
|
|
1137
1318
|
const present = new Set(rows.map((row) => `${row.table}\x00${row.column}`));
|
|
1138
1319
|
return columns.find(({ table, column }) => !present.has(`${table}\x00${column}`));
|
|
1139
1320
|
});
|
|
1140
|
-
var requireDeclaredObjectsExist = (pg, declared) =>
|
|
1321
|
+
var requireDeclaredObjectsExist = (pg, declared) => Effect13.gen(function* () {
|
|
1141
1322
|
const missingTable = yield* findMissingTable(pg, declared.schema, declared.tables.map((table) => table.table));
|
|
1142
1323
|
if (missingTable !== undefined) {
|
|
1143
|
-
return yield*
|
|
1324
|
+
return yield* Effect13.fail(new PostgresGrantsTableMissing({ schema: declared.schema, table: missingTable }));
|
|
1144
1325
|
}
|
|
1145
1326
|
const missingColumn = yield* findMissingColumn(pg, declared.schema, declared.columns.map((column) => ({ table: column.table, column: column.column })));
|
|
1146
1327
|
if (missingColumn !== undefined) {
|
|
1147
|
-
return yield*
|
|
1328
|
+
return yield* Effect13.fail(new PostgresGrantsColumnMissing({
|
|
1148
1329
|
schema: declared.schema,
|
|
1149
1330
|
table: missingColumn.table,
|
|
1150
1331
|
column: missingColumn.column
|
|
@@ -1153,35 +1334,35 @@ var requireDeclaredObjectsExist = (pg, declared) => Effect12.gen(function* () {
|
|
|
1153
1334
|
});
|
|
1154
1335
|
|
|
1155
1336
|
// src/postgres/grants-read.ts
|
|
1156
|
-
import * as
|
|
1337
|
+
import * as Effect16 from "effect/Effect";
|
|
1157
1338
|
|
|
1158
1339
|
// src/postgres/grants-ownership.ts
|
|
1159
|
-
import * as
|
|
1340
|
+
import * as Effect14 from "effect/Effect";
|
|
1160
1341
|
var SCHEMA_OWNER_SQL = `SELECT
|
|
1161
|
-
n.nspowner = (SELECT oid FROM pg_roles WHERE rolname = $2) AS role_owns
|
|
1162
|
-
FROM pg_namespace n
|
|
1342
|
+
n.nspowner = (SELECT oid FROM pg_catalog.pg_roles WHERE rolname = $2) AS role_owns
|
|
1343
|
+
FROM pg_catalog.pg_namespace n
|
|
1163
1344
|
WHERE n.nspname = $1`;
|
|
1164
|
-
var readSchemaOwnership = (pg, schema, role) =>
|
|
1345
|
+
var readSchemaOwnership = (pg, schema, role) => Effect14.map(pg.unsafe(SCHEMA_OWNER_SQL, [schema, role]), (rows) => rows[0]?.role_owns === true);
|
|
1165
1346
|
var OWNED_TABLES_SQL = `SELECT c.relname AS table
|
|
1166
|
-
FROM pg_class c
|
|
1167
|
-
WHERE c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $1)
|
|
1168
|
-
AND c.relowner = (SELECT oid FROM pg_roles WHERE rolname = $2)
|
|
1347
|
+
FROM pg_catalog.pg_class c
|
|
1348
|
+
WHERE c.relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
1349
|
+
AND c.relowner = (SELECT oid FROM pg_catalog.pg_roles WHERE rolname = $2)
|
|
1169
1350
|
ORDER BY c.relname`;
|
|
1170
|
-
var readOwnedTables = (pg, schema, role) =>
|
|
1351
|
+
var readOwnedTables = (pg, schema, role) => Effect14.map(pg.unsafe(OWNED_TABLES_SQL, [schema, role]), (rows) => rows.map((row) => row.table).sort((a, b) => a.localeCompare(b)));
|
|
1171
1352
|
|
|
1172
1353
|
// src/postgres/grants-read-defaults.ts
|
|
1173
|
-
import * as
|
|
1354
|
+
import * as Effect15 from "effect/Effect";
|
|
1174
1355
|
var DEFAULTS_SQL = `SELECT
|
|
1175
|
-
pg_get_userbyid(d.defaclrole) AS for_role,
|
|
1356
|
+
pg_catalog.pg_get_userbyid(d.defaclrole) AS for_role,
|
|
1176
1357
|
a.privilege_type AS privilege,
|
|
1177
1358
|
a.is_grantable AS grantable
|
|
1178
|
-
FROM pg_default_acl d
|
|
1179
|
-
CROSS JOIN LATERAL aclexplode(d.defaclacl) AS a
|
|
1180
|
-
WHERE d.defaclnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $1)
|
|
1359
|
+
FROM pg_catalog.pg_default_acl d
|
|
1360
|
+
CROSS JOIN LATERAL pg_catalog.aclexplode(d.defaclacl) AS a
|
|
1361
|
+
WHERE d.defaclnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
1181
1362
|
AND d.defaclobjtype = 'r'
|
|
1182
|
-
AND a.grantee = (SELECT oid FROM pg_roles WHERE rolname = $2)
|
|
1363
|
+
AND a.grantee = (SELECT oid FROM pg_catalog.pg_roles WHERE rolname = $2)
|
|
1183
1364
|
ORDER BY for_role`;
|
|
1184
|
-
var readDefaultAcls = (pg, schema, role) =>
|
|
1365
|
+
var readDefaultAcls = (pg, schema, role) => Effect15.map(pg.unsafe(DEFAULTS_SQL, [schema, role]), (rows) => {
|
|
1185
1366
|
const byRole = new Map;
|
|
1186
1367
|
for (const row of rows) {
|
|
1187
1368
|
const words = byRole.get(row.for_role) ?? [];
|
|
@@ -1192,17 +1373,17 @@ var readDefaultAcls = (pg, schema, role) => Effect14.map(pg.unsafe(DEFAULTS_SQL,
|
|
|
1192
1373
|
});
|
|
1193
1374
|
|
|
1194
1375
|
// src/postgres/grants-read.ts
|
|
1195
|
-
var SCHEMA_PRESENT_SQL = "SELECT 1 AS present FROM pg_namespace WHERE nspname = $1";
|
|
1196
|
-
var schemaExists = (pg, schema) =>
|
|
1376
|
+
var SCHEMA_PRESENT_SQL = "SELECT 1 AS present FROM pg_catalog.pg_namespace WHERE nspname = $1";
|
|
1377
|
+
var schemaExists = (pg, schema) => Effect16.map(pg.unsafe(SCHEMA_PRESENT_SQL, [schema]), (rows) => rows.length > 0);
|
|
1197
1378
|
var SCHEMA_ACL_SQL = `SELECT
|
|
1198
1379
|
a.grantee = 0 AS public,
|
|
1199
1380
|
a.privilege_type AS privilege,
|
|
1200
1381
|
a.is_grantable AS grantable
|
|
1201
|
-
FROM pg_namespace n
|
|
1202
|
-
CROSS JOIN LATERAL aclexplode(n.nspacl) AS a
|
|
1382
|
+
FROM pg_catalog.pg_namespace n
|
|
1383
|
+
CROSS JOIN LATERAL pg_catalog.aclexplode(n.nspacl) AS a
|
|
1203
1384
|
WHERE n.nspname = $1
|
|
1204
|
-
AND (a.grantee = 0 OR a.grantee = (SELECT oid FROM pg_roles WHERE rolname = $2))`;
|
|
1205
|
-
var readSchemaAcl = (pg, schema, role) =>
|
|
1385
|
+
AND (a.grantee = 0 OR a.grantee = (SELECT oid FROM pg_catalog.pg_roles WHERE rolname = $2))`;
|
|
1386
|
+
var readSchemaAcl = (pg, schema, role) => Effect16.map(pg.unsafe(SCHEMA_ACL_SQL, [schema, role]), (rows) => ({
|
|
1206
1387
|
role: wordsOf(rows, false),
|
|
1207
1388
|
public: wordsOf(rows, true)
|
|
1208
1389
|
}));
|
|
@@ -1212,12 +1393,12 @@ var TABLES_SQL = `SELECT
|
|
|
1212
1393
|
a.grantee = 0 AS public,
|
|
1213
1394
|
a.privilege_type AS privilege,
|
|
1214
1395
|
a.is_grantable AS grantable
|
|
1215
|
-
FROM pg_class c
|
|
1216
|
-
CROSS JOIN LATERAL aclexplode(c.relacl) AS a
|
|
1217
|
-
WHERE c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $1)
|
|
1218
|
-
AND (a.grantee = 0 OR a.grantee = (SELECT oid FROM pg_roles WHERE rolname = $2))
|
|
1396
|
+
FROM pg_catalog.pg_class c
|
|
1397
|
+
CROSS JOIN LATERAL pg_catalog.aclexplode(c.relacl) AS a
|
|
1398
|
+
WHERE c.relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
1399
|
+
AND (a.grantee = 0 OR a.grantee = (SELECT oid FROM pg_catalog.pg_roles WHERE rolname = $2))
|
|
1219
1400
|
ORDER BY c.relname`;
|
|
1220
|
-
var readTableAcls = (pg, schema, role) =>
|
|
1401
|
+
var readTableAcls = (pg, schema, role) => Effect16.map(pg.unsafe(TABLES_SQL, [
|
|
1221
1402
|
schema,
|
|
1222
1403
|
role
|
|
1223
1404
|
]), (rows) => {
|
|
@@ -1240,19 +1421,19 @@ var COLUMNS_SQL = `SELECT
|
|
|
1240
1421
|
a.grantee = 0 AS public,
|
|
1241
1422
|
a.privilege_type AS privilege,
|
|
1242
1423
|
a.is_grantable AS grantable,
|
|
1243
|
-
pg_get_userbyid(a.grantor) AS grantor,
|
|
1244
|
-
pg_get_userbyid(c.relowner) AS owner,
|
|
1424
|
+
pg_catalog.pg_get_userbyid(a.grantor) AS grantor,
|
|
1425
|
+
pg_catalog.pg_get_userbyid(c.relowner) AS owner,
|
|
1245
1426
|
current_user AS revoker,
|
|
1246
|
-
pg_has_role(current_user, c.relowner, 'USAGE') AS revoker_as_owner
|
|
1247
|
-
FROM pg_attribute v
|
|
1248
|
-
JOIN pg_class c ON c.oid = v.attrelid
|
|
1249
|
-
CROSS JOIN LATERAL aclexplode(v.attacl) AS a
|
|
1250
|
-
WHERE c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $1)
|
|
1427
|
+
pg_catalog.pg_has_role(current_user, c.relowner, 'USAGE') AS revoker_as_owner
|
|
1428
|
+
FROM pg_catalog.pg_attribute v
|
|
1429
|
+
JOIN pg_catalog.pg_class c ON c.oid = v.attrelid
|
|
1430
|
+
CROSS JOIN LATERAL pg_catalog.aclexplode(v.attacl) AS a
|
|
1431
|
+
WHERE c.relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $1)
|
|
1251
1432
|
AND v.attnum > 0
|
|
1252
1433
|
AND NOT v.attisdropped
|
|
1253
|
-
AND (a.grantee = 0 OR a.grantee = (SELECT oid FROM pg_roles WHERE rolname = $2))
|
|
1434
|
+
AND (a.grantee = 0 OR a.grantee = (SELECT oid FROM pg_catalog.pg_roles WHERE rolname = $2))
|
|
1254
1435
|
ORDER BY c.relname, v.attname`;
|
|
1255
|
-
var readColumnAcls = (pg, schema, role) =>
|
|
1436
|
+
var readColumnAcls = (pg, schema, role) => Effect16.map(pg.unsafe(COLUMNS_SQL, [schema, role]), (rows) => {
|
|
1256
1437
|
const byColumn = new Map;
|
|
1257
1438
|
for (const row of rows) {
|
|
1258
1439
|
const key = `${row.table}\x00${row.column}`;
|
|
@@ -1275,7 +1456,7 @@ var readColumnAcls = (pg, schema, role) => Effect15.map(pg.unsafe(COLUMNS_SQL, [
|
|
|
1275
1456
|
};
|
|
1276
1457
|
}).sort((a, b) => a.table.localeCompare(b.table) || a.column.localeCompare(b.column));
|
|
1277
1458
|
});
|
|
1278
|
-
var readGrants = (pg, schema, role) =>
|
|
1459
|
+
var readGrants = (pg, schema, role) => Effect16.all({
|
|
1279
1460
|
schemaExists: schemaExists(pg, schema),
|
|
1280
1461
|
schema: readSchemaAcl(pg, schema, role),
|
|
1281
1462
|
tables: readTableAcls(pg, schema, role),
|
|
@@ -1286,8 +1467,8 @@ var readGrants = (pg, schema, role) => Effect15.all({
|
|
|
1286
1467
|
});
|
|
1287
1468
|
|
|
1288
1469
|
// src/postgres/grants-ops.ts
|
|
1289
|
-
var failRefusal = (refusal) => refusal.kind === "privilege" ?
|
|
1290
|
-
var proveDatabase = (pg, declared) =>
|
|
1470
|
+
var failRefusal = (refusal) => refusal.kind === "privilege" ? Effect17.fail(new PostgresGrantsPrivilegeRefused({ prop: refusal.prop, word: refusal.word })) : Effect17.fail(new PostgresGrantsDuplicateObject({ prop: refusal.prop, name: refusal.name }));
|
|
1471
|
+
var proveDatabase = (pg, declared) => Effect17.flatMap(currentDatabase(pg), (connected) => connected === declared ? Effect17.void : Effect17.fail(new PostgresGrantsDatabaseMismatch({ declared, connected })));
|
|
1291
1472
|
var refuseNames = (props) => {
|
|
1292
1473
|
const declared = resolveProps(props);
|
|
1293
1474
|
const names = grantsNamesRefusal(declared);
|
|
@@ -1297,30 +1478,30 @@ var refuseNames = (props) => {
|
|
|
1297
1478
|
limit: names.limit
|
|
1298
1479
|
});
|
|
1299
1480
|
};
|
|
1300
|
-
var reconcileWithClient3 = (pg, props, output) =>
|
|
1481
|
+
var reconcileWithClient3 = (pg, props, output) => Effect17.gen(function* () {
|
|
1301
1482
|
const declared = resolveProps(props);
|
|
1302
1483
|
const declRefusal = declarationRefusal(declared);
|
|
1303
1484
|
if (declRefusal !== undefined)
|
|
1304
1485
|
return yield* failRefusal(declRefusal);
|
|
1305
1486
|
const nameRefusal = refuseNames(props);
|
|
1306
1487
|
if (nameRefusal !== undefined)
|
|
1307
|
-
return yield*
|
|
1488
|
+
return yield* Effect17.fail(nameRefusal);
|
|
1308
1489
|
for (const [prop, from, to] of [
|
|
1309
1490
|
["role", output?.role, declared.role],
|
|
1310
1491
|
["database", output?.database, declared.database],
|
|
1311
1492
|
["schema", output?.schema, declared.schema]
|
|
1312
1493
|
]) {
|
|
1313
1494
|
if (from !== undefined && from !== to) {
|
|
1314
|
-
return yield*
|
|
1495
|
+
return yield* Effect17.fail(new PostgresGrantsRetargetRefused({ prop, from, to }));
|
|
1315
1496
|
}
|
|
1316
1497
|
}
|
|
1317
1498
|
yield* proveDatabase(pg, declared.database);
|
|
1318
1499
|
if (!(yield* schemaExists(pg, declared.schema))) {
|
|
1319
|
-
return yield*
|
|
1500
|
+
return yield* Effect17.fail(new PostgresGrantsSchemaMissing({ schema: declared.schema }));
|
|
1320
1501
|
}
|
|
1321
1502
|
for (const role of [declared.role, ...declared.defaults.map((entry) => entry.forRole)]) {
|
|
1322
1503
|
if (!(yield* roleExists(pg, role))) {
|
|
1323
|
-
return yield*
|
|
1504
|
+
return yield* Effect17.fail(new PostgresGrantsRoleMissing({ role }));
|
|
1324
1505
|
}
|
|
1325
1506
|
}
|
|
1326
1507
|
yield* requireDeclaredObjectsExist(pg, declared);
|
|
@@ -1332,7 +1513,7 @@ var reconcileWithClient3 = (pg, props, output) => Effect16.gen(function* () {
|
|
|
1332
1513
|
const after = yield* readGrants(pg, declared.schema, declared.role);
|
|
1333
1514
|
const remaining = planReconcile(declared, after, removed);
|
|
1334
1515
|
if (remaining.length > 0) {
|
|
1335
|
-
return yield*
|
|
1516
|
+
return yield* Effect17.fail(new PostgresGrantsRepairRefused({
|
|
1336
1517
|
schema: declared.schema,
|
|
1337
1518
|
role: declared.role,
|
|
1338
1519
|
remaining
|
|
@@ -1340,7 +1521,7 @@ var reconcileWithClient3 = (pg, props, output) => Effect16.gen(function* () {
|
|
|
1340
1521
|
}
|
|
1341
1522
|
return attributesOf(after, declaredNames(declared));
|
|
1342
1523
|
});
|
|
1343
|
-
var readWithClient3 = (pg, names, stored) =>
|
|
1524
|
+
var readWithClient3 = (pg, names, stored) => Effect17.gen(function* () {
|
|
1344
1525
|
yield* proveDatabase(pg, names.database);
|
|
1345
1526
|
if (!(yield* schemaExists(pg, names.schema)))
|
|
1346
1527
|
return;
|
|
@@ -1349,7 +1530,7 @@ var readWithClient3 = (pg, names, stored) => Effect16.gen(function* () {
|
|
|
1349
1530
|
const holdsAnything = projected.schemaPrivileges.length > 0 || projected.tables.some((table) => table.privileges.length > 0) || projected.columns.some((column) => column.privileges.length > 0) || projected.defaults.some((entry) => entry.privileges.length > 0);
|
|
1350
1531
|
return stored || holdsAnything ? projected : undefined;
|
|
1351
1532
|
});
|
|
1352
|
-
var deleteWithClient2 = (pg, props) =>
|
|
1533
|
+
var deleteWithClient2 = (pg, props) => Effect17.gen(function* () {
|
|
1353
1534
|
yield* proveDatabase(pg, props.database);
|
|
1354
1535
|
if (!(yield* roleExists(pg, props.role)))
|
|
1355
1536
|
return;
|
|
@@ -1363,14 +1544,14 @@ var deleteWithClient2 = (pg, props) => Effect16.gen(function* () {
|
|
|
1363
1544
|
const after = yield* readGrants(pg, cleared.schema, cleared.role);
|
|
1364
1545
|
const remaining = planRepair(cleared, after);
|
|
1365
1546
|
if (remaining.length > 0) {
|
|
1366
|
-
return yield*
|
|
1547
|
+
return yield* Effect17.fail(new PostgresGrantsRepairRefused({
|
|
1367
1548
|
schema: cleared.schema,
|
|
1368
1549
|
role: cleared.role,
|
|
1369
1550
|
remaining
|
|
1370
1551
|
}));
|
|
1371
1552
|
}
|
|
1372
1553
|
});
|
|
1373
|
-
var diffPostgresGrants = (news, output) =>
|
|
1554
|
+
var diffPostgresGrants = (news, output) => Effect17.gen(function* () {
|
|
1374
1555
|
if (output === undefined || !isResolved3(news))
|
|
1375
1556
|
return;
|
|
1376
1557
|
const declared = resolveProps(news);
|
|
@@ -1380,12 +1561,12 @@ var diffPostgresGrants = (news, output) => Effect16.gen(function* () {
|
|
|
1380
1561
|
["schema", output.schema, declared.schema]
|
|
1381
1562
|
]) {
|
|
1382
1563
|
if (from !== to) {
|
|
1383
|
-
return yield*
|
|
1564
|
+
return yield* Effect17.fail(new PostgresGrantsRetargetRefused({ prop, from, to }));
|
|
1384
1565
|
}
|
|
1385
1566
|
}
|
|
1386
1567
|
const nameRefusal = refuseNames(news);
|
|
1387
1568
|
if (nameRefusal !== undefined)
|
|
1388
|
-
return yield*
|
|
1569
|
+
return yield* Effect17.fail(nameRefusal);
|
|
1389
1570
|
const declRefusal = declarationRefusal(declared);
|
|
1390
1571
|
if (declRefusal !== undefined)
|
|
1391
1572
|
return yield* failRefusal(declRefusal);
|
|
@@ -1398,9 +1579,9 @@ var PostgresGrants = Resource3("Postgres.Grants", {
|
|
|
1398
1579
|
});
|
|
1399
1580
|
var isPostgresGrants = (value) => (typeof value === "object" || typeof value === "function") && value !== null && value.Type === "Postgres.Grants";
|
|
1400
1581
|
var postgresGrantsHandlers = PostgresGrants.Provider.of({
|
|
1401
|
-
list: () =>
|
|
1582
|
+
list: () => Effect18.succeed([]),
|
|
1402
1583
|
nuke: { skip: true },
|
|
1403
|
-
read: ({ olds, output }) =>
|
|
1584
|
+
read: ({ olds, output }) => Effect18.gen(function* () {
|
|
1404
1585
|
const names = output !== undefined ? namesFromAttrs(output) : declaredNames(resolveProps(olds));
|
|
1405
1586
|
const present = yield* withPg((pg) => databaseExists(pg, names.database));
|
|
1406
1587
|
if (!present)
|
|
@@ -1409,14 +1590,14 @@ var postgresGrantsHandlers = PostgresGrants.Provider.of({
|
|
|
1409
1590
|
return live === undefined ? undefined : Unowned3(live);
|
|
1410
1591
|
}),
|
|
1411
1592
|
diff: ({ news, output }) => diffPostgresGrants(news, output),
|
|
1412
|
-
reconcile: ({ news, output }) =>
|
|
1593
|
+
reconcile: ({ news, output }) => Effect18.gen(function* () {
|
|
1413
1594
|
const present = yield* withPg((pg) => databaseExists(pg, news.database));
|
|
1414
1595
|
if (!present) {
|
|
1415
|
-
return yield*
|
|
1596
|
+
return yield* Effect18.fail(new PostgresGrantsDatabaseMissing({ database: news.database }));
|
|
1416
1597
|
}
|
|
1417
1598
|
return yield* withPg((pg) => reconcileWithClient3(pg, news, output), news.database);
|
|
1418
1599
|
}),
|
|
1419
|
-
delete: ({ olds }) =>
|
|
1600
|
+
delete: ({ olds }) => Effect18.gen(function* () {
|
|
1420
1601
|
const present = yield* withPg((pg) => databaseExists(pg, olds.database));
|
|
1421
1602
|
if (!present)
|
|
1422
1603
|
return;
|
|
@@ -1435,70 +1616,70 @@ var validUntilRefusal = (value) => {
|
|
|
1435
1616
|
};
|
|
1436
1617
|
var sameValidUntil = (declared, live) => live !== null && Date.parse(declared) === Date.parse(live);
|
|
1437
1618
|
// src/postgres/role-sql.ts
|
|
1438
|
-
import * as
|
|
1619
|
+
import * as Effect20 from "effect/Effect";
|
|
1439
1620
|
|
|
1440
1621
|
// src/postgres/role-membership-sql.ts
|
|
1441
|
-
import * as
|
|
1622
|
+
import * as Effect19 from "effect/Effect";
|
|
1442
1623
|
|
|
1443
1624
|
// src/postgres/role-errors.ts
|
|
1444
|
-
import * as
|
|
1625
|
+
import * as Data5 from "effect/Data";
|
|
1445
1626
|
|
|
1446
|
-
class PostgresRoleNameRefused extends
|
|
1627
|
+
class PostgresRoleNameRefused extends Data5.TaggedError("PostgresRoleNameRefused") {
|
|
1447
1628
|
get message() {
|
|
1448
1629
|
return `Postgres.Role "${this.name}": ${String(this.byteLength)} UTF-8 bytes, over the ` + `${String(this.limit)}-byte limit (NAMEDATALEN 64, minus the terminator). PostgreSQL would ` + "accept the CREATE and silently truncate the name with only a NOTICE, so this plan refuses " + "it instead of creating a role no later read will ever find again.";
|
|
1449
1630
|
}
|
|
1450
1631
|
}
|
|
1451
1632
|
|
|
1452
|
-
class PostgresRoleRenameRefused extends
|
|
1633
|
+
class PostgresRoleRenameRefused extends Data5.TaggedError("PostgresRoleRenameRefused") {
|
|
1453
1634
|
get message() {
|
|
1454
1635
|
return `Postgres.Role: the declared name changed from "${this.from}" to "${this.to}". A ` + "rename is refused at plan — this provider never replaces a role (that is DROP then " + "CREATE, which loses memberships, grants and ownerships). Declare a new logical id for " + "the new name, and remove the old one once its objects have moved.";
|
|
1455
1636
|
}
|
|
1456
1637
|
}
|
|
1457
1638
|
|
|
1458
|
-
class PostgresRolePasswordEnvUnsetError extends
|
|
1639
|
+
class PostgresRolePasswordEnvUnsetError extends Data5.TaggedError("PostgresRolePasswordEnvUnsetError") {
|
|
1459
1640
|
get message() {
|
|
1460
1641
|
return `Postgres.Role "${this.role}": password.fromEnv "${this.variable}" is unset or empty ` + "in the deploying process, but this write requires a password this stack has not sealed.";
|
|
1461
1642
|
}
|
|
1462
1643
|
}
|
|
1463
1644
|
|
|
1464
|
-
class PostgresRolePrivilegedRefused extends
|
|
1645
|
+
class PostgresRolePrivilegedRefused extends Data5.TaggedError("PostgresRolePrivilegedRefused") {
|
|
1465
1646
|
get message() {
|
|
1466
1647
|
return `Postgres.Role "${this.role}": the live role has ${this.flags.join(", ")} set. This ` + "family never declares those attributes (a create lands on the server default, all off), " + "and they are not inherited — a member who SET ROLEs to this role would exercise them. " + "Clear the flag on the cluster before this stack adopts the role.";
|
|
1467
1648
|
}
|
|
1468
1649
|
}
|
|
1469
1650
|
|
|
1470
|
-
class PostgresRoleValidUntilRefused extends
|
|
1651
|
+
class PostgresRoleValidUntilRefused extends Data5.TaggedError("PostgresRoleValidUntilRefused") {
|
|
1471
1652
|
get message() {
|
|
1472
1653
|
return `Postgres.Role "${this.role}": validUntil "${this.value}" is ${this.reason === "unparseable" ? "not a timestamp this kit can parse" : "missing its UTC designator or numeric offset"}. ` + 'Declare an explicit-zone ISO 8601 value such as "2027-01-01T00:00:00Z" — PostgreSQL would ' + "read a zone-free value in the session time zone while the plan compares UTC, and the two " + "would never agree.";
|
|
1473
1654
|
}
|
|
1474
1655
|
}
|
|
1475
1656
|
|
|
1476
|
-
class PostgresRoleCreateVanished extends
|
|
1657
|
+
class PostgresRoleCreateVanished extends Data5.TaggedError("PostgresRoleCreateVanished") {
|
|
1477
1658
|
get message() {
|
|
1478
1659
|
return `Postgres.Role "${this.role}": CREATE ROLE raised no error, but the role is still ` + "absent on the immediate re-read. Re-plan — this is not a state this provider expects to reach.";
|
|
1479
1660
|
}
|
|
1480
1661
|
}
|
|
1481
1662
|
|
|
1482
|
-
class PostgresRoleMembershipUnrepaired extends
|
|
1663
|
+
class PostgresRoleMembershipUnrepaired extends Data5.TaggedError("PostgresRoleMembershipUnrepaired") {
|
|
1483
1664
|
get message() {
|
|
1484
1665
|
const who = this.grantor === null ? "an unresolvable grantor (inconsistent catalog)" : `grantor "${this.grantor}"`;
|
|
1485
1666
|
return `Postgres.Role "${this.role}": membership of "${this.parent}" ` + `(${this.declared ? "declared, options unsafe" : "not declared"}) could not be repaired ` + `under ${who}. The server refused the repair or the catalog re-read still found the row ` + "outside the declaration. pg_auth_members keys a membership on (parent, member, grantor). " + "Check dependent grants, executor permissions and grantor identity before re-planning.";
|
|
1486
1667
|
}
|
|
1487
1668
|
}
|
|
1488
1669
|
|
|
1489
|
-
class PostgresRoleParentMissing extends
|
|
1670
|
+
class PostgresRoleParentMissing extends Data5.TaggedError("PostgresRoleParentMissing") {
|
|
1490
1671
|
get message() {
|
|
1491
1672
|
return `Postgres.Role "${this.role}": memberOf parent "${this.parent}" does not exist. ` + "Nothing was written — declare that role first (or drop it from memberOf). A GRANT of a " + "missing role fails only after CREATE ROLE has committed, and the next plan then needs " + "--adopt to finish the orphan.";
|
|
1492
1673
|
}
|
|
1493
1674
|
}
|
|
1494
1675
|
|
|
1495
|
-
class PostgresRoleIdentityRefused extends
|
|
1676
|
+
class PostgresRoleIdentityRefused extends Data5.TaggedError("PostgresRoleIdentityRefused") {
|
|
1496
1677
|
get message() {
|
|
1497
1678
|
return `Postgres.Role "${this.role}": the live oid is ${String(this.liveOid)}, but state recorded ` + `${String(this.storedOid)}. The name was dropped and recreated outside this stack. Nothing ` + "was altered and the live role was not dropped — remove the stale state, or adopt the new " + "role under a new logical id once you mean to own it.";
|
|
1498
1679
|
}
|
|
1499
1680
|
}
|
|
1500
1681
|
|
|
1501
|
-
class PostgresRolePasswordNonAsciiRefused extends
|
|
1682
|
+
class PostgresRolePasswordNonAsciiRefused extends Data5.TaggedError("PostgresRolePasswordNonAsciiRefused") {
|
|
1502
1683
|
get message() {
|
|
1503
1684
|
return `Postgres.Role "${this.role}": password must be ASCII; this provider does not implement PostgreSQL SASLprep normalization. Nothing was written.`;
|
|
1504
1685
|
}
|
|
@@ -1510,13 +1691,13 @@ var MEMBERSHIP_SQL = `SELECT parent.rolname AS parent,
|
|
|
1510
1691
|
m.admin_option AS admin,
|
|
1511
1692
|
m.set_option AS set,
|
|
1512
1693
|
m.inherit_option AS inherit
|
|
1513
|
-
FROM pg_auth_members m
|
|
1514
|
-
JOIN pg_roles member ON member.oid = m.member
|
|
1515
|
-
JOIN pg_roles parent ON parent.oid = m.roleid
|
|
1516
|
-
LEFT JOIN pg_roles grantor ON grantor.oid = m.grantor
|
|
1694
|
+
FROM pg_catalog.pg_auth_members m
|
|
1695
|
+
JOIN pg_catalog.pg_roles member ON member.oid = m.member
|
|
1696
|
+
JOIN pg_catalog.pg_roles parent ON parent.oid = m.roleid
|
|
1697
|
+
LEFT JOIN pg_catalog.pg_roles grantor ON grantor.oid = m.grantor
|
|
1517
1698
|
WHERE member.rolname = $1
|
|
1518
1699
|
ORDER BY parent.rolname, grantor.rolname NULLS FIRST`;
|
|
1519
|
-
var selectRoleMemberships = (pg, name) =>
|
|
1700
|
+
var selectRoleMemberships = (pg, name) => Effect19.map(pg.unsafe(MEMBERSHIP_SQL, [name]), (rows) => rows);
|
|
1520
1701
|
var buildGrantMembershipSql = (member, parent) => `GRANT ${quoteIdent(parent)} TO ${quoteIdent(member)} WITH SET FALSE`;
|
|
1521
1702
|
var buildRepairMembershipSql = (member, parent, grantor, option) => `REVOKE ${option} OPTION FOR ${quoteIdent(parent)} FROM ${quoteIdent(member)} GRANTED BY ${quoteIdent(grantor)} RESTRICT`;
|
|
1522
1703
|
var buildRevokeGrantorMembershipSql = (member, parent, grantor) => `REVOKE ${quoteIdent(parent)} FROM ${quoteIdent(member)} GRANTED BY ${quoteIdent(grantor)}`;
|
|
@@ -1534,16 +1715,16 @@ var membershipDrift = (declared, live, unsafe = new Set) => {
|
|
|
1534
1715
|
]
|
|
1535
1716
|
};
|
|
1536
1717
|
};
|
|
1537
|
-
var assertParentsExist = (pg, role, parents) =>
|
|
1718
|
+
var assertParentsExist = (pg, role, parents) => Effect19.gen(function* () {
|
|
1538
1719
|
if (parents === undefined)
|
|
1539
1720
|
return;
|
|
1540
1721
|
for (const parent of [...new Set(parents)].sort()) {
|
|
1541
1722
|
if (!(yield* roleExists(pg, parent))) {
|
|
1542
|
-
return yield*
|
|
1723
|
+
return yield* Effect19.fail(new PostgresRoleParentMissing({ role, parent }));
|
|
1543
1724
|
}
|
|
1544
1725
|
}
|
|
1545
1726
|
});
|
|
1546
|
-
var syncMemberships = (pg, props, rows) =>
|
|
1727
|
+
var syncMemberships = (pg, props, rows) => Effect19.gen(function* () {
|
|
1547
1728
|
if (props.memberOf === undefined) {
|
|
1548
1729
|
return [...new Set(rows.map((row) => row.parent))].sort();
|
|
1549
1730
|
}
|
|
@@ -1568,10 +1749,10 @@ var syncMemberships = (pg, props, rows) => Effect18.gen(function* () {
|
|
|
1568
1749
|
}
|
|
1569
1750
|
}
|
|
1570
1751
|
if (statements.length > 0)
|
|
1571
|
-
yield* pg.transaction(statements).pipe(
|
|
1752
|
+
yield* pg.transaction(statements).pipe(Effect19.catchTag("SqlError", (error) => {
|
|
1572
1753
|
const cause = error.reason.cause;
|
|
1573
1754
|
const code = typeof cause === "object" && cause !== null ? cause.code : undefined;
|
|
1574
|
-
return
|
|
1755
|
+
return Effect19.fail(code === "2BP01" || code === "42501" ? new PostgresRoleMembershipUnrepaired({
|
|
1575
1756
|
role: props.name,
|
|
1576
1757
|
parent: row.parent,
|
|
1577
1758
|
grantor: row.grantor,
|
|
@@ -1584,7 +1765,7 @@ var syncMemberships = (pg, props, rows) => Effect18.gen(function* () {
|
|
|
1584
1765
|
yield* pg.transaction(grants);
|
|
1585
1766
|
for (const row of yield* selectRoleMemberships(pg, props.name)) {
|
|
1586
1767
|
if (!wanted.includes(row.parent) || row.admin || row.set || row.inherit && !props.inherit) {
|
|
1587
|
-
return yield*
|
|
1768
|
+
return yield* Effect19.fail(new PostgresRoleMembershipUnrepaired({
|
|
1588
1769
|
role: props.name,
|
|
1589
1770
|
parent: row.parent,
|
|
1590
1771
|
grantor: row.grantor,
|
|
@@ -1608,10 +1789,10 @@ var SELECT_ROLE_SQL = `SELECT
|
|
|
1608
1789
|
r.rolreplication AS replication,
|
|
1609
1790
|
r.rolbypassrls AS bypassrls,
|
|
1610
1791
|
to_char(r.rolvaliduntil AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS "validUntil"
|
|
1611
|
-
FROM pg_roles r
|
|
1792
|
+
FROM pg_catalog.pg_roles r
|
|
1612
1793
|
WHERE r.rolname = $1`;
|
|
1613
|
-
var selectRole = (pg, name) =>
|
|
1614
|
-
var readRoleWithClient = (pg, name) =>
|
|
1794
|
+
var selectRole = (pg, name) => Effect20.map(pg.unsafe(SELECT_ROLE_SQL, [name]), (rows) => rows[0]);
|
|
1795
|
+
var readRoleWithClient = (pg, name) => Effect20.gen(function* () {
|
|
1615
1796
|
const row = yield* selectRole(pg, name);
|
|
1616
1797
|
if (row === undefined)
|
|
1617
1798
|
return;
|
|
@@ -1692,12 +1873,12 @@ var privilegedFlags = (live) => {
|
|
|
1692
1873
|
};
|
|
1693
1874
|
// src/postgres/role.ts
|
|
1694
1875
|
import { Resource as Resource4 } from "alchemy";
|
|
1695
|
-
import * as
|
|
1876
|
+
import * as Effect22 from "effect/Effect";
|
|
1696
1877
|
import * as Redacted2 from "effect/Redacted";
|
|
1697
1878
|
|
|
1698
1879
|
// src/postgres/role-secrets.ts
|
|
1699
1880
|
import * as Redacted from "effect/Redacted";
|
|
1700
|
-
import * as
|
|
1881
|
+
import * as Effect21 from "effect/Effect";
|
|
1701
1882
|
|
|
1702
1883
|
// src/secrets/write-only.ts
|
|
1703
1884
|
import { Buffer } from "node:buffer";
|
|
@@ -1737,7 +1918,7 @@ var sealMatches = (sealed, values) => {
|
|
|
1737
1918
|
};
|
|
1738
1919
|
|
|
1739
1920
|
// src/postgres/role-secrets.ts
|
|
1740
|
-
var assertPasswordAscii = (role, resolved) => resolved.value !== undefined && /[\u0080-\uffff]/.test(Redacted.value(resolved.value)) ?
|
|
1921
|
+
var assertPasswordAscii = (role, resolved) => resolved.value !== undefined && /[\u0080-\uffff]/.test(Redacted.value(resolved.value)) ? Effect21.fail(new PostgresRolePasswordNonAsciiRefused({ role })) : Effect21.void;
|
|
1741
1922
|
var resolvePassword = (props, env = process.env) => {
|
|
1742
1923
|
if (props.password === undefined)
|
|
1743
1924
|
return { variable: undefined, value: undefined };
|
|
@@ -1771,20 +1952,20 @@ var PostgresRole = Resource4("Postgres.Role", {
|
|
|
1771
1952
|
defaultRemovalPolicy: "retain"
|
|
1772
1953
|
});
|
|
1773
1954
|
var isPostgresRole = (value3) => (typeof value3 === "object" || typeof value3 === "function") && value3 !== null && value3.Type === "Postgres.Role";
|
|
1774
|
-
var reconcileWithClient4 = (pg, props, env = process.env, previousSeal = "", storedOid) =>
|
|
1955
|
+
var reconcileWithClient4 = (pg, props, env = process.env, previousSeal = "", storedOid) => Effect22.gen(function* () {
|
|
1775
1956
|
const resolved = resolvePassword(props, env);
|
|
1776
1957
|
yield* assertPasswordAscii(props.name, resolved);
|
|
1777
1958
|
const observed = yield* readRoleWithClient(pg, props.name);
|
|
1778
1959
|
if (observed === undefined) {
|
|
1779
1960
|
if (resolved.variable !== undefined && resolved.value === undefined) {
|
|
1780
|
-
return yield*
|
|
1961
|
+
return yield* Effect22.fail(new PostgresRolePasswordEnvUnsetError({ role: props.name, variable: resolved.variable }));
|
|
1781
1962
|
}
|
|
1782
1963
|
yield* assertParentsExist(pg, props.name, props.memberOf);
|
|
1783
1964
|
const verifier = resolved.value === undefined ? undefined : scramSha256Verifier(Redacted2.value(resolved.value));
|
|
1784
1965
|
yield* pg.transaction(buildCreateStatements(props, verifier));
|
|
1785
1966
|
const created = yield* readRoleWithClient(pg, props.name);
|
|
1786
1967
|
if (created === undefined) {
|
|
1787
|
-
return yield*
|
|
1968
|
+
return yield* Effect22.fail(new PostgresRoleCreateVanished({ role: props.name }));
|
|
1788
1969
|
}
|
|
1789
1970
|
return {
|
|
1790
1971
|
...storedAttributes(created),
|
|
@@ -1792,7 +1973,7 @@ var reconcileWithClient4 = (pg, props, env = process.env, previousSeal = "", sto
|
|
|
1792
1973
|
};
|
|
1793
1974
|
}
|
|
1794
1975
|
if (storedOid !== undefined && observed.oid !== storedOid) {
|
|
1795
|
-
return yield*
|
|
1976
|
+
return yield* Effect22.fail(new PostgresRoleIdentityRefused({
|
|
1796
1977
|
role: props.name,
|
|
1797
1978
|
storedOid,
|
|
1798
1979
|
liveOid: observed.oid
|
|
@@ -1800,23 +1981,23 @@ var reconcileWithClient4 = (pg, props, env = process.env, previousSeal = "", sto
|
|
|
1800
1981
|
}
|
|
1801
1982
|
const flags = privilegedFlags(observed);
|
|
1802
1983
|
if (flags.length > 0) {
|
|
1803
|
-
return yield*
|
|
1984
|
+
return yield* Effect22.fail(new PostgresRolePrivilegedRefused({ role: props.name, flags }));
|
|
1804
1985
|
}
|
|
1805
1986
|
if (resolved.variable !== undefined && resolved.value === undefined && previousSeal === "") {
|
|
1806
|
-
return yield*
|
|
1987
|
+
return yield* Effect22.fail(new PostgresRolePasswordEnvUnsetError({ role: props.name, variable: resolved.variable }));
|
|
1807
1988
|
}
|
|
1808
1989
|
yield* assertParentsExist(pg, props.name, props.memberOf);
|
|
1809
1990
|
for (const change of scalarDrift(props, observed)) {
|
|
1810
|
-
yield* pg.unsafe(buildAlterRoleSql(props.name, change)).pipe(
|
|
1991
|
+
yield* pg.unsafe(buildAlterRoleSql(props.name, change)).pipe(Effect22.asVoid);
|
|
1811
1992
|
}
|
|
1812
1993
|
const passwordMatched = resolved.value !== undefined && passwordMatchesSeal(resolved.value, previousSeal);
|
|
1813
1994
|
if (resolved.value !== undefined && !passwordMatched) {
|
|
1814
|
-
yield* pg.unsafe(buildSetPasswordSql(props.name, scramSha256Verifier(Redacted2.value(resolved.value)))).pipe(
|
|
1995
|
+
yield* pg.unsafe(buildSetPasswordSql(props.name, scramSha256Verifier(Redacted2.value(resolved.value)))).pipe(Effect22.asVoid);
|
|
1815
1996
|
}
|
|
1816
1997
|
yield* syncMemberships(pg, props, observed.memberships ?? []);
|
|
1817
1998
|
const after = yield* readRoleWithClient(pg, props.name);
|
|
1818
1999
|
if (after === undefined) {
|
|
1819
|
-
return yield*
|
|
2000
|
+
return yield* Effect22.fail(new PostgresRoleCreateVanished({ role: props.name }));
|
|
1820
2001
|
}
|
|
1821
2002
|
return {
|
|
1822
2003
|
...storedAttributes(after),
|
|
@@ -1824,15 +2005,15 @@ var reconcileWithClient4 = (pg, props, env = process.env, previousSeal = "", sto
|
|
|
1824
2005
|
};
|
|
1825
2006
|
});
|
|
1826
2007
|
var readRole = (pg, name) => readRoleWithClient(pg, name);
|
|
1827
|
-
var refuseAtPlan = (props) =>
|
|
2008
|
+
var refuseAtPlan = (props) => Effect22.gen(function* () {
|
|
1828
2009
|
const nameRefusal = nameByteRefusal(props.name);
|
|
1829
2010
|
if (nameRefusal !== undefined) {
|
|
1830
|
-
return yield*
|
|
2011
|
+
return yield* Effect22.fail(new PostgresRoleNameRefused({ name: props.name, ...nameRefusal }));
|
|
1831
2012
|
}
|
|
1832
2013
|
if (props.validUntil !== undefined) {
|
|
1833
2014
|
const untilRefusal = validUntilRefusal(props.validUntil);
|
|
1834
2015
|
if (untilRefusal !== undefined) {
|
|
1835
|
-
return yield*
|
|
2016
|
+
return yield* Effect22.fail(new PostgresRoleValidUntilRefused({
|
|
1836
2017
|
role: props.name,
|
|
1837
2018
|
value: props.validUntil,
|
|
1838
2019
|
reason: untilRefusal.reason
|
|
@@ -1843,21 +2024,21 @@ var refuseAtPlan = (props) => Effect21.gen(function* () {
|
|
|
1843
2024
|
// src/postgres/role-provider.ts
|
|
1844
2025
|
import * as Provider4 from "alchemy/Provider";
|
|
1845
2026
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1846
|
-
import * as
|
|
2027
|
+
import * as Effect29 from "effect/Effect";
|
|
1847
2028
|
|
|
1848
2029
|
// src/ownership/probe.ts
|
|
1849
2030
|
import { Unowned as Unowned4 } from "alchemy/AdoptPolicy";
|
|
1850
|
-
import * as
|
|
2031
|
+
import * as Effect25 from "effect/Effect";
|
|
1851
2032
|
|
|
1852
2033
|
// src/ownership/rows.ts
|
|
1853
2034
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
1854
2035
|
import { State, isActionState } from "alchemy/State/State";
|
|
1855
|
-
import * as
|
|
2036
|
+
import * as Effect24 from "effect/Effect";
|
|
1856
2037
|
import * as Option2 from "effect/Option";
|
|
1857
2038
|
|
|
1858
2039
|
// src/ownership/whole.ts
|
|
1859
2040
|
import { Stack } from "alchemy/Stack";
|
|
1860
|
-
import * as
|
|
2041
|
+
import * as Effect23 from "effect/Effect";
|
|
1861
2042
|
import * as Option from "effect/Option";
|
|
1862
2043
|
var absent = (value3) => value3 === undefined || value3 === null;
|
|
1863
2044
|
var isPlainObject = (value3) => {
|
|
@@ -1883,22 +2064,22 @@ var carries = (declared, recorded) => {
|
|
|
1883
2064
|
}
|
|
1884
2065
|
return true;
|
|
1885
2066
|
};
|
|
1886
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2067
|
+
var wholeDeclaration = (fqn, props) => Effect23.map(Effect23.serviceOption(Stack), (stack) => {
|
|
1887
2068
|
const declared = Option.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
1888
2069
|
return declared !== undefined && carries(declared.Props, props);
|
|
1889
2070
|
});
|
|
1890
2071
|
|
|
1891
2072
|
// src/ownership/rows.ts
|
|
1892
|
-
var storeOf =
|
|
1893
|
-
const stack = yield*
|
|
1894
|
-
const state = yield*
|
|
2073
|
+
var storeOf = Effect24.gen(function* () {
|
|
2074
|
+
const stack = yield* Effect24.serviceOption(Stack2);
|
|
2075
|
+
const state = yield* Effect24.serviceOption(State);
|
|
1895
2076
|
if (Option2.isNone(stack) || Option2.isNone(state))
|
|
1896
2077
|
return;
|
|
1897
2078
|
const store = yield* state.value;
|
|
1898
2079
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
1899
2080
|
return { resources: stack.value.resources, store, where };
|
|
1900
2081
|
});
|
|
1901
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2082
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect24.orElseSucceed(() => {
|
|
1902
2083
|
return;
|
|
1903
2084
|
}));
|
|
1904
2085
|
var generationOf = (row, instanceId) => {
|
|
@@ -1911,7 +2092,7 @@ var generationOf = (row, instanceId) => {
|
|
|
1911
2092
|
}
|
|
1912
2093
|
return;
|
|
1913
2094
|
};
|
|
1914
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2095
|
+
var recordedGeneration = (fqn, instanceId) => Effect24.gen(function* () {
|
|
1915
2096
|
const found = yield* storeOf;
|
|
1916
2097
|
if (found === undefined)
|
|
1917
2098
|
return;
|
|
@@ -1922,20 +2103,20 @@ var recordedGeneration = (fqn, instanceId) => Effect23.gen(function* () {
|
|
|
1922
2103
|
}
|
|
1923
2104
|
return;
|
|
1924
2105
|
});
|
|
1925
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2106
|
+
var recordedInstance = (fqn, instanceId) => Effect24.gen(function* () {
|
|
1926
2107
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
1927
2108
|
if (generation === undefined)
|
|
1928
2109
|
return "absent";
|
|
1929
2110
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
1930
2111
|
});
|
|
1931
|
-
var isCreate = (fqn, instanceId) =>
|
|
2112
|
+
var isCreate = (fqn, instanceId) => Effect24.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
1932
2113
|
var idOf = (attr) => {
|
|
1933
2114
|
if (typeof attr !== "object" || attr === null)
|
|
1934
2115
|
return;
|
|
1935
2116
|
const id = attr.id;
|
|
1936
2117
|
return typeof id === "string" && id !== "" ? id : undefined;
|
|
1937
2118
|
};
|
|
1938
|
-
var olderGenerationIds = (fqn, instanceId) =>
|
|
2119
|
+
var olderGenerationIds = (fqn, instanceId) => Effect24.gen(function* () {
|
|
1939
2120
|
const found = yield* storeOf;
|
|
1940
2121
|
if (found === undefined)
|
|
1941
2122
|
return [];
|
|
@@ -1963,7 +2144,7 @@ var collectOlder = (row, instanceId, ids) => {
|
|
|
1963
2144
|
at = generation.old;
|
|
1964
2145
|
}
|
|
1965
2146
|
};
|
|
1966
|
-
var forgetRefusedCreate = (fqn, instanceId) =>
|
|
2147
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect24.gen(function* () {
|
|
1967
2148
|
const found = yield* storeOf;
|
|
1968
2149
|
if (found === undefined)
|
|
1969
2150
|
return;
|
|
@@ -1972,22 +2153,22 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect23.gen(function* () {
|
|
|
1972
2153
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
1973
2154
|
return;
|
|
1974
2155
|
}
|
|
1975
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2156
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect24.ignore);
|
|
1976
2157
|
});
|
|
1977
2158
|
|
|
1978
2159
|
// src/ownership/probe.ts
|
|
1979
|
-
var provenOurs = (ask, settled) =>
|
|
2160
|
+
var provenOurs = (ask, settled) => Effect25.gen(function* () {
|
|
1980
2161
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
1981
2162
|
if (recorded === "absent")
|
|
1982
2163
|
return false;
|
|
1983
2164
|
if (recorded === "partial") {
|
|
1984
|
-
yield*
|
|
2165
|
+
yield* Effect25.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
|
|
1985
2166
|
return false;
|
|
1986
2167
|
}
|
|
1987
|
-
const unproven = (reason) =>
|
|
1988
|
-
return yield* settled.pipe(
|
|
2168
|
+
const unproven = (reason) => Effect25.as(Effect25.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
|
|
2169
|
+
return yield* settled.pipe(Effect25.catch(unproven), Effect25.catchDefect(unproven));
|
|
1989
2170
|
});
|
|
1990
|
-
var ownedRead = (ask, found, settled) =>
|
|
2171
|
+
var ownedRead = (ask, found, settled) => Effect25.gen(function* () {
|
|
1991
2172
|
if (found === undefined || ask.output !== undefined)
|
|
1992
2173
|
return found;
|
|
1993
2174
|
return (yield* provenOurs(ask, settled)) ? found : Unowned4(found);
|
|
@@ -1996,26 +2177,26 @@ var ownedRead = (ask, found, settled) => Effect24.gen(function* () {
|
|
|
1996
2177
|
// src/ownership/resume.ts
|
|
1997
2178
|
import { Unowned as Unowned5 } from "alchemy/AdoptPolicy";
|
|
1998
2179
|
import { Artifacts } from "alchemy/Artifacts";
|
|
1999
|
-
import * as
|
|
2180
|
+
import * as Effect26 from "effect/Effect";
|
|
2000
2181
|
import * as Option3 from "effect/Option";
|
|
2001
2182
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2002
2183
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2003
|
-
var note = (key, instanceId) =>
|
|
2004
|
-
const bag = yield*
|
|
2184
|
+
var note = (key, instanceId) => Effect26.gen(function* () {
|
|
2185
|
+
const bag = yield* Effect26.serviceOption(Artifacts);
|
|
2005
2186
|
if (Option3.isSome(bag))
|
|
2006
2187
|
yield* bag.value.set(key, instanceId);
|
|
2007
2188
|
});
|
|
2008
|
-
var noted = (key, instanceId) =>
|
|
2009
|
-
const bag = yield*
|
|
2189
|
+
var noted = (key, instanceId) => Effect26.gen(function* () {
|
|
2190
|
+
const bag = yield* Effect26.serviceOption(Artifacts);
|
|
2010
2191
|
if (Option3.isNone(bag))
|
|
2011
2192
|
return false;
|
|
2012
2193
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2013
2194
|
});
|
|
2014
|
-
var noteUnfinished = (instanceId) =>
|
|
2015
|
-
var noteResume = (instanceId, recovered) =>
|
|
2195
|
+
var noteUnfinished = (instanceId) => Effect26.as(note(UNFINISHED, instanceId), undefined);
|
|
2196
|
+
var noteResume = (instanceId, recovered) => Effect26.gen(function* () {
|
|
2016
2197
|
yield* noteUnfinished(instanceId);
|
|
2017
|
-
const unproven = () =>
|
|
2018
|
-
const found = yield* recovered.pipe(
|
|
2198
|
+
const unproven = () => Effect26.succeed(undefined);
|
|
2199
|
+
const found = yield* recovered.pipe(Effect26.catch(unproven), Effect26.catchDefect(unproven));
|
|
2019
2200
|
if (found === undefined || found === null || Unowned5.is(found))
|
|
2020
2201
|
return;
|
|
2021
2202
|
yield* note(PROVEN, instanceId);
|
|
@@ -2026,7 +2207,7 @@ var provingResumes = (service) => {
|
|
|
2026
2207
|
const { diff, read } = service;
|
|
2027
2208
|
if (diff === undefined || read === undefined)
|
|
2028
2209
|
return service;
|
|
2029
|
-
const proving = (input) =>
|
|
2210
|
+
const proving = (input) => Effect26.gen(function* () {
|
|
2030
2211
|
if (input.output === undefined) {
|
|
2031
2212
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2032
2213
|
}
|
|
@@ -2039,30 +2220,30 @@ var provingResumes = (service) => {
|
|
|
2039
2220
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2040
2221
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2041
2222
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2042
|
-
import * as
|
|
2223
|
+
import * as Effect27 from "effect/Effect";
|
|
2043
2224
|
import * as Option4 from "effect/Option";
|
|
2044
|
-
var adoptEnabled = (fqn) =>
|
|
2045
|
-
const stack = yield*
|
|
2046
|
-
const
|
|
2047
|
-
if (
|
|
2048
|
-
return
|
|
2049
|
-
const policy = yield*
|
|
2225
|
+
var adoptEnabled = (fqn) => Effect27.gen(function* () {
|
|
2226
|
+
const stack = yield* Effect27.serviceOption(Stack3);
|
|
2227
|
+
const scoped2 = Option4.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2228
|
+
if (scoped2 !== undefined)
|
|
2229
|
+
return scoped2;
|
|
2230
|
+
const policy = yield* Effect27.serviceOption(AdoptPolicy);
|
|
2050
2231
|
if (Option4.isSome(policy))
|
|
2051
2232
|
return policy.value;
|
|
2052
|
-
const context = yield*
|
|
2233
|
+
const context = yield* Effect27.serviceOption(AlchemyContext);
|
|
2053
2234
|
return Option4.isSome(context) ? context.value.adopt : false;
|
|
2054
2235
|
});
|
|
2055
|
-
var adoptable = (owner) =>
|
|
2236
|
+
var adoptable = (owner) => Effect27.gen(function* () {
|
|
2056
2237
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2057
2238
|
return true;
|
|
2058
2239
|
return yield* unfinished(owner.instanceId);
|
|
2059
2240
|
});
|
|
2060
|
-
var adoptsAtApply = (owner) =>
|
|
2241
|
+
var adoptsAtApply = (owner) => Effect27.gen(function* () {
|
|
2061
2242
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2062
2243
|
return false;
|
|
2063
2244
|
return yield* adoptable(owner);
|
|
2064
2245
|
});
|
|
2065
|
-
var refuseTakeover = (owner, what) =>
|
|
2246
|
+
var refuseTakeover = (owner, what) => Effect27.gen(function* () {
|
|
2066
2247
|
if (owner.output !== undefined)
|
|
2067
2248
|
return;
|
|
2068
2249
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2072,23 +2253,23 @@ var refuseTakeover = (owner, what) => Effect26.gen(function* () {
|
|
|
2072
2253
|
return;
|
|
2073
2254
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2074
2255
|
const remedy = may ? "Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first." : "It is the new identity of a replace, which --adopt does not cover: remove it first.";
|
|
2075
|
-
return yield*
|
|
2256
|
+
return yield* Effect27.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
|
|
2076
2257
|
});
|
|
2077
2258
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2078
2259
|
|
|
2079
2260
|
// src/postgres/role-diff.ts
|
|
2080
2261
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
2081
|
-
import * as
|
|
2082
|
-
var diffPostgresRole = (news, output, env = process.env, observation) =>
|
|
2262
|
+
import * as Effect28 from "effect/Effect";
|
|
2263
|
+
var diffPostgresRole = (news, output, env = process.env, observation) => Effect28.gen(function* () {
|
|
2083
2264
|
if (output === undefined || !isResolved4(news))
|
|
2084
2265
|
return;
|
|
2085
2266
|
if (news.name !== output.name) {
|
|
2086
|
-
return yield*
|
|
2267
|
+
return yield* Effect28.fail(new PostgresRoleRenameRefused({ from: output.name, to: news.name }));
|
|
2087
2268
|
}
|
|
2088
2269
|
yield* refuseAtPlan(news);
|
|
2089
2270
|
const live = observation?.found;
|
|
2090
2271
|
if (live !== undefined && live.oid !== output.oid) {
|
|
2091
|
-
return yield*
|
|
2272
|
+
return yield* Effect28.fail(new PostgresRoleIdentityRefused({
|
|
2092
2273
|
role: output.name,
|
|
2093
2274
|
storedOid: output.oid,
|
|
2094
2275
|
liveOid: live.oid
|
|
@@ -2107,15 +2288,15 @@ var diffPostgresRole = (news, output, env = process.env, observation) => Effect2
|
|
|
2107
2288
|
|
|
2108
2289
|
// src/postgres/role-provider.ts
|
|
2109
2290
|
var postgresRoleHandlers = PostgresRole.Provider.of({
|
|
2110
|
-
list: () =>
|
|
2291
|
+
list: () => Effect29.succeed([]),
|
|
2111
2292
|
nuke: { skip: true },
|
|
2112
|
-
read: ({ fqn, instanceId, olds, output }) =>
|
|
2293
|
+
read: ({ fqn, instanceId, olds, output }) => Effect29.gen(function* () {
|
|
2113
2294
|
const name = output?.name ?? olds.name;
|
|
2114
2295
|
const live = yield* withPg((pg) => readRole(pg, name));
|
|
2115
2296
|
if (live === undefined)
|
|
2116
2297
|
return;
|
|
2117
2298
|
if (output !== undefined && live.oid !== output.oid) {
|
|
2118
|
-
return yield*
|
|
2299
|
+
return yield* Effect29.fail(new PostgresRoleIdentityRefused({
|
|
2119
2300
|
role: name,
|
|
2120
2301
|
storedOid: output.oid,
|
|
2121
2302
|
liveOid: live.oid
|
|
@@ -2123,9 +2304,9 @@ var postgresRoleHandlers = PostgresRole.Provider.of({
|
|
|
2123
2304
|
}
|
|
2124
2305
|
const passwordSeal = output?.passwordSeal ?? "";
|
|
2125
2306
|
const found = { ...storedAttributes(live), passwordSeal };
|
|
2126
|
-
return yield* ownedRead({ fqn, instanceId, output }, found,
|
|
2307
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, Effect29.succeed(declarationMatches(olds, live)));
|
|
2127
2308
|
}),
|
|
2128
|
-
diff: ({ news, output, instanceId }) =>
|
|
2309
|
+
diff: ({ news, output, instanceId }) => Effect29.gen(function* () {
|
|
2129
2310
|
if (output === undefined)
|
|
2130
2311
|
return yield* noteUnfinished(instanceId);
|
|
2131
2312
|
if (!isResolved5(news))
|
|
@@ -2133,9 +2314,9 @@ var postgresRoleHandlers = PostgresRole.Provider.of({
|
|
|
2133
2314
|
const found = yield* withPg((pg) => readRole(pg, output.name));
|
|
2134
2315
|
return yield* diffPostgresRole(news, output, process.env, { found });
|
|
2135
2316
|
}),
|
|
2136
|
-
reconcile: ({ fqn, instanceId, news, output }) =>
|
|
2317
|
+
reconcile: ({ fqn, instanceId, news, output }) => Effect29.gen(function* () {
|
|
2137
2318
|
yield* refuseAtPlan(news);
|
|
2138
|
-
return yield* withPg((pg) =>
|
|
2319
|
+
return yield* withPg((pg) => Effect29.gen(function* () {
|
|
2139
2320
|
const observed = yield* readRole(pg, news.name);
|
|
2140
2321
|
if (observed !== undefined && output === undefined) {
|
|
2141
2322
|
yield* refuseTakeover({ fqn, instanceId, output }, "Postgres.Role");
|
|
@@ -2143,20 +2324,20 @@ var postgresRoleHandlers = PostgresRole.Provider.of({
|
|
|
2143
2324
|
return yield* reconcileWithClient4(pg, news, process.env, output?.passwordSeal, output?.oid);
|
|
2144
2325
|
}));
|
|
2145
2326
|
}),
|
|
2146
|
-
delete: ({ output }) => withPg((pg) =>
|
|
2327
|
+
delete: ({ output }) => withPg((pg) => Effect29.gen(function* () {
|
|
2147
2328
|
if (output === undefined)
|
|
2148
2329
|
return;
|
|
2149
2330
|
const live = yield* readRole(pg, output.name);
|
|
2150
2331
|
if (live === undefined)
|
|
2151
2332
|
return;
|
|
2152
2333
|
if (live.oid !== output.oid) {
|
|
2153
|
-
return yield*
|
|
2334
|
+
return yield* Effect29.fail(new PostgresRoleIdentityRefused({
|
|
2154
2335
|
role: output.name,
|
|
2155
2336
|
storedOid: output.oid,
|
|
2156
2337
|
liveOid: live.oid
|
|
2157
2338
|
}));
|
|
2158
2339
|
}
|
|
2159
|
-
yield* pg.unsafe(buildDropRoleSql(output.name)).pipe(
|
|
2340
|
+
yield* pg.unsafe(buildDropRoleSql(output.name)).pipe(Effect29.asVoid);
|
|
2160
2341
|
}))
|
|
2161
2342
|
});
|
|
2162
2343
|
var PostgresRoleProvider = () => Provider4.succeed(PostgresRole, postgresRoleHandlers);
|
|
@@ -2203,6 +2384,8 @@ export {
|
|
|
2203
2384
|
PostgresRoleRenameRefused,
|
|
2204
2385
|
PostgresRoleValidUntilRefused,
|
|
2205
2386
|
PostgresSchema,
|
|
2387
|
+
PostgresSchemaCascadeCrossSchemaRefused,
|
|
2388
|
+
PostgresSchemaCascadeSequencesRefused,
|
|
2206
2389
|
PostgresSchemaCreateVanished,
|
|
2207
2390
|
PostgresSchemaDatabaseRefused,
|
|
2208
2391
|
PostgresSchemaDeleteForeignRefused,
|
|
@@ -2281,5 +2464,5 @@ export {
|
|
|
2281
2464
|
withPg
|
|
2282
2465
|
};
|
|
2283
2466
|
|
|
2284
|
-
//# debugId=
|
|
2467
|
+
//# debugId=DCC960CECB491BBD64756E2164756E21
|
|
2285
2468
|
//# sourceMappingURL=index.js.map
|