@shivaedev/sql 0.29.0 → 0.30.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 +12 -0
  2. package/README.md +78 -1
  3. package/dist/batchedDelete.d.ts +33 -0
  4. package/dist/batchedDelete.d.ts.map +1 -0
  5. package/dist/batchedDelete.js +64 -0
  6. package/dist/batchedDelete.js.map +1 -0
  7. package/dist/compositeRepository.d.ts +14 -13
  8. package/dist/compositeRepository.d.ts.map +1 -1
  9. package/dist/compositeRepository.js.map +1 -1
  10. package/dist/jsonb.d.ts +3 -0
  11. package/dist/jsonb.d.ts.map +1 -0
  12. package/dist/jsonb.js +9 -0
  13. package/dist/jsonb.js.map +1 -0
  14. package/dist/repository.d.ts.map +1 -1
  15. package/dist/repository.js +19 -17
  16. package/dist/repository.js.map +1 -1
  17. package/dist/repositoryChanges.d.ts +1 -0
  18. package/dist/repositoryChanges.d.ts.map +1 -1
  19. package/dist/repositoryChanges.js +9 -1
  20. package/dist/repositoryChanges.js.map +1 -1
  21. package/dist/repositoryUpdate.d.ts +31 -0
  22. package/dist/repositoryUpdate.d.ts.map +1 -0
  23. package/dist/repositoryUpdate.js +16 -0
  24. package/dist/repositoryUpdate.js.map +1 -0
  25. package/dist/repositoryWrites.d.ts +5 -2
  26. package/dist/repositoryWrites.d.ts.map +1 -1
  27. package/dist/repositoryWrites.js +19 -4
  28. package/dist/repositoryWrites.js.map +1 -1
  29. package/dist/tryPurgeLock.d.ts +4 -0
  30. package/dist/tryPurgeLock.d.ts.map +1 -0
  31. package/dist/tryPurgeLock.js +15 -0
  32. package/dist/tryPurgeLock.js.map +1 -0
  33. package/dist/versionedRepository.d.ts +3 -2
  34. package/dist/versionedRepository.d.ts.map +1 -1
  35. package/dist/versionedRepository.js.map +1 -1
  36. package/package.json +4 -4
  37. package/src/batchedDelete.ts +93 -0
  38. package/src/compositeRepository.ts +25 -34
  39. package/src/jsonb.ts +12 -0
  40. package/src/repository.ts +19 -17
  41. package/src/repositoryChanges.ts +9 -1
  42. package/src/repositoryUpdate.ts +65 -0
  43. package/src/repositoryWrites.ts +19 -4
  44. package/src/tryPurgeLock.ts +18 -0
  45. package/src/versionedRepository.ts +3 -2
@@ -1,6 +1,7 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { SqlSchema } from "effect/sql";
3
3
  import { makeFilter } from "./repositoryFilter.js";
