@shivaedev/sql 0.0.0 → 0.22.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 (189) hide show
  1. package/CHANGELOG.md +275 -0
  2. package/LICENSE +21 -0
  3. package/README.md +613 -1
  4. package/dist/SchemaComponent.d.ts +9 -0
  5. package/dist/SchemaComponent.d.ts.map +1 -0
  6. package/dist/SchemaComponent.js +6 -0
  7. package/dist/SchemaComponent.js.map +1 -0
  8. package/dist/WorkerRelease.d.ts +14 -0
  9. package/dist/WorkerRelease.d.ts.map +1 -0
  10. package/dist/WorkerRelease.js +30 -0
  11. package/dist/WorkerRelease.js.map +1 -0
  12. package/dist/advisoryXactLock.d.ts +10 -0
  13. package/dist/advisoryXactLock.d.ts.map +1 -0
  14. package/dist/advisoryXactLock.js +18 -0
  15. package/dist/advisoryXactLock.js.map +1 -0
  16. package/dist/aggregateColumn.d.ts +8 -0
  17. package/dist/aggregateColumn.d.ts.map +1 -0
  18. package/dist/aggregateColumn.js +44 -0
  19. package/dist/aggregateColumn.js.map +1 -0
  20. package/dist/aggregateQuery.d.ts +51 -0
  21. package/dist/aggregateQuery.d.ts.map +1 -0
  22. package/dist/aggregateQuery.js +2 -0
  23. package/dist/aggregateQuery.js.map +1 -0
  24. package/dist/assertPostgresMigrations.d.ts +7 -0
  25. package/dist/assertPostgresMigrations.d.ts.map +1 -0
  26. package/dist/assertPostgresMigrations.js +20 -0
  27. package/dist/assertPostgresMigrations.js.map +1 -0
  28. package/dist/batchWrites.d.ts +16 -0
  29. package/dist/batchWrites.d.ts.map +1 -0
  30. package/dist/batchWrites.js +49 -0
  31. package/dist/batchWrites.js.map +1 -0
  32. package/dist/clientOptions.d.ts +8 -0
  33. package/dist/clientOptions.d.ts.map +1 -0
  34. package/dist/clientOptions.js +8 -0
  35. package/dist/clientOptions.js.map +1 -0
  36. package/dist/compositeRepository.d.ts +41 -0
  37. package/dist/compositeRepository.d.ts.map +1 -0
  38. package/dist/compositeRepository.js +38 -0
  39. package/dist/compositeRepository.js.map +1 -0
  40. package/dist/conditionalUpsert.d.ts +59 -0
  41. package/dist/conditionalUpsert.d.ts.map +1 -0
  42. package/dist/conditionalUpsert.js +28 -0
  43. package/dist/conditionalUpsert.js.map +1 -0
  44. package/dist/conflictWrites.d.ts +45 -0
  45. package/dist/conflictWrites.d.ts.map +1 -0
  46. package/dist/conflictWrites.js +40 -0
  47. package/dist/conflictWrites.js.map +1 -0
  48. package/dist/coordinateWorkerRelease.d.ts +5 -0
  49. package/dist/coordinateWorkerRelease.d.ts.map +1 -0
  50. package/dist/coordinateWorkerRelease.js +30 -0
  51. package/dist/coordinateWorkerRelease.js.map +1 -0
  52. package/dist/insertFromSelect.d.ts +24 -0
  53. package/dist/insertFromSelect.d.ts.map +1 -0
  54. package/dist/insertFromSelect.js +15 -0
  55. package/dist/insertFromSelect.js.map +1 -0
  56. package/dist/latestPerGroup.d.ts +11 -0
  57. package/dist/latestPerGroup.d.ts.map +1 -0
  58. package/dist/latestPerGroup.js +51 -0
  59. package/dist/latestPerGroup.js.map +1 -0
  60. package/dist/listenForChanges.d.ts +5 -0
  61. package/dist/listenForChanges.d.ts.map +1 -0
  62. package/dist/listenForChanges.js +75 -0
  63. package/dist/listenForChanges.js.map +1 -0
  64. package/dist/makeAggregate.d.ts +8 -0
  65. package/dist/makeAggregate.d.ts.map +1 -0
  66. package/dist/makeAggregate.js +38 -0
  67. package/dist/makeAggregate.js.map +1 -0
  68. package/dist/makeConflictClause.d.ts +10 -0
  69. package/dist/makeConflictClause.d.ts.map +1 -0
  70. package/dist/makeConflictClause.js +41 -0
  71. package/dist/makeConflictClause.js.map +1 -0
  72. package/dist/makeQueryClauses.d.ts +14 -0
  73. package/dist/makeQueryClauses.d.ts.map +1 -0
  74. package/dist/makeQueryClauses.js +20 -0
  75. package/dist/makeQueryClauses.js.map +1 -0
  76. package/dist/migrationConvention.d.ts +3 -0
  77. package/dist/migrationConvention.d.ts.map +1 -0
  78. package/dist/migrationConvention.js +3 -0
  79. package/dist/migrationConvention.js.map +1 -0
  80. package/dist/migrations.d.ts +12 -0
  81. package/dist/migrations.d.ts.map +1 -0
  82. package/dist/migrations.js +41 -0
  83. package/dist/migrations.js.map +1 -0
  84. package/dist/migrationsFromDirectory.d.ts +4 -0
  85. package/dist/migrationsFromDirectory.d.ts.map +1 -0
  86. package/dist/migrationsFromDirectory.js +7 -0
  87. package/dist/migrationsFromDirectory.js.map +1 -0
  88. package/dist/notifyPayload.d.ts +7 -0
  89. package/dist/notifyPayload.d.ts.map +1 -0
  90. package/dist/notifyPayload.js +31 -0
  91. package/dist/notifyPayload.js.map +1 -0
  92. package/dist/pendingPostgresMigrations.d.ts +24 -0
  93. package/dist/pendingPostgresMigrations.d.ts.map +1 -0
  94. package/dist/pendingPostgresMigrations.js +30 -0
  95. package/dist/pendingPostgresMigrations.js.map +1 -0
  96. package/dist/pinnedGroups.d.ts +22 -0
  97. package/dist/pinnedGroups.d.ts.map +1 -0
  98. package/dist/pinnedGroups.js +35 -0
  99. package/dist/pinnedGroups.js.map +1 -0
  100. package/dist/postgresChanges.d.ts +20 -0
  101. package/dist/postgresChanges.d.ts.map +1 -0
  102. package/dist/postgresChanges.js +26 -0
  103. package/dist/postgresChanges.js.map +1 -0
  104. package/dist/postgresRelease.d.ts +9 -0
  105. package/dist/postgresRelease.d.ts.map +1 -0
  106. package/dist/postgresRelease.js +39 -0
  107. package/dist/postgresRelease.js.map +1 -0
  108. package/dist/releaseWorkers.d.ts +8 -0
  109. package/dist/releaseWorkers.d.ts.map +1 -0
  110. package/dist/releaseWorkers.js +26 -0
  111. package/dist/releaseWorkers.js.map +1 -0
  112. package/dist/repository.d.ts +66 -0
  113. package/dist/repository.d.ts.map +1 -0
  114. package/dist/repository.js +43 -0
  115. package/dist/repository.js.map +1 -0
  116. package/dist/repositoryChanges.d.ts +9 -0
  117. package/dist/repositoryChanges.d.ts.map +1 -0
  118. package/dist/repositoryChanges.js +32 -0
  119. package/dist/repositoryChanges.js.map +1 -0
  120. package/dist/repositoryFilter.d.ts +43 -0
  121. package/dist/repositoryFilter.d.ts.map +1 -0
  122. package/dist/repositoryFilter.js +69 -0
  123. package/dist/repositoryFilter.js.map +1 -0
  124. package/dist/repositoryQueries.d.ts +26 -0
  125. package/dist/repositoryQueries.d.ts.map +1 -0
  126. package/dist/repositoryQueries.js +49 -0
  127. package/dist/repositoryQueries.js.map +1 -0
  128. package/dist/repositoryWrites.d.ts +18 -0
  129. package/dist/repositoryWrites.d.ts.map +1 -0
  130. package/dist/repositoryWrites.js +49 -0
  131. package/dist/repositoryWrites.js.map +1 -0
  132. package/dist/testing.d.ts +12 -0
  133. package/dist/testing.d.ts.map +1 -0
  134. package/dist/testing.js +29 -0
  135. package/dist/testing.js.map +1 -0
  136. package/dist/transact.d.ts +18 -0
  137. package/dist/transact.d.ts.map +1 -0
  138. package/dist/transact.js +43 -0
  139. package/dist/transact.js.map +1 -0
  140. package/dist/tupleIn.d.ts +19 -0
  141. package/dist/tupleIn.d.ts.map +1 -0
  142. package/dist/tupleIn.js +20 -0
  143. package/dist/tupleIn.js.map +1 -0
  144. package/dist/versionedRepository.d.ts +37 -0
  145. package/dist/versionedRepository.d.ts.map +1 -0
  146. package/dist/versionedRepository.js +63 -0
  147. package/dist/versionedRepository.js.map +1 -0
  148. package/dist/versionedStatements.d.ts +25 -0
  149. package/dist/versionedStatements.d.ts.map +1 -0
  150. package/dist/versionedStatements.js +75 -0
  151. package/dist/versionedStatements.js.map +1 -0
  152. package/package.json +71 -4
  153. package/src/SchemaComponent.ts +12 -0
  154. package/src/WorkerRelease.ts +38 -0
  155. package/src/advisoryXactLock.ts +17 -0
  156. package/src/aggregateColumn.ts +49 -0
  157. package/src/aggregateQuery.ts +57 -0
  158. package/src/assertPostgresMigrations.ts +24 -0
  159. package/src/batchWrites.ts +69 -0
  160. package/src/clientOptions.ts +16 -0
  161. package/src/compositeRepository.ts +101 -0
  162. package/src/conditionalUpsert.ts +97 -0
  163. package/src/conflictWrites.ts +93 -0
  164. package/src/coordinateWorkerRelease.ts +33 -0
  165. package/src/insertFromSelect.ts +47 -0
  166. package/src/latestPerGroup.ts +58 -0
  167. package/src/listenForChanges.ts +97 -0
  168. package/src/makeAggregate.ts +64 -0
  169. package/src/makeConflictClause.ts +53 -0
  170. package/src/makeQueryClauses.ts +36 -0
  171. package/src/migrationConvention.ts +2 -0
  172. package/src/migrations.ts +58 -0
  173. package/src/migrationsFromDirectory.ts +7 -0
  174. package/src/notifyPayload.ts +34 -0
  175. package/src/pendingPostgresMigrations.ts +42 -0
  176. package/src/pinnedGroups.ts +46 -0
  177. package/src/postgresChanges.ts +48 -0
  178. package/src/postgresRelease.ts +41 -0
  179. package/src/releaseWorkers.ts +32 -0
  180. package/src/repository.ts +147 -0
  181. package/src/repositoryChanges.ts +49 -0
  182. package/src/repositoryFilter.ts +108 -0
  183. package/src/repositoryQueries.ts +107 -0
  184. package/src/repositoryWrites.ts +70 -0
  185. package/src/testing.ts +38 -0
  186. package/src/transact.ts +70 -0
  187. package/src/tupleIn.ts +44 -0
  188. package/src/versionedRepository.ts +108 -0
  189. package/src/versionedStatements.ts +90 -0
