@shivaedev/effect-prisma 0.5.2 → 0.6.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 -7
- package/dist/database.d.ts +6 -6
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +9 -2
- package/dist/database.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/database-factory.d.ts +20 -22
- package/dist/internal/database-factory.d.ts.map +1 -1
- package/dist/internal/database-factory.js +83 -24
- package/dist/internal/database-factory.js.map +1 -1
- package/dist/internal/executor.d.ts +9 -7
- package/dist/internal/executor.d.ts.map +1 -1
- package/dist/internal/query-execution.d.ts +3 -4
- package/dist/internal/query-execution.d.ts.map +1 -1
- package/dist/internal/query-execution.js +9 -3
- package/dist/internal/query-execution.js.map +1 -1
- package/dist/internal/recipe.d.ts +1 -1
- package/dist/internal/recipe.d.ts.map +1 -1
- package/dist/internal/recipe.js +22 -9
- package/dist/internal/recipe.js.map +1 -1
- package/dist/internal/relation-plan.d.ts +6 -1
- package/dist/internal/relation-plan.d.ts.map +1 -1
- package/dist/internal/relation-plan.js +6 -5
- package/dist/internal/relation-plan.js.map +1 -1
- package/dist/internal/relation-runtime.d.ts +4 -3
- package/dist/internal/relation-runtime.d.ts.map +1 -1
- package/dist/internal/relation-runtime.js +38 -19
- package/dist/internal/relation-runtime.js.map +1 -1
- package/dist/internal/relation-stream.d.ts +3 -4
- package/dist/internal/relation-stream.d.ts.map +1 -1
- package/dist/internal/relation-stream.js +23 -21
- package/dist/internal/relation-stream.js.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 -3
- package/dist/internal/transaction.d.ts.map +1 -1
- package/dist/internal/transaction.js +14 -4
- package/dist/internal/transaction.js.map +1 -1
- package/dist/internal/vitest-database.d.ts +2 -2
- package/dist/internal/vitest-database.d.ts.map +1 -1
- package/dist/internal/vitest-database.js.map +1 -1
- package/dist/relation/include.d.ts +10 -8
- package/dist/relation/include.d.ts.map +1 -1
- package/dist/relation/prisma-methods.d.ts +20 -20
- package/dist/relation/prisma-methods.d.ts.map +1 -1
- package/dist/relation.d.ts +8 -7
- package/dist/relation.d.ts.map +1 -1
- package/dist/sqlite.d.ts +6 -6
- package/dist/sqlite.d.ts.map +1 -1
- package/dist/sqlite.js +10 -2
- package/dist/sqlite.js.map +1 -1
- package/dist/testing/transaction.d.ts +3 -3
- package/dist/testing/transaction.d.ts.map +1 -1
- package/dist/testing/transaction.js.map +1 -1
- package/dist/testing/types.d.ts +1 -1
- package/dist/testing/types.d.ts.map +1 -1
- package/dist/testing/vitest.d.ts +3 -3
- package/dist/testing/vitest.d.ts.map +1 -1
- package/dist/testing/vitest.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js.map +1 -1
- package/package.json +5 -5
- package/src/database.ts +53 -47
- package/src/index.ts +0 -1
- package/src/internal/database-factory.ts +221 -98
- package/src/internal/executor.ts +9 -15
- package/src/internal/query-execution.ts +14 -6
- package/src/internal/recipe.ts +46 -7
- package/src/internal/relation-plan.ts +11 -11
- package/src/internal/relation-runtime.ts +67 -65
- package/src/internal/relation-stream.ts +54 -48
- package/src/internal/testing.ts +8 -8
- package/src/internal/transaction.ts +80 -56
- package/src/internal/vitest-database.ts +3 -12
- package/src/relation/include.ts +31 -22
- package/src/relation/prisma-methods.ts +27 -31
- package/src/relation.ts +19 -27
- package/src/sqlite.ts +61 -54
- package/src/testing/transaction.ts +16 -6
- package/src/testing/types.ts +1 -1
- package/src/testing/vitest.ts +3 -10
- package/src/testing.ts +0 -1
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import type { Context } from "effect";
|
|
2
1
|
import { Effect, Effectable, Option, type Stream } from "effect";
|
|
3
2
|
import type { PrismaError } from "../error.js";
|
|
4
3
|
import type { Relation } from "../relation.js";
|
|
5
|
-
import type {
|
|
6
|
-
AnyPostgresContract,
|
|
7
|
-
DatabaseExecutor,
|
|
8
|
-
ExecutorIdentifier,
|
|
9
|
-
} from "./executor.js";
|
|
4
|
+
import type { AnyPostgresContract, DatabaseExecutor } from "./executor.js";
|
|
10
5
|
import { fromPrismaPromise } from "./promise.js";
|
|
11
6
|
import { executeQuery } from "./query-execution.js";
|
|
12
7
|
import {
|
|
@@ -15,7 +10,7 @@ import {
|
|
|
15
10
|
replayRecipe,
|
|
16
11
|
rootRecipe,
|
|
17
12
|
} from "./recipe.js";
|
|
18
|
-
import {
|
|
13
|
+
import { setRelationPlan } from "./relation-plan.js";
|
|
19
14
|
import { makeRelationStream } from "./relation-stream.js";
|
|
20
15
|
|
|
21
16
|
type AnyFunction = (...arguments_: ReadonlyArray<never>) => unknown;
|
|
@@ -24,11 +19,12 @@ interface RelationRuntime<
|
|
|
24
19
|
Models extends object,
|
|
25
20
|
Contract extends AnyPostgresContract,
|
|
26
21
|
> {
|
|
27
|
-
readonly executor:
|
|
28
|
-
ExecutorIdentifier<Models>,
|
|
29
|
-
DatabaseExecutor<Models, Contract>
|
|
30
|
-
>;
|
|
22
|
+
readonly executor: DatabaseExecutor<Models, Contract>;
|
|
31
23
|
readonly recipe: RelationRecipe;
|
|
24
|
+
readonly resolveExecutor: Effect.Effect<
|
|
25
|
+
DatabaseExecutor<Models, Contract>,
|
|
26
|
+
PrismaError
|
|
27
|
+
>;
|
|
32
28
|
readonly terminal?: PropertyKey;
|
|
33
29
|
}
|
|
34
30
|
|
|
@@ -90,74 +86,72 @@ const evaluateResult = (
|
|
|
90
86
|
return Effect.succeed(executable);
|
|
91
87
|
};
|
|
92
88
|
|
|
93
|
-
interface RelationValue<
|
|
94
|
-
|
|
95
|
-
Contract extends AnyPostgresContract,
|
|
96
|
-
> extends Effect.Effect<unknown, PrismaError, ExecutorIdentifier<Models>> {
|
|
97
|
-
readonly [RelationPlanTypeId]: {
|
|
98
|
-
readonly recipe: RelationRecipe;
|
|
99
|
-
readonly terminal?: PropertyKey;
|
|
100
|
-
};
|
|
101
|
-
readonly runtime: RelationRuntime<Models, Contract>;
|
|
102
|
-
readonly stream: Stream.Stream<
|
|
103
|
-
unknown,
|
|
104
|
-
PrismaError,
|
|
105
|
-
ExecutorIdentifier<Models>
|
|
106
|
-
>;
|
|
89
|
+
interface RelationValue extends Effect.Effect<unknown, PrismaError> {
|
|
90
|
+
readonly stream: Stream.Stream<unknown, PrismaError>;
|
|
107
91
|
}
|
|
108
92
|
|
|
93
|
+
const runtimes = new WeakMap<object, unknown>();
|
|
94
|
+
|
|
95
|
+
const runtimeOf = <Models extends object, Contract extends AnyPostgresContract>(
|
|
96
|
+
self: object,
|
|
97
|
+
): RelationRuntime<Models, Contract> => {
|
|
98
|
+
const runtime = runtimes.get(self);
|
|
99
|
+
if (runtime === undefined) {
|
|
100
|
+
throw new TypeError("Relation runtime is unavailable");
|
|
101
|
+
}
|
|
102
|
+
return runtime as RelationRuntime<Models, Contract>;
|
|
103
|
+
};
|
|
104
|
+
|
|
109
105
|
const relationEffect = <
|
|
110
106
|
Models extends object,
|
|
111
107
|
Contract extends AnyPostgresContract,
|
|
112
108
|
>(
|
|
113
|
-
self: RelationValue
|
|
114
|
-
): Effect.Effect<unknown, PrismaError
|
|
115
|
-
|
|
109
|
+
self: RelationValue,
|
|
110
|
+
): Effect.Effect<unknown, PrismaError> => {
|
|
111
|
+
const runtime = runtimeOf<Models, Contract>(self);
|
|
112
|
+
return Effect.flatMap(runtime.resolveExecutor, (executor) =>
|
|
116
113
|
executeQuery(
|
|
117
114
|
executor,
|
|
118
115
|
Effect.suspend(() =>
|
|
119
116
|
evaluateResult(
|
|
120
|
-
replayRecipe(
|
|
121
|
-
|
|
117
|
+
replayRecipe(
|
|
118
|
+
executor.models,
|
|
119
|
+
runtime.recipe,
|
|
120
|
+
executor.identity,
|
|
121
|
+
executor.transactionIdentity,
|
|
122
|
+
),
|
|
123
|
+
runtime.terminal,
|
|
122
124
|
),
|
|
123
125
|
),
|
|
124
126
|
),
|
|
125
127
|
).pipe(
|
|
126
128
|
Effect.withSpan(
|
|
127
|
-
`prisma.${
|
|
129
|
+
`prisma.${runtime.recipe.model}.${String(runtime.terminal ?? "all")}`,
|
|
128
130
|
{
|
|
129
131
|
kind: "client",
|
|
130
132
|
attributes: {
|
|
131
133
|
"db.system": "postgresql",
|
|
132
|
-
"db.model":
|
|
133
|
-
"db.operation": String(
|
|
134
|
+
"db.model": runtime.recipe.model,
|
|
135
|
+
"db.operation": String(runtime.terminal ?? "all"),
|
|
134
136
|
},
|
|
135
137
|
},
|
|
136
138
|
),
|
|
137
139
|
);
|
|
140
|
+
};
|
|
138
141
|
|
|
139
142
|
const RelationPrototype = {
|
|
140
|
-
...Effectable.Prototype<
|
|
141
|
-
RelationValue<Record<string, unknown>, AnyPostgresContract>
|
|
142
|
-
>({
|
|
143
|
+
...Effectable.Prototype<RelationValue>({
|
|
143
144
|
label: "EffectPrismaRelation",
|
|
144
145
|
evaluate() {
|
|
145
146
|
return relationEffect(this);
|
|
146
147
|
},
|
|
147
148
|
}),
|
|
148
|
-
get stream(): Stream.Stream<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
> {
|
|
153
|
-
const relation = this as RelationValue<
|
|
154
|
-
Record<string, unknown>,
|
|
155
|
-
AnyPostgresContract
|
|
156
|
-
>;
|
|
157
|
-
return makeRelationStream(
|
|
158
|
-
relation.runtime.executor,
|
|
159
|
-
relation.runtime.recipe,
|
|
149
|
+
get stream(): Stream.Stream<unknown, PrismaError> {
|
|
150
|
+
const relation = this as RelationValue;
|
|
151
|
+
const runtime = runtimeOf<Record<string, unknown>, AnyPostgresContract>(
|
|
152
|
+
relation,
|
|
160
153
|
);
|
|
154
|
+
return makeRelationStream(runtime.resolveExecutor, runtime.recipe);
|
|
161
155
|
},
|
|
162
156
|
};
|
|
163
157
|
|
|
@@ -167,15 +161,8 @@ const makeRelationProxy = <
|
|
|
167
161
|
>(
|
|
168
162
|
runtime: RelationRuntime<Models, Contract>,
|
|
169
163
|
): unknown => {
|
|
170
|
-
const target = Object.
|
|
171
|
-
|
|
172
|
-
recipe: runtime.recipe,
|
|
173
|
-
...(runtime.terminal === undefined ? {} : { terminal: runtime.terminal }),
|
|
174
|
-
},
|
|
175
|
-
runtime,
|
|
176
|
-
}) as RelationValue<Models, Contract>;
|
|
177
|
-
|
|
178
|
-
return new Proxy(target, {
|
|
164
|
+
const target = Object.create(RelationPrototype) as RelationValue;
|
|
165
|
+
const proxy = new Proxy(target, {
|
|
179
166
|
get(self, property, receiver) {
|
|
180
167
|
if (property === "then") {
|
|
181
168
|
return undefined;
|
|
@@ -205,20 +192,35 @@ const makeRelationProxy = <
|
|
|
205
192
|
});
|
|
206
193
|
},
|
|
207
194
|
});
|
|
195
|
+
const plan = {
|
|
196
|
+
liveness: runtime.executor.liveness,
|
|
197
|
+
owner: runtime.executor.identity,
|
|
198
|
+
recipe: runtime.recipe,
|
|
199
|
+
...(runtime.terminal === undefined ? {} : { terminal: runtime.terminal }),
|
|
200
|
+
transactionIdentity: runtime.executor.transactionIdentity,
|
|
201
|
+
};
|
|
202
|
+
for (const value of [target, proxy]) {
|
|
203
|
+
runtimes.set(value, runtime);
|
|
204
|
+
setRelationPlan(value, plan);
|
|
205
|
+
}
|
|
206
|
+
return proxy;
|
|
208
207
|
};
|
|
209
208
|
|
|
210
209
|
export const makeModelRelation = <
|
|
211
210
|
Collection,
|
|
212
211
|
Models extends object,
|
|
213
|
-
|
|
212
|
+
ExecutorContract extends AnyPostgresContract = AnyPostgresContract,
|
|
213
|
+
Model extends string = string,
|
|
214
214
|
>(
|
|
215
|
-
executor:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
)
|
|
215
|
+
executor: DatabaseExecutor<Models, ExecutorContract>,
|
|
216
|
+
model: Model,
|
|
217
|
+
resolveExecutor: Effect.Effect<
|
|
218
|
+
DatabaseExecutor<Models, ExecutorContract>,
|
|
219
|
+
PrismaError
|
|
220
|
+
> = Effect.succeed(executor),
|
|
221
|
+
): Relation<Collection, undefined, Model> =>
|
|
221
222
|
makeRelationProxy({
|
|
222
223
|
executor,
|
|
223
224
|
recipe: rootRecipe(model),
|
|
224
|
-
|
|
225
|
+
resolveExecutor,
|
|
226
|
+
}) as Relation<Collection, undefined, Model>;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type { Context } from "effect";
|
|
2
1
|
import { Effect, Stream } from "effect";
|
|
3
2
|
import { isPrismaFailure, type PrismaError, toPrismaError } from "../error.js";
|
|
4
|
-
import type {
|
|
5
|
-
AnyPostgresContract,
|
|
6
|
-
DatabaseExecutor,
|
|
7
|
-
ExecutorIdentifier,
|
|
8
|
-
} from "./executor.js";
|
|
3
|
+
import type { AnyPostgresContract, DatabaseExecutor } from "./executor.js";
|
|
9
4
|
import { fromPrismaPromise } from "./promise.js";
|
|
10
5
|
import { executeQuery } from "./query-execution.js";
|
|
11
6
|
import { type RelationRecipe, replayRecipe } from "./recipe.js";
|
|
@@ -16,51 +11,62 @@ export const makeRelationStream = <
|
|
|
16
11
|
Models extends object,
|
|
17
12
|
Contract extends AnyPostgresContract,
|
|
18
13
|
>(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
resolveExecutor: Effect.Effect<
|
|
15
|
+
DatabaseExecutor<Models, Contract>,
|
|
16
|
+
PrismaError
|
|
22
17
|
>,
|
|
23
18
|
recipe: RelationRecipe,
|
|
24
|
-
): Stream.Stream<unknown, PrismaError
|
|
25
|
-
Stream.unwrap(
|
|
26
|
-
Effect.
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
-
typeof collection !== "object" ||
|
|
30
|
-
collection === null ||
|
|
31
|
-
typeof Reflect.get(collection, "all") !== "function"
|
|
32
|
-
) {
|
|
33
|
-
throw new TypeError("Only collection Relations can be streamed");
|
|
34
|
-
}
|
|
35
|
-
const iterable = Reflect.apply(
|
|
36
|
-
Reflect.get(collection, "all") as AnyFunction,
|
|
37
|
-
collection,
|
|
38
|
-
[],
|
|
39
|
-
) as AsyncIterable<unknown>;
|
|
40
|
-
|
|
41
|
-
if (executor.querySemaphore === undefined) {
|
|
42
|
-
return Stream.fromAsyncIterable(iterable, (error) => error).pipe(
|
|
43
|
-
Stream.catch((error) =>
|
|
44
|
-
isPrismaFailure(error)
|
|
45
|
-
? Stream.fail(toPrismaError(error))
|
|
46
|
-
: Stream.die(error),
|
|
47
|
-
),
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const buffered = executeQuery(
|
|
19
|
+
): Stream.Stream<unknown, PrismaError> => {
|
|
20
|
+
return Stream.unwrap(
|
|
21
|
+
Effect.flatMap(resolveExecutor, (executor) =>
|
|
22
|
+
executeQuery(
|
|
52
23
|
executor,
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
24
|
+
Effect.sync(() => {
|
|
25
|
+
const collection = replayRecipe(
|
|
26
|
+
executor.models,
|
|
27
|
+
recipe,
|
|
28
|
+
executor.identity,
|
|
29
|
+
executor.transactionIdentity,
|
|
30
|
+
);
|
|
31
|
+
if (
|
|
32
|
+
typeof collection !== "object" ||
|
|
33
|
+
collection === null ||
|
|
34
|
+
typeof Reflect.get(collection, "all") !== "function"
|
|
35
|
+
) {
|
|
36
|
+
throw new TypeError("Only collection Relations can be streamed");
|
|
57
37
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
const iterable = Reflect.apply(
|
|
39
|
+
Reflect.get(collection, "all") as AnyFunction,
|
|
40
|
+
collection,
|
|
41
|
+
[],
|
|
42
|
+
) as AsyncIterable<unknown>;
|
|
61
43
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
44
|
+
if (executor.querySemaphore === undefined) {
|
|
45
|
+
return Stream.fromAsyncIterable(iterable, (error) => error).pipe(
|
|
46
|
+
Stream.catch((error) =>
|
|
47
|
+
isPrismaFailure(error)
|
|
48
|
+
? Stream.fail(toPrismaError(error))
|
|
49
|
+
: Stream.die(error),
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const buffered = executeQuery(
|
|
55
|
+
executor,
|
|
56
|
+
fromPrismaPromise(async () => {
|
|
57
|
+
const rows: Array<unknown> = [];
|
|
58
|
+
for await (const row of iterable) {
|
|
59
|
+
rows.push(row);
|
|
60
|
+
}
|
|
61
|
+
return rows;
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return Stream.unwrap(
|
|
66
|
+
Effect.map(buffered, (rows) => Stream.fromIterable(rows)),
|
|
67
|
+
);
|
|
68
|
+
}),
|
|
69
|
+
),
|
|
70
|
+
),
|
|
66
71
|
);
|
|
72
|
+
};
|
package/src/internal/testing.ts
CHANGED
|
@@ -5,21 +5,21 @@ export const DatabaseTestingTypeId: unique symbol = Symbol.for(
|
|
|
5
5
|
"@shivaedev/effect-prisma/DatabaseTesting",
|
|
6
6
|
);
|
|
7
7
|
|
|
8
|
-
export interface DatabaseTesting<
|
|
8
|
+
export interface DatabaseTesting<DatabaseId> {
|
|
9
9
|
readonly withTestTransaction: <A, E, R>(
|
|
10
|
-
program: Effect.Effect<A, E, R
|
|
11
|
-
) => Effect.Effect<A, E | PrismaError,
|
|
10
|
+
program: Effect.Effect<A, E, R> & (DatabaseId extends R ? unknown : never),
|
|
11
|
+
) => Effect.Effect<A, E | PrismaError, DatabaseId | Exclude<R, DatabaseId>>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export interface DatabaseWithTesting<
|
|
15
|
-
readonly [DatabaseTestingTypeId]: DatabaseTesting<
|
|
14
|
+
export interface DatabaseWithTesting<DatabaseId> {
|
|
15
|
+
readonly [DatabaseTestingTypeId]: DatabaseTesting<DatabaseId>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export const getDatabaseTesting = <
|
|
18
|
+
export const getDatabaseTesting = <DatabaseId>(
|
|
19
19
|
database: object,
|
|
20
|
-
): DatabaseTesting<
|
|
20
|
+
): DatabaseTesting<DatabaseId> => {
|
|
21
21
|
const testing = Reflect.get(database, DatabaseTestingTypeId) as
|
|
22
|
-
| DatabaseTesting<
|
|
22
|
+
| DatabaseTesting<DatabaseId>
|
|
23
23
|
| undefined;
|
|
24
24
|
|
|
25
25
|
if (testing === undefined) {
|
|
@@ -12,13 +12,21 @@ export type TransactionOrm<Contract extends AnySqlContract> = ReturnType<
|
|
|
12
12
|
typeof orm<Contract>
|
|
13
13
|
>;
|
|
14
14
|
|
|
15
|
+
export const withTransactionSemaphore = <A, E, R>(
|
|
16
|
+
semaphore: Semaphore.Semaphore | undefined,
|
|
17
|
+
transaction: Effect.Effect<A, E, R>,
|
|
18
|
+
): Effect.Effect<A, E, R> =>
|
|
19
|
+
semaphore === undefined ? transaction : semaphore.withPermit(transaction);
|
|
20
|
+
|
|
15
21
|
export interface TransactionResource<
|
|
16
22
|
Models extends object,
|
|
17
23
|
Contract extends AnySqlContract,
|
|
18
24
|
> {
|
|
19
25
|
readonly connection: RuntimeConnection;
|
|
20
26
|
readonly transaction: RuntimeTransaction;
|
|
21
|
-
readonly executor: DatabaseExecutor<Models, Contract
|
|
27
|
+
readonly executor: DatabaseExecutor<Models, Contract> & {
|
|
28
|
+
readonly querySemaphore: Semaphore.Semaphore;
|
|
29
|
+
};
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
const runtimeFailure = (
|
|
@@ -34,6 +42,7 @@ export const acquireTransaction = <
|
|
|
34
42
|
>(
|
|
35
43
|
current: DatabaseExecutor<Models, Contract>,
|
|
36
44
|
models: (orm: TransactionOrm<Contract>) => Models,
|
|
45
|
+
mode: "test" | "transaction",
|
|
37
46
|
): Effect.Effect<TransactionResource<Models, Contract>, PrismaError> =>
|
|
38
47
|
fromPrismaPromise(async () => {
|
|
39
48
|
const connection = await current.client.runtime().connection();
|
|
@@ -50,9 +59,16 @@ export const acquireTransaction = <
|
|
|
50
59
|
transaction,
|
|
51
60
|
executor: {
|
|
52
61
|
client: current.client,
|
|
62
|
+
identity: current.identity,
|
|
63
|
+
liveness: {
|
|
64
|
+
closedCode: "RUNTIME.TRANSACTION_CLOSED",
|
|
65
|
+
open: true,
|
|
66
|
+
},
|
|
67
|
+
mode,
|
|
53
68
|
models: models(transactionOrm),
|
|
54
69
|
querySemaphore: Semaphore.makeUnsafe(1),
|
|
55
|
-
|
|
70
|
+
transactionIdentity: {},
|
|
71
|
+
transactionSemaphore: current.transactionSemaphore,
|
|
56
72
|
},
|
|
57
73
|
};
|
|
58
74
|
} catch (error) {
|
|
@@ -92,62 +108,70 @@ const settleTransaction = <
|
|
|
92
108
|
commitOnSuccess: boolean,
|
|
93
109
|
): Effect.Effect<void, PrismaError> =>
|
|
94
110
|
Effect.uninterruptible(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
111
|
+
Effect.sync(() => {
|
|
112
|
+
resource.executor.liveness.open = false;
|
|
113
|
+
}).pipe(
|
|
114
|
+
Effect.andThen(
|
|
115
|
+
resource.executor.querySemaphore.withPermit(
|
|
116
|
+
fromPrismaPromise(async () => {
|
|
117
|
+
let disposed = false;
|
|
118
|
+
let failure: unknown;
|
|
98
119
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
const destroy = async (reason: unknown): Promise<void> => {
|
|
121
|
+
if (disposed) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
disposed = true;
|
|
125
|
+
await resource.connection.destroy(reason).catch(() => undefined);
|
|
126
|
+
};
|
|
106
127
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
if (commitOnSuccess && Exit.isSuccess(exit)) {
|
|
129
|
+
try {
|
|
130
|
+
await resource.transaction.commit();
|
|
131
|
+
} catch (commitError) {
|
|
132
|
+
try {
|
|
133
|
+
await resource.transaction.rollback();
|
|
134
|
+
} catch {
|
|
135
|
+
await destroy(commitError);
|
|
136
|
+
}
|
|
137
|
+
failure = runtimeFailure(
|
|
138
|
+
"RUNTIME.TRANSACTION_COMMIT_FAILED",
|
|
139
|
+
commitError,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
try {
|
|
144
|
+
await resource.transaction.rollback();
|
|
145
|
+
} catch (rollbackError) {
|
|
146
|
+
await destroy(rollbackError);
|
|
147
|
+
failure = runtimeFailure(
|
|
148
|
+
"RUNTIME.TRANSACTION_ROLLBACK_FAILED",
|
|
149
|
+
rollbackError,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
132
153
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
if (!disposed) {
|
|
155
|
+
try {
|
|
156
|
+
await resource.connection.release();
|
|
157
|
+
} catch (releaseError) {
|
|
158
|
+
await destroy(releaseError);
|
|
159
|
+
if (failure !== undefined) {
|
|
160
|
+
throw runtimeFailure(
|
|
161
|
+
"RUNTIME.TRANSACTION_RELEASE_FAILED",
|
|
162
|
+
failure,
|
|
163
|
+
{ releaseError },
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
throw releaseError;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
148
169
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
170
|
+
if (failure !== undefined) {
|
|
171
|
+
throw failure;
|
|
172
|
+
}
|
|
173
|
+
}),
|
|
174
|
+
),
|
|
175
|
+
),
|
|
176
|
+
),
|
|
153
177
|
);
|
|
@@ -5,7 +5,6 @@ import * as TestConsole from "effect/testing/TestConsole";
|
|
|
5
5
|
import { withTestTransaction } from "../testing/transaction.js";
|
|
6
6
|
import type {
|
|
7
7
|
AnyDatabase,
|
|
8
|
-
DatabaseRequirement,
|
|
9
8
|
DatabaseService,
|
|
10
9
|
DatabaseTest,
|
|
11
10
|
DatabaseTester,
|
|
@@ -76,18 +75,10 @@ const restoreContext = <Provided>(
|
|
|
76
75
|
}) as DatabaseFixture<Provided>;
|
|
77
76
|
|
|
78
77
|
export const makeDatabaseTester = <Database extends AnyDatabase, Provided>(
|
|
79
|
-
fixtureIt: FixtureTestApi<
|
|
80
|
-
Provided | DatabaseRequirement<Database> | Effect.Services<Database>
|
|
81
|
-
>,
|
|
78
|
+
fixtureIt: FixtureTestApi<Provided | Effect.Services<Database>>,
|
|
82
79
|
database: Database,
|
|
83
|
-
): DatabaseTester<
|
|
84
|
-
Database
|
|
85
|
-
Provided | DatabaseRequirement<Database> | Effect.Services<Database>
|
|
86
|
-
> => {
|
|
87
|
-
type Services =
|
|
88
|
-
| Provided
|
|
89
|
-
| DatabaseRequirement<Database>
|
|
90
|
-
| Effect.Services<Database>;
|
|
80
|
+
): DatabaseTester<Database, Provided | Effect.Services<Database>> => {
|
|
81
|
+
type Services = Provided | Effect.Services<Database>;
|
|
91
82
|
|
|
92
83
|
const run = <A, Eff extends Effect.Effect<unknown, unknown, Services>>(
|
|
93
84
|
body: (
|
package/src/relation/include.ts
CHANGED
|
@@ -16,9 +16,9 @@ type Simplify<Value> = { [Key in keyof Value]: Value[Key] };
|
|
|
16
16
|
type QueryValue<Query> =
|
|
17
17
|
Query extends RelationQuery<
|
|
18
18
|
infer Value,
|
|
19
|
-
infer _Requirement,
|
|
20
19
|
infer _Contract,
|
|
21
|
-
infer _Model
|
|
20
|
+
infer _Model,
|
|
21
|
+
infer _DatabaseId
|
|
22
22
|
>
|
|
23
23
|
? Value
|
|
24
24
|
: never;
|
|
@@ -27,21 +27,27 @@ type AcceptRelatedQuery<
|
|
|
27
27
|
Query,
|
|
28
28
|
Contract extends AnyPostgresContract,
|
|
29
29
|
Model extends string,
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
DatabaseId,
|
|
31
|
+
> = [Query] extends [
|
|
32
|
+
RelationQuery<
|
|
32
33
|
infer _Value,
|
|
33
|
-
infer _Requirement,
|
|
34
34
|
infer QueryContract,
|
|
35
|
-
infer QueryModel
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
infer QueryModel,
|
|
36
|
+
infer QueryDatabaseId
|
|
37
|
+
>,
|
|
38
|
+
]
|
|
39
|
+
? [QueryContract] extends [Contract]
|
|
40
|
+
? [Contract] extends [QueryContract]
|
|
41
|
+
? [QueryDatabaseId] extends [DatabaseId]
|
|
42
|
+
? [DatabaseId] extends [QueryDatabaseId]
|
|
43
|
+
? QueryModel extends Model
|
|
44
|
+
? unknown
|
|
45
|
+
: never
|
|
41
46
|
: never
|
|
42
47
|
: never
|
|
43
48
|
: never
|
|
44
|
-
: never
|
|
49
|
+
: never
|
|
50
|
+
: never;
|
|
45
51
|
|
|
46
52
|
type IncludedQueryValue<
|
|
47
53
|
Query,
|
|
@@ -61,9 +67,10 @@ type AcceptRelatedQueryShape<
|
|
|
61
67
|
Shape extends Readonly<Record<string, unknown>>,
|
|
62
68
|
Contract extends AnyPostgresContract,
|
|
63
69
|
Model extends string,
|
|
70
|
+
DatabaseId,
|
|
64
71
|
> = {
|
|
65
72
|
readonly [Key in keyof Shape]: Shape[Key] &
|
|
66
|
-
AcceptRelatedQuery<Shape[Key], Contract, Model>;
|
|
73
|
+
AcceptRelatedQuery<Shape[Key], Contract, Model, DatabaseId>;
|
|
67
74
|
};
|
|
68
75
|
|
|
69
76
|
type WithIncludedRelation<
|
|
@@ -84,9 +91,9 @@ type WithIncludedRelation<
|
|
|
84
91
|
|
|
85
92
|
export type IncludeMethod<
|
|
86
93
|
Collection,
|
|
87
|
-
Requirement,
|
|
88
94
|
Contract,
|
|
89
95
|
Model extends string,
|
|
96
|
+
DatabaseId,
|
|
90
97
|
> = Contract extends AnyPostgresContract
|
|
91
98
|
? Collection extends PrismaCollection<
|
|
92
99
|
Contract,
|
|
@@ -113,9 +120,9 @@ export type IncludeMethod<
|
|
|
113
120
|
>
|
|
114
121
|
>
|
|
115
122
|
>,
|
|
116
|
-
Requirement,
|
|
117
123
|
Contract,
|
|
118
|
-
Model
|
|
124
|
+
Model,
|
|
125
|
+
DatabaseId
|
|
119
126
|
>;
|
|
120
127
|
include<RelationName extends RelationNames<Contract, Model>, Query>(
|
|
121
128
|
relationName: RelationName,
|
|
@@ -123,7 +130,8 @@ export type IncludeMethod<
|
|
|
123
130
|
AcceptRelatedQuery<
|
|
124
131
|
Query,
|
|
125
132
|
Contract,
|
|
126
|
-
RelatedModelNameOf<Contract, Model, RelationName
|
|
133
|
+
RelatedModelNameOf<Contract, Model, RelationName>,
|
|
134
|
+
DatabaseId
|
|
127
135
|
>,
|
|
128
136
|
): Relation<
|
|
129
137
|
WithIncludedRelation<
|
|
@@ -133,9 +141,9 @@ export type IncludeMethod<
|
|
|
133
141
|
RelationName,
|
|
134
142
|
IncludedQueryValue<Query, Contract, Model, RelationName>
|
|
135
143
|
>,
|
|
136
|
-
Requirement,
|
|
137
144
|
Contract,
|
|
138
|
-
Model
|
|
145
|
+
Model,
|
|
146
|
+
DatabaseId
|
|
139
147
|
>;
|
|
140
148
|
include<
|
|
141
149
|
RelationName extends RelationNames<Contract, Model>,
|
|
@@ -149,7 +157,8 @@ export type IncludeMethod<
|
|
|
149
157
|
AcceptRelatedQueryShape<
|
|
150
158
|
Shape,
|
|
151
159
|
Contract,
|
|
152
|
-
RelatedModelNameOf<Contract, Model, RelationName
|
|
160
|
+
RelatedModelNameOf<Contract, Model, RelationName>,
|
|
161
|
+
DatabaseId
|
|
153
162
|
>
|
|
154
163
|
: never,
|
|
155
164
|
): Relation<
|
|
@@ -160,9 +169,9 @@ export type IncludeMethod<
|
|
|
160
169
|
RelationName,
|
|
161
170
|
QueryShapeValue<Shape>
|
|
162
171
|
>,
|
|
163
|
-
Requirement,
|
|
164
172
|
Contract,
|
|
165
|
-
Model
|
|
173
|
+
Model,
|
|
174
|
+
DatabaseId
|
|
166
175
|
>;
|
|
167
176
|
}
|
|
168
177
|
: Record<never, never>
|