@shivaedev/sql 0.30.0 → 0.32.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +30 -5
  3. package/dist/applyLowMemoryPostgres.d.ts +7 -0
  4. package/dist/applyLowMemoryPostgres.d.ts.map +1 -0
  5. package/dist/applyLowMemoryPostgres.js +24 -0
  6. package/dist/applyLowMemoryPostgres.js.map +1 -0
  7. package/dist/coordinateWorkerRelease.d.ts.map +1 -1
  8. package/dist/coordinateWorkerRelease.js +10 -3
  9. package/dist/coordinateWorkerRelease.js.map +1 -1
  10. package/dist/internal/MigrationStartedAt.d.ts +3 -0
  11. package/dist/internal/MigrationStartedAt.d.ts.map +1 -0
  12. package/dist/internal/MigrationStartedAt.js +5 -0
  13. package/dist/internal/MigrationStartedAt.js.map +1 -0
  14. package/dist/internal/migrationLock.d.ts +4 -0
  15. package/dist/internal/migrationLock.d.ts.map +1 -0
  16. package/dist/internal/migrationLock.js +17 -0
  17. package/dist/internal/migrationLock.js.map +1 -0
  18. package/dist/migrations.d.ts +1 -1
  19. package/dist/migrations.d.ts.map +1 -1
  20. package/dist/migrations.js +17 -6
  21. package/dist/migrations.js.map +1 -1
  22. package/dist/postgresRelease.d.ts +1 -1
  23. package/dist/postgresRelease.d.ts.map +1 -1
  24. package/dist/postgresRelease.js +7 -2
  25. package/dist/postgresRelease.js.map +1 -1
  26. package/dist/repositoryCollection.d.ts +1 -0
  27. package/dist/repositoryCollection.d.ts.map +1 -1
  28. package/dist/repositoryCollection.js +19 -6
  29. package/dist/repositoryCollection.js.map +1 -1
  30. package/dist/repositoryFilter.d.ts.map +1 -1
  31. package/dist/repositoryFilter.js +9 -2
  32. package/dist/repositoryFilter.js.map +1 -1
  33. package/dist/transact.d.ts.map +1 -1
  34. package/dist/transact.js +4 -1
  35. package/dist/transact.js.map +1 -1
  36. package/package.json +7 -6
  37. package/src/applyLowMemoryPostgres.ts +28 -0
  38. package/src/coordinateWorkerRelease.ts +13 -3
  39. package/src/internal/MigrationStartedAt.ts +5 -0
  40. package/src/internal/migrationLock.ts +20 -0
  41. package/src/migrations.ts +20 -6
  42. package/src/postgresRelease.ts +9 -2
  43. package/src/repositoryCollection.ts +20 -6
  44. package/src/repositoryFilter.ts +11 -2
  45. package/src/transact.ts +6 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.32.0 - 2026-11-02
4
+
5
+ ### Added
6
+
7
+ - `@shivaedev/changes/keys.ts` exports `isBucketSchema` to check whether a schema decodes to string or number keys, including nullable and optional model fields. `declaredBuckets` includes this check as `supported`.
8
+
9
+ ### Fixed
10
+
11
+ - Exceptions in change observers are logged without stopping sink delivery or changing transaction outcomes, including SQL change observations.
12
+ - Match SQL NULL for null equality filters on JSONB fields in reads, counts and deletes. Values accepted by the column schema compare through its codec before filter operators are considered, including JSON objects with `gt` or `in` keys.
13
+ - Fail the scope coordinating a worker release with the original cause when heartbeat or ownership polling retries are exhausted, and stop registered jobs workers before removing the release lease. Application-host workers can no longer keep fetching after their release coordinator fails.
14
+ - Publish a release only after every component succeeds, and reject marker writes from invocations older than the recorded one. `recordedAt` identifies the invocation's PostgreSQL start time; a new invocation can still deploy an earlier release label.
15
+ - Allow interrupted transactions to stop waiting for a pooled connection while preserving announcements for commits that land during interruption.
16
+
17
+ ### Breaking
18
+
19
+ - Transactions inside `batch` now publish at their outermost transaction's commit, honoring the scoped `CommittedSink`, instead of waiting for the batch to end. Use an enclosing transaction when writes and their changes must commit together, or coalesce in the sink when independent transactions need grouped delivery. Nontransactional batch changes still wait for the batch to end, and rolled-back transactions publish nothing.
20
+ - SQL repository registration rejects annotated bucket fields whose decoded schemas cannot be represented by change keys, with `BucketRegistrationError.invalidFields` naming the rejected fields. Use string or number schemas, optionally nullable or optional, for bucket values. Codecs such as `Schema.NumberFromString` remain supported. Replace opaque declarations with an explicit string or number schema and refinements. When constructing `BucketRegistrationError` directly, supply `invalidFields` (an empty array for field-name mismatches).
21
+ - Migration runners with schema components or a release now hold a session advisory lock through components and release publication. Allocate at least two pool connections for an active runner plus capacity for waiting runners and other work, and migrate transaction-pooled connections to direct connections or session pooling. Components continue to run outside the ledger transaction. Runs with only numbered migrations retain their transaction lock and one-connection pool support.
22
+ - Direct callers of `postgresRelease(...).apply` must handle `SchemaError` alongside `SqlError` because the component now decodes its PostgreSQL clock row.
23
+
24
+ ## 0.31.0 - 2026-11-01
25
+
26
+ ### Added
27
+
28
+ - Apply an opt-in low-memory PostgreSQL preset with an explicit per-app point-in-time recovery choice.
29
+ - Trim PostgreSQL's clean filesystem cache without privileges through the server's Effect process boundary.
30
+
3
31
  ## 0.30.0 - 2026-11-01
4
32
 
5
33
  ### Added
package/README.md CHANGED
@@ -29,6 +29,29 @@ Migrations are ordinary Effects loaded by native Migrator. `migratePostgres` add
29
29
 
30
30
  The work has three parts: describe the model and provide its database once, choose repository operations per feature, and put each changed write inside the transaction that owns its commit.
31
31
 
32
+ ### Low-memory PostgreSQL hosts
33
+
34
+ `applyLowMemoryPostgres({ pointInTimeRecovery })` from `@shivaedev/sql/applyLowMemoryPostgres.ts` is an opt-in database-owner operation for small applications on Linux hosts that bill cgroup memory, including filesystem page cache. It uses the provided native `SqlClient` to write `ALTER SYSTEM` settings and request a reload. Run it once, outside a transaction, against the app's dedicated PostgreSQL instance with a role allowed to change these settings. It changes the whole instance, including every database on it. Keep it out of normal application startup and numbered migrations.
35
+
36
+ ```ts
37
+ import { Config, Effect } from "effect";
38
+ import { applyLowMemoryPostgres } from "@shivaedev/sql/applyLowMemoryPostgres.ts";
39
+ import { postgresLayer } from "@shivaedev/sql/postgresLayer.ts";
40
+
41
+ const configure = Effect.gen(function* () {
42
+ const url = yield* Config.Redacted("DATABASE_URL");
43
+ yield* applyLowMemoryPostgres({ pointInTimeRecovery: false }).pipe(Effect.provide(postgresLayer(url)));
44
+ }).pipe(Effect.scoped);
45
+ ```
46
+
47
+ Restart PostgreSQL after this operation. `shared_buffers=32MB`, `max_connections=50` and `wal_buffers=4MB` take effect on restart. The reload settings are `jit=off`, `max_parallel_workers_per_gather=0`, `hash_mem_multiplier=1`, `autovacuum_max_workers=2`, `autovacuum_work_mem=32MB`, `idle_in_transaction_session_timeout=10min` and `wal_compression=zstd`. `idle_session_timeout=0` keeps idle LISTEN connections alive. Use PostgreSQL 18 with zstd support; older versions can require a restart for additional settings. Command-line `-c` settings override `ALTER SYSTEM`, so remove conflicting overrides. A failed operation can leave earlier settings written; correct the reported SQL error before restarting.
48
+
49
+ Point-in-time recovery is an explicit per-app memory and storage choice. With `pointInTimeRecovery: false`, the preset disables WAL archiving with `archive_mode=off`; it leaves `archive_timeout` alone and needs no backup bucket or pgBackRest configuration. Remove the host's archive and backup jobs and bucket configuration as well. This choice gives up recovery to a time between backups. With `true`, retain the host's working WAL archiving, backup bucket and restore procedure; the preset sets `archive_timeout=300` seconds. It does not provision backups or enable archiving. A timeout of 60 seconds can force a 16 MB WAL segment each minute even when the app is idle.
50
+
51
+ For PITR hosts, pgBackRest derives its process count from the CPU limit. Set a CPU limit of 2 or explicitly set `PGBACKREST_BACKUP_PROCESS_MAX=1` on the PostgreSQL service. Eight processes under a 32-vCPU limit exhausted a 477 MiB container in the reported Railway workload. Declare both CPU and memory limits in infrastructure as code: an omitted limit can be reset by the next plan. Keep enough headroom for backups, maintenance and the app's total connection budget across replicas and workers.
52
+
53
+ Pair this preset with server's [cache trim and connection lifetime](https://github.com/ShivaeDev/platform/tree/main/packages/server#low-memory-postgresql-hosts). Railway measurements supplied with this preset found billing within 0.2% of `memory.current`, shared memory around 45 MB instead of 175 MB, and small-app idle usage around 150–250 MB instead of 0.95 GB with preset, trim and connection recycling. Peaks returned within 5–10 minutes. These are workload observations, not memory limits or a promise for another app; measure your own cgroup before selecting a memory limit.
54
+
32
55
  ### One PostgreSQL pool per application