4
+ import { selectedUpdate } from "./repositoryUpdate.js";
4
5
  export function repositoryWrites(model, sql, options, changes) {
5
6
  const { idColumns, tableName, spanPrefix } = options;
6
7
  const { where } = makeFilter(model, sql);
@@ -21,6 +22,15 @@ export function repositoryWrites(model, sql, options, changes) {
21
22
  const insertVoid = SqlSchema.void({ execute: insert, Request: model.insert });
22
23
  const updateRow = SqlSchema.findOne({ execute: update, Request: model.update, Result: model });
23
24
  const updateVoid = SqlSchema.void({ execute: update, Request: model.update });
25
+ function selected(input, columns, returning) {
26
+ return Effect.gen(function* () {
27
+ const row = yield* record(input);
28
+ const Request = yield* selectedUpdate(model, columns, idColumns, row);
29
+ return yield* returning
30
+ ? SqlSchema.findOne({ execute: update, Request, Result: model })(row)
31
+ : SqlSchema.void({ execute: update, Request })(row);
32
+ });
33
+ }
24
34
  const idColumn = idColumns[0] ?? "";
25
35
  const key = model.fields[idColumn];
26
36
  if (key === undefined) {
@@ -40,10 +50,15 @@ export function repositoryWrites(model, sql, options, changes) {
40
50
  delete: (id) => changes.write(remove(id)).pipe(Effect.withSpan(`${spanPrefix}.delete`)),
41
51
  insert: (input) => changes.write(insertRow(input).pipe(Effect.catchTag("NoSuchElementError", Effect.die))).pipe(Effect.withSpan(`${spanPrefix}.insert`)),
42
52
  insertVoid: (input) => changes.write(insertVoid(input)).pipe(Effect.withSpan(`${spanPrefix}.insertVoid`)),
43
- update: (input, settings) => changes
44
- .write(settings?.onMissing === "fail" ? updateRow(input) : updateRow(input).pipe(Effect.catchTag("NoSuchElementError", Effect.die)))
45
- .pipe(Effect.withSpan(`${spanPrefix}.update`)),
46
- updateVoid: (input) => changes.write(updateVoid(input)).pipe(Effect.withSpan(`${spanPrefix}.updateVoid`)),
53
+ update: (input, settings) => {
54
+ const result = settings?.columns === undefined ? updateRow(input) : selected(input, settings.columns, true);
55
+ return changes
56
+ .write(settings?.onMissing === "fail" ? result : result.pipe(Effect.catchTag("NoSuchElementError", Effect.die)))
57
+ .pipe(Effect.withSpan(`${spanPrefix}.update`));
58
+ },
59
+ updateVoid: (input, settings) => changes
60
+ .write(settings === undefined ? updateVoid(input) : selected(input, settings.columns, false))
61
+ .pipe(Effect.withSpan(`${spanPrefix}.updateVoid`)),
47
62
  };
48
63
  }
49
64
  //# sourceMappingURL=repositoryWrites.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"repositoryWrites.js","sourceRoot":"","sources":["../src/repositoryWrites.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,UAAU,gBAAgB,CAC/B,KAAgB,EAChB,GAAwB,EACxB,OAA2G,EAC3G,OAA0B;IAE1B,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IACrD,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACxF,MAAM,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACnG,SAAS,SAAS,CAAC,KAAwC;QAC1D,OAAO,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IACD,SAAS,MAAM,CAAC,KAAc;QAC7B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAC5C,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC;YAC7B,CAAC,CAAC,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,6BAA6B,OAAO,CAAC,SAAS,EAAE,EAAE;YACpF,CAAC,CAAC,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,SAAS,EAAE,EAAE,CACxF,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAClC,CAAC;IACH,CAAC;IACD,SAAS,MAAM,CAAC,KAAc;QAC7B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAC5C,GAAG,CAAA,UAAU,GAAG,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,UAAU,SAAS,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAC5H,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAC1B,CACD,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/F,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/F,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC;QAClC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CACf,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CACtD,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,UAAU,SAAS,CAAC,OAAO,CAAC,cAAc,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAChI;QACF,OAAO,EAAE,GAAG;KACZ,CAAC,CAAC;IACH,SAAS,MAAM,CAAC,KAAc;QAC7B,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC;YAC5C,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAC9C,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,UAAU,MAAM,cAAc,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CACnI,CACD,CAAC;IACL,CAAC;IACD,OAAO;QACN,MAAM,EAAE,CAAC,EAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;QAChG,MAAM,EAAE,CAAC,KAAc,EAAE,EAAE,CAC1B,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;QACtI,UAAU,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,aAAa,CAAC,CAAC;QAClH,MAAM,EAAE,CAAC,KAAc,EAAE,QAAyC,EAAE,EAAE,CACrE,OAAO;aACL,KAAK,CAAC,QAAQ,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;aACnI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;QAChD,UAAU,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,aAAa,CAAC,CAAC;KAClH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"repositoryWrites.js","sourceRoot":"","sources":["../src/repositoryWrites.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ export declare const tryPurgeLock: (tableName: string) => Effect.Effect<boolean, import("effect/sql/SqlError").SqlError, import("effect/Scope").Scope | SqlClient.SqlClient>;
4
+ //# sourceMappingURL=tryPurgeLock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tryPurgeLock.d.ts","sourceRoot":"","sources":["../src/tryPurgeLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,eAAO,MAAM,YAAY,2IAavB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ export const tryPurgeLock = Effect.fnUntraced(function* (tableName) {
4
+ const sql = yield* SqlClient.SqlClient;
5
+ const [identifier] = sql `${sql(tableName)}`.compile();
6
+ const key = sql `hashtextextended('@shivaedev/sql/deleteBatched:' || ${identifier}::regclass::oid::text, 0)`;
7
+ const connection = yield* sql.reserve;
8
+ function execute(statement) {
9
+ const [text, parameters] = statement.compile();
10
+ return connection.execute(text, parameters, undefined);
11
+ }
12
+ const [lock] = yield* Effect.acquireRelease(execute(sql `select pg_try_advisory_lock(${key}) as acquired`), (rows) => rows[0]?.acquired === true ? Effect.orDie(execute(sql `select pg_advisory_unlock(${key})`)) : Effect.void);
13
+ return lock?.acquired === true;
14
+ });
15
+ //# sourceMappingURL=tryPurgeLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tryPurgeLock.js","sourceRoot":"","sources":["../src/tryPurgeLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,SAAiB;IACzE,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAA,GAAG,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAA,uDAAuD,UAAU,2BAA2B,CAAC;IAC5G,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,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAA,+BAA+B,GAAG,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACnH,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAA,6BAA6B,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CACxG,CAAC;IACF,OAAO,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;AAChC,CAAC,CAAC,CAAC"}
@@ -4,6 +4,7 @@ import type { SqlClient, SqlModel } from "effect/sql";
4
4
  import type { SqlError } from "effect/sql/SqlError";
