@shivaedev/local-postgres 0.7.0 → 0.9.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/CHANGELOG.md +23 -0
- package/README.md +51 -38
- package/dist/server/LocalPostgresError.d.ts +8 -0
- package/dist/server/LocalPostgresError.d.ts.map +1 -0
- package/dist/server/LocalPostgresError.js +6 -0
- package/dist/server/LocalPostgresError.js.map +1 -0
- package/dist/server/PostgresCommandError.d.ts +11 -0
- package/dist/server/PostgresCommandError.d.ts.map +1 -0
- package/dist/server/PostgresCommandError.js +9 -0
- package/dist/server/PostgresCommandError.js.map +1 -0
- package/dist/server/PostgresVersionMismatch.d.ts +8 -5
- package/dist/server/PostgresVersionMismatch.d.ts.map +1 -1
- package/dist/server/PostgresVersionMismatch.js +7 -7
- package/dist/server/PostgresVersionMismatch.js.map +1 -1
- package/dist/server/clientConnection.d.ts +13 -0
- package/dist/server/clientConnection.d.ts.map +1 -0
- package/dist/server/clientConnection.js +19 -0
- package/dist/server/clientConnection.js.map +1 -0
- package/dist/server/localConnections.d.ts +16 -6
- package/dist/server/localConnections.d.ts.map +1 -1
- package/dist/server/localConnections.js +30 -24
- package/dist/server/localConnections.js.map +1 -1
- package/dist/server/localContainer.d.ts +8 -4
- package/dist/server/localContainer.d.ts.map +1 -1
- package/dist/server/localContainer.js +24 -36
- package/dist/server/localContainer.js.map +1 -1
- package/dist/server/localDocker.d.ts +7 -2
- package/dist/server/localDocker.d.ts.map +1 -1
- package/dist/server/localDocker.js +17 -9
- package/dist/server/localDocker.js.map +1 -1
- package/dist/server/localPostgres.d.ts +8 -5
- package/dist/server/localPostgres.d.ts.map +1 -1
- package/dist/server/localPostgres.js +53 -82
- package/dist/server/localPostgres.js.map +1 -1
- package/dist/server/runCommand.d.ts +7 -0
- package/dist/server/runCommand.d.ts.map +1 -0
- package/dist/server/runCommand.js +23 -0
- package/dist/server/runCommand.js.map +1 -0
- package/package.json +8 -4
- package/src/server/LocalPostgresError.ts +5 -0
- package/src/server/PostgresCommandError.ts +8 -0
- package/src/server/PostgresVersionMismatch.ts +7 -7
- package/src/server/clientConnection.ts +20 -0
- package/src/server/localConnections.ts +42 -24
- package/src/server/localContainer.ts +32 -36
- package/src/server/localDocker.ts +18 -10
- package/src/server/localPostgres.ts +62 -85
- package/src/server/runCommand.ts +31 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.0 - 2026-11-02
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Pin Docker operations to the validated local endpoint and refuse conflicting Docker host or context settings in the command environment before invoking Docker.
|
|
8
|
+
- Accept PostgreSQL 18.6 distribution version suffixes and leave native server connection limits unchanged when the managed container is unavailable.
|
|
9
|
+
- Return a typed `LocalPostgresError` for malformed URL password escapes instead of a defect.
|
|
10
|
+
|
|
11
|
+
### Breaking
|
|
12
|
+
|
|
13
|
+
- `clientConnection` now returns an Effect. Replace direct calls with `yield* clientConnection(url, options)` inside an Effect program so password decoding failures stay in the typed error channel.
|
|
14
|
+
|
|
15
|
+
## 0.8.0 - 2026-10-31
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Generated applications provide Node services when running database setup, so setup commands participate in Effect interruption and typed failure handling.
|
|
20
|
+
|
|
21
|
+
### Breaking
|
|
22
|
+
|
|
23
|
+
- `@shivaedev/local-postgres`: `assertLocalDatabase`, `sql`, `startPostgres`, `prepareDatabases` and lower-level command helpers return Effects. Yield them in an Effect program and provide `ChildProcessSpawner` for commands, for example with `NodeServices.layer` at a Node entry point. Replace synchronous try/catch with Effect error handling. Command failures use `PostgresCommandError`; local-target and image refusals use `LocalPostgresError`. Construct the Schema tagged errors as `new PostgresVersionMismatch({ expectedVersion: "18.6", observedVersion })` or `new PostgresSettingError({ container: "development-postgres", setting: "max_connections", cause })`. Exhausted readiness checks retain their final failure instead of reporting an unobserved version mismatch.
|
|
24
|
+
- `@shivaedev/server`: `setupDatabases()` requires `ChildProcessSpawner` and exposes local PostgreSQL failures in its typed error channel. Provide `NodeServices.layer` at the setup entry point instead of relying on synchronous commands hidden inside the host.
|
|
25
|
+
|
|
3
26
|
## 0.7.0 - 2026-10-25
|
|
4
27
|
|
|
5
28
|
### Breaking
|
package/README.md
CHANGED
|
@@ -7,10 +7,16 @@ Make development and integration tests share one persistent local PostgreSQL ser
|
|
|
7
7
|
A setup command should make a machine ready to work without erasing the work already on it. Reimplementing PostgreSQL startup in every repository makes that promise harder to keep. This package gives a setup script one place to prepare the service and its databases:
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
+
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
11
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
12
|
+
import { Effect } from "effect";
|
|
10
13
|
import { LOCAL_SERVER, localPostgres } from "@shivaedev/local-postgres/server/localPostgres.ts";
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
localPostgres(
|
|
15
|
+
NodeRuntime.runMain(
|
|
16
|
+
localPostgres({})
|
|
17
|
+
.prepareDatabases([`${LOCAL_SERVER}/example_dev`])
|
|
18
|
+
.pipe(Effect.provide(NodeServices.layer)),
|
|
19
|
+
);
|
|
14
20
|
```
|
|
15
21
|
|
|
16
22
|
The application supplies its configured database URL. Preparation checks that the target is local and can run again without losing the data already in the database.
|
|
@@ -20,12 +26,11 @@ The application supplies its configured database URL. Preparation checks that th
|
|
|
20
26
|
### How to think about it
|
|
21
27
|
|
|
22
28
|
There are three separate responsibilities:
|
|
23
|
-
|
|
24
29
|
1. The **service** is PostgreSQL running on the local machine. This package prepares access to it.
|
|
25
30
|
2. A **database** is an application-chosen name on that service. This package creates missing databases; the application chooses their names through configuration or a fixed allowlist.
|
|
26
31
|
3. The **schema and data** belong to the application. Its setup script runs migrations, loads fixtures or seeds data after preparation.
|
|
27
32
|
|
|
28
|
-
`localPostgres(environment)` returns three
|
|
33
|
+
`localPostgres(environment)` returns three functions that produce Effects: `startPostgres`, `prepareDatabases` and `sql`. Yield them in setup tooling, and provide `ChildProcessSpawner` through the Effect environment. `NodeServices.layer` supplies the Node implementation at an entry point; command scopes preserve interruption and readiness waits use Effect’s clock. Use your application's database client and `@shivaedev/sql` for persistence and migrations in an Effect application.
|
|
29
34
|
|
|
30
35
|
### 1. Once per application: choose the databases
|
|
31
36
|
|
|
@@ -34,79 +39,87 @@ There are three separate responsibilities:
|
|
|
34
39
|
When database names come from the application's configured URLs, pass those URLs directly to preparation:
|
|
35
40
|
|
|
36
41
|
```ts
|
|
42
|
+
import { Config, Effect } from "effect";
|
|
37
43
|
import { LOCAL_SERVER, localPostgres } from "@shivaedev/local-postgres/server/localPostgres.ts";
|
|
38
44
|
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
const setup = Effect.gen(function* () {
|
|
46
|
+
const development = yield* Config.String("DATABASE_URL").pipe(Config.withDefault(`${LOCAL_SERVER}/example_dev`));
|
|
47
|
+
const tests = yield* Config.String("TEST_DATABASE_URL").pipe(Config.withDefault(`${LOCAL_SERVER}/example_test`));
|
|
48
|
+
const environment = yield* Config.all({
|
|
49
|
+
"DOCKER_CONTEXT": Config.String("DOCKER_CONTEXT").pipe(Config.withDefault("")),
|
|
50
|
+
"DOCKER_HOST": Config.String("DOCKER_HOST").pipe(Config.withDefault("")),
|
|
51
|
+
});
|
|
52
|
+
yield* localPostgres(environment).prepareDatabases([development, tests]);
|
|
53
|
+
});
|
|
43
54
|
```
|
|
44
55
|
|
|
45
56
|
Generated applications use this configuration-driven approach. An allowlist built from the same URLs adds no restriction; preparation's own local-target check is the guard.
|
|
46
57
|
|
|
47
|
-
Use `assertLocalDatabase` when the setup script owns a fixed set of database names, as
|
|
58
|
+
Use `assertLocalDatabase` when the setup script owns a fixed set of database names, as the Platform repository's [`script/setup-database.ts`](https://github.com/ShivaeDev/platform/blob/main/script/setup-database.ts) does. Its allowlist restricts configuration to the names the script intends to touch:
|
|
48
59
|
|
|
49
60
|
```ts
|
|
61
|
+
import { Effect } from "effect";
|
|
50
62
|
import { assertLocalDatabase, LOCAL_SERVER, localPostgres } from "@shivaedev/local-postgres/server/localPostgres.ts";
|
|
51
63
|
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
assertLocalDatabase(development, ["example_dev"]);
|
|
56
|
-
assertLocalDatabase(tests, ["example_test"]);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
postgres.prepareDatabases([development, tests]);
|
|
64
|
+
const setup = Effect.gen(function* () {
|
|
65
|
+
const development = `${LOCAL_SERVER}/example_dev`;
|
|
66
|
+
const tests = `${LOCAL_SERVER}/example_test`;
|
|
67
|
+
yield* assertLocalDatabase(development, ["example_dev"]);
|
|
68
|
+
yield* assertLocalDatabase(tests, ["example_test"]);
|
|
69
|
+
yield* localPostgres({}).prepareDatabases([development, tests]);
|
|
70
|
+
});
|
|
60
71
|
```
|
|
61
72
|
|
|
62
73
|
`assertLocalDatabase` applies the same local-target checks and also rejects a database name outside the caller's allowlist. The fixed names above provide an independent application policy.
|
|
63
74
|
|
|
64
75
|
### 2. Once per feature: prepare its schema in application tooling
|
|
65
76
|
|
|
66
|
-
After `prepareDatabases`, run the application's own schema or migration entry point. This package provides no schema model, migration ledger, fixture catalogue or seed convention. `@shivaedev/
|
|
77
|
+
After `prepareDatabases`, run the application's own schema or migration entry point. This package provides no schema model, migration ledger, fixture catalogue or seed convention. `@shivaedev/sql` owns the SQL and migration APIs.
|
|
67
78
|
|
|
68
79
|
### 3. In daily setup: prepare again and inspect with SQL
|
|
69
80
|
|
|
70
81
|
```ts
|
|
82
|
+
import { Effect } from "effect";
|
|
71
83
|
import { LOCAL_SERVER, localPostgres } from "@shivaedev/local-postgres/server/localPostgres.ts";
|
|
72
84
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const postgres = localPostgres(
|
|
76
|
-
postgres.prepareDatabases([database]);
|
|
77
|
-
|
|
85
|
+
const setup = Effect.gen(function* () {
|
|
86
|
+
const database = `${LOCAL_SERVER}/example_dev`;
|
|
87
|
+
const postgres = localPostgres({});
|
|
88
|
+
yield* postgres.prepareDatabases([database]);
|
|
89
|
+
yield* Effect.log(yield* postgres.sql(database, "SHOW server_version"));
|
|
90
|
+
});
|
|
78
91
|
```
|
|
79
92
|
|
|
80
|
-
The version query returns
|
|
93
|
+
Run these setup Effects at a Node entry point with `NodeRuntime.runMain(setup.pipe(Effect.provide(NodeServices.layer)))`, as in the first example. The version query returns `18.6` for the managed image; native distributions may append packaging details. `sql` also accepts a `URL` and returns the command's trimmed text. URLs carrying the application's `schema` and `connection_limit` settings work for this query; those settings are removed before calling PostgreSQL's client.
|
|
81
94
|
|
|
82
95
|
`startPostgres(connection)` prepares the service without choosing an application database to create. Its connection defaults to `LOCAL_SERVER`. Prefer `prepareDatabases` when the setup script needs named databases as well.
|
|
83
96
|
|
|
84
|
-
On each start, setup reads `SHOW max_connections`. When the
|
|
97
|
+
On each start, setup reads `SHOW max_connections`. Native servers retain their configured limit. When the running managed container publishes port 55432 and allows fewer than 500 connections, setup applies `ALTER SYSTEM SET max_connections = 500`, restarts that same container, waits for readiness and confirms the setting. Existing data stays in place. A limit of 500 or higher causes no setting change or restart. If the setting cannot be applied, setup fails with `PostgresSettingError` from `@shivaedev/local-postgres/server/localConnections.ts`, with `_tag`, `container`, `setting` and the original `cause`.
|
|
85
98
|
|
|
86
99
|
### API
|
|
87
100
|
|
|
88
101
|
Import the setup API from `@shivaedev/local-postgres/server/localPostgres.ts`:
|
|
89
102
|
|
|
90
|
-
| Export
|
|
91
|
-
|
|
|
92
|
-
| `LOCAL_SERVER`
|
|
93
|
-
| `assertLocalDatabase(value: string, names: readonly string[])
|
|
103
|
+
| Export | Purpose |
|
|
104
|
+
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
105
|
+
| `LOCAL_SERVER` | The base URL `postgresql://postgres:postgres@127.0.0.1:55432`. Append the application database name. |
|
|
106
|
+
| `assertLocalDatabase(value: string, names: readonly string[])` | Return an Effect validating a local database URL against application-owned allowed names. |
|
|
94
107
|
| `localPostgres(environment: DockerEnvironment, readiness?: ReadinessOptions)` | Create the setup functions using the Docker settings to validate. After starting the container, `startPostgres` checks readiness `attempts` times (default 30), waiting `delayMillis` between checks (default 1000). |
|
|
95
|
-
| `prepareDatabases(values: readonly string[])
|
|
96
|
-
| `startPostgres(connection?: string)
|
|
97
|
-
| `sql(value: string \| URL, query: string)
|
|
108
|
+
| `prepareDatabases(values: readonly string[])` | Return an Effect preparing the service and creating absent databases. |
|
|
109
|
+
| `startPostgres(connection?: string)` | Return an Effect preparing the service; the default connection is `LOCAL_SERVER`. |
|
|
110
|
+
| `sql(value: string \| URL, query: string)` | Return an Effect executing SQL through PostgreSQL's command-line client. |
|
|
98
111
|
|
|
99
|
-
The last three functions are members of the object returned by `localPostgres`, not module-level exports. They
|
|
112
|
+
The last three functions are members of the object returned by `localPostgres`, not module-level exports. They fail in the typed error channel. `PostgresCommandError` carries the command, diagnostic message and exit code or platform cause; `LocalPostgresError` describes local-target and image refusals, and malformed URL password escapes. Exhausted readiness checks retain their final failure; a version mismatch always names a version the service returned.
|
|
100
113
|
|
|
101
114
|
The module export pattern also exposes the lower-level Docker and container command functions in `@shivaedev/local-postgres/server/localDocker.ts` and `@shivaedev/local-postgres/server/localContainer.ts`. Use `@shivaedev/local-postgres/server/localPostgres.ts` for application preparation.
|
|
102
115
|
|
|
103
116
|
### Install and machine setup
|
|
104
117
|
|
|
105
118
|
```sh
|
|
106
|
-
pnpm add --save-dev @shivaedev/local-postgres
|
|
119
|
+
pnpm add --save-dev @shivaedev/local-postgres @effect/platform-node effect
|
|
107
120
|
```
|
|
108
121
|
|
|
109
|
-
The package requires Node 24 or later and
|
|
122
|
+
The package requires Node 24 or later and uses Effect as a peer dependency. It needs host `psql` or a local Docker installation. SQL uses host `psql` when available and falls back to the container's client when the host executable is missing. Both clients receive the connection password through `PGPASSWORD`, outside the command line. Query failures retain PostgreSQL's diagnostics and command failure details (and a platform `cause` when a process cannot start) without exposing the connection password.
|
|
110
123
|
|
|
111
124
|
The shared baseline is PostgreSQL 18.6 on loopback port 55432. Docker preparation uses container and volume name `development-postgres`, loopback publication `127.0.0.1:55432:5432`, and this image:
|
|
112
125
|
|
|
@@ -114,14 +127,14 @@ The shared baseline is PostgreSQL 18.6 on loopback port 55432. Docker preparatio
|
|
|
114
127
|
postgres:18.6-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873
|
|
115
128
|
```
|
|
116
129
|
|
|
117
|
-
A newly created container uses username and password `postgres`; connection URLs supply credentials for client commands. Setup refuses a running
|
|
130
|
+
A newly created container uses username and password `postgres`; connection URLs supply credentials for client commands. Setup accepts native PostgreSQL 18.6 version strings with distribution suffixes, such as `18.6 (Debian 18.6-1.pgdg13+2)`, without requiring a managed container or Docker installation. Setup refuses a running release other than 18.6 with `PostgresVersionMismatch` from `@shivaedev/local-postgres/server/PostgresVersionMismatch.ts`. The error carries `_tag: "PostgresVersionMismatch"`, `expectedVersion` and `observedVersion`. A running PostgreSQL 17 service is refused without losing its existing rows; upgrading it while preserving its data is your job. Container preparation and container-client fallback also check the managed image; a successful host-`psql` version probe does not inspect that image.
|
|
118
131
|
|
|
119
|
-
|
|
132
|
+
Read Docker settings through Effect Config and pass them to `localPostgres`, as in the configuration example. With `DOCKER_CONTEXT`, endpoint validation uses that context and ignores `DOCKER_HOST`; otherwise it validates `DOCKER_HOST` or the active context. Remote endpoints are rejected before a Docker operation. Each operation pins `DOCKER_HOST` to the validated endpoint and clears `DOCKER_CONTEXT`. The lower-level `docker` function refuses command environment settings that conflict with the supplied `DOCKER_HOST` or `DOCKER_CONTEXT` before invoking Docker.
|
|
120
133
|
|
|
121
134
|
### Limits
|
|
122
135
|
|
|
123
136
|
- The service version, port, container name and volume name are fixed. Choose any upgrade and data-preservation procedure outside this package.
|
|
124
|
-
-
|
|
137
|
+
- Keep commands in development and test setup tooling; setup never becomes an application request path.
|
|
125
138
|
- Keep allowed names, schema changes, test isolation and cleanup in the application. Preparation is not a database reset.
|
|
126
139
|
- A prepared database name has 1–63 lowercase letters, digits or underscores and starts with a letter. An allowlisted connection URL does not bypass this SQL-name constraint.
|
|
127
140
|
- Concurrent creation of the same absent database is not supported. Prepare databases before parallel tests begin.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
declare const LocalPostgresError_base: Schema.Class<LocalPostgresError, Schema.TaggedStruct<"LocalPostgresError", {
|
|
3
|
+
readonly message: Schema.String;
|
|
4
|
+
}>, import("effect/Cause").YieldableError>;
|
|
5
|
+
export declare class LocalPostgresError extends LocalPostgresError_base {
|
|
6
|
+
}
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=LocalPostgresError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalPostgresError.d.ts","sourceRoot":"","sources":["../../src/server/LocalPostgresError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAEhC,qBAAa,kBAAmB,SAAQ,uBAEtC;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalPostgresError.js","sourceRoot":"","sources":["../../src/server/LocalPostgresError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAAC,oBAAoB,EAAE;IACtG,OAAO,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
declare const PostgresCommandError_base: Schema.Class<PostgresCommandError, Schema.TaggedStruct<"PostgresCommandError", {
|
|
3
|
+
readonly cause: Schema.optional<Schema.Unknown>;
|
|
4
|
+
readonly command: Schema.String;
|
|
5
|
+
readonly exitCode: Schema.optional<Schema.Number>;
|
|
6
|
+
readonly message: Schema.String;
|
|
7
|
+
}>, import("effect/Cause").YieldableError>;
|
|
8
|
+
export declare class PostgresCommandError extends PostgresCommandError_base {
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=PostgresCommandError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresCommandError.d.ts","sourceRoot":"","sources":["../../src/server/PostgresCommandError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;;;;AAEhC,qBAAa,oBAAqB,SAAQ,yBAKxC;CAAG"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export class PostgresCommandError extends Schema.TaggedError()("PostgresCommandError", {
|
|
3
|
+
cause: Schema.optional(Schema.Unknown),
|
|
4
|
+
command: Schema.String,
|
|
5
|
+
exitCode: Schema.optional(Schema.Number),
|
|
6
|
+
message: Schema.String,
|
|
7
|
+
}) {
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=PostgresCommandError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresCommandError.js","sourceRoot":"","sources":["../../src/server/PostgresCommandError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,oBAAqB,SAAQ,MAAM,CAAC,WAAW,EAAwB,CAAC,sBAAsB,EAAE;IAC5G,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
readonly expectedVersion
|
|
4
|
-
readonly observedVersion:
|
|
5
|
-
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
declare const PostgresVersionMismatch_base: Schema.Class<PostgresVersionMismatch, Schema.TaggedStruct<"PostgresVersionMismatch", {
|
|
3
|
+
readonly expectedVersion: Schema.Literal<"18.6">;
|
|
4
|
+
readonly observedVersion: Schema.String;
|
|
5
|
+
}>, import("effect/Cause").YieldableError>;
|
|
6
|
+
export declare class PostgresVersionMismatch extends PostgresVersionMismatch_base {
|
|
7
|
+
get message(): string;
|
|
6
8
|
}
|
|
9
|
+
export {};
|
|
7
10
|
//# sourceMappingURL=PostgresVersionMismatch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostgresVersionMismatch.d.ts","sourceRoot":"","sources":["../../src/server/PostgresVersionMismatch.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"PostgresVersionMismatch.d.ts","sourceRoot":"","sources":["../../src/server/PostgresVersionMismatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;;AAEhC,qBAAa,uBAAwB,SAAQ,4BAG3C;IACD,IAAa,OAAO,WAEnB;CACD"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
expectedVersion
|
|
4
|
-
observedVersion
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export class PostgresVersionMismatch extends Schema.TaggedError()("PostgresVersionMismatch", {
|
|
3
|
+
expectedVersion: Schema.Literal("18.6"),
|
|
4
|
+
observedVersion: Schema.String,
|
|
5
|
+
}) {
|
|
6
|
+
get message() {
|
|
7
|
+
return "Expected local PostgreSQL 18.6. Check the existing service; setup never removes containers or data.";
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
//# sourceMappingURL=PostgresVersionMismatch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostgresVersionMismatch.js","sourceRoot":"","sources":["../../src/server/PostgresVersionMismatch.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,uBAAwB,SAAQ,
|
|
1
|
+
{"version":3,"file":"PostgresVersionMismatch.js","sourceRoot":"","sources":["../../src/server/PostgresVersionMismatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,uBAAwB,SAAQ,MAAM,CAAC,WAAW,EAA2B,CAAC,yBAAyB,EAAE;IACrH,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IACvC,eAAe,EAAE,MAAM,CAAC,MAAM;CAC9B,CAAC;IACD,IAAa,OAAO;QACnB,OAAO,qGAAqG,CAAC;IAC9G,CAAC;CACD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { LocalPostgresError } from "#LocalPostgresError.ts";
|
|
3
|
+
import type { CommandOptions } from "#runCommand.ts";
|
|
4
|
+
export declare const clientConnection: (value: URL, options?: CommandOptions | undefined) => Effect.Effect<{
|
|
5
|
+
options: {
|
|
6
|
+
env: {
|
|
7
|
+
PGPASSWORD?: string;
|
|
8
|
+
};
|
|
9
|
+
extendEnv: boolean;
|
|
10
|
+
};
|
|
11
|
+
url: import("url").URL;
|
|
12
|
+
}, LocalPostgresError, never>;
|
|
13
|
+
//# sourceMappingURL=clientConnection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientConnection.d.ts","sourceRoot":"","sources":["../../src/server/clientConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,gBAAgB;;;;;;;;6BAe3B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { LocalPostgresError } from "#LocalPostgresError.ts";
|
|
3
|
+
export const clientConnection = Effect.fn("LocalPostgres.clientConnection")(function* (value, options = {}) {
|
|
4
|
+
const url = new URL(value);
|
|
5
|
+
// libpq treats + literally in URI passwords.
|
|
6
|
+
const password = yield* Effect.try({
|
|
7
|
+
catch: () => new LocalPostgresError({ message: "Invalid local database password escape." }),
|
|
8
|
+
try: () => new URLSearchParams(url.search.replaceAll("+", "%2B")).getAll("password").at(-1) ?? decodeURIComponent(url.password),
|
|
9
|
+
});
|
|
10
|
+
url.password = "";
|
|
11
|
+
for (const key of ["password", "schema", "connection_limit", "pool_timeout", "pgbouncer"]) {
|
|
12
|
+
url.searchParams.delete(key);
|
|
13
|
+
}
|
|
14
|
+
if (!url.searchParams.has("connect_timeout")) {
|
|
15
|
+
url.searchParams.set("connect_timeout", "3");
|
|
16
|
+
}
|
|
17
|
+
return { options: { ...options, env: { ...options.env, ...(password && { "PGPASSWORD": password }) }, extendEnv: true }, url };
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=clientConnection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientConnection.js","sourceRoot":"","sources":["../../src/server/clientConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,gCAAgC,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAU,EAAE,OAAO,GAAmB,EAAE;IAC9H,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAClC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC;QAC3F,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC;KAC/H,CAAC,CAAC;IACH,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,WAAW,CAAC,EAAE,CAAC;QAC3F,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC;AAChI,CAAC,CAAC,CAAC"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { ChildProcessSpawner } from "effect/process";
|
|
3
|
+
import { LocalPostgresError } from "#LocalPostgresError.ts";
|
|
4
|
+
import type { docker as localDocker } from "#localDocker.ts";
|
|
5
|
+
import type { PostgresCommandError } from "#PostgresCommandError.ts";
|
|
6
|
+
import type { PostgresVersionMismatch } from "#PostgresVersionMismatch.ts";
|
|
7
|
+
declare const PostgresSettingError_base: Schema.Class<PostgresSettingError, Schema.TaggedStruct<"PostgresSettingError", {
|
|
8
|
+
readonly cause: Schema.Unknown;
|
|
9
|
+
readonly container: Schema.Literal<"development-postgres">;
|
|
10
|
+
readonly setting: Schema.Literal<"max_connections">;
|
|
11
|
+
}>, import("effect/Cause").YieldableError>;
|
|
12
|
+
export declare class PostgresSettingError extends PostgresSettingError_base {
|
|
13
|
+
get message(): string;
|
|
6
14
|
}
|
|
7
|
-
|
|
15
|
+
type Query = (query: string) => Effect.Effect<string, LocalPostgresError | PostgresCommandError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
16
|
+
export declare const ensureConnections: (docker: (args: readonly string[]) => ReturnType<typeof localDocker>, sql: Query, ready: () => Effect.Effect<void, LocalPostgresError | PostgresCommandError | PostgresVersionMismatch, ChildProcessSpawner.ChildProcessSpawner>) => Effect.Effect<void, PostgresSettingError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
17
|
+
export {};
|
|
8
18
|
//# sourceMappingURL=localConnections.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localConnections.d.ts","sourceRoot":"","sources":["../../src/server/localConnections.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"localConnections.d.ts","sourceRoot":"","sources":["../../src/server/localConnections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;;;;;;AAE3E,qBAAa,oBAAqB,SAAQ,yBAIxC;IACD,IAAa,OAAO,WAEnB;CACD;AAED,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,CAAC;AAE1I,eAAO,MAAM,iBAAiB,kBACd,SAAS,MAAM,EAAE,KAAK,UAAU,CAAC,OAAO,WAAW,CAAC,2BAEtD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,oBAAoB,GAAG,uBAAuB,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,uFA6B7I,CAAC"}
|
|
@@ -1,34 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { LocalPostgresError } from "#LocalPostgresError.ts";
|
|
3
|
+
import { POSTGRES_IMAGE } from "#localContainer.ts";
|
|
4
|
+
export class PostgresSettingError extends Schema.TaggedError()("PostgresSettingError", {
|
|
5
|
+
cause: Schema.Unknown,
|
|
6
|
+
container: Schema.Literal("development-postgres"),
|
|
7
|
+
setting: Schema.Literal("max_connections"),
|
|
8
|
+
}) {
|
|
9
|
+
get message() {
|
|
10
|
+
return "Could not set max_connections to at least 500 in container development-postgres.";
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
const current = Number(sql("SHOW max_connections"));
|
|
13
|
+
export const ensureConnections = Effect.fn("LocalPostgres.ensureConnections")(function* (docker, sql, ready) {
|
|
14
|
+
yield* Effect.gen(function* () {
|
|
15
|
+
const current = Number(yield* sql("SHOW max_connections"));
|
|
14
16
|
if (!Number.isInteger(current) || current <= 0) {
|
|
15
|
-
|
|
17
|
+
return yield* new LocalPostgresError({ message: "PostgreSQL returned an invalid max_connections value." });
|
|
16
18
|
}
|
|
17
19
|
if (current >= 500) {
|
|
18
20
|
return;
|
|
19
21
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
const managed = yield* docker(["ps", "--filter", "name=^/development-postgres$", "--filter", "publish=55432", "--format", "{{.ID}}"]).pipe(Effect.catchTag("PostgresCommandError", () => Effect.succeed("")));
|
|
23
|
+
if (!managed) {
|
|
24
|
+
return;
|
|
22
25
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
const image = yield* docker(["inspect", "--format", "{{.Config.Image}}", "development-postgres"]);
|
|
27
|
+
if (image !== POSTGRES_IMAGE) {
|
|
28
|
+
return yield* new LocalPostgresError({
|
|
29
|
+
message: "The shared PostgreSQL container uses a different image. Preserve its data and upgrade it explicitly.",
|
|
30
|
+
});
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
32
|
+
yield* sql("ALTER SYSTEM SET max_connections = 500");
|
|
33
|
+
yield* docker(["restart", "development-postgres"]);
|
|
34
|
+
yield* ready();
|
|
35
|
+
if (!(Number(yield* sql("SHOW max_connections")) >= 500)) {
|
|
36
|
+
return yield* new LocalPostgresError({ message: "PostgreSQL did not apply max_connections after restarting." });
|
|
37
|
+
}
|
|
38
|
+
}).pipe(Effect.mapError((cause) => new PostgresSettingError({ cause, container: "development-postgres", setting: "max_connections" })));
|
|
39
|
+
});
|
|
34
40
|
//# sourceMappingURL=localConnections.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localConnections.js","sourceRoot":"","sources":["../../src/server/localConnections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"localConnections.js","sourceRoot":"","sources":["../../src/server/localConnections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKpD,MAAM,OAAO,oBAAqB,SAAQ,MAAM,CAAC,WAAW,EAAwB,CAAC,sBAAsB,EAAE;IAC5G,KAAK,EAAE,MAAM,CAAC,OAAO;IACrB,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC;CAC1C,CAAC;IACD,IAAa,OAAO;QACnB,OAAO,kFAAkF,CAAC;IAC3F,CAAC;CACD;AAID,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAC,iCAAiC,CAAC,CAAC,QAAQ,CAAC,EACtF,MAAmE,EACnE,GAAU,EACV,KAA8I;IAE9I,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO,KAAK,CAAC,CAAC,IAAI,kBAAkB,CAAC,EAAE,OAAO,EAAE,uDAAuD,EAAE,CAAC,CAAC;QAC5G,CAAC;QACD,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,8BAA8B,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CACzI,MAAM,CAAC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CACjE,CAAC;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO;QACR,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,sBAAsB,CAAC,CAAC,CAAC;QAClG,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC,CAAC,IAAI,kBAAkB,CAAC;gBACpC,OAAO,EAAE,sGAAsG;aAC/G,CAAC,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACrD,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC,CAAC;QACnD,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC1D,OAAO,KAAK,CAAC,CAAC,IAAI,kBAAkB,CAAC,EAAE,OAAO,EAAE,4DAA4D,EAAE,CAAC,CAAC;QACjH,CAAC;IACF,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,oBAAoB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;AACzI,CAAC,CAAC,CAAC"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { LocalPostgresError } from "#LocalPostgresError.ts";
|
|
3
|
+
import type { docker as runDocker } from "#localDocker.ts";
|
|
4
|
+
import { PostgresCommandError } from "#PostgresCommandError.ts";
|
|
5
|
+
import type { CommandOptions } from "#runCommand.ts";
|
|
2
6
|
export declare const POSTGRES_IMAGE = "postgres:18.6-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873";
|
|
3
|
-
type Docker = (args: readonly string[], options?:
|
|
4
|
-
export declare
|
|
5
|
-
export declare
|
|
7
|
+
type Docker = (args: readonly string[], options?: CommandOptions) => ReturnType<typeof runDocker>;
|
|
8
|
+
export declare const sqlInContainer: (docker: Docker, url: URL, args: readonly string[], options: CommandOptions) => Effect.Effect<string, LocalPostgresError | PostgresCommandError, import("effect/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
9
|
+
export declare const startContainer: (docker: Docker) => Effect.Effect<undefined, LocalPostgresError | PostgresCommandError, import("effect/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
6
10
|
export {};
|
|
7
11
|
//# sourceMappingURL=localContainer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localContainer.d.ts","sourceRoot":"","sources":["../../src/server/localContainer.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"localContainer.d.ts","sourceRoot":"","sources":["../../src/server/localContainer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,cAAc,iGAAiG,CAAC;AAE7H,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAElG,eAAO,MAAM,cAAc,oNAmBzB,CAAC;AAEH,eAAO,MAAM,cAAc,2JA2BzB,CAAC"}
|
|
@@ -1,49 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { clientConnection } from "#clientConnection.ts";
|
|
3
|
+
import { LocalPostgresError } from "#LocalPostgresError.ts";
|
|
4
|
+
import { PostgresCommandError } from "#PostgresCommandError.ts";
|
|
2
5
|
export const POSTGRES_IMAGE = "postgres:18.6-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873";
|
|
3
6
|
const CONTAINER = "development-postgres";
|
|
4
|
-
export
|
|
5
|
-
const id = docker(["ps", "--filter", "publish=55432", "--format", "{{.ID}}"], options)
|
|
7
|
+
export const sqlInContainer = Effect.fn("LocalPostgres.sqlInContainer")(function* (docker, url, args, options) {
|
|
8
|
+
const id = yield* docker(["ps", "--filter", "publish=55432", "--format", "{{.ID}}"], options);
|
|
6
9
|
if (!id || id.includes("\n")) {
|
|
7
|
-
|
|
10
|
+
return yield* new PostgresCommandError({ command: "psql", message: "Install psql or start the shared PostgreSQL service with Docker." });
|
|
8
11
|
}
|
|
9
|
-
if (docker(["inspect", "--format", "{{.Config.Image}}", id], options)
|
|
10
|
-
|
|
12
|
+
if ((yield* docker(["inspect", "--format", "{{.Config.Image}}", id], options)) !== POSTGRES_IMAGE) {
|
|
13
|
+
return yield* new LocalPostgresError({
|
|
14
|
+
message: "The shared PostgreSQL image differs from the pinned baseline. Upgrade explicitly, preserving data.",
|
|
15
|
+
});
|
|
11
16
|
}
|
|
12
|
-
|
|
13
|
-
const password = new URLSearchParams(url.search.replaceAll("+", "%2B")).getAll("password").at(-1) ?? decodeURIComponent(url.password);
|
|
14
|
-
const inside = new URL(url);
|
|
17
|
+
const { url: inside, options: settings } = yield* clientConnection(url, options);
|
|
15
18
|
inside.hostname = "127.0.0.1";
|
|
16
19
|
inside.port = "5432";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
env: { ...env, ...options.env, ...(password && { "PGPASSWORD": password }) },
|
|
23
|
-
}).trim();
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
throw new Error(error instanceof Error && "stderr" in error ? String(error.stderr) : "PostgreSQL query failed.", { cause: error });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export function startContainer(docker) {
|
|
30
|
-
docker(["info"]);
|
|
31
|
-
let existing;
|
|
32
|
-
try {
|
|
33
|
-
docker(["container", "inspect", CONTAINER]);
|
|
34
|
-
existing = true;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
existing = false;
|
|
38
|
-
}
|
|
20
|
+
return yield* docker(["exec", "--env", "PGPASSWORD", id, "psql", ...args, "--dbname", inside.toString()], settings);
|
|
21
|
+
});
|
|
22
|
+
export const startContainer = Effect.fn("LocalPostgres.startContainer")(function* (docker) {
|
|
23
|
+
yield* docker(["info"]);
|
|
24
|
+
const existing = yield* docker(["container", "ls", "--all", "--filter", `name=^/${CONTAINER}$`, "--format", "{{.ID}}"]);
|
|
39
25
|
if (existing) {
|
|
40
|
-
if (docker(["inspect", "--format", "{{.Config.Image}}", CONTAINER])
|
|
41
|
-
|
|
26
|
+
if ((yield* docker(["inspect", "--format", "{{.Config.Image}}", CONTAINER])) !== POSTGRES_IMAGE) {
|
|
27
|
+
return yield* new LocalPostgresError({
|
|
28
|
+
message: "The shared PostgreSQL container uses a different image. Preserve its volume and upgrade it explicitly.",
|
|
29
|
+
});
|
|
42
30
|
}
|
|
43
|
-
docker(["start", CONTAINER]);
|
|
31
|
+
yield* docker(["start", CONTAINER]);
|
|
44
32
|
}
|
|
45
33
|
else {
|
|
46
|
-
docker([
|
|
34
|
+
yield* docker([
|
|
47
35
|
"run",
|
|
48
36
|
"--detach",
|
|
49
37
|
"--name",
|
|
@@ -59,5 +47,5 @@ export function startContainer(docker) {
|
|
|
59
47
|
POSTGRES_IMAGE,
|
|
60
48
|
]);
|
|
61
49
|
}
|
|
62
|
-
}
|
|
50
|
+
});
|
|
63
51
|
//# sourceMappingURL=localContainer.js.map
|