33
56
 
34
57
  `postgresLayer(url, options)` from `@shivaedev/sql/postgresLayer.ts` provides the native `PgPool` service from `@effect/sql-pg/PgPool`, `PgClient` and `SqlClient` together. `options` accepts `applicationName`, `maxConnections`, `minConnections`, `connectionTTL`, `idleTimeout`, `transformQueryNames` and `transformResultNames`. Queries, transactions and raw connections reserved with `yield* pool.reserve` share the same `maxConnections` budget. A reservation holds its connection until its scope closes; release it before waiting for work that needs that slot.
@@ -217,7 +240,9 @@ Use `{ in: values }` to match any value in a list, alongside equality entries:
217
240
  yield* lines.findMany({ where: { id: { in: [1, 3, 5] }, amount: 52 } });
218
241
  ```
219
242
 
220
- Each list value uses the field's codec and decoded type. An empty list matches no rows. A plain array remains an equality value for an array-typed field; only the explicit `{ in: [...] }` entry requests SQL `IN`.
243
+ Each list value uses the field's codec and decoded type. An empty list matches no rows. A plain array remains an equality value for an array-typed field.
244
+
245
+ A value accepted by the field's decoded schema uses equality through its codec before filter operators are considered. For a JSONB field whose schema accepts `{ gt: 7 }` or `{ in: [7] }`, those objects compare as JSON values. An object is an operator filter only when the field's decoded schema does not accept it. A nullable field's `null` equality matches SQL NULL, including on JSONB columns; it does not match JSON null. This rule applies to reads, counts and deletes.
221
246
 
222
247
  Use `count` with the same `where` shape as `findMany` to return the matching row count decoded as a number:
223
248
 
@@ -539,7 +564,7 @@ const makeNotes = makeRepository(Note, {
539
564
  });
540
565
  ```
541
566
 
542
- Pass the contract collection as the repository's `collection` option when the model has buckets. Registration fails with `BucketRegistrationError` if the collection is missing, its name differs from `tableName`, or its bucket field names differ from the model's annotated fields. The error names both declarations. Repositories without buckets may omit the collection. Every inserted, updated or deleted row announces its record key and each declared bucket from the old and new stored values. An insert belongs only to its new buckets; a move announces both sides; a delete announces the old buckets. Bucket codecs decode stored values before producing keys, so a `bucket(Schema.NumberFromString)` field matches a numeric query bucket even when stored as text. Nullable and optional bucket values contribute no key when absent. Bucket codecs must need no services and decode to strings, numbers or absent values.
567
+ Pass the contract collection as the repository's `collection` option when the model has buckets. Registration fails with `BucketRegistrationError` if the collection is missing, its name differs from `tableName`, or its bucket field names differ from the model's annotated fields. The error names both declarations. Registration also rejects annotated fields whose decoded schemas cannot produce key values, naming them in `invalidFields`, before any write. Use explicit string or number schemas and refinements instead of opaque declarations; nullable and optional wrappers remain supported. Repositories without buckets may omit the collection. Every inserted, updated or deleted row announces its record key and each declared bucket from the old and new stored values. An insert belongs only to its new buckets; a move announces both sides; a delete announces the old buckets. Bucket codecs decode stored values before producing keys, so a `bucket(Schema.NumberFromString)` field matches a numeric query bucket even when stored as text. Nullable and optional bucket values contribute no key when absent. Bucket codecs must need no services and decode to strings, numbers or absent values.
543
568
 
544
569
  Bucket writes require PostgreSQL 18 or later: native `RETURNING old` supplies old values atomically, including for conflict updates. Repositories without bucket fields keep their existing SQL dialect support. Bulk writes keep every record and bucket key; the PostgreSQL publisher splits large batches into NOTIFY payloads.
545
570
 
@@ -615,7 +640,7 @@ Use sequential numbers, not timestamps. Effect's Migrator skips any migration wh
615
640
 
616
641
  `migratePostgres` rejects loaded migration IDs at or below the latest applied ID that are missing from the ledger with a typed native `MigrationError` (`kind: "BadState"`) naming those IDs.
617
642
 
618
- `migratePostgres` takes a transaction-scoped advisory lock before creating the ledger and running native Migrator. Concurrent runners on a fresh or existing ledger wait, then see the committed ledger and avoid repeating the migrations. Every runner of that ledger must use this helper and the same ledger name. The required `lockTimeout` bounds PostgreSQL lock waits; `Duration.infinity` sets the transaction's lock timeout to zero. Choose deployment and execution timeouts in the application.
643
+ `migratePostgres` discovers migrations, then takes an advisory lock before creating the ledger and running native Migrator. Runs with only numbered migrations use a transaction lock and work with a one-connection pool. Runs with schema components or a `release` use a session lock that stays held through the ledger transaction, all schema components and release publication, and releases on completion, failure or interruption. Both lock modes coordinate on the same ledger key. Concurrent runners on a fresh or existing ledger wait, then see the committed ledger and avoid repeating migrations; their schema components never overlap. Every runner of that ledger must use this helper and the same ledger name. The session lock reserves one pool connection while migration and component SQL use other connections: allow at least two connections for an active runner with components or a release, plus room for waiting runners and other work. Those runs require a direct PostgreSQL connection or session pooling. The required `lockTimeout` bounds acquisition of the advisory lock and lock waits in the ledger transaction; `Duration.infinity` disables those lock timeouts. Choose deployment and execution timeouts in the application.
619
644
 
620
645
  A failed batch rolls back its DDL, data and ledger entries, retaining previously committed migrations. A failed first batch also rolls back the bootstrapped ledger. A lock timeout fails with typed `SqlError` and reason `LockTimeoutError`; a migration-body SQL failure is a typed native `MigrationError`. Inspect startup completion with `Effect.exit` when both typed failures and defects matter. Keep nontransactional DDL in schema components; external side effects, crash recovery and deployment compatibility need their own migration policy.
621
646
 