5
5
  import type { PrimaryKey, Repository } from "#compositeRepository.ts";
6
6
  import type { OptimisticConcurrencyError } from "#repository.ts";
7
+ import type { UpdateInput } from "#repositoryUpdate.ts";
7
8
  import { type VersionedOptions } from "#versionedStatements.ts";
8
9
  import type { RepositoryChanges } from "./repositoryChanges.ts";
9
10
  export type IdColumn<TModel extends Model.Any> = keyof TModel["Type"] & keyof TModel["update"]["Type"] & keyof TModel["fields"];
@@ -19,8 +20,8 @@ export interface VersionedWrites<TModel extends Model.Any, TId extends PrimaryKe
19
20
  readonly delete: (id: TId extends readonly IdColumn<TModel>[] ? Pick<TModel["Type"], TId[number]> : TModel["fields"][Extract<TId, IdColumn<TModel>>]["Type"], expectedVersion: number) => Effect.Effect<void, WriteError, TModel["fields"][KeyColumn<TModel, TId>]["EncodingServices"]>;
20
21
  readonly insert: Repository<TModel, TId>["insert"];
21
22
  readonly insertVoid: Repository<TModel, TId>["insertVoid"];
22
- readonly update: (input: TModel["update"]["Type"]) => Effect.Effect<TModel["Type"], WriteError, TModel["update"]["EncodingServices"] | TModel["DecodingServices"]>;
23
- readonly updateVoid: (input: TModel["update"]["Type"]) => Effect.Effect<void, WriteError, TModel["update"]["EncodingServices"]>;
23
+ readonly update: (input: UpdateInput<TModel>) => Effect.Effect<TModel["Type"], WriteError, TModel["update"]["EncodingServices"] | TModel["DecodingServices"]>;
24
+ readonly updateVoid: (input: UpdateInput<TModel>) => Effect.Effect<void, WriteError, TModel["update"]["EncodingServices"]>;
24
25
  }
