@shivaedev/sql 0.0.0-stage → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +269 -0
- package/LICENSE +21 -0
- package/README.md +614 -2
- package/dist/SchemaComponent.d.ts +9 -0
- package/dist/SchemaComponent.d.ts.map +1 -0
- package/dist/SchemaComponent.js +6 -0
- package/dist/SchemaComponent.js.map +1 -0
- package/dist/WorkerRelease.d.ts +14 -0
- package/dist/WorkerRelease.d.ts.map +1 -0
- package/dist/WorkerRelease.js +30 -0
- package/dist/WorkerRelease.js.map +1 -0
- package/dist/advisoryXactLock.d.ts +10 -0
- package/dist/advisoryXactLock.d.ts.map +1 -0
- package/dist/advisoryXactLock.js +18 -0
- package/dist/advisoryXactLock.js.map +1 -0
- package/dist/aggregateColumn.d.ts +8 -0
- package/dist/aggregateColumn.d.ts.map +1 -0
- package/dist/aggregateColumn.js +44 -0
- package/dist/aggregateColumn.js.map +1 -0
- package/dist/aggregateQuery.d.ts +51 -0
- package/dist/aggregateQuery.d.ts.map +1 -0
- package/dist/aggregateQuery.js +2 -0
- package/dist/aggregateQuery.js.map +1 -0
- package/dist/assertPostgresMigrations.d.ts +7 -0
- package/dist/assertPostgresMigrations.d.ts.map +1 -0
- package/dist/assertPostgresMigrations.js +20 -0
- package/dist/assertPostgresMigrations.js.map +1 -0
- package/dist/batchWrites.d.ts +16 -0
- package/dist/batchWrites.d.ts.map +1 -0
- package/dist/batchWrites.js +49 -0
- package/dist/batchWrites.js.map +1 -0
- package/dist/clientOptions.d.ts +8 -0
- package/dist/clientOptions.d.ts.map +1 -0
- package/dist/clientOptions.js +8 -0
- package/dist/clientOptions.js.map +1 -0
- package/dist/compositeRepository.d.ts +41 -0
- package/dist/compositeRepository.d.ts.map +1 -0
- package/dist/compositeRepository.js +38 -0
- package/dist/compositeRepository.js.map +1 -0
- package/dist/conditionalUpsert.d.ts +59 -0
- package/dist/conditionalUpsert.d.ts.map +1 -0
- package/dist/conditionalUpsert.js +28 -0
- package/dist/conditionalUpsert.js.map +1 -0
- package/dist/conflictWrites.d.ts +45 -0
- package/dist/conflictWrites.d.ts.map +1 -0
- package/dist/conflictWrites.js +40 -0
- package/dist/conflictWrites.js.map +1 -0
- package/dist/coordinateWorkerRelease.d.ts +5 -0
- package/dist/coordinateWorkerRelease.d.ts.map +1 -0
- package/dist/coordinateWorkerRelease.js +30 -0
- package/dist/coordinateWorkerRelease.js.map +1 -0
- package/dist/insertFromSelect.d.ts +24 -0
- package/dist/insertFromSelect.d.ts.map +1 -0
- package/dist/insertFromSelect.js +15 -0
- package/dist/insertFromSelect.js.map +1 -0
- package/dist/latestPerGroup.d.ts +11 -0
- package/dist/latestPerGroup.d.ts.map +1 -0
- package/dist/latestPerGroup.js +51 -0
- package/dist/latestPerGroup.js.map +1 -0
- package/dist/listenForChanges.d.ts +5 -0
- package/dist/listenForChanges.d.ts.map +1 -0
- package/dist/listenForChanges.js +75 -0
- package/dist/listenForChanges.js.map +1 -0
- package/dist/makeAggregate.d.ts +8 -0
- package/dist/makeAggregate.d.ts.map +1 -0
- package/dist/makeAggregate.js +38 -0
- package/dist/makeAggregate.js.map +1 -0
- package/dist/makeConflictClause.d.ts +10 -0
- package/dist/makeConflictClause.d.ts.map +1 -0
- package/dist/makeConflictClause.js +41 -0
- package/dist/makeConflictClause.js.map +1 -0
- package/dist/makeQueryClauses.d.ts +14 -0
- package/dist/makeQueryClauses.d.ts.map +1 -0
- package/dist/makeQueryClauses.js +20 -0
- package/dist/makeQueryClauses.js.map +1 -0
- package/dist/migrationConvention.d.ts +3 -0
- package/dist/migrationConvention.d.ts.map +1 -0
- package/dist/migrationConvention.js +3 -0
- package/dist/migrationConvention.js.map +1 -0
- package/dist/migrations.d.ts +12 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +41 -0
- package/dist/migrations.js.map +1 -0
- package/dist/migrationsFromDirectory.d.ts +4 -0
- package/dist/migrationsFromDirectory.d.ts.map +1 -0
- package/dist/migrationsFromDirectory.js +7 -0
- package/dist/migrationsFromDirectory.js.map +1 -0
- package/dist/notifyPayload.d.ts +7 -0
- package/dist/notifyPayload.d.ts.map +1 -0
- package/dist/notifyPayload.js +31 -0
- package/dist/notifyPayload.js.map +1 -0
- package/dist/pendingPostgresMigrations.d.ts +24 -0
- package/dist/pendingPostgresMigrations.d.ts.map +1 -0
- package/dist/pendingPostgresMigrations.js +30 -0
- package/dist/pendingPostgresMigrations.js.map +1 -0
- package/dist/pinnedGroups.d.ts +22 -0
- package/dist/pinnedGroups.d.ts.map +1 -0
- package/dist/pinnedGroups.js +35 -0
- package/dist/pinnedGroups.js.map +1 -0
- package/dist/postgresChanges.d.ts +20 -0
- package/dist/postgresChanges.d.ts.map +1 -0
- package/dist/postgresChanges.js +26 -0
- package/dist/postgresChanges.js.map +1 -0
- package/dist/postgresRelease.d.ts +9 -0
- package/dist/postgresRelease.d.ts.map +1 -0
- package/dist/postgresRelease.js +39 -0
- package/dist/postgresRelease.js.map +1 -0
- package/dist/releaseWorkers.d.ts +8 -0
- package/dist/releaseWorkers.d.ts.map +1 -0
- package/dist/releaseWorkers.js +26 -0
- package/dist/releaseWorkers.js.map +1 -0
- package/dist/repository.d.ts +66 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +43 -0
- package/dist/repository.js.map +1 -0
- package/dist/repositoryChanges.d.ts +9 -0
- package/dist/repositoryChanges.d.ts.map +1 -0
- package/dist/repositoryChanges.js +32 -0
- package/dist/repositoryChanges.js.map +1 -0
- package/dist/repositoryFilter.d.ts +43 -0
- package/dist/repositoryFilter.d.ts.map +1 -0
- package/dist/repositoryFilter.js +69 -0
- package/dist/repositoryFilter.js.map +1 -0
- package/dist/repositoryQueries.d.ts +26 -0
- package/dist/repositoryQueries.d.ts.map +1 -0
- package/dist/repositoryQueries.js +49 -0
- package/dist/repositoryQueries.js.map +1 -0
- package/dist/repositoryWrites.d.ts +18 -0
- package/dist/repositoryWrites.d.ts.map +1 -0
- package/dist/repositoryWrites.js +49 -0
- package/dist/repositoryWrites.js.map +1 -0
- package/dist/testing.d.ts +12 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +29 -0
- package/dist/testing.js.map +1 -0
- package/dist/transact.d.ts +18 -0
- package/dist/transact.d.ts.map +1 -0
- package/dist/transact.js +43 -0
- package/dist/transact.js.map +1 -0
- package/dist/tupleIn.d.ts +19 -0
- package/dist/tupleIn.d.ts.map +1 -0
- package/dist/tupleIn.js +20 -0
- package/dist/tupleIn.js.map +1 -0
- package/dist/versionedRepository.d.ts +37 -0
- package/dist/versionedRepository.d.ts.map +1 -0
- package/dist/versionedRepository.js +63 -0
- package/dist/versionedRepository.js.map +1 -0
- package/dist/versionedStatements.d.ts +25 -0
- package/dist/versionedStatements.d.ts.map +1 -0
- package/dist/versionedStatements.js +75 -0
- package/dist/versionedStatements.js.map +1 -0
- package/package.json +74 -3
- package/src/SchemaComponent.ts +12 -0
- package/src/WorkerRelease.ts +38 -0
- package/src/advisoryXactLock.ts +17 -0
- package/src/aggregateColumn.ts +49 -0
- package/src/aggregateQuery.ts +57 -0
- package/src/assertPostgresMigrations.ts +24 -0
- package/src/batchWrites.ts +69 -0
- package/src/clientOptions.ts +16 -0
- package/src/compositeRepository.ts +101 -0
- package/src/conditionalUpsert.ts +97 -0
- package/src/conflictWrites.ts +93 -0
- package/src/coordinateWorkerRelease.ts +33 -0
- package/src/insertFromSelect.ts +47 -0
- package/src/latestPerGroup.ts +58 -0
- package/src/listenForChanges.ts +97 -0
- package/src/makeAggregate.ts +64 -0
- package/src/makeConflictClause.ts +53 -0
- package/src/makeQueryClauses.ts +36 -0
- package/src/migrationConvention.ts +2 -0
- package/src/migrations.ts +58 -0
- package/src/migrationsFromDirectory.ts +7 -0
- package/src/notifyPayload.ts +34 -0
- package/src/pendingPostgresMigrations.ts +42 -0
- package/src/pinnedGroups.ts +46 -0
- package/src/postgresChanges.ts +48 -0
- package/src/postgresRelease.ts +41 -0
- package/src/releaseWorkers.ts +32 -0
- package/src/repository.ts +147 -0
- package/src/repositoryChanges.ts +49 -0
- package/src/repositoryFilter.ts +108 -0
- package/src/repositoryQueries.ts +107 -0
- package/src/repositoryWrites.ts +70 -0
- package/src/testing.ts +38 -0
- package/src/transact.ts +70 -0
- package/src/tupleIn.ts +44 -0
- package/src/versionedRepository.ts +108 -0
- 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":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhD,OAAO,EAAmB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAsD,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAClH,OAAO,EAAyB,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAiC5D,MAAM,UAAU,kBAAkB,CACjC,KAAgB,EAChB,GAAwB,EACxB,OAOC;IAED,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACxF,MAAM,WAAW,GAAG,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IACvD,SAAS,SAAS,CAAC,KAAc,EAAE,aAAiC;QACnE,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YACrD,OAAO,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,cAAc,CAAC;QACxF,CAAC,CAAC,CAAC;IACJ,CAAC;IACD,OAAO;QACN,wBAAwB,EAAE,oBAAoB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,OAAO,EAAE,EAAE,CAC3G,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAClE;QACD,kBAAkB,EAAE,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnG,cAAc,EAAE,CAAC,KAAc,EAAE,EAAE,CAClC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACnB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC5C,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,iBAAiB,CAAC,CAAC;QAChF,MAAM,EAAE,CAAC,KAAc,EAAE,QAAiH,EAAE,EAAE,CAC7I,QAAQ,CAAC,WAAW,KAAK,SAAS;YACjC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACpB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;gBACpE,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACpC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;YACxE,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACtH,UAAU,EAAE,CACX,MAA0B,EAC1B,QAAiH,EAChH,EAAE,CACH,QAAQ,CAAC,WAAW,KAAK,SAAS;YACjC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;YACzG,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,GAAG,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;KAC3E,CAAC;AACH,CAAC"}
|
|
@@ -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":"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"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|