@shivaedev/effect-test-sql 0.2.0 → 0.4.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 +19 -0
- package/README.md +22 -4
- package/dist/server/assertModelColumns.d.ts +1 -1
- package/dist/server/assertModelColumns.d.ts.map +1 -1
- package/dist/server/database.d.ts +3 -3
- package/dist/server/database.d.ts.map +1 -1
- 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/databases.d.ts +6 -5
- package/dist/server/internal/databases.d.ts.map +1 -1
- package/dist/server/internal/databases.js +10 -6
- package/dist/server/internal/databases.js.map +1 -1
- package/dist/server/migrationUpgrade.d.ts +2 -2
- package/dist/server/migrationUpgrade.d.ts.map +1 -1
- package/dist/server/migrationUpgrade.js +1 -1
- package/dist/server/migrationUpgrade.js.map +1 -1
- package/dist/server/postgres.d.ts +3 -3
- package/dist/server/postgres.d.ts.map +1 -1
- package/dist/server/postgres.js +10 -10
- package/dist/server/postgres.js.map +1 -1
- package/dist/server/withIsolatedDatabase.d.ts +1 -1
- package/dist/server/withIsolatedDatabase.d.ts.map +1 -1
- package/dist/server/withIsolatedDatabase.js +2 -1
- package/dist/server/withIsolatedDatabase.js.map +1 -1
- package/dist/server/withTestTransaction.d.ts +2 -2
- package/dist/server/withTestTransaction.d.ts.map +1 -1
- package/dist/server/withTestTransaction.js +2 -1
- package/dist/server/withTestTransaction.js.map +1 -1
- package/package.json +10 -10
- package/src/server/assertModelColumns.ts +1 -1
- package/src/server/database.ts +3 -3
- package/src/server/internal/connectionLimitHint.ts +16 -0
- package/src/server/internal/databases.ts +19 -9
- package/src/server/migrationUpgrade.ts +1 -1
- package/src/server/postgres.ts +11 -10
- package/src/server/withIsolatedDatabase.ts +2 -1
- package/src/server/withTestTransaction.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 - 2026-10-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `PostgresTestOptions.maxConnections` configures the preparation, shared and isolated database pool limit per suite.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `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.
|
|
12
|
+
- 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.
|
|
13
|
+
- 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`.
|
|
14
|
+
- Publish against `@shivaedev/effect-sql` 0.5.0 so a generated app shares the same SQL service tags as Platform.
|
|
15
|
+
|
|
16
|
+
## 0.3.0 - 2026-10-13
|
|
17
|
+
|
|
18
|
+
### Breaking
|
|
19
|
+
|
|
20
|
+
- 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`.
|
|
21
|
+
|
|
3
22
|
## 0.2.0 - 2026-10-13
|
|
4
23
|
|
|
5
24
|
### Added
|
package/README.md
CHANGED
|
@@ -31,13 +31,13 @@ Define the tester in test support:
|
|
|
31
31
|
```ts
|
|
32
32
|
import { expect } from "vitest";
|
|
33
33
|
import { Config, Effect, Redacted } from "effect";
|
|
34
|
-
import { Migrator, SqlClient } from "effect/
|
|
34
|
+
import { Migrator, SqlClient } from "effect/sql";
|
|
35
35
|
import { makeEffectIt } from "@shivaedev/effect-test/vitest.ts";
|
|
36
36
|
import { makePostgresTestLayer } from "@shivaedev/effect-test-sql/postgres.ts";
|
|
37
37
|
import { withTestTransaction } from "@shivaedev/effect-test-sql/withTestTransaction.ts";
|
|
38
38
|
|
|
39
39
|
const layer = makePostgresTestLayer({
|
|
40
|
-
url: Redacted.make(Effect.runSync(Config.
|
|
40
|
+
url: Redacted.make(Effect.runSync(Config.String("TEST_DATABASE_URL"))),
|
|
41
41
|
migrations: {
|
|
42
42
|
lockTimeout: "5 seconds",
|
|
43
43
|
loader: Migrator.fromRecord({
|
|
@@ -63,6 +63,24 @@ export const { effectApp } = makeEffectIt({
|
|
|
63
63
|
|
|
64
64
|
Use the application's migration loader in place of the example. `migrations` takes the existing `PostgresMigrationOptions`: `loader`, `lockTimeout`, and an optional ledger `table`. 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
65
|
|
|
66
|
+
### Budget PostgreSQL connections
|
|
67
|
+
|
|
68
|
+
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:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const layer = makePostgresTestLayer({
|
|
72
|
+
url,
|
|
73
|
+
migrations,
|
|
74
|
+
maxConnections: 3,
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
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.
|
|
79
|
+
|
|
80
|
+
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.
|
|
81
|
+
|
|
82
|
+
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.
|
|
83
|
+
|
|
66
84
|
### Ordinary tests: rollback
|
|
67
85
|
|
|
68
86
|
`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.
|
|
@@ -124,7 +142,7 @@ Import each name from the module that defines it. The package has no root entry.
|
|
|
124
142
|
|
|
125
143
|
| Module | Exports |
|
|
126
144
|
| --- | --- |
|
|
127
|
-
| `@shivaedev/effect-test-sql/postgres.ts` | `makePostgresTestLayer({ url, migrations, fixtures? })`, `PostgresTestOptions` |
|
|
145
|
+
| `@shivaedev/effect-test-sql/postgres.ts` | `makePostgresTestLayer({ url, migrations, fixtures?, maxConnections? })`, `PostgresTestOptions` |
|
|
128
146
|
| `@shivaedev/effect-test-sql/withTestTransaction.ts` | `withTestTransaction(effect)` |
|
|
129
147
|
| `@shivaedev/effect-test-sql/withIsolatedDatabase.ts` | `withIsolatedDatabase(effect)` |
|
|
130
148
|
| `@shivaedev/effect-test-sql/database.ts` | `PostgresTestDatabase`, `PostgresTestDatabaseService`, `PostgresTestServices` |
|
|
@@ -141,4 +159,4 @@ pnpm add --save-dev @shivaedev/effect-test-sql @shivaedev/effect-test @effect/sq
|
|
|
141
159
|
|
|
142
160
|
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.
|
|
143
161
|
|
|
144
|
-
The package tests use `PLATFORM_EFFECT_TEST_SQL_TEST_DATABASE_URL`. Repository setup and CI prepare that database on real PostgreSQL. Local tests skip when that variable is absent; CI rejects its absence. The PostgreSQL tests prove overlapping same-row visibility, shared-key lock contention and release, rollback, nested savepoints, runner/harness scope composition, one-time template preparation, commits visible through another connection, and database cleanup. Compiler and packed-consumer tests prove the exercised public type and export contracts. These are library checks, not evidence for an application's servers or notification delivery.
|
|
162
|
+
The package tests use `PLATFORM_EFFECT_TEST_SQL_TEST_DATABASE_URL`. Repository setup and CI prepare that database on real PostgreSQL. Local tests skip when that variable is absent; CI rejects its absence. The PostgreSQL tests prove overlapping same-row visibility, shared-key lock contention and release, rollback, nested savepoints, runner/harness scope composition, one-time template preparation, commits visible through another connection, and database cleanup. They also measure twelve concurrent clones through `pg_stat_activity` at both the default and overridden pool limits, verify administrative connection release, and exercise connection-limit diagnostics using restricted PostgreSQL roles. Compiler and packed-consumer tests prove the exercised public type and export contracts. These are library checks, not evidence for an application's servers or notification delivery.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import type { Model } from "effect/
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
3
|
import type { PostgresColumn } from "./migrationUpgrade.ts";
|
|
4
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
5
|
readonly _tag: "ModelColumnMismatch";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assertModelColumns.d.ts","sourceRoot":"","sources":["../../src/server/assertModelColumns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"assertModelColumns.d.ts","sourceRoot":"","sources":["../../src/server/assertModelColumns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,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,wBAAgB,kBAAkB,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,EAC1D,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,MAAM;CAAE,wFA2BvE"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
2
|
import { Context, type Effect, type Redacted, type Scope } from "effect";
|
|
3
|
-
import type * as Reactivity from "effect/
|
|
4
|
-
import type { SqlClient } from "effect/
|
|
5
|
-
import type { SqlError } 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
6
|
export type PostgresTestServices = PgClient.PgClient | SqlClient.SqlClient | Reactivity.Reactivity;
|
|
7
7
|
export interface PostgresTestDatabaseService {
|
|
8
8
|
readonly isolated: Effect.Effect<Context.Context<PostgresTestServices | PostgresTestDatabase>, SqlError, Scope.Scope>;
|
|
@@ -1 +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,
|
|
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;AAEnG,MAAM,WAAW,2BAA2B;IAC3C,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":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
2
|
import { Effect, Layer, Redacted } from "effect";
|
|
3
|
-
import * as Reactivity from "effect/
|
|
4
|
-
import { SqlClient } from "effect/
|
|
5
|
-
|
|
6
|
-
export declare
|
|
3
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import { SqlClient } from "effect/sql";
|
|
5
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
6
|
+
export declare function connection(url: Redacted.Redacted<string>, maxConnections: number): Layer.Layer<PgClient.PgClient | Reactivity.Reactivity | SqlClient.SqlClient, SqlError, never>;
|
|
7
|
+
export declare const database: (url: Redacted.Redacted<string>, template?: any) => Effect.Effect<{
|
|
7
8
|
name: string;
|
|
8
9
|
url: Redacted.Redacted<string>;
|
|
9
|
-
},
|
|
10
|
+
}, SqlError, import("effect/Scope").Scope>;
|
|
10
11
|
//# sourceMappingURL=databases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"databases.d.ts","sourceRoot":"","sources":["../../../src/server/internal/databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAW,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"databases.d.ts","sourceRoot":"","sources":["../../../src/server/internal/databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAW,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,MAAM,iGAMhF;AAWD,eAAO,MAAM,QAAQ;;;0CAUnB,CAAC"}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
2
|
import { Context, Effect, Layer, Redacted } from "effect";
|
|
3
|
-
import * as Reactivity from "effect/
|
|
4
|
-
import { SqlClient } from "effect/
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import { SqlClient } from "effect/sql";
|
|
5
|
+
import { connectionLimitHint } from "./connectionLimitHint.js";
|
|
6
|
+
export function connection(url, maxConnections) {
|
|
7
|
+
return Layer.effectContext(Effect.map(PgClient.make({ maxConnections, url }), (client) => Context.make(SqlClient.SqlClient, client).pipe(Context.add(PgClient.PgClient, client)))).pipe(Layer.provideMerge(Layer.fresh(Reactivity.layer)));
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
const administer = Effect.fn("PostgresTest.administer")(function* (url, operation) {
|
|
10
|
+
return yield* Effect.scoped(Effect.flatMap(PgClient.makeClient({ url }), operation).pipe(Effect.mapError(connectionLimitHint))).pipe(Effect.provide(Reactivity.layer));
|
|
11
|
+
});
|
|
12
|
+
export const database = Effect.fn("PostgresTest.database")(function* (url, template = "template0") {
|
|
9
13
|
const name = `effect_test_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
10
14
|
const target = new URL(Redacted.value(url));
|
|
11
15
|
target.pathname = `/${name}`;
|
|
12
16
|
target.searchParams.delete("database");
|
|
13
|
-
yield* Effect.acquireRelease(admin `create database ${admin(name)} template ${admin(template)}
|
|
17
|
+
yield* Effect.acquireRelease(administer(url, (admin) => admin `create database ${admin(name)} template ${admin(template)}`), () => Effect.orDie(administer(url, (admin) => admin `drop database ${admin(name)} with (force)`)));
|
|
14
18
|
return { name, url: Redacted.make(target.toString()) };
|
|
15
19
|
});
|
|
16
20
|
//# sourceMappingURL=databases.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"databases.js","sourceRoot":"","sources":["../../../src/server/internal/databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"databases.js","sourceRoot":"","sources":["../../../src/server/internal/databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,UAAU,UAAU,CAAC,GAA8B,EAAE,cAAsB;IAChF,OAAO,KAAK,CAAC,aAAa,CACzB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAC7D,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CACtF,CACD,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC,EAChE,GAA8B,EAC9B,SAAyE;IAEzE,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,IAAI,CACnI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAChC,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAE,GAA8B,EAAE,QAAQ,GAAG,WAAW;IAC3H,MAAM,IAAI,GAAG,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;IAC7B,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAC3B,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAA,mBAAmB,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,EAC7F,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAA,iBAAiB,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAChG,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC;AACxD,CAAC,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import { Migrator, SqlClient } from "effect/
|
|
2
|
+
import { Migrator, SqlClient } from "effect/sql";
|
|
3
3
|
import { type PostgresMigrationOptions } from "@shivaedev/effect-sql/migrations.ts";
|
|
4
4
|
export interface PostgresColumn {
|
|
5
5
|
readonly name: string;
|
|
@@ -10,5 +10,5 @@ export interface MigrationUpgradeOptions<R = never> {
|
|
|
10
10
|
readonly table: string;
|
|
11
11
|
readonly upTo: number;
|
|
12
12
|
}
|
|
13
|
-
export declare const migrationUpgrade: <R>(options: MigrationUpgradeOptions<R>) => Effect.Effect<readonly PostgresColumn[], Migrator.MigrationError | import("effect/
|
|
13
|
+
export declare const migrationUpgrade: <R>(options: MigrationUpgradeOptions<R>) => Effect.Effect<readonly PostgresColumn[], Migrator.MigrationError | import("effect/sql/SqlError").SqlError, R | SqlClient.SqlClient>;
|
|
14
14
|
//# sourceMappingURL=migrationUpgrade.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationUpgrade.d.ts","sourceRoot":"","sources":["../../src/server/migrationUpgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"migrationUpgrade.d.ts","sourceRoot":"","sources":["../../src/server/migrationUpgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAmB,KAAK,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAErG,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,GAAG,KAAK;IACjD,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,GAAyD,CAAC,6KA6BrF,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, Option } from "effect";
|
|
2
|
-
import { Migrator, SqlClient } from "effect/
|
|
2
|
+
import { Migrator, SqlClient } from "effect/sql";
|
|
3
3
|
import { migratePostgres } from "@shivaedev/effect-sql/migrations.ts";
|
|
4
4
|
export const migrationUpgrade = Effect.fn("PostgresTest.migrationUpgrade")(function* (options) {
|
|
5
5
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationUpgrade.js","sourceRoot":"","sources":["../../src/server/migrationUpgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"migrationUpgrade.js","sourceRoot":"","sources":["../../src/server/migrationUpgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,eAAe,EAAiC,MAAM,qCAAqC,CAAC;AAarG,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAAK,OAAmC;IAC3H,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,SAAS,OAAO,CAAC,OAAe;QAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC;IACD,KAAK,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,8CAA8C,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7H,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,mEAAmE,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,uBAAuB,CAAC;IACnE,MAAM,UAAU,GAAG,GAAG,CAAA,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAkC,sBAAsB,UAAU,iBAAiB,CAAC,gBAAgB,CAAC;IAChI,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA,4BAA4B,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;QAC5E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,6DAA6D,CAAC,CAAC;QACtF,CAAC;IACF,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;IAClD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,aAAa,OAAO,CAAC,IAAI,wBAAwB,CAAC,CAAC;IAC1E,CAAC;IACD,KAAK,CAAC,CAAC,eAAe,CAAC,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;IACzH,KAAK,CAAC,CAAC,eAAe,CAAC,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACpF,OAAO,KAAK,CAAC,CAAC,GAAG,CAAgB;;;qBAGb,OAAO,CAAC,KAAK;mBACf,CAAC,gBAAgB,CAAC;AACrC,CAAC,CAAC,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
1
|
import { Effect, Layer, type Redacted } from "effect";
|
|
3
|
-
import * as Reactivity from "effect/
|
|
2
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
3
|
import { type PostgresMigrationOptions } from "@shivaedev/effect-sql/migrations.ts";
|
|
5
4
|
import { PostgresTestDatabase, type PostgresTestServices } from "./database.ts";
|
|
6
5
|
export interface PostgresTestOptions<E = never, R = never, TFixtures = never> {
|
|
7
6
|
readonly fixtures?: Effect.Effect<unknown, E, TFixtures | PostgresTestServices>;
|
|
7
|
+
readonly maxConnections?: number;
|
|
8
8
|
readonly migrations: PostgresMigrationOptions<R>;
|
|
9
9
|
readonly url: Redacted.Redacted<string>;
|
|
10
10
|
}
|
|
11
|
-
export declare function makePostgresTestLayer<E = never, R = never, TFixtures = never>(options: PostgresTestOptions<E, R, TFixtures>): Layer.Layer<PgClient.PgClient | PostgresTestDatabase | Reactivity.Reactivity | import("effect/
|
|
11
|
+
export declare function makePostgresTestLayer<E = never, R = never, TFixtures = never>(options: PostgresTestOptions<E, R, TFixtures>): Layer.Layer<import("@effect/sql-pg/PgClient").PgClient | PostgresTestDatabase | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient, E | import("effect/sql/Migrator").MigrationError | import("effect/sql/SqlError").SqlError, Exclude<Exclude<Exclude<Exclude<R, import("@effect/sql-pg/PgClient").PgClient | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient>, import("effect/Scope").Scope>, import("effect/Scope").Scope>, Reactivity.Reactivity> | Exclude<Exclude<Exclude<Exclude<TFixtures, import("@effect/sql-pg/PgClient").PgClient | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient>, import("effect/Scope").Scope>, import("effect/Scope").Scope>, Reactivity.Reactivity>>;
|
|
12
12
|
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/server/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/server/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAmB,KAAK,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAGrG,OAAO,EAAE,oBAAoB,EAAoC,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAElH,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,SAAS,GAAG,oBAAoB,CAAC,CAAC;IAChF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,wBAAgB,qBAAqB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,2sBAwB3H"}
|
package/dist/server/postgres.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
1
|
import { Context, Effect, Layer } from "effect";
|
|
3
|
-
import * as Reactivity from "effect/
|
|
2
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
3
|
import { migratePostgres } from "@shivaedev/effect-sql/migrations.ts";
|
|
4
|
+
import { connectionLimitHint } from "#internal/connectionLimitHint.ts";
|
|
5
5
|
import { connection, database } from "#internal/databases.ts";
|
|
6
6
|
import { PostgresTestDatabase } from "./database.js";
|
|
7
7
|
export function makePostgresTestLayer(options) {
|
|
8
8
|
return Layer.effectContext(Effect.gen(function* () {
|
|
9
|
-
const
|
|
10
|
-
const template = yield* database(
|
|
9
|
+
const maxConnections = options.maxConnections ?? 2;
|
|
10
|
+
const template = yield* database(options.url);
|
|
11
11
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
12
|
-
const services = yield* Layer.build(connection(template.url));
|
|
12
|
+
const services = yield* Layer.build(connection(template.url, maxConnections));
|
|
13
13
|
yield* migratePostgres(options.migrations).pipe(Effect.provideContext(services));
|
|
14
14
|
if (options.fixtures !== undefined) {
|
|
15
15
|
yield* options.fixtures.pipe(Effect.provideContext(services));
|
|
16
16
|
}
|
|
17
17
|
}));
|
|
18
|
-
const shared = yield* database(
|
|
19
|
-
const services = yield* Layer.build(connection(shared.url));
|
|
18
|
+
const shared = yield* database(options.url, template.name);
|
|
19
|
+
const services = yield* Layer.build(connection(shared.url, maxConnections));
|
|
20
20
|
const isolated = Effect.gen(function* () {
|
|
21
|
-
const clone = yield* database(
|
|
22
|
-
const context = yield* Layer.build(connection(clone.url));
|
|
21
|
+
const clone = yield* database(options.url, template.name);
|
|
22
|
+
const context = yield* Layer.build(connection(clone.url, maxConnections));
|
|
23
23
|
return Context.add(context, PostgresTestDatabase, { isolated, url: clone.url });
|
|
24
24
|
});
|
|
25
25
|
return Context.add(services, PostgresTestDatabase, { isolated, url: shared.url });
|
|
26
|
-
})).pipe(Layer.provide(Reactivity.layer));
|
|
26
|
+
}).pipe(Effect.mapError(connectionLimitHint))).pipe(Layer.provide(Reactivity.layer));
|
|
27
27
|
}
|
|
28
28
|
//# sourceMappingURL=postgres.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/server/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/server/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAiB,MAAM,QAAQ,CAAC;AAC/D,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAiC,MAAM,qCAAqC,CAAC;AACrG,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAA+D,MAAM,eAAe,CAAC;AASlH,MAAM,UAAU,qBAAqB,CAA0C,OAA6C;IAC3H,OAAO,KAAK,CAAC,aAAa,CACzB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;YAC9E,KAAK,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjF,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACpC,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC/D,CAAC;QACF,CAAC,CAAC,CACF,CAAC;QACF,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;QAC5E,MAAM,QAAQ,GAA4C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC7E,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;YAC1E,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,oBAAoB,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAC7C,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { PostgresTestDatabase } from "./database.ts";
|
|
3
|
-
export declare function withIsolatedDatabase<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | import("effect/
|
|
3
|
+
export declare function withIsolatedDatabase<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | import("effect/sql/SqlError").SqlError, PostgresTestDatabase | Exclude<Exclude<R, PostgresTestDatabase | import("./database.ts").PostgresTestServices>, import("effect/Scope").Scope>>;
|
|
4
4
|
//# sourceMappingURL=withIsolatedDatabase.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withIsolatedDatabase.d.ts","sourceRoot":"","sources":["../../src/server/withIsolatedDatabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"withIsolatedDatabase.d.ts","sourceRoot":"","sources":["../../src/server/withIsolatedDatabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,+MAQ3E"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
+
import { connectionLimitHint } from "#internal/connectionLimitHint.ts";
|
|
2
3
|
import { PostgresTestDatabase } from "./database.js";
|
|
3
4
|
export function withIsolatedDatabase(effect) {
|
|
4
5
|
return Effect.scoped(Effect.gen(function* () {
|
|
5
6
|
const database = yield* PostgresTestDatabase;
|
|
6
7
|
const services = yield* database.isolated;
|
|
7
8
|
return yield* effect.pipe(Effect.provideContext(services));
|
|
8
|
-
}));
|
|
9
|
+
})).pipe(Effect.mapError(connectionLimitHint));
|
|
9
10
|
}
|
|
10
11
|
//# sourceMappingURL=withIsolatedDatabase.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withIsolatedDatabase.js","sourceRoot":"","sources":["../../src/server/withIsolatedDatabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,UAAU,oBAAoB,CAAU,MAA8B;IAC3E,OAAO,MAAM,CAAC,MAAM,CACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC1C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CACF,CAAC;
|
|
1
|
+
{"version":3,"file":"withIsolatedDatabase.js","sourceRoot":"","sources":["../../src/server/withIsolatedDatabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,UAAU,oBAAoB,CAAU,MAA8B;IAC3E,OAAO,MAAM,CAAC,MAAM,CACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC1C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CACF,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import type { SqlError } from "effect/
|
|
3
|
-
export declare function withTestTransaction<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | SqlError, import("effect/
|
|
2
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
3
|
+
export declare function withTestTransaction<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | SqlError, import("effect/reactivity/Reactivity").Reactivity | import("effect/sql/SqlClient").SqlClient | Exclude<R, import("effect/Scope").Scope>>;
|
|
4
4
|
//# sourceMappingURL=withTestTransaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withTestTransaction.d.ts","sourceRoot":"","sources":["../../src/server/withTestTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"withTestTransaction.d.ts","sourceRoot":"","sources":["../../src/server/withTestTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAQpD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,2KAO1E"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Effect, Exit } from "effect";
|
|
2
2
|
import { transact } from "@shivaedev/effect-sql/transact.ts";
|
|
3
|
+
import { connectionLimitHint } from "#internal/connectionLimitHint.ts";
|
|
3
4
|
function isTestExit(value) {
|
|
4
5
|
return Exit.isExit(value);
|
|
5
6
|
}
|
|
6
7
|
export function withTestTransaction(effect) {
|
|
7
|
-
return Effect.uninterruptibleMask((restore) => transact(Effect.flatMap(Effect.exit(Effect.scoped(restore(effect))), Effect.fail), { onSqlError: (error) => error }).pipe(Effect.catchIf(isTestExit, (exit) => exit)));
|
|
8
|
+
return Effect.uninterruptibleMask((restore) => transact(Effect.flatMap(Effect.exit(Effect.scoped(restore(effect))), Effect.fail), { onSqlError: (error) => error }).pipe(Effect.catchIf(isTestExit, (exit) => exit), Effect.mapError(connectionLimitHint)));
|
|
8
9
|
}
|
|
9
10
|
//# sourceMappingURL=withTestTransaction.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withTestTransaction.js","sourceRoot":"","sources":["../../src/server/withTestTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"withTestTransaction.js","sourceRoot":"","sources":["../../src/server/withTestTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,SAAS,UAAU,CAAO,KAAiC;IAC1D,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAU,MAA8B;IAC1E,OAAO,MAAM,CAAC,mBAAmB,CAAC,CAAC,OAAO,EAAE,EAAE,CAC7C,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CACxH,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAC1C,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CACpC,CACD,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-test-sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "PostgreSQL rollback and real-commit test isolation for Effect",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-test-sql#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -42,22 +42,22 @@
|
|
|
42
42
|
"README.md"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@shivaedev/effect-sql": "0.
|
|
45
|
+
"@shivaedev/effect-sql": "0.5.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@effect/sql-pg": "4.0.
|
|
49
|
-
"@effect/vitest": "4.0.
|
|
50
|
-
"@shivaedev/effect-test": "0.
|
|
51
|
-
"@shivaedev/quality": "0.
|
|
48
|
+
"@effect/sql-pg": "4.0.4",
|
|
49
|
+
"@effect/vitest": "4.0.4",
|
|
50
|
+
"@shivaedev/effect-test": "0.5.0",
|
|
51
|
+
"@shivaedev/quality": "0.22.0",
|
|
52
52
|
"@types/node": "24.19.1",
|
|
53
53
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
54
|
-
"effect": "4.0.
|
|
54
|
+
"effect": "4.0.4",
|
|
55
55
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
56
|
-
"vitest": "
|
|
56
|
+
"vitest": "5.0.3"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@effect/sql-pg": "4.0.
|
|
60
|
-
"effect": "4.0.
|
|
59
|
+
"@effect/sql-pg": "4.0.4",
|
|
60
|
+
"effect": "4.0.4"
|
|
61
61
|
},
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=24"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Data, Effect } from "effect";
|
|
2
|
-
import type { Model } from "effect/
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
3
|
import type { PostgresColumn } from "./migrationUpgrade.ts";
|
|
4
4
|
|
|
5
5
|
export class ModelColumnMismatch extends Data.TaggedError("ModelColumnMismatch")<{
|
package/src/server/database.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
2
|
import { Context, type Effect, type Redacted, type Scope } from "effect";
|
|
3
|
-
import type * as Reactivity from "effect/
|
|
4
|
-
import type { SqlClient } from "effect/
|
|
5
|
-
import type { SqlError } 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
6
|
|
|
7
7
|
export type PostgresTestServices = PgClient.PgClient | SqlClient.SqlClient | Reactivity.Reactivity;
|
|
8
8
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Predicate } from "effect";
|
|
2
|
+
import { ConnectionError, isSqlError, SqlError } from "effect/sql/SqlError";
|
|
3
|
+
|
|
4
|
+
export function connectionLimitHint<E>(error: E): E | SqlError {
|
|
5
|
+
if (!(isSqlError(error) && Predicate.hasProperty(error.reason.cause, "code")) || error.reason.cause.code !== "53300") {
|
|
6
|
+
return error;
|
|
7
|
+
}
|
|
8
|
+
return new SqlError({
|
|
9
|
+
reason: new ConnectionError({
|
|
10
|
+
cause: error.reason.cause,
|
|
11
|
+
message:
|
|
12
|
+
"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.",
|
|
13
|
+
operation: error.reason.operation,
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
2
|
import { Context, Effect, Layer, Redacted } from "effect";
|
|
3
|
-
import * as Reactivity from "effect/
|
|
4
|
-
import { SqlClient } from "effect/
|
|
3
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import { SqlClient } from "effect/sql";
|
|
5
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
6
|
+
import { connectionLimitHint } from "./connectionLimitHint.ts";
|
|
5
7
|
|
|
6
|
-
export function connection(url: Redacted.Redacted<string
|
|
8
|
+
export function connection(url: Redacted.Redacted<string>, maxConnections: number) {
|
|
7
9
|
return Layer.effectContext(
|
|
8
|
-
Effect.map(PgClient.make({ url }), (client) =>
|
|
10
|
+
Effect.map(PgClient.make({ maxConnections, url }), (client) =>
|
|
11
|
+
Context.make(SqlClient.SqlClient, client).pipe(Context.add(PgClient.PgClient, client)),
|
|
12
|
+
),
|
|
9
13
|
).pipe(Layer.provideMerge(Layer.fresh(Reactivity.layer)));
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
admin: PgClient.PgClient,
|
|
16
|
+
const administer = Effect.fn("PostgresTest.administer")(function* (
|
|
14
17
|
url: Redacted.Redacted<string>,
|
|
15
|
-
|
|
18
|
+
operation: (admin: PgClient.PgClient) => Effect.Effect<unknown, SqlError>,
|
|
16
19
|
) {
|
|
20
|
+
return yield* Effect.scoped(Effect.flatMap(PgClient.makeClient({ url }), operation).pipe(Effect.mapError(connectionLimitHint))).pipe(
|
|
21
|
+
Effect.provide(Reactivity.layer),
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const database = Effect.fn("PostgresTest.database")(function* (url: Redacted.Redacted<string>, template = "template0") {
|
|
17
26
|
const name = `effect_test_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
18
27
|
const target = new URL(Redacted.value(url));
|
|
19
28
|
target.pathname = `/${name}`;
|
|
20
29
|
target.searchParams.delete("database");
|
|
21
|
-
yield* Effect.acquireRelease(
|
|
22
|
-
|
|
30
|
+
yield* Effect.acquireRelease(
|
|
31
|
+
administer(url, (admin) => admin`create database ${admin(name)} template ${admin(template)}`),
|
|
32
|
+
() => Effect.orDie(administer(url, (admin) => admin`drop database ${admin(name)} with (force)`)),
|
|
23
33
|
);
|
|
24
34
|
return { name, url: Redacted.make(target.toString()) };
|
|
25
35
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, Option } from "effect";
|
|
2
|
-
import { Migrator, SqlClient } from "effect/
|
|
2
|
+
import { Migrator, SqlClient } from "effect/sql";
|
|
3
3
|
import { migratePostgres, type PostgresMigrationOptions } from "@shivaedev/effect-sql/migrations.ts";
|
|
4
4
|
|
|
5
5
|
export interface PostgresColumn {
|
package/src/server/postgres.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import * as PgClient from "@effect/sql-pg/PgClient";
|
|
2
1
|
import { Context, Effect, Layer, type Redacted } from "effect";
|
|
3
|
-
import * as Reactivity from "effect/
|
|
2
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
3
|
import { migratePostgres, type PostgresMigrationOptions } from "@shivaedev/effect-sql/migrations.ts";
|
|
4
|
+
import { connectionLimitHint } from "#internal/connectionLimitHint.ts";
|
|
5
5
|
import { connection, database } from "#internal/databases.ts";
|
|
6
6
|
import { PostgresTestDatabase, type PostgresTestDatabaseService, type PostgresTestServices } from "./database.ts";
|
|
7
7
|
|
|
8
8
|
export interface PostgresTestOptions<E = never, R = never, TFixtures = never> {
|
|
9
9
|
readonly fixtures?: Effect.Effect<unknown, E, TFixtures | PostgresTestServices>;
|
|
10
|
+
readonly maxConnections?: number;
|
|
10
11
|
readonly migrations: PostgresMigrationOptions<R>;
|
|
11
12
|
readonly url: Redacted.Redacted<string>;
|
|
12
13
|
}
|
|
@@ -14,25 +15,25 @@ export interface PostgresTestOptions<E = never, R = never, TFixtures = never> {
|
|
|
14
15
|
export function makePostgresTestLayer<E = never, R = never, TFixtures = never>(options: PostgresTestOptions<E, R, TFixtures>) {
|
|
15
16
|
return Layer.effectContext(
|
|
16
17
|
Effect.gen(function* () {
|
|
17
|
-
const
|
|
18
|
-
const template = yield* database(
|
|
18
|
+
const maxConnections = options.maxConnections ?? 2;
|
|
19
|
+
const template = yield* database(options.url);
|
|
19
20
|
yield* Effect.scoped(
|
|
20
21
|
Effect.gen(function* () {
|
|
21
|
-
const services = yield* Layer.build(connection(template.url));
|
|
22
|
+
const services = yield* Layer.build(connection(template.url, maxConnections));
|
|
22
23
|
yield* migratePostgres(options.migrations).pipe(Effect.provideContext(services));
|
|
23
24
|
if (options.fixtures !== undefined) {
|
|
24
25
|
yield* options.fixtures.pipe(Effect.provideContext(services));
|
|
25
26
|
}
|
|
26
27
|
}),
|
|
27
28
|
);
|
|
28
|
-
const shared = yield* database(
|
|
29
|
-
const services = yield* Layer.build(connection(shared.url));
|
|
29
|
+
const shared = yield* database(options.url, template.name);
|
|
30
|
+
const services = yield* Layer.build(connection(shared.url, maxConnections));
|
|
30
31
|
const isolated: PostgresTestDatabaseService["isolated"] = Effect.gen(function* () {
|
|
31
|
-
const clone = yield* database(
|
|
32
|
-
const context = yield* Layer.build(connection(clone.url));
|
|
32
|
+
const clone = yield* database(options.url, template.name);
|
|
33
|
+
const context = yield* Layer.build(connection(clone.url, maxConnections));
|
|
33
34
|
return Context.add(context, PostgresTestDatabase, { isolated, url: clone.url });
|
|
34
35
|
});
|
|
35
36
|
return Context.add(services, PostgresTestDatabase, { isolated, url: shared.url });
|
|
36
|
-
}),
|
|
37
|
+
}).pipe(Effect.mapError(connectionLimitHint)),
|
|
37
38
|
).pipe(Layer.provide(Reactivity.layer));
|
|
38
39
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
+
import { connectionLimitHint } from "#internal/connectionLimitHint.ts";
|
|
2
3
|
import { PostgresTestDatabase } from "./database.ts";
|
|
3
4
|
|
|
4
5
|
export function withIsolatedDatabase<A, E, R>(effect: Effect.Effect<A, E, R>) {
|
|
@@ -8,5 +9,5 @@ export function withIsolatedDatabase<A, E, R>(effect: Effect.Effect<A, E, R>) {
|
|
|
8
9
|
const services = yield* database.isolated;
|
|
9
10
|
return yield* effect.pipe(Effect.provideContext(services));
|
|
10
11
|
}),
|
|
11
|
-
);
|
|
12
|
+
).pipe(Effect.mapError(connectionLimitHint));
|
|
12
13
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Effect, Exit } from "effect";
|
|
2
|
-
import type { SqlError } from "effect/
|
|
2
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
3
3
|
import { transact } from "@shivaedev/effect-sql/transact.ts";
|
|
4
|
+
import { connectionLimitHint } from "#internal/connectionLimitHint.ts";
|
|
4
5
|
|
|
5
6
|
function isTestExit<A, E>(value: Exit.Exit<A, E> | SqlError): value is Exit.Exit<A, E> {
|
|
6
7
|
return Exit.isExit(value);
|
|
@@ -10,6 +11,7 @@ export function withTestTransaction<A, E, R>(effect: Effect.Effect<A, E, R>) {
|
|
|
10
11
|
return Effect.uninterruptibleMask((restore) =>
|
|
11
12
|
transact(Effect.flatMap(Effect.exit(Effect.scoped(restore(effect))), Effect.fail), { onSqlError: (error) => error }).pipe(
|
|
12
13
|
Effect.catchIf(isTestExit, (exit) => exit),
|
|
14
|
+
Effect.mapError(connectionLimitHint),
|
|
13
15
|
),
|
|
14
16
|
);
|
|
15
17
|
}
|