25
26
  export declare function makeVersionedWrites(model: Model.Any, sql: SqlClient.SqlClient, options: VersionedOptions & {
26
27
  readonly changes: RepositoryChanges;
@@ -1 +1 @@
1
- {"version":3,"file":"versionedRepository.d.ts","sourceRoot":"","sources":["../src/versionedRepository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"versionedRepository.d.ts","sourceRoot":"","sources":["../src/versionedRepository.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"versionedRepository.js","sourceRoot":"","sources":["../src/versionedRepository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"versionedRepository.js","sourceRoot":"","sources":["../src/versionedRepository.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.29.0",
3
+ "version": "0.30.0",
4
4
  "description": "Schema-derived repositories over native Effect SQL",
5
5
  "keywords": [
6
6
  "effect"
@@ -50,9 +50,9 @@
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.52.0",
54
- "@shivaedev/test-sql": "0.15.2",
55
- "@shivaedev/test-story": "0.31.2",
53
+ "@shivaedev/quality": "0.53.0",
54
+ "@shivaedev/test-sql": "0.15.3",
55
+ "@shivaedev/test-story": "0.31.3",
56
56
  "@types/node": "24.19.2",
57
57
  "effect": "4.0.6",
58
58
  "typescript": "7.0.2",
@@ -0,0 +1,93 @@
1
+ import { Data, type Duration, Effect, Option, Schema } from "effect";
2
+ import type { Model } from "effect/schema";
3
+ import { SqlClient, SqlSchema } from "effect/sql";
4
+ import type { SqlError } from "effect/sql/SqlError";
5
+ import type { Fragment } from "effect/sql/Statement";
6
+ import type { RepositoryChanges } from "#repositoryChanges.ts";
7
+ import { type FindManyFilter, makeFilter } from "#repositoryFilter.ts";
8
+ import { tryPurgeLock } from "#tryPurgeLock.ts";
9
+
10
+ export interface BatchedDeleteOptions<TModel extends Model.Any> {
11
+ readonly batchSize: number;
12
+ readonly maxRows: number;
13
+ readonly pause: Duration.Input;
14
+ readonly where: FindManyFilter<TModel>;
15
+ }
16
+
17
+ export class BatchedDeleteUnavailable extends Data.TaggedError("BatchedDeleteUnavailable")<{
18
+ readonly reason: "transaction" | "dialect";
19
+ }> {}
20
+
21
+ export interface BatchedDelete<TModel extends Model.Any> {
22
+ readonly deleteBatched: (
23
+ options: BatchedDeleteOptions<TModel>,
24
+ ) => Effect.Effect<number, SqlError | Schema.SchemaError | BatchedDeleteUnavailable, TModel["fields"][keyof TModel["fields"]]["EncodingServices"]>;
25
+ }
26
+
27
+ const Positive = Schema.Number.check(Schema.isInt(), Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER));
28
+ const Nonnegative = Schema.Number.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER));
29
+ const Limits = Schema.Struct({ batchSize: Positive, maxRows: Nonnegative });
30
+
31
+ export const makeBatchedDelete = Effect.fnUntraced(function* (
32
+ model: Model.Any,
33
+ { tableName, spanPrefix }: { readonly tableName: string; readonly spanPrefix: string },
34
+ changes: RepositoryChanges,
35
+ ) {
36
+ const sql = yield* SqlClient.SqlClient;
37
+ const { where } = makeFilter(model, sql);
38
+ const available = Effect.gen(function* () {
39
+ if (sql.driver !== "pg") {
40
+ return yield* new BatchedDeleteUnavailable({ reason: "dialect" });
41
+ }
42
+ if (Option.isSome(yield* Effect.serviceOption(sql.transactionService))) {
43
+ return yield* new BatchedDeleteUnavailable({ reason: "transaction" });
44
+ }
45
+ });
46
+ function deleteBatch(predicate: Fragment, limit: number) {
47
+ const count = SqlSchema.findOne({
48
+ execute: (batchLimit) => sql`with removed as (
49
+ delete from ${sql(tableName)} where (tableoid, ctid) in (
50
+ select tableoid, ctid from ${sql(tableName)} where ${predicate} limit ${batchLimit} for update skip locked
51
+ ) returning 1
52
+ ) select count(*)::text as count from removed`,
53
+ Request: Schema.Number,
54
+ Result: Schema.Struct({ count: Schema.NumberFromString }),
55
+ });
56
+ return changes.write(
57
+ Effect.gen(function* () {
58
+ const result = yield* count(limit).pipe(Effect.catchTag("NoSuchElementError", Effect.die));
59
+ yield* changes.recordTable(result.count);
60
+ return result.count;
61
+ }),
62
+ );
63
+ }
64
+
65
+ const runBatches = Effect.fnUntraced(function* (options: BatchedDeleteOptions<Model.Any>, predicate: Fragment) {
66
+ const { batchSize, maxRows } = options;
67
+ let removed = 0;
68
+ while (removed < maxRows) {
69
+ const limit = Math.min(batchSize, maxRows - removed);
70
+ const count = yield* deleteBatch(predicate, limit);
71
+ removed += count;
72
+ if (count < limit || removed === maxRows) {
73
+ break;
74
+ }
75
+ yield* Effect.sleep(options.pause);
76
+ }
77
+ return removed;
78
+ });
79
+
80
+ return (options: BatchedDeleteOptions<Model.Any>) =>
81
+ Effect.gen(function* () {
82
+ yield* available;
83
+ const { maxRows } = yield* Schema.decodeUnknownEffect(Limits)(options);
84
+ const predicate = yield* where(options.where, true, true);
85
+ if (maxRows === 0) {
86
+ return 0;
87
+ }
88
+ if (!(yield* tryPurgeLock(tableName).pipe(Effect.provideService(SqlClient.SqlClient, sql)))) {
89
+ return 0;
90
+ }
91
+ return yield* runBatches(options, predicate);
92
+ }).pipe(Effect.scoped, Effect.withSpan(`${spanPrefix}.deleteBatched`));
93
+ });
@@ -3,8 +3,10 @@ import { Effect, Schema } from "effect";
3
3
  import type { Model } from "effect/schema";
4
4
  import { type SqlClient, SqlSchema } from "effect/sql";
5
5
  import type { SqlError } from "effect/sql/SqlError";
6
+ import type { BatchedDelete } from "#batchedDelete.ts";
6
7
  import type { RepositoryChanges } from "#repositoryChanges.ts";
7
8
  import type { RepositoryListFilter } from "#repositoryFilter.ts";
9
+ import type { Update, UpdateVoid } from "#repositoryUpdate.ts";
8
10
  import { repositoryWrites } from "#repositoryWrites.ts";
9
11
  import type { IdColumn, NativeRepository } from "#versionedRepository.ts";
10
12
 
@@ -14,41 +16,30 @@ type DeleteWhere<TModel extends Model.Any> = (
14
16
  where: RepositoryListFilter<TModel>,
15
17
  ) => Effect.Effect<void, SqlError | Schema.SchemaError, TModel["fields"][keyof TModel["fields"]]["EncodingServices"]>;
16
18
 
17
- interface Update<TModel extends Model.Any> {
18
- (
19
- input: TModel["update"]["Type"],
20
- options: { readonly onMissing: "fail" },
21
- ): Effect.Effect<
22
- TModel["Type"],
23
- SqlError | Schema.SchemaError | Cause.NoSuchElementError,
24
- TModel["update"]["EncodingServices"] | TModel["DecodingServices"]
25
- >;
26
- (
27
- input: TModel["update"]["Type"],
28
- ): Effect.Effect<TModel["Type"], SqlError | Schema.SchemaError, TModel["update"]["EncodingServices"] | TModel["DecodingServices"]>;
29
- }
30
-
31
- export type Repository<TModel extends Model.Any, TId extends PrimaryKey<TModel>> = [TId] extends [IdColumn<TModel>]
32
- ? Omit<NativeRepository<TModel, Extract<TId, IdColumn<TModel>>>, "delete" | "update"> & {
33
- readonly delete: NativeRepository<TModel, Extract<TId, IdColumn<TModel>>>["delete"] & DeleteWhere<TModel>;
34
- readonly update: Update<TModel>;
35
- }
36
- : TId extends CompositeKey<TModel>
37
- ? Omit<NativeRepository<TModel, TId[number]>, "findById" | "delete" | "update"> & {
38
- readonly update: Update<TModel>;
39
- readonly findById: (
40
- id: Pick<TModel["Type"], TId[number]>,
41
- ) => Effect.Effect<
42
- TModel["Type"],
43
- SqlError | Schema.SchemaError | Cause.NoSuchElementError,
44
- TModel["DecodingServices"] | TModel["fields"][TId[number]]["EncodingServices"]
45
- >;
46
- readonly delete: ((
47
- id: Pick<TModel["Type"], TId[number]>,
48
- ) => Effect.Effect<void, SqlError | Schema.SchemaError, TModel["fields"][TId[number]]["EncodingServices"]>) &
49
- DeleteWhere<TModel>;
19
+ export type Repository<TModel extends Model.Any, TId extends PrimaryKey<TModel>> = BatchedDelete<TModel> &
20
+ ([TId] extends [IdColumn<TModel>]
21
+ ? Omit<NativeRepository<TModel, Extract<TId, IdColumn<TModel>>>, "delete" | "update" | "updateVoid"> & {
22
+ readonly delete: NativeRepository<TModel, Extract<TId, IdColumn<TModel>>>["delete"] & DeleteWhere<TModel>;
23
+ readonly update: Update<TModel, TId extends readonly PropertyKey[] ? TId[number] : Extract<TId, PropertyKey>>;
24
+ readonly updateVoid: UpdateVoid<TModel, TId extends readonly PropertyKey[] ? TId[number] : Extract<TId, PropertyKey>>;
50
25
  }
51
- : never;
26
+ : TId extends CompositeKey<TModel>
27
+ ? Omit<NativeRepository<TModel, TId[number]>, "findById" | "delete" | "update" | "updateVoid"> & {
28
+ readonly update: Update<TModel, TId extends readonly PropertyKey[] ? TId[number] : Extract<TId, PropertyKey>>;
29
+ readonly updateVoid: UpdateVoid<TModel, TId extends readonly PropertyKey[] ? TId[number] : Extract<TId, PropertyKey>>;
30
+ readonly findById: (
31
+ id: Pick<TModel["Type"], TId[number]>,
32
+ ) => Effect.Effect<
33
+ TModel["Type"],
34
+ SqlError | Schema.SchemaError | Cause.NoSuchElementError,
35
+ TModel["DecodingServices"] | TModel["fields"][TId[number]]["EncodingServices"]
36
+ >;
37
+ readonly delete: ((
38
+ id: Pick<TModel["Type"], TId[number]>,
39
+ ) => Effect.Effect<void, SqlError | Schema.SchemaError, TModel["fields"][TId[number]]["EncodingServices"]>) &
40
+ DeleteWhere<TModel>;
41
+ }
42
+ : never);
52
43
 
53
44
  export function makeCompositeCrud(
54
45
  model: Model.Any,
package/src/jsonb.ts ADDED
@@ -0,0 +1,12 @@
1
+ import * as PgTypes from "@effect/sql-pg/PgTypes";
2
+ import { Schema, SchemaGetter } from "effect";
3
+
4
+ export function jsonb<TSchema extends Schema.Top>(schema: TSchema) {
5
+ return Schema.Unknown.pipe(
6
+ Schema.decodeTo(Schema.Unknown, {
7
+ decode: SchemaGetter.transform((value) => (PgTypes.isParameter(value) ? value.value : value)),
8
+ encode: SchemaGetter.transform(PgTypes.jsonb),
9
+ }),
10
+ Schema.decodeTo(schema),
11
+ );
12
+ }
package/src/repository.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Data, Effect, type Schema } from "effect";
2
2
  import type { Model } from "effect/schema";
3
3
  import { SqlClient } from "effect/sql";
4
+ import { makeBatchedDelete } from "#batchedDelete.ts";
4
5
  import { type BatchWrites, makeInsertMany } from "#batchWrites.ts";
5
6
  import { makeCompositeCrud, type PrimaryKey, type Repository } from "#compositeRepository.ts";
6
7
  import { type ConflictColumns, type ConflictWrites, makeConflictWrites } from "#conflictWrites.ts";
@@ -120,28 +121,29 @@ export function makeRepository<TModel extends Model.Any, TId extends IdColumn<TM
120
121
  const composite = typeof options.idColumn === "object";
121
122
  const idColumns = (composite ? options.idColumn : [options.idColumn]).map(String);
122
123
  const changes = yield* repositoryChanges(sql, options.tableName, idColumns, model.fields);
123
- const crud = makeCompositeCrud(model, sql, { ...options, columns: idColumns }, changes);
124
+ const crud = {
125
+ ...makeCompositeCrud(model, sql, { ...options, columns: idColumns }, changes),
126
+ deleteBatched: yield* makeBatchedDelete(model, options, changes),
127
+ };
124
128
  const queries = makeQueries(model, sql, options);
125
- return options.versionColumn === undefined
126
- ? {
127
- ...crud,
128
- insertFromSelect: makeInsertFromSelect(model, sql, { ...options, changes }, "insertFromSelect"),
129
- insertMany: makeInsertMany(model, sql, { ...options, changes }, "insertMany"),
130
- ...(options.conflictColumns === undefined
131
- ? {}
132
- : makeConflictWrites(model, sql, { ...options, changes, conflictColumns: options.conflictColumns, idColumns })),
133
- ...queries,
134
- }
135
- : {
136
- ...crud,
137
- ...makeVersionedWrites(model, sql, {
129
+ return {
130
+ ...crud,
131
+ ...queries,
132
+ ...(options.versionColumn === undefined
133
+ ? {
134
+ insertFromSelect: makeInsertFromSelect(model, sql, { ...options, changes }, "insertFromSelect"),
135
+ insertMany: makeInsertMany(model, sql, { ...options, changes }, "insertMany"),
136
+ ...(options.conflictColumns === undefined
137
+ ? {}
138
+ : makeConflictWrites(model, sql, { ...options, changes, conflictColumns: options.conflictColumns, idColumns })),
139
+ }
140
+ : makeVersionedWrites(model, sql, {
138
141
  ...options,
139
142
  changes,
140
143
  conflict: (id, expectedVersion, reason) => new OptimisticConcurrencyError({ expectedVersion, id, reason, tableName: options.tableName }),
141
144
  idColumns,
142
145
  versionColumn: options.versionColumn,
143
- }),
144
- ...queries,
145
- };
146
+ })),
147
+ };
146
148
  })();
147
149
  }
@@ -66,5 +66,13 @@ export const repositoryChanges = Effect.fnUntraced(function* (
66
66
  function write<A, E, R>(effect: Effect.Effect<A, E, R>) {
67
67
  return provide(transact(effect, { onSqlError: (error) => error }));
68
68
  }
69
- return { record, returning, write };
69
+ const recordTable = Effect.fnUntraced(function* (rows: number) {
70
+ if (rows === 0) {
71
+ return;
72
+ }
73
+ const declarations = yield* ChangeDeclarations;
74
+ yield* declarations.declare(table, [table], rows);
75
+ yield* provide(invalidateOnCommit([table]));
76
+ });
77
+ return { record, recordTable, returning, write };
70
78
  });
@@ -0,0 +1,65 @@
1
+ import type { Brand, Cause } from "effect";
2
+ import { Effect, Schema, SchemaAST, SchemaIssue } from "effect";
3
+ import type { Model } from "effect/schema";
4
+ import type { SqlError } from "effect/sql/SqlError";
5
+
6
+ type WithoutOverride<A> = A extends infer TValue & Brand.Brand<"Override"> ? TValue : A;
7
+ export type UpdateInput<TModel extends Model.Any> = {
8
+ readonly [TKey in keyof TModel["update"]["Type"]]: WithoutOverride<TModel["update"]["Type"][TKey]>;
9
+ };
10
+
11
+ type Column<TModel extends Model.Any, TId extends PropertyKey> = Exclude<Extract<keyof UpdateInput<TModel>, string>, TId>;
12
+ type Selected<TModel extends Model.Any, TId extends PropertyKey, TColumn extends PropertyKey> = Required<
13
+ Pick<UpdateInput<TModel>, Extract<TId | TColumn, keyof UpdateInput<TModel>>>
14
+ >;
15
+ interface Columns<TColumn> {
16
+ readonly columns: readonly [TColumn, ...TColumn[]];
17
+ }
18
+ type WriteResult<TModel extends Model.Any, A, E = never> = Effect.Effect<
19
+ A,
20
+ SqlError | Schema.SchemaError | E,
21
+ TModel["update"]["EncodingServices"] | TModel["DecodingServices"]
22
+ >;
23
+
24
+ export interface Update<TModel extends Model.Any, TId extends PropertyKey> {
25
+ <TColumn extends Column<TModel, TId>>(
26
+ input: Selected<TModel, TId, TColumn>,
27
+ options: Columns<TColumn> & { readonly onMissing: "fail" },
28
+ ): WriteResult<TModel, TModel["Type"], Cause.NoSuchElementError>;
29
+ <TColumn extends Column<TModel, TId>>(input: Selected<TModel, TId, TColumn>, options: Columns<TColumn>): WriteResult<TModel, TModel["Type"]>;
30
+ (input: UpdateInput<TModel>, options: { readonly onMissing: "fail" }): WriteResult<TModel, TModel["Type"], Cause.NoSuchElementError>;
31
+ (input: UpdateInput<TModel>): WriteResult<TModel, TModel["Type"]>;
32
+ }
33
+
34
+ export interface UpdateVoid<TModel extends Model.Any, TId extends PropertyKey> {
35
+ <TColumn extends Column<TModel, TId>>(
36
+ input: Selected<TModel, TId, TColumn>,
37
+ options: Columns<TColumn>,
38
+ ): Effect.Effect<void, SqlError | Schema.SchemaError, TModel["update"]["EncodingServices"]>;
39
+ (input: UpdateInput<TModel>): Effect.Effect<void, SqlError | Schema.SchemaError, TModel["update"]["EncodingServices"]>;
40
+ }
41
+
42
+ export const selectedUpdate = Effect.fnUntraced(function* (
43
+ model: Model.Any,
44
+ columns: readonly string[],
45
+ idColumns: readonly string[],
46
+ input: Readonly<Record<string, unknown>>,
47
+ ) {
48
+ const ast = model.update.ast;
49
+ const fields = SchemaAST.isObjects(ast) ? ast.propertySignatures : [];
50
+ const writable = new Set(fields.map((field) => String(field.name)));
51
+ const invalid = columns.find((column) => idColumns.includes(column) || !writable.has(column));
52
+ if (columns.length === 0 || invalid !== undefined) {
53
+ return yield* Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([invalid ?? ""], new SchemaIssue.UnexpectedKey(ast, invalid ?? ""))));
54
+ }
55
+ const missing = [...idColumns, ...columns].find((column) => !Object.hasOwn(input, column));
56
+ if (missing !== undefined) {
57
+ return yield* Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([missing], new SchemaIssue.MissingKey(undefined))));
58
+ }
59
+ return Schema.make(
60
+ new SchemaAST.Objects(
61
+ fields.filter((field) => [...idColumns, ...columns].includes(String(field.name))),
62
+ [],
63
+ ),
64
+ );
65
+ });
@@ -3,6 +3,7 @@ import type { Model } from "effect/schema";
3
3
  import { type SqlClient, SqlSchema } from "effect/sql";