@@ -625,9 +650,9 @@ For processes whose deployment owns migration execution, call `assertPostgresMig
625
650
 
626
651
  For a structured readiness readout, use `pendingPostgresMigrations({ loader, table?, components? })` from `@shivaedev/sql/pendingPostgresMigrations.ts`. It returns `{ migrations: [{ id, name }], components: [{ name, detail }] }` for pending work, with both arrays empty when current. It reads the same ledger and component checks as `assertPostgresMigrations` without running migrations. Malformed ledger and release rows fail with `SchemaError`.
627
652
 
628
- Pass an optional `release` string to `migratePostgres` to record the owning release after all ledger migrations and schema components succeed. The final `postgresRelease(release, table?)` schema component owns a one-row `<ledger>_release` table with typed `release` and UTC `recorded_at timestamptz` columns, plus a `<ledger>_workers` table with typed process identity, release and UTC heartbeat columns. `readPostgresRelease(table?)` from `postgresRelease.ts` returns the recorded release and `recordedAt` Date, or `undefined` for a missing marker. `pendingPostgresMigrations({ loader, release, table? })` reports a missing or different release as a pending component. Without `release`, migration and readiness calls neither write nor read these tables.
653
+ Pass an optional `release` string to `migratePostgres` to record the owning release after all ledger migrations and schema components succeed. A failed component publishes no release and preserves any existing marker. PostgreSQL timestamps each invocation before discovery and locking, and the marker accepts only a strictly newer timestamp, so an older invocation finishing later cannot replace a newer release. Release labels are opaque strings; they are not sorted. To deploy an earlier release again, start a new invocation. The final `postgresRelease(release, table?)` schema component owns a one-row `<ledger>_release` table with typed `release` and UTC `recorded_at timestamptz` columns, plus a `<ledger>_workers` table with typed process identity, release and UTC heartbeat columns. `readPostgresRelease(table?)` from `postgresRelease.ts` returns the recorded release and `recordedAt` Date of the invocation's start, or `undefined` for a missing marker. A standalone `postgresRelease` component timestamps the start of its `apply` effect. `pendingPostgresMigrations({ loader, release, table? })` reports a missing or different release as a pending component. Without `release`, migration and readiness calls neither write nor read these tables.
629
654
 
630
- `appDatabase` from `@shivaedev/server/appDatabase.ts` supplies the optional `WorkerRelease` Context service in migration mode `"wait"` with a release. Startup waits for that marker within `waitTimeout`; subsequent checks run every `pollInterval`. Each worker database Layer claims a process row only when its release owns the marker and no live row of another release remains. Heartbeats continue every poll while jobs drain, including after a connection blip. Each failed heartbeat or ownership poll logs its cause and retries three times, one quarter of a polling interval apart; exhausted retries close the worker scope with the failure cause. Completed drain and clean shutdown remove the row. Rows older than five polling intervals count as gone, bounding takeover after a crash (five seconds at the default one-second poll). Reserve SQL pool capacity for heartbeats alongside active jobs and the change listener. Release equality decides ownership, so rolling back the marker resumes the earlier worker. `@shivaedev/jobs` reads the service automatically; applications do not connect a signal themselves. Web's `"check"` mode ignores the marker.
655
+ `appDatabase` from `@shivaedev/server/appDatabase.ts` supplies the optional `WorkerRelease` Context service in migration mode `"wait"` with a release. Startup waits for that marker within `waitTimeout`; subsequent checks run every `pollInterval`. Each worker database Layer claims a process row only when its release owns the marker and no live row of another release remains. Heartbeats continue every poll while jobs drain, including after a connection blip. Each failed heartbeat or ownership poll logs its cause and retries three times, one quarter of a polling interval apart; exhausted retries close the worker scope with the failure cause. Completed drain and clean shutdown remove the row. Rows older than five polling intervals count as gone, bounding takeover after a crash (five seconds at the default one-second poll). Reserve SQL pool capacity for heartbeats alongside active jobs and the change listener. Release equality decides ownership, so a new migration invocation publishing an earlier release resumes that release's worker. `@shivaedev/jobs` reads the service automatically; applications do not connect a signal themselves. Web's `"check"` mode ignores the marker.
631
656
 
632
657
  ### PostgreSQL delivery between processes
633
658
 
@@ -0,0 +1,7 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ export interface LowMemoryPostgresOptions {
4
+ readonly pointInTimeRecovery: boolean;
5
+ }
6
+ export declare const applyLowMemoryPostgres: (args_0: LowMemoryPostgresOptions) => Effect.Effect<void, import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
7
+ //# sourceMappingURL=applyLowMemoryPostgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyLowMemoryPostgres.d.ts","sourceRoot":"","sources":["../src/applyLowMemoryPostgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;CACtC;AAED,eAAO,MAAM,sBAAsB,wHAoBjC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ export const applyLowMemoryPostgres = Effect.fn("Sql.applyLowMemoryPostgres")(function* ({ pointInTimeRecovery }) {
4
+ const sql = yield* SqlClient.SqlClient;
5
+ const settings = {
6
+ "autovacuum_max_workers": "2",
7
+ "autovacuum_work_mem": "32MB",
8
+ "hash_mem_multiplier": "1",
9
+ "idle_in_transaction_session_timeout": "10min",
10
+ "idle_session_timeout": "0",
11
+ jit: "off",
12
+ "max_connections": "50",
13
+ "max_parallel_workers_per_gather": "0",
14
+ "shared_buffers": "32MB",
15
+ "wal_buffers": "4MB",
16
+ "wal_compression": "zstd",
17
+ ...(pointInTimeRecovery ? { "archive_timeout": "300" } : { "archive_mode": "off" }),
18
+ };
19
+ for (const [name, value] of Object.entries(settings)) {
20
+ yield* sql.unsafe(`ALTER SYSTEM SET ${name} = '${value}'`);
21
+ }
22
+ yield* sql `select pg_reload_conf()`;
23
+ });
24
+ //# sourceMappingURL=applyLowMemoryPostgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyLowMemoryPostgres.js","sourceRoot":"","sources":["../src/applyLowMemoryPostgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAMvC,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,mBAAmB,EAA4B;IACzI,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,MAAM,QAAQ,GAAG;QAChB,wBAAwB,EAAE,GAAG;QAC7B,qBAAqB,EAAE,MAAM;QAC7B,qBAAqB,EAAE,GAAG;QAC1B,qCAAqC,EAAE,OAAO;QAC9C,sBAAsB,EAAE,GAAG;QAC3B,GAAG,EAAE,KAAK;QACV,iBAAiB,EAAE,IAAI;QACvB,iCAAiC,EAAE,GAAG;QACtC,gBAAgB,EAAE,MAAM;QACxB,aAAa,EAAE,KAAK;QACpB,iBAAiB,EAAE,MAAM;QACzB,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;KACnF,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,oBAAoB,IAAI,OAAO,KAAK,GAAG,CAAC,CAAC;IAC5D,CAAC;IACD,KAAK,CAAC,CAAC,GAAG,CAAA,yBAAyB,CAAC;AACrC,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"coordinateWorkerRelease.d.ts","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAkB,KAAK,EAAE,MAAM,QAAQ,CAAC;AAMjE,eAAO,MAAM,uBAAuB;;wIAoDlC,CAAC"}
1
+ {"version":3,"file":"coordinateWorkerRelease.d.ts","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAA6B,KAAK,EAAE,MAAM,QAAQ,CAAC;AAU5E,eAAO,MAAM,uBAAuB;;wIA0DlC,CAAC"}
@@ -1,11 +1,18 @@
1
- import { Duration, Effect, Exit, Schedule, Scope } from "effect";
1
+ import { Duration, Effect, Exit, Predicate, Schedule, Scope } from "effect";
2
2
  import { isSqlError } from "effect/sql/SqlError";
3
3
  import { readPostgresRelease } from "./postgresRelease.js";
4
4
  import { releaseWorkers } from "./releaseWorkers.js";
5
5
  import { makeWorkerRelease } from "./WorkerRelease.js";
6
+ function isCloseable(scope) {
7
+ return Predicate.hasProperty(scope, "~effect/Scope/Closeable") && scope["~effect/Scope/Closeable"] === "~effect/Scope/Closeable";
8
+ }
6
9
  export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRelease")(function* (release, pollInterval = "1 second", table = "effect_sql_migrations") {
7
10
  const gate = yield* makeWorkerRelease();
8
- const scope = yield* Scope.fork(yield* Effect.scope);
11
+ const owningScope = yield* Effect.scope;
12
+ if (!isCloseable(owningScope)) {
13
+ return yield* Effect.die(new Error("Worker release coordination requires a closeable owning scope"));
14
+ }
15
+ const scope = owningScope;
9
16
  const retries = Schedule.spaced(Duration.toMillis(pollInterval) / 4).pipe(Schedule.upTo({ times: 3 }));
10
17
  const rows = yield* releaseWorkers(release, Duration.toMillis(pollInterval) * 5, table);
11
18
  let claimed = false;
@@ -29,7 +36,7 @@ export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRele
29
36
  function loop(name, effect) {
30
37
  return Effect.forever(Effect.sleep(pollInterval).pipe(Effect.andThen(tick(name, effect)))).pipe(Effect.catchCause((cause) => Effect.logError(`Worker release ${name} stopped; closing worker scope`, cause).pipe(Effect.andThen(Scope.close(scope, Exit.failCause(cause))))), Scope.provide(scope), Effect.forkIn(scope));
31
38
  }
32
- yield* Scope.addFinalizer(scope, rows.remove.pipe(Effect.tapCause((cause) => Effect.logError("Worker release cleanup failed", cause)), Effect.orDie));
39
+ yield* Scope.addFinalizer(scope, gate.setActive(false).pipe(Effect.orDie, Effect.andThen(rows.remove), Effect.tapCause((cause) => Effect.logError("Worker release cleanup failed", cause)), Effect.orDie));
33
40
  // Heartbeats continue while offWork waits for active jobs to finish.
34
41
  yield* loop("heartbeat", rows.heartbeat);
35
42
  yield* tick("poll", poll).pipe(Scope.provide(scope));
@@ -1 +1 @@
1
- {"version":3,"file":"coordinateWorkerRelease.js","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coordinateWorkerRelease.js","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Context } from "effect";
2
+ export declare const MigrationStartedAt: Context.Reference<string | undefined>;
3
+ //# sourceMappingURL=MigrationStartedAt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MigrationStartedAt.d.ts","sourceRoot":"","sources":["../../src/internal/MigrationStartedAt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,eAAO,MAAM,kBAAkB,uCAE7B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Context } from "effect";
2
+ export const MigrationStartedAt = Context.Reference("@shivaedev/sql/internal/MigrationStartedAt", {
3
+ defaultValue: () => undefined,
4
+ });
5
+ //# sourceMappingURL=MigrationStartedAt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MigrationStartedAt.js","sourceRoot":"","sources":["../../src/internal/MigrationStartedAt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC,SAAS,CAAqB,4CAA4C,EAAE;IACrH,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;CAC7B,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ export declare const migrationLock: (table: string, timeout: string) => Effect.Effect<void, import("effect/sql/SqlError").SqlError, import("effect/Scope").Scope | SqlClient.SqlClient>;
4
+ //# sourceMappingURL=migrationLock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrationLock.d.ts","sourceRoot":"","sources":["../../src/internal/migrationLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,eAAO,MAAM,aAAa,qJAexB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ export const migrationLock = Effect.fnUntraced(function* (table, timeout) {
4
+ const sql = yield* SqlClient.SqlClient;
5
+ const connection = yield* sql.reserve;
6
+ function execute(statement) {
7
+ const [text, parameters] = statement.compile();
8
+ return connection.execute(text, parameters, undefined);
9
+ }
10
+ const [previous] = yield* execute(sql `select current_setting('lock_timeout') as timeout`);
11
+ yield* Effect.acquireRelease(execute(sql `select set_config('lock_timeout', ${timeout}, false)`), () => execute(sql `select set_config('lock_timeout', ${previous?.timeout}, false)`).pipe(Effect.orDie));
12
+ const key = `effect_sql_migrations:${table}`;
13
+ // Register cleanup before waiting so interruption also releases a lock granted just before cancellation.
14
+ yield* Effect.addFinalizer(() => execute(sql `select pg_advisory_unlock(hashtextextended(${key}, 0))`).pipe(Effect.orDie));
15
+ yield* execute(sql `select pg_advisory_lock(hashtextextended(${key}, 0))`);
16
+ });
17
+ //# sourceMappingURL=migrationLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrationLock.js","sourceRoot":"","sources":["../../src/internal/migrationLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAa,EAAE,OAAe;IACvF,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;IACtC,SAAS,OAAO,CAAC,SAAuD;QACvE,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QAC/C,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA,mDAAmD,CAAC,CAAC;IAC1F,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAA,qCAAqC,OAAO,UAAU,CAAC,EAAE,GAAG,EAAE,CACrG,OAAO,CAAC,GAAG,CAAA,qCAAqC,QAAQ,EAAE,OAAO,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAC/F,CAAC;IACF,MAAM,GAAG,GAAG,yBAAyB,KAAK,EAAE,CAAC;IAC7C,yGAAyG;IACzG,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,8CAA8C,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1H,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA,4CAA4C,GAAG,OAAO,CAAC,CAAC;AAC3E,CAAC,CAAC,CAAC"}
@@ -9,5 +9,5 @@ export interface PostgresMigrationOptions<R, E = never> {
9
9
  readonly release?: string;
10
10
  readonly table?: string;
11
11
  }
12
- export declare const migratePostgres: <R, E = never>(args_0: PostgresMigrationOptions<R, E>) => Effect.Effect<readonly (readonly [id: number, name: string])[], E | Migrator.MigrationError | Schema.SchemaError | SqlError, R | SqlClient.SqlClient>;
12
+ export declare const migratePostgres: <R, E = never>(args_0: PostgresMigrationOptions<R, E>) => Effect.Effect<readonly (readonly [id: number, name: string])[], E | Migrator.MigrationError | Schema.SchemaError | SqlError, SqlClient.SqlClient | Exclude<R, import("effect/Scope").Scope>>;
13
13
  //# sourceMappingURL=migrations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGhF,MAAM,WAAW,wBAAwB,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK;IACrD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACvD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,eAAO,MAAM,eAAe,GAAqD,CAAC,EAAE,CAAC,0MA6CnF,CAAC"}
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGhF,MAAM,WAAW,wBAAwB,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK;IACrD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACvD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,eAAO,MAAM,eAAe,GAAqD,CAAC,EAAE,CAAC,iPAyDpE,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import { Duration, Effect, Option, Schema } from "effect";
2
2
  import * as Reactivity from "effect/reactivity/Reactivity";
3
3
  import { Migrator, SqlClient } from "effect/sql";
4
+ import { MigrationStartedAt } from "#internal/MigrationStartedAt.ts";
5
+ import { migrationLock } from "#internal/migrationLock.ts";
4
6
  import { advisoryXactLock } from "./advisoryXactLock.js";
5
7
  import { postgresRelease } from "./postgresRelease.js";
6
8
  import { runSchemaComponent } from "./SchemaComponent.js";
@@ -8,19 +10,28 @@ import { transact } from "./transact.js";
8
10
  const migrate = Migrator.make({});
9
11
  export const migratePostgres = Effect.fn("EffectSql.migratePostgres")(function* ({ loader, components = [], table = "effect_sql_migrations", lockTimeout, release, }) {
10
12
  const sql = yield* SqlClient.SqlClient;
11
- const available = yield* Effect.serviceOption(Reactivity.Reactivity);
12
- const reactivity = Option.isSome(available) ? available.value : yield* Reactivity.make;
13
+ const [invocation] = release === undefined
14
+ ? []
15
+ : yield* sql `select clock_timestamp()::text as "startedAt"`.withoutTransform.pipe(Effect.flatMap(Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ startedAt: Schema.String })))));
16
+ const current = [...(yield* loader)].sort(([left], [right]) => left - right);
17
+ const extendedLock = components.length > 0 || release !== undefined;
13
18
  const millis = Duration.toMillis(lockTimeout);
14
19
  const timeout = millis === Number.POSITIVE_INFINITY ? "0" : `${Math.max(1, Math.ceil(millis))}ms`;
20
+ if (extendedLock) {
21
+ yield* migrationLock(table, timeout);
22
+ }
23
+ const available = yield* Effect.serviceOption(Reactivity.Reactivity);
24
+ const reactivity = Option.isSome(available) ? available.value : yield* Reactivity.make;
15
25
  const appliedMigrations = yield* Effect.gen(function* () {
16
26
  yield* sql `select set_config('lock_timeout', ${timeout}, true)`;
17
- yield* advisoryXactLock(`effect_sql_migrations:${table}`).pipe(Effect.catchTag("AdvisoryLockOutsideTransaction", Effect.die));
27
+ if (!extendedLock) {
28
+ yield* advisoryXactLock(`effect_sql_migrations:${table}`).pipe(Effect.catchTag("AdvisoryLockOutsideTransaction", Effect.die));
29
+ }
18
30
  yield* sql `create table if not exists ${sql(table)} (
19
31
  migration_id integer primary key,
20
32
  created_at timestamp with time zone not null default now(),
21
33
  name text not null
22
34
  )`;
23
- const current = [...(yield* loader)].sort(([left], [right]) => left - right);
24
35
  const applied = yield* sql `select migration_id as id from ${sql(table)}`.withoutTransform.pipe(Effect.flatMap(Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ id: Schema.Int })))));
25
36
  const appliedIds = new Set(applied.map(({ id }) => id));
26
37
  const latest = applied.reduce((max, { id }) => Math.max(max, id), 0);
@@ -38,8 +49,8 @@ export const migratePostgres = Effect.fn("EffectSql.migratePostgres")(function*
38
49
  ...(release === undefined ? [] : [postgresRelease(release, table)]),
39
50
  ];
40
51
  for (const component of schemaComponents) {
41
- yield* runSchemaComponent(component.name, component.apply);
52
+ yield* runSchemaComponent(component.name, component.apply).pipe(Effect.provideService(MigrationStartedAt, invocation?.startedAt));
42
53
  }
43
54
  return appliedMigrations;
44
- });
55
+ }, Effect.scoped);
45
56
  //# sourceMappingURL=migrations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ export declare const readPostgresRelease: (table?: any) => Effect.Effect<{
5
5
  readonly release: string;
6
6
  } | undefined, Schema.SchemaError | import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
7
7
  export declare function postgresRelease(release: string, table?: string): {
8
- apply: Effect.Effect<void, import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
8
+ apply: Effect.Effect<void, Schema.SchemaError | import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
9
9
  name: string;
10
10
  pending: Effect.Effect<string | undefined, Schema.SchemaError | import("effect/sql/SqlError").SqlError, SqlClient.SqlClient>;
11
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"postgresRelease.d.ts","sourceRoot":"","sources":["../src/postgresRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,eAAO,MAAM,mBAAmB;;;gGAc9B,CAAC;AAEH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAA0B;;;;EAwB/E"}
1
+ {"version":3,"file":"postgresRelease.d.ts","sourceRoot":"","sources":["../src/postgresRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,eAAO,MAAM,mBAAmB;;;gGAc9B,CAAC;AAEH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAA0B;;;;EA8B/E"}
@@ -1,5 +1,6 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { SqlClient } from "effect/sql";
3
+ import { MigrationStartedAt } from "#internal/MigrationStartedAt.ts";
3
4
  export const readPostgresRelease = Effect.fn("EffectSql.readPostgresRelease")(function* (table = "effect_sql_migrations") {
4
5
  const sql = yield* SqlClient.SqlClient;
5
6
  const name = `${table}_release`;
@@ -15,6 +16,9 @@ export function postgresRelease(release, table = "effect_sql_migrations") {
15
16
  return {
16
17
  apply: Effect.gen(function* () {
17
18
  const sql = yield* SqlClient.SqlClient;
19
+ const startedAt = yield* MigrationStartedAt;
20
+ const timestamp = startedAt === undefined ? sql `clock_timestamp()` : sql `${startedAt}::timestamptz`;
21
+ const [invocation] = yield* sql `select ${timestamp}::text as at`.withoutTransform.pipe(Effect.flatMap(Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ at: Schema.String })))));
18
22
  yield* sql `create table if not exists ${sql(`${table}_release`)} (
19
23
  id boolean primary key default true check (id),
20
24
  release text not null,
@@ -26,8 +30,9 @@ export function postgresRelease(release, table = "effect_sql_migrations") {
26
30
  heartbeat timestamptz not null
27
31
  )`;
28
32
  yield* sql `insert into ${sql(`${table}_release`)} (id, release, recorded_at)
29
- values (true, ${release}, clock_timestamp())
30
- on conflict (id) do update set release = excluded.release, recorded_at = excluded.recorded_at`;
33
+ values (true, ${release}, ${invocation?.at}::timestamptz)
34
+ on conflict (id) do update set release = excluded.release, recorded_at = excluded.recorded_at
35
+ where ${sql(`${table}_release`)}.recorded_at < excluded.recorded_at`;
31
36
  }),
