@shivaedev/effect-prisma 0.7.1 → 0.9.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 +22 -0
- package/README.md +198 -155
- package/dist/database.d.ts +7 -7
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +12 -8
- package/dist/database.js.map +1 -1
- package/dist/databaseTypes.d.ts +33 -0
- package/dist/databaseTypes.d.ts.map +1 -0
- package/dist/{internal/database-types.js → databaseTypes.js} +1 -1
- package/dist/databaseTypes.js.map +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/internal/adapters/transaction-settlement.d.ts.map +1 -1
- package/dist/internal/adapters/transaction-settlement.js +9 -7
- package/dist/internal/adapters/transaction-settlement.js.map +1 -1
- package/dist/internal/client-lifecycle.d.ts.map +1 -1
- package/dist/internal/contract-normalization.d.ts.map +1 -1
- package/dist/internal/database-facade.d.ts +12 -12
- package/dist/internal/database-facade.d.ts.map +1 -1
- package/dist/internal/database-facade.js.map +1 -1
- package/dist/internal/database-factory.d.ts +2 -2
- package/dist/internal/database-factory.d.ts.map +1 -1
- package/dist/internal/database-factory.js +3 -3
- package/dist/internal/database-factory.js.map +1 -1
- package/dist/internal/dynamic.d.ts.map +1 -1
- package/dist/internal/dynamic.js +3 -1
- package/dist/internal/dynamic.js.map +1 -1
- package/dist/internal/executor.d.ts +6 -6
- package/dist/internal/executor.d.ts.map +1 -1
- package/dist/internal/promise.d.ts.map +1 -1
- package/dist/internal/query-execution.d.ts.map +1 -1
- package/dist/internal/recipe.d.ts.map +1 -1
- package/dist/internal/recipe.js +10 -10
- package/dist/internal/recipe.js.map +1 -1
- package/dist/internal/relation-plan.d.ts.map +1 -1
- package/dist/internal/relation-result.d.ts.map +1 -1
- package/dist/internal/relation-result.js +6 -2
- package/dist/internal/relation-result.js.map +1 -1
- package/dist/internal/relation-runtime.d.ts +1 -1
- package/dist/internal/relation-runtime.d.ts.map +1 -1
- package/dist/internal/relation-runtime.js +11 -6
- package/dist/internal/relation-runtime.js.map +1 -1
- package/dist/internal/relation-stream.d.ts +1 -1
- package/dist/internal/relation-stream.d.ts.map +1 -1
- package/dist/internal/relation-stream.js +9 -7
- package/dist/internal/relation-stream.js.map +1 -1
- package/dist/internal/sqlite-datetime.d.ts.map +1 -1
- package/dist/internal/sqlite-datetime.js +11 -9
- package/dist/internal/sqlite-datetime.js.map +1 -1
- package/dist/internal/sqlite-pragmas.d.ts.map +1 -1
- package/dist/internal/testing.d.ts +5 -5
- package/dist/internal/testing.d.ts.map +1 -1
- package/dist/internal/testing.js.map +1 -1
- package/dist/internal/transaction.d.ts +6 -6
- package/dist/internal/transaction.d.ts.map +1 -1
- package/dist/internal/transaction.js +5 -3
- package/dist/internal/transaction.js.map +1 -1
- package/dist/relation/include.d.ts +20 -20
- package/dist/relation/include.d.ts.map +1 -1
- package/dist/relation.d.ts +23 -23
- package/dist/relation.d.ts.map +1 -1
- package/dist/sqlite.d.ts +1 -1
- package/dist/sqlite.d.ts.map +1 -1
- package/dist/sqlite.js +8 -6
- package/dist/sqlite.js.map +1 -1
- package/dist/testing/transaction.d.ts +1 -1
- package/dist/testing/transaction.d.ts.map +1 -1
- package/dist/testing/transaction.js.map +1 -1
- package/dist/testing/types.d.ts +2 -3
- package/dist/testing/types.d.ts.map +1 -1
- package/dist/testing/vitest.d.ts +2 -1
- package/dist/testing/vitest.d.ts.map +1 -1
- package/dist/testing/vitest.js +1 -1
- package/dist/testing/vitest.js.map +1 -1
- package/docs/north-star.md +47 -0
- package/docs/roadmap.md +32 -0
- package/package.json +33 -40
- package/src/database.ts +30 -30
- package/src/databaseTypes.ts +65 -0
- package/src/internal/adapters/transaction-settlement.ts +9 -8
- package/src/internal/database-facade.ts +28 -28
- package/src/internal/database-factory.ts +15 -15
- package/src/internal/dynamic.ts +3 -1
- package/src/internal/executor.ts +6 -6
- package/src/internal/recipe.ts +10 -10
- package/src/internal/relation-result.ts +6 -3
- package/src/internal/relation-runtime.ts +25 -20
- package/src/internal/relation-stream.ts +5 -4
- package/src/internal/sqlite-datetime.ts +11 -9
- package/src/internal/testing.ts +8 -8
- package/src/internal/transaction.ts +16 -15
- package/src/relation/include.ts +48 -48
- package/src/relation.ts +38 -38
- package/src/sqlite.ts +9 -7
- package/src/testing/transaction.ts +1 -1
- package/src/testing/types.ts +2 -3
- package/src/testing/vitest.ts +4 -2
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +0 -1
- package/dist/internal/database-types.d.ts +0 -33
- package/dist/internal/database-types.d.ts.map +0 -1
- package/dist/internal/database-types.js.map +0 -1
- package/dist/testing.d.ts +0 -4
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -3
- package/dist/testing.js.map +0 -1
- package/src/index.ts +0 -17
- package/src/internal/database-types.ts +0 -65
- package/src/testing.ts +0 -10
|
@@ -3,10 +3,13 @@ import type { PrismaError } from "#error.ts";
|
|
|
3
3
|
import { hasMethod, invokeMethod, isPromiseLike } from "./dynamic.ts";
|
|
4
4
|
import { fromPrismaPromise } from "./promise.ts";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
isPromiseLike(value) ? fromPrismaPromise(() => value).pipe(Effect.map(map)) : Effect.succeed(map(value));
|
|
6
|
+
function settle(value: unknown, map: (result: unknown) => unknown): Effect.Effect<unknown, PrismaError> {
|
|
7
|
+
return isPromiseLike(value) ? fromPrismaPromise(() => value).pipe(Effect.map(map)) : Effect.succeed(map(value));
|
|
8
|
+
}
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
function countOf(result: unknown): unknown {
|
|
11
|
+
return typeof result === "object" && result !== null ? Reflect.get(result, "count") : undefined;
|
|
12
|
+
}
|
|
10
13
|
|
|
11
14
|
export const evaluateResult = (value: unknown, terminal: PropertyKey | undefined): Effect.Effect<unknown, PrismaError> => {
|
|
12
15
|
if (terminal === "count" && hasMethod(value, "aggregate")) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Effect, Effectable, type Stream } from "effect";
|
|
2
2
|
import type { PrismaError } from "#error.ts";
|
|
3
3
|
import type { Relation } from "#relation.ts";
|
|
4
|
+
import { hasMethod } from "./dynamic.ts";
|
|
4
5
|
import type { AnyPostgresContract, DatabaseExecutor } from "./executor.ts";
|
|
5
6
|
import { executeQuery } from "./query-execution.ts";
|
|
6
7
|
import { appendOperation, type RelationRecipe, replayRecipe, rootRecipe } from "./recipe.ts";
|
|
@@ -8,10 +9,10 @@ import { setRelationPlan } from "./relation-plan.ts";
|
|
|
8
9
|
import { evaluateResult } from "./relation-result.ts";
|
|
9
10
|
import { makeRelationStream } from "./relation-stream.ts";
|
|
10
11
|
|
|
11
|
-
interface RelationRuntime<
|
|
12
|
-
readonly executor: DatabaseExecutor<
|
|
12
|
+
interface RelationRuntime<TModels extends object, TContract extends AnyPostgresContract> {
|
|
13
|
+
readonly executor: DatabaseExecutor<TModels, TContract>;
|
|
13
14
|
readonly recipe: RelationRecipe;
|
|
14
|
-
readonly resolveExecutor: Effect.Effect<DatabaseExecutor<
|
|
15
|
+
readonly resolveExecutor: Effect.Effect<DatabaseExecutor<TModels, TContract>, PrismaError>;
|
|
15
16
|
readonly terminal?: PropertyKey;
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -23,15 +24,15 @@ type AnyRelationRuntime = RelationRuntime<object, AnyPostgresContract>;
|
|
|
23
24
|
|
|
24
25
|
const runtimes = new WeakMap<object, AnyRelationRuntime>();
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
function runtimeOf(self: object): AnyRelationRuntime {
|
|
27
28
|
const runtime = runtimes.get(self);
|
|
28
29
|
if (runtime === undefined) {
|
|
29
30
|
throw new TypeError("Relation runtime is unavailable");
|
|
30
31
|
}
|
|
31
32
|
return runtime;
|
|
32
|
-
}
|
|
33
|
+
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
function relationEffect(self: object): Effect.Effect<unknown, PrismaError> {
|
|
35
36
|
const runtime = runtimeOf(self);
|
|
36
37
|
return Effect.flatMap(runtime.resolveExecutor, (executor) =>
|
|
37
38
|
executeQuery(
|
|
@@ -50,11 +51,11 @@ const relationEffect = (self: object): Effect.Effect<unknown, PrismaError> => {
|
|
|
50
51
|
kind: "client",
|
|
51
52
|
}),
|
|
52
53
|
);
|
|
53
|
-
}
|
|
54
|
+
}
|
|
54
55
|
|
|
55
56
|
const RelationPrototype = {
|
|
56
57
|
...Effectable.Prototype<RelationValue>({
|
|
57
|
-
evaluate() {
|
|
58
|
+
evaluate(this: RelationValue) {
|
|
58
59
|
return relationEffect(this);
|
|
59
60
|
},
|
|
60
61
|
label: "EffectPrismaRelation",
|
|
@@ -65,7 +66,7 @@ const RelationPrototype = {
|
|
|
65
66
|
},
|
|
66
67
|
};
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
function makeRelationProxy(runtime: AnyRelationRuntime): object {
|
|
69
70
|
const target: object = Object.create(RelationPrototype);
|
|
70
71
|
const proxy = new Proxy(target, {
|
|
71
72
|
get(self, property, receiver) {
|
|
@@ -89,6 +90,10 @@ const makeRelationProxy = (runtime: AnyRelationRuntime): object => {
|
|
|
89
90
|
terminal: "count",
|
|
90
91
|
});
|
|
91
92
|
}
|
|
93
|
+
// Effect reads protocol keys such as its Exit identifier from every yielded value, so only the collection's own methods become Relation calls.
|
|
94
|
+
if (!hasMethod(Reflect.get(runtime.executor.models, runtime.recipe.model), property)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
92
97
|
return (...arguments_: readonly unknown[]) =>
|
|
93
98
|
makeRelationProxy({
|
|
94
99
|
...runtime,
|
|
@@ -109,25 +114,25 @@ const makeRelationProxy = (runtime: AnyRelationRuntime): object => {
|
|
|
109
114
|
setRelationPlan(value, plan);
|
|
110
115
|
}
|
|
111
116
|
return proxy;
|
|
112
|
-
}
|
|
117
|
+
}
|
|
113
118
|
|
|
114
119
|
// The proxy replays every Relation call onto the Prisma collection for `model`, so it has that collection's Relation surface.
|
|
115
|
-
function asRelation<
|
|
120
|
+
function asRelation<TCollection, TModel extends string>(proxy: object): Relation<TCollection, undefined, TModel>;
|
|
116
121
|
function asRelation(proxy: object): unknown {
|
|
117
122
|
return proxy;
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
export const makeModelRelation = <
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
TCollection,
|
|
127
|
+
TModels extends object,
|
|
128
|
+
TExecutorContract extends AnyPostgresContract = AnyPostgresContract,
|
|
129
|
+
TModel extends string = string,
|
|
125
130
|
>(
|
|
126
|
-
executor: DatabaseExecutor<
|
|
127
|
-
model:
|
|
128
|
-
resolveExecutor: Effect.Effect<DatabaseExecutor<
|
|
129
|
-
): Relation<
|
|
130
|
-
asRelation<
|
|
131
|
+
executor: DatabaseExecutor<TModels, TExecutorContract>,
|
|
132
|
+
model: TModel,
|
|
133
|
+
resolveExecutor: Effect.Effect<DatabaseExecutor<TModels, TExecutorContract>, PrismaError> = Effect.succeed(executor),
|
|
134
|
+
): Relation<TCollection, undefined, TModel> =>
|
|
135
|
+
asRelation<TCollection, TModel>(
|
|
131
136
|
makeRelationProxy({
|
|
132
137
|
executor,
|
|
133
138
|
recipe: rootRecipe(model),
|
|
@@ -6,17 +6,18 @@ import { fromPrismaPromise } from "./promise.ts";
|
|
|
6
6
|
import { executeQuery } from "./query-execution.ts";
|
|
7
7
|
import { type RelationRecipe, replayRecipe } from "./recipe.ts";
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
fromPrismaPromise(async () => {
|
|
9
|
+
function collectRows(iterable: AsyncIterable<unknown>): Effect.Effect<unknown[], PrismaError> {
|
|
10
|
+
return fromPrismaPromise(async () => {
|
|
11
11
|
const rows: unknown[] = [];
|
|
12
12
|
for await (const row of iterable) {
|
|
13
13
|
rows.push(row);
|
|
14
14
|
}
|
|
15
15
|
return rows;
|
|
16
16
|
});
|
|
17
|
+
}
|
|
17
18
|
|
|
18
|
-
export const makeRelationStream = <
|
|
19
|
-
resolveExecutor: Effect.Effect<DatabaseExecutor<
|
|
19
|
+
export const makeRelationStream = <TModels extends object, TContract extends AnyPostgresContract>(
|
|
20
|
+
resolveExecutor: Effect.Effect<DatabaseExecutor<TModels, TContract>, PrismaError>,
|
|
20
21
|
recipe: RelationRecipe,
|
|
21
22
|
): Stream.Stream<unknown, PrismaError> =>
|
|
22
23
|
Stream.unwrap(
|
|
@@ -14,13 +14,15 @@ const zonelessDatetime = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}(?::\d{2})?(?:\.\d
|
|
|
14
14
|
// with no zone, and `new Date` reads that form as local time. Values with a zone and date-only values already read as UTC.
|
|
15
15
|
export const normalizeSqliteDatetime = (value: string): string => value.replace(zonelessDatetime, "$1T$2Z");
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
function decodeAsUtc(codec: ContractCodec): ContractCodec {
|
|
18
|
+
return {
|
|
19
|
+
decode: (wire: CodecWire, context) => codec.decode(typeof wire === "string" ? normalizeSqliteDatetime(wire) : wire, context),
|
|
20
|
+
decodeJson: (json: CodecJson) => codec.decodeJson(typeof json === "string" ? normalizeSqliteDatetime(json) : json),
|
|
21
|
+
encode: (value, context) => codec.encode(value, context),
|
|
22
|
+
encodeJson: (value) => codec.encodeJson(value),
|
|
23
|
+
id: sqliteDatetimeCodecId,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
24
26
|
|
|
25
27
|
// The registry resolves codecs for rows and included relations alike, and Prisma Next rejects a second descriptor for a registered
|
|
26
28
|
// codec id, so wrapping the registry is the one way to cover every read. It must run before the first query, which reads the
|
|
@@ -30,7 +32,7 @@ export const decodeSqliteDatetimesAsUtc = (context: ExecutionContext<AnySqlContr
|
|
|
30
32
|
const descriptors = context.codecDescriptors;
|
|
31
33
|
const utcCodecs = new WeakMap<ContractCodec, ContractCodec>();
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
function wrap(codec: ContractCodec): ContractCodec {
|
|
34
36
|
const existing = utcCodecs.get(codec);
|
|
35
37
|
if (existing !== undefined) {
|
|
36
38
|
return existing;
|
|
@@ -38,7 +40,7 @@ export const decodeSqliteDatetimesAsUtc = (context: ExecutionContext<AnySqlContr
|
|
|
38
40
|
const utc = decodeAsUtc(codec);
|
|
39
41
|
utcCodecs.set(codec, utc);
|
|
40
42
|
return utc;
|
|
41
|
-
}
|
|
43
|
+
}
|
|
42
44
|
|
|
43
45
|
const utcRegistry: CodecRegistry = {
|
|
44
46
|
forCodecRef: (reference) => {
|
package/src/internal/testing.ts
CHANGED
|
@@ -3,28 +3,28 @@ import type { PrismaError } from "#error.ts";
|
|
|
3
3
|
|
|
4
4
|
export const DatabaseTestingTypeId: unique symbol = Symbol.for("@shivaedev/effect-prisma/DatabaseTesting");
|
|
5
5
|
|
|
6
|
-
export interface DatabaseTesting<
|
|
6
|
+
export interface DatabaseTesting<TDatabaseId> {
|
|
7
7
|
readonly withTestTransaction: <A, E, R>(
|
|
8
|
-
program: Effect.Effect<A, E, R> & (
|
|
9
|
-
) => Effect.Effect<A, E | PrismaError,
|
|
8
|
+
program: Effect.Effect<A, E, R> & (TDatabaseId extends R ? unknown : never),
|
|
9
|
+
) => Effect.Effect<A, E | PrismaError, TDatabaseId | Exclude<R, TDatabaseId>>;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export interface DatabaseWithTesting<
|
|
13
|
-
readonly [DatabaseTestingTypeId]: DatabaseTesting<
|
|
12
|
+
export interface DatabaseWithTesting<TDatabaseId> {
|
|
13
|
+
readonly [DatabaseTestingTypeId]: DatabaseTesting<TDatabaseId>;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// makeSqlDatabase installs the testing hooks for the database's own service identifier.
|
|
17
|
-
function testingFor<
|
|
17
|
+
function testingFor<TDatabaseId>(testing: object): DatabaseTesting<TDatabaseId>;
|
|
18
18
|
function testingFor(testing: object): unknown {
|
|
19
19
|
return testing;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export const getDatabaseTesting = <
|
|
22
|
+
export const getDatabaseTesting = <TDatabaseId>(database: object): DatabaseTesting<TDatabaseId> => {
|
|
23
23
|
const testing: unknown = Reflect.get(database, DatabaseTestingTypeId);
|
|
24
24
|
|
|
25
25
|
if (typeof testing !== "object" || testing === null || typeof Reflect.get(testing, "withTestTransaction") !== "function") {
|
|
26
26
|
throw new TypeError("The database was not created by this copy of @shivaedev/effect-prisma");
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
return testingFor<
|
|
29
|
+
return testingFor<TDatabaseId>(testing);
|
|
30
30
|
};
|
|
@@ -5,26 +5,26 @@ import { type SettledConnection, type SettledTransaction, settleConnection } fro
|
|
|
5
5
|
import type { AnySqlContract, DatabaseExecutor } from "./executor.ts";
|
|
6
6
|
import { fromPrismaPromise } from "./promise.ts";
|
|
7
7
|
|
|
8
|
-
export type TransactionOrm<
|
|
8
|
+
export type TransactionOrm<TContract extends AnySqlContract> = ReturnType<typeof orm<TContract>>;
|
|
9
9
|
|
|
10
10
|
export const withTransactionSemaphore = <A, E, R>(
|
|
11
11
|
semaphore: Semaphore.Semaphore | undefined,
|
|
12
12
|
transaction: Effect.Effect<A, E, R>,
|
|
13
13
|
): Effect.Effect<A, E, R> => (semaphore === undefined ? transaction : semaphore.withPermit(transaction));
|
|
14
14
|
|
|
15
|
-
export interface TransactionResource<
|
|
15
|
+
export interface TransactionResource<TModels extends object, TContract extends AnySqlContract> {
|
|
16
16
|
readonly connection: SettledConnection;
|
|
17
|
-
readonly executor: DatabaseExecutor<
|
|
17
|
+
readonly executor: DatabaseExecutor<TModels, TContract> & {
|
|
18
18
|
readonly querySemaphore: Semaphore.Semaphore;
|
|
19
19
|
};
|
|
20
20
|
readonly transaction: SettledTransaction;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export const acquireTransaction = <
|
|
24
|
-
current: DatabaseExecutor<
|
|
25
|
-
models: (orm: TransactionOrm<
|
|
23
|
+
export const acquireTransaction = <TModels extends object, TContract extends AnySqlContract>(
|
|
24
|
+
current: DatabaseExecutor<TModels, TContract>,
|
|
25
|
+
models: (orm: TransactionOrm<TContract>) => TModels,
|
|
26
26
|
mode: "test" | "transaction",
|
|
27
|
-
): Effect.Effect<TransactionResource<
|
|
27
|
+
): Effect.Effect<TransactionResource<TModels, TContract>, PrismaError> =>
|
|
28
28
|
fromPrismaPromise(async () => {
|
|
29
29
|
const connection = await current.client.runtime().connection();
|
|
30
30
|
|
|
@@ -58,22 +58,22 @@ export const acquireTransaction = <Models extends object, Contract extends AnySq
|
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
export const releaseTransaction = <
|
|
62
|
-
resource: TransactionResource<
|
|
61
|
+
export const releaseTransaction = <TModels extends object, TContract extends AnySqlContract, A, E>(
|
|
62
|
+
resource: TransactionResource<TModels, TContract>,
|
|
63
63
|
exit: Exit.Exit<A, E>,
|
|
64
64
|
): Effect.Effect<void, PrismaError> => settleTransaction(resource, exit, true);
|
|
65
65
|
|
|
66
|
-
export const releaseTestTransaction = <
|
|
67
|
-
resource: TransactionResource<
|
|
66
|
+
export const releaseTestTransaction = <TModels extends object, TContract extends AnySqlContract, A, E>(
|
|
67
|
+
resource: TransactionResource<TModels, TContract>,
|
|
68
68
|
exit: Exit.Exit<A, E>,
|
|
69
69
|
): Effect.Effect<void, PrismaError> => settleTransaction(resource, exit, false);
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
resource: TransactionResource<
|
|
71
|
+
function settleTransaction<TModels extends object, TContract extends AnySqlContract, A, E>(
|
|
72
|
+
resource: TransactionResource<TModels, TContract>,
|
|
73
73
|
exit: Exit.Exit<A, E>,
|
|
74
74
|
commitOnSuccess: boolean,
|
|
75
|
-
): Effect.Effect<void, PrismaError>
|
|
76
|
-
Effect.uninterruptible(
|
|
75
|
+
): Effect.Effect<void, PrismaError> {
|
|
76
|
+
return Effect.uninterruptible(
|
|
77
77
|
Effect.sync(() => {
|
|
78
78
|
resource.executor.liveness.open = false;
|
|
79
79
|
}).pipe(
|
|
@@ -82,3 +82,4 @@ const settleTransaction = <Models extends object, Contract extends AnySqlContrac
|
|
|
82
82
|
),
|
|
83
83
|
),
|
|
84
84
|
);
|
|
85
|
+
}
|
package/src/relation/include.ts
CHANGED
|
@@ -2,18 +2,18 @@ import type { DefaultModelRow, Collection as PrismaCollection, RelationNames } f
|
|
|
2
2
|
import type { Relation, RelationQuery } from "#relation.ts";
|
|
3
3
|
import type { AnyPostgresContract, IncludedRelationValue, IsToManyRelation, RelatedModelNameOf } from "./include-metadata.ts";
|
|
4
4
|
|
|
5
|
-
type Simplify<
|
|
5
|
+
type Simplify<TValue> = { [TKey in keyof TValue]: TValue[TKey] };
|
|
6
6
|
|
|
7
|
-
type QueryValue<
|
|
7
|
+
type QueryValue<TQuery> = TQuery extends RelationQuery<infer TValue, infer _Contract, infer _Model, infer _DatabaseId> ? TValue : never;
|
|
8
8
|
|
|
9
|
-
type AcceptRelatedQuery<
|
|
10
|
-
RelationQuery<infer _Value, infer
|
|
9
|
+
type AcceptRelatedQuery<TQuery, TContract extends AnyPostgresContract, TModel extends string, TDatabaseId> = [TQuery] extends [
|
|
10
|
+
RelationQuery<infer _Value, infer TQueryContract, infer TQueryModel, infer TQueryDatabaseId>,
|
|
11
11
|
]
|
|
12
|
-
? [
|
|
13
|
-
? [
|
|
14
|
-
? [
|
|
15
|
-
? [
|
|
16
|
-
?
|
|
12
|
+
? [TQueryContract] extends [TContract]
|
|
13
|
+
? [TContract] extends [TQueryContract]
|
|
14
|
+
? [TQueryDatabaseId] extends [TDatabaseId]
|
|
15
|
+
? [TDatabaseId] extends [TQueryDatabaseId]
|
|
16
|
+
? TQueryModel extends TModel
|
|
17
17
|
? unknown
|
|
18
18
|
: never
|
|
19
19
|
: never
|
|
@@ -22,63 +22,63 @@ type AcceptRelatedQuery<Query, Contract extends AnyPostgresContract, Model exten
|
|
|
22
22
|
: never
|
|
23
23
|
: never;
|
|
24
24
|
|
|
25
|
-
type IncludedQueryValue<
|
|
26
|
-
QueryValue<
|
|
25
|
+
type IncludedQueryValue<TQuery, TContract extends AnyPostgresContract, TModel extends string, TRelationName extends string> =
|
|
26
|
+
QueryValue<TQuery> extends ReadonlyArray<infer TRow> ? IncludedRelationValue<TContract, TModel, TRelationName, TRow> : QueryValue<TQuery>;
|
|
27
27
|
|
|
28
|
-
type QueryShapeValue<
|
|
29
|
-
readonly [
|
|
28
|
+
type QueryShapeValue<TShape extends Readonly<Record<string, unknown>>> = {
|
|
29
|
+
readonly [TKey in keyof TShape]: QueryValue<TShape[TKey]>;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
type AcceptRelatedQueryShape<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
TShape extends Readonly<Record<string, unknown>>,
|
|
34
|
+
TContract extends AnyPostgresContract,
|
|
35
|
+
TModel extends string,
|
|
36
|
+
TDatabaseId,
|
|
37
37
|
> = {
|
|
38
|
-
readonly [
|
|
38
|
+
readonly [TKey in keyof TShape]: TShape[TKey] & AcceptRelatedQuery<TShape[TKey], TContract, TModel, TDatabaseId>;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
type WithIncludedRelation<
|
|
42
|
-
|
|
43
|
-
? PrismaCollection<
|
|
41
|
+
type WithIncludedRelation<TCollection, TContract extends AnyPostgresContract, TModel extends string, TRelationName extends string, TValue> =
|
|
42
|
+
TCollection extends PrismaCollection<TContract, TModel, infer TRow, infer TState>
|
|
43
|
+
? PrismaCollection<TContract, TModel, Simplify<TRow & { readonly [TKey in TRelationName]: TValue }>, TState>
|
|
44
44
|
: never;
|
|
45
45
|
|
|
46
|
-
interface IncludeOverloads<
|
|
47
|
-
<
|
|
48
|
-
relationName:
|
|
46
|
+
interface IncludeOverloads<TCollection, TContract extends AnyPostgresContract, TModel extends string, TDatabaseId> {
|
|
47
|
+
<TRelationName extends RelationNames<TContract, TModel>>(
|
|
48
|
+
relationName: TRelationName,
|
|
49
49
|
): Relation<
|
|
50
50
|
WithIncludedRelation<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
IncludedRelationValue<
|
|
51
|
+
TCollection,
|
|
52
|
+
TContract,
|
|
53
|
+
TModel,
|
|
54
|
+
TRelationName,
|
|
55
|
+
IncludedRelationValue<TContract, TModel, TRelationName, DefaultModelRow<TContract, RelatedModelNameOf<TContract, TModel, TRelationName>>>
|
|
56
56
|
>,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
TContract,
|
|
58
|
+
TModel,
|
|
59
|
+
TDatabaseId
|
|
60
60
|
>;
|
|
61
|
-
<
|
|
62
|
-
relationName:
|
|
63
|
-
query:
|
|
61
|
+
<TRelationName extends RelationNames<TContract, TModel>, TQuery>(
|
|
62
|
+
relationName: TRelationName,
|
|
63
|
+
query: TQuery & AcceptRelatedQuery<TQuery, TContract, RelatedModelNameOf<TContract, TModel, TRelationName>, TDatabaseId>,
|
|
64
64
|
): Relation<
|
|
65
|
-
WithIncludedRelation<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
WithIncludedRelation<TCollection, TContract, TModel, TRelationName, IncludedQueryValue<TQuery, TContract, TModel, TRelationName>>,
|
|
66
|
+
TContract,
|
|
67
|
+
TModel,
|
|
68
|
+
TDatabaseId
|
|
69
69
|
>;
|
|
70
|
-
<
|
|
71
|
-
relationName:
|
|
72
|
-
shape: IsToManyRelation<
|
|
73
|
-
? keyof
|
|
70
|
+
<TRelationName extends RelationNames<TContract, TModel>, TShape extends Readonly<Record<string, unknown>>>(
|
|
71
|
+
relationName: TRelationName,
|
|
72
|
+
shape: IsToManyRelation<TContract, TModel, TRelationName> extends true
|
|
73
|
+
? keyof TShape extends never
|
|
74
74
|
? never
|
|
75
|
-
:
|
|
75
|
+
: TShape & AcceptRelatedQueryShape<TShape, TContract, RelatedModelNameOf<TContract, TModel, TRelationName>, TDatabaseId>
|
|
76
76
|
: never,
|
|
77
|
-
): Relation<WithIncludedRelation<
|
|
77
|
+
): Relation<WithIncludedRelation<TCollection, TContract, TModel, TRelationName, QueryShapeValue<TShape>>, TContract, TModel, TDatabaseId>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
export type IncludeMethod<
|
|
81
|
-
?
|
|
82
|
-
? { include: IncludeOverloads<
|
|
80
|
+
export type IncludeMethod<TCollection, TContract, TModel extends string, TDatabaseId> = TContract extends AnyPostgresContract
|
|
81
|
+
? TCollection extends PrismaCollection<TContract, TModel, infer _Row, infer _State>
|
|
82
|
+
? { include: IncludeOverloads<TCollection, TContract, TModel, TDatabaseId> }
|
|
83
83
|
: Record<never, never>
|
|
84
84
|
: Record<never, never>;
|
package/src/relation.ts
CHANGED
|
@@ -4,40 +4,40 @@ import type { PrismaError } from "./error.ts";
|
|
|
4
4
|
|
|
5
5
|
type AnyFunction = (...arguments_: readonly never[]) => unknown;
|
|
6
6
|
|
|
7
|
-
export type CollectionResult<
|
|
8
|
-
all: () => infer
|
|
7
|
+
export type CollectionResult<TCollection> = TCollection extends {
|
|
8
|
+
all: () => infer TResult;
|
|
9
9
|
}
|
|
10
|
-
? Awaited<
|
|
10
|
+
? Awaited<TResult>
|
|
11
11
|
: never;
|
|
12
12
|
|
|
13
|
-
type NormalizeTerminal<
|
|
13
|
+
type NormalizeTerminal<TName, TResult> = TName extends "first" ? import("effect").Option.Option<Exclude<TResult, null>> : TResult;
|
|
14
14
|
|
|
15
|
-
type WrapReturn<
|
|
16
|
-
|
|
17
|
-
? Effect.Effect<NormalizeTerminal<
|
|
18
|
-
:
|
|
19
|
-
? Relation<
|
|
15
|
+
type WrapReturn<TName, TResult, TContract, TModel extends string, TDatabaseId> =
|
|
16
|
+
TResult extends PromiseLike<infer TValue>
|
|
17
|
+
? Effect.Effect<NormalizeTerminal<TName, Awaited<TValue>>, PrismaError>
|
|
18
|
+
: TResult extends object
|
|
19
|
+
? Relation<TResult, TContract, TModel, TDatabaseId>
|
|
20
20
|
: never;
|
|
21
21
|
|
|
22
|
-
type WrapFunction<
|
|
23
|
-
(...arguments_: infer
|
|
24
|
-
(...arguments_: infer
|
|
25
|
-
(...arguments_: infer
|
|
26
|
-
(...arguments_: infer
|
|
27
|
-
(...arguments_: infer
|
|
28
|
-
(...arguments_: infer
|
|
22
|
+
type WrapFunction<TName, TFunction, TContract, TModel extends string, TDatabaseId> = TFunction extends {
|
|
23
|
+
(...arguments_: infer TArguments1): infer TResult1;
|
|
24
|
+
(...arguments_: infer TArguments2): infer TResult2;
|
|
25
|
+
(...arguments_: infer TArguments3): infer TResult3;
|
|
26
|
+
(...arguments_: infer TArguments4): infer TResult4;
|
|
27
|
+
(...arguments_: infer TArguments5): infer TResult5;
|
|
28
|
+
(...arguments_: infer TArguments6): infer TResult6;
|
|
29
29
|
}
|
|
30
|
-
? ((...arguments_:
|
|
31
|
-
((...arguments_:
|
|
32
|
-
((...arguments_:
|
|
33
|
-
((...arguments_:
|
|
34
|
-
((...arguments_:
|
|
35
|
-
((...arguments_:
|
|
30
|
+
? ((...arguments_: TArguments1) => WrapReturn<TName, TResult1, TContract, TModel, TDatabaseId>) &
|
|
31
|
+
((...arguments_: TArguments2) => WrapReturn<TName, TResult2, TContract, TModel, TDatabaseId>) &
|
|
32
|
+
((...arguments_: TArguments3) => WrapReturn<TName, TResult3, TContract, TModel, TDatabaseId>) &
|
|
33
|
+
((...arguments_: TArguments4) => WrapReturn<TName, TResult4, TContract, TModel, TDatabaseId>) &
|
|
34
|
+
((...arguments_: TArguments5) => WrapReturn<TName, TResult5, TContract, TModel, TDatabaseId>) &
|
|
35
|
+
((...arguments_: TArguments6) => WrapReturn<TName, TResult6, TContract, TModel, TDatabaseId>)
|
|
36
36
|
: never;
|
|
37
37
|
|
|
38
|
-
type FunctionKeys<
|
|
39
|
-
[
|
|
40
|
-
}[keyof
|
|
38
|
+
type FunctionKeys<TValue> = {
|
|
39
|
+
[TKey in keyof TValue]-?: TValue[TKey] extends AnyFunction ? TKey : never;
|
|
40
|
+
}[keyof TValue];
|
|
41
41
|
|
|
42
42
|
type ExplicitPrismaMethod =
|
|
43
43
|
| "aggregate"
|
|
@@ -58,25 +58,25 @@ type ExplicitPrismaMethod =
|
|
|
58
58
|
| "sum"
|
|
59
59
|
| "variant";
|
|
60
60
|
|
|
61
|
-
type RelationMethods<
|
|
62
|
-
readonly [
|
|
61
|
+
type RelationMethods<TCollection, TContract, TModel extends string, TDatabaseId> = {
|
|
62
|
+
readonly [TKey in Exclude<FunctionKeys<TCollection>, ExplicitPrismaMethod>]: WrapFunction<TKey, TCollection[TKey], TContract, TModel, TDatabaseId>;
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
declare const RelationQueryTypeId: unique symbol;
|
|
66
66
|
|
|
67
|
-
export type RelationQuery<
|
|
67
|
+
export type RelationQuery<TValue, TContract, TModel extends string, TDatabaseId> = Effect.Effect<TValue, PrismaError> & {
|
|
68
68
|
readonly [RelationQueryTypeId]: {
|
|
69
|
-
readonly contract:
|
|
70
|
-
readonly database: (database:
|
|
71
|
-
readonly model:
|
|
69
|
+
readonly contract: TContract;
|
|
70
|
+
readonly database: (database: TDatabaseId) => TDatabaseId;
|
|
71
|
+
readonly model: TModel;
|
|
72
72
|
};
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
export type Relation<
|
|
76
|
-
CollectionResult<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
export type Relation<TCollection, TContract = undefined, TModel extends string = string, TDatabaseId = undefined> = RelationQuery<
|
|
76
|
+
CollectionResult<TCollection>,
|
|
77
|
+
TContract,
|
|
78
|
+
TModel,
|
|
79
|
+
TDatabaseId
|
|
80
80
|
> &
|
|
81
|
-
RelationMethods<
|
|
82
|
-
PrismaRelationMethods<
|
|
81
|
+
RelationMethods<TCollection, TContract, TModel, TDatabaseId> &
|
|
82
|
+
PrismaRelationMethods<TCollection, TContract, TModel, TDatabaseId>;
|
package/src/sqlite.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import sqlite, { type SqliteClient, type SqliteOptionsBase } from "@prisma-next/sqlite/runtime";
|
|
2
2
|
import { type Layer, Semaphore } from "effect";
|
|
3
|
+
import type { DatabaseIdentifier, DatabaseIdentifierLiteral, DatabaseServiceHolder, DefaultModels } from "#databaseTypes.ts";
|
|
3
4
|
import { acquireConnectedClient, assertAvailableModelNames } from "#internal/client-lifecycle.ts";
|
|
4
5
|
import { contractModels } from "#internal/database-facade.ts";
|
|
5
6
|
import { makeSqlDatabase } from "#internal/database-factory.ts";
|
|
6
|
-
import type { DatabaseIdentifier, DatabaseIdentifierLiteral, DatabaseServiceHolder, DefaultModels } from "#internal/database-types.ts";
|
|
7
7
|
import type { AnySqlContract } from "#internal/executor.ts";
|
|
8
8
|
import { fromPrismaPromise } from "#internal/promise.ts";
|
|
9
9
|
import { decodeSqliteDatetimesAsUtc } from "#internal/sqlite-datetime.ts";
|
|
@@ -32,12 +32,14 @@ export interface SqliteDatabaseDefinition<Contract extends AnySqlContract, Ident
|
|
|
32
32
|
readonly layer: (options: SqliteDatabaseLayerOptions) => Layer.Layer<DatabaseIdentifier<Contract, Identifier>, PrismaError>;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
})
|
|
35
|
+
function clientOptions({ path, extensions, middleware, verifyMarker }: SqliteDatabaseLayerOptions) {
|
|
36
|
+
return {
|
|
37
|
+
path,
|
|
38
|
+
...(extensions === undefined ? {} : { extensions }),
|
|
39
|
+
...(middleware === undefined ? {} : { middleware }),
|
|
40
|
+
...(verifyMarker === undefined ? {} : { verifyMarker }),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
41
43
|
|
|
42
44
|
export const makeSqliteDatabase =
|
|
43
45
|
<const Contract extends AnySqlContract>() =>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Effect } from "effect";
|
|
2
|
+
import type { AnyDatabase } from "#databaseTypes.ts";
|
|
2
3
|
import type { PrismaError } from "#error.ts";
|
|
3
4
|
import { getDatabaseTesting } from "#internal/testing.ts";
|
|
4
|
-
import type { AnyDatabase } from "./types.ts";
|
|
5
5
|
|
|
6
6
|
type TestProgram<Database extends AnyDatabase, A, E, R> = Effect.Effect<A, E, R> & (Effect.Services<Database> extends R ? unknown : never);
|
|
7
7
|
|
package/src/testing/types.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { TestContext, Vitest } from "@effect/vitest";
|
|
2
2
|
import type { Effect, Layer } from "effect";
|
|
3
|
-
import type { EffectClock, EffectTestOptions } from "@shivaedev/effect-test";
|
|
4
|
-
import type { AnyDatabase, DatabaseServiceOf } from "#
|
|
3
|
+
import type { EffectClock, EffectTestOptions } from "@shivaedev/effect-test/types.ts";
|
|
4
|
+
import type { AnyDatabase, DatabaseServiceOf } from "#databaseTypes.ts";
|
|
5
5
|
|
|
6
|
-
export type { AnyDatabase } from "#database.ts";
|
|
7
6
|
export type DatabaseService<Database extends AnyDatabase> = DatabaseServiceOf<Database>;
|
|
8
7
|
|
|
9
8
|
export type DatabaseTest<Database extends AnyDatabase, Provided> = <A, Eff extends Effect.Effect<unknown, unknown, Provided>>(
|
package/src/testing/vitest.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { it as effectIt } from "@effect/vitest";
|
|
2
2
|
import type { Effect, Layer } from "effect";
|
|
3
|
-
import {
|
|
3
|
+
import type { EffectClock } from "@shivaedev/effect-test/types.ts";
|
|
4
|
+
import { makeEffectIt } from "@shivaedev/effect-test/vitest.ts";
|
|
5
|
+
import type { AnyDatabase } from "#databaseTypes.ts";
|
|
4
6
|
import { withTestTransaction } from "./transaction.ts";
|
|
5
|
-
import type {
|
|
7
|
+
import type { DatabaseIt, MakeDatabaseItOptions } from "./types.ts";
|
|
6
8
|
|
|
7
9
|
export function makeDatabaseIt<Database extends AnyDatabase, Provided, LayerError>(
|
|
8
10
|
options: MakeDatabaseItOptions<Database, Provided, LayerError> & {
|
package/dist/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { all, and, not, or } from "@prisma-next/sql-orm-client";
|
|
2
|
-
export { type AnyDatabase, type DatabaseDefinition, type DatabaseLayerOptions, type DatabaseService, type DatabaseServiceOf, makeDatabase, } from "./database.ts";
|
|
3
|
-
export { PrismaConnectionFailure, PrismaError, type PrismaErrorReason, PrismaQueryFailure, PrismaRuntimeFailure, } from "./error.ts";
|
|
4
|
-
export type { Relation } from "./relation.ts";
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,YAAY,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,uBAAuB,EACvB,WAAW,EACX,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,oBAAoB,GACpB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|