@astralarium/repo-postgres 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +38 -2
- package/container/init/.containerignore +2 -0
- package/container/init/Containerfile +26 -0
- package/container/init/entrypoint.d/init-db.sh +20 -0
- package/container/snapshot/run-snapshot.sh +23 -0
- package/container/util/.containerignore +2 -0
- package/container/util/Containerfile +7 -0
- package/container/util/entrypoint.d/dump-db.sh +19 -0
- package/container/util/entrypoint.d/upgrade-db.sh +103 -0
- package/dist/bin/stage-schema.d.ts +2 -0
- package/dist/bin/stage-schema.js +20 -0
- package/dist/src/provision/connection.d.ts +11 -0
- package/dist/src/provision/connection.js +33 -0
- package/dist/src/provision/container.d.ts +87 -0
- package/dist/src/provision/container.js +244 -0
- package/dist/src/provision/data.d.ts +8 -0
- package/dist/src/provision/data.js +47 -0
- package/dist/src/provision/disposable.d.ts +49 -0
- package/dist/src/provision/disposable.js +188 -0
- package/dist/src/provision/image.d.ts +63 -0
- package/dist/src/provision/image.js +159 -0
- package/dist/src/provision/index.d.ts +17 -0
- package/dist/src/provision/index.js +205 -0
- package/dist/src/provision/options.d.ts +23 -0
- package/dist/src/provision/options.js +1 -0
- package/dist/src/provision/schema.d.ts +11 -0
- package/dist/src/provision/schema.js +134 -0
- package/dist/src/provision/test-database.d.ts +29 -0
- package/dist/src/provision/test-database.js +130 -0
- package/dist/src/queue.d.ts +86 -0
- package/dist/src/queue.js +201 -0
- package/dist/src/schema/index.d.ts +3 -0
- package/dist/src/schema/index.js +3 -0
- package/dist/src/schema/module.d.ts +59 -0
- package/dist/src/schema/module.js +122 -0
- package/dist/src/schema/modules.d.ts +24 -0
- package/dist/src/schema/modules.js +71 -0
- package/dist/src/sql.d.ts +83 -0
- package/dist/src/sql.js +146 -0
- package/dist/testkit/index.d.ts +14 -0
- package/dist/testkit/index.js +32 -0
- package/dist/testkit/locks.d.ts +27 -0
- package/dist/testkit/locks.js +57 -0
- package/dist/testkit/schema.d.ts +14 -0
- package/dist/testkit/schema.js +89 -0
- package/package.json +63 -3
- package/scripts/build-images.sh +52 -0
- package/scripts/dump-db.sh +32 -0
- package/sql/app/schema.sql +8 -0
- package/sql/bootstrap.sql +27 -0
- package/sql/database-grants.sql +3 -0
- package/sql/drop-schemas.sql +11 -0
- package/sql/extensions/cron/schema.sql +23 -0
- package/sql/extensions/partman/before-reset.sql +38 -0
- package/sql/extensions/partman/schema.sql +8 -0
- package/sql/extensions/trgm/schema.sql +1 -0
- package/sql/reset.sql +22 -0
- package/sql/roles.sql +10 -0
- package/sql/slug/schema.sql +25 -0
- package/sql/taskclaim/jobs/schema.sql +19 -0
- package/sql/taskclaim/schema.sql +41 -0
- package/sql/taskclaim/scrub.sql +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Astralarium
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@astralarium/repo-postgres`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared Postgres tooling: container images, schema modules, clients.
|
|
4
|
+
|
|
5
|
+
Roles:
|
|
6
|
+
|
|
7
|
+
- `app_admin`: schema owner.
|
|
8
|
+
- `app_service`: app service.
|
|
9
|
+
|
|
10
|
+
Roles are cluster-wide: one app per cluster.
|
|
11
|
+
|
|
12
|
+
```sql
|
|
13
|
+
SELECT slug.slug('Room 52'); -- room-52
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// app modules: `taskclaimJobs` (requires `taskclaim`, `cron`) deletes expired claims hourly
|
|
18
|
+
postgresDatabase({ modules: [appModule, slug, taskclaimJobs], name: "app-db" });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// producer: one message per key per window
|
|
23
|
+
await enqueueClaimed(
|
|
24
|
+
sql,
|
|
25
|
+
env.REFRESH,
|
|
26
|
+
`project:${id}`,
|
|
27
|
+
{ id },
|
|
28
|
+
{ windowSeconds: 300 },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// consumer
|
|
32
|
+
await consumeClaimed(sql, batch, {
|
|
33
|
+
parse: parseRefreshTask,
|
|
34
|
+
run: refreshProject,
|
|
35
|
+
maxRetries: 3, // the consumer's max_retries
|
|
36
|
+
retryAfterMs: (e) =>
|
|
37
|
+
e instanceof RetryAfterError ? e.retryAfterMs : undefined,
|
|
38
|
+
});
|
|
39
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
FROM postgres:18-trixie
|
|
2
|
+
|
|
3
|
+
# Extension names, space-separated: Debian's postgresql-<major>-<name> packages.
|
|
4
|
+
ARG DB_EXTENSIONS=""
|
|
5
|
+
RUN if [ -n "$DB_EXTENSIONS" ]; then \
|
|
6
|
+
packages=""; \
|
|
7
|
+
for name in $DB_EXTENSIONS; do packages="$packages postgresql-${PG_MAJOR}-${name}"; done; \
|
|
8
|
+
apt-get update \
|
|
9
|
+
&& apt-get install -y --no-install-recommends $packages \
|
|
10
|
+
&& rm -rf /var/lib/apt/lists/*; \
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
# `schemaHash` of the staged schema, this package and DB_EXTENSIONS.
|
|
14
|
+
# The RUN keys the layer cache on it, so each hash gets its own ENV and LABEL.
|
|
15
|
+
ARG DB_SCHEMA
|
|
16
|
+
RUN echo "$DB_SCHEMA" > /etc/db-schema
|
|
17
|
+
ENV DB_SCHEMA=$DB_SCHEMA
|
|
18
|
+
LABEL db.schema=$DB_SCHEMA
|
|
19
|
+
|
|
20
|
+
WORKDIR /docker-entrypoint-initdb.d
|
|
21
|
+
COPY entrypoint.d/ .
|
|
22
|
+
# Packed packages ship scripts without mode bits.
|
|
23
|
+
RUN chmod 0755 *.sh
|
|
24
|
+
|
|
25
|
+
# The staged schema: schema.sql beside sql/.
|
|
26
|
+
COPY --from=schema . schema
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# First boot: creates `db_template`, the app roles (schema/roles.sql) and
|
|
3
|
+
# its grants (schema/database-grants.sql), loads the staged schema
|
|
4
|
+
# (schema/schema.sql includes sql/ in order) with schema/ as cwd, then
|
|
5
|
+
# stamps the data directory with the image's DB_SCHEMA.
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
|
10
|
+
|
|
11
|
+
export PGDATABASE="db_template"
|
|
12
|
+
|
|
13
|
+
createdb "${PGDATABASE}"
|
|
14
|
+
|
|
15
|
+
cd schema
|
|
16
|
+
psql -X -v ON_ERROR_STOP=1 --file roles.sql
|
|
17
|
+
psql -X -v ON_ERROR_STOP=1 --file database-grants.sql
|
|
18
|
+
psql -X -v ON_ERROR_STOP=1 --file schema.sql
|
|
19
|
+
|
|
20
|
+
echo "${DB_SCHEMA}" > /var/lib/postgresql/db-schema
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# First boot, after init-db.sh: recreates `db_template` with the staged
|
|
3
|
+
# database-grants.sql, loads the dump at /app/data.sql, runs the staged
|
|
4
|
+
# scrub.sql (each module's `scrub`) unless SNAPSHOT_SCRUB=0, then vacuums.
|
|
5
|
+
# Init runs before the server listens: clients only see the scrubbed data.
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
cd /docker-entrypoint-initdb.d/schema
|
|
10
|
+
|
|
11
|
+
export PGDATABASE="db_template"
|
|
12
|
+
|
|
13
|
+
dropdb --force "$PGDATABASE"
|
|
14
|
+
createdb "$PGDATABASE"
|
|
15
|
+
psql -X -v ON_ERROR_STOP=1 --file database-grants.sql
|
|
16
|
+
|
|
17
|
+
psql -X -v ON_ERROR_STOP=1 --file /app/data.sql
|
|
18
|
+
|
|
19
|
+
if [[ ${SNAPSHOT_SCRUB:-1} != 0 ]]; then
|
|
20
|
+
psql -X -v ON_ERROR_STOP=1 --single-transaction --file scrub.sql
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
vacuumdb --full --analyze --echo
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Data-only dump of the PG* database: the app's rows, excluding extension
|
|
3
|
+
# config tables (the target schema owns its own) and the rows of tables
|
|
4
|
+
# matching DB_DUMP_EXCLUDE (space-separated schema-qualified pg_dump
|
|
5
|
+
# patterns; a partitioned table covers its partitions). The replica role
|
|
6
|
+
# skips triggers and FK checks on load.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
read -ra patterns <<< "${DB_DUMP_EXCLUDE:-}"
|
|
11
|
+
excludes=()
|
|
12
|
+
for pattern in ${patterns[@]+"${patterns[@]}"}; do
|
|
13
|
+
[[ $pattern == *.* ]] || { echo "dump-db: DB_DUMP_EXCLUDE pattern $pattern lacks a schema" >&2; exit 1; }
|
|
14
|
+
excludes+=("--exclude-table-data-and-children=$pattern")
|
|
15
|
+
done
|
|
16
|
+
|
|
17
|
+
echo "SET session_replication_role = 'replica';"
|
|
18
|
+
|
|
19
|
+
pg_dump --data-only --exclude-extension='*' ${excludes[@]+"${excludes[@]}"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Loads the PG* source database's data into a db_template clone on the
|
|
3
|
+
# throwaway instance at CONTAINER_PGHOST and prints that clone's full
|
|
4
|
+
# pg_dump. With /app/migrate.d/*.sql, the data comes from a copy of the
|
|
5
|
+
# source those files migrate, in name order. Tables matching
|
|
6
|
+
# DB_DUMP_EXCLUDE keep the clone's seed rows.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
CONTAINER_PGHOST=${CONTAINER_PGHOST:?temporary database host}
|
|
11
|
+
|
|
12
|
+
TEMPLATE_DATABASE=db_template
|
|
13
|
+
UPGRADE_PGDATABASE=db_upgrade
|
|
14
|
+
MIGRATE_PGDATABASE=db_migrate
|
|
15
|
+
|
|
16
|
+
# Name order, independent of the locale.
|
|
17
|
+
LC_COLLATE=C
|
|
18
|
+
shopt -s nullglob
|
|
19
|
+
migratefiles=(/app/migrate.d/*.sql)
|
|
20
|
+
|
|
21
|
+
# Runs a client against the throwaway instance's database <db>.
|
|
22
|
+
on_local() {
|
|
23
|
+
local db=$1
|
|
24
|
+
shift
|
|
25
|
+
PGSSLMODE=prefer \
|
|
26
|
+
PGHOST="$CONTAINER_PGHOST" \
|
|
27
|
+
PGPORT=5432 \
|
|
28
|
+
PGUSER=postgres \
|
|
29
|
+
PGPASSWORD="" \
|
|
30
|
+
PGDATABASE="$db" \
|
|
31
|
+
"$@"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Empties every table of the app_admin-owned schemas in the upgrade db: the
|
|
35
|
+
# template's seed rows give way to the source's data. Tables matching
|
|
36
|
+
# DB_DUMP_EXCLUDE (schema-qualified pg_dump patterns, `*` and `?`
|
|
37
|
+
# wildcards) keep theirs, as the dump skips their rows.
|
|
38
|
+
clear_app_data() {
|
|
39
|
+
on_local "$UPGRADE_PGDATABASE" psql -X -q -v ON_ERROR_STOP=1 \
|
|
40
|
+
-v exclude="${DB_DUMP_EXCLUDE:-}" >&2 <<'SQL'
|
|
41
|
+
SET upgrade.dump_exclude = :'exclude';
|
|
42
|
+
-- One pg_dump pattern part as an anchored regex.
|
|
43
|
+
CREATE FUNCTION pg_temp.pattern_regex(part text) RETURNS text
|
|
44
|
+
LANGUAGE sql IMMUTABLE
|
|
45
|
+
RETURN '^(' || replace(replace(replace(lower(part), '$', '\$'), '?', '.'), '*', '.*') || ')$';
|
|
46
|
+
DO $$
|
|
47
|
+
DECLARE tables text;
|
|
48
|
+
BEGIN
|
|
49
|
+
SELECT string_agg(c.oid::regclass::text, ', ') INTO tables
|
|
50
|
+
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
51
|
+
WHERE n.nspowner = 'app_admin'::regrole
|
|
52
|
+
AND c.relkind IN ('r', 'p')
|
|
53
|
+
AND NOT EXISTS (SELECT 1 FROM pg_inherits WHERE inhrelid = c.oid)
|
|
54
|
+
AND NOT EXISTS (
|
|
55
|
+
SELECT 1
|
|
56
|
+
FROM regexp_split_to_table(current_setting('upgrade.dump_exclude'), '\s+') AS pattern
|
|
57
|
+
WHERE pattern <> ''
|
|
58
|
+
AND n.nspname ~ pg_temp.pattern_regex(split_part(pattern, '.', 1))
|
|
59
|
+
AND c.relname ~ pg_temp.pattern_regex(
|
|
60
|
+
substr(pattern, strpos(pattern, '.') + 1))
|
|
61
|
+
);
|
|
62
|
+
IF tables IS NOT NULL THEN
|
|
63
|
+
EXECUTE 'TRUNCATE ' || tables;
|
|
64
|
+
END IF;
|
|
65
|
+
END $$;
|
|
66
|
+
SQL
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
while ! on_local postgres pg_isready >&2; do
|
|
70
|
+
echo "Waiting for local db instance..." >&2
|
|
71
|
+
sleep 2
|
|
72
|
+
done
|
|
73
|
+
echo "Local db connected!" >&2
|
|
74
|
+
|
|
75
|
+
if (( ${#migratefiles[@]} )); then
|
|
76
|
+
echo "Copy remote db into the migration db..." >&2
|
|
77
|
+
on_local postgres createdb "$MIGRATE_PGDATABASE" >&2
|
|
78
|
+
# pg_cron loads only via shared_preload_libraries; the throwaway runs stock Postgres.
|
|
79
|
+
# The copy feeds a data-only dump and migrate files run as `postgres`,
|
|
80
|
+
# so owners and grants stay out.
|
|
81
|
+
pg_dump --no-owner --no-privileges --exclude-extension=pg_cron | on_local "$MIGRATE_PGDATABASE" psql -v ON_ERROR_STOP=1 >&2
|
|
82
|
+
|
|
83
|
+
for migratefile in "${migratefiles[@]}"; do
|
|
84
|
+
echo "Migrate: $(basename "$migratefile")..." >&2
|
|
85
|
+
on_local "$MIGRATE_PGDATABASE" psql -v ON_ERROR_STOP=1 < "$migratefile" >&2
|
|
86
|
+
done
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
echo "Create upgrade db" >&2
|
|
90
|
+
on_local postgres createdb -T "$TEMPLATE_DATABASE" "$UPGRADE_PGDATABASE" >&2
|
|
91
|
+
clear_app_data
|
|
92
|
+
|
|
93
|
+
echo "Copy data into the upgrade db..." >&2
|
|
94
|
+
if (( ${#migratefiles[@]} )); then
|
|
95
|
+
on_local "$MIGRATE_PGDATABASE" /entrypoint.d/dump-db.sh
|
|
96
|
+
else
|
|
97
|
+
/entrypoint.d/dump-db.sh
|
|
98
|
+
fi | on_local "$UPGRADE_PGDATABASE" psql -v ON_ERROR_STOP=1 >&2
|
|
99
|
+
|
|
100
|
+
echo "Dump upgrade db data" >&2
|
|
101
|
+
echo "SET session_replication_role = 'replica';"
|
|
102
|
+
on_local "$UPGRADE_PGDATABASE" pg_dump
|
|
103
|
+
echo "DONE" >&2
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** `stage-schema --app <module> <dir>`: stages the app's schema for psql
|
|
3
|
+
* under `<dir>` (`PostgresProvider.stageSchema`). */
|
|
4
|
+
import { appArgs } from "@astralarium/repo-deploy-info/server";
|
|
5
|
+
import { loadDevConfig } from "@astralarium/repo-dev";
|
|
6
|
+
import { ExpectedError, log } from "@astralarium/repo-telemetry";
|
|
7
|
+
const USAGE = "Usage: stage-schema --app <module> <dir>";
|
|
8
|
+
try {
|
|
9
|
+
const { app, argv } = appArgs(process.argv.slice(2), USAGE, {
|
|
10
|
+
positionals: 1,
|
|
11
|
+
});
|
|
12
|
+
const { database } = await loadDevConfig(app);
|
|
13
|
+
if (!database || !("stageSchema" in database))
|
|
14
|
+
throw new ExpectedError(`${app}: dev config declares no Postgres database`);
|
|
15
|
+
database.stageSchema(argv[0]);
|
|
16
|
+
}
|
|
17
|
+
catch (exception) {
|
|
18
|
+
log.error("stage_schema.failed", "stage-schema failed", { exception });
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Preferred published port; a taken one moves to the next free port up. */
|
|
2
|
+
export declare const DEFAULT_PORT = 5432;
|
|
3
|
+
/** The app's login role, as `sql/roles.sql` creates it: non-superuser;
|
|
4
|
+
* schema access through grants; `app_admin` inherits it. */
|
|
5
|
+
export declare const APP_SERVICE_ROLE = "app_service";
|
|
6
|
+
/** Local connection as `APP_SERVICE_ROLE`. */
|
|
7
|
+
export declare function appConnectionString(port: number, database: string): string;
|
|
8
|
+
/** Local connection as `postgres`. */
|
|
9
|
+
export declare function adminConnectionString(port: number, database: string): string;
|
|
10
|
+
/** Authenticates through the host port and executes a read-only query. */
|
|
11
|
+
export declare function probePostgres(connectionString: string): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Connections to local instances: trust auth on the published loopback port. */
|
|
2
|
+
import postgres from "postgres";
|
|
3
|
+
/** Preferred published port; a taken one moves to the next free port up. */
|
|
4
|
+
export const DEFAULT_PORT = 5432;
|
|
5
|
+
/**
|
|
6
|
+
* Loopback connection string for a local instance. The containers trust
|
|
7
|
+
* every connection on their published loopback port; the password is a
|
|
8
|
+
* placeholder the Cloudflare tooling insists on.
|
|
9
|
+
*/
|
|
10
|
+
function localConnectionString(user, port, database) {
|
|
11
|
+
return `postgres://${user}:trust@127.0.0.1:${port}/${database}`;
|
|
12
|
+
}
|
|
13
|
+
/** The app's login role, as `sql/roles.sql` creates it: non-superuser;
|
|
14
|
+
* schema access through grants; `app_admin` inherits it. */
|
|
15
|
+
export const APP_SERVICE_ROLE = "app_service";
|
|
16
|
+
/** Local connection as `APP_SERVICE_ROLE`. */
|
|
17
|
+
export function appConnectionString(port, database) {
|
|
18
|
+
return localConnectionString(APP_SERVICE_ROLE, port, database);
|
|
19
|
+
}
|
|
20
|
+
/** Local connection as `postgres`. */
|
|
21
|
+
export function adminConnectionString(port, database) {
|
|
22
|
+
return localConnectionString("postgres", port, database);
|
|
23
|
+
}
|
|
24
|
+
/** Authenticates through the host port and executes a read-only query. */
|
|
25
|
+
export async function probePostgres(connectionString) {
|
|
26
|
+
const sql = postgres(connectionString, { max: 1, connect_timeout: 5 });
|
|
27
|
+
try {
|
|
28
|
+
await sql `SELECT 1`;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
await sql.end({ timeout: 1 });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type ResourceScope } from "@astralarium/repo-dev";
|
|
2
|
+
/** Image label carrying the `schemaHash()` it was built from. */
|
|
3
|
+
export declare const SCHEMA_LABEL = "db.schema";
|
|
4
|
+
/** Container and volume label naming the checkout that owns it. */
|
|
5
|
+
export declare const OWNER_LABEL = "dev.owner";
|
|
6
|
+
/** `CONTAINER_RUNTIME`, else the first of podman, docker that answers `info`. */
|
|
7
|
+
export declare function detectRuntime(): string;
|
|
8
|
+
/** The container's data was initialised from a schema other than its image's. */
|
|
9
|
+
export declare class StaleSchemaError extends Error {
|
|
10
|
+
constructor(runtime: string, container: string, stamp: string | null);
|
|
11
|
+
}
|
|
12
|
+
/** Existing container: run state, image ID and labels. */
|
|
13
|
+
interface ContainerState {
|
|
14
|
+
running: boolean;
|
|
15
|
+
/** SHA-256 image ID, including the algorithm prefix. */
|
|
16
|
+
image: string;
|
|
17
|
+
/** `SCHEMA_LABEL` value; undefined on an unlabeled image. */
|
|
18
|
+
schema?: string;
|
|
19
|
+
/** `OWNER_LABEL` value; undefined on an unlabeled container. */
|
|
20
|
+
owner?: string;
|
|
21
|
+
/** `ARGS_LABEL` value; undefined on an unlabeled container. */
|
|
22
|
+
args?: string;
|
|
23
|
+
/** Requested loopback publish specification. */
|
|
24
|
+
bindings: {
|
|
25
|
+
HostIp: string;
|
|
26
|
+
HostPort: string;
|
|
27
|
+
}[];
|
|
28
|
+
/** Mount at the Postgres data directory. */
|
|
29
|
+
dataMount?: {
|
|
30
|
+
Type: string;
|
|
31
|
+
Name?: string;
|
|
32
|
+
Destination: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** One `container inspect`; null for an absent `name`. */
|
|
36
|
+
export declare function inspectContainer(runtime: string, name: string): ContainerState | null;
|
|
37
|
+
/** Persistent data volume of dev instance `name`. */
|
|
38
|
+
export declare function volumeName(name: string): string;
|
|
39
|
+
/** Something holding dev instance `name`: its container or its data volume. */
|
|
40
|
+
interface Holder {
|
|
41
|
+
kind: "container" | "volume";
|
|
42
|
+
/** Container or volume name. */
|
|
43
|
+
name: string;
|
|
44
|
+
/** `OWNER_LABEL` value; undefined when unlabeled. */
|
|
45
|
+
owner?: string;
|
|
46
|
+
}
|
|
47
|
+
/** The existing container and data volume of dev instance `name`. */
|
|
48
|
+
export declare function holders(runtime: string, name: string): Holder[];
|
|
49
|
+
/** Container `name` and its data volume are each absent or labeled as
|
|
50
|
+
* owned by `owner`, so a volume surviving its container stays with the
|
|
51
|
+
* checkout that made it. */
|
|
52
|
+
export declare function claimable(runtime: string, name: string, owner: string): boolean;
|
|
53
|
+
/** `rm -f`; a missing container is fine, any other failure throws. */
|
|
54
|
+
export declare function removeContainer(runtime: string, name: string): void;
|
|
55
|
+
/** `volume rm -f`; a missing volume is fine, any other failure throws. */
|
|
56
|
+
export declare function removeVolume(runtime: string, name: string): void;
|
|
57
|
+
/** Local Postgres instance. */
|
|
58
|
+
interface PostgresContainerOptions {
|
|
59
|
+
/** Container name. */
|
|
60
|
+
name: string;
|
|
61
|
+
/** Immutable image ID from `ensureImage`. */
|
|
62
|
+
image: string;
|
|
63
|
+
/** Schema hash of the image. */
|
|
64
|
+
hash: string;
|
|
65
|
+
/** Published loopback port; omitted lets the runtime assign one. */
|
|
66
|
+
port?: number;
|
|
67
|
+
/** Persistent data volume, created labeled for `owner`; omitted uses the container's disposable storage. */
|
|
68
|
+
volume?: string;
|
|
69
|
+
/** Owning checkout, stored as `OWNER_LABEL` on the container and the volume. */
|
|
70
|
+
owner?: string;
|
|
71
|
+
/** Postgres server arguments appended to the image command. */
|
|
72
|
+
serverArgs?: readonly string[];
|
|
73
|
+
/** Further container labels, applied at creation. */
|
|
74
|
+
labels?: Readonly<Record<string, string>>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Reuses a container of exactly `image`, `owner`, server arguments and
|
|
78
|
+
* settings, else recreates it (named volumes survive). Resolves once
|
|
79
|
+
* Postgres accepts connections and the data carries `hash`, with the
|
|
80
|
+
* published host port. `resources` stops a persistent container this call
|
|
81
|
+
* started; one already running is left alone. The caller removes an
|
|
82
|
+
* ephemeral one (`volume` unset).
|
|
83
|
+
*/
|
|
84
|
+
export declare function startPostgresContainer(runtime: string, resources: ResourceScope, { name, image, hash, port, volume, owner, serverArgs, labels, }: PostgresContainerOptions): Promise<{
|
|
85
|
+
port: number;
|
|
86
|
+
}>;
|
|
87
|
+
export {};
|