@shivaedev/test-sql 0.11.0 → 0.13.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 +30 -0
- package/README.md +2 -2
- package/dist/server/internal/databaseOwner.d.ts +3 -1
- package/dist/server/internal/databaseOwner.d.ts.map +1 -1
- package/dist/server/internal/databaseOwner.js +3 -3
- package/dist/server/internal/databaseOwner.js.map +1 -1
- package/dist/server/internal/databases.js +1 -1
- package/dist/server/internal/databases.js.map +1 -1
- package/dist/server/migrationSteps.d.ts +3 -3
- package/dist/server/migrationSteps.d.ts.map +1 -1
- package/dist/server/migrationSteps.js.map +1 -1
- package/dist/server/migrationUpgrade.d.ts +3 -3
- package/dist/server/migrationUpgrade.d.ts.map +1 -1
- package/dist/server/migrationUpgrade.js.map +1 -1
- package/dist/server/postgres.d.ts +2 -2
- package/dist/server/postgres.d.ts.map +1 -1
- package/dist/server/raceWithLock.d.ts +1 -0
- package/dist/server/raceWithLock.d.ts.map +1 -1
- package/dist/server/raceWithLock.js +16 -5
- package/dist/server/raceWithLock.js.map +1 -1
- package/package.json +8 -7
- package/src/server/internal/databaseOwner.ts +6 -3
- package/src/server/internal/databases.ts +1 -1
- package/src/server/migrationSteps.ts +1 -1
- package/src/server/migrationUpgrade.ts +3 -3
- package/src/server/postgres.ts +1 -1
- package/src/server/raceWithLock.ts +26 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.0 - 2026-10-30
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `raceWithLock` takes `count: "every blocked session"` for contenders whose SQL runs on other fibers, such as an HTTP server's handlers. The holder then releases once it blocks as many sessions as there are effects.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `raceWithLock` releases its holder once its own contenders wait, instead of hanging until its timeout when another session also waits on the holder. Each contender's statements now start with a `/* raceWithLock <holder pid>.<index> */` comment.
|
|
12
|
+
|
|
13
|
+
## 0.12.0 - 2026-10-30
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Export every engine module through the package's existing `.ts` wildcard, including modules under `internal/` in `test` and `vitest-rerun` and `server/internal/` in `test-story` and `test-sql`, so downstream kits can reuse them directly. Importing the rerun worker leaves test execution to its direct launch.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Generate disposable PostgreSQL database names through Effect's Random service.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- SQL decodes migration ledger, release ownership and change-coverage rows before using them. Malformed rows fail with `SchemaError` instead of being treated as current, pending or a different owner.
|
|
26
|
+
- SQL generates worker identities and change-listener heartbeat tokens through Effect's `Random` service.
|
|
27
|
+
|
|
28
|
+
### Breaking
|
|
29
|
+
|
|
30
|
+
- Schema component failures now reach SQL migration and readiness callers, server startup and test-sql migration helpers with their original error, tag and cause, and log the component name. Handle the component's own error instead of a wrapping `MigrationError` with kind `Failed`. When annotating migration options with fallible components, supply their error type as the second generic parameter; the default describes components that cannot fail.
|
|
31
|
+
- Declare `WorkerRelease` through `defineService`. Consumers using the old class as a type must use `Context.Service.Identifier<typeof WorkerRelease>`; yielding the service and providing its value stay the same.
|
|
32
|
+
|
|
3
33
|
## 0.11.0 - 2026-10-30
|
|
4
34
|
|
|
5
35
|
### Added
|
package/README.md
CHANGED
|
@@ -156,7 +156,7 @@ Inside an isolated block, `PostgresTestDatabase.url` names that clone. Use it to
|
|
|
156
156
|
|
|
157
157
|
### Race stories
|
|
158
158
|
|
|
159
|
-
Use `raceWithLock` with a live story clock inside an isolated database, outside a wrapping transaction. Supply the native SQL Effect that takes a row, table or transaction advisory lock, and one Effect per competing call. The helper holds the lock in a separate transaction, starts the calls, and waits
|
|
159
|
+
Use `raceWithLock` with a live story clock inside an isolated database, outside a wrapping transaction. Supply the native SQL Effect that takes a row, table or transaction advisory lock, and one Effect per competing call. The helper holds the lock in a separate transaction, starts the calls, and waits until PostgreSQL's blocker graph contains every contender before releasing the holder. Each contender's statements start with a `/* raceWithLock <holder pid>.<index> */` comment, so the helper counts only its own contenders and another session waiting on the holder does not hold up the release. When the contenders' SQL runs on other fibers, such as an HTTP server's handlers, the tag cannot reach it; set `count: "every blocked session"` to release once the holder blocks as many sessions as there are effects, and keep other waiters out of that database. Other lock-taking work in that database can still queue ahead of the contenders and change who wins, and the helper needs at least `effects.length + 1` pool connections. Contenders keep their own transaction and service conventions.
|
|
160
160
|
|
|
161
161
|
```ts
|
|
162
162
|
import { raceWithLock } from "@shivaedev/test-sql/server/raceWithLock.ts";
|
|
@@ -251,7 +251,7 @@ The assertion uses the SQL `Model`'s selected database fields, including generat
|
|
|
251
251
|
|
|
252
252
|
### API
|
|
253
253
|
|
|
254
|
-
Import each name from the module that defines it. The package has no root entry.
|
|
254
|
+
Import each name from the module that defines it. The package has no root entry. Every source module is available through its `.ts` subpath, including modules under `server/internal/`.
|
|
255
255
|
|
|
256
256
|
| Module | Exports |
|
|
257
257
|
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
export declare const databaseId: Effect.Effect<string, never, never>;
|
|
3
|
+
export declare const databaseName: Effect.Effect<string, never, never>;
|
|
2
4
|
export declare function abandonedDatabase(name: string): boolean;
|
|
3
5
|
//# sourceMappingURL=databaseOwner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"databaseOwner.d.ts","sourceRoot":"","sources":["../../../src/server/internal/databaseOwner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"databaseOwner.d.ts","sourceRoot":"","sources":["../../../src/server/internal/databaseOwner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAIxC,eAAO,MAAM,UAAU,qCAEtB,CAAC;AAEF,eAAO,MAAM,YAAY,qCAA6E,CAAC;AAEvG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,WAc7C"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { hostname } from "node:os";
|
|
3
3
|
import process from "node:process";
|
|
4
|
+
import { Effect, Random } from "effect";
|
|
4
5
|
const host = createHash("sha256").update(hostname()).digest("hex").slice(0, 8);
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
}
|
|
6
|
+
export const databaseId = Effect.map(Effect.replicateEffect(Random.nextIntBetween(0, 0xff_ff_ff_ff), 4), (parts) => parts.map((part) => part.toString(16).padStart(8, "0")).join(""));
|
|
7
|
+
export const databaseName = Effect.map(databaseId, (id) => `effect_test_${host}_${process.pid}_${id}`);
|
|
8
8
|
export function abandonedDatabase(name) {
|
|
9
9
|
if (/^effect_test_[a-f0-9]{32}$/u.test(name)) {
|
|
10
10
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"databaseOwner.js","sourceRoot":"","sources":["../../../src/server/internal/databaseOwner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,OAAO,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"databaseOwner.js","sourceRoot":"","sources":["../../../src/server/internal/databaseOwner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE/E,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAClH,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAChE,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC;AAEvG,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC7C,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,KAAK,GAAG,iEAAiE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3F,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,EAAE,CAAC;QACnD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,OAAO,KAAK,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;IAC5E,CAAC;AACF,CAAC"}
|
|
@@ -16,7 +16,7 @@ export const administer = Effect.fn("PostgresTest.administer")(function* (url, o
|
|
|
16
16
|
return yield* Effect.scoped(Effect.flatMap(PgClient.makeClient({ url }), operation).pipe(Effect.mapError(connectionLimitHint))).pipe(Effect.provide(Reactivity.layer));
|
|
17
17
|
});
|
|
18
18
|
export const database = Effect.fn("PostgresTest.database")(function* (url, release, template = "template0") {
|
|
19
|
-
const name = databaseName
|
|
19
|
+
const name = yield* databaseName;
|
|
20
20
|
const target = new URL(Redacted.value(url));
|
|
21
21
|
target.pathname = `/${name}`;
|
|
22
22
|
target.searchParams.delete("database");
|
|
@@ -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,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,UAAU,UAAU,CAAC,GAA8B,EAAE,cAAsB,EAAE,UAA6B;IAC/G,OAAO,KAAK,CAAC,aAAa,CACzB,MAAM,CAAC,GAAG,CACT,QAAQ,CAAC,IAAI,CAAC;QACb,cAAc;QACd,mBAAmB,EAAE,UAAU,CAAC,mBAAmB;QACnD,oBAAoB,EAAE,UAAU,CAAC,oBAAoB;QACrD,GAAG;KACH,CAAC,EACF,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAClG,CACD,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC,EACvE,GAA8B,EAC9B,SAAmE;IAEnE,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,EACnE,GAA8B,EAC9B,OAAiD,EACjD,QAAQ,GAAG,WAAW;IAEtB,MAAM,IAAI,GAAG,
|
|
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;AAGvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,UAAU,UAAU,CAAC,GAA8B,EAAE,cAAsB,EAAE,UAA6B;IAC/G,OAAO,KAAK,CAAC,aAAa,CACzB,MAAM,CAAC,GAAG,CACT,QAAQ,CAAC,IAAI,CAAC;QACb,cAAc;QACd,mBAAmB,EAAE,UAAU,CAAC,mBAAmB;QACnD,oBAAoB,EAAE,UAAU,CAAC,oBAAoB;QACrD,GAAG;KACH,CAAC,EACF,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAClG,CACD,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC,EACvE,GAA8B,EAC9B,SAAmE;IAEnE,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,EACnE,GAA8B,EAC9B,OAAiD,EACjD,QAAQ,GAAG,WAAW;IAEtB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC;IACjC,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,OAAO,CAAC,IAAI,CAAC,CACnB,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC;AACxD,CAAC,CAAC,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { Migrator, SqlClient } from "effect/sql";
|
|
3
3
|
import { type PostgresMigrationOptions } from "@shivaedev/sql/migrations.ts";
|
|
4
|
-
export declare const migrationSteps: <R>(migrations: PostgresMigrationOptions<R>) => Effect.Effect<{
|
|
5
|
-
migrateTo: (name: string | number) => Effect.Effect<readonly (readonly [id: number, name: string])[], Migrator.MigrationError | import("effect/sql/SqlError").SqlError, Exclude<R, R | SqlClient.SqlClient>>;
|
|
6
|
-
migrateToLatest: Effect.Effect<readonly (readonly [id: number, name: string])[], Migrator.MigrationError | import("effect/sql/SqlError").SqlError, Exclude<R, R | SqlClient.SqlClient>>;
|
|
4
|
+
export declare const migrationSteps: <R, E = never>(migrations: PostgresMigrationOptions<R, E>) => Effect.Effect<{
|
|
5
|
+
migrateTo: (name: string | number) => Effect.Effect<readonly (readonly [id: number, name: string])[], E | Migrator.MigrationError | import("effect/Schema").SchemaError | import("effect/sql/SqlError").SqlError, Exclude<R, R | SqlClient.SqlClient>>;
|
|
6
|
+
migrateToLatest: Effect.Effect<readonly (readonly [id: number, name: string])[], E | Migrator.MigrationError | import("effect/Schema").SchemaError | import("effect/sql/SqlError").SqlError, Exclude<R, R | SqlClient.SqlClient>>;
|
|
7
7
|
}, Migrator.MigrationError, R | SqlClient.SqlClient>;
|
|
8
8
|
//# sourceMappingURL=migrationSteps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationSteps.d.ts","sourceRoot":"","sources":["../../src/server/migrationSteps.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,8BAA8B,CAAC;AAY9F,eAAO,MAAM,cAAc,GAAuD,CAAC;
|
|
1
|
+
{"version":3,"file":"migrationSteps.d.ts","sourceRoot":"","sources":["../../src/server/migrationSteps.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,8BAA8B,CAAC;AAY9F,eAAO,MAAM,cAAc,GAAuD,CAAC,EAAE,CAAC;sBAwBlE,MAAM,GAAG,MAAM;;oDAejC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationSteps.js","sourceRoot":"","sources":["../../src/server/migrationSteps.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,8BAA8B,CAAC;AAE9F,SAAS,OAAO,CAAC,OAAe;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAwB;IAC/E,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,0DAA0D,CAAC,CAAC;IACnF,CAAC;AACF,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,6BAA6B,CAAC,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"migrationSteps.js","sourceRoot":"","sources":["../../src/server/migrationSteps.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,10 +5,10 @@ export interface PostgresColumn {
|
|
|
5
5
|
readonly name: string;
|
|
6
6
|
readonly type: string;
|
|
7
7
|
}
|
|
8
|
-
export interface MigrationUpgradeOptions<R = never> {
|
|
9
|
-
readonly migrations: PostgresMigrationOptions<R>;
|
|
8
|
+
export interface MigrationUpgradeOptions<R = never, E = never> {
|
|
9
|
+
readonly migrations: PostgresMigrationOptions<R, E>;
|
|
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/sql/SqlError").SqlError, R | SqlClient.SqlClient>;
|
|
13
|
+
export declare const migrationUpgrade: <R, E = never>(options: MigrationUpgradeOptions<R, E>) => Effect.Effect<readonly PostgresColumn[], E | Migrator.MigrationError | import("effect/Schema").SchemaError | 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,YAAY,CAAC;AACjD,OAAO,EAAmB,KAAK,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,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;
|
|
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,8BAA8B,CAAC;AAE9F,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,EAAE,CAAC,GAAG,KAAK;IAC5D,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,GAAyD,CAAC,EAAE,CAAC,kOA6BxF,CAAC"}
|
|
@@ -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,YAAY,CAAC;AACjD,OAAO,EAAE,eAAe,EAAiC,MAAM,8BAA8B,CAAC;AAa9F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,
|
|
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,8BAA8B,CAAC;AAa9F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAAgB,OAAsC;IACzI,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"}
|
|
@@ -11,12 +11,12 @@ interface PostgresTestCommonOptions<E, TFixtures> extends SqlNameTransforms {
|
|
|
11
11
|
readonly url: Redacted.Redacted<string>;
|
|
12
12
|
}
|
|
13
13
|
export type PostgresTestOptions<E = never, R = never, TFixtures = never> = PostgresTestCommonOptions<E, TFixtures> & ({
|
|
14
|
-
readonly migrations: PostgresMigrationOptions<R>;
|
|
14
|
+
readonly migrations: PostgresMigrationOptions<R, E>;
|
|
15
15
|
readonly initialize?: never;
|
|
16
16
|
} | {
|
|
17
17
|
readonly initialize: Effect.Effect<unknown, E, R | PostgresTestServices | Scope.Scope> | PostgresTestLoader<E, R>;
|
|
18
18
|
readonly migrations?: never;
|
|
19
19
|
});
|
|
20
|
-
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>, Scope.Scope>, Scope.Scope>, Reactivity.Reactivity> | Exclude<Exclude<Exclude<Exclude<TFixtures, import("@effect/sql-pg/PgClient").PgClient | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient>, Scope.Scope>, Scope.Scope>, Reactivity.Reactivity>>;
|
|
20
|
+
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/Schema").SchemaError | import("effect/sql/SqlError").SqlError, Exclude<Exclude<Exclude<Exclude<R, import("@effect/sql-pg/PgClient").PgClient | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient>, Scope.Scope>, Scope.Scope>, Reactivity.Reactivity> | Exclude<Exclude<Exclude<Exclude<TFixtures, import("@effect/sql-pg/PgClient").PgClient | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient>, Scope.Scope>, Scope.Scope>, Reactivity.Reactivity>>;
|
|
21
21
|
export {};
|
|
22
22
|
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC3E,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAmB,KAAK,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAoC,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKjH,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,IAAI,CACtD,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAC1B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,oBAAoB,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;AAEvE,UAAU,yBAAyB,CAAC,CAAC,EAAE,SAAS,CAAE,SAAQ,iBAAiB;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,SAAS,GAAG,oBAAoB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACjI,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,mBAAmB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,IAAI,yBAAyB,CAAC,CAAC,EAAE,SAAS,CAAC,GACjH,CACG;IAAE,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,
|
|
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,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC3E,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAmB,KAAK,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAoC,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKjH,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,IAAI,CACtD,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAC1B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,oBAAoB,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;AAEvE,UAAU,yBAAyB,CAAC,CAAC,EAAE,SAAS,CAAE,SAAQ,iBAAiB;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,SAAS,GAAG,oBAAoB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACjI,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,mBAAmB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,IAAI,yBAAyB,CAAC,CAAC,EAAE,SAAS,CAAC,GACjH,CACG;IAAE,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACpF;IACA,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,oBAAoB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClH,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC;CAC3B,CACH,CAAC;AASH,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,6qBAmC3H"}
|
|
@@ -5,5 +5,6 @@ export declare function raceWithLock<A, E, R, TLockError, TLockServices>(options
|
|
|
5
5
|
readonly effects: readonly Effect.Effect<A, E, R>[];
|
|
6
6
|
readonly timeout?: Duration.Input;
|
|
7
7
|
readonly release?: "commit" | "rollback";
|
|
8
|
+
readonly count?: "contenders" | "every blocked session";
|
|
8
9
|
}): Effect.Effect<import("effect/Result").Result<A, E>[], TLockError | import("effect/sql/SqlError").SqlError | import("effect/Cause").TimeoutError, import("effect/reactivity/Reactivity").Reactivity | SqlClient.SqlClient | Exclude<R, import("effect/Scope").Scope> | Exclude<Exclude<TLockServices, import("effect/Scope").Scope>, import("effect/Scope").Scope>>;
|
|
9
10
|
//# sourceMappingURL=raceWithLock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raceWithLock.d.ts","sourceRoot":"","sources":["../../src/server/raceWithLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,EAAmB,MAAM,QAAQ,CAAC;AAC1E,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"raceWithLock.d.ts","sourceRoot":"","sources":["../../src/server/raceWithLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,EAAmB,MAAM,QAAQ,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AAUlD,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IACjE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,uBAAuB,CAAC;CACxD,sWAyCA"}
|
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
import { Deferred, Effect, Fiber, Schedule } from "effect";
|
|
2
|
-
import { SqlClient } from "effect/sql";
|
|
2
|
+
import { SqlClient, Statement } from "effect/sql";
|
|
3
3
|
import { transact } from "@shivaedev/sql/transact.ts";
|
|
4
4
|
import { withTestTransaction } from "#withTestTransaction.ts";
|
|
5
|
+
function tagged(effect, tag) {
|
|
6
|
+
return Effect.provideService(effect, Statement.CurrentTransformer, (statement, sql) => Effect.succeed(sql `${sql.literal(`/* ${tag} */`)} ${statement}`));
|
|
7
|
+
}
|
|
5
8
|
export function raceWithLock(options) {
|
|
9
|
+
const everyBlockedSession = options.count === "every blocked session";
|
|
6
10
|
return Effect.scoped(Effect.gen(function* () {
|
|
7
11
|
const sql = yield* SqlClient.SqlClient;
|
|
8
12
|
const ready = yield* Deferred.make();
|
|
9
13
|
const started = yield* Deferred.make();
|
|
10
14
|
const hold = Effect.gen(function* () {
|
|
11
15
|
yield* options.lock;
|
|
12
|
-
yield*
|
|
16
|
+
const [holder] = yield* sql `select pg_backend_pid() as pid`;
|
|
17
|
+
const race = `raceWithLock ${holder?.pid}.`;
|
|
18
|
+
yield* Deferred.succeed(ready, race);
|
|
13
19
|
yield* Deferred.await(started);
|
|
20
|
+
// PostgreSQL signals nothing when a session starts waiting on a lock, so the holder polls its blocker graph.
|
|
14
21
|
yield* sql `select pg_stat_clear_snapshot()`.pipe(Effect.andThen(sql `with recursive blocked(pid) as (
|
|
15
22
|
select pid from pg_stat_activity where pg_backend_pid() = any(pg_blocking_pids(pid))
|
|
16
23
|
union
|
|
17
24
|
select activity.pid from pg_stat_activity activity join blocked on blocked.pid = any(pg_blocking_pids(activity.pid))
|
|
18
|
-
) select count(*)
|
|
25
|
+
) select ${everyBlockedSession ? sql `count(*)` : sql `count(distinct split_part(activity.query, ' */', 1))`}::integer as waiting
|
|
26
|
+
from pg_stat_activity activity join blocked using (pid)
|
|
27
|
+
where ${everyBlockedSession ? sql `true` : sql `starts_with(activity.query, ${`/* ${race}`})`}`), Effect.repeat({ schedule: Schedule.spaced("10 millis"), while: ([row]) => (row?.waiting ?? 0) < options.effects.length }));
|
|
19
28
|
});
|
|
20
29
|
const holder = yield* (options.release === "commit" ? transact(Effect.scoped(hold), { onSqlError: (error) => error }) : withTestTransaction(hold)).pipe(Effect.forkScoped);
|
|
21
|
-
yield* Effect.raceFirst(Deferred.await(ready), Fiber.join(holder).pipe(Effect.andThen(Effect.never)));
|
|
22
|
-
const contenders = yield* Effect.forEach(options.effects, Effect.result
|
|
30
|
+
const race = yield* Effect.raceFirst(Deferred.await(ready), Fiber.join(holder).pipe(Effect.andThen(Effect.never)));
|
|
31
|
+
const contenders = yield* Effect.forEach(options.effects, (effect, index) => Effect.result(everyBlockedSession ? effect : tagged(effect, `${race}${index}`)), {
|
|
32
|
+
concurrency: "unbounded",
|
|
33
|
+
}).pipe(Effect.forkScoped);
|
|
23
34
|
yield* Deferred.succeed(started, undefined);
|
|
24
35
|
yield* Effect.raceFirst(Fiber.join(holder), Fiber.join(contenders).pipe(Effect.andThen(Effect.never)));
|
|
25
36
|
return yield* Fiber.join(contenders);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raceWithLock.js","sourceRoot":"","sources":["../../src/server/raceWithLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiB,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"raceWithLock.js","sourceRoot":"","sources":["../../src/server/raceWithLock.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/test-sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "PostgreSQL rollback and real-commit test isolation for Effect",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect"
|
|
@@ -31,8 +31,7 @@
|
|
|
31
31
|
"types": "./dist/*.d.ts",
|
|
32
32
|
"default": "./dist/*.js"
|
|
33
33
|
},
|
|
34
|
-
"./package.json": "./package.json"
|
|
35
|
-
"./server/internal/*": null
|
|
34
|
+
"./package.json": "./package.json"
|
|
36
35
|
},
|
|
37
36
|
"files": [
|
|
38
37
|
"dist",
|
|
@@ -44,14 +43,16 @@
|
|
|
44
43
|
"README.md"
|
|
45
44
|
],
|
|
46
45
|
"dependencies": {
|
|
47
|
-
"@shivaedev/sql": "0.
|
|
46
|
+
"@shivaedev/sql": "0.26.1"
|
|
48
47
|
},
|
|
49
48
|
"devDependencies": {
|
|
50
49
|
"@effect/sql-pg": "4.0.6",
|
|
51
50
|
"@effect/vitest": "4.0.6",
|
|
52
|
-
"@shivaedev/
|
|
53
|
-
"@shivaedev/
|
|
54
|
-
"@shivaedev/
|
|
51
|
+
"@shivaedev/jobs": "0.23.1",
|
|
52
|
+
"@shivaedev/quality": "0.47.0",
|
|
53
|
+
"@shivaedev/service": "0.6.0",
|
|
54
|
+
"@shivaedev/test": "0.11.0",
|
|
55
|
+
"@shivaedev/test-story": "0.25.1",
|
|
55
56
|
"@types/node": "24.19.2",
|
|
56
57
|
"effect": "4.0.6",
|
|
57
58
|
"pg-boss": "12.38.0",
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { hostname } from "node:os";
|
|
3
3
|
import process from "node:process";
|
|
4
|
+
import { Effect, Random } from "effect";
|
|
4
5
|
|
|
5
6
|
const host = createHash("sha256").update(hostname()).digest("hex").slice(0, 8);
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export const databaseId = Effect.map(Effect.replicateEffect(Random.nextIntBetween(0, 0xff_ff_ff_ff), 4), (parts) =>
|
|
9
|
+
parts.map((part) => part.toString(16).padStart(8, "0")).join(""),
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export const databaseName = Effect.map(databaseId, (id) => `effect_test_${host}_${process.pid}_${id}`);
|
|
10
13
|
|
|
11
14
|
export function abandonedDatabase(name: string) {
|
|
12
15
|
if (/^effect_test_[a-f0-9]{32}$/u.test(name)) {
|
|
@@ -35,7 +35,7 @@ export const database = Effect.fn("PostgresTest.database")(function* (
|
|
|
35
35
|
release: (name: string) => Effect.Effect<unknown>,
|
|
36
36
|
template = "template0",
|
|
37
37
|
) {
|
|
38
|
-
const name = databaseName
|
|
38
|
+
const name = yield* databaseName;
|
|
39
39
|
const target = new URL(Redacted.value(url));
|
|
40
40
|
target.pathname = `/${name}`;
|
|
41
41
|
target.searchParams.delete("database");
|
|
@@ -12,7 +12,7 @@ const outsideTransaction = Effect.fnUntraced(function* (sql: SqlClient.SqlClient
|
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
export const migrationSteps = Effect.fn("PostgresTest.migrationSteps")(function* <R>(migrations: PostgresMigrationOptions<R>) {
|
|
15
|
+
export const migrationSteps = Effect.fn("PostgresTest.migrationSteps")(function* <R, E = never>(migrations: PostgresMigrationOptions<R, E>) {
|
|
16
16
|
const sql = yield* SqlClient.SqlClient;
|
|
17
17
|
const context = yield* Effect.context<R | SqlClient.SqlClient>();
|
|
18
18
|
yield* sql.onDialectOrElse({ orElse: () => invalid("Migration steps require PostgreSQL."), pg: () => Effect.void });
|
|
@@ -7,13 +7,13 @@ export interface PostgresColumn {
|
|
|
7
7
|
readonly type: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface MigrationUpgradeOptions<R = never> {
|
|
11
|
-
readonly migrations: PostgresMigrationOptions<R>;
|
|
10
|
+
export interface MigrationUpgradeOptions<R = never, E = never> {
|
|
11
|
+
readonly migrations: PostgresMigrationOptions<R, E>;
|
|
12
12
|
readonly table: string;
|
|
13
13
|
readonly upTo: number;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const migrationUpgrade = Effect.fn("PostgresTest.migrationUpgrade")(function* <R>(options: MigrationUpgradeOptions<R>) {
|
|
16
|
+
export const migrationUpgrade = Effect.fn("PostgresTest.migrationUpgrade")(function* <R, E = never>(options: MigrationUpgradeOptions<R, E>) {
|
|
17
17
|
const sql = yield* SqlClient.SqlClient;
|
|
18
18
|
function invalid(message: string) {
|
|
19
19
|
return Effect.fail(new Migrator.MigrationError({ kind: "BadState", message }));
|
package/src/server/postgres.ts
CHANGED
|
@@ -20,7 +20,7 @@ interface PostgresTestCommonOptions<E, TFixtures> extends SqlNameTransforms {
|
|
|
20
20
|
|
|
21
21
|
export type PostgresTestOptions<E = never, R = never, TFixtures = never> = PostgresTestCommonOptions<E, TFixtures> &
|
|
22
22
|
(
|
|
23
|
-
| { readonly migrations: PostgresMigrationOptions<R>; readonly initialize?: never }
|
|
23
|
+
| { readonly migrations: PostgresMigrationOptions<R, E>; readonly initialize?: never }
|
|
24
24
|
| {
|
|
25
25
|
readonly initialize: Effect.Effect<unknown, E, R | PostgresTestServices | Scope.Scope> | PostgresTestLoader<E, R>;
|
|
26
26
|
readonly migrations?: never;
|
|
@@ -1,37 +1,56 @@
|
|
|
1
1
|
import { Deferred, type Duration, Effect, Fiber, Schedule } from "effect";
|
|
2
|
-
import { SqlClient } from "effect/sql";
|
|
2
|
+
import { SqlClient, Statement } from "effect/sql";
|
|
3
3
|
import { transact } from "@shivaedev/sql/transact.ts";
|
|
4
4
|
import { withTestTransaction } from "#withTestTransaction.ts";
|
|
5
5
|
|
|
6
|
+
function tagged<A, E, R>(effect: Effect.Effect<A, E, R>, tag: string) {
|
|
7
|
+
return Effect.provideService(effect, Statement.CurrentTransformer, (statement, sql) =>
|
|
8
|
+
Effect.succeed(sql`${sql.literal(`/* ${tag} */`)} ${statement}`),
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export function raceWithLock<A, E, R, TLockError, TLockServices>(options: {
|
|
7
13
|
readonly lock: Effect.Effect<unknown, TLockError, TLockServices>;
|
|
8
14
|
readonly effects: readonly Effect.Effect<A, E, R>[];
|
|
9
15
|
readonly timeout?: Duration.Input;
|
|
10
16
|
readonly release?: "commit" | "rollback";
|
|
17
|
+
readonly count?: "contenders" | "every blocked session";
|
|
11
18
|
}) {
|
|
19
|
+
const everyBlockedSession = options.count === "every blocked session";
|
|
12
20
|
return Effect.scoped(
|
|
13
21
|
Effect.gen(function* () {
|
|
14
22
|
const sql = yield* SqlClient.SqlClient;
|
|
15
|
-
const ready = yield* Deferred.make<
|
|
23
|
+
const ready = yield* Deferred.make<string>();
|
|
16
24
|
const started = yield* Deferred.make<void>();
|
|
17
25
|
const hold = Effect.gen(function* () {
|
|
18
26
|
yield* options.lock;
|
|
19
|
-
yield*
|
|
27
|
+
const [holder] = yield* sql<{ pid: number }>`select pg_backend_pid() as pid`;
|
|
28
|
+
const race = `raceWithLock ${holder?.pid}.`;
|
|
29
|
+
yield* Deferred.succeed(ready, race);
|
|
20
30
|
yield* Deferred.await(started);
|
|
31
|
+
// PostgreSQL signals nothing when a session starts waiting on a lock, so the holder polls its blocker graph.
|
|
21
32
|
yield* sql`select pg_stat_clear_snapshot()`.pipe(
|
|
22
33
|
Effect.andThen(sql<{ waiting: number }>`with recursive blocked(pid) as (
|
|
23
34
|
select pid from pg_stat_activity where pg_backend_pid() = any(pg_blocking_pids(pid))
|
|
24
35
|
union
|
|
25
36
|
select activity.pid from pg_stat_activity activity join blocked on blocked.pid = any(pg_blocking_pids(activity.pid))
|
|
26
|
-
) select count(*)::integer as waiting
|
|
27
|
-
|
|
37
|
+
) select ${everyBlockedSession ? sql`count(*)` : sql`count(distinct split_part(activity.query, ' */', 1))`}::integer as waiting
|
|
38
|
+
from pg_stat_activity activity join blocked using (pid)
|
|
39
|
+
where ${everyBlockedSession ? sql`true` : sql`starts_with(activity.query, ${`/* ${race}`})`}`),
|
|
40
|
+
Effect.repeat({ schedule: Schedule.spaced("10 millis"), while: ([row]) => (row?.waiting ?? 0) < options.effects.length }),
|
|
28
41
|
);
|
|
29
42
|
});
|
|
30
43
|
const holder = yield* (
|
|
31
44
|
options.release === "commit" ? transact(Effect.scoped(hold), { onSqlError: (error) => error }) : withTestTransaction(hold)
|
|
32
45
|
).pipe(Effect.forkScoped);
|
|
33
|
-
yield* Effect.raceFirst(Deferred.await(ready), Fiber.join(holder).pipe(Effect.andThen(Effect.never)));
|
|
34
|
-
const contenders = yield* Effect.forEach(
|
|
46
|
+
const race = yield* Effect.raceFirst(Deferred.await(ready), Fiber.join(holder).pipe(Effect.andThen(Effect.never)));
|
|
47
|
+
const contenders = yield* Effect.forEach(
|
|
48
|
+
options.effects,
|
|
49
|
+
(effect, index) => Effect.result(everyBlockedSession ? effect : tagged(effect, `${race}${index}`)),
|
|
50
|
+
{
|
|
51
|
+
concurrency: "unbounded",
|
|
52
|
+
},
|
|
53
|
+
).pipe(Effect.forkScoped);
|
|
35
54
|
yield* Deferred.succeed(started, undefined);
|
|
36
55
|
yield* Effect.raceFirst(Fiber.join(holder), Fiber.join(contenders).pipe(Effect.andThen(Effect.never)));
|
|
37
56
|
return yield* Fiber.join(contenders);
|