@shivaedev/sql 0.40.0 → 0.41.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 +10 -0
- package/README.md +88 -0
- package/dist/{testing/WorkerRelease.d.ts → WorkerReleaseClock.d.ts} +3 -3
- package/dist/WorkerReleaseClock.d.ts.map +1 -0
- package/dist/WorkerReleaseClock.js +4 -0
- package/dist/WorkerReleaseClock.js.map +1 -0
- package/dist/coordinateWorkerRelease.js +2 -2
- package/dist/coordinateWorkerRelease.js.map +1 -1
- package/dist/defineRepository.d.ts +8 -0
- package/dist/defineRepository.d.ts.map +1 -0
- package/dist/defineRepository.js +6 -0
- package/dist/defineRepository.js.map +1 -0
- package/dist/releaseWorkers.js +2 -2
- package/dist/releaseWorkers.js.map +1 -1
- package/package.json +7 -7
- package/src/{testing/WorkerRelease.ts → WorkerReleaseClock.ts} +3 -3
- package/src/coordinateWorkerRelease.ts +2 -2
- package/src/defineRepository.ts +9 -0
- package/src/releaseWorkers.ts +2 -2
- package/dist/testing/WorkerRelease.d.ts.map +0 -1
- package/dist/testing/WorkerRelease.js +0 -4
- package/dist/testing/WorkerRelease.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.41.0 - 2026-11-05
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `defineRepository` exposes a repository and its domain operations through one native Effect service and Layer, shared by services that declare it in `requires`. Initialization retains its typed errors, dependencies and Layer-owned scope; repository operations retain caller transactions.
|
|
8
|
+
|
|
9
|
+
### Breaking
|
|
10
|
+
|
|
11
|
+
- The worker scheduling port is `WorkerReleaseClock` from `@shivaedev/sql/WorkerReleaseClock.ts`. Replace imports and uses of `WorkerReleaseTesting`; use `hostTime` from test-kits for controlled story time.
|
|
12
|
+
|
|
3
13
|
## 0.40.0 - 2026-11-04
|
|
4
14
|
|
|
5
15
|
### Added
|
package/README.md
CHANGED
|
@@ -189,6 +189,93 @@ class Receipt extends Model.Class<Receipt>("Receipt")({
|
|
|
189
189
|
|
|
190
190
|
`jsonb` uses native `PgTypes.jsonb` parameters. The supplied schema encodes nested values for storage and decodes PostgreSQL's returned object through the repository, including projections. Here `amount` is a number in application code and a string inside the stored JSON. Invalid input or stored data fails with `SchemaError`. Use `jsonb(Schema.NullOr(Details))` for a nullable column: a null input binds SQL `NULL`. The application still owns the column's DDL.
|
|
191
191
|
|
|
192
|
+
### Share a table's repository and domain reads between services
|
|
193
|
+
|
|
194
|
+
Use `defineRepository` from `@shivaedev/sql/defineRepository.ts` to give the table's repository and its domain operations one native Effect service and Layer. Its initializer returns the whole public shape: values, repositories and functions are all allowed. Services declare that repository tag in `requires`, then read it from the environment. Keep repository construction out of each service's initializer.
|
|
195
|
+
|
|
196
|
+
For a pot with `id`, `amount` and `pending` integer fields, its repository module can own loading and replaying pending portions:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { Effect } from "effect";
|
|
200
|
+
import { defineRepository } from "@shivaedev/sql/defineRepository.ts";
|
|
201
|
+
import { makeRepository } from "@shivaedev/sql/repository.ts";
|
|
202
|
+
import { Pot } from "#pots/Pot.ts";
|
|
203
|
+
|
|
204
|
+
const initializePots = Effect.gen(function* () {
|
|
205
|
+
const rows = yield* makeRepository(Pot, {
|
|
206
|
+
idColumn: "id",
|
|
207
|
+
spanPrefix: "Pots",
|
|
208
|
+
tableName: "pots",
|
|
209
|
+
});
|
|
210
|
+
const load = Effect.fn("Pots.load")((id: number) => rows.findById(id));
|
|
211
|
+
const settle = Effect.fn("Pots.settle")(function* (id: number) {
|
|
212
|
+
const pot = yield* load(id);
|
|
213
|
+
return yield* rows.update({ ...pot, amount: pot.amount + pot.pending, pending: 0 });
|
|
214
|
+
});
|
|
215
|
+
return { rows, load, settle };
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
export const Pots = defineRepository({ id: "app/Pots", initialize: initializePots });
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`Pots.layer` requires the initializer's services, including `SqlClient`. Its initialization errors stay in the Layer's error type, and resources acquired by initialization belong to the Layer's scope. The returned operations keep their own types and caller requirements; `defineRepository` does not bind their dependencies. Here `load` and `settle` close over `rows`, which captures the native SQL client.
|
|
222
|
+
|
|
223
|
+
Put service operations in their operation modules, reading the shared tag:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { Effect } from "effect";
|
|
227
|
+
import { Pots } from "#pots/Pots.ts";
|
|
228
|
+
|
|
229
|
+
export const loadPot = Effect.fn("Plates.loadPot")(function* (id: number) {
|
|
230
|
+
return yield* (yield* Pots).load(id);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
export const settlePot = Effect.fn("PotLifecycle.settlePot")(function* (id: number) {
|
|
234
|
+
return yield* (yield* Pots).settle(id);
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Keep each operation in its own module. The two service assemblies import those operations:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { Effect, Layer } from "effect";
|
|
242
|
+
import { defineService } from "@shivaedev/service/defineService.ts";
|
|
243
|
+
import { loadPot } from "#pots/loadPot.ts";
|
|
244
|
+
import { Pots } from "#pots/Pots.ts";
|
|
245
|
+
import { settlePot } from "#pots/settlePot.ts";
|
|
246
|
+
|
|
247
|
+
const Plates = defineService({
|
|
248
|
+
id: "app/Plates",
|
|
249
|
+
requires: [Pots],
|
|
250
|
+
initialize: Effect.void,
|
|
251
|
+
methods: () => ({ loadPot }),
|
|
252
|
+
});
|
|
253
|
+
const PotLifecycle = defineService({
|
|
254
|
+
id: "app/PotLifecycle",
|
|
255
|
+
requires: [Pots],
|
|
256
|
+
initialize: Effect.void,
|
|
257
|
+
methods: () => ({ settlePot }),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const features = Layer.merge(Plates.layer, PotLifecycle.layer).pipe(Layer.provide(Pots.layer));
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Provide the application's PostgreSQL Layer to `features` once. Both services receive the same repository instance within that Layer build. Reuse the same `Pots.layer` value so native Layer memoization shares construction; `Layer.fresh` and separate builds intentionally create separate lifetimes. The repository does not open another pool or a transaction. Wrap work spanning both services in `transact`; repository reads and writes keep the caller's transaction and savepoints, and a failure rolls back the work across both services. The application chooses concurrency and locking for a read followed by an update. Closing the Layer scope releases its repository initialization resources.
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { transact } from "@shivaedev/sql/transact.ts";
|
|
267
|
+
|
|
268
|
+
const application = features.pipe(Layer.provideMerge(database));
|
|
269
|
+
const settleAndLoad = Effect.gen(function* () {
|
|
270
|
+
const lifecycle = yield* PotLifecycle;
|
|
271
|
+
const plates = yield* Plates;
|
|
272
|
+
yield* lifecycle.settlePot(1);
|
|
273
|
+
return yield* plates.loadPot(1);
|
|
274
|
+
}).pipe(transact({ onSqlError: (error) => error }), Effect.provide(application));
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
`database` is the application's `postgresLayer`. `Layer.provideMerge` also keeps its SQL and Reactivity services available to the outer `transact`.
|
|
278
|
+
|
|
192
279
|
### 2. Per feature: write and query through the model
|
|
193
280
|
|
|
194
281
|
```ts
|
|
@@ -917,6 +1004,7 @@ Import the module that defines the name; there is no root entry.
|
|
|
917
1004
|
- `@shivaedev/sql/int8.ts`: `int8(field)` — PostgreSQL bigint storage codec using the supplied field schema.
|
|
918
1005
|
- `@shivaedev/sql/int4Array.ts`: `int4Array(field)` — PostgreSQL integer-array storage codec, including typed empty arrays.
|
|
919
1006
|
- `@shivaedev/sql/compositeRecordKey.ts`: `compositeRecordKey(model, { tableName, idColumn }, value)` — Encodes decoded composite key fields into the published record key.
|
|
1007
|
+
- `@shivaedev/sql/defineRepository.ts`: `defineRepository({ id, initialize })` — Native Context service and `.layer` for a shared repository shape; the initializer's dependencies, errors and scoped resources belong to its Layer.
|
|
920
1008
|
- `@shivaedev/sql/repository.ts`: `makeRepository(model, options)` — `tableName`, scalar or composite `idColumn`, `spanPrefix`, optional `versionColumn`, `conflictColumns` and `conflictWhere`, and `collection` required for bucket models; requires native `SqlClient`.
|
|
921
1009
|
- `@shivaedev/sql/repository.ts`: `OptimisticConcurrencyError` — Typed stale or missing-row failure for versioned writes, with `tableName`, `id`, `expectedVersion`, `reason: "missing" | "stale"`.
|
|
922
1010
|
- `@shivaedev/sql/tupleIn.ts`: `tupleIn(model, fields, tuples, types)` — Filter entry matching two or more fields together against a list of tuples, for `where` in reads and unversioned deletes.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { type Clock, Context, type Effect, type Schema, type Scope } from "effect";
|
|
2
2
|
import type { SqlError } from "effect/sql/SqlError";
|
|
3
|
-
declare const
|
|
3
|
+
declare const WorkerReleaseClock_base: Context.ServiceClass<WorkerReleaseClock, "@shivaedev/sql/WorkerReleaseClock", {
|
|
4
4
|
readonly clock: Clock.Clock;
|
|
5
5
|
readonly register: (tick: {
|
|
6
6
|
readonly heartbeat: Effect.Effect<void, SqlError | Schema.SchemaError>;
|
|
7
7
|
readonly poll: Effect.Effect<void, SqlError | Schema.SchemaError>;
|
|
8
8
|
}) => Effect.Effect<void, never, Scope.Scope>;
|
|
9
9
|
}>;
|
|
10
|
-
export declare class
|
|
10
|
+
export declare class WorkerReleaseClock extends WorkerReleaseClock_base {
|
|
11
11
|
}
|
|
12
12
|
export {};
|
|
13
|
-
//# sourceMappingURL=
|
|
13
|
+
//# sourceMappingURL=WorkerReleaseClock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkerReleaseClock.d.ts","sourceRoot":"","sources":["../src/WorkerReleaseClock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACnF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;;oBAKlC,KAAK,CAAC,KAAK;uBACR,CAAC,IAAI,EAAE;QACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;KAClE,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;;AAP/C,qBAAa,kBAAmB,SAAQ,uBASA;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkerReleaseClock.js","sourceRoot":"","sources":["../src/WorkerReleaseClock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAwC,MAAM,QAAQ,CAAC;AAGnF,MAAM,OAAO,kBAAmB,SAAQ,OAAO,CAAC,OAAO,EASpD,CAAC,mCAAmC,CAAC;CAAG"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Duration, Effect, Exit, Option, Predicate, Schedule, Scope } from "effect";
|
|
2
2
|
import { isSqlError } from "effect/sql/SqlError";
|
|
3
|
-
import {
|
|
3
|
+
import { WorkerReleaseClock } from "#WorkerReleaseClock.ts";
|
|
4
4
|
import { makeWorkerRelease } from "./makeWorkerRelease.js";
|
|
5
5
|
import { readPostgresRelease } from "./postgresRelease.js";
|
|
6
6
|
import { releaseWorkers } from "./releaseWorkers.js";
|
|
@@ -42,7 +42,7 @@ export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRele
|
|
|
42
42
|
yield* loop("heartbeat", rows.heartbeat);
|
|
43
43
|
yield* tick("poll", poll).pipe(Scope.provide(scope));
|
|
44
44
|
yield* loop("poll", poll);
|
|
45
|
-
const testing = yield* Effect.serviceOption(
|
|
45
|
+
const testing = yield* Effect.serviceOption(WorkerReleaseClock);
|
|
46
46
|
if (Option.isSome(testing)) {
|
|
47
47
|
const context = yield* Effect.context();
|
|
48
48
|
yield* testing.value.register({ heartbeat: rows.heartbeat, poll: poll.pipe(Effect.provideContext(context)) }).pipe(Scope.provide(scope));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordinateWorkerRelease.js","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"coordinateWorkerRelease.js","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Context, type Effect, Layer } from "effect";
|
|
2
|
+
export declare function defineRepository<const TIdentifier extends string, TShape, TError, TRequirements>(definition: {
|
|
3
|
+
readonly id: TIdentifier;
|
|
4
|
+
readonly initialize: Effect.Effect<TShape, TError, TRequirements>;
|
|
5
|
+
}): Context.Service<TIdentifier, TShape> & {
|
|
6
|
+
layer: Layer.Layer<TIdentifier, TError, Exclude<TRequirements, import("effect/Scope").Scope>>;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=defineRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineRepository.d.ts","sourceRoot":"","sources":["../src/defineRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAErD,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,WAAW,SAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE;IAC7G,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;CAClE;;EAGA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Context, Layer } from "effect";
|
|
2
|
+
export function defineRepository(definition) {
|
|
3
|
+
const repository = Context.Service(definition.id);
|
|
4
|
+
return Object.assign(repository, { layer: Layer.effect(repository)(definition.initialize) });
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=defineRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineRepository.js","sourceRoot":"","sources":["../src/defineRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,KAAK,EAAE,MAAM,QAAQ,CAAC;AAErD,MAAM,UAAU,gBAAgB,CAAkE,UAGjG;IACA,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAsB,UAAU,CAAC,EAAE,CAAC,CAAC;IACvE,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;AAC9F,CAAC"}
|
package/dist/releaseWorkers.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Clock, Effect, Option, Random, Schema } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/sql";
|
|
3
|
-
import {
|
|
3
|
+
import { WorkerReleaseClock } from "#WorkerReleaseClock.ts";
|
|
4
4
|
export const releaseWorkers = Effect.fn("EffectSql.releaseWorkers")(function* (release, staleMillis, table = "effect_sql_migrations") {
|
|
5
5
|
const sql = yield* SqlClient.SqlClient;
|
|
6
6
|
const processId = `${yield* Random.nextInt}:${yield* Random.nextInt}`;
|
|
7
7
|
const workers = `${table}_workers`;
|
|
8
|
-
const testing = yield* Effect.serviceOption(
|
|
8
|
+
const testing = yield* Effect.serviceOption(WorkerReleaseClock);
|
|
9
9
|
const now = Option.isSome(testing)
|
|
10
10
|
? Clock.currentTimeMillis.pipe(Effect.provideService(Clock.Clock, testing.value.clock), Effect.map((millis) => sql `${new Date(millis).toISOString()}::timestamptz`))
|
|
11
11
|
: Effect.succeed(sql `clock_timestamp()`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseWorkers.js","sourceRoot":"","sources":["../src/releaseWorkers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"releaseWorkers.js","sourceRoot":"","sources":["../src/releaseWorkers.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "Schema-derived repositories over native Effect SQL",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect"
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"@effect/platform-node": "4.0.7",
|
|
51
51
|
"@effect/sql-pg": "4.0.7",
|
|
52
52
|
"@effect/sql-sqlite-node": "4.0.7",
|
|
53
|
-
"@shivaedev/contract": "0.
|
|
54
|
-
"@shivaedev/jobs": "0.37.
|
|
55
|
-
"@shivaedev/quality": "0.
|
|
56
|
-
"@shivaedev/test-kits": "0.
|
|
57
|
-
"@shivaedev/test-sql": "0.
|
|
58
|
-
"@shivaedev/test-story": "0.
|
|
53
|
+
"@shivaedev/contract": "0.37.0",
|
|
54
|
+
"@shivaedev/jobs": "0.37.1",
|
|
55
|
+
"@shivaedev/quality": "0.63.0",
|
|
56
|
+
"@shivaedev/test-kits": "0.6.0",
|
|
57
|
+
"@shivaedev/test-sql": "0.22.0",
|
|
58
|
+
"@shivaedev/test-story": "0.40.0",
|
|
59
59
|
"@types/node": "24.19.2",
|
|
60
60
|
"effect": "4.0.7",
|
|
61
61
|
"typescript": "7.0.2",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Clock, Context, type Effect, type Schema, type Scope } from "effect";
|
|
2
2
|
import type { SqlError } from "effect/sql/SqlError";
|
|
3
3
|
|
|
4
|
-
export class
|
|
5
|
-
|
|
4
|
+
export class WorkerReleaseClock extends Context.Service<
|
|
5
|
+
WorkerReleaseClock,
|
|
6
6
|
{
|
|
7
7
|
readonly clock: Clock.Clock;
|
|
8
8
|
readonly register: (tick: {
|
|
@@ -10,4 +10,4 @@ export class WorkerReleaseTesting extends Context.Service<
|
|
|
10
10
|
readonly poll: Effect.Effect<void, SqlError | Schema.SchemaError>;
|
|
11
11
|
}) => Effect.Effect<void, never, Scope.Scope>;
|
|
12
12
|
}
|
|
13
|
-
>()("@shivaedev/sql/
|
|
13
|
+
>()("@shivaedev/sql/WorkerReleaseClock") {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Duration, Effect, Exit, Option, Predicate, Schedule, Scope } from "effect";
|
|
2
2
|
import { isSqlError } from "effect/sql/SqlError";
|
|
3
|
-
import {
|
|
3
|
+
import { WorkerReleaseClock } from "#WorkerReleaseClock.ts";
|
|
4
4
|
import { makeWorkerRelease } from "./makeWorkerRelease.ts";
|
|
5
5
|
import { readPostgresRelease } from "./postgresRelease.ts";
|
|
6
6
|
import { releaseWorkers } from "./releaseWorkers.ts";
|
|
@@ -66,7 +66,7 @@ export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRele
|
|
|
66
66
|
yield* loop("heartbeat", rows.heartbeat);
|
|
67
67
|
yield* tick("poll", poll).pipe(Scope.provide(scope));
|
|
68
68
|
yield* loop("poll", poll);
|
|
69
|
-
const testing = yield* Effect.serviceOption(
|
|
69
|
+
const testing = yield* Effect.serviceOption(WorkerReleaseClock);
|
|
70
70
|
if (Option.isSome(testing)) {
|
|
71
71
|
const context = yield* Effect.context<Effect.Services<typeof poll>>();
|
|
72
72
|
yield* testing.value.register({ heartbeat: rows.heartbeat, poll: poll.pipe(Effect.provideContext(context)) }).pipe(Scope.provide(scope));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Context, type Effect, Layer } from "effect";
|
|
2
|
+
|
|
3
|
+
export function defineRepository<const TIdentifier extends string, TShape, TError, TRequirements>(definition: {
|
|
4
|
+
readonly id: TIdentifier;
|
|
5
|
+
readonly initialize: Effect.Effect<TShape, TError, TRequirements>;
|
|
6
|
+
}) {
|
|
7
|
+
const repository = Context.Service<TIdentifier, TShape>(definition.id);
|
|
8
|
+
return Object.assign(repository, { layer: Layer.effect(repository)(definition.initialize) });
|
|
9
|
+
}
|
package/src/releaseWorkers.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Clock, Effect, Option, Random, Schema } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/sql";
|
|
3
|
-
import {
|
|
3
|
+
import { WorkerReleaseClock } from "#WorkerReleaseClock.ts";
|
|
4
4
|
|
|
5
5
|
export const releaseWorkers = Effect.fn("EffectSql.releaseWorkers")(function* (
|
|
6
6
|
release: string,
|
|
@@ -10,7 +10,7 @@ export const releaseWorkers = Effect.fn("EffectSql.releaseWorkers")(function* (
|
|
|
10
10
|
const sql = yield* SqlClient.SqlClient;
|
|
11
11
|
const processId = `${yield* Random.nextInt}:${yield* Random.nextInt}`;
|
|
12
12
|
const workers = `${table}_workers`;
|
|
13
|
-
const testing = yield* Effect.serviceOption(
|
|
13
|
+
const testing = yield* Effect.serviceOption(WorkerReleaseClock);
|
|
14
14
|
const now = Option.isSome(testing)
|
|
15
15
|
? Clock.currentTimeMillis.pipe(
|
|
16
16
|
Effect.provideService(Clock.Clock, testing.value.clock),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerRelease.d.ts","sourceRoot":"","sources":["../../src/testing/WorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACnF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;;oBAKlC,KAAK,CAAC,KAAK;uBACR,CAAC,IAAI,EAAE;QACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;KAClE,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;;AAP/C,qBAAa,oBAAqB,SAAQ,yBASQ;CAAG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerRelease.js","sourceRoot":"","sources":["../../src/testing/WorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAwC,MAAM,QAAQ,CAAC;AAGnF,MAAM,OAAO,oBAAqB,SAAQ,OAAO,CAAC,OAAO,EAStD,CAAC,6CAA6C,CAAC;CAAG"}
|