@shivaedev/effect-prisma 0.0.0 → 0.2.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +150 -2
  4. package/dist/database.d.ts +35 -0
  5. package/dist/database.d.ts.map +1 -0
  6. package/dist/database.js +83 -0
  7. package/dist/database.js.map +1 -0
  8. package/dist/error.d.ts +52 -0
  9. package/dist/error.d.ts.map +1 -0
  10. package/dist/error.js +48 -0
  11. package/dist/error.js.map +1 -0
  12. package/dist/index.d.ts +4 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +3 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/internal/client-lifecycle.d.ts +7 -0
  17. package/dist/internal/client-lifecycle.d.ts.map +1 -0
  18. package/dist/internal/client-lifecycle.js +19 -0
  19. package/dist/internal/client-lifecycle.js.map +1 -0
  20. package/dist/internal/executor.d.ts +16 -0
  21. package/dist/internal/executor.d.ts.map +1 -0
  22. package/dist/internal/executor.js +2 -0
  23. package/dist/internal/executor.js.map +1 -0
  24. package/dist/internal/promise.d.ts +4 -0
  25. package/dist/internal/promise.d.ts.map +1 -0
  26. package/dist/internal/promise.js +9 -0
  27. package/dist/internal/promise.js.map +1 -0
  28. package/dist/internal/recipe.d.ts +13 -0
  29. package/dist/internal/recipe.d.ts.map +1 -0
  30. package/dist/internal/recipe.js +92 -0
  31. package/dist/internal/recipe.js.map +1 -0
  32. package/dist/internal/relation-plan.d.ts +8 -0
  33. package/dist/internal/relation-plan.d.ts.map +1 -0
  34. package/dist/internal/relation-plan.js +10 -0
  35. package/dist/internal/relation-plan.js.map +1 -0
  36. package/dist/internal/relation-runtime.d.ts +5 -0
  37. package/dist/internal/relation-runtime.d.ts.map +1 -0
  38. package/dist/internal/relation-runtime.js +106 -0
  39. package/dist/internal/relation-runtime.js.map +1 -0
  40. package/dist/internal/testing.d.ts +11 -0
  41. package/dist/internal/testing.d.ts.map +1 -0
  42. package/dist/internal/testing.js +9 -0
  43. package/dist/internal/testing.js.map +1 -0
  44. package/dist/internal/transaction.d.ts +14 -0
  45. package/dist/internal/transaction.d.ts.map +1 -0
  46. package/dist/internal/transaction.js +79 -0
  47. package/dist/internal/transaction.js.map +1 -0
  48. package/dist/internal/vitest-database.d.ts +18 -0
  49. package/dist/internal/vitest-database.d.ts.map +1 -0
  50. package/dist/internal/vitest-database.js +73 -0
  51. package/dist/internal/vitest-database.js.map +1 -0
  52. package/dist/relation/include-metadata.d.ts +34 -0
  53. package/dist/relation/include-metadata.d.ts.map +1 -0
  54. package/dist/relation/include-metadata.js +2 -0
  55. package/dist/relation/include-metadata.js.map +1 -0
  56. package/dist/relation/include.d.ts +25 -0
  57. package/dist/relation/include.d.ts.map +1 -0
  58. package/dist/relation/include.js +2 -0
  59. package/dist/relation/include.js.map +1 -0
  60. package/dist/relation/prisma-methods.d.ts +56 -0
  61. package/dist/relation/prisma-methods.d.ts.map +1 -0
  62. package/dist/relation/prisma-methods.js +2 -0
  63. package/dist/relation/prisma-methods.js.map +1 -0
  64. package/dist/relation.d.ts +34 -0
  65. package/dist/relation.d.ts.map +1 -0
  66. package/dist/relation.js +2 -0
  67. package/dist/relation.js.map +1 -0
  68. package/dist/testing/transaction.d.ts +10 -0
  69. package/dist/testing/transaction.d.ts.map +1 -0
  70. package/dist/testing/transaction.js +6 -0
  71. package/dist/testing/transaction.js.map +1 -0
  72. package/dist/testing/types.d.ts +29 -0
  73. package/dist/testing/types.d.ts.map +1 -0
  74. package/dist/testing/types.js +2 -0
  75. package/dist/testing/types.js.map +1 -0
  76. package/dist/testing/vitest.d.ts +6 -0
  77. package/dist/testing/vitest.d.ts.map +1 -0
  78. package/dist/testing/vitest.js +28 -0
  79. package/dist/testing/vitest.js.map +1 -0
  80. package/dist/testing.d.ts +4 -0
  81. package/dist/testing.d.ts.map +1 -0
  82. package/dist/testing.js +3 -0
  83. package/dist/testing.js.map +1 -0
  84. package/package.json +69 -4
  85. package/src/database.ts +232 -0
  86. package/src/error.ts +89 -0
  87. package/src/index.ts +14 -0
  88. package/src/internal/client-lifecycle.ts +31 -0
  89. package/src/internal/executor.ts +28 -0
  90. package/src/internal/promise.ts +16 -0
  91. package/src/internal/recipe.ts +148 -0
  92. package/src/internal/relation-plan.ts +22 -0
  93. package/src/internal/relation-runtime.ts +249 -0
  94. package/src/internal/testing.ts +32 -0
  95. package/src/internal/transaction.ts +149 -0
  96. package/src/internal/vitest-database.ts +210 -0
  97. package/src/relation/include-metadata.ts +102 -0
  98. package/src/relation/include.ts +169 -0
  99. package/src/relation/prisma-methods.ts +196 -0
  100. package/src/relation.ts +118 -0
  101. package/src/testing/transaction.ts +28 -0
  102. package/src/testing/types.ts +67 -0
  103. package/src/testing/vitest.ts +67 -0
  104. package/src/testing.ts +8 -0