32
37
  name: "database release",
33
38
  pending: Effect.gen(function* () {
@@ -1 +1 @@
1
- {"version":3,"file":"postgresRelease.js","sourceRoot":"","sources":["../src/postgresRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,uBAAuB;IACvH,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,KAAK,UAAU,CAAC;IAChC,MAAM,UAAU,GAAG,GAAG,CAAA,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA,sBAAsB,UAAU,iBAAiB,CAAC,gBAAgB,CAAC,IAAI,CACjG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAC/G,CAAC;IACF,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA,oDAAoD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAC5G,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAC5H,CAAC;IACF,OAAO,GAAG,CAAC;AACZ,CAAC,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,KAAK,GAAG,uBAAuB;IAC/E,OAAO;QACN,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;YACvC,KAAK,CAAC,CAAC,GAAG,CAAA,8BAA8B,GAAG,CAAC,GAAG,KAAK,UAAU,CAAC;;;;KAI7D,CAAC;YACH,KAAK,CAAC,CAAC,GAAG,CAAA,8BAA8B,GAAG,CAAC,GAAG,KAAK,UAAU,CAAC;;;;KAI7D,CAAC;YACH,KAAK,CAAC,CAAC,GAAG,CAAA,eAAe,GAAG,CAAC,GAAG,KAAK,UAAU,CAAC;oBAC/B,OAAO;kGACuE,CAAC;QACjG,CAAC,CAAC;QACF,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAClD,OAAO,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,OAAO,cAAc,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC;QACzH,CAAC,CAAC;KACwB,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"postgresRelease.js","sourceRoot":"","sources":["../src/postgresRelease.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ export declare class BucketRegistrationError extends BucketRegistrationError_bas
17
17
  readonly collectionName: string | undefined;
18
18
  readonly modelFields: readonly string[];
19
19
  readonly collectionFields: readonly string[];
20
+ readonly invalidFields: readonly string[];
20
21
  }> {
21
22
  get message(): string;
22
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"repositoryCollection.d.ts","sourceRoot":"","sources":["../src/repositoryCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAS,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG1D,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB,CAAC,GAAG;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;;;;AAED,qBAAa,uBAAwB,SAAQ,6BAA4C;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C,CAAC;IACD,IAAa,OAAO,WAEnB;CACD;AAED,eAAO,MAAM,4BAA4B;wBAET,MAAM;0BAAwB,oBAAoB;8DAiBhF,CAAC"}
1
+ {"version":3,"file":"repositoryCollection.d.ts","sourceRoot":"","sources":["../src/repositoryCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAS,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG1D,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB,CAAC,GAAG;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;;;;AAED,qBAAa,uBAAwB,SAAQ,6BAA4C;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;IACD,IAAa,OAAO,WAKnB;CACD;AAED,eAAO,MAAM,4BAA4B;wBAET,MAAM;0BAAwB,oBAAoB;8DA2BhF,CAAC"}
@@ -2,20 +2,33 @@ import { Data, Effect, Order } from "effect";
2
2
  import { declaredBuckets } from "@shivaedev/changes/buckets.ts";
3
3
  export class BucketRegistrationError extends Data.TaggedError("BucketRegistrationError") {
4
4
  get message() {
5
+ if (this.invalidFields.length > 0) {
6
+ return `Bucket registration for ${this.tableName}: fields ${JSON.stringify(this.invalidFields)} must decode to strings, numbers or absent values`;
7
+ }
5
8
  return `Bucket registration for ${this.tableName}: model fields ${JSON.stringify(this.modelFields)} disagree with collection ${this.collectionName ?? "(missing)"} fields ${JSON.stringify(this.collectionFields)}`;
6
9
  }
7
10
  }
8
11
  export const validateRepositoryCollection = Effect.fnUntraced(function* (fields, options) {
9
- const modelFields = declaredBuckets(fields)
12
+ const buckets = declaredBuckets(fields);
13
+ const invalidFields = buckets
14
+ .filter(({ supported }) => !supported)
10
15
  .map(({ field }) => field)
11
16
  .sort(Order.String);
17
+ const modelFields = buckets.map(({ field }) => field).sort(Order.String);
12
18
  const collectionFields = Object.keys(options.collection?.bucket ?? {}).sort(Order.String);
13
- if ((options.collection === undefined && modelFields.length === 0)
14
- || (options.collection?.name === options.tableName
15
- && modelFields.length === collectionFields.length
16
- && modelFields.every((field, index) => field === collectionFields[index]))) {
19
+ if (invalidFields.length === 0
20
+ && ((options.collection === undefined && modelFields.length === 0)
21
+ || (options.collection?.name === options.tableName
22
+ && modelFields.length === collectionFields.length
23
+ && modelFields.every((field, index) => field === collectionFields[index])))) {
17
24
  return;
18
25
  }
19
- return yield* Effect.fail(new BucketRegistrationError({ collectionFields, collectionName: options.collection?.name, modelFields, tableName: options.tableName }));
26
+ return yield* Effect.fail(new BucketRegistrationError({
27
+ collectionFields,
28
+ collectionName: options.collection?.name,
29
+ invalidFields,
30
+ modelFields,
31
+ tableName: options.tableName,
32
+ }));
20
33
  });
21
34
  //# sourceMappingURL=repositoryCollection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"repositoryCollection.js","sourceRoot":"","sources":["../src/repositoryCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAe,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAchE,MAAM,OAAO,uBAAwB,SAAQ,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAKrF;IACD,IAAa,OAAO;QACnB,OAAO,2BAA2B,IAAI,CAAC,SAAS,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,6BAA6B,IAAI,CAAC,cAAc,IAAI,WAAW,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;IACrN,CAAC;CACD;AAED,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACtE,MAA4B,EAC5B,OAAmF;IAEnF,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC;SACzC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC;SACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1F,IACC,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC;WAC3D,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,KAAK,OAAO,CAAC,SAAS;eAC9C,WAAW,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM;eAC9C,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,EAC1E,CAAC;QACF,OAAO;IACR,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACxB,IAAI,uBAAuB,CAAC,EAAE,gBAAgB,EAAE,cAAc,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CACtI,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"repositoryCollection.js","sourceRoot":"","sources":["../src/repositoryCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAe,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAchE,MAAM,OAAO,uBAAwB,SAAQ,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAMrF;IACD,IAAa,OAAO;QACnB,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,OAAO,2BAA2B,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,mDAAmD,CAAC;QACnJ,CAAC;QACD,OAAO,2BAA2B,IAAI,CAAC,SAAS,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,6BAA6B,IAAI,CAAC,cAAc,IAAI,WAAW,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;IACrN,CAAC;CACD;AAED,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACtE,MAA4B,EAC5B,OAAmF;IAEnF,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,OAAO;SAC3B,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC;SACrC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC;SACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzE,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1F,IACC,aAAa,CAAC,MAAM,KAAK,CAAC;WACvB,CAAC,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC;eAC9D,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,KAAK,OAAO,CAAC,SAAS;mBAC9C,WAAW,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM;mBAC9C,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAC5E,CAAC;QACF,OAAO;IACR,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACxB,IAAI,uBAAuB,CAAC;QAC3B,gBAAgB;QAChB,cAAc,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI;QACxC,aAAa;QACb,WAAW;QACX,SAAS,EAAE,OAAO,CAAC,SAAS;KAC5B,CAAC,CACF,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"repositoryFilter.d.ts","sourceRoot":"","sources":["../src/repositoryFilter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repositoryFilter.d.ts","sourceRoot":"","sources":["../src/repositoryFilter.ts"],"names":[],"mappings":"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"}
@@ -39,17 +39,24 @@ export function makeFilter(model, sql, references) {
39
39
  }
40
40
  function predicate(key, value, allowIn, allowComparisons) {
41
41
  return Effect.flatMap(fieldAt(key), (field) => {
42
+ const encode = Schema.encodeEffect(field);
43
+ function equality() {
44
+ return Effect.map(encode(value), (encoded) => value === null || encoded === null ? sql `${column(key)} is null` : sql `${column(key)} = ${encoded}`);
45
+ }
46
+ const acceptsValue = Schema.is(field);
47
+ if (acceptsValue(value)) {
48
+ return equality();
49
+ }
42
50
  const incoming = reference(value);
43
51
  if (incoming !== undefined) {
44
52
  return Effect.as(fieldAt(incoming), sql `${column(key)} = excluded.${sql(incoming)}`);
45
53
  }
46
- const encode = Schema.encodeEffect(field);
47
54
  if (allowComparisons && typeof value === "object" && value !== null && Object.keys(value).some(isOperator)) {
48
55
  return Effect.map(Effect.forEach(Object.entries(value), ([operator, operand]) => comparison(key, field, operator, operand)), (predicates) => sql.and(predicates));
49
56
  }
50
57
  return allowIn && typeof value === "object" && value !== null && "in" in value && Array.isArray(value.in)
51
58
  ? Effect.map(Effect.forEach(value.in, (entry) => encode(entry)), (encoded) => inPredicate(key, encoded))
52
- : Effect.map(encode(value), (encoded) => (encoded === null ? sql `${column(key)} is null` : sql `${column(key)} = ${encoded}`));
59
+ : equality();
53
60
  });
54
61
  }
55
62
  function where(input = {}, allowIn = false, allowComparisons = false) {
@@ -1 +1 @@
1
- {"version":3,"file":"repositoryFilter.js","sourceRoot":"","sources":["../src/repositoryFilter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repositoryFilter.js","sourceRoot":"","sources":["../src/repositoryFilter.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"transact.d.ts","sourceRoot":"","sources":["../src/transact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIhE,MAAM,MAAM,gBAAgB,GAAG,SAAS,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;AA2B/F,eAAO,MAAM,cAAc,+FAAyB,CAAC;AACrD,eAAO,MAAM,YAAY,0JAA6B,CAAC;AACvD,eAAO,MAAM,aAAa,uJAA8B,CAAC;AAEzD,eAAO,MAAM,kBAAkB,qGAE7B,CAAC;AAEH,MAAM,WAAW,eAAe,CAAC,MAAM;IACtC,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;CACjD;AAED,eAAO,MAAM,QAAQ,EAAE;IACtB,CAAC,MAAM,EACN,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACjJ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;CASpG,CAAC"}
1
+ {"version":3,"file":"transact.d.ts","sourceRoot":"","sources":["../src/transact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIhE,MAAM,MAAM,gBAAgB,GAAG,SAAS,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;AA2B/F,eAAO,MAAM,cAAc,+FAAyB,CAAC;AACrD,eAAO,MAAM,YAAY,0JAA6B,CAAC;AACvD,eAAO,MAAM,aAAa,uJAA8B,CAAC;AAEzD,eAAO,MAAM,kBAAkB,qGAE7B,CAAC;AAEH,MAAM,WAAW,eAAe,CAAC,MAAM;IACtC,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;CACjD;AAED,eAAO,MAAM,QAAQ,EAAE;IACtB,CAAC,MAAM,EACN,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACjJ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;CAcpG,CAAC"}
package/dist/transact.js CHANGED
@@ -32,8 +32,11 @@ export const invalidateOnCommit = Effect.fn("Transact.invalidateOnCommit")(funct
32
32
  });
33
33
  export const transact = dual(2, Effect.fn("Transact.transact")(function* (effect, options) {
34
34
  const sql = yield* SqlClient.SqlClient;
35
+ const native = yield* Effect.serviceOption(sql.transactionService);
35
36
  return yield* invalidations
36
- .within(sql.withTransaction)(effect)
37
+ .within((body, boundary) => native._tag === "Some"
38
+ ? sql.withTransaction(body)
39
+ : boundary.restore(sql.withTransaction(Effect.tap(body, () => sql.afterCommit(boundary.committed)))))(effect)
37
40
  .pipe(Effect.catchIf(isSqlError, (error) => Effect.fail(options.onSqlError(error))));
38
41
  }));
39
42
  //# sourceMappingURL=transact.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transact.js","sourceRoot":"","sources":["../src/transact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transact.js","sourceRoot":"","sources":["../src/transact.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.30.0",
3
+ "version": "0.32.0",
4
4
  "description": "Schema-derived repositories over native Effect SQL",
5
5
  "keywords": [
6
6
  "effect"
@@ -43,16 +43,17 @@
43
43
  "README.md"
44
44
  ],
45
45
  "dependencies": {
46
- "@shivaedev/changes": "0.6.0",
47
- "@shivaedev/service": "0.6.0"
46
+ "@shivaedev/changes": "0.7.0",
47
+ "@shivaedev/service": "0.6.1"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@effect/platform-node": "4.0.6",
51
51
  "@effect/sql-pg": "4.0.6",
52
52
  "@effect/sql-sqlite-node": "4.0.6",
53
- "@shivaedev/quality": "0.53.0",
54
- "@shivaedev/test-sql": "0.15.3",
55
- "@shivaedev/test-story": "0.31.3",
53
+ "@shivaedev/jobs": "0.29.2",
54
+ "@shivaedev/quality": "0.55.0",
55
+ "@shivaedev/test-sql": "0.16.1",
56
+ "@shivaedev/test-story": "0.33.0",
56
57
  "@types/node": "24.19.2",
57
58
  "effect": "4.0.6",
58
59
  "typescript": "7.0.2",
@@ -0,0 +1,28 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+
4
+ export interface LowMemoryPostgresOptions {
5
+ readonly pointInTimeRecovery: boolean;
6
+ }
7
+
8
+ export const applyLowMemoryPostgres = Effect.fn("Sql.applyLowMemoryPostgres")(function* ({ pointInTimeRecovery }: LowMemoryPostgresOptions) {
9
+ const sql = yield* SqlClient.SqlClient;
10
+ const settings = {
11
+ "autovacuum_max_workers": "2",
12
+ "autovacuum_work_mem": "32MB",
13
+ "hash_mem_multiplier": "1",
14
+ "idle_in_transaction_session_timeout": "10min",
15
+ "idle_session_timeout": "0",
16
+ jit: "off",
17
+ "max_connections": "50",
18
+ "max_parallel_workers_per_gather": "0",
19
+ "shared_buffers": "32MB",
20
+ "wal_buffers": "4MB",
21
+ "wal_compression": "zstd",
22
+ ...(pointInTimeRecovery ? { "archive_timeout": "300" } : { "archive_mode": "off" }),
23
+ };
24
+ for (const [name, value] of Object.entries(settings)) {
25
+ yield* sql.unsafe(`ALTER SYSTEM SET ${name} = '${value}'`);
26
+ }
27
+ yield* sql`select pg_reload_conf()`;
28
+ });
@@ -1,16 +1,24 @@
1
- import { Duration, Effect, Exit, Schedule, Scope } from "effect";
1
+ import { Duration, Effect, Exit, Predicate, Schedule, Scope } from "effect";
2
2
  import { isSqlError } from "effect/sql/SqlError";
3
3
  import { readPostgresRelease } from "./postgresRelease.ts";
4
4
  import { releaseWorkers } from "./releaseWorkers.ts";
5
5
  import { makeWorkerRelease } from "./WorkerRelease.ts";
6
6
 
7
+ function isCloseable(scope: Scope.Scope): scope is Scope.Closeable {
8
+ return Predicate.hasProperty(scope, "~effect/Scope/Closeable") && scope["~effect/Scope/Closeable"] === "~effect/Scope/Closeable";
9
+ }
10
+
7
11
  export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRelease")(function* (
8
12
  release: string,
9
13
  pollInterval: Duration.Input = "1 second",
10
14
  table = "effect_sql_migrations",
11
15
  ) {
12
16
  const gate = yield* makeWorkerRelease();
13
- const scope = yield* Scope.fork(yield* Effect.scope);
17
+ const owningScope = yield* Effect.scope;
18
+ if (!isCloseable(owningScope)) {
19
+ return yield* Effect.die(new Error("Worker release coordination requires a closeable owning scope"));
20
+ }
21
+ const scope = owningScope;
14
22
  const retries = Schedule.spaced(Duration.toMillis(pollInterval) / 4).pipe(Schedule.upTo({ times: 3 }));
15
23
  const rows = yield* releaseWorkers(release, Duration.toMillis(pollInterval) * 5, table);
16
24
  let claimed = false;
@@ -46,7 +54,9 @@ export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRele
46
54
  }
47
55
  yield* Scope.addFinalizer(
48
56
  scope,
49
- rows.remove.pipe(
57
+ gate.setActive(false).pipe(
58
+ Effect.orDie,
59
+ Effect.andThen(rows.remove),
50
60
  Effect.tapCause((cause) => Effect.logError("Worker release cleanup failed", cause)),
51
61
  Effect.orDie,
52
62
  ),
@@ -0,0 +1,5 @@
1
+ import { Context } from "effect";
2
+
3
+ export const MigrationStartedAt = Context.Reference<string | undefined>("@shivaedev/sql/internal/MigrationStartedAt", {
4
+ defaultValue: () => undefined,
5
+ });
@@ -0,0 +1,20 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import type { Statement } from "effect/sql/Statement";
4
+
5
+ export const migrationLock = Effect.fnUntraced(function* (table: string, timeout: string) {
6
+ const sql = yield* SqlClient.SqlClient;
7
+ const connection = yield* sql.reserve;
8
+ function execute(statement: Statement<Readonly<Record<string, unknown>>>) {
9
+ const [text, parameters] = statement.compile();
10
+ return connection.execute(text, parameters, undefined);
11
+ }
12
+ const [previous] = yield* execute(sql`select current_setting('lock_timeout') as timeout`);
13
+ yield* Effect.acquireRelease(execute(sql`select set_config('lock_timeout', ${timeout}, false)`), () =>
14
+ execute(sql`select set_config('lock_timeout', ${previous?.timeout}, false)`).pipe(Effect.orDie),
15
+ );
16
+ const key = `effect_sql_migrations:${table}`;
17
+ // Register cleanup before waiting so interruption also releases a lock granted just before cancellation.
18
+ yield* Effect.addFinalizer(() => execute(sql`select pg_advisory_unlock(hashtextextended(${key}, 0))`).pipe(Effect.orDie));
19
+ yield* execute(sql`select pg_advisory_lock(hashtextextended(${key}, 0))`);
20
+ });
package/src/migrations.ts CHANGED
@@ -2,6 +2,8 @@ import { Duration, Effect, Option, Schema } from "effect";
2
2
  import * as Reactivity from "effect/reactivity/Reactivity";
3
3
  import { Migrator, SqlClient } from "effect/sql";
4
4
  import type { SqlError } from "effect/sql/SqlError";
5
+ import { MigrationStartedAt } from "#internal/MigrationStartedAt.ts";
6
+ import { migrationLock } from "#internal/migrationLock.ts";
5
7
  import { advisoryXactLock } from "./advisoryXactLock.ts";
6
8
  import { postgresRelease } from "./postgresRelease.ts";
7
9
  import { runSchemaComponent, type SchemaComponent } from "./SchemaComponent.ts";
@@ -25,19 +27,31 @@ export const migratePostgres = Effect.fn("EffectSql.migratePostgres")(function*
25
27
  release,
26
28
  }: PostgresMigrationOptions<R, E>) {
27
29
  const sql = yield* SqlClient.SqlClient;
28
- const available = yield* Effect.serviceOption(Reactivity.Reactivity);
29
- const reactivity = Option.isSome(available) ? available.value : yield* Reactivity.make;
30
+ const [invocation] =
31
+ release === undefined
32
+ ? []
33
+ : yield* sql`select clock_timestamp()::text as "startedAt"`.withoutTransform.pipe(
34
+ Effect.flatMap(Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ startedAt: Schema.String })))),
35
+ );
36
+ const current = [...(yield* loader)].sort(([left], [right]) => left - right);
37
+ const extendedLock = components.length > 0 || release !== undefined;
30
38
  const millis = Duration.toMillis(lockTimeout);
31
39
  const timeout = millis === Number.POSITIVE_INFINITY ? "0" : `${Math.max(1, Math.ceil(millis))}ms`;
40
+ if (extendedLock) {
41
+ yield* migrationLock(table, timeout);
42
+ }
43
+ const available = yield* Effect.serviceOption(Reactivity.Reactivity);
44
+ const reactivity = Option.isSome(available) ? available.value : yield* Reactivity.make;
32
45
  const appliedMigrations = yield* Effect.gen(function* () {
33
46
  yield* sql`select set_config('lock_timeout', ${timeout}, true)`;
34
- yield* advisoryXactLock(`effect_sql_migrations:${table}`).pipe(Effect.catchTag("AdvisoryLockOutsideTransaction", Effect.die));
47
+ if (!extendedLock) {
48
+ yield* advisoryXactLock(`effect_sql_migrations:${table}`).pipe(Effect.catchTag("AdvisoryLockOutsideTransaction", Effect.die));
49
+ }
35
50
  yield* sql`create table if not exists ${sql(table)} (
36
51
  migration_id integer primary key,
37
52
  created_at timestamp with time zone not null default now(),
38
53
  name text not null
39
54
  )`;
40
- const current = [...(yield* loader)].sort(([left], [right]) => left - right);
41
55
  const applied = yield* sql`select migration_id as id from ${sql(table)}`.withoutTransform.pipe(
42
56
  Effect.flatMap(Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ id: Schema.Int })))),
43
57
  );
@@ -59,7 +73,7 @@ export const migratePostgres = Effect.fn("EffectSql.migratePostgres")(function*
59
73
  ...(release === undefined ? [] : [postgresRelease(release, table)]),
60
74
  ];
61
75
  for (const component of schemaComponents) {
62
- yield* runSchemaComponent(component.name, component.apply);
76
+ yield* runSchemaComponent(component.name, component.apply).pipe(Effect.provideService(MigrationStartedAt, invocation?.startedAt));
63
77
  }
64
78
  return appliedMigrations;
65
- });
79
+ }, Effect.scoped);
@@ -1,5 +1,6 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { SqlClient } from "effect/sql";
3
+ import { MigrationStartedAt } from "#internal/MigrationStartedAt.ts";
3
4
  import type { SchemaComponent } from "./SchemaComponent.ts";
4
5
 
5
6
  export const readPostgresRelease = Effect.fn("EffectSql.readPostgresRelease")(function* (table = "effect_sql_migrations") {
@@ -22,6 +23,11 @@ export function postgresRelease(release: string, table = "effect_sql_migrations"
22
23
  return {
23
24
  apply: Effect.gen(function* () {
24
25
  const sql = yield* SqlClient.SqlClient;
26
+ const startedAt = yield* MigrationStartedAt;
27
+ const timestamp = startedAt === undefined ? sql`clock_timestamp()` : sql`${startedAt}::timestamptz`;
28
+ const [invocation] = yield* sql`select ${timestamp}::text as at`.withoutTransform.pipe(
29
+ Effect.flatMap(Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ at: Schema.String })))),
30
+ );
25
31
  yield* sql`create table if not exists ${sql(`${table}_release`)} (
26
32
  id boolean primary key default true check (id),
27
33
  release text not null,
@@ -33,8 +39,9 @@ export function postgresRelease(release: string, table = "effect_sql_migrations"
33
39
  heartbeat timestamptz not null
34
40
  )`;
35
41
  yield* sql`insert into ${sql(`${table}_release`)} (id, release, recorded_at)
36
- values (true, ${release}, clock_timestamp())
37
- on conflict (id) do update set release = excluded.release, recorded_at = excluded.recorded_at`;
42
+ values (true, ${release}, ${invocation?.at}::timestamptz)
43
+ on conflict (id) do update set release = excluded.release, recorded_at = excluded.recorded_at
44
+ where ${sql(`${table}_release`)}.recorded_at < excluded.recorded_at`;
38
45
  }),
39
46
  name: "database release",
40
47
  pending: Effect.gen(function* () {
@@ -18,8 +18,12 @@ export class BucketRegistrationError extends Data.TaggedError("BucketRegistratio
18
18
  readonly collectionName: string | undefined;
19
19
  readonly modelFields: readonly string[];
20
20
  readonly collectionFields: readonly string[];
21
+ readonly invalidFields: readonly string[];
21
22
  }> {
22
23
  override get message() {
24
+ if (this.invalidFields.length > 0) {
25
+ return `Bucket registration for ${this.tableName}: fields ${JSON.stringify(this.invalidFields)} must decode to strings, numbers or absent values`;
26
+ }
23
27
  return `Bucket registration for ${this.tableName}: model fields ${JSON.stringify(this.modelFields)} disagree with collection ${this.collectionName ?? "(missing)"} fields ${JSON.stringify(this.collectionFields)}`;
24
28
  }
25
29
  }
@@ -28,19 +32,29 @@ export const validateRepositoryCollection = Effect.fnUntraced(function* (
28
32
  fields: Schema.Struct.Fields,
29
33
  options: { readonly tableName: string; readonly collection?: RepositoryCollection },
30
34
  ) {
31
- const modelFields = declaredBuckets(fields)
35
+ const buckets = declaredBuckets(fields);
36
+ const invalidFields = buckets
37
+ .filter(({ supported }) => !supported)
32
38
  .map(({ field }) => field)
33
39
  .sort(Order.String);
40
+ const modelFields = buckets.map(({ field }) => field).sort(Order.String);
34
41
  const collectionFields = Object.keys(options.collection?.bucket ?? {}).sort(Order.String);
35
42
  if (
36
- (options.collection === undefined && modelFields.length === 0)
37
- || (options.collection?.name === options.tableName
38
- && modelFields.length === collectionFields.length
39
- && modelFields.every((field, index) => field === collectionFields[index]))
43
+ invalidFields.length === 0
44
+ && ((options.collection === undefined && modelFields.length === 0)
45
+ || (options.collection?.name === options.tableName
46
+ && modelFields.length === collectionFields.length
47
+ && modelFields.every((field, index) => field === collectionFields[index])))
40
48
  ) {
41
49
  return;
42
50
  }
43
51
  return yield* Effect.fail(
44
- new BucketRegistrationError({ collectionFields, collectionName: options.collection?.name, modelFields, tableName: options.tableName }),
52
+ new BucketRegistrationError({
53
+ collectionFields,
54
+ collectionName: options.collection?.name,
55
+ invalidFields,
56
+ modelFields,
57
+ tableName: options.tableName,
58
+ }),
45
59
  );
46
60
  });
@@ -70,11 +70,20 @@ export function makeFilter<TModel extends Model.Any>(model: TModel, sql: SqlClie
70
70
  }
71
71
  function predicate(key: string, value: unknown, allowIn: boolean, allowComparisons: boolean) {
72
72
  return Effect.flatMap(fieldAt(key), (field) => {
73
+ const encode = Schema.encodeEffect(field);
74
+ function equality() {
75
+ return Effect.map(encode(value), (encoded) =>
76
+ value === null || encoded === null ? sql`${column(key)} is null` : sql`${column(key)} = ${encoded}`,
77
+ );
78
+ }
79
+ const acceptsValue: (input: unknown) => boolean = Schema.is(field);
80
+ if (acceptsValue(value)) {
81
+ return equality();
82
+ }
73
83
  const incoming = reference(value);
74
84
  if (incoming !== undefined) {
75
85
  return Effect.as(fieldAt(incoming), sql`${column(key)} = excluded.${sql(incoming)}`);
76
86
  }
77
- const encode = Schema.encodeEffect(field);
78
87
  if (allowComparisons && typeof value === "object" && value !== null && Object.keys(value).some(isOperator)) {
79
88
  return Effect.map(
80
89
  Effect.forEach(Object.entries(value), ([operator, operand]) => comparison(key, field, operator, operand)),
@@ -86,7 +95,7 @@ export function makeFilter<TModel extends Model.Any>(model: TModel, sql: SqlClie
86
95
  Effect.forEach(value.in, (entry) => encode(entry)),
87
96
  (encoded) => inPredicate(key, encoded),
88
97
  )
89
- : Effect.map(encode(value), (encoded) => (encoded === null ? sql`${column(key)} is null` : sql`${column(key)} = ${encoded}`));
98
+ : equality();
90
99
  });
91
100
  }
92
101
  function where(input: Readonly<Record<string, unknown>> & Partial<TupleFilter<Model.Any>> = {}, allowIn = false, allowComparisons = false) {
package/src/transact.ts CHANGED
@@ -58,8 +58,13 @@ export const transact: {
58
58
  2,
59
59
  Effect.fn("Transact.transact")(function* <A, E, R, TError>(effect: Effect.Effect<A, E, R>, options: TransactOptions<TError>) {
60
60
  const sql = yield* SqlClient.SqlClient;
61
+ const native = yield* Effect.serviceOption(sql.transactionService);
61
62
  return yield* invalidations
62
- .within(sql.withTransaction)(effect)
63
+ .within((body, boundary) =>
64
+ native._tag === "Some"
65
+ ? sql.withTransaction(body)
66
+ : boundary.restore(sql.withTransaction(Effect.tap(body, () => sql.afterCommit(boundary.committed)))),
67
+ )(effect)
63
68
  .pipe(Effect.catchIf(isSqlError, (error) => Effect.fail(options.onSqlError(error))));
64
69
  }),
65
70
  );