@shivaedev/sql 0.0.0 → 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 +613 -1
- 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 +71 -4
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryChanges.js","sourceRoot":"","sources":["../src/repositoryChanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE5D,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,SAAS,cAAc,CAAC,IAAY,EAAE,KAAc;IACnD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1D,CAAC;AAID,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAwB,EAAE,KAAa,EAAE,OAA0B;IAChI,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;IACjF,SAAS,OAAO,CAAU,MAA4E;QACrG,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAC9E,MAAM,CAAC,IAAI,CACV,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,EAC/C,MAAM,CAAC,cAAc,CACpB,UAAU,CAAC,UAAU,EACrB,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CACzC,CACD,CACD,CAAC;IACH,CAAC;IACD,SAAS,MAAM,CAAC,IAAkD;QACjE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC,IAAI,CAAC;QACpB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YAClC,OAAO,OAAO,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC5B,OAAO,CAAC,MAAM,KAAK,CAAC;YACnB,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACvB,CAAC,CAAC,IAAI,CAAC,SAAS,CACd,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EACpC,cAAc,CACd,CACH,CAAC;QACF,OAAO,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,SAAS,KAAK,CAAU,MAA8B;QACrD,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
|
+
import type { SqlClient } from "effect/sql";
|
|
4
|
+
import { type TupleFilter } from "#tupleIn.ts";
|
|
5
|
+
export type RepositoryFilter<TModel extends Model.Any> = {
|
|
6
|
+
readonly [TField in keyof Schema.Struct.Type<TModel["fields"]>]?: Schema.Struct.Type<TModel["fields"]>[TField] | undefined;
|
|
7
|
+
};
|
|
8
|
+
export type RepositoryListFilter<TModel extends Model.Any> = Partial<TupleFilter<TModel>> & {
|
|
9
|
+
readonly [TField in keyof Schema.Struct.Type<TModel["fields"]>]?: Schema.Struct.Type<TModel["fields"]>[TField] | {
|
|
10
|
+
readonly in: readonly Schema.Struct.Type<TModel["fields"]>[TField][];
|
|
11
|
+
} | undefined;
|
|
12
|
+
};
|
|
13
|
+
declare const Ordered: Schema.Union<readonly [Schema.String, Schema.Number, Schema.BigInt, Schema.Date, Schema.BigDecimal, Schema.DateTimeUtc]>;
|
|
14
|
+
export type OrderedValue = typeof Ordered.Type;
|
|
15
|
+
export type Comparisons<T, TOperand = NonNullable<T>> = [NonNullable<T>] extends [OrderedValue] ? {
|
|
16
|
+
readonly gt?: TOperand;
|
|
17
|
+
readonly gte?: TOperand;
|
|
18
|
+
readonly lt?: TOperand;
|
|
19
|
+
readonly lte?: TOperand;
|
|
20
|
+
} : {
|
|
21
|
+
readonly gt?: never;
|
|
22
|
+
readonly gte?: never;
|
|
23
|
+
readonly lt?: never;
|
|
24
|
+
readonly lte?: never;
|
|
25
|
+
};
|
|
26
|
+
type Pattern<T> = [NonNullable<T>] extends [string] ? {
|
|
27
|
+
readonly like?: NonNullable<T>;
|
|
28
|
+
} : {
|
|
29
|
+
readonly like?: never;
|
|
30
|
+
};
|
|
31
|
+
export type FindManyFilter<TModel extends Model.Any> = Partial<TupleFilter<TModel>> & {
|
|
32
|
+
readonly [TField in keyof Schema.Struct.Type<TModel["fields"]>]?: Schema.Struct.Type<TModel["fields"]>[TField] | (Comparisons<Schema.Struct.Type<TModel["fields"]>[TField]> & Pattern<Schema.Struct.Type<TModel["fields"]>[TField]>) | {
|
|
33
|
+
readonly in: readonly Schema.Struct.Type<TModel["fields"]>[TField][];
|
|
34
|
+
} | undefined;
|
|
35
|
+
};
|
|
36
|
+
export declare function makeFilter<TModel extends Model.Any>(model: TModel, sql: SqlClient.SqlClient, references?: {
|
|
37
|
+
readonly tableName: string;
|
|
38
|
+
}): {
|
|
39
|
+
fieldAt: (key: string) => Effect.Effect<never, Schema.SchemaError, never> | Effect.Effect<Schema.Constraint, never, never>;
|
|
40
|
+
where: (input?: Readonly<Record<string, unknown>> & Partial<TupleFilter<Model.Any>>, allowIn?: boolean, allowComparisons?: boolean) => Effect.Effect<import("effect/sql/Statement").Fragment, Schema.SchemaError, unknown>;
|
|
41
|
+
};
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=repositoryFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryFilter.d.ts","sourceRoot":"","sources":["../src/repositoryFilter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Effect, Schema, SchemaIssue } from "effect";
|
|
2
|
+
import { tuplePredicate } from "#tupleIn.ts";
|
|
3
|
+
const Ordered = Schema.Union([Schema.String, Schema.Number, Schema.BigInt, Schema.Date, Schema.BigDecimal, Schema.DateTimeUtc]);
|
|
4
|
+
const operators = { gt: ">", gte: ">=", like: "like", lt: "<", lte: "<=" };
|
|
5
|
+
function isOperator(key) {
|
|
6
|
+
return Object.hasOwn(operators, key);
|
|
7
|
+
}
|
|
8
|
+
export function makeFilter(model, sql, references) {
|
|
9
|
+
function fieldAt(key) {
|
|
10
|
+
const field = Object.hasOwn(model.fields, key) ? model.fields[key] : undefined;
|
|
11
|
+
return field === undefined
|
|
12
|
+
? Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([key], new SchemaIssue.UnexpectedKey(model.ast, key))))
|
|
13
|
+
: Effect.succeed(field);
|
|
14
|
+
}
|
|
15
|
+
function column(key) {
|
|
16
|
+
return references === undefined ? sql `${sql(key)}` : sql `${sql(references.tableName)}.${sql(key)}`;
|
|
17
|
+
}
|
|
18
|
+
function reference(value) {
|
|
19
|
+
return references !== undefined && typeof value === "object" && value !== null && "excluded" in value && typeof value.excluded === "string"
|
|
20
|
+
? value.excluded
|
|
21
|
+
: undefined;
|
|
22
|
+
}
|
|
23
|
+
function comparison(key, field, operator, operand) {
|
|
24
|
+
if (!isOperator(operator)) {
|
|
25
|
+
return Effect.fail(new Schema.SchemaError(new SchemaIssue.Pointer([key, operator], new SchemaIssue.UnexpectedKey(model.ast, operator))));
|
|
26
|
+
}
|
|
27
|
+
const incoming = reference(operand);
|
|
28
|
+
if (incoming !== undefined) {
|
|
29
|
+
return Effect.as(fieldAt(incoming), sql `${column(key)} ${sql.literal(operators[operator])} excluded.${sql(incoming)}`);
|
|
30
|
+
}
|
|
31
|
+
const validate = Schema.decodeUnknownEffect(operator === "like" ? Schema.String : Ordered);
|
|
32
|
+
return Effect.flatMap(validate(operand), (decoded) => Effect.map(Schema.encodeEffect(field)(decoded), (encoded) => sql `${column(key)} ${sql.literal(operators[operator])} ${encoded}`));
|
|
33
|
+
}
|
|
34
|
+
function inPredicate(key, encoded) {
|
|
35
|
+
if (references === undefined) {
|
|
36
|
+
return sql.in(key, encoded);
|
|
37
|
+
}
|
|
38
|
+
return encoded.length === 0 ? sql `1 = 0` : sql `${column(key)} in ${sql.in(encoded)}`;
|
|
39
|
+
}
|
|
40
|
+
function predicate(key, value, allowIn, allowComparisons) {
|
|
41
|
+
return Effect.flatMap(fieldAt(key), (field) => {
|
|
42
|
+
const incoming = reference(value);
|
|
43
|
+
if (incoming !== undefined) {
|
|
44
|
+
return Effect.as(fieldAt(incoming), sql `${column(key)} = excluded.${sql(incoming)}`);
|
|
45
|
+
}
|
|
46
|
+
const encode = Schema.encodeEffect(field);
|
|
47
|
+
if (allowComparisons && typeof value === "object" && value !== null && Object.keys(value).some(isOperator)) {
|
|
48
|
+
return Effect.map(Effect.forEach(Object.entries(value), ([operator, operand]) => comparison(key, field, operator, operand)), (predicates) => sql.and(predicates));
|
|
49
|
+
}
|
|
50
|
+
return allowIn && typeof value === "object" && value !== null && "in" in value && Array.isArray(value.in)
|
|
51
|
+
? Effect.map(Effect.forEach(value.in, (entry) => encode(entry)), (encoded) => inPredicate(key, encoded))
|
|
52
|
+
: Effect.map(encode(value), (encoded) => (encoded === null ? sql `${column(key)} is null` : sql `${column(key)} = ${encoded}`));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function where(input = {}, allowIn = false, allowComparisons = false) {
|
|
56
|
+
return Effect.gen(function* () {
|
|
57
|
+
const predicates = yield* Effect.forEach(Object.entries(input).filter(([, value]) => value !== undefined), ([key, value]) => predicate(key, value, allowIn, allowComparisons));
|
|
58
|
+
if (allowIn) {
|
|
59
|
+
const tuple = yield* tuplePredicate(input, sql, fieldAt);
|
|
60
|
+
if (tuple !== undefined) {
|
|
61
|
+
predicates.push(tuple);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return sql.and(predicates);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return { fieldAt, where };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=repositoryFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryFilter.js","sourceRoot":"","sources":["../src/repositoryFilter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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 { Aggregate } from "#aggregateQuery.ts";
|
|
7
|
+
import type { FindMany, LatestPerGroup } from "#repository.ts";
|
|
8
|
+
type Key<TModel extends Model.Any> = Extract<keyof TModel["fields"] & keyof Row<TModel>, string>;
|
|
9
|
+
type Row<TModel extends Model.Any> = Schema.Struct.Type<TModel["fields"]>;
|
|
10
|
+
export interface RepositorySelect<TFields extends Schema.Struct.Fields, TServices = never> {
|
|
11
|
+
readonly fields: TFields;
|
|
12
|
+
readonly statement: Effect.Effect<Fragment, Schema.SchemaError, TServices>;
|
|
13
|
+
}
|
|
14
|
+
export interface Queries<TModel extends Model.Any> {
|
|
15
|
+
aggregate: Aggregate<TModel>;
|
|
16
|
+
count: (query?: Pick<FindMany<TModel, Key<TModel>>, "where">) => Effect.Effect<number, SqlError | Schema.SchemaError, TModel["fields"][Key<TModel>]["EncodingServices"]>;
|
|
17
|
+
findMany: <TKey extends Key<TModel> = Key<TModel>>(query?: FindMany<TModel, TKey>) => Effect.Effect<Pick<Row<TModel>, TKey>[], SqlError | Schema.SchemaError, TModel["fields"][Key<TModel>]["EncodingServices"] | TModel["fields"][TKey]["DecodingServices"]>;
|
|
18
|
+
latestPerGroup: (query: LatestPerGroup<TModel>) => Effect.Effect<Row<TModel>[], SqlError | Schema.SchemaError, TModel["fields"][Key<TModel>]["EncodingServices"] | TModel["fields"][Key<TModel>]["DecodingServices"]>;
|
|
19
|
+
select: <TKey extends Key<TModel> = Key<TModel>>(query?: FindMany<TModel, TKey>) => RepositorySelect<Pick<TModel["fields"], TKey>, TModel["fields"][Key<TModel>]["EncodingServices"]>;
|
|
20
|
+
}
|
|
21
|
+
export declare function makeQueries<TModel extends Model.Any>(model: TModel, sql: SqlClient.SqlClient, options: {
|
|
22
|
+
readonly tableName: string;
|
|
23
|
+
readonly spanPrefix: string;
|
|
24
|
+
}): Queries<TModel>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=repositoryQueries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryQueries.d.ts","sourceRoot":"","sources":["../src/repositoryQueries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { latestPerGroup as makeLatestPerGroup } from "#latestPerGroup.ts";
|
|
3
|
+
import { makeAggregate } from "#makeAggregate.ts";
|
|
4
|
+
import { makeQueryClauses } from "#makeQueryClauses.ts";
|
|
5
|
+
import { makeFilter } from "#repositoryFilter.ts";
|
|
6
|
+
const CountResult = Schema.Tuple([Schema.Struct({ count: Schema.NumberFromString })]);
|
|
7
|
+
export function makeQueries(model, sql, options) {
|
|
8
|
+
const { fieldAt, where } = makeFilter(model, sql);
|
|
9
|
+
const readLatest = makeLatestPerGroup(model, sql, options.tableName);
|
|
10
|
+
const { decodeLimit, orderClause, limitClause } = makeQueryClauses(sql, fieldAt);
|
|
11
|
+
const aggregate = makeAggregate(model, sql, options);
|
|
12
|
+
function count(query = {}) {
|
|
13
|
+
return Effect.gen(function* () {
|
|
14
|
+
const predicate = yield* where(query.where, true, true);
|
|
15
|
+
const rows = yield* sql `select cast(count(*) as text) as count from ${sql(options.tableName)} where ${predicate}`;
|
|
16
|
+
const [result] = yield* Schema.decodeUnknownEffect(CountResult)(rows);
|
|
17
|
+
return result.count;
|
|
18
|
+
}).pipe(Effect.withSpan(`${options.spanPrefix}.count`));
|
|
19
|
+
}
|
|
20
|
+
function select(query = {}) {
|
|
21
|
+
const keys = query.select ?? Object.keys(model.fields);
|
|
22
|
+
const fields = Object.fromEntries(keys.map((key) => [key, model.fields[key]]));
|
|
23
|
+
const statement = Effect.gen(function* () {
|
|
24
|
+
yield* Effect.forEach(keys, fieldAt);
|
|
25
|
+
const predicate = yield* where(query.where, true, true);
|
|
26
|
+
const order = yield* orderClause(query.orderBy);
|
|
27
|
+
const limit = yield* limitClause(query.limit);
|
|
28
|
+
return sql `select ${sql.csv(keys.map((key) => sql `${sql(key)}`))} from ${sql(options.tableName)} where ${predicate} ${order} ${limit}`;
|
|
29
|
+
});
|
|
30
|
+
return { fields, statement };
|
|
31
|
+
}
|
|
32
|
+
// Object.fromEntries erases the selected key-to-schema correspondence, so the typed overload restates it.
|
|
33
|
+
function findMany(query = {}) {
|
|
34
|
+
return Effect.gen(function* () {
|
|
35
|
+
const selected = select(query);
|
|
36
|
+
const rows = yield* sql `${yield* selected.statement}`;
|
|
37
|
+
return yield* Schema.decodeUnknownEffect(Schema.Array(Schema.Struct(selected.fields)))(rows);
|
|
38
|
+
}).pipe(Effect.withSpan(`${options.spanPrefix}.findMany`));
|
|
39
|
+
}
|
|
40
|
+
function latestPerGroup(query) {
|
|
41
|
+
return Effect.gen(function* () {
|
|
42
|
+
const order = yield* orderClause(query.orderBy);
|
|
43
|
+
const rowLimit = yield* decodeLimit(query.limit);
|
|
44
|
+
return yield* readLatest(query, order, rowLimit);
|
|
45
|
+
}).pipe(Effect.withSpan(`${options.spanPrefix}.latestPerGroup`));
|
|
46
|
+
}
|
|
47
|
+
return { aggregate, count, findMany, latestPerGroup, select };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=repositoryQueries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryQueries.js","sourceRoot":"","sources":["../src/repositoryQueries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
|
+
import { type SqlClient } from "effect/sql";
|
|
4
|
+
import type { RepositoryChanges } from "./repositoryChanges.ts";
|
|
5
|
+
export declare function repositoryWrites(model: Model.Any, sql: SqlClient.SqlClient, options: {
|
|
6
|
+
readonly idColumns: readonly string[];
|
|
7
|
+
readonly tableName: string;
|
|
8
|
+
readonly spanPrefix: string;
|
|
9
|
+
}, changes: RepositoryChanges): {
|
|
10
|
+
delete: (id: unknown) => Effect.Effect<void, Schema.SchemaError | import("effect/sql/SqlError").SqlError, unknown>;
|
|
11
|
+
insert: (input: unknown) => Effect.Effect<unknown, Schema.SchemaError | import("effect/sql/SqlError").SqlError, unknown>;
|
|
12
|
+
insertVoid: (input: unknown) => Effect.Effect<void, Schema.SchemaError | import("effect/sql/SqlError").SqlError, unknown>;
|
|
13
|
+
update: (input: unknown, settings?: {
|
|
14
|
+
readonly onMissing: "fail";
|
|
15
|
+
}) => Effect.Effect<unknown, import("effect/Cause").NoSuchElementError | Schema.SchemaError | import("effect/sql/SqlError").SqlError, unknown>;
|
|
16
|
+
updateVoid: (input: unknown) => Effect.Effect<void, Schema.SchemaError | import("effect/sql/SqlError").SqlError, unknown>;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=repositoryWrites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryWrites.d.ts","sourceRoot":"","sources":["../src/repositoryWrites.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,GAAG,EAAE,SAAS,CAAC,SAAS,EACxB,OAAO,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAC3G,OAAO,EAAE,iBAAiB;IAiDzB,MAAM,OAAO,OAAO;IACpB,MAAM,UAAU,OAAO;IAEvB,UAAU,UAAU,OAAO;IAC3B,MAAM,UAAU,OAAO,aAAa;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAIlE,UAAU,UAAU,OAAO;EAE5B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { SqlSchema } from "effect/sql";
|
|
3
|
+
import { makeFilter } from "./repositoryFilter.js";
|
|
4
|
+
export function repositoryWrites(model, sql, options, changes) {
|
|
5
|
+
const { idColumns, tableName, spanPrefix } = options;
|
|
6
|
+
const { where } = makeFilter(model, sql);
|
|
7
|
+
const record = Schema.decodeUnknownEffect(Schema.Record(Schema.String, Schema.Unknown));
|
|
8
|
+
const filterRecord = Schema.decodeUnknownEffect(Schema.Record(Schema.PropertyKey, Schema.Unknown));
|
|
9
|
+
function predicate(input) {
|
|
10
|
+
return sql.and(idColumns.map((column) => sql `${sql(column)} = ${input[column]}`));
|
|
11
|
+
}
|
|
12
|
+
function insert(input) {
|
|
13
|
+
return Effect.flatMap(record(input), (row) => (Object.keys(row).length === 0
|
|
14
|
+
? sql `insert into ${sql(tableName)} default values returning *`
|
|
15
|
+
: sql `insert into ${sql(tableName)} ${sql.insert(row)} returning *`).pipe(Effect.tap(changes.record)));
|
|
16
|
+
}
|
|
17
|
+
function update(input) {
|
|
18
|
+
return Effect.flatMap(record(input), (row) => sql `update ${sql(tableName)} set ${sql.update(row, idColumns)} where ${predicate(row)} returning *`.pipe(Effect.tap(changes.record)));
|
|
19
|
+
}
|
|
20
|
+
const insertRow = SqlSchema.findOne({ execute: insert, Request: model.insert, Result: model });
|
|
21
|
+
const insertVoid = SqlSchema.void({ execute: insert, Request: model.insert });
|
|
22
|
+
const updateRow = SqlSchema.findOne({ execute: update, Request: model.update, Result: model });
|
|
23
|
+
const updateVoid = SqlSchema.void({ execute: update, Request: model.update });
|
|
24
|
+
const idColumn = idColumns[0] ?? "";
|
|
25
|
+
const key = model.fields[idColumn];
|
|
26
|
+
if (key === undefined) {
|
|
27
|
+
throw new Error("Unknown repository ID column");
|
|
28
|
+
}
|
|
29
|
+
const isKey = Schema.is(key);
|
|
30
|
+
const removeByKey = SqlSchema.void({
|
|
31
|
+
execute: (id) => Effect.flatMap(record({ [idColumn]: id }), (encoded) => sql `delete from ${sql(tableName)} where ${predicate(encoded)} returning *`.pipe(Effect.tap(changes.record))),
|
|
32
|
+
Request: key,
|
|
33
|
+
});
|
|
34
|
+
function remove(input) {
|
|
35
|
+
return idColumns.length === 1 && isKey(input)
|
|
36
|
+
? removeByKey(input)
|
|
37
|
+
: Effect.flatMap(filterRecord(input), (filter) => Effect.flatMap(where(filter, true), (clause) => sql `delete from ${sql(tableName)} where ${clause} returning *`.pipe(Effect.tap(changes.record), Effect.asVoid)));
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
delete: (id) => changes.write(remove(id)).pipe(Effect.withSpan(`${spanPrefix}.delete`)),
|
|
41
|
+
insert: (input) => changes.write(insertRow(input).pipe(Effect.catchTag("NoSuchElementError", Effect.die))).pipe(Effect.withSpan(`${spanPrefix}.insert`)),
|
|
42
|
+
insertVoid: (input) => changes.write(insertVoid(input)).pipe(Effect.withSpan(`${spanPrefix}.insertVoid`)),
|
|
43
|
+
update: (input, settings) => changes
|
|
44
|
+
.write(settings?.onMissing === "fail" ? updateRow(input) : updateRow(input).pipe(Effect.catchTag("NoSuchElementError", Effect.die)))
|
|
45
|
+
.pipe(Effect.withSpan(`${spanPrefix}.update`)),
|
|
46
|
+
updateVoid: (input) => changes.write(updateVoid(input)).pipe(Effect.withSpan(`${spanPrefix}.updateVoid`)),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=repositoryWrites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryWrites.js","sourceRoot":"","sources":["../src/repositoryWrites.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
declare const UnannouncedWrites_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
4
|
+
readonly _tag: "UnannouncedWrites";
|
|
5
|
+
} & Readonly<A>;
|
|
6
|
+
export declare class UnannouncedWrites extends UnannouncedWrites_base<{
|
|
7
|
+
readonly tables: readonly string[];
|
|
8
|
+
}> {
|
|
9
|
+
}
|
|
10
|
+
export declare const withChangeCoverage: <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, import("effect/sql/SqlError").SqlError | UnannouncedWrites | Exclude<E, import("effect/sql/SqlError").SqlError>, import("effect/reactivity/Reactivity").Reactivity | SqlClient.SqlClient | Exclude<R, never>>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;;;;AAGvC,qBAAa,iBAAkB,SAAQ,uBAAsC;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;CAAG;AAQvH,eAAO,MAAM,kBAAkB,GAAsD,CAAC,EAAE,CAAC,EAAE,CAAC,iQAyB1F,CAAC"}
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Data, Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { ChangeObserver, transact } from "./transact.js";
|
|
4
|
+
export class UnannouncedWrites extends Data.TaggedError("UnannouncedWrites") {
|
|
5
|
+
}
|
|
6
|
+
export const withChangeCoverage = Effect.fn("Changes.withChangeCoverage")(function* (body) {
|
|
7
|
+
const observer = yield* ChangeObserver;
|
|
8
|
+
const sql = yield* SqlClient.SqlClient;
|
|
9
|
+
const named = new Set();
|
|
10
|
+
const written = sql `select relid, relname, (n_tup_ins + n_tup_upd + n_tup_del)::int as writes from pg_stat_xact_user_tables`;
|
|
11
|
+
const checked = Effect.gen(function* () {
|
|
12
|
+
const before = new Map((yield* written).map((row) => [row.relid, row.writes]));
|
|
13
|
+
const result = yield* body;
|
|
14
|
+
const missing = (yield* written).filter((row) => row.writes > (before.get(row.relid) ?? 0) && !named.has(row.relname));
|
|
15
|
+
if (missing.length > 0) {
|
|
16
|
+
return yield* Effect.fail(new UnannouncedWrites({ tables: missing.map((row) => row.relname).sort() }));
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
});
|
|
20
|
+
return yield* checked.pipe(transact({ onSqlError: (error) => error }), Effect.provideService(ChangeObserver, (event) => {
|
|
21
|
+
if (event._tag === "Recorded") {
|
|
22
|
+
for (const key of event.changes) {
|
|
23
|
+
named.add(key);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return observer(event);
|
|
27
|
+
}));
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,OAAO,iBAAkB,SAAQ,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAyC;CAAG;AAQvH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC,EAAW,IAA4B;IACzH,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC;IACvC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAW,CAAC;IACjC,MAAM,OAAO,GAAG,GAAG,CAAa,yGAAyG,CAAC;IAC1I,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC;QAC3B,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QACvH,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CACzB,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,EAC1C,MAAM,CAAC,cAAc,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/C,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC/B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACjC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACF,CAAC;QACD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC,CAAC,CACF,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { ReadonlyRecord } from "effect/Record";
|
|
3
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import { SqlClient } from "effect/sql";
|
|
5
|
+
import { type SqlError } from "effect/sql/SqlError";
|
|
6
|
+
export type InvalidationKeys = readonly unknown[] | ReadonlyRecord<string, readonly unknown[]>;
|
|
7
|
+
export declare const ChangeObserver: import("effect/Context").Reference<import("@shivaedev/changes/observe.ts").Observer<unknown>>;
|
|
8
|
+
export declare const BeforeCommit: import("effect/Context").Reference<import("@shivaedev/changes/channel.ts").BeforeCommit<unknown, SqlError, Reactivity.Reactivity | SqlClient.SqlClient>>;
|
|
9
|
+
export declare const CommittedSink: import("effect/Context").Reference<import("@shivaedev/changes/publish.ts").Publish<unknown, Reactivity.Reactivity | SqlClient.SqlClient> | undefined>;
|
|
10
|
+
export declare const invalidateOnCommit: (keys: InvalidationKeys) => Effect.Effect<void, never, Reactivity.Reactivity | SqlClient.SqlClient>;
|
|
11
|
+
export interface TransactOptions<TError> {
|
|
12
|
+
readonly onSqlError: (error: SqlError) => TError;
|
|
13
|
+
}
|
|
14
|
+
export declare const transact: {
|
|
15
|
+
<TError>(options: TransactOptions<TError>): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, Exclude<E, SqlError> | TError, R | SqlClient.SqlClient | Reactivity.Reactivity>;
|
|
16
|
+
<A, E, R, TError>(effect: Effect.Effect<A, E, R>, options: TransactOptions<TError>): Effect.Effect<A, Exclude<E, SqlError> | TError, R | SqlClient.SqlClient | Reactivity.Reactivity>;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=transact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transact.d.ts","sourceRoot":"","sources":["../src/transact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGhE,MAAM,MAAM,gBAAgB,GAAG,SAAS,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;AAiC/F,eAAO,MAAM,cAAc,+FAAyB,CAAC;AACrD,eAAO,MAAM,YAAY,0JAA6B,CAAC;AACvD,eAAO,MAAM,aAAa,uJAA8B,CAAC;AAEzD,eAAO,MAAM,kBAAkB,qGAE7B,CAAC;AAEH,MAAM,WAAW,eAAe,CAAC,MAAM;IACtC,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;CACjD;AAED,eAAO,MAAM,QAAQ,EAAE;IACtB,CAAC,MAAM,EACN,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACjJ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;CASpG,CAAC"}
|
package/dist/transact.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Effect, Hash } from "effect";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import { SqlClient } from "effect/sql";
|
|
5
|
+
import { isSqlError } from "effect/sql/SqlError";
|
|
6
|
+
import { makeChannel } from "@shivaedev/changes/channel.ts";
|
|
7
|
+
function hashOf(value) {
|
|
8
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean"
|
|
9
|
+
? String(value)
|
|
10
|
+
: Hash.hash(value);
|
|
11
|
+
}
|
|
12
|
+
function isList(keys) {
|
|
13
|
+
return Array.isArray(keys);
|
|
14
|
+
}
|
|
15
|
+
function flatten(keys) {
|
|
16
|
+
return isList(keys) ? keys : Object.entries(keys).flatMap(([name, ids]) => [name, ...ids.map((id) => `${name}:${hashOf(id)}`)]);
|
|
17
|
+
}
|
|
18
|
+
const guard = Effect.fn("Transact.guard")(function* () {
|
|
19
|
+
const sql = yield* SqlClient.SqlClient;
|
|
20
|
+
const native = yield* Effect.serviceOption(sql.transactionService);
|
|
21
|
+
if (native._tag === "Some") {
|
|
22
|
+
return yield* Effect.die(new Error("transact cannot announce changes after a transaction it does not own; begin the outer transaction with transact"));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const invalidations = makeChannel({
|
|
26
|
+
name: "@shivaedev/sql/transact",
|
|
27
|
+
owner: Effect.map(SqlClient.SqlClient, (sql) => sql.transactionService),
|
|
28
|
+
publish: (keys) => Reactivity.invalidate(keys),
|
|
29
|
+
unowned: guard(),
|
|
30
|
+
});
|
|
31
|
+
export const ChangeObserver = invalidations.Observer;
|
|
32
|
+
export const BeforeCommit = invalidations.BeforeCommit;
|
|
33
|
+
export const CommittedSink = invalidations.CommittedSink;
|
|
34
|
+
export const invalidateOnCommit = Effect.fn("Transact.invalidateOnCommit")(function* (keys) {
|
|
35
|
+
yield* invalidations.record(flatten(keys));
|
|
36
|
+
});
|
|
37
|
+
export const transact = dual(2, Effect.fn("Transact.transact")(function* (effect, options) {
|
|
38
|
+
const sql = yield* SqlClient.SqlClient;
|
|
39
|
+
return yield* invalidations
|
|
40
|
+
.within(sql.withTransaction)(effect)
|
|
41
|
+
.pipe(Effect.catchIf(isSqlError, (error) => Effect.fail(options.onSqlError(error))));
|
|
42
|
+
}));
|
|
43
|
+
//# sourceMappingURL=transact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transact.js","sourceRoot":"","sources":["../src/transact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
|
+
import type { SqlClient } from "effect/sql";
|
|
4
|
+
export declare const tupleFilter: unique symbol;
|
|
5
|
+
type Row<TModel extends Model.Any> = Schema.Struct.Type<TModel["fields"]>;
|
|
6
|
+
type Key<TModel extends Model.Any> = Extract<keyof Row<TModel>, string>;
|
|
7
|
+
export interface TupleFilter<TModel extends Model.Any> {
|
|
8
|
+
readonly [tupleFilter]: {
|
|
9
|
+
readonly model: TModel;
|
|
10
|
+
readonly fields: readonly Key<TModel>[];
|
|
11
|
+
readonly values: readonly (readonly unknown[])[];
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare function tupleIn<TModel extends Model.Any, const TFields extends readonly [Key<TModel>, Key<TModel>, ...Key<TModel>[]]>(model: TModel, fields: TFields, values: readonly {
|
|
15
|
+
readonly [TIndex in keyof TFields]: Row<TModel>[TFields[TIndex]];
|
|
16
|
+
}[]): TupleFilter<TModel>;
|
|
17
|
+
export declare function tuplePredicate(input: Partial<TupleFilter<Model.Any>>, sql: SqlClient.SqlClient, fieldAt: (key: string) => Effect.Effect<Schema.Constraint, Schema.SchemaError>): Effect.Effect<undefined, never, never> | Effect.Effect<import("effect/sql/Statement").Fragment, Schema.SchemaError, unknown>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=tupleIn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tupleIn.d.ts","sourceRoot":"","sources":["../src/tupleIn.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;AAE5C,eAAO,MAAM,WAAW,eAAwB,CAAC;AACjD,KAAK,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1E,KAAK,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAExE,MAAM,WAAW,WAAW,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG;IACpD,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;KACjD,CAAC;CACF;AAED,wBAAgB,OAAO,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,SAAS,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAC5H,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,SAAS;IAAE,QAAQ,EAAE,MAAM,IAAI,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;CAAE,EAAE,GACrF,WAAW,CAAC,MAAM,CAAC,CAErB;AAED,wBAAgB,cAAc,CAC7B,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EACtC,GAAG,EAAE,SAAS,CAAC,SAAS,EACxB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,gIAgB9E"}
|
package/dist/tupleIn.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
export const tupleFilter = Symbol("sql/tupleIn");
|
|
3
|
+
export function tupleIn(model, fields, values) {
|
|
4
|
+
return { [tupleFilter]: { fields, model, values } };
|
|
5
|
+
}
|
|
6
|
+
export function tuplePredicate(input, sql, fieldAt) {
|
|
7
|
+
const tuple = input[tupleFilter];
|
|
8
|
+
if (tuple === undefined) {
|
|
9
|
+
return Effect.succeed(undefined);
|
|
10
|
+
}
|
|
11
|
+
return Effect.gen(function* () {
|
|
12
|
+
const fields = yield* Effect.forEach(tuple.fields, fieldAt);
|
|
13
|
+
const encode = Schema.encodeUnknownEffect(Schema.Tuple(fields));
|
|
14
|
+
const columns = sql.csv(tuple.fields.map((field) => sql `${sql(field)}`));
|
|
15
|
+
// Row comparisons retain column type inference for string-encoded numerics without PostgreSQL's deeply nested row-IN rewrite.
|
|
16
|
+
const rows = yield* Effect.forEach(tuple.values, (value) => Effect.map(encode(value), (encoded) => sql `(${columns}) = (${sql.csv(encoded.map((entry) => sql `${entry}`))})`));
|
|
17
|
+
return rows.length === 0 ? sql `1 = 0` : sql.or(rows);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=tupleIn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tupleIn.js","sourceRoot":"","sources":["../src/tupleIn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIxC,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;AAYjD,MAAM,UAAU,OAAO,CACtB,KAAa,EACb,MAAe,EACf,MAAuF;IAEvF,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,cAAc,CAC7B,KAAsC,EACtC,GAAwB,EACxB,OAA8E;IAE9E,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IACjC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACzE,8HAA8H;QAC9H,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAC1D,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAA,IAAI,OAAO,QAAQ,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAC/G,CAAC;QACF,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Effect, Option, Schema } from "effect";
|
|
2
|
+
import type { Model } from "effect/schema";
|
|
3
|
+
import type { SqlClient, SqlModel } from "effect/sql";
|
|
4
|
+
import type { SqlError } from "effect/sql/SqlError";
|
|
5
|
+
import type { PrimaryKey, Repository } from "#compositeRepository.ts";
|
|
6
|
+
import type { OptimisticConcurrencyError } from "#repository.ts";
|
|
7
|
+
import { type VersionedOptions } from "#versionedStatements.ts";
|
|
8
|
+
import type { RepositoryChanges } from "./repositoryChanges.ts";
|
|
9
|
+
export type IdColumn<TModel extends Model.Any> = keyof TModel["Type"] & keyof TModel["update"]["Type"] & keyof TModel["fields"];
|
|
10
|
+
export type VersionColumn<TModel extends Model.Any, TId extends PrimaryKey<TModel>> = {
|
|
11
|
+
[TKey in Extract<keyof TModel["fields"] & keyof TModel["update"]["Type"], string>]: TModel["fields"][TKey] extends Schema.ConstraintCodec<number, number, never, never> ? TModel["update"]["Type"] extends {
|
|
12
|
+
readonly [TField in TKey]: number;
|
|
13
|
+
} ? TKey : never : never;
|
|
14
|
+
}[Extract<keyof TModel["fields"] & keyof TModel["update"]["Type"], string>] & Exclude<keyof TModel["fields"], (TId extends readonly PropertyKey[] ? TId[number] : TId) | keyof TModel["insert"]["Type"]>;
|
|
15
|
+
export type NativeRepository<TModel extends Model.Any, TId extends IdColumn<TModel>> = Effect.Success<ReturnType<typeof SqlModel.makeRepository<TModel, TId>>>;
|
|
16
|
+
type WriteError = SqlError | Schema.SchemaError | OptimisticConcurrencyError;
|
|
17
|
+
type KeyColumn<TModel extends Model.Any, TId extends PrimaryKey<TModel>> = TId extends readonly IdColumn<TModel>[] ? TId[number] : Extract<TId, IdColumn<TModel>>;
|
|
18
|
+
export interface VersionedWrites<TModel extends Model.Any, TId extends PrimaryKey<TModel>> {
|
|
19
|
+
readonly delete: (id: TId extends readonly IdColumn<TModel>[] ? Pick<TModel["Type"], TId[number]> : TModel["fields"][Extract<TId, IdColumn<TModel>>]["Type"], expectedVersion: number) => Effect.Effect<void, WriteError, TModel["fields"][KeyColumn<TModel, TId>]["EncodingServices"]>;
|
|
20
|
+
readonly insert: Repository<TModel, TId>["insert"];
|
|
21
|
+
readonly insertVoid: Repository<TModel, TId>["insertVoid"];
|
|
22
|
+
readonly update: (input: TModel["update"]["Type"]) => Effect.Effect<TModel["Type"], WriteError, TModel["update"]["EncodingServices"] | TModel["DecodingServices"]>;
|
|
23
|
+
readonly updateVoid: (input: TModel["update"]["Type"]) => Effect.Effect<void, WriteError, TModel["update"]["EncodingServices"]>;
|
|
24
|
+
}
|
|
25
|
+
export declare function makeVersionedWrites(model: Model.Any, sql: SqlClient.SqlClient, options: VersionedOptions & {
|
|
26
|
+
readonly changes: RepositoryChanges;
|
|
27
|
+
readonly spanPrefix: string;
|
|
28
|
+
}): {
|
|
29
|
+
delete: (id: unknown, expected: number) => Effect.Effect<undefined, OptimisticConcurrencyError | Schema.SchemaError | SqlError, unknown>;
|
|
30
|
+
insert: (input: unknown) => Effect.Effect<unknown, Schema.SchemaError | SqlError, unknown>;
|
|
31
|
+
insertVoid: (input: unknown) => Effect.Effect<void, Schema.SchemaError | SqlError, unknown>;
|
|
32
|
+
update: (input: Readonly<Record<string, unknown>>) => Effect.Effect<unknown, OptimisticConcurrencyError | Schema.SchemaError | SqlError, unknown>;
|
|
33
|
+
updateVoid: (input: Readonly<Record<string, unknown>>) => Effect.Effect<undefined, OptimisticConcurrencyError | Schema.SchemaError | SqlError, unknown>;
|
|
34
|
+
insertOrIgnore?: (input: unknown) => Effect.Effect<Option.None<unknown> | Option.Some<unknown>, Schema.SchemaError | SqlError, unknown>;
|
|
35
|
+
};
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=versionedRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versionedRepository.d.ts","sourceRoot":"","sources":["../src/versionedRepository.ts"],"names":[],"mappings":"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"}
|