4
4
  import type { RepositoryChanges } from "./repositoryChanges.ts";
5
5
  import { makeFilter } from "./repositoryFilter.ts";
6
+ import { selectedUpdate } from "./repositoryUpdate.ts";
6
7
 
7
8
  export function repositoryWrites(
8
9
  model: Model.Any,
@@ -36,6 +37,15 @@ export function repositoryWrites(
36
37
  const insertVoid = SqlSchema.void({ execute: insert, Request: model.insert });
37
38
  const updateRow = SqlSchema.findOne({ execute: update, Request: model.update, Result: model });
38
39
  const updateVoid = SqlSchema.void({ execute: update, Request: model.update });
40
+ function selected(input: unknown, columns: readonly string[], returning: boolean) {
41
+ return Effect.gen(function* () {
42
+ const row = yield* record(input);
43
+ const Request = yield* selectedUpdate(model, columns, idColumns, row);
44
+ return yield* returning
45
+ ? SqlSchema.findOne({ execute: update, Request, Result: model })(row)
46
+ : SqlSchema.void({ execute: update, Request })(row);
47
+ });
48
+ }
39
49
  const idColumn = idColumns[0] ?? "";
40
50
  const key = model.fields[idColumn];
41
51
  if (key === undefined) {
@@ -63,10 +73,15 @@ export function repositoryWrites(
63
73
  insert: (input: unknown) =>
64
74
  changes.write(insertRow(input).pipe(Effect.catchTag("NoSuchElementError", Effect.die))).pipe(Effect.withSpan(`${spanPrefix}.insert`)),
65
75
  insertVoid: (input: unknown) => changes.write(insertVoid(input)).pipe(Effect.withSpan(`${spanPrefix}.insertVoid`)),
66
- update: (input: unknown, settings?: { readonly onMissing: "fail" }) =>
76
+ update: (input: unknown, settings?: { readonly onMissing?: "fail"; readonly columns?: readonly string[] }) => {
77
+ const result = settings?.columns === undefined ? updateRow(input) : selected(input, settings.columns, true);
78
+ return changes
79
+ .write(settings?.onMissing === "fail" ? result : result.pipe(Effect.catchTag("NoSuchElementError", Effect.die)))
80
+ .pipe(Effect.withSpan(`${spanPrefix}.update`));
81
+ },
82
+ updateVoid: (input: unknown, settings?: { readonly columns: readonly string[] }) =>
67
83
  changes
68
- .write(settings?.onMissing === "fail" ? updateRow(input) : updateRow(input).pipe(Effect.catchTag("NoSuchElementError", Effect.die)))
69
- .pipe(Effect.withSpan(`${spanPrefix}.update`)),
70
- updateVoid: (input: unknown) => changes.write(updateVoid(input)).pipe(Effect.withSpan(`${spanPrefix}.updateVoid`)),
84
+ .write(settings === undefined ? updateVoid(input) : selected(input, settings.columns, false))
85
+ .pipe(Effect.withSpan(`${spanPrefix}.updateVoid`)),
71
86
  };
72
87
  }
@@ -0,0 +1,18 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/sql";
3
+ import type { Statement } from "effect/sql/Statement";
4
+
5
+ export const tryPurgeLock = Effect.fnUntraced(function* (tableName: string) {
6
+ const sql = yield* SqlClient.SqlClient;
7
+ const [identifier] = sql`${sql(tableName)}`.compile();
8
+ const key = sql`hashtextextended('@shivaedev/sql/deleteBatched:' || ${identifier}::regclass::oid::text, 0)`;
9
+ const connection = yield* sql.reserve;
10
+ function execute(statement: Statement<Readonly<Record<string, unknown>>>) {
11
+ const [text, parameters] = statement.compile();
12
+ return connection.execute(text, parameters, undefined);
13
+ }
14
+ const [lock] = yield* Effect.acquireRelease(execute(sql`select pg_try_advisory_lock(${key}) as acquired`), (rows) =>
15
+ rows[0]?.acquired === true ? Effect.orDie(execute(sql`select pg_advisory_unlock(${key})`)) : Effect.void,
16
+ );
17
+ return lock?.acquired === true;
18
+ });
@@ -4,6 +4,7 @@ import type { SqlClient, SqlModel } from "effect/sql";
4
4
  import type { SqlError } from "effect/sql/SqlError";
5
5
  import type { PrimaryKey, Repository } from "#compositeRepository.ts";
6
6
  import type { OptimisticConcurrencyError } from "#repository.ts";
7
+ import type { UpdateInput } from "#repositoryUpdate.ts";
7
8
  import { type VersionedOptions, versionedStatements } from "#versionedStatements.ts";
8
9
  import type { RepositoryChanges } from "./repositoryChanges.ts";
9
10
 
@@ -37,9 +38,9 @@ export interface VersionedWrites<TModel extends Model.Any, TId extends PrimaryKe
37
38
  readonly insert: Repository<TModel, TId>["insert"];
38
39
  readonly insertVoid: Repository<TModel, TId>["insertVoid"];
39
40
  readonly update: (
40
- input: TModel["update"]["Type"],
41
+ input: UpdateInput<TModel>,
41
42
  ) => Effect.Effect<TModel["Type"], WriteError, TModel["update"]["EncodingServices"] | TModel["DecodingServices"]>;
42
- readonly updateVoid: (input: TModel["update"]["Type"]) => Effect.Effect<void, WriteError, TModel["update"]["EncodingServices"]>;
43
+ readonly updateVoid: (input: UpdateInput<TModel>) => Effect.Effect<void, WriteError, TModel["update"]["EncodingServices"]>;
43
44
  }
44
45
 
45
46
  export function makeVersionedWrites(