@shivaedev/sql 0.27.0 → 0.29.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 +25 -0
- package/README.md +25 -10
- package/dist/adapters/makePostgresClient.d.ts.map +1 -1
- package/dist/adapters/makePostgresClient.js +8 -1
- package/dist/adapters/makePostgresClient.js.map +1 -1
- package/dist/latestPerGroup.d.ts +1 -1
- package/dist/latestPerGroup.d.ts.map +1 -1
- package/dist/latestPerGroup.js +37 -13
- package/dist/latestPerGroup.js.map +1 -1
- package/dist/listenForChanges.d.ts.map +1 -1
- package/dist/listenForChanges.js +11 -5
- package/dist/listenForChanges.js.map +1 -1
- package/dist/pinnedGroups.d.ts +9 -1
- package/dist/pinnedGroups.d.ts.map +1 -1
- package/dist/pinnedGroups.js +2 -2
- package/dist/pinnedGroups.js.map +1 -1
- package/dist/postgresChanges.d.ts +1 -0
- package/dist/postgresChanges.d.ts.map +1 -1
- package/dist/postgresChanges.js.map +1 -1
- package/dist/postgresLayer.d.ts +3 -0
- package/dist/postgresLayer.d.ts.map +1 -1
- package/dist/postgresLayer.js.map +1 -1
- package/dist/repository.d.ts +5 -9
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +2 -0
- package/dist/repository.js.map +1 -1
- package/dist/repositoryCollection.d.ts +28 -0
- package/dist/repositoryCollection.d.ts.map +1 -0
- package/dist/repositoryCollection.js +21 -0
- package/dist/repositoryCollection.js.map +1 -0
- package/dist/testing.d.ts +2 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/tupleIn.d.ts +4 -2
- package/dist/tupleIn.d.ts.map +1 -1
- package/dist/tupleIn.js +13 -5
- package/dist/tupleIn.js.map +1 -1
- package/dist/tupleUnnest.d.ts +5 -0
- package/dist/tupleUnnest.d.ts.map +1 -0
- package/dist/tupleUnnest.js +26 -0
- package/dist/tupleUnnest.js.map +1 -0
- package/package.json +4 -4
- package/src/adapters/makePostgresClient.ts +9 -1
- package/src/latestPerGroup.ts +41 -14
- package/src/listenForChanges.ts +13 -10
- package/src/pinnedGroups.ts +5 -3
- package/src/postgresChanges.ts +1 -0
- package/src/postgresLayer.ts +3 -0
- package/src/repository.ts +11 -11
- package/src/repositoryCollection.ts +46 -0
- package/src/testing.ts +7 -3
- package/src/tupleIn.ts +40 -7
- package/src/tupleUnnest.ts +25 -0
package/src/testing.ts
CHANGED
|
@@ -76,8 +76,12 @@ export class PublishedKeysMismatch extends Data.TaggedError("PublishedKeysMismat
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
export function expectPublished(keys: readonly unknown[])
|
|
80
|
-
|
|
79
|
+
export function expectPublished(keys: readonly unknown[]): <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch, R>;
|
|
80
|
+
export function expectPublished<A>(
|
|
81
|
+
keys: (result: A) => readonly unknown[],
|
|
82
|
+
): <E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch, R>;
|
|
83
|
+
export function expectPublished<A>(keys: readonly unknown[] | ((result: A) => readonly unknown[])) {
|
|
84
|
+
return Effect.fn("Changes.expectPublished")(function* <E, R>(body: Effect.Effect<A, E, R>) {
|
|
81
85
|
const observer = yield* ChangeObserver;
|
|
82
86
|
const actual = new Set<unknown>();
|
|
83
87
|
const result = yield* body.pipe(
|
|
@@ -90,7 +94,7 @@ export function expectPublished(keys: readonly unknown[]) {
|
|
|
90
94
|
return observer(event);
|
|
91
95
|
}),
|
|
92
96
|
);
|
|
93
|
-
const expected = new Set(keys);
|
|
97
|
+
const expected = new Set(typeof keys === "function" ? keys(result) : keys);
|
|
94
98
|
if (actual.size !== expected.size || [...expected].some((key) => !actual.has(key))) {
|
|
95
99
|
return yield* Effect.fail(new PublishedKeysMismatch({ actual: [...actual], expected: [...expected] }));
|
|
96
100
|
}
|
package/src/tupleIn.ts
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
2
|
import type { Model } from "effect/schema";
|
|
3
|
-
import
|
|
3
|
+
import { SqlClient } from "effect/sql";
|
|
4
|
+
import { tupleUnnest } from "#tupleUnnest.ts";
|
|
5
|
+
|
|
6
|
+
export type TupleColumnType =
|
|
7
|
+
| "bool"
|
|
8
|
+
| "bpchar"
|
|
9
|
+
| "bytea"
|
|
10
|
+
| "cidr"
|
|
11
|
+
| "date"
|
|
12
|
+
| "float4"
|
|
13
|
+
| "float8"
|
|
14
|
+
| "inet"
|
|
15
|
+
| "int2"
|
|
16
|
+
| "int4"
|
|
17
|
+
| "int8"
|
|
18
|
+
| "interval"
|
|
19
|
+
| "jsonb"
|
|
20
|
+
| "name"
|
|
21
|
+
| "numeric"
|
|
22
|
+
| "oid"
|
|
23
|
+
| "regclass"
|
|
24
|
+
| "text"
|
|
25
|
+
| "time"
|
|
26
|
+
| "timestamp"
|
|
27
|
+
| "timestamptz"
|
|
28
|
+
| "timetz"
|
|
29
|
+
| "uuid"
|
|
30
|
+
| "varchar";
|
|
4
31
|
|
|
5
32
|
export const tupleFilter = Symbol("sql/tupleIn");
|
|
6
33
|
type Row<TModel extends Model.Any> = Schema.Struct.Type<TModel["fields"]>;
|
|
@@ -11,6 +38,7 @@ export interface TupleFilter<TModel extends Model.Any> {
|
|
|
11
38
|
readonly model: TModel;
|
|
12
39
|
readonly fields: readonly Key<TModel>[];
|
|
13
40
|
readonly values: readonly (readonly unknown[])[];
|
|
41
|
+
readonly types: readonly TupleColumnType[];
|
|
14
42
|
};
|
|
15
43
|
}
|
|
16
44
|
|
|
@@ -18,8 +46,9 @@ export function tupleIn<TModel extends Model.Any, const TFields extends readonly
|
|
|
18
46
|
model: TModel,
|
|
19
47
|
fields: TFields,
|
|
20
48
|
values: readonly { readonly [TIndex in keyof TFields]: Row<TModel>[TFields[TIndex]] }[],
|
|
49
|
+
types: Readonly<Record<TFields[number], TupleColumnType>>,
|
|
21
50
|
): TupleFilter<TModel> {
|
|
22
|
-
return { [tupleFilter]: { fields, model, values } };
|
|
51
|
+
return { [tupleFilter]: { fields, model, types: fields.map((field: TFields[number]) => types[field]), values } };
|
|
23
52
|
}
|
|
24
53
|
|
|
25
54
|
export function tuplePredicate(
|
|
@@ -35,10 +64,14 @@ export function tuplePredicate(
|
|
|
35
64
|
const fields = yield* Effect.forEach(tuple.fields, fieldAt);
|
|
36
65
|
const encode = Schema.encodeUnknownEffect(Schema.Tuple(fields));
|
|
37
66
|
const columns = sql.csv(tuple.fields.map((field) => sql`${sql(field)}`));
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
67
|
+
const rows: readonly (readonly unknown[])[] = yield* Effect.forEach(tuple.values, (value) => encode(value));
|
|
68
|
+
if (rows.length === 0) {
|
|
69
|
+
return sql`1 = 0`;
|
|
70
|
+
}
|
|
71
|
+
if (sql.onDialectOrElse({ orElse: () => false, pg: () => true })) {
|
|
72
|
+
const relation = yield* tupleUnnest(tuple.types, rows).pipe(Effect.provideService(SqlClient.SqlClient, sql));
|
|
73
|
+
return sql`(${columns}) in (select * from ${relation})`;
|
|
74
|
+
}
|
|
75
|
+
return sql.or(rows.map((row) => sql`(${columns}) = (${sql.csv(row.map((entry) => sql`${entry}`))})`));
|
|
43
76
|
});
|
|
44
77
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect, Result } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import type { TupleColumnType } from "#tupleIn.ts";
|
|
4
|
+
|
|
5
|
+
export const tupleUnnest = Effect.fnUntraced(function* (types: readonly TupleColumnType[], rows: readonly (readonly unknown[])[]) {
|
|
6
|
+
const sql = yield* SqlClient.SqlClient;
|
|
7
|
+
const pg = yield* Effect.promise(() => import("@effect/sql-pg/PgTypes"));
|
|
8
|
+
const arrays = types.map((type, index) => {
|
|
9
|
+
const entries = rows.map((row) => row[index]);
|
|
10
|
+
const values = entries.map((value) => (pg.isParameter(value) ? value.value : value));
|
|
11
|
+
// String-encoded fields rely on PostgreSQL input casts, including numerics and dates.
|
|
12
|
+
const first = entries.find((value) => value !== null && value !== undefined);
|
|
13
|
+
let oid: number = pg.OID[type];
|
|
14
|
+
if (pg.isParameter(first)) {
|
|
15
|
+
oid = first.oid;
|
|
16
|
+
} else if (first instanceof Date) {
|
|
17
|
+
oid = pg.OID.timestamptz;
|
|
18
|
+
} else if (values.every((value) => value === null || typeof value === "string")) {
|
|
19
|
+
oid = pg.OID.text;
|
|
20
|
+
}
|
|
21
|
+
const parameter = Result.getOrThrow(pg.array(values, oid));
|
|
22
|
+
return sql`${parameter}::${sql.literal(type)}[]`;
|
|
23
|
+
});
|
|
24
|
+
return sql`unnest(${sql.csv(arrays)})`;
|
|
25
|
+
});
|