@@ -0,0 +1,149 @@
1
+ import type { PostgresClient } from "@prisma-next/postgres/runtime";
2
+ import { orm } from "@prisma-next/sql-orm-client";
3
+ import type {
4
+ RuntimeConnection,
5
+ RuntimeTransaction,
6
+ } from "@prisma-next/sql-runtime";
7
+ import { Effect, Exit } from "effect";
8
+ import type { PrismaError } from "../error.js";
9
+ import type { AnyPostgresContract, DatabaseExecutor } from "./executor.js";
10
+ import { fromPrismaPromise } from "./promise.js";
11
+
12
+ export interface TransactionResource<
13
+ Models extends object,
14
+ Contract extends AnyPostgresContract,
15
+ > {
16
+ readonly connection: RuntimeConnection;
17
+ readonly transaction: RuntimeTransaction;
18
+ readonly executor: DatabaseExecutor<Models, Contract>;
19
+ }
20
+
21
+ const runtimeFailure = (
22
+ code: string,
23
+ cause: unknown,
24
+ details?: Readonly<Record<string, unknown>>,
25
+ ): Error & { readonly code: string } =>
26
+ Object.assign(new Error(code, { cause }), { code, ...details });
27
+
28
+ export const acquireTransaction = <
29
+ Models extends object,
30
+ Contract extends AnyPostgresContract,
31
+ >(
32
+ current: DatabaseExecutor<Models, Contract>,
33
+ models: (orm: PostgresClient<Contract>["orm"]) => Models,
34
+ ): Effect.Effect<TransactionResource<Models, Contract>, PrismaError> =>
35
+ fromPrismaPromise(async () => {
36
+ const connection = await current.client.runtime().connection();
37
+
38
+ try {
39
+ const transaction = await connection.transaction();
40
+ const transactionOrm = orm({
41
+ runtime: transaction,
42
+ context: current.client.context,
43
+ });
44
+
45
+ return {
46
+ connection,
47
+ transaction,
48
+ executor: {
49
+ client: current.client,
50
+ models: models(transactionOrm),
51
+ transactional: true,
52
+ },
53
+ };
54
+ } catch (error) {
55
+ await connection.destroy(error).catch(() => undefined);
56
+ throw error;
57
+ }
58
+ });
59
+
60
+ export const releaseTransaction = <
61
+ Models extends object,
62
+ Contract extends AnyPostgresContract,
63
+ A,
64
+ E,
65
+ >(
66
+ resource: TransactionResource<Models, Contract>,
67
+ exit: Exit.Exit<A, E>,
68
+ ): Effect.Effect<void, PrismaError> => settleTransaction(resource, exit, true);
69
+
70
+ export const releaseTestTransaction = <
71
+ Models extends object,
72
+ Contract extends AnyPostgresContract,
73
+ A,
74
+ E,
75
+ >(
76
+ resource: TransactionResource<Models, Contract>,
77
+ exit: Exit.Exit<A, E>,
78
+ ): Effect.Effect<void, PrismaError> => settleTransaction(resource, exit, false);
79
+
80
+ const settleTransaction = <
81
+ Models extends object,
82
+ Contract extends AnyPostgresContract,
83
+ A,
84
+ E,
85
+ >(
86
+ resource: TransactionResource<Models, Contract>,
87
+ exit: Exit.Exit<A, E>,
88
+ commitOnSuccess: boolean,
89
+ ): Effect.Effect<void, PrismaError> =>
90
+ Effect.uninterruptible(
91
+ fromPrismaPromise(async () => {
92
+ let disposed = false;
93
+ let failure: unknown;
94
+
95
+ const destroy = async (reason: unknown): Promise<void> => {
96
+ if (disposed) {
97
+ return;
98
+ }
99
+ disposed = true;
100
+ await resource.connection.destroy(reason).catch(() => undefined);
101
+ };
102
+
103
+ if (commitOnSuccess && Exit.isSuccess(exit)) {
104
+ try {
105
+ await resource.transaction.commit();
106
+ } catch (commitError) {
107
+ try {
108
+ await resource.transaction.rollback();
109
+ } catch {
110
+ await destroy(commitError);
111
+ }
112
+ failure = runtimeFailure(
113
+ "RUNTIME.TRANSACTION_COMMIT_FAILED",
114
+ commitError,
115
+ );
116
+ }
117
+ } else {
118
+ try {
119
+ await resource.transaction.rollback();
120
+ } catch (rollbackError) {
121
+ await destroy(rollbackError);
122
+ failure = runtimeFailure(
123
+ "RUNTIME.TRANSACTION_ROLLBACK_FAILED",
124
+ rollbackError,
125
+ );
126
+ }
127
+ }
128
+
129
+ if (!disposed) {
130
+ try {
131
+ await resource.connection.release();
132
+ } catch (releaseError) {
133
+ await destroy(releaseError);
134
+ if (failure !== undefined) {
135
+ throw runtimeFailure(
136
+ "RUNTIME.TRANSACTION_RELEASE_FAILED",
137
+ failure,
138
+ { releaseError },
139
+ );
140
+ }
141
+ throw releaseError;
142
+ }
143
+ }
144
+
145
+ if (failure !== undefined) {
146
+ throw failure;
147
+ }
148
+ }),
149
+ );
@@ -0,0 +1,210 @@
1
+ import type { TestContext, TestOptions } from "@effect/vitest";
2
+ import { Cause, type Context, Effect, Exit, Layer, type Scope } from "effect";
3
+ import * as TestClock from "effect/testing/TestClock";
4
+ import * as TestConsole from "effect/testing/TestConsole";
5
+ import { withTestTransaction } from "../testing/transaction.js";
6
+ import type {
7
+ AnyDatabase,
8
+ DatabaseRequirement,
9
+ DatabaseService,
10
+ DatabaseTest,
11
+ DatabaseTester,
12
+ } from "../testing/types.js";
13
+
14
+ export const fixtureName = "__effectPrismaContext";
15
+
16
+ export type DatabaseFixture<Provided> = TestContext & {
17
+ readonly [fixtureName]: Context.Context<Provided>;
18
+ };
19
+
20
+ export interface FixtureTestApi<Provided> {
21
+ (
22
+ name: string,
23
+ options: TestOptions,
24
+ body: (context: DatabaseFixture<Provided>) => Promise<unknown>,
25
+ ): void;
26
+ readonly skip: FixtureTestApi<Provided>;
27
+ readonly skipIf: (condition: unknown) => FixtureTestApi<Provided>;
28
+ readonly runIf: (condition: unknown) => FixtureTestApi<Provided>;
29
+ readonly only: FixtureTestApi<Provided>;
30
+ readonly fails: FixtureTestApi<Provided>;
31
+ readonly for: <Item>(
32
+ cases: ReadonlyArray<Item>,
33
+ ) => (
34
+ name: string,
35
+ options: TestOptions,
36
+ body: (item: Item, context: DatabaseFixture<Provided>) => Promise<unknown>,
37
+ ) => void;
38
+ }
39
+
40
+ const TestEnvironment = Layer.mergeAll(TestConsole.layer, TestClock.layer());
41
+
42
+ const contextFrom = <Provided>(
43
+ context: TestContext,
44
+ ): Context.Context<Provided> =>
45
+ (context as DatabaseFixture<Provided>)[fixtureName];
46
+
47
+ const runEffectTest = <A, E>(
48
+ effect: Effect.Effect<A, E, Scope.Scope>,
49
+ context: TestContext,
50
+ ): Promise<A> =>
51
+ Effect.runPromise(
52
+ Effect.gen(function* () {
53
+ const exit = yield* Effect.exit(effect);
54
+ if (Exit.isFailure(exit)) {
55
+ for (const error of Cause.prettyErrors(exit.cause)) {
56
+ yield* Effect.logError(error);
57
+ }
58
+ }
59
+ return yield* exit;
60
+ }).pipe(Effect.scoped, Effect.provide(TestEnvironment)),
61
+ { signal: context.signal },
62
+ );
63
+
64
+ const normalizeTestOptions = (
65
+ options: number | TestOptions | undefined,
66
+ ): TestOptions =>
67
+ typeof options === "number" ? { timeout: options } : (options ?? {});
68
+
69
+ const restoreContext = <Provided>(
70
+ fixture: Context.Context<Provided>,
71
+ context: Omit<DatabaseFixture<Provided>, typeof fixtureName>,
72
+ ): DatabaseFixture<Provided> =>
73
+ ({
74
+ ...context,
75
+ [fixtureName]: fixture,
76
+ }) as DatabaseFixture<Provided>;
77
+
78
+ export const makeDatabaseTester = <Database extends AnyDatabase, Provided>(
79
+ fixtureIt: FixtureTestApi<
80
+ Provided | DatabaseRequirement<Database> | Effect.Services<Database>
81
+ >,
82
+ 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>;
91
+
92
+ const run = <A, Eff extends Effect.Effect<unknown, unknown, Services>>(
93
+ body: (
94
+ database: DatabaseService<Database>,
95
+ context: TestContext,
96
+ ) => Generator<Eff, A, never>,
97
+ context: TestContext,
98
+ ): Effect.Effect<A, unknown, Scope.Scope> => {
99
+ const effect = withTestTransaction(
100
+ database,
101
+ Effect.gen(function* () {
102
+ const service = yield* database as unknown as Effect.Effect<
103
+ DatabaseService<Database>,
104
+ never,
105
+ Effect.Services<Database>
106
+ >;
107
+ return yield* Effect.gen(() => body(service, context));
108
+ }),
109
+ ).pipe(Effect.provide(contextFrom<Services>(context)));
110
+
111
+ // The callback constraint proves that its services are in the built
112
+ // Layer. TypeScript cannot reduce that generic Exclude after
113
+ // Effect.provide, so the runner closes the type at this private boundary.
114
+ return effect as unknown as Effect.Effect<A, unknown, Scope.Scope>;
115
+ };
116
+
117
+ const register =
118
+ (current: FixtureTestApi<Services>): DatabaseTest<Database, Services> =>
119
+ (name, body, options) =>
120
+ current(
121
+ name,
122
+ normalizeTestOptions(options),
123
+ ({
124
+ __effectPrismaContext,
125
+ task,
126
+ signal,
127
+ onTestFailed,
128
+ onTestFinished,
129
+ skip,
130
+ annotate,
131
+ expect,
132
+ _local,
133
+ }: DatabaseFixture<Services>) => {
134
+ const testContext = restoreContext(__effectPrismaContext, {
135
+ task,
136
+ signal,
137
+ onTestFailed,
138
+ onTestFinished,
139
+ skip,
140
+ annotate,
141
+ expect,
142
+ _local,
143
+ });
144
+ return runEffectTest(run(body, testContext), testContext);
145
+ },
146
+ );
147
+
148
+ const make = (
149
+ current: FixtureTestApi<Services>,
150
+ ): DatabaseTester<Database, Services> => {
151
+ const test = register(current);
152
+
153
+ return Object.assign(test, {
154
+ skip: register(current.skip),
155
+ skipIf: (condition: unknown) => register(current.skipIf(condition)),
156
+ runIf: (condition: unknown) => register(current.runIf(condition)),
157
+ only: register(current.only),
158
+ each: <Item>(cases: ReadonlyArray<Item>) => {
159
+ return <A, Eff extends Effect.Effect<unknown, unknown, Services>>(
160
+ name: string,
161
+ body: (
162
+ item: Item,
163
+ database: DatabaseService<Database>,
164
+ context: TestContext,
165
+ ) => Generator<Eff, A, never>,
166
+ options?: number | TestOptions,
167
+ ) =>
168
+ fixtureIt.for(cases)(
169
+ name,
170
+ normalizeTestOptions(options),
171
+ (
172
+ item,
173
+ {
174
+ __effectPrismaContext,
175
+ task,
176
+ signal,
177
+ onTestFailed,
178
+ onTestFinished,
179
+ skip,
180
+ annotate,
181
+ expect,
182
+ _local,
183
+ }: DatabaseFixture<Services>,
184
+ ) => {
185
+ const testContext = restoreContext(__effectPrismaContext, {
186
+ task,
187
+ signal,
188
+ onTestFailed,
189
+ onTestFinished,
190
+ skip,
191
+ annotate,
192
+ expect,
193
+ _local,
194
+ });
195
+ return runEffectTest(
196
+ run(
197
+ (service, testContext) => body(item, service, testContext),
198
+ testContext,
199
+ ),
200
+ testContext,
201
+ );
202
+ },
203
+ );
204
+ },
205
+ fails: register(current.fails),
206
+ });
207
+ };
208
+
209
+ return make(fixtureIt);
210
+ };
@@ -0,0 +1,102 @@
1
+ import type { Contract as PrismaContract } from "@prisma-next/contract/types";
2
+ import type { SqlStorage } from "@prisma-next/sql-contract/types";
3
+ import type { RelationsOf } from "@prisma-next/sql-orm-client";
4
+
5
+ export type AnyPostgresContract = PrismaContract<SqlStorage>;
6
+
7
+ type RelationDefinition<
8
+ Contract extends AnyPostgresContract,
9
+ Model extends string,
10
+ RelationName extends string,
11
+ > = RelationName extends keyof RelationsOf<Contract, Model>
12
+ ? RelationsOf<Contract, Model>[RelationName]
13
+ : never;
14
+
15
+ type RelationCardinalityOf<
16
+ Contract extends AnyPostgresContract,
17
+ Model extends string,
18
+ RelationName extends string,
19
+ > =
20
+ RelationDefinition<Contract, Model, RelationName> extends {
21
+ readonly cardinality: infer Cardinality extends string;
22
+ }
23
+ ? Cardinality
24
+ : never;
25
+
26
+ export type IsToManyRelation<
27
+ Contract extends AnyPostgresContract,
28
+ Model extends string,
29
+ RelationName extends string,
30
+ > =
31
+ RelationCardinalityOf<Contract, Model, RelationName> extends "1:N" | "N:M"
32
+ ? true
33
+ : false;
34
+
35
+ export type RelatedModelNameOf<
36
+ Contract extends AnyPostgresContract,
37
+ Model extends string,
38
+ RelationName extends string,
39
+ > =
40
+ RelationDefinition<Contract, Model, RelationName> extends {
41
+ readonly to: { readonly model: infer Related extends string };
42
+ }
43
+ ? Related
44
+ : never;
45
+
46
+ type RelationLocalFields<
47
+ Contract extends AnyPostgresContract,
48
+ Model extends string,
49
+ RelationName extends string,
50
+ > =
51
+ RelationDefinition<Contract, Model, RelationName> extends {
52
+ readonly on: {
53
+ readonly localFields: infer Fields extends readonly string[];
54
+ };
55
+ }
56
+ ? Fields
57
+ : readonly [];
58
+
59
+ type DefaultNamespace<Contract extends AnyPostgresContract> =
60
+ Contract["domain"]["namespaces"][keyof Contract["domain"]["namespaces"]];
61
+
62
+ type ModelFields<Contract extends AnyPostgresContract, Model extends string> =
63
+ DefaultNamespace<Contract> extends {
64
+ readonly models: infer Models;
65
+ }
66
+ ? Model extends keyof Models
67
+ ? Models[Model] extends { readonly fields: infer Fields }
68
+ ? Fields
69
+ : never
70
+ : never
71
+ : never;
72
+
73
+ type AnyNullableField<
74
+ Fields,
75
+ Names extends readonly string[],
76
+ > = Names extends readonly [
77
+ infer Head extends string,
78
+ ...infer Tail extends readonly string[],
79
+ ]
80
+ ? Head extends keyof Fields
81
+ ? Fields[Head] extends { readonly nullable: true }
82
+ ? true
83
+ : AnyNullableField<Fields, Tail>
84
+ : true
85
+ : false;
86
+
87
+ export type IncludedRelationValue<
88
+ Contract extends AnyPostgresContract,
89
+ Model extends string,
90
+ RelationName extends string,
91
+ Value,
92
+ > =
93
+ RelationCardinalityOf<Contract, Model, RelationName> extends "1:N" | "N:M"
94
+ ? Array<Value>
95
+ : RelationCardinalityOf<Contract, Model, RelationName> extends "N:1"
96
+ ? AnyNullableField<
97
+ ModelFields<Contract, Model>,
98
+ RelationLocalFields<Contract, Model, RelationName>
99
+ > extends true
100
+ ? Value | null
101
+ : Value
102
+ : Value | null;
@@ -0,0 +1,169 @@
1
+ import type {
2
+ DefaultModelRow,
3
+ Collection as PrismaCollection,
4
+ RelationNames,
5
+ } from "@prisma-next/sql-orm-client";
6
+ import type { Relation, RelationQuery } from "../relation.js";
7
+ import type {
8
+ AnyPostgresContract,
9
+ IncludedRelationValue,
10
+ IsToManyRelation,
11
+ RelatedModelNameOf,
12
+ } from "./include-metadata.js";
13
+
14
+ type Simplify<Value> = { [Key in keyof Value]: Value[Key] };
15
+
16
+ type QueryValue<Query> =
17
+ Query extends RelationQuery<
18
+ infer Value,
19
+ infer _Requirement,
20
+ infer _Contract,
21
+ infer _Model
22
+ >
23
+ ? Value
24
+ : never;
25
+
26
+ type AcceptRelatedQuery<
27
+ Query,
28
+ Contract extends AnyPostgresContract,
29
+ Model extends string,
30
+ > =
31
+ Query extends RelationQuery<
32
+ infer _Value,
33
+ infer _Requirement,
34
+ infer QueryContract,
35
+ infer QueryModel
36
+ >
37
+ ? [QueryContract] extends [Contract]
38
+ ? [Contract] extends [QueryContract]
39
+ ? QueryModel extends Model
40
+ ? unknown
41
+ : never
42
+ : never
43
+ : never
44
+ : never;
45
+
46
+ type IncludedQueryValue<
47
+ Query,
48
+ Contract extends AnyPostgresContract,
49
+ Model extends string,
50
+ RelationName extends string,
51
+ > =
52
+ QueryValue<Query> extends ReadonlyArray<infer Row>
53
+ ? IncludedRelationValue<Contract, Model, RelationName, Row>
54
+ : QueryValue<Query>;
55
+
56
+ type QueryShapeValue<Shape extends Readonly<Record<string, unknown>>> = {
57
+ readonly [Key in keyof Shape]: QueryValue<Shape[Key]>;
58
+ };
59
+
60
+ type AcceptRelatedQueryShape<
61
+ Shape extends Readonly<Record<string, unknown>>,
62
+ Contract extends AnyPostgresContract,
63
+ Model extends string,
64
+ > = {
65
+ readonly [Key in keyof Shape]: Shape[Key] &
66
+ AcceptRelatedQuery<Shape[Key], Contract, Model>;
67
+ };
68
+
69
+ type WithIncludedRelation<
70
+ Collection,
71
+ Contract extends AnyPostgresContract,
72
+ Model extends string,
73
+ RelationName extends string,
74
+ Value,
75
+ > =
76
+ Collection extends PrismaCollection<Contract, Model, infer Row, infer State>
77
+ ? PrismaCollection<
78
+ Contract,
79
+ Model,
80
+ Simplify<Row & { readonly [Key in RelationName]: Value }>,
81
+ State
82
+ >
83
+ : never;
84
+
85
+ export type IncludeMethod<
86
+ Collection,
87
+ Requirement,
88
+ Contract,
89
+ Model extends string,
90
+ > = Contract extends AnyPostgresContract
91
+ ? Collection extends PrismaCollection<
92
+ Contract,
93
+ Model,
94
+ infer _Row,
95
+ infer _State
96
+ >
97
+ ? {
98
+ include<RelationName extends RelationNames<Contract, Model>>(
99
+ relationName: RelationName,
100
+ ): Relation<
101
+ WithIncludedRelation<
102
+ Collection,
103
+ Contract,
104
+ Model,
105
+ RelationName,
106
+ IncludedRelationValue<
107
+ Contract,
108
+ Model,
109
+ RelationName,
110
+ DefaultModelRow<
111
+ Contract,
112
+ RelatedModelNameOf<Contract, Model, RelationName>
113
+ >
114
+ >
115
+ >,
116
+ Requirement,
117
+ Contract,
118
+ Model
119
+ >;
120
+ include<RelationName extends RelationNames<Contract, Model>, Query>(
121
+ relationName: RelationName,
122
+ query: Query &
123
+ AcceptRelatedQuery<
124
+ Query,
125
+ Contract,
126
+ RelatedModelNameOf<Contract, Model, RelationName>
127
+ >,
128
+ ): Relation<
129
+ WithIncludedRelation<
130
+ Collection,
131
+ Contract,
132
+ Model,
133
+ RelationName,
134
+ IncludedQueryValue<Query, Contract, Model, RelationName>
135
+ >,
136
+ Requirement,
137
+ Contract,
138
+ Model
139
+ >;
140
+ include<
141
+ RelationName extends RelationNames<Contract, Model>,
142
+ Shape extends Readonly<Record<string, unknown>>,
143
+ >(
144
+ relationName: RelationName,
145
+ shape: IsToManyRelation<Contract, Model, RelationName> extends true
146
+ ? keyof Shape extends never
147
+ ? never
148
+ : Shape &
149
+ AcceptRelatedQueryShape<
150
+ Shape,
151
+ Contract,
152
+ RelatedModelNameOf<Contract, Model, RelationName>
153
+ >
154
+ : never,
155
+ ): Relation<
156
+ WithIncludedRelation<
157
+ Collection,
158
+ Contract,
159
+ Model,
160
+ RelationName,
161
+ QueryShapeValue<Shape>
162
+ >,
163
+ Requirement,
164
+ Contract,
165
+ Model
166
+ >;
167
+ }
168
+ : Record<never, never>
169
+ : Record<never, never>;