@shivaedev/test-sql 0.0.0 → 0.9.3
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 +225 -0
- package/LICENSE +21 -0
- package/README.md +256 -1
- package/dist/server/assertModelColumns.d.ts +13 -0
- package/dist/server/assertModelColumns.d.ts.map +1 -0
- package/dist/server/assertModelColumns.js +11 -0
- package/dist/server/assertModelColumns.js.map +1 -0
- package/dist/server/database.d.ts +18 -0
- package/dist/server/database.d.ts.map +1 -0
- package/dist/server/database.js +4 -0
- package/dist/server/database.js.map +1 -0
- package/dist/server/internal/connectionLimitHint.d.ts +3 -0
- package/dist/server/internal/connectionLimitHint.d.ts.map +1 -0
- package/dist/server/internal/connectionLimitHint.js +15 -0
- package/dist/server/internal/connectionLimitHint.js.map +1 -0
- package/dist/server/internal/databaseCleanup.d.ts +7 -0
- package/dist/server/internal/databaseCleanup.d.ts.map +1 -0
- package/dist/server/internal/databaseCleanup.js +34 -0
- package/dist/server/internal/databaseCleanup.js.map +1 -0
- package/dist/server/internal/databaseOwner.d.ts +3 -0
- package/dist/server/internal/databaseOwner.d.ts.map +1 -0
- package/dist/server/internal/databaseOwner.js +24 -0
- package/dist/server/internal/databaseOwner.js.map +1 -0
- package/dist/server/internal/databases.d.ts +13 -0
- package/dist/server/internal/databases.d.ts.map +1 -0
- package/dist/server/internal/databases.js +26 -0
- package/dist/server/internal/databases.js.map +1 -0
- package/dist/server/internal/modelColumnProblems.d.ts +8 -0
- package/dist/server/internal/modelColumnProblems.d.ts.map +1 -0
- package/dist/server/internal/modelColumnProblems.js +35 -0
- package/dist/server/internal/modelColumnProblems.js.map +1 -0
- package/dist/server/migrationSteps.d.ts +8 -0
- package/dist/server/migrationSteps.d.ts.map +1 -0
- package/dist/server/migrationSteps.js +51 -0
- package/dist/server/migrationSteps.js.map +1 -0
- package/dist/server/migrationUpgrade.d.ts +14 -0
- package/dist/server/migrationUpgrade.d.ts.map +1 -0
- package/dist/server/migrationUpgrade.js +34 -0
- package/dist/server/migrationUpgrade.js.map +1 -0
- package/dist/server/postgres.d.ts +22 -0
- package/dist/server/postgres.d.ts.map +1 -0
- package/dist/server/postgres.js +43 -0
- package/dist/server/postgres.js.map +1 -0
- package/dist/server/withIsolatedDatabase.d.ts +6 -0
- package/dist/server/withIsolatedDatabase.d.ts.map +1 -0
- package/dist/server/withIsolatedDatabase.js +11 -0
- package/dist/server/withIsolatedDatabase.js.map +1 -0
- package/dist/server/withTestTransaction.d.ts +4 -0
- package/dist/server/withTestTransaction.d.ts.map +1 -0
- package/dist/server/withTestTransaction.js +10 -0
- package/dist/server/withTestTransaction.js.map +1 -0
- package/package.json +72 -4
- package/src/server/assertModelColumns.ts +19 -0
- package/src/server/database.ts +21 -0
- package/src/server/internal/connectionLimitHint.ts +16 -0
- package/src/server/internal/databaseCleanup.ts +40 -0
- package/src/server/internal/databaseOwner.ts +25 -0
- package/src/server/internal/databases.ts +47 -0
- package/src/server/internal/modelColumnProblems.ts +45 -0
- package/src/server/migrationSteps.ts +54 -0
- package/src/server/migrationUpgrade.ts +45 -0
- package/src/server/postgres.ts +72 -0
- package/src/server/withIsolatedDatabase.ts +13 -0
- package/src/server/withTestTransaction.ts +17 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.9.3 - 2026-10-25
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Release with updated workspace dependencies.
|
|
8
|
+
|
|
9
|
+
## 0.9.2 - 2026-10-25
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Release with updated workspace dependencies.
|
|
14
|
+
|
|
15
|
+
## 0.9.1 - 2026-10-25
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Release with updated workspace dependencies.
|
|
20
|
+
|
|
21
|
+
## 0.9.0 - 2026-10-25
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- `makePostgresTestLayer` accepts `initialize` instead of `migrations` to run an application's complete production database initializer once against the prepared template. Pass an Effect using the supplied SQL services or a callback receiving the template's redacted URL. Initialization and optional subsequent fixtures finish and release scoped resources before cloning; deployment stories can still select the empty template. Replace a dummy `migrations` loader and initializer in `fixtures` with `initialize: (url) => migrateDatabase(url)`.
|
|
26
|
+
|
|
27
|
+
### Breaking
|
|
28
|
+
|
|
29
|
+
- `PostgresTestOptions` is now a union requiring exactly one of `migrations` and `initialize`. Wrappers that read `options.migrations` must first narrow `options.initialize === undefined`. Replace interfaces extending `PostgresTestOptions` with intersection type aliases. Existing calls supplying migrations retain their behavior.
|
|
30
|
+
|
|
31
|
+
## 0.8.8 - 2026-10-25
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Release with updated workspace dependencies.
|
|
36
|
+
|
|
37
|
+
## 0.8.7 - 2026-10-25
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Release with updated workspace dependencies.
|
|
42
|
+
|
|
43
|
+
## 0.8.6 - 2026-10-25
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Release with updated workspace dependencies.
|
|
48
|
+
|
|
49
|
+
## 0.8.5 - 2026-10-25
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- Release with updated workspace dependencies.
|
|
54
|
+
|
|
55
|
+
## 0.8.4 - 2026-10-25
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- Migration options accept schema components beside the numbered loader. Components apply after the ledger commits and report pending work through the same readiness check and host wait loop.
|
|
60
|
+
- `pgBossSchema` registers pg-boss installation and upgrades as a schema component, reporting the schema's installed and required versions.
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- Generated apps migrate pg-boss through their migration list and start producers and workers with schema migration disabled.
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- Migration-step controllers capture schema-component services when constructed, keeping subsequent migration calls free of external service requirements.
|
|
69
|
+
|
|
70
|
+
## 0.8.3 - 2026-10-24
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- Require Effect and its companion packages at exactly 4.0.5. Generated applications use the same versions.
|
|
75
|
+
|
|
76
|
+
## 0.8.2 - 2026-10-19
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- Release with updated workspace dependencies.
|
|
81
|
+
|
|
82
|
+
## 0.8.1 - 2026-10-19
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
|
|
86
|
+
- Release with updated workspace dependencies.
|
|
87
|
+
|
|
88
|
+
## 0.8.0 - 2026-10-19
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- Quality's `manifests/exports-shape` rule checks exports at the package root and in workspace members by default. Modules use one file-preserving TypeScript wildcard with matching source, types and runtime targets; root entries, exact non-code assets, package metadata and null blocks are allowed.
|
|
93
|
+
|
|
94
|
+
### Breaking
|
|
95
|
+
|
|
96
|
+
- Quality's Biome preset moves from `@shivaedev/quality/biome` to `@shivaedev/quality/biome/preset.json`. Change the `extends` entry in your Biome config to the new path; the old alias is removed. TypeScript preset paths are unchanged.
|
|
97
|
+
- `@shivaedev/effect-pg-boss`, `@shivaedev/effect-test-sql`, `@shivaedev/local-postgres` and `@shivaedev/test-story` expose server modules at their file paths. Add `/server/` after the package name in imports, for example `@shivaedev/test-story/server/storyKit.ts`. The shortened paths are removed; internal server modules remain blocked.
|
|
98
|
+
- Work Board moves `@shivaedev/work-board/client/client.ts` to `@shivaedev/work-board/browserClient.ts`; change browser-client imports to that file path. `@shivaedev/work-board/client/document/View.ts` is removed: consume document queries with your own renderer, or use the bundled Board browser UI. The client bundle stays private and the old export overrides are removed.
|
|
99
|
+
|
|
100
|
+
## 0.7.5 - 2026-10-19
|
|
101
|
+
|
|
102
|
+
### Changed
|
|
103
|
+
|
|
104
|
+
- Release with updated workspace dependencies.
|
|
105
|
+
|
|
106
|
+
## 0.7.4 - 2026-10-19
|
|
107
|
+
|
|
108
|
+
### Changed
|
|
109
|
+
|
|
110
|
+
- Release with updated workspace dependencies.
|
|
111
|
+
|
|
112
|
+
## 0.7.3 - 2026-10-19
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- Release with updated workspace dependencies.
|
|
117
|
+
|
|
118
|
+
## 0.7.2 - 2026-10-19
|
|
119
|
+
|
|
120
|
+
### Changed
|
|
121
|
+
|
|
122
|
+
- Release with updated workspace dependencies.
|
|
123
|
+
|
|
124
|
+
## 0.7.1 - 2026-10-19
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
|
|
128
|
+
- Release with updated workspace dependencies.
|
|
129
|
+
|
|
130
|
+
## 0.7.0 - 2026-10-19
|
|
131
|
+
|
|
132
|
+
### Added
|
|
133
|
+
|
|
134
|
+
- `PostgresTestOptions` accepts effect-sql's `SqlNameTransforms`, including the options returned by `clientOptions`, for preparation, shared and isolated PostgreSQL clients. Reuse the app's client options without a test-only name mapping.
|
|
135
|
+
- `assertModelColumns` uses the current PostgreSQL client's name transforms to compare database columns with model fields and report mismatches in model field names. Calls without a configured mapping retain literal column comparisons.
|
|
136
|
+
|
|
137
|
+
## 0.6.1 - 2026-10-18
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- Release with updated workspace dependencies.
|
|
142
|
+
|
|
143
|
+
## 0.6.0 - 2026-10-18
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
|
|
147
|
+
- `PostgresTestDatabase.awaitCleanup`, a native `Effect<void>` that waits for already-queued drops and preserves cleanup failures as SQL defects.
|
|
148
|
+
- Select an empty or migrated database from one test layer with `PostgresTestDatabase.clone(template)` or `withIsolatedDatabase(effect, { template })`. `PostgresTestTemplate` names the choices; migrated clones remain the default. Story traits can choose a template before acquiring their app services.
|
|
149
|
+
- Accept a scoped `PostgresTestLoader` callback in `fixtures` that receives the migrated template's redacted URL, so app options can open their own pool during once-per-layer preparation. Existing fixture Effects remain supported.
|
|
150
|
+
|
|
151
|
+
### Changed
|
|
152
|
+
|
|
153
|
+
- Drop isolated databases in the background and await outstanding cleanup when the PostgreSQL test layer closes.
|
|
154
|
+
|
|
155
|
+
### Fixed
|
|
156
|
+
|
|
157
|
+
- Retry database drops when PostgreSQL's connection budget is exhausted, and sweep abandoned local test databases at startup. Retries use live time even when a test clock is paused. Permanent cleanup failures still surface as SQL defects when the layer closes.
|
|
158
|
+
|
|
159
|
+
## 0.5.5 - 2026-10-18
|
|
160
|
+
|
|
161
|
+
### Changed
|
|
162
|
+
|
|
163
|
+
- Release with updated workspace dependencies.
|
|
164
|
+
|
|
165
|
+
## 0.5.4 - 2026-10-18
|
|
166
|
+
|
|
167
|
+
### Fixed
|
|
168
|
+
|
|
169
|
+
- Align published framework dependencies with the current releases.
|
|
170
|
+
|
|
171
|
+
## 0.5.3 - 2026-10-18
|
|
172
|
+
|
|
173
|
+
### Fixed
|
|
174
|
+
|
|
175
|
+
- Close the isolated test's application scope before closing its SQL services and dropping its database.
|
|
176
|
+
|
|
177
|
+
## 0.5.2 - 2026-10-17
|
|
178
|
+
|
|
179
|
+
### Changed
|
|
180
|
+
|
|
181
|
+
- Block `@shivaedev/effect-test-sql/internal/*` imports; use the public test isolation modules instead.
|
|
182
|
+
|
|
183
|
+
## 0.5.1 - 2026-10-17
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- The `migrateTo(name: string | number)` helper returned by `migrationSteps` accepts zero-padded migration names as written, unpadded names and bare numeric ids. Unknown or ambiguous targets fail with a typed `MigrationError` naming the requested target.
|
|
188
|
+
|
|
189
|
+
## 0.5.0 - 2026-10-17
|
|
190
|
+
|
|
191
|
+
### Added
|
|
192
|
+
|
|
193
|
+
- `migrationSteps(appMigrations)` from `migrationSteps.ts` provides `migrateTo("1_name")` and `migrateToLatest` on the current PostgreSQL client, so tests can seed old-schema rows before running a backfill. Unknown names fail with a typed `MigrationError`; loader dependencies and scope stay explicit.
|
|
194
|
+
- `makePostgresTestLayer({ prepare: false, ... })` skips migration and fixture preparation, giving isolated tests and test-story stories empty databases without a second migration list.
|
|
195
|
+
|
|
196
|
+
## 0.4.0 - 2026-10-17
|
|
197
|
+
|
|
198
|
+
### Added
|
|
199
|
+
|
|
200
|
+
- `PostgresTestOptions.maxConnections` configures the preparation, shared and isolated database pool limit per suite.
|
|
201
|
+
|
|
202
|
+
### Fixed
|
|
203
|
+
|
|
204
|
+
- `makePostgresTestLayer` keeps its administration connection alive until fixture cleanup, so an idle period cannot leave database finalizers waiting for a new pooled connection during scope closure.
|
|
205
|
+
- Test database pools default to two connections, and administrative connections close after each create or drop, so concurrent database copies use a smaller PostgreSQL connection budget. Fresh scoped administration connections preserve database cleanup after idle periods without retaining a worker-lifetime connection.
|
|
206
|
+
- Setup, rollback and isolated test wrappers explain PostgreSQL connection-limit failures with `max_connections` and a `vitest run --maxWorkers=4` suggestion while retaining SQLSTATE `53300`.
|
|
207
|
+
- Publish against `@shivaedev/effect-sql` 0.5.0 so a generated app shares the same SQL service tags as Platform.
|
|
208
|
+
|
|
209
|
+
## 0.3.0 - 2026-10-13
|
|
210
|
+
|
|
211
|
+
### Breaking
|
|
212
|
+
|
|
213
|
+
- Requires stable Effect 4.0.4 in place of 4.0.0-rc.112. Effect 4.0.4 moves the former `effect/unstable/*` modules to `effect/*` and renames constructors such as `Config.string` to `Config.String`. Install `@effect/sql-pg` 4.0.4 alongside it, whose native PostgreSQL client replaces `pg`.
|
|
214
|
+
|
|
215
|
+
## 0.2.0 - 2026-10-13
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
|
|
219
|
+
- `migrationUpgrade({ migrations, upTo, table })` applies an older migration prefix and then the latest migrations on PostgreSQL, returning live column names and exact PostgreSQL types. `assertModelColumns(columns, model, types)` checks those columns against the model's database fields and an explicit type map, failing with `ModelColumnMismatch` for missing, extra or wrongly typed columns. Upgrade checks reject populated custom ledgers before loading migrations, using the migration runner's identifier semantics.
|
|
220
|
+
|
|
221
|
+
## 0.1.0 - 2026-10-11
|
|
222
|
+
|
|
223
|
+
### Added
|
|
224
|
+
|
|
225
|
+
- `makePostgresTestLayer` prepares migrations and optional fixtures once in a PostgreSQL template and provides native services on a shared test database. `withTestTransaction` wraps harness setup, the body and scope finalizers in rollback, preserves nested `transact` savepoints, and discards commit-bound invalidations. `withIsolatedDatabase` clones the prepared template for real commits and drops the clone after the test. The Layer scope drops its shared database and template. Real PostgreSQL tests cover concurrency, row-lock release, failure and interruption, template reuse, second-connection commit visibility and resource cleanup.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ShivaeDev
|
|
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,258 @@
|
|
|
1
1
|
# @shivaedev/test-sql
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PostgreSQL tests should start from known data and leave it there. This package prepares migrations and fixtures once, wraps ordinary Effect tests in transactions that roll back, and clones the prepared database when a test needs real commits.
|
|
4
|
+
|
|
5
|
+
## Why you want this
|
|
6
|
+
|
|
7
|
+
Table cleanup couples tests to the order they run. A rollback test keeps its writes private and restores the prepared data when it ends:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
effectApp("renames an item", function* () {
|
|
11
|
+
const sql = yield* SqlClient.SqlClient;
|
|
12
|
+
yield* sql`update items set name = 'Renamed' where id = 1`;
|
|
13
|
+
expect(yield* sql`select name from items where id = 1`).toEqual([
|
|
14
|
+
{ name: "Renamed" },
|
|
15
|
+
]);
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The next test still sees the original name. Tests that must observe a committed write use a disposable database copied from the same starting data.
|
|
20
|
+
|
|
21
|
+
## Using it
|
|
22
|
+
|
|
23
|
+
### Prepare one fixture
|
|
24
|
+
|
|
25
|
+
`makePostgresTestLayer` creates an empty template and a migrated template through an administrative connection, runs either `migratePostgres` or the application's initializer followed by optional fixtures in the migrated template, then closes its preparation connections. It creates a shared test database from the migrated template and provides `SqlClient`, `PgClient`, `Reactivity` and `PostgresTestDatabase`. The templates remain closed and unchanged while tests run. Each isolated database copies the template it asks for; initialization and fixtures do not run again when cloning. Set `prepare: false` for a suite that needs only empty databases: preparation and fixtures are skipped.
|
|
26
|
+
|
|
27
|
+
The Layer's scope owns the template, shared database and their connections. `makeEffectIt` builds the Layer once for its worker fixture. Each test's wrapper owns the transaction or isolated database. Closing a test scope releases its connections and queues its database drop in the background. Closing the Layer waits for all queued drops. To wait earlier, run `PostgresTestDatabase.awaitCleanup` after the isolated scope ends; it waits for drops queued before that Effect starts and reports cleanup failures as SQL defects. The shared database and templates stay available; the administrative database named by `url` remains in place.
|
|
28
|
+
|
|
29
|
+
Define the tester in test support:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { expect } from "vitest";
|
|
33
|
+
import { Config, Effect, Redacted } from "effect";
|
|
34
|
+
import { Migrator, SqlClient } from "effect/sql";
|
|
35
|
+
import { makeEffectIt } from "@shivaedev/test/makeEffectIt.ts";
|
|
36
|
+
import { makePostgresTestLayer } from "@shivaedev/test-sql/server/postgres.ts";
|
|
37
|
+
import { withTestTransaction } from "@shivaedev/test-sql/server/withTestTransaction.ts";
|
|
38
|
+
|
|
39
|
+
const layer = makePostgresTestLayer({
|
|
40
|
+
url: Redacted.make(Effect.runSync(Config.String("TEST_DATABASE_URL"))),
|
|
41
|
+
migrations: {
|
|
42
|
+
lockTimeout: "5 seconds",
|
|
43
|
+
loader: Migrator.fromRecord({
|
|
44
|
+
"1_create_items": Effect.gen(function* () {
|
|
45
|
+
const sql = yield* SqlClient.SqlClient;
|
|
46
|
+
yield* sql`create table items (id integer primary key, name text not null)`;
|
|
47
|
+
}),
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
fixtures: Effect.gen(function* () {
|
|
51
|
+
const sql = yield* SqlClient.SqlClient;
|
|
52
|
+
yield* sql`insert into items values (1, 'Original')`;
|
|
53
|
+
}),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const { effectApp } = makeEffectIt({
|
|
57
|
+
layer,
|
|
58
|
+
clock: "live",
|
|
59
|
+
around: withTestTransaction,
|
|
60
|
+
makeHarness: () => Effect.void,
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Use the application's migration loader in place of the example. `migrations` takes sql's `PostgresMigrationOptions`. Fixtures are an Effect with access to the native PostgreSQL services. Additional migration or fixture dependencies remain requirements of the Layer and must be supplied before passing it to the runner. Setup failures remain failures; acquired databases are dropped when the acquisition scope closes.
|
|
65
|
+
|
|
66
|
+
Fixtures can also be a `PostgresTestLoader`: a callback from the migrated template's redacted URL to a scoped Effect. Use it when a loader needs application options with its own pool, such as Better Auth's options. Acquire the pool in that Effect with `Effect.acquireRelease` and close it in the release action. The callback runs once during preparation, after migrations, with the native SQL services available. Its resources close before the first clone. For example, a loader using a separate native PostgreSQL client can be written as:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
70
|
+
|
|
71
|
+
const layer = makePostgresTestLayer({
|
|
72
|
+
url,
|
|
73
|
+
migrations: appMigrations,
|
|
74
|
+
fixtures: (templateUrl) => Effect.gen(function* () {
|
|
75
|
+
const client = yield* PgClient.makeClient({ url: templateUrl });
|
|
76
|
+
yield* client`create table app_fixture (name text not null)`;
|
|
77
|
+
yield* client`insert into app_fixture values ('Original')`;
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Run the production initializer
|
|
83
|
+
|
|
84
|
+
Supply `initialize` instead of `migrations` when the application already owns its complete database setup:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const layer = makePostgresTestLayer({
|
|
88
|
+
url: testDatabaseUrl,
|
|
89
|
+
initialize: (templateUrl) => migrateDatabase(templateUrl),
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Choose exactly one of `migrations` and `initialize`. The initializer is an Effect using the supplied `SqlClient`, `PgClient` and `Reactivity`, or a `PostgresTestLoader` receiving the template's redacted URL. It runs once against the migrated template and completes before fixtures and cloning. Its scoped resources close before cloning, and additional service requirements remain requirements of the Layer. Optional `fixtures` run afterward. Ordinary stories inherit the initialized schema and data; deployment stories can still select the empty template.
|
|
94
|
+
|
|
95
|
+
### Reuse the app's SQL name mapping
|
|
96
|
+
|
|
97
|
+
`PostgresTestOptions` accepts sql's native `transformQueryNames` and `transformResultNames`. Spread the same options returned by `clientOptions` that the app host uses; the test layer carries them into preparation, the shared database, `withIsolatedDatabase` and story clones:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const layer = makePostgresTestLayer({
|
|
101
|
+
...appClientOptions,
|
|
102
|
+
url: testDatabaseUrl,
|
|
103
|
+
migrations: appMigrations,
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Declare the mapping once in `appClientOptions`, for example with `clientOptions(config, { snakeCase: true })`. The test URL selects the administrative database independently of the app's database URL. Omitting transforms preserves SQL names.
|
|
108
|
+
|
|
109
|
+
### Budget PostgreSQL connections
|
|
110
|
+
|
|
111
|
+
Each database pool opens connections on demand, with a default maximum of **two**: the shared database can use two, and each active per-test or per-story clone can use another two. Preparation uses the same limit and closes before tests start. An administrative connection exists only during a create or drop operation and closes as soon as that operation finishes; idle workers keep no administrative connection. Set `maxConnections` on `makePostgresTestLayer` to override the limit for the suite's preparation, shared and isolated pools:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
const layer = makePostgresTestLayer({
|
|
115
|
+
url,
|
|
116
|
+
migrations,
|
|
117
|
+
maxConnections: 3,
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Allow at least three shared connections when two tests hold transactions while a third connection inspects locks. A listener, stream or reserved transaction holds a pool slot until its scope closes; a suite that waits for more simultaneous reservations than its pool allows can stall. Additional clients that the application creates have their own connection budgets.
|
|
122
|
+
|
|
123
|
+
For `W` active workers with one fixture and at most `C` simultaneous clones each, allow up to `W × maxConnections × (1 + C)` pooled connections, plus one transient administrative connection per concurrent create/drop operation. Add other application clients and leave room for PostgreSQL's reserved slots and other users of the server. With stock `max_connections = 100`, four workers with one clone each use at most 16 pooled connections at the default limit, plus transient administration connections. Vitest's default worker count depends on the machine; use this budget when a larger machine or concurrent stories can exceed the server's capacity.
|
|
124
|
+
|
|
125
|
+
Setup and the test wrappers report PostgreSQL's connection-limit failure (`53300`) with `max_connections` and a suggestion to try `vitest run --maxWorkers=4`. Reduce `maxConnections` or concurrent clones, or increase the server budget, if four workers still need too many connections. Other SQL failures retain their original errors.
|
|
126
|
+
|
|
127
|
+
### Ordinary tests: rollback
|
|
128
|
+
|
|
129
|
+
`around: withTestTransaction` wraps harness acquisition, the body and their scope finalizers. Success returns the body's value after rollback. Typed failures, defects and interruption also roll back and retain their failure kind. A nested `transact` uses the native savepoint path: a rejected nested write can roll back without losing earlier writes in the test. Commit-bound invalidations stay buffered and are discarded when the wrapping transaction rolls back.
|
|
130
|
+
|
|
131
|
+
Tests may run concurrently on the shared database, with separate transaction connections. Other tests do not see uncommitted writes. PostgreSQL still enforces row locks and unique constraints: updates to the same keyed row, or inserts with the same unique key, can wait until the first test rolls back. Do not make tests wait for each other after acquiring conflicting locks. Use different keys or isolated databases when a scenario needs overlapping writes without that contention.
|
|
132
|
+
|
|
133
|
+
PostgreSQL sequence advances survive rollback. Avoid asserting exact generated sequence numbers on the shared database; use an isolated database when its sequence state must start from the template.
|
|
134
|
+
|
|
135
|
+
### Real commits: an isolated database
|
|
136
|
+
|
|
137
|
+
Use `withIsolatedDatabase` for after-commit effects, LISTEN/NOTIFY, advisory-lock scenarios that need independent connections, migration tests, or work through several connections. It runs without a wrapping transaction on its clone. Ordinary autocommit and `transact` commit for real, and the wrapper queues its clone for background cleanup when it finishes. The Layer waits for cleanup at the end of its scope.
|
|
138
|
+
|
|
139
|
+
An isolated block can live inside the rollback tester above:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { withIsolatedDatabase } from "@shivaedev/test-sql/server/withIsolatedDatabase.ts";
|
|
143
|
+
|
|
144
|
+
effectApp("commits in its own database", function* () {
|
|
145
|
+
yield* withIsolatedDatabase(Effect.gen(function* () {
|
|
146
|
+
const sql = yield* SqlClient.SqlClient;
|
|
147
|
+
yield* sql`update items set name = 'Committed' where id = 1`;
|
|
148
|
+
}));
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The clone starts from the template, including the original fixtures, even if the shared database has changed. The outer rollback transaction belongs to a different native client and does not wrap the clone's work. To isolate harness acquisition and the entire body instead, define a tester with `around: withIsolatedDatabase`.
|
|
153
|
+
|
|
154
|
+
Inside an isolated block, `PostgresTestDatabase.url` names that clone. Use it to acquire additional native PostgreSQL connections in the block's scope. Native SQL services are replaced in the block's Context; application services acquired earlier retain the client they captured. Build application service Layers inside the isolated block when they acquire SQL clients; use `Layer.fresh` when reusing a Layer definition already acquired by the worker. Keep servers and background fibers in that scope so they finish before the database is dropped. Separate databases isolate database contents; external services and server capacity need separate planning.
|
|
155
|
+
|
|
156
|
+
### Choose an empty database per story or trait
|
|
157
|
+
|
|
158
|
+
The default clone is migrated. A first-deploy or upgrade block can select the empty template from the same Layer:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
yield* withIsolatedDatabase(Effect.gen(function* () {
|
|
162
|
+
const sql = yield* SqlClient.SqlClient;
|
|
163
|
+
expect(yield* sql`select table_name from information_schema.tables where table_schema = 'public'`).toEqual([]);
|
|
164
|
+
}), { template: "empty" });
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
For a `test-story` kit that chooses through traits, keep a `template: PostgresTestTemplate` field on its engine, initially `"migrated"`. Add a database stage before the stages that boot the app. A trait in that stage sets `engine.template = "empty"`; the stage's `after` hook acquires `yield* database.clone(engine.template)` from `PostgresTestDatabase`. Run app acquisition and verbs with `Effect.provideContext(services)` using that returned Context. The story's Scope owns the clone and its connections. Do not also use `around: withIsolatedDatabase` for this kit, since that would acquire a migrated clone before the traits run.
|
|
168
|
+
|
|
169
|
+
Both selections copy a closed PostgreSQL template with `CREATE DATABASE ... TEMPLATE`; neither selection executes migrations or fixture loaders. The amount of preparation work does not add per-clone migration or loader work. PostgreSQL still has to copy the template's stored data.
|
|
170
|
+
|
|
171
|
+
### Test a backfill against existing rows
|
|
172
|
+
|
|
173
|
+
A backfill needs rows in the old schema. Prepare an empty template with the application's own `PostgresMigrationOptions`, then use `migrationSteps` inside `withIsolatedDatabase`. `migrateTo` accepts the migration name as written without a file extension (`"001_create_contacts"`), its unpadded form (`"1_create_contacts"`), or its bare numeric id (`1`, `"1"` or `"001"`). It commits migrations through that target; seed rows with the native SQL client, then yield `migrateToLatest` to apply the remaining migrations on the same database.
|
|
174
|
+
|
|
175
|
+
This example uses an application loader whose `001_create_contacts` migration creates `contacts(id, email)`, `002_backfill_emails` creates `emails(contact_id, address)` and copies the contact email addresses into it, and `003_drop_email` drops `contacts.email`:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { migrationSteps } from "@shivaedev/test-sql/server/migrationSteps.ts";
|
|
179
|
+
import { withIsolatedDatabase } from "@shivaedev/test-sql/server/withIsolatedDatabase.ts";
|
|
180
|
+
import { appMigrations } from "./migrations.ts";
|
|
181
|
+
|
|
182
|
+
const migrationLayer = makePostgresTestLayer({
|
|
183
|
+
url,
|
|
184
|
+
migrations: appMigrations,
|
|
185
|
+
prepare: false,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const { effectApp: migrationTest } = makeEffectIt({
|
|
189
|
+
layer: migrationLayer,
|
|
190
|
+
clock: "live",
|
|
191
|
+
around: withIsolatedDatabase,
|
|
192
|
+
makeHarness: () => migrationSteps(appMigrations),
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
migrationTest("preserves contact emails in the new table", function* (steps) {
|
|
196
|
+
yield* steps.migrateTo("001_create_contacts");
|
|
197
|
+
const sql = yield* SqlClient.SqlClient;
|
|
198
|
+
yield* sql`insert into contacts (id, email) values (1, 'alice@example.test')`;
|
|
199
|
+
yield* steps.migrateToLatest;
|
|
200
|
+
expect(yield* sql`select contact_id, address from emails`).toEqual([
|
|
201
|
+
{ contact_id: 1, address: "alice@example.test" },
|
|
202
|
+
]);
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The helper resolves the loader once and uses `migratePostgres` for each step, preserving its ledger table and lock timeout. Unknown or ambiguous targets fail with a typed `MigrationError` that names the requested target. Moving behind an already applied migration and running inside a wrapping transaction also fail with `MigrationError`. Loader dependencies, including `Scope`, remain requirements of `migrationSteps`; its resources live until the caller's scope closes. Use the returned steps inside that database's scope. SQL and loader failures retain their failure channels.
|
|
207
|
+
|
|
208
|
+
For test-story, use the same Layer and `around: withIsolatedDatabase`, acquire `migrationSteps(appMigrations)` in the kit's `create`, and let schema and data traits call `migrateTo` and seed native SQL. A verb can yield `migrateToLatest` before the story asserts the backfilled rows.
|
|
209
|
+
|
|
210
|
+
### Check upgrades against the current model
|
|
211
|
+
|
|
212
|
+
A fresh-database test cannot prove that older databases upgrade to the current model. Run `migrationUpgrade` in a disposable database with an empty migration ledger, outside a wrapping transaction. It resolves the application's loader once, commits migrations through the existing `upTo` id, then applies the remaining migrations through `migratePostgres`. It returns the target table's column names and PostgreSQL `format_type` strings, including type modifiers such as `numeric(10,2)`; dropped columns are excluded.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { assertModelColumns } from "@shivaedev/test-sql/server/assertModelColumns.ts";
|
|
216
|
+
import { migrationUpgrade } from "@shivaedev/test-sql/server/migrationUpgrade.ts";
|
|
217
|
+
|
|
218
|
+
const columns = yield* migrationUpgrade({
|
|
219
|
+
migrations: appMigrations,
|
|
220
|
+
upTo: 1,
|
|
221
|
+
table: "items",
|
|
222
|
+
});
|
|
223
|
+
yield* assertModelColumns(columns, Item, {
|
|
224
|
+
id: "integer",
|
|
225
|
+
name: "text",
|
|
226
|
+
price: "numeric(10,2)",
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Use `prepare: false` when preparing the test Layer, and `withIsolatedDatabase` for the upgrade test. The helper requires the native `SqlClient`; loader dependencies remain Effect requirements. Unknown starting ids, populated ledgers and wrapping transactions fail with `MigrationError`. Native loader and SQL failures retain their failure channel.
|
|
231
|
+
|
|
232
|
+
With a PostgreSQL client in the current Context, the assertion compares names through that client's query and result name transforms and reports problems in model field terms. Without a client or configured transforms it compares literal names.
|
|
233
|
+
|
|
234
|
+
The assertion uses the SQL `Model`'s selected database fields, including generated ids and excluding JSON-only fields. Supply an exact PostgreSQL type for every field: schemas such as `Schema.Number` do not determine whether storage is `integer`, `numeric` or `double precision`. It fails with a typed `ModelColumnMismatch` containing all detected missing, extra and wrongly typed column problems. The type map is checked against the model both by TypeScript and at runtime. This check covers names and types; it does not check defaults, nullability, constraints or application data transformations.
|
|
235
|
+
|
|
236
|
+
### API
|
|
237
|
+
|
|
238
|
+
Import each name from the module that defines it. The package has no root entry.
|
|
239
|
+
|
|
240
|
+
| Module | Exports |
|
|
241
|
+
| --- | --- |
|
|
242
|
+
| `@shivaedev/test-sql/server/postgres.ts` | `makePostgresTestLayer({ url, migrations?, initialize?, fixtures?, maxConnections?, prepare?, transformQueryNames?, transformResultNames? })`, `PostgresTestOptions`, `PostgresTestLoader` |
|
|
243
|
+
| `@shivaedev/test-sql/server/withTestTransaction.ts` | `withTestTransaction(effect)` |
|
|
244
|
+
| `@shivaedev/test-sql/server/withIsolatedDatabase.ts` | `withIsolatedDatabase(effect, { template? }?)` |
|
|
245
|
+
| `@shivaedev/test-sql/server/database.ts` | `PostgresTestDatabase`, `PostgresTestDatabaseService`, `PostgresTestServices`, `PostgresTestTemplate` |
|
|
246
|
+
| `@shivaedev/test-sql/server/migrationSteps.ts` | `migrationSteps(appMigrations)` returning `{ migrateTo(name), migrateToLatest }` |
|
|
247
|
+
| `@shivaedev/test-sql/server/migrationUpgrade.ts` | `migrationUpgrade({ migrations, upTo, table })`, `MigrationUpgradeOptions`, `PostgresColumn` |
|
|
248
|
+
| `@shivaedev/test-sql/server/assertModelColumns.ts` | `assertModelColumns(columns, model, types)`, `ModelColumnMismatch` |
|
|
249
|
+
|
|
250
|
+
`url` is a redacted PostgreSQL URL for an existing administrative database. `PostgresTestDatabase` supplies the current database's redacted `url`, an `awaitCleanup: Effect<void>` drain, a scoped `isolated` Effect that acquires a migrated clone's service Context, and `clone(template)` for an explicit `"empty"` or `"migrated"` choice. With `prepare: false`, both choices are empty. Prefer `withIsolatedDatabase` to acquire and release that Context around a test. Wrappers retain the body's result, failures and unmet service requirements, with native `SqlError` added for acquisition or transaction failures. Cleanup failures surface as SQL defects when the Layer closes. Drops that fail with connection exhaustion (SQLSTATE `53300`) retry every 100 ms of live time for up to 300 retries, even while a test clock is paused; if capacity does not return, the SQL defect remains visible. Startup sweeps databases left by dead processes on the same host and databases from the older unowned naming format. Databases owned by live processes or another host are retained, so local parallel workers keep their databases. Use the same host to reclaim its abandoned databases.
|
|
251
|
+
|
|
252
|
+
### Install and setup
|
|
253
|
+
|
|
254
|
+
```sh
|
|
255
|
+
pnpm add --save-dev @shivaedev/test-sql @shivaedev/test @effect/sql-pg @effect/vitest effect vitest
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Use versions compatible with the package's peer dependencies. The package requires Node.js 24 or later. The PostgreSQL role must be able to create and drop databases; use a dedicated test server. PostgreSQL 13 or later supports the forced database drops used for cleanup. The migrations and fixtures must complete their work during preparation; their scoped resources are closed before cloning.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
|
+
import type { PostgresColumn } from "./migrationUpgrade.ts";
|
|
4
|
+
declare const ModelColumnMismatch_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
5
|
+
readonly _tag: "ModelColumnMismatch";
|
|
6
|
+
} & Readonly<A>;
|
|
7
|
+
export declare class ModelColumnMismatch extends ModelColumnMismatch_base<{
|
|
8
|
+
readonly problems: readonly string[];
|
|
9
|
+
}> {
|
|
10
|
+
}
|
|
11
|
+
export declare const assertModelColumns: <TModel extends Model.Any>(columns: readonly PostgresColumn[], model: TModel, types: { readonly [TField in keyof NoInfer<TModel>["fields"]]: string; }) => Effect.Effect<void, ModelColumnMismatch, never>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=assertModelColumns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertModelColumns.d.ts","sourceRoot":"","sources":["../../src/server/assertModelColumns.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,MAAM,EAAU,MAAM,QAAQ,CAAC;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;;;;AAE5D,qBAAa,mBAAoB,SAAQ,yBAAwC;IAChF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC,CAAC;CAAG;AAEL,eAAO,MAAM,kBAAkB,GAA2D,MAAM,SAAS,KAAK,CAAC,GAAG,wEAG9F,MAAM,mGAKxB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
|
+
import { Data, Effect, Option } from "effect";
|
|
3
|
+
import { modelColumnProblems } from "#internal/modelColumnProblems.ts";
|
|
4
|
+
export class ModelColumnMismatch extends Data.TaggedError("ModelColumnMismatch") {
|
|
5
|
+
}
|
|
6
|
+
export const assertModelColumns = Effect.fn("PostgresTest.assertModelColumns")(function* (columns, model, types) {
|
|
7
|
+
const client = yield* Effect.serviceOption(PgClient.PgClient);
|
|
8
|
+
const problems = modelColumnProblems(columns, model.fields, types, Option.getOrUndefined(client)?.config);
|
|
9
|
+
return yield* problems.length === 0 ? Effect.void : Effect.fail(new ModelColumnMismatch({ problems }));
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=assertModelColumns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertModelColumns.js","sourceRoot":"","sources":["../../src/server/assertModelColumns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAGvE,MAAM,OAAO,mBAAoB,SAAQ,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAE7E;CAAG;AAEL,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,EAAE,CAAC,iCAAiC,CAAC,CAAC,QAAQ,CAAC,EACvF,OAAkC,EAClC,KAAa,EACb,KAAuE;IAEvE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1G,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AACxG,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
|
+
import { Context, type Effect, type Redacted, type Scope } from "effect";
|
|
3
|
+
import type * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import type { SqlClient } from "effect/sql";
|
|
5
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
6
|
+
export type PostgresTestServices = PgClient.PgClient | SqlClient.SqlClient | Reactivity.Reactivity;
|
|
7
|
+
export type PostgresTestTemplate = "empty" | "migrated";
|
|
8
|
+
export interface PostgresTestDatabaseService {
|
|
9
|
+
readonly awaitCleanup: Effect.Effect<void>;
|
|
10
|
+
readonly clone: (template: PostgresTestTemplate) => Effect.Effect<Context.Context<PostgresTestServices | PostgresTestDatabase>, SqlError, Scope.Scope>;
|
|
11
|
+
readonly isolated: Effect.Effect<Context.Context<PostgresTestServices | PostgresTestDatabase>, SqlError, Scope.Scope>;
|
|
12
|
+
readonly url: Redacted.Redacted<string>;
|
|
13
|
+
}
|
|
14
|
+
declare const PostgresTestDatabase_base: Context.ServiceClass<PostgresTestDatabase, "@shivaedev/test-sql/server/PostgresTestDatabase", PostgresTestDatabaseService>;
|
|
15
|
+
export declare class PostgresTestDatabase extends PostgresTestDatabase_base {
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/server/database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,KAAK,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC;AACnG,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,CACf,QAAQ,EAAE,oBAAoB,KAC1B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACxG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACtH,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACxC;;AAED,qBAAa,oBAAqB,SAAQ,yBAEzC;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/server/database.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAA0C,MAAM,QAAQ,CAAC;AAiBzE,MAAM,OAAO,oBAAqB,SAAQ,OAAO,CAAC,OAAO,EAAqD,CAC7G,iDAAiD,CACjD;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionLimitHint.d.ts","sourceRoot":"","sources":["../../../src/server/internal/connectionLimitHint.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE5E,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,QAAQ,CAY7D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Predicate } from "effect";
|
|
2
|
+
import { ConnectionError, isSqlError, SqlError } from "effect/sql/SqlError";
|
|
3
|
+
export function connectionLimitHint(error) {
|
|
4
|
+
if (!(isSqlError(error) && Predicate.hasProperty(error.reason.cause, "code")) || error.reason.cause.code !== "53300") {
|
|
5
|
+
return error;
|
|
6
|
+
}
|
|
7
|
+
return new SqlError({
|
|
8
|
+
reason: new ConnectionError({
|
|
9
|
+
cause: error.reason.cause,
|
|
10
|
+
message: "PostgreSQL connection limit reached (SQLSTATE 53300): check max_connections and role connection limits. Try vitest run --maxWorkers=4, reduce the suite's maxConnections, or increase the server's connection budget.",
|
|
11
|
+
operation: error.reason.operation,
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=connectionLimitHint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionLimitHint.js","sourceRoot":"","sources":["../../../src/server/internal/connectionLimitHint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,UAAU,mBAAmB,CAAI,KAAQ;IAC9C,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACtH,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,QAAQ,CAAC;QACnB,MAAM,EAAE,IAAI,eAAe,CAAC;YAC3B,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;YACzB,OAAO,EACN,uNAAuN;YACxN,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS;SACjC,CAAC;KACF,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
3
|
+
export declare const databaseCleanup: (url: import("effect/Redacted").Redacted<string>) => Effect.Effect<{
|
|
4
|
+
awaitCleanup: Effect.Effect<void, never, never>;
|
|
5
|
+
release: (name: string) => Effect.Effect<void, never, never>;
|
|
6
|
+
}, SqlError, import("effect/Scope").Scope>;
|
|
7
|
+
//# sourceMappingURL=databaseCleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"databaseCleanup.d.ts","sourceRoot":"","sources":["../../../src/server/internal/databaseCleanup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAyC,MAAM,QAAQ,CAAC;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,eAAO,MAAM,eAAe;;oBAyBJ,MAAM;0CAS5B,CAAC"}
|