@@ -0,0 +1,45 @@
1
+ import { Effect, Option, Schema } from "effect";
2
+ import type { Model } from "effect/schema";
3
+ import type { SqlClient } from "effect/sql";
4
+ import type { SqlError } from "effect/sql/SqlError";
5
+ import { type InsertMany } from "#batchWrites.ts";
6
+ import { type ConditionalUpsert, type ConditionalUpsertMany } from "#conditionalUpsert.ts";
7
+ import { type InsertFromSelect } from "#insertFromSelect.ts";
8
+ import type { RepositoryChanges } from "./repositoryChanges.ts";
9
+ export type InsertColumn<TModel extends Model.Any> = Extract<keyof TModel["insert"]["Type"] & keyof TModel["fields"], string>;
10
+ export type ConflictColumns<TModel extends Model.Any> = readonly [InsertColumn<TModel>, ...InsertColumn<TModel>[]];
11
+ interface UpdateOptions<TModel extends Model.Any, TExcluded extends PropertyKey> {
12
+ readonly updateColumns: readonly [
13
+ Exclude<InsertColumn<TModel> & keyof TModel["update"]["Type"], TExcluded>,
14
+ ...Exclude<InsertColumn<TModel> & keyof TModel["update"]["Type"], TExcluded>[]
15
+ ];
16
+ }
17
+ export interface ConflictWrites<TModel extends Model.Any, TExcluded extends PropertyKey, TFilterServices = never> {
18
+ readonly insertFromSelectOrIgnore: InsertFromSelect<TModel, TFilterServices>;
19
+ readonly insertManyOrIgnore: InsertMany<TModel, TFilterServices>;
20
+ readonly insertOrIgnore: (input: TModel["insert"]["Type"]) => Effect.Effect<Option.Option<TModel["Type"]>, SqlError | Schema.SchemaError, TModel["insert"]["EncodingServices"] | TModel["DecodingServices"] | TFilterServices>;
21
+ readonly upsert: ConditionalUpsert<TModel, UpdateOptions<TModel, TExcluded>, TModel["insert"]["EncodingServices"] | TModel["DecodingServices"] | TFilterServices>;
22
+ readonly upsertMany: ConditionalUpsertMany<TModel, UpdateOptions<TModel, TExcluded>, TModel["insert"]["EncodingServices"] | TModel["DecodingServices"] | TFilterServices>;
23
+ }
24
+ export declare function makeConflictWrites(model: Model.Any, sql: SqlClient.SqlClient, options: {
25
+ readonly changes: RepositoryChanges;
26
+ readonly tableName: string;
27
+ readonly spanPrefix: string;
28
+ readonly conflictColumns: readonly string[];
29
+ readonly conflictWhere?: Readonly<Record<string, unknown>>;
30
+ readonly idColumns: readonly string[];
31
+ }): {
32
+ insertFromSelectOrIgnore: (source: import("./repositoryQueries.ts").RepositorySelect<Schema.Struct.Fields, unknown>, columns: Readonly<Record<string, string>>) => Effect.Effect<readonly unknown[], Schema.SchemaError | SqlError, unknown>;
33
+ insertManyOrIgnore: (inputs: readonly unknown[]) => Effect.Effect<unknown[], Schema.SchemaError | SqlError, unknown>;
34
+ insertOrIgnore: (input: unknown) => Effect.Effect<Option.None<unknown> | Option.Some<unknown>, Schema.SchemaError | SqlError, unknown>;
35
+ upsert: (input: unknown, settings: {
36
+ readonly updateColumns: readonly string[];
37
+ readonly updateWhere?: Readonly<Record<string, unknown>>;
38
+ }) => Effect.Effect<unknown, Schema.SchemaError | SqlError, unknown>;
39
+ upsertMany: (inputs: readonly unknown[], settings: {
40
+ readonly updateColumns: readonly string[];
41
+ readonly updateWhere?: Readonly<Record<string, unknown>>;
42
+ }) => Effect.Effect<unknown[], Schema.SchemaError | SqlError, unknown>;
43
+ };
44
+ export {};
45
+ //# sourceMappingURL=conflictWrites.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflictWrites.d.ts","sourceRoot":"","sources":["../src/conflictWrites.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { Effect, Option, Schema } from "effect";
2
+ import { makeInsertMany } from "#batchWrites.ts";
3
+ import { makeConditionalUpsert } from "#conditionalUpsert.ts";
4
+ import { makeInsertFromSelect } from "#insertFromSelect.ts";
5
+ import { makeConflictClause } from "#makeConflictClause.ts";
6
+ export function makeConflictWrites(model, sql, options) {
7
+ const { tableName, spanPrefix } = options;
8
+ const encode = Schema.encodeEffect(model.insert);
9
+ const decode = Schema.decodeUnknownEffect(model);
10
+ const record = Schema.decodeUnknownEffect(Schema.Record(Schema.String, Schema.Unknown));
11
+ const conditional = makeConditionalUpsert(model, sql, options);
12
+ const clause = makeConflictClause(model, sql, options);
13
+ function statement(input, updateColumns) {
14
+ return Effect.gen(function* () {
15
+ const encoded = yield* record(yield* encode(input));
16
+ const suffix = yield* clause(encoded, updateColumns);
17
+ return sql `insert into ${sql(tableName)} ${sql.insert(encoded)} ${suffix} returning *`;
18
+ });
19
+ }
20
+ return {
21
+ insertFromSelectOrIgnore: makeInsertFromSelect(model, sql, options, "insertFromSelectOrIgnore", (columns) => clause(Object.fromEntries(columns.map((key) => [key, undefined])))),
22
+ insertManyOrIgnore: makeInsertMany(model, sql, options, "insertManyOrIgnore", (row) => clause(row)),
23
+ insertOrIgnore: (input) => Effect.gen(function* () {
24
+ const rows = yield* yield* statement(input);
25
+ yield* options.changes.record(rows);
26
+ return rows.length === 0 ? Option.none() : Option.some(yield* decode(rows[0]));
27
+ }).pipe(options.changes.write, Effect.withSpan(`${spanPrefix}.insertOrIgnore`)),
28
+ upsert: (input, settings) => settings.updateWhere === undefined
29
+ ? Effect.gen(function* () {
30
+ const rows = yield* yield* statement(input, settings.updateColumns);
31
+ yield* options.changes.record(rows);
32
+ return yield* decode(rows[0]);
33
+ }).pipe(options.changes.write, Effect.withSpan(`${spanPrefix}.upsert`))
34
+ : conditional([input], { ...settings, updateWhere: settings.updateWhere }).pipe(Effect.map((results) => results[0])),
35
+ upsertMany: (inputs, settings) => settings.updateWhere === undefined
36
+ ? makeInsertMany(model, sql, options, "upsertMany", (row) => clause(row, settings.updateColumns))(inputs)
37
+ : conditional(inputs, { ...settings, updateWhere: settings.updateWhere }),
38
+ };
39
+ }
40
+ //# sourceMappingURL=conflictWrites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflictWrites.js","sourceRoot":"","sources":["../src/conflictWrites.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Duration, Effect } from "effect";
2
+ export declare const coordinateWorkerRelease: (release: string, pollInterval?: Duration.Input | undefined, table?: any) => Effect.Effect<{
3
+ readonly register: <E>(control: (active: boolean) => Effect.Effect<void, E>) => Effect.Effect<void, E, import("effect/Scope").Scope>;
4
+ }, import("effect/sql/SqlError").SqlError, import("effect/Scope").Scope | import("effect/sql/SqlClient").SqlClient>;
5
+ //# sourceMappingURL=coordinateWorkerRelease.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinateWorkerRelease.d.ts","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAK1C,eAAO,MAAM,uBAAuB;;mHA2BlC,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { Duration, Effect } from "effect";
2
+ import { readPostgresRelease } from "./postgresRelease.js";
3
+ import { releaseWorkers } from "./releaseWorkers.js";
4
+ import { makeWorkerRelease } from "./WorkerRelease.js";
5
+ export const coordinateWorkerRelease = Effect.fn("EffectSql.coordinateWorkerRelease")(function* (release, pollInterval = "1 second", table = "effect_sql_migrations") {
6
+ const gate = yield* makeWorkerRelease();
7
+ const rows = yield* releaseWorkers(release, Duration.toMillis(pollInterval) * 5, table);
8
+ let claimed = false;
9
+ const poll = Effect.gen(function* () {
10
+ const owner = yield* readPostgresRelease(table);
11
+ if (owner?.release !== release) {
12
+ yield* gate.setActive(false).pipe(Effect.orDie);
13
+ yield* rows.remove;
14
+ claimed = false;
15
+ }
16
+ else if (!claimed) {
17
+ claimed = yield* rows.claim;
18
+ if (claimed) {
19
+ yield* gate.setActive(true).pipe(Effect.orDie);
20
+ }
21
+ }
22
+ });
23
+ yield* Effect.addFinalizer(() => rows.remove.pipe(Effect.orDie));
24
+ // Heartbeats continue while offWork waits for active jobs to finish.
25
+ yield* Effect.forever(Effect.sleep(pollInterval).pipe(Effect.andThen(rows.heartbeat))).pipe(Effect.orDie, Effect.forkScoped);
26
+ yield* poll;
27
+ yield* Effect.forever(Effect.sleep(pollInterval).pipe(Effect.andThen(poll))).pipe(Effect.orDie, Effect.forkScoped);
28
+ return gate.service;
29
+ });
30
+ //# sourceMappingURL=coordinateWorkerRelease.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinateWorkerRelease.js","sourceRoot":"","sources":["../src/coordinateWorkerRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAC,QAAQ,CAAC,EAC9F,OAAe,EACf,YAAY,GAAmB,UAAU,EACzC,KAAK,GAAG,uBAAuB;IAE/B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,iBAAiB,EAAE,CAAC;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACxF,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,KAAK,EAAE,OAAO,KAAK,OAAO,EAAE,CAAC;YAChC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChD,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;YACnB,OAAO,GAAG,KAAK,CAAC;QACjB,CAAC;aAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACrB,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;YAC5B,IAAI,OAAO,EAAE,CAAC;gBACb,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChD,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACjE,qEAAqE;IACrE,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7H,KAAK,CAAC,CAAC,IAAI,CAAC;IACZ,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IACnH,OAAO,IAAI,CAAC,OAAO,CAAC;AACrB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { Model } from "effect/schema";
3
+ import type { SqlClient } 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 { RepositorySelect } from "#repositoryQueries.ts";
8
+ type CompatibleColumn<TType, TEncoded, TFields extends Schema.Struct.Fields> = {
9
+ [TKey in keyof TFields]: TFields[TKey]["Type"] extends TType ? (TFields[TKey]["Encoded"] extends TEncoded ? TKey : never) : never;
10
+ }[keyof TFields] & string;
11
+ type ColumnMapping<TInput, TEncoded, TFields extends Schema.Struct.Fields> = {
12
+ [TKey in keyof TInput]: CompatibleColumn<TInput[TKey], TEncoded[Extract<TKey, keyof TEncoded>], TFields>;
13
+ };
14
+ export type InsertFromSelect<TModel extends Model.Any, TServices = never> = <TFields extends Schema.Struct.Fields, TSourceServices>(source: RepositorySelect<TFields, TSourceServices>, columns: ColumnMapping<TModel["insert"]["Type"], TModel["insert"]["Encoded"], TFields>) => Effect.Effect<TModel["Type"][], SqlError | Schema.SchemaError, TSourceServices | TModel["DecodingServices"] | TServices>;
15
+ export interface SelectWrites<TModel extends Model.Any> {
16
+ readonly insertFromSelect: InsertFromSelect<TModel>;
17
+ }
18
+ export declare function makeInsertFromSelect<TServices = never>(model: Model.Any, sql: SqlClient.SqlClient, options: {
19
+ readonly tableName: string;
20
+ readonly spanPrefix: string;
21
+ readonly changes: RepositoryChanges;
22
+ }, operation: string, prepare?: (columns: readonly string[]) => Effect.Effect<Fragment, Schema.SchemaError, TServices>): (source: RepositorySelect<Schema.Struct.Fields, unknown>, columns: Readonly<Record<string, string>>) => Effect.Effect<readonly unknown[], Schema.SchemaError | SqlError, unknown>;
23
+ export {};
24
+ //# sourceMappingURL=insertFromSelect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insertFromSelect.d.ts","sourceRoot":"","sources":["../src/insertFromSelect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,KAAK,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI;KAC7E,IAAI,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,SAAS,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK;CACjI,CAAC,MAAM,OAAO,CAAC,GACf,MAAM,CAAC;AAER,KAAK,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI;KAC3E,IAAI,IAAI,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACxG,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,KAAK,IAAI,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,EACjI,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,EAClD,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,KAClF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC,CAAC;AAE9H,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG;IACrD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;CACpD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,GAAG,KAAK,EACrD,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,GAAG,EAAE,SAAS,CAAC,SAAS,EACxB,OAAO,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,EACzG,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,CAA+B,YAG7G,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,+EAY1G"}
@@ -0,0 +1,15 @@
1
+ import { Effect, Schema } from "effect";
2
+ export function makeInsertFromSelect(model, sql, options, operation, prepare = () => Effect.succeed(sql ``)) {
3
+ const decode = Schema.decodeUnknownEffect(Schema.Array(model));
4
+ return (source, columns) => Effect.gen(function* () {
5
+ const names = Object.keys(columns);
6
+ const selected = sql.csv(Object.values(columns).map((column) => sql `${sql(column)}`));
7
+ const target = sql.csv(names.map((column) => sql `${sql(column)}`));
8
+ const suffix = yield* prepare(names);
9
+ const statement = yield* source.statement;
10
+ const rows = yield* sql `insert into ${sql(options.tableName)} (${target}) select ${selected} from (${statement}) as ${sql("source")} where true ${suffix} returning *`;
11
+ yield* options.changes.record(rows);
12
+ return yield* decode(rows);
13
+ }).pipe(options.changes.write, Effect.withSpan(`${options.spanPrefix}.${operation}`));
14
+ }
15
+ //# sourceMappingURL=insertFromSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insertFromSelect.js","sourceRoot":"","sources":["../src/insertFromSelect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AA0BxC,MAAM,UAAU,oBAAoB,CACnC,KAAgB,EAChB,GAAwB,EACxB,OAAyG,EACzG,SAAiB,EACjB,OAAO,GAA2F,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAA,EAAE,CAAC;IAE7H,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,MAAuD,EAAE,OAAyC,EAAE,EAAE,CAC7G,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QACtF,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QACnE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;QAC1C,MAAM,IAAI,GACT,KAAK,CAAC,CAAC,GAAG,CAAA,eAAe,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,MAAM,YAAY,QAAQ,UAAU,SAAS,QAAQ,GAAG,CAAC,QAAQ,CAAC,eAAe,MAAM,cAAc,CAAC;QAC3J,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,UAAU,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC;AACxF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { Model } from "effect/schema";
3
+ import type { SqlClient } from "effect/sql";
4
+ import type { Fragment } from "effect/sql/Statement";
5
+ import type { LatestPerGroup } from "#repository.ts";
6
+ export declare function latestPerGroup(model: Model.Any, sql: SqlClient.SqlClient, tableName: string): (query: LatestPerGroup<Model.Any>, order: Fragment, rowLimit: number) => Effect.Effect<readonly {
7
+ readonly [x: string]: unknown;
8
+ readonly [x: number]: unknown;
9
+ readonly [x: symbol]: unknown;
10
+ }[], Schema.SchemaError | import("effect/sql/SqlError").SqlError, unknown>;
11
+ //# sourceMappingURL=latestPerGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestPerGroup.d.ts","sourceRoot":"","sources":["../src/latestPerGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM;;;;2EAiD3F"}
@@ -0,0 +1,51 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { pinnedGroups } from "#pinnedGroups.ts";
3
+ import { makeFilter } from "#repositoryFilter.ts";
4
+ export function latestPerGroup(model, sql, tableName) {
5
+ const { fieldAt, where } = makeFilter(model, sql);
6
+ return Effect.fnUntraced(function* (query, order, rowLimit) {
7
+ yield* Effect.forEach(query.partitionBy, fieldAt);
8
+ const predicate = yield* where(query.where, true);
9
+ const partitions = sql.csv(query.partitionBy.map((key) => sql `${sql(key)}`));
10
+ const keys = Object.keys(model.fields);
11
+ const columns = sql.csv(keys.map((key) => sql `${sql(key)}`));
12
+ const pinned = yield* pinnedGroups(model, sql, query.partitionBy, query.where);
13
+ if (pinned !== undefined && pinned.groups.length === 0) {
14
+ return [];
15
+ }
16
+ if (pinned !== undefined && sql.onDialectOrElse({ orElse: () => false, pg: () => true })) {
17
+ const remaining = yield* where(pinned.remaining, true);
18
+ const masks = new Map();
19
+ for (const group of pinned.groups) {
20
+ const mask = group.map((value) => (value === null ? "0" : "1")).join("");
21
+ const groups = masks.get(mask) ?? [];
22
+ groups.push(group);
23
+ masks.set(mask, groups);
24
+ }
25
+ const branches = Array.from(masks.values(), (groups) => {
26
+ const values = sql.join(" union ", false)(groups.map((group) => sql `select ${sql.csv(group.map((value) => sql `${value}`))}`));
27
+ const matches = query.partitionBy.map((key, index) => groups[0]?.[index] === null ? sql `${sql(key)} is null` : sql `${sql(key)} = ${sql("__effect_sql_groups")}.${sql(key)}`);
28
+ // The empty table projection gives encoded parameters their actual PostgreSQL column types.
29
+ return sql `select ${sql("__effect_sql_latest")}.* from (
30
+ select ${partitions} from ${sql(tableName)} where false union ${values}
31
+ ) as ${sql("__effect_sql_groups")} cross join lateral (
32
+ select ${columns} from ${sql(tableName)} where ${sql.and([...matches, remaining])} ${order} limit ${rowLimit}
33
+ ) as ${sql("__effect_sql_latest")}`;
34
+ });
35
+ const ordering = sql.csv(query.orderBy.map(({ field, direction }) => sql `${sql(field)} ${sql.literal(direction === "desc" ? "desc" : "asc")}`));
36
+ const rows = yield* sql `select ${columns} from (${sql.join(" union all ")(branches)}) as ${sql("__effect_sql_pinned")} order by ${partitions}, ${ordering}`;
37
+ return yield* Schema.decodeUnknownEffect(Schema.Array(Schema.Struct(model.fields)))(rows);
38
+ }
39
+ let rankColumn = "__effect_sql_rank";
40
+ while (Object.hasOwn(model.fields, rankColumn)) {
41
+ rankColumn += "_";
42
+ }
43
+ const rows = yield* sql `select ${columns} from (
44
+ select ${columns}, row_number() over (partition by ${partitions} ${order}) as ${sql(rankColumn)}
45
+ from ${sql(tableName)} where ${predicate}
46
+ ) as ${sql("__effect_sql_ranked")} where ${sql(rankColumn)} <= ${rowLimit}
47
+ order by ${partitions}, ${sql(rankColumn)}`;
48
+ return yield* Schema.decodeUnknownEffect(Schema.Array(Schema.Struct(model.fields)))(rows);
49
+ });
50
+ }
51
+ //# sourceMappingURL=latestPerGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestPerGroup.js","sourceRoot":"","sources":["../src/latestPerGroup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Effect, Scope } from "effect";
2
+ import * as Reactivity from "effect/reactivity/Reactivity";
3
+ import type { PostgresChangesOptions } from "./postgresChanges.ts";
4
+ export declare const listenForChanges: (options: PostgresChangesOptions) => Effect.Effect<void, never, Reactivity.Reactivity | Scope.Scope>;
5
+ //# sourceMappingURL=listenForChanges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listenForChanges.d.ts","sourceRoot":"","sources":["../src/listenForChanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,MAAM,EAAoB,KAAK,EAAE,MAAM,QAAQ,CAAC;AACzF,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAE3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAuBnE,eAAO,MAAM,gBAAgB,sGAsE3B,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { Clock, Deferred, Effect, Queue, Scope } from "effect";
2
+ import * as Reactivity from "effect/reactivity/Reactivity";
3
+ import { decodeKeys } from "./notifyPayload.js";
4
+ function closeListener(scope, outcome, timeout) {
5
+ return Effect.suspend(() => {
6
+ function bounded(finalizer) {
7
+ return (exit) => finalizer(exit).pipe(Effect.interruptible, Effect.timeoutOption(timeout), Effect.asVoid);
8
+ }
9
+ // Bound each finalizer so a stalled UNLISTEN cannot prevent the native connection release that follows it.
10
+ if (scope.state._tag === "Open") {
11
+ const state = scope.state;
12
+ if (state.finalizer !== undefined) {
13
+ state.finalizer = bounded(state.finalizer);
14
+ }
15
+ if (state.finalizers !== undefined) {
16
+ for (const [key, finalizer] of state.finalizers) {
17
+ state.finalizers.set(key, bounded(finalizer));
18
+ }
19
+ }
20
+ }
21
+ return Scope.closeUnsafe(scope, outcome) ?? Effect.void;
22
+ });
23
+ }
24
+ export const listenForChanges = Effect.fn("PostgresChanges.listenForChanges")(function* (options) {
25
+ const ready = yield* Deferred.make();
26
+ const reactivity = yield* Reactivity.Reactivity;
27
+ const { client, channel, resync } = options;
28
+ const timeout = options.heartbeatTimeout ?? "10 seconds";
29
+ let lostAt;
30
+ const attempt = Effect.scoped(Effect.gen(function* () {
31
+ const scope = yield* Effect.acquireRelease(Scope.make(), (listenerScope, exit) => closeListener(listenerScope, exit, timeout));
32
+ const token = JSON.stringify({ heartbeat: crypto.randomUUID() });
33
+ let ack = yield* Deferred.make();
34
+ function receive(payload) {
35
+ if (payload === token) {
36
+ return Effect.asVoid(Deferred.succeed(ack, undefined));
37
+ }
38
+ if (!payload.startsWith("[")) {
39
+ return Effect.void;
40
+ }
41
+ return decodeKeys(payload).pipe(Effect.flatMap((keys) => Effect.sync(() => reactivity.invalidateUnsafe(keys))), Effect.catchCause(() => resync));
42
+ }
43
+ const listening = Effect.gen(function* () {
44
+ const notifications = yield* client.listen(channel).pipe(Scope.provide(scope));
45
+ yield* Effect.forever(Effect.flatMap(Queue.takeAll(notifications), (batch) => Effect.forEach(batch, (notification) => receive(notification.payload), { discard: true })));
46
+ });
47
+ const send = Effect.asVoid(client `select pg_notify(${channel}, ${token})`);
48
+ const monitor = Effect.gen(function* () {
49
+ yield* Effect.raceFirst(Deferred.await(ack), Effect.forever(Effect.andThen(send, Effect.sleep("50 millis")))).pipe(Effect.timeout(timeout));
50
+ const streamCount = yield* resync;
51
+ if (lostAt !== undefined) {
52
+ const downtimeMs = (yield* Clock.currentTimeMillis) - lostAt;
53
+ yield* Effect.logInfo("PostgreSQL change listener recovered; resynchronized live streams").pipe(Effect.annotateLogs({ downtimeMs, streamCount }));
54
+ lostAt = undefined;
55
+ }
56
+ yield* Deferred.succeed(ready, undefined);
57
+ yield* Effect.forever(Effect.gen(function* () {
58
+ yield* Effect.sleep(options.heartbeatInterval ?? "5 seconds");
59
+ ack = yield* Deferred.make();
60
+ yield* Effect.andThen(send, Deferred.await(ack)).pipe(Effect.timeout(timeout));
61
+ }));
62
+ });
63
+ yield* Effect.raceFirst(listening, monitor).pipe(Effect.onExit(() => resync));
64
+ }));
65
+ yield* Effect.forever(attempt.pipe(Effect.catchCause(() => Effect.gen(function* () {
66
+ if (lostAt !== undefined) {
67
+ yield* Effect.logDebug("PostgreSQL change listener reconnect failed; retrying");
68
+ return;
69
+ }
70
+ lostAt = yield* Clock.currentTimeMillis;
71
+ yield* Effect.logWarning("PostgreSQL change listener lost; resynchronizing live streams");
72
+ })), Effect.andThen(Effect.sleep(options.retryDelay ?? "1 second")))).pipe(Effect.forkScoped);
73
+ yield* Deferred.await(ready);
74
+ });
75
+ //# sourceMappingURL=listenForChanges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listenForChanges.js","sourceRoot":"","sources":["../src/listenForChanges.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Model } from "effect/schema";
2
+ import type { SqlClient } from "effect/sql";
3
+ import type { Aggregate } from "#aggregateQuery.ts";
4
+ export declare function makeAggregate<TModel extends Model.Any>(model: TModel, sql: SqlClient.SqlClient, options: {
5
+ readonly tableName: string;
6
+ readonly spanPrefix: string;
7
+ }): Aggregate<TModel>;
8
+ //# sourceMappingURL=makeAggregate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeAggregate.d.ts","sourceRoot":"","sources":["../src/makeAggregate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIpD,wBAAgB,aAAa,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,EACrD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,SAAS,CAAC,SAAS,EACxB,OAAO,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAClE,SAAS,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { Effect, Schema, SchemaIssue } from "effect";
2
+ import { aggregateColumn } from "#aggregateColumn.ts";
3
+ import { makeQueryClauses } from "#makeQueryClauses.ts";
4
+ import { makeFilter } from "#repositoryFilter.ts";
5
+ export function makeAggregate(model, sql, options) {
6
+ const { fieldAt, where } = makeFilter(model, sql);
7
+ const selectAggregate = aggregateColumn(sql, fieldAt);
8
+ return (query) => Effect.gen(function* () {
9
+ const groups = yield* Schema.decodeUnknownEffect(Schema.NonEmptyArray(Schema.String))(query.groupBy);
10
+ const fields = new Map();
11
+ const columns = [];
12
+ const ordering = new Map();
13
+ for (const key of groups) {
14
+ fields.set(key, yield* fieldAt(key));
15
+ columns.push(sql `${sql(key)}`);
16
+ }
17
+ for (const [name, expression] of Object.entries(query.aggregates)) {
18
+ if (groups.includes(name)) {
19
+ return yield* Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([name], new SchemaIssue.UnexpectedKey(model.ast, name))));
20
+ }
21
+ const selected = yield* selectAggregate(name, expression);
22
+ ordering.set(name, selected.order);
23
+ columns.push(selected.column);
24
+ fields.set(name, selected.schema);
25
+ }
26
+ const Result = Schema.Struct(Object.fromEntries(fields));
27
+ const clauses = makeQueryClauses(sql, (key) => fields.has(key)
28
+ ? Effect.succeed(fields.get(key))
29
+ : Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([key], new SchemaIssue.UnexpectedKey(Result.ast, key)))), (key) => ordering.get(key) ?? sql `${sql(key)}`);
30
+ const predicate = yield* where(query.where, true, true);
31
+ const order = yield* clauses.orderClause(query.orderBy);
32
+ const limit = yield* clauses.limitClause(query.limit);
33
+ const partitions = sql.csv(groups.map((key) => sql `${sql(key)}`));
34
+ const rows = yield* sql `select ${sql.csv(columns)} from ${sql(options.tableName)} where ${predicate} group by ${partitions} ${order} ${limit}`;
35
+ return yield* Schema.decodeUnknownEffect(Schema.Array(Result))(rows);
36
+ }).pipe(Effect.withSpan(`${options.spanPrefix}.aggregate`));
37
+ }
38
+ //# sourceMappingURL=makeAggregate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeAggregate.js","sourceRoot":"","sources":["../src/makeAggregate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAKrD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAuB,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOvE,MAAM,UAAU,aAAa,CAC5B,KAAgB,EAChB,GAAwB,EACxB,OAAoE;IAEpE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,eAAe,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtD,OAAO,CAAC,KAMP,EAAkE,EAAE,CACpE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrG,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAC;QACpD,MAAM,OAAO,GAAe,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC7C,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YACnE,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACpI,CAAC;YACD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC1D,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,gBAAgB,CAC/B,GAAG,EACH,CAAC,GAAG,EAAE,EAAE,CACP,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YACd,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,WAAW,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EACvH,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAA,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAC9C,CAAC;QACF,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA,UAAU,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,SAAS,aAAa,UAAU,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;QAC/I,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,UAAU,YAAY,CAAC,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { Model } from "effect/schema";
3
+ import type { SqlClient } from "effect/sql";
4
+ export declare function makeConflictClause(model: Model.Any, sql: SqlClient.SqlClient, options: {
5
+ readonly tableName: string;
6
+ readonly conflictColumns: readonly string[];
7
+ readonly conflictWhere?: Readonly<Record<string, unknown>>;
8
+ readonly idColumns: readonly string[];
9
+ }): (encoded: Readonly<Record<string, unknown>>, updateColumns?: readonly string[], updateWhere?: Readonly<Record<string, unknown>>) => Effect.Effect<import("effect/sql/Statement").Statement<import("effect/sql/SqlConnection").Row>, Schema.SchemaError, unknown>;
10
+ //# sourceMappingURL=makeConflictClause.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeConflictClause.d.ts","sourceRoot":"","sources":["../src/makeConflictClause.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAA0B,MAAM,QAAQ,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,GAAG,EAAE,SAAS,CAAC,SAAS,EACxB,OAAO,EAAE;IACR,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,aAsBwB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,SAAS,MAAM,EAAE,gBAAgB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kIAiB9I"}
@@ -0,0 +1,41 @@
1
+ import { Effect, Schema, SchemaAST, SchemaIssue } from "effect";
2
+ import { makeFilter } from "#repositoryFilter.ts";
3
+ export function makeConflictClause(model, sql, options) {
4
+ const { conflictColumns, idColumns } = options;
5
+ const updateFilter = makeFilter(model, sql, options);
6
+ const filter = makeFilter(model, sql);
7
+ const updateFields = SchemaAST.isObjects(model.update.ast) ? model.update.ast.propertySignatures.map((field) => field.name) : [];
8
+ const immutable = Object.keys(model.fields).filter((column) => !updateFields.includes(column));
9
+ function invalid(column) {
10
+ return Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([column], new SchemaIssue.UnexpectedKey(model.ast, column))));
11
+ }
12
+ function validateColumns(encoded, columns, excluded = []) {
13
+ return Effect.gen(function* () {
14
+ if (columns.length === 0) {
15
+ return yield* invalid("");
16
+ }
17
+ for (const column of columns) {
18
+ if (!(Object.hasOwn(model.fields, column) && Object.hasOwn(encoded, column)) || excluded.includes(column)) {
19
+ return yield* invalid(column);
20
+ }
21
+ }
22
+ });
23
+ }
24
+ function clause(encoded, updateColumns, updateWhere) {
25
+ return Effect.gen(function* () {
26
+ yield* validateColumns(encoded, conflictColumns);
27
+ if (updateColumns !== undefined) {
28
+ yield* validateColumns(encoded, updateColumns, [...idColumns, ...conflictColumns, ...immutable]);
29
+ }
30
+ const conflict = sql.csv(conflictColumns.map((column) => sql `${sql(column)}`));
31
+ const where = options.conflictWhere === undefined ? sql `` : sql `where ${yield* filter.where(options.conflictWhere)}`;
32
+ const action = updateColumns === undefined
33
+ ? sql `do nothing`
34
+ : sql `do update set ${sql.csv(updateColumns.map((column) => sql `${sql(column)} = excluded.${sql(column)}`))}`;
35
+ const condition = updateWhere === undefined ? sql `` : sql `where ${yield* updateFilter.where(updateWhere, true, true)}`;
36
+ return sql `on conflict (${conflict}) ${where} ${action} ${condition}`;
37
+ });
38
+ }
39
+ return clause;
40
+ }
41
+ //# sourceMappingURL=makeConflictClause.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeConflictClause.js","sourceRoot":"","sources":["../src/makeConflictClause.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { SqlClient } from "effect/sql";
3
+ import type { Fragment } from "effect/sql/Statement";
4
+ interface Order {
5
+ readonly direction: "asc" | "desc";
6
+ readonly field: string;
7
+ }
8
+ export declare function makeQueryClauses(sql: SqlClient.SqlClient, fieldAt: (key: string) => Effect.Effect<unknown, Schema.SchemaError>, column?: (key: string) => Fragment): {
9
+ decodeLimit: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Effect.Effect<number, Schema.SchemaError, never>;
10
+ limitClause: (limit: number | undefined) => Effect.Effect<import("effect/sql/Statement").Statement<import("effect/sql/SqlConnection").Row>, Schema.SchemaError, never>;
11
+ orderClause: (orderBy: Order | readonly Order[] | undefined) => Effect.Effect<import("effect/sql/Statement").Statement<import("effect/sql/SqlConnection").Row>, Schema.SchemaError, never>;
12
+ };
13
+ export {};
14
+ //# sourceMappingURL=makeQueryClauses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeQueryClauses.d.ts","sourceRoot":"","sources":["../src/makeQueryClauses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIrD,UAAU,KAAK;IACd,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,SAAS,CAAC,SAAS,EACxB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,EACpE,MAAM,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,QAAoC;;yBAiBjC,MAAM,GAAG,SAAS;2BAfhB,KAAK,GAAG,SAAS,KAAK,EAAE,GAAG,SAAS;EAmBlE"}
@@ -0,0 +1,20 @@
1
+ import { Effect, Schema } from "effect";
2
+ const Limit = Schema.Number.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0));
3
+ const decodeLimit = Schema.decodeUnknownEffect(Limit);
4
+ export function makeQueryClauses(sql, fieldAt, column = (key) => sql `${sql(key)}`) {
5
+ function orderClause(orderBy) {
6
+ if (orderBy === undefined) {
7
+ return Effect.succeed(sql ``);
8
+ }
9
+ const entries = "field" in orderBy ? [orderBy] : orderBy;
10
+ if (entries.length === 0) {
11
+ return Effect.succeed(sql ``);
12
+ }
13
+ return Effect.map(Effect.forEach(entries, ({ field, direction }) => Effect.as(fieldAt(field), sql `${column(field)} ${sql.literal(direction === "desc" ? "desc" : "asc")}`)), (columns) => sql `order by ${sql.csv(columns)}`);
14
+ }
15
+ function limitClause(limit) {
16
+ return limit === undefined ? Effect.succeed(sql ``) : Effect.map(decodeLimit(limit), (rowLimit) => sql `limit ${rowLimit}`);
17
+ }
18
+ return { decodeLimit, limitClause, orderClause };
19
+ }
20
+ //# sourceMappingURL=makeQueryClauses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeQueryClauses.js","sourceRoot":"","sources":["../src/makeQueryClauses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIxC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;AACpF,MAAM,WAAW,GAAG,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;AAMtD,MAAM,UAAU,gBAAgB,CAC/B,GAAwB,EACxB,OAAoE,EACpE,MAAM,GAA8B,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE;IAE7D,SAAS,WAAW,CAAC,OAA6C;QACjE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,MAAM,CAAC,GAAG,CAChB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAChD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAA,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CACtG,EACD,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAA,YAAY,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAC9C,CAAC;IACH,CAAC;IACD,SAAS,WAAW,CAAC,KAAyB;QAC7C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAA,SAAS,QAAQ,EAAE,CAAC,CAAC;IAC3H,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const MIGRATIONS_DIRECTORY = "src/server/migrations";
2
+ export declare const MIGRATION_FILE_PATTERN: RegExp;
3
+ //# sourceMappingURL=migrationConvention.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrationConvention.d.ts","sourceRoot":"","sources":["../src/migrationConvention.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAC5D,eAAO,MAAM,sBAAsB,QAAkD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export const MIGRATIONS_DIRECTORY = "src/server/migrations";
2
+ export const MIGRATION_FILE_PATTERN = /^[0-9]{4}_[a-z][a-z0-9]*(?:_[a-z0-9]+)*\.ts$/u;
3
+ //# sourceMappingURL=migrationConvention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrationConvention.js","sourceRoot":"","sources":["../src/migrationConvention.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;AAC5D,MAAM,CAAC,MAAM,sBAAsB,GAAG,+CAA+C,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { Duration, Effect } from "effect";
2
+ import { Migrator, SqlClient } from "effect/sql";
3
+ import { type SchemaComponent } from "./SchemaComponent.ts";
4
+ export interface PostgresMigrationOptions<R> {
5
+ readonly components?: readonly SchemaComponent<R>[];
6
+ readonly loader: Migrator.Loader<R>;
7
+ readonly lockTimeout: Duration.Input;
8
+ readonly release?: string;
9
+ readonly table?: string;
10
+ }
11
+ export declare const migratePostgres: <R>(args_0: PostgresMigrationOptions<R>) => Effect.Effect<readonly (readonly [id: number, name: string])[], Migrator.MigrationError | import("effect/sql/SqlError").SqlError, R | SqlClient.SqlClient>;
12
+ //# sourceMappingURL=migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGhF,MAAM,WAAW,wBAAwB,CAAC,CAAC;IAC1C,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,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,oMAuChF,CAAC"}