@prisma-next/compat-prisma 0.3.0-dev.3 → 0.3.0-dev.31

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.
@@ -1,62 +1,2 @@
1
- import { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
2
- import { schema } from '@prisma-next/sql-relational-core/schema';
3
- import { Runtime, RuntimeContext } from '@prisma-next/sql-runtime';
4
-
5
- interface PrismaClientOptions {
6
- readonly contract: SqlContract<SqlStorage>;
7
- readonly runtime?: Runtime;
8
- readonly connectionString?: string;
9
- }
10
- interface FindUniqueArgs {
11
- readonly where: Record<string, unknown>;
12
- readonly select?: Record<string, boolean>;
13
- }
14
- interface FindManyArgs {
15
- readonly where?: Record<string, unknown>;
16
- readonly select?: Record<string, boolean>;
17
- readonly orderBy?: Record<string, 'asc' | 'desc'>;
18
- readonly take?: number;
19
- readonly skip?: number;
20
- }
21
- type FindFirstArgs = FindManyArgs;
22
- type TableFromSchema<Contract extends SqlContract<SqlStorage>> = ReturnType<typeof schema<Contract>>['tables'][string];
23
- declare class ModelDelegate {
24
- private readonly runtime;
25
- private readonly context;
26
- private readonly contract;
27
- private readonly table;
28
- private readonly tableName;
29
- private readonly tableRef;
30
- constructor(runtime: Runtime, context: RuntimeContext<SqlContract<SqlStorage>>, contract: SqlContract<SqlStorage>, table: TableFromSchema<SqlContract<SqlStorage>>, tableName: string);
31
- findUnique(args: FindUniqueArgs): Promise<Record<string, unknown> | null>;
32
- findFirst(args?: FindFirstArgs): Promise<Record<string, unknown> | null>;
33
- findMany(args?: FindManyArgs): Promise<Record<string, unknown>[]>;
34
- create(args: {
35
- data: Record<string, unknown>;
36
- }): Promise<Record<string, unknown>>;
37
- update(_args: {
38
- where: Record<string, unknown>;
39
- data: Record<string, unknown>;
40
- }): Promise<Record<string, unknown>>;
41
- delete(_args: {
42
- where: Record<string, unknown>;
43
- }): Promise<Record<string, unknown>>;
44
- private validateWhereArgs;
45
- private unsupportedError;
46
- }
47
- declare class PrismaClientImpl {
48
- readonly runtime: Runtime;
49
- readonly context: RuntimeContext<SqlContract<SqlStorage>>;
50
- readonly contract: SqlContract<SqlStorage>;
51
- readonly schemaHandle: ReturnType<typeof schema>;
52
- readonly models: Record<string, ModelDelegate>;
53
- [key: string]: unknown;
54
- constructor(options: PrismaClientOptions);
55
- $disconnect(): Promise<void>;
56
- }
57
- declare class PrismaClient extends PrismaClientImpl {
58
- readonly user: ModelDelegate;
59
- constructor(options: PrismaClientOptions);
60
- }
61
-
62
- export { PrismaClient };
1
+ export { PrismaClient } from '../prisma-client';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,61 @@
1
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
2
+ import { schema } from '@prisma-next/sql-relational-core/schema';
3
+ import { type Runtime, type RuntimeContext } from '@prisma-next/sql-runtime';
4
+ interface PrismaClientOptions {
5
+ readonly contract: SqlContract<SqlStorage>;
6
+ readonly runtime?: Runtime;
7
+ readonly connectionString?: string;
8
+ }
9
+ interface FindUniqueArgs {
10
+ readonly where: Record<string, unknown>;
11
+ readonly select?: Record<string, boolean>;
12
+ }
13
+ interface FindManyArgs {
14
+ readonly where?: Record<string, unknown>;
15
+ readonly select?: Record<string, boolean>;
16
+ readonly orderBy?: Record<string, 'asc' | 'desc'>;
17
+ readonly take?: number;
18
+ readonly skip?: number;
19
+ }
20
+ type FindFirstArgs = FindManyArgs;
21
+ type TableFromSchema<Contract extends SqlContract<SqlStorage>> = ReturnType<typeof schema<Contract>>['tables'][string];
22
+ declare class ModelDelegate {
23
+ private readonly runtime;
24
+ private readonly context;
25
+ private readonly contract;
26
+ private readonly table;
27
+ private readonly tableName;
28
+ private readonly tableRef;
29
+ constructor(runtime: Runtime, context: RuntimeContext<SqlContract<SqlStorage>>, contract: SqlContract<SqlStorage>, table: TableFromSchema<SqlContract<SqlStorage>>, tableName: string);
30
+ findUnique(args: FindUniqueArgs): Promise<Record<string, unknown> | null>;
31
+ findFirst(args?: FindFirstArgs): Promise<Record<string, unknown> | null>;
32
+ findMany(args?: FindManyArgs): Promise<Record<string, unknown>[]>;
33
+ create(args: {
34
+ data: Record<string, unknown>;
35
+ }): Promise<Record<string, unknown>>;
36
+ update(_args: {
37
+ where: Record<string, unknown>;
38
+ data: Record<string, unknown>;
39
+ }): Promise<Record<string, unknown>>;
40
+ delete(_args: {
41
+ where: Record<string, unknown>;
42
+ }): Promise<Record<string, unknown>>;
43
+ private validateWhereArgs;
44
+ private unsupportedError;
45
+ }
46
+ declare class PrismaClientImpl {
47
+ readonly runtime: Runtime;
48
+ readonly context: RuntimeContext<SqlContract<SqlStorage>>;
49
+ readonly contract: SqlContract<SqlStorage>;
50
+ readonly schemaHandle: ReturnType<typeof schema>;
51
+ readonly models: Record<string, ModelDelegate>;
52
+ [key: string]: unknown;
53
+ constructor(options: PrismaClientOptions);
54
+ $disconnect(): Promise<void>;
55
+ }
56
+ export declare class PrismaClient extends PrismaClientImpl {
57
+ readonly user: ModelDelegate;
58
+ constructor(options: PrismaClientOptions);
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=prisma-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client.d.ts","sourceRoot":"","sources":["../src/prisma-client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAK/E,OAAO,EAAE,MAAM,EAAE,MAAM,yCAAyC,CAAC;AAMjE,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAGlC,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,UAAU,cAAc;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,KAAK,aAAa,GAAG,YAAY,CAAC;AAElC,KAAK,eAAe,CAAC,QAAQ,SAAS,WAAW,CAAC,UAAU,CAAC,IAAI,UAAU,CACzE,OAAO,MAAM,CAAC,QAAQ,CAAC,CACxB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAapB,cAAM,aAAa;IAKf,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAPxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;gBAGjB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,cAAc,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,EAChD,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,EACjC,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,EAChE,SAAS,EAAE,MAAM;IAab,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IASzE,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAS5E,QAAQ,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAqJrE,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAkEjF,MAAM,CAAC,KAAK,EAAE;QAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAK9B,MAAM,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAKzF,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,gBAAgB;CAWzB;AAED,cAAM,gBAAgB;IACpB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAM;IAGpD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;gBAEX,OAAO,EAAE,mBAAmB;IAoDlC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC;AAGD,qBAAa,YAAa,SAAQ,gBAAgB;IAEhD,SAAiB,IAAI,EAAE,aAAa,CAAC;gBAEzB,OAAO,EAAE,mBAAmB;CA4BzC"}
package/package.json CHANGED
@@ -1,32 +1,32 @@
1
1
  {
2
2
  "name": "@prisma-next/compat-prisma",
3
- "version": "0.3.0-dev.3",
3
+ "version": "0.3.0-dev.31",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
7
- "dist"
7
+ "dist",
8
+ "src"
8
9
  ],
9
10
  "dependencies": {
10
- "@prisma-next/adapter-postgres": "0.3.0-dev.3",
11
- "@prisma-next/contract": "0.3.0-dev.3",
12
- "@prisma-next/driver-postgres": "0.3.0-dev.3",
13
- "@prisma-next/sql-contract": "0.3.0-dev.3",
14
- "@prisma-next/sql-lane": "0.3.0-dev.3",
15
- "@prisma-next/sql-relational-core": "0.3.0-dev.3",
16
- "@prisma-next/sql-runtime": "0.3.0-dev.3",
17
- "@prisma-next/target-postgres": "0.3.0-dev.3"
11
+ "@prisma-next/adapter-postgres": "0.3.0-dev.31",
12
+ "@prisma-next/driver-postgres": "0.3.0-dev.31",
13
+ "@prisma-next/sql-contract": "0.3.0-dev.31",
14
+ "@prisma-next/sql-relational-core": "0.3.0-dev.31",
15
+ "@prisma-next/sql-lane": "0.3.0-dev.31",
16
+ "@prisma-next/contract": "0.3.0-dev.31",
17
+ "@prisma-next/sql-runtime": "0.3.0-dev.31",
18
+ "@prisma-next/target-postgres": "0.3.0-dev.31"
18
19
  },
19
20
  "devDependencies": {
20
21
  "@prisma/dev": "0.19.1",
21
- "@types/pg": "^8.11.10",
22
- "@vitest/coverage-v8": "^4.0.0",
23
- "pg": "^8.11.5",
24
- "tsup": "^8.3.0",
25
- "typescript": "^5.9.3",
26
- "vite-tsconfig-paths": "^5.1.4",
27
- "vitest": "^4.0.16",
28
- "@prisma-next/sql-contract-ts": "0.3.0-dev.3",
29
- "@prisma-next/test-utils": "0.0.1"
22
+ "@types/pg": "8.16.0",
23
+ "pg": "8.16.3",
24
+ "tsup": "8.5.1",
25
+ "typescript": "5.9.3",
26
+ "vitest": "4.0.16",
27
+ "@prisma-next/sql-contract-ts": "0.3.0-dev.31",
28
+ "@prisma-next/test-utils": "0.0.1",
29
+ "@prisma-next/tsconfig": "0.0.0"
30
30
  },
31
31
  "exports": {
32
32
  ".": {
@@ -35,13 +35,13 @@
35
35
  }
36
36
  },
37
37
  "scripts": {
38
- "build": "tsup --config tsup.config.ts",
38
+ "build": "tsup --config tsup.config.ts && tsc --project tsconfig.build.json",
39
39
  "test": "vitest run",
40
40
  "test:coverage": "vitest run --coverage",
41
41
  "typecheck": "tsc --project tsconfig.json --noEmit",
42
- "lint": "biome check . --config-path ../../../biome.json --error-on-warnings",
43
- "lint:fix": "biome check --write . --config-path ../../../biome.json",
44
- "lint:fix:unsafe": "biome check --write --unsafe . --config-path ../../../biome.json",
45
- "clean": "node ../../../scripts/clean.mjs"
42
+ "lint": "biome check . --error-on-warnings",
43
+ "lint:fix": "biome check --write .",
44
+ "lint:fix:unsafe": "biome check --write --unsafe .",
45
+ "clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output"
46
46
  }
47
47
  }
@@ -0,0 +1 @@
1
+ export { PrismaClient } from '../prisma-client';
@@ -0,0 +1,457 @@
1
+ import postgresAdapter from '@prisma-next/adapter-postgres/runtime';
2
+ import type { ExecutionPlan } from '@prisma-next/contract/types';
3
+ import postgresDriver from '@prisma-next/driver-postgres/runtime';
4
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
5
+ import { sql } from '@prisma-next/sql-lane/sql';
6
+ import type { TableRef } from '@prisma-next/sql-relational-core/ast';
7
+ import { param } from '@prisma-next/sql-relational-core/param';
8
+ import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
9
+ import { schema } from '@prisma-next/sql-relational-core/schema';
10
+ import type {
11
+ BinaryBuilder,
12
+ ColumnBuilder,
13
+ OrderBuilder,
14
+ } from '@prisma-next/sql-relational-core/types';
15
+ import {
16
+ createRuntime,
17
+ createRuntimeContext,
18
+ type Runtime,
19
+ type RuntimeContext,
20
+ } from '@prisma-next/sql-runtime';
21
+ import postgresTarget from '@prisma-next/target-postgres/runtime';
22
+
23
+ interface PrismaClientOptions {
24
+ readonly contract: SqlContract<SqlStorage>;
25
+ readonly runtime?: Runtime;
26
+ readonly connectionString?: string;
27
+ }
28
+
29
+ interface FindUniqueArgs {
30
+ readonly where: Record<string, unknown>;
31
+ readonly select?: Record<string, boolean>;
32
+ }
33
+
34
+ interface FindManyArgs {
35
+ readonly where?: Record<string, unknown>;
36
+ readonly select?: Record<string, boolean>;
37
+ readonly orderBy?: Record<string, 'asc' | 'desc'>;
38
+ readonly take?: number;
39
+ readonly skip?: number;
40
+ }
41
+
42
+ type FindFirstArgs = FindManyArgs;
43
+
44
+ type TableFromSchema<Contract extends SqlContract<SqlStorage>> = ReturnType<
45
+ typeof schema<Contract>
46
+ >['tables'][string];
47
+
48
+ function isColumnBuilder(value: unknown): value is ColumnBuilder {
49
+ return (
50
+ value !== null &&
51
+ value !== undefined &&
52
+ typeof value === 'object' &&
53
+ 'kind' in value &&
54
+ value.kind === 'column'
55
+ );
56
+ }
57
+
58
+ // NOTE: we can rely on the Prisma ORM's complex type definitions for the method return values, we only need to ensure the compatibility layer behaves correctly at runtime
59
+ class ModelDelegate {
60
+ private readonly tableName: string;
61
+ private readonly tableRef: TableRef;
62
+
63
+ constructor(
64
+ private readonly runtime: Runtime,
65
+ private readonly context: RuntimeContext<SqlContract<SqlStorage>>,
66
+ private readonly contract: SqlContract<SqlStorage>,
67
+ private readonly table: TableFromSchema<SqlContract<SqlStorage>>,
68
+ tableName: string,
69
+ ) {
70
+ // Store table name explicitly (from schema key)
71
+ this.tableName = tableName;
72
+ // Create a clean TableRef that preserves the name property
73
+ // Object.assign in TableBuilderImpl may have overwritten name if there's a column named 'name'
74
+ // We preserve the original table for column access but create a clean ref for from() calls
75
+ this.tableRef = Object.freeze({
76
+ kind: 'table' as const,
77
+ name: tableName,
78
+ }) as TableRef;
79
+ }
80
+
81
+ async findUnique(args: FindUniqueArgs): Promise<Record<string, unknown> | null> {
82
+ const result = await this.findMany({
83
+ ...args,
84
+ take: 1,
85
+ });
86
+
87
+ return result[0] ?? null;
88
+ }
89
+
90
+ async findFirst(args: FindFirstArgs = {}): Promise<Record<string, unknown> | null> {
91
+ const result = await this.findMany({
92
+ ...args,
93
+ take: 1,
94
+ });
95
+
96
+ return result[0] ?? null;
97
+ }
98
+
99
+ async findMany(args: FindManyArgs = {}): Promise<Record<string, unknown>[]> {
100
+ const tableName = this.tableName;
101
+ let query = sql({ context: this.context }).from(this.tableRef);
102
+
103
+ // Handle where clause (equality only for MVP)
104
+ if (args.where) {
105
+ this.validateWhereArgs(args.where);
106
+ const whereConditions: Array<{ column: ColumnBuilder; value: unknown }> = [];
107
+
108
+ for (const [field, value] of Object.entries(args.where)) {
109
+ // Check contract first to validate field exists
110
+ const tableDef = this.contract.storage.tables[this.tableName];
111
+ if (!tableDef || !tableDef.columns[field]) {
112
+ throw this.unsupportedError(`Unknown field '${field}' in where clause`);
113
+ }
114
+ // Access column via columns property to avoid conflicts with table properties
115
+ const columns = this.table.columns;
116
+ const column = columns[field];
117
+ if (!isColumnBuilder(column)) {
118
+ throw this.unsupportedError(`Invalid column '${field}' in where clause`);
119
+ }
120
+ whereConditions.push({ column, value });
121
+ }
122
+
123
+ if (whereConditions.length === 1) {
124
+ const condition = whereConditions[0];
125
+ if (!condition) {
126
+ throw this.unsupportedError('Invalid where condition');
127
+ }
128
+ const column = condition.column as unknown as ColumnBuilder;
129
+ const paramPlaceholder = param(`${tableName}_${(column as { column: string }).column}`);
130
+ const binaryExpr = (column as { eq: (value: unknown) => BinaryBuilder }).eq(
131
+ paramPlaceholder,
132
+ );
133
+ query = query.where(binaryExpr);
134
+ } else if (whereConditions.length > 1) {
135
+ throw this.unsupportedError('Multiple where conditions (AND/OR) not supported in MVP');
136
+ }
137
+ }
138
+
139
+ // Handle select projection
140
+ const projection: Record<string, ColumnBuilder> = {};
141
+ if (args.select) {
142
+ for (const [field, include] of Object.entries(args.select)) {
143
+ if (include) {
144
+ // Check contract first, then access column
145
+ const tableDef = this.contract.storage.tables[this.tableName];
146
+ if (!tableDef || !tableDef.columns[field]) {
147
+ throw this.unsupportedError(`Unknown field '${field}' in select clause`);
148
+ }
149
+ const columns = this.table.columns;
150
+ const column = columns[field];
151
+ if (!isColumnBuilder(column)) {
152
+ throw this.unsupportedError(`Invalid column '${field}' in select clause`);
153
+ }
154
+ projection[field] = column;
155
+ }
156
+ }
157
+ } else {
158
+ // Default: select all columns from contract definition
159
+ const tableDef = this.contract.storage.tables[tableName];
160
+ const tableColumns = this.table.columns;
161
+ if (tableDef && tableColumns) {
162
+ for (const columnName of Object.keys(tableDef.columns)) {
163
+ // Access column via columns property to avoid conflicts with table properties like 'name'
164
+ const column = tableColumns[columnName];
165
+ if (isColumnBuilder(column)) {
166
+ projection[columnName] = column;
167
+ }
168
+ }
169
+ }
170
+
171
+ // Fallback: iterate table columns directly
172
+ if (Object.keys(projection).length === 0 && tableColumns) {
173
+ for (const key in tableColumns) {
174
+ const value = tableColumns[key];
175
+ if (isColumnBuilder(value)) {
176
+ projection[key] = value;
177
+ }
178
+ }
179
+ }
180
+
181
+ if (Object.keys(projection).length === 0) {
182
+ throw this.unsupportedError('Select projection cannot be empty');
183
+ }
184
+ }
185
+
186
+ query = query.select(projection);
187
+
188
+ // Handle orderBy
189
+ if (args.orderBy) {
190
+ const orderByEntries = Object.entries(args.orderBy);
191
+ if (orderByEntries.length > 1) {
192
+ throw this.unsupportedError('Multiple orderBy fields not supported in MVP');
193
+ }
194
+
195
+ const orderByEntry = orderByEntries[0];
196
+ if (!orderByEntry) {
197
+ throw this.unsupportedError('Invalid orderBy entry');
198
+ }
199
+ const [field, direction] = orderByEntry;
200
+ const tableDef = this.contract.storage.tables[this.tableName];
201
+ if (!tableDef || !tableDef.columns[field]) {
202
+ throw this.unsupportedError(`Unknown field '${field}' in orderBy clause`);
203
+ }
204
+ const columns = this.table.columns;
205
+ const columnValue = columns[field];
206
+ if (!isColumnBuilder(columnValue)) {
207
+ throw this.unsupportedError(`Invalid column '${field}' in orderBy clause`);
208
+ }
209
+ const column = columnValue as unknown as ColumnBuilder;
210
+
211
+ const orderExpr: OrderBuilder =
212
+ direction === 'asc'
213
+ ? (column as { asc: () => OrderBuilder }).asc()
214
+ : (column as { desc: () => OrderBuilder }).desc();
215
+ query = query.orderBy(orderExpr);
216
+ }
217
+
218
+ // Handle pagination
219
+ if (args.take !== undefined) {
220
+ query = query.limit(args.take);
221
+ }
222
+
223
+ if (args.skip !== undefined) {
224
+ throw this.unsupportedError('skip/OFFSET not supported in MVP');
225
+ }
226
+
227
+ // Build plan with params
228
+ const paramsMap: Record<string, unknown> = {};
229
+ if (args.where) {
230
+ for (const [field, value] of Object.entries(args.where)) {
231
+ paramsMap[`${tableName}_${field}`] = value;
232
+ }
233
+ }
234
+
235
+ const plan = query.build({ params: paramsMap });
236
+
237
+ // Execute via runtime
238
+ const results: Record<string, unknown>[] = [];
239
+ for await (const row of this.runtime.execute<Record<string, unknown>>(
240
+ plan as ExecutionPlan<Record<string, unknown>> | SqlQueryPlan<Record<string, unknown>>,
241
+ )) {
242
+ results.push(row);
243
+ }
244
+
245
+ return results;
246
+ }
247
+
248
+ async create(args: { data: Record<string, unknown> }): Promise<Record<string, unknown>> {
249
+ const tableName = this.tableName;
250
+ const tableDef = this.contract.storage.tables[tableName];
251
+
252
+ if (!tableDef) {
253
+ throw new Error(`Table ${tableName} not found in contract`);
254
+ }
255
+
256
+ // Build INSERT statement using raw SQL (MVP: simple inserts only)
257
+ const columns: string[] = [];
258
+ const values: unknown[] = [];
259
+ const placeholders: string[] = [];
260
+ let paramIndex = 1;
261
+
262
+ for (const [field, value] of Object.entries(args.data)) {
263
+ const columnDef = tableDef.columns[field];
264
+ if (!columnDef) {
265
+ throw this.unsupportedError(`Unknown field '${field}' in create data`);
266
+ }
267
+
268
+ // Skip auto-generated fields (id with default, createdAt with default, etc.)
269
+ // For MVP, we'll include all provided fields
270
+ columns.push(`"${field}"`);
271
+ values.push(value);
272
+ placeholders.push(`$${paramIndex}`);
273
+ paramIndex++;
274
+ }
275
+
276
+ if (columns.length === 0) {
277
+ throw this.unsupportedError('create() requires at least one field in data');
278
+ }
279
+
280
+ // Use raw SQL for INSERT (MVP approach)
281
+ const sqlBuilder = sql({ context: this.context });
282
+ const insertPlan = sqlBuilder.raw(
283
+ `INSERT INTO "${tableName}" (${columns.join(', ')}) VALUES (${placeholders.join(', ')}) RETURNING *`,
284
+ {
285
+ params: values,
286
+ annotations: {
287
+ intent: 'write',
288
+ isMutation: true,
289
+ hasWhere: false,
290
+ hasLimit: false,
291
+ },
292
+ },
293
+ );
294
+
295
+ // Execute and return the created row
296
+ const results: Record<string, unknown>[] = [];
297
+ for await (const row of this.runtime.execute<Record<string, unknown>>(
298
+ insertPlan as ExecutionPlan<Record<string, unknown>> | SqlQueryPlan<Record<string, unknown>>,
299
+ )) {
300
+ results.push(row);
301
+ }
302
+
303
+ if (results.length === 0) {
304
+ throw new Error('INSERT did not return a row');
305
+ }
306
+
307
+ const result = results[0];
308
+ if (!result) {
309
+ throw new Error('INSERT did not return a row');
310
+ }
311
+ return result;
312
+ }
313
+
314
+ async update(_args: {
315
+ where: Record<string, unknown>;
316
+ data: Record<string, unknown>;
317
+ }): Promise<Record<string, unknown>> {
318
+ void _args;
319
+ throw this.unsupportedError('update() mutations are not supported in MVP compatibility layer');
320
+ }
321
+
322
+ async delete(_args: { where: Record<string, unknown> }): Promise<Record<string, unknown>> {
323
+ void _args;
324
+ throw this.unsupportedError('delete() mutations are not supported in MVP compatibility layer');
325
+ }
326
+
327
+ private validateWhereArgs(where: Record<string, unknown>): void {
328
+ // MVP: only simple equality is supported
329
+ for (const [field, value] of Object.entries(where)) {
330
+ if (value === null || value === undefined) {
331
+ throw this.unsupportedError('Null/undefined values in where clause not supported in MVP');
332
+ }
333
+ if (typeof value === 'object' && !Array.isArray(value)) {
334
+ throw this.unsupportedError(
335
+ `Complex where predicates (e.g., {${field}: {gt: ...}}) not supported in MVP`,
336
+ );
337
+ }
338
+ if (Array.isArray(value)) {
339
+ throw this.unsupportedError('IN/NOT IN predicates not supported in MVP');
340
+ }
341
+ }
342
+ }
343
+
344
+ private unsupportedError(message: string): Error {
345
+ const error = new Error(message) as Error & {
346
+ code: string;
347
+ category: string;
348
+ severity: string;
349
+ };
350
+ error.code = 'CONFIG.INVALID';
351
+ error.category = 'CONFIG';
352
+ error.severity = 'error';
353
+ return error;
354
+ }
355
+ }
356
+
357
+ class PrismaClientImpl {
358
+ readonly runtime: Runtime;
359
+ readonly context: RuntimeContext<SqlContract<SqlStorage>>;
360
+ readonly contract: SqlContract<SqlStorage>;
361
+ readonly schemaHandle: ReturnType<typeof schema>;
362
+ readonly models: Record<string, ModelDelegate> = {};
363
+
364
+ // Dynamic model access properties (populated at runtime)
365
+ [key: string]: unknown;
366
+
367
+ constructor(options: PrismaClientOptions) {
368
+ // Currently only SQL contracts are supported
369
+ this.contract = options.contract;
370
+
371
+ // Create context with contract and descriptor-first composition
372
+ this.context = createRuntimeContext({
373
+ contract: this.contract,
374
+ target: postgresTarget,
375
+ adapter: postgresAdapter,
376
+ extensionPacks: [],
377
+ });
378
+
379
+ // Initialize runtime if not provided
380
+ if (options.runtime) {
381
+ this.runtime = options.runtime;
382
+ } else {
383
+ const connectionString = options.connectionString ?? process.env['DATABASE_URL'];
384
+
385
+ if (!connectionString) {
386
+ throw new Error('DATABASE_URL environment variable or connectionString option is required');
387
+ }
388
+
389
+ const driver = postgresDriver.create({ connectionString });
390
+
391
+ this.runtime = createRuntime({
392
+ driver,
393
+ context: this.context,
394
+ verify: {
395
+ mode: 'onFirstUse',
396
+ requireMarker: false,
397
+ },
398
+ });
399
+ }
400
+
401
+ // Initialize schema handle
402
+ this.schemaHandle = schema(this.context);
403
+
404
+ // Build model delegates
405
+ for (const [tableName, table] of Object.entries(this.schemaHandle.tables)) {
406
+ // Convert table name to camelCase model name (e.g., "user" -> "user", "User" -> "user")
407
+ const modelName = tableName.charAt(0).toLowerCase() + tableName.slice(1);
408
+ // Pass tableName explicitly since Object.assign in TableBuilderImpl may interfere with name property
409
+ this.models[modelName] = new ModelDelegate(
410
+ this.runtime,
411
+ this.context,
412
+ this.contract,
413
+ table as TableFromSchema<SqlContract<SqlStorage>>,
414
+ tableName,
415
+ );
416
+ }
417
+ }
418
+
419
+ async $disconnect(): Promise<void> {
420
+ await this.runtime.close();
421
+ }
422
+ }
423
+
424
+ // Export PrismaClient as a Proxy-wrapped class for dynamic model access
425
+ export class PrismaClient extends PrismaClientImpl {
426
+ // Declare user model for TypeScript (MVP: assumes user table exists)
427
+ declare readonly user: ModelDelegate;
428
+
429
+ constructor(options: PrismaClientOptions) {
430
+ super(options);
431
+ const proxy = new Proxy(this, {
432
+ get(target, prop) {
433
+ if (prop in target && prop !== 'models') {
434
+ if (typeof prop === 'string' || typeof prop === 'number') {
435
+ return (target as Record<string | number, unknown>)[prop];
436
+ }
437
+ return undefined;
438
+ }
439
+
440
+ // Check if it's a model name
441
+ if (typeof prop === 'string' && target.models[prop]) {
442
+ return target.models[prop];
443
+ }
444
+
445
+ return undefined;
446
+ },
447
+ });
448
+
449
+ // Copy model properties to instance for TypeScript type checking
450
+ for (const [modelName, delegate] of Object.entries(this.models)) {
451
+ (proxy as Record<string, unknown>)[modelName] = delegate;
452
+ }
453
+
454
+ // biome-ignore lint/correctness/noConstructorReturn: Proxy pattern requires returning the proxy
455
+ return proxy;
456
+ }
457
+ }