@prisma/client-engine-runtime 7.6.0 → 7.7.0-dev.2

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/dist/index.d.mts CHANGED
@@ -4,6 +4,9 @@ import { ConnectionInfo } from '@prisma/driver-adapter-utils';
4
4
  import { Context } from '@opentelemetry/api';
5
5
  import { Decimal } from '@prisma/client-runtime-utils';
6
6
  import type { IsolationLevel } from '@prisma/driver-adapter-utils';
7
+ import type { JsonBatchQuery } from '@prisma/json-protocol';
8
+ import type { JsonQuery } from '@prisma/json-protocol';
9
+ import { ParamGraph } from '@prisma/param-graph';
7
10
  import { Span } from '@opentelemetry/api';
8
11
  import { SpanOptions } from '@opentelemetry/api';
9
12
  import type { SqlCommenterContext } from '@prisma/sqlcommenter';
@@ -224,6 +227,44 @@ export declare type Pagination = {
224
227
  skip: number | null;
225
228
  };
226
229
 
230
+ /**
231
+ * Parameterizes a batch of queries using the schema-aware approach.
232
+ *
233
+ * @param batch - The batch to parameterize
234
+ * @param view - The ParamGraph for schema lookups
235
+ * @returns The parameterized batch with extracted placeholder values
236
+ */
237
+ export declare function parameterizeBatch(batch: JsonBatchQuery, view: ParamGraph): ParameterizeBatchResult;
238
+
239
+ /**
240
+ * Result of parameterizing a batch of queries.
241
+ */
242
+ declare interface ParameterizeBatchResult {
243
+ /** The batch with user data values replaced by placeholders */
244
+ parameterizedBatch: JsonBatchQuery;
245
+ /** Combined map of placeholder names to their actual values */
246
+ placeholderValues: Record<string, unknown>;
247
+ }
248
+
249
+ /**
250
+ * Parameterizes a single query using the schema-aware approach.
251
+ *
252
+ * @param query - The query to parameterize
253
+ * @param view - The ParamGraph for schema lookups
254
+ * @returns The parameterized query with extracted placeholder values
255
+ */
256
+ export declare function parameterizeQuery(query: JsonQuery, view: ParamGraph): ParameterizeResult;
257
+
258
+ /**
259
+ * Result of parameterizing a single query.
260
+ */
261
+ declare interface ParameterizeResult {
262
+ /** The query with user data values replaced by placeholders */
263
+ parameterizedQuery: JsonQuery;
264
+ /** Map of placeholder names to their actual values */
265
+ placeholderValues: Record<string, unknown>;
266
+ }
267
+
227
268
  export declare interface PlaceholderFormat {
228
269
  prefix: string;
229
270
  hasNumbering: boolean;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,9 @@ import { ConnectionInfo } from '@prisma/driver-adapter-utils';
4
4
  import { Context } from '@opentelemetry/api';
5
5
  import { Decimal } from '@prisma/client-runtime-utils';
6
6
  import type { IsolationLevel } from '@prisma/driver-adapter-utils';
7
+ import type { JsonBatchQuery } from '@prisma/json-protocol';
8
+ import type { JsonQuery } from '@prisma/json-protocol';
9
+ import { ParamGraph } from '@prisma/param-graph';
7
10
  import { Span } from '@opentelemetry/api';
8
11
  import { SpanOptions } from '@opentelemetry/api';
9
12
  import type { SqlCommenterContext } from '@prisma/sqlcommenter';
@@ -224,6 +227,44 @@ export declare type Pagination = {
224
227
  skip: number | null;
225
228
  };
226
229
 
230
+ /**
231
+ * Parameterizes a batch of queries using the schema-aware approach.
232
+ *
233
+ * @param batch - The batch to parameterize
234
+ * @param view - The ParamGraph for schema lookups
235
+ * @returns The parameterized batch with extracted placeholder values
236
+ */
237
+ export declare function parameterizeBatch(batch: JsonBatchQuery, view: ParamGraph): ParameterizeBatchResult;
238
+
239
+ /**
240
+ * Result of parameterizing a batch of queries.
241
+ */
242
+ declare interface ParameterizeBatchResult {
243
+ /** The batch with user data values replaced by placeholders */
244
+ parameterizedBatch: JsonBatchQuery;
245
+ /** Combined map of placeholder names to their actual values */
246
+ placeholderValues: Record<string, unknown>;
247
+ }
248
+
249
+ /**
250
+ * Parameterizes a single query using the schema-aware approach.
251
+ *
252
+ * @param query - The query to parameterize
253
+ * @param view - The ParamGraph for schema lookups
254
+ * @returns The parameterized query with extracted placeholder values
255
+ */
256
+ export declare function parameterizeQuery(query: JsonQuery, view: ParamGraph): ParameterizeResult;
257
+
258
+ /**
259
+ * Result of parameterizing a single query.
260
+ */
261
+ declare interface ParameterizeResult {
262
+ /** The query with user data values replaced by placeholders */
263
+ parameterizedQuery: JsonQuery;
264
+ /** Map of placeholder names to their actual values */
265
+ placeholderValues: Record<string, unknown>;
266
+ }
267
+
227
268
  export declare interface PlaceholderFormat {
228
269
  prefix: string;
229
270
  hasNumbering: boolean;
package/dist/index.js CHANGED
@@ -45,6 +45,8 @@ __export(index_exports, {
45
45
  noopTracingHelper: () => noopTracingHelper,
46
46
  normalizeJsonProtocolValues: () => normalizeJsonProtocolValues,
47
47
  normalizeRawJsonProtocolResponse: () => normalizeRawJsonProtocolResponse,
48
+ parameterizeBatch: () => parameterizeBatch,
49
+ parameterizeQuery: () => parameterizeQuery,
48
50
  safeJsonStringify: () => safeJsonStringify
49
51
  });
50
52
  module.exports = __toCommonJS(index_exports);
@@ -1070,10 +1072,11 @@ function renderQuery(dbQuery, scope, generators, maxChunkSize) {
1070
1072
  case "templateSql": {
1071
1073
  const chunks = dbQuery.chunkable ? chunkParams(dbQuery.fragments, args, maxChunkSize) : [args];
1072
1074
  return chunks.map((params) => {
1073
- if (maxChunkSize !== void 0 && params.length > maxChunkSize) {
1075
+ const rendered = renderTemplateSql(dbQuery.fragments, dbQuery.placeholderFormat, params, dbQuery.argTypes);
1076
+ if (maxChunkSize !== void 0 && rendered.args.length > maxChunkSize) {
1074
1077
  throw new UserFacingError("The query parameter limit supported by your database is exceeded.", "P2029");
1075
1078
  }
1076
- return renderTemplateSql(dbQuery.fragments, dbQuery.placeholderFormat, params, dbQuery.argTypes);
1079
+ return rendered;
1077
1080
  });
1078
1081
  }
1079
1082
  default:
@@ -1988,6 +1991,443 @@ function cloneObject(value) {
1988
1991
  return (0, import_klona2.klona)(value);
1989
1992
  }
1990
1993
 
1994
+ // src/parameterization/parameterize.ts
1995
+ var import_param_graph = require("@prisma/param-graph");
1996
+
1997
+ // src/parameterization/classify.ts
1998
+ var SCALAR_TAGS = /* @__PURE__ */ new Set(["DateTime", "Decimal", "BigInt", "Bytes", "Json", "Raw"]);
1999
+ function classifyValue(value) {
2000
+ if (value === null || value === void 0) {
2001
+ return { kind: "null" };
2002
+ }
2003
+ if (typeof value === "string") {
2004
+ return { kind: "primitive", value };
2005
+ }
2006
+ if (typeof value === "number") {
2007
+ return { kind: "primitive", value };
2008
+ }
2009
+ if (typeof value === "boolean") {
2010
+ return { kind: "primitive", value };
2011
+ }
2012
+ if (Array.isArray(value)) {
2013
+ return { kind: "array", items: value };
2014
+ }
2015
+ if (typeof value === "object") {
2016
+ const obj = value;
2017
+ if ("$type" in obj && typeof obj.$type === "string") {
2018
+ const tag = obj.$type;
2019
+ if (SCALAR_TAGS.has(tag)) {
2020
+ return { kind: "taggedScalar", tag, value: obj.value };
2021
+ }
2022
+ return { kind: "structural", value: obj.value };
2023
+ }
2024
+ return { kind: "object", entries: obj };
2025
+ }
2026
+ return { kind: "structural", value };
2027
+ }
2028
+ function isPlainObject(value) {
2029
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !("$type" in value);
2030
+ }
2031
+ function isTaggedValue2(value) {
2032
+ return typeof value === "object" && value !== null && "$type" in value && typeof value.$type === "string";
2033
+ }
2034
+
2035
+ // src/parameterization/parameterize.ts
2036
+ function parameterizeQuery(query, view) {
2037
+ const parameterizer = new Parameterizer(view);
2038
+ const rootKey = query.modelName ? `${query.modelName}.${query.action}` : query.action;
2039
+ const root = view.root(rootKey);
2040
+ const parameterizedQuery = {
2041
+ ...query,
2042
+ query: parameterizer.parameterizeFieldSelection(query.query, root?.argsNodeId, root?.outputNodeId)
2043
+ };
2044
+ return {
2045
+ parameterizedQuery,
2046
+ placeholderValues: parameterizer.getPlaceholderValues()
2047
+ };
2048
+ }
2049
+ function parameterizeBatch(batch, view) {
2050
+ const parameterizer = new Parameterizer(view);
2051
+ const parameterizedQueries = [];
2052
+ for (let i = 0; i < batch.batch.length; i++) {
2053
+ const query = batch.batch[i];
2054
+ const rootKey = query.modelName ? `${query.modelName}.${query.action}` : query.action;
2055
+ const root = view.root(rootKey);
2056
+ parameterizedQueries.push({
2057
+ ...query,
2058
+ query: parameterizer.parameterizeFieldSelection(query.query, root?.argsNodeId, root?.outputNodeId)
2059
+ });
2060
+ }
2061
+ return {
2062
+ parameterizedBatch: { ...batch, batch: parameterizedQueries },
2063
+ placeholderValues: parameterizer.getPlaceholderValues()
2064
+ };
2065
+ }
2066
+ var Parameterizer = class {
2067
+ #view;
2068
+ #placeholders = /* @__PURE__ */ new Map();
2069
+ #valueToPlaceholder = /* @__PURE__ */ new Map();
2070
+ #nextPlaceholderId = 1;
2071
+ constructor(view) {
2072
+ this.#view = view;
2073
+ }
2074
+ /**
2075
+ * Returns the collected placeholder values as a plain object.
2076
+ */
2077
+ getPlaceholderValues() {
2078
+ return Object.fromEntries(this.#placeholders);
2079
+ }
2080
+ /**
2081
+ * Gets or creates a placeholder for the given value.
2082
+ * If a placeholder already exists for this value, returns a reference to the existing name.
2083
+ * Otherwise, registers a new placeholder with a sequential name.
2084
+ * We reuse the placeholders for equal values because the query compiler needs to be able
2085
+ * to compare the values for equality for certain optimizations (at the time of writing,
2086
+ * only for deciding whether to use native or emulated upserts).
2087
+ */
2088
+ #getOrCreatePlaceholder(value, type) {
2089
+ const valueKey = createValueKey(value, type);
2090
+ const existingName = this.#valueToPlaceholder.get(valueKey);
2091
+ if (existingName !== void 0) {
2092
+ return createPlaceholder(existingName, type);
2093
+ }
2094
+ const name = `%${this.#nextPlaceholderId++}`;
2095
+ this.#valueToPlaceholder.set(valueKey, name);
2096
+ this.#placeholders.set(name, value);
2097
+ return createPlaceholder(name, type);
2098
+ }
2099
+ /**
2100
+ * Parameterizes a field selection (arguments + selection).
2101
+ */
2102
+ parameterizeFieldSelection(sel, argsNodeId, outNodeId) {
2103
+ const argsNode = this.#view.inputNode(argsNodeId);
2104
+ const outNode = this.#view.outputNode(outNodeId);
2105
+ const result = { ...sel };
2106
+ if (sel.arguments && sel.arguments.$type !== "Raw") {
2107
+ result.arguments = this.#parameterizeObject(sel.arguments, argsNode);
2108
+ }
2109
+ if (sel.selection) {
2110
+ result.selection = this.#parameterizeSelection(sel.selection, outNode);
2111
+ }
2112
+ return result;
2113
+ }
2114
+ /**
2115
+ * Parameterizes an object by traversing its fields with the input node.
2116
+ */
2117
+ #parameterizeObject(obj, node) {
2118
+ if (!node) {
2119
+ return obj;
2120
+ }
2121
+ const result = {};
2122
+ for (const [key, value] of Object.entries(obj)) {
2123
+ const edge = this.#view.inputEdge(node, key);
2124
+ if (edge) {
2125
+ result[key] = this.#parameterizeValue(value, edge);
2126
+ } else {
2127
+ result[key] = value;
2128
+ }
2129
+ }
2130
+ return result;
2131
+ }
2132
+ /**
2133
+ * Core parameterization logic for a single value.
2134
+ */
2135
+ #parameterizeValue(value, edge) {
2136
+ const classified = classifyValue(value);
2137
+ switch (classified.kind) {
2138
+ case "null":
2139
+ return value;
2140
+ case "structural":
2141
+ return value;
2142
+ case "primitive":
2143
+ return this.#handlePrimitive(classified.value, edge);
2144
+ case "taggedScalar":
2145
+ return this.#handleTaggedScalar(value, classified.tag, edge);
2146
+ case "array":
2147
+ return this.#handleArray(classified.items, value, edge);
2148
+ case "object":
2149
+ return this.#handleObject(classified.entries, edge);
2150
+ default:
2151
+ throw new Error(`Unknown value kind ${classified.kind}`);
2152
+ }
2153
+ }
2154
+ /**
2155
+ * Handles parameterization of primitive values (string, number, boolean).
2156
+ */
2157
+ #handlePrimitive(value, edge) {
2158
+ if ((0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ParamEnum) && edge.enumNameIndex !== void 0 && typeof value === "string") {
2159
+ const enumValues = this.#view.enumValues(edge);
2160
+ if (enumValues && Object.hasOwn(enumValues, value)) {
2161
+ const type2 = { type: "Enum" };
2162
+ return this.#getOrCreatePlaceholder(enumValues[value], type2);
2163
+ }
2164
+ }
2165
+ if (!(0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ParamScalar)) {
2166
+ return value;
2167
+ }
2168
+ const mask = (0, import_param_graph.getScalarMask)(edge);
2169
+ if (mask === 0) {
2170
+ return value;
2171
+ }
2172
+ const type = getPrimitivePlaceholderType(value);
2173
+ if (!matchesPrimitiveMask(type, mask)) {
2174
+ return value;
2175
+ }
2176
+ if (mask & import_param_graph.ScalarMask.Json) {
2177
+ value = JSON.stringify(value);
2178
+ }
2179
+ return this.#getOrCreatePlaceholder(value, type);
2180
+ }
2181
+ /**
2182
+ * Handles parameterization of tagged scalar values (DateTime, Decimal, etc.).
2183
+ */
2184
+ #handleTaggedScalar(tagged, tag, edge) {
2185
+ if (!(0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ParamScalar)) {
2186
+ return tagged;
2187
+ }
2188
+ const mask = (0, import_param_graph.getScalarMask)(edge);
2189
+ if (mask === 0 || !matchesTaggedMask(tag, mask)) {
2190
+ return tagged;
2191
+ }
2192
+ const type = getTaggedPlaceholderType(tagged.$type);
2193
+ const decoded = decodeTaggedValue(tagged);
2194
+ return this.#getOrCreatePlaceholder(decoded, type);
2195
+ }
2196
+ /**
2197
+ * Handles parameterization of array values.
2198
+ */
2199
+ #handleArray(items, originalValue, edge) {
2200
+ if ((0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ParamScalar) && (0, import_param_graph.getScalarMask)(edge) & import_param_graph.ScalarMask.Json) {
2201
+ const jsonValue = safeJsonStringify(deserializeJsonObject(items));
2202
+ const type = { type: "Json" };
2203
+ return this.#getOrCreatePlaceholder(jsonValue, type);
2204
+ }
2205
+ if ((0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ParamEnum)) {
2206
+ const enumValues = this.#view.enumValues(edge);
2207
+ if (enumValues && items.every((item) => typeof item === "string" && Object.hasOwn(enumValues, item))) {
2208
+ const type = { type: "List", inner: { type: "Enum" } };
2209
+ return this.#getOrCreatePlaceholder(items, type);
2210
+ }
2211
+ }
2212
+ if ((0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ParamListScalar)) {
2213
+ const allValid = items.every((item) => validateListElement(item, edge));
2214
+ if (allValid && items.length > 0) {
2215
+ const decodedItems = items.map((item) => decodeIfTagged(item));
2216
+ const innerType = inferListElementType(items);
2217
+ const type = { type: "List", inner: innerType };
2218
+ return this.#getOrCreatePlaceholder(decodedItems, type);
2219
+ }
2220
+ }
2221
+ if ((0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.ListObject)) {
2222
+ const childNode = this.#view.inputNode(edge.childNodeId);
2223
+ if (childNode) {
2224
+ return items.map((item) => {
2225
+ if (isPlainObject(item)) {
2226
+ return this.#parameterizeObject(item, childNode);
2227
+ }
2228
+ return item;
2229
+ });
2230
+ }
2231
+ }
2232
+ return originalValue;
2233
+ }
2234
+ /**
2235
+ * Handles parameterization of object values.
2236
+ */
2237
+ #handleObject(obj, edge) {
2238
+ if ((0, import_param_graph.hasFlag)(edge, import_param_graph.EdgeFlag.Object)) {
2239
+ const childNode = this.#view.inputNode(edge.childNodeId);
2240
+ if (childNode) {
2241
+ return this.#parameterizeObject(obj, childNode);
2242
+ }
2243
+ }
2244
+ const mask = (0, import_param_graph.getScalarMask)(edge);
2245
+ if (mask & import_param_graph.ScalarMask.Json) {
2246
+ const jsonValue = safeJsonStringify(deserializeJsonObject(obj));
2247
+ const type = { type: "Json" };
2248
+ return this.#getOrCreatePlaceholder(jsonValue, type);
2249
+ }
2250
+ return obj;
2251
+ }
2252
+ /**
2253
+ * Parameterizes a selection set using output nodes.
2254
+ */
2255
+ #parameterizeSelection(selection, node) {
2256
+ if (!selection || !node) {
2257
+ return selection;
2258
+ }
2259
+ const result = {};
2260
+ for (const [key, value] of Object.entries(selection)) {
2261
+ if (key === "$scalars" || key === "$composites" || typeof value === "boolean") {
2262
+ result[key] = value;
2263
+ continue;
2264
+ }
2265
+ const edge = this.#view.outputEdge(node, key);
2266
+ if (edge) {
2267
+ const nested = value;
2268
+ const argsNode = this.#view.inputNode(edge.argsNodeId);
2269
+ const childOutNode = this.#view.outputNode(edge.outputNodeId);
2270
+ const processedValue = {
2271
+ selection: nested.selection ? this.#parameterizeSelection(nested.selection, childOutNode) : {}
2272
+ };
2273
+ if (nested.arguments) {
2274
+ processedValue.arguments = this.#parameterizeObject(nested.arguments, argsNode);
2275
+ }
2276
+ result[key] = processedValue;
2277
+ } else {
2278
+ result[key] = value;
2279
+ }
2280
+ }
2281
+ return result;
2282
+ }
2283
+ };
2284
+ function createPlaceholder(name, type) {
2285
+ return { $type: "Param", value: { name, ...type } };
2286
+ }
2287
+ function serializePlaceholderType(type) {
2288
+ if (type.type === "List") {
2289
+ return `List<${serializePlaceholderType(type.inner)}>`;
2290
+ }
2291
+ return type.type;
2292
+ }
2293
+ function serializeValue(value) {
2294
+ if (ArrayBuffer.isView(value)) {
2295
+ const bufView = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
2296
+ return bufView.toString("base64");
2297
+ }
2298
+ return JSON.stringify(value);
2299
+ }
2300
+ function createValueKey(value, type) {
2301
+ const typeKey = serializePlaceholderType(type);
2302
+ const valueKey = serializeValue(value);
2303
+ return `${typeKey}:${valueKey}`;
2304
+ }
2305
+ var MAX_INT = 2 ** 31 - 1;
2306
+ var MIN_INT = -(2 ** 31);
2307
+ function getPrimitivePlaceholderType(value) {
2308
+ switch (typeof value) {
2309
+ case "boolean":
2310
+ return { type: "Boolean" };
2311
+ case "number":
2312
+ if (!Number.isInteger(value)) {
2313
+ return { type: "Float" };
2314
+ }
2315
+ if (MIN_INT <= value && value <= MAX_INT) {
2316
+ return { type: "Int" };
2317
+ }
2318
+ return { type: "BigInt" };
2319
+ case "string":
2320
+ return { type: "String" };
2321
+ default:
2322
+ throw new Error("unreachable");
2323
+ }
2324
+ }
2325
+ function matchesPrimitiveMask({ type }, mask) {
2326
+ switch (type) {
2327
+ case "Boolean":
2328
+ return (mask & import_param_graph.ScalarMask.Boolean) !== 0;
2329
+ case "Int":
2330
+ return (mask & (import_param_graph.ScalarMask.Int | import_param_graph.ScalarMask.BigInt | import_param_graph.ScalarMask.Float)) !== 0;
2331
+ case "BigInt":
2332
+ return (mask & import_param_graph.ScalarMask.BigInt) !== 0;
2333
+ case "Float":
2334
+ return (mask & import_param_graph.ScalarMask.Float) !== 0;
2335
+ case "String":
2336
+ return (mask & import_param_graph.ScalarMask.String) !== 0;
2337
+ default:
2338
+ return false;
2339
+ }
2340
+ }
2341
+ function getTaggedPlaceholderType(tag) {
2342
+ switch (tag) {
2343
+ case "BigInt":
2344
+ case "Bytes":
2345
+ case "DateTime":
2346
+ case "Json":
2347
+ return { type: tag };
2348
+ case "Decimal":
2349
+ return { type: "Float" };
2350
+ default:
2351
+ return void 0;
2352
+ }
2353
+ }
2354
+ function inferListElementType(items) {
2355
+ let widest = { type: "Any" };
2356
+ for (const item of items) {
2357
+ const classified = classifyValue(item);
2358
+ let itemType;
2359
+ switch (classified.kind) {
2360
+ case "primitive":
2361
+ itemType = getPrimitivePlaceholderType(classified.value);
2362
+ break;
2363
+ case "taggedScalar":
2364
+ itemType = getTaggedPlaceholderType(classified.tag) ?? { type: "Any" };
2365
+ break;
2366
+ default:
2367
+ return { type: "Any" };
2368
+ }
2369
+ widest = widenType(widest, itemType);
2370
+ }
2371
+ return widest;
2372
+ }
2373
+ function widenType(a, b) {
2374
+ if (a.type === "Any") return b;
2375
+ if (b.type === "Any") return a;
2376
+ if (a.type === b.type) return a;
2377
+ const NUMERIC_WIDTH = { Int: 0, BigInt: 1, Float: 2 };
2378
+ const aWidth = NUMERIC_WIDTH[a.type];
2379
+ const bWidth = NUMERIC_WIDTH[b.type];
2380
+ if (aWidth !== void 0 && bWidth !== void 0) {
2381
+ return aWidth >= bWidth ? a : b;
2382
+ }
2383
+ return { type: "Any" };
2384
+ }
2385
+ function matchesTaggedMask(tag, mask) {
2386
+ switch (tag) {
2387
+ case "DateTime":
2388
+ return (mask & import_param_graph.ScalarMask.DateTime) !== 0;
2389
+ case "Decimal":
2390
+ return (mask & import_param_graph.ScalarMask.Decimal) !== 0;
2391
+ case "BigInt":
2392
+ return (mask & import_param_graph.ScalarMask.BigInt) !== 0;
2393
+ case "Bytes":
2394
+ return (mask & import_param_graph.ScalarMask.Bytes) !== 0;
2395
+ case "Json":
2396
+ return (mask & import_param_graph.ScalarMask.Json) !== 0;
2397
+ default:
2398
+ return false;
2399
+ }
2400
+ }
2401
+ function validateListElement(item, edge) {
2402
+ const classified = classifyValue(item);
2403
+ switch (classified.kind) {
2404
+ case "structural":
2405
+ return false;
2406
+ case "null":
2407
+ return false;
2408
+ case "primitive": {
2409
+ const type = getPrimitivePlaceholderType(classified.value);
2410
+ const mask = (0, import_param_graph.getScalarMask)(edge);
2411
+ return mask !== 0 && matchesPrimitiveMask(type, mask);
2412
+ }
2413
+ case "taggedScalar": {
2414
+ const mask = (0, import_param_graph.getScalarMask)(edge);
2415
+ return mask !== 0 && matchesTaggedMask(classified.tag, mask);
2416
+ }
2417
+ default:
2418
+ return false;
2419
+ }
2420
+ }
2421
+ function decodeIfTagged(value) {
2422
+ if (isTaggedValue2(value)) {
2423
+ return decodeTaggedValue(value);
2424
+ }
2425
+ return value;
2426
+ }
2427
+ function decodeTaggedValue(tagged) {
2428
+ return tagged.value;
2429
+ }
2430
+
1991
2431
  // src/raw-json-protocol.ts
1992
2432
  var import_client_runtime_utils4 = require("@prisma/client-runtime-utils");
1993
2433
  function normalizeRawJsonProtocolResponse(response) {
@@ -2477,5 +2917,7 @@ function createTimeoutIfDefined(cb, ms) {
2477
2917
  noopTracingHelper,
2478
2918
  normalizeJsonProtocolValues,
2479
2919
  normalizeRawJsonProtocolResponse,
2920
+ parameterizeBatch,
2921
+ parameterizeQuery,
2480
2922
  safeJsonStringify
2481
2923
  });
package/dist/index.mjs CHANGED
@@ -1019,10 +1019,11 @@ function renderQuery(dbQuery, scope, generators, maxChunkSize) {
1019
1019
  case "templateSql": {
1020
1020
  const chunks = dbQuery.chunkable ? chunkParams(dbQuery.fragments, args, maxChunkSize) : [args];
1021
1021
  return chunks.map((params) => {
1022
- if (maxChunkSize !== void 0 && params.length > maxChunkSize) {
1022
+ const rendered = renderTemplateSql(dbQuery.fragments, dbQuery.placeholderFormat, params, dbQuery.argTypes);
1023
+ if (maxChunkSize !== void 0 && rendered.args.length > maxChunkSize) {
1023
1024
  throw new UserFacingError("The query parameter limit supported by your database is exceeded.", "P2029");
1024
1025
  }
1025
- return renderTemplateSql(dbQuery.fragments, dbQuery.placeholderFormat, params, dbQuery.argTypes);
1026
+ return rendered;
1026
1027
  });
1027
1028
  }
1028
1029
  default:
@@ -1937,6 +1938,443 @@ function cloneObject(value) {
1937
1938
  return klona2(value);
1938
1939
  }
1939
1940
 
1941
+ // src/parameterization/parameterize.ts
1942
+ import { EdgeFlag, getScalarMask, hasFlag, ScalarMask } from "@prisma/param-graph";
1943
+
1944
+ // src/parameterization/classify.ts
1945
+ var SCALAR_TAGS = /* @__PURE__ */ new Set(["DateTime", "Decimal", "BigInt", "Bytes", "Json", "Raw"]);
1946
+ function classifyValue(value) {
1947
+ if (value === null || value === void 0) {
1948
+ return { kind: "null" };
1949
+ }
1950
+ if (typeof value === "string") {
1951
+ return { kind: "primitive", value };
1952
+ }
1953
+ if (typeof value === "number") {
1954
+ return { kind: "primitive", value };
1955
+ }
1956
+ if (typeof value === "boolean") {
1957
+ return { kind: "primitive", value };
1958
+ }
1959
+ if (Array.isArray(value)) {
1960
+ return { kind: "array", items: value };
1961
+ }
1962
+ if (typeof value === "object") {
1963
+ const obj = value;
1964
+ if ("$type" in obj && typeof obj.$type === "string") {
1965
+ const tag = obj.$type;
1966
+ if (SCALAR_TAGS.has(tag)) {
1967
+ return { kind: "taggedScalar", tag, value: obj.value };
1968
+ }
1969
+ return { kind: "structural", value: obj.value };
1970
+ }
1971
+ return { kind: "object", entries: obj };
1972
+ }
1973
+ return { kind: "structural", value };
1974
+ }
1975
+ function isPlainObject(value) {
1976
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !("$type" in value);
1977
+ }
1978
+ function isTaggedValue2(value) {
1979
+ return typeof value === "object" && value !== null && "$type" in value && typeof value.$type === "string";
1980
+ }
1981
+
1982
+ // src/parameterization/parameterize.ts
1983
+ function parameterizeQuery(query, view) {
1984
+ const parameterizer = new Parameterizer(view);
1985
+ const rootKey = query.modelName ? `${query.modelName}.${query.action}` : query.action;
1986
+ const root = view.root(rootKey);
1987
+ const parameterizedQuery = {
1988
+ ...query,
1989
+ query: parameterizer.parameterizeFieldSelection(query.query, root?.argsNodeId, root?.outputNodeId)
1990
+ };
1991
+ return {
1992
+ parameterizedQuery,
1993
+ placeholderValues: parameterizer.getPlaceholderValues()
1994
+ };
1995
+ }
1996
+ function parameterizeBatch(batch, view) {
1997
+ const parameterizer = new Parameterizer(view);
1998
+ const parameterizedQueries = [];
1999
+ for (let i = 0; i < batch.batch.length; i++) {
2000
+ const query = batch.batch[i];
2001
+ const rootKey = query.modelName ? `${query.modelName}.${query.action}` : query.action;
2002
+ const root = view.root(rootKey);
2003
+ parameterizedQueries.push({
2004
+ ...query,
2005
+ query: parameterizer.parameterizeFieldSelection(query.query, root?.argsNodeId, root?.outputNodeId)
2006
+ });
2007
+ }
2008
+ return {
2009
+ parameterizedBatch: { ...batch, batch: parameterizedQueries },
2010
+ placeholderValues: parameterizer.getPlaceholderValues()
2011
+ };
2012
+ }
2013
+ var Parameterizer = class {
2014
+ #view;
2015
+ #placeholders = /* @__PURE__ */ new Map();
2016
+ #valueToPlaceholder = /* @__PURE__ */ new Map();
2017
+ #nextPlaceholderId = 1;
2018
+ constructor(view) {
2019
+ this.#view = view;
2020
+ }
2021
+ /**
2022
+ * Returns the collected placeholder values as a plain object.
2023
+ */
2024
+ getPlaceholderValues() {
2025
+ return Object.fromEntries(this.#placeholders);
2026
+ }
2027
+ /**
2028
+ * Gets or creates a placeholder for the given value.
2029
+ * If a placeholder already exists for this value, returns a reference to the existing name.
2030
+ * Otherwise, registers a new placeholder with a sequential name.
2031
+ * We reuse the placeholders for equal values because the query compiler needs to be able
2032
+ * to compare the values for equality for certain optimizations (at the time of writing,
2033
+ * only for deciding whether to use native or emulated upserts).
2034
+ */
2035
+ #getOrCreatePlaceholder(value, type) {
2036
+ const valueKey = createValueKey(value, type);
2037
+ const existingName = this.#valueToPlaceholder.get(valueKey);
2038
+ if (existingName !== void 0) {
2039
+ return createPlaceholder(existingName, type);
2040
+ }
2041
+ const name = `%${this.#nextPlaceholderId++}`;
2042
+ this.#valueToPlaceholder.set(valueKey, name);
2043
+ this.#placeholders.set(name, value);
2044
+ return createPlaceholder(name, type);
2045
+ }
2046
+ /**
2047
+ * Parameterizes a field selection (arguments + selection).
2048
+ */
2049
+ parameterizeFieldSelection(sel, argsNodeId, outNodeId) {
2050
+ const argsNode = this.#view.inputNode(argsNodeId);
2051
+ const outNode = this.#view.outputNode(outNodeId);
2052
+ const result = { ...sel };
2053
+ if (sel.arguments && sel.arguments.$type !== "Raw") {
2054
+ result.arguments = this.#parameterizeObject(sel.arguments, argsNode);
2055
+ }
2056
+ if (sel.selection) {
2057
+ result.selection = this.#parameterizeSelection(sel.selection, outNode);
2058
+ }
2059
+ return result;
2060
+ }
2061
+ /**
2062
+ * Parameterizes an object by traversing its fields with the input node.
2063
+ */
2064
+ #parameterizeObject(obj, node) {
2065
+ if (!node) {
2066
+ return obj;
2067
+ }
2068
+ const result = {};
2069
+ for (const [key, value] of Object.entries(obj)) {
2070
+ const edge = this.#view.inputEdge(node, key);
2071
+ if (edge) {
2072
+ result[key] = this.#parameterizeValue(value, edge);
2073
+ } else {
2074
+ result[key] = value;
2075
+ }
2076
+ }
2077
+ return result;
2078
+ }
2079
+ /**
2080
+ * Core parameterization logic for a single value.
2081
+ */
2082
+ #parameterizeValue(value, edge) {
2083
+ const classified = classifyValue(value);
2084
+ switch (classified.kind) {
2085
+ case "null":
2086
+ return value;
2087
+ case "structural":
2088
+ return value;
2089
+ case "primitive":
2090
+ return this.#handlePrimitive(classified.value, edge);
2091
+ case "taggedScalar":
2092
+ return this.#handleTaggedScalar(value, classified.tag, edge);
2093
+ case "array":
2094
+ return this.#handleArray(classified.items, value, edge);
2095
+ case "object":
2096
+ return this.#handleObject(classified.entries, edge);
2097
+ default:
2098
+ throw new Error(`Unknown value kind ${classified.kind}`);
2099
+ }
2100
+ }
2101
+ /**
2102
+ * Handles parameterization of primitive values (string, number, boolean).
2103
+ */
2104
+ #handlePrimitive(value, edge) {
2105
+ if (hasFlag(edge, EdgeFlag.ParamEnum) && edge.enumNameIndex !== void 0 && typeof value === "string") {
2106
+ const enumValues = this.#view.enumValues(edge);
2107
+ if (enumValues && Object.hasOwn(enumValues, value)) {
2108
+ const type2 = { type: "Enum" };
2109
+ return this.#getOrCreatePlaceholder(enumValues[value], type2);
2110
+ }
2111
+ }
2112
+ if (!hasFlag(edge, EdgeFlag.ParamScalar)) {
2113
+ return value;
2114
+ }
2115
+ const mask = getScalarMask(edge);
2116
+ if (mask === 0) {
2117
+ return value;
2118
+ }
2119
+ const type = getPrimitivePlaceholderType(value);
2120
+ if (!matchesPrimitiveMask(type, mask)) {
2121
+ return value;
2122
+ }
2123
+ if (mask & ScalarMask.Json) {
2124
+ value = JSON.stringify(value);
2125
+ }
2126
+ return this.#getOrCreatePlaceholder(value, type);
2127
+ }
2128
+ /**
2129
+ * Handles parameterization of tagged scalar values (DateTime, Decimal, etc.).
2130
+ */
2131
+ #handleTaggedScalar(tagged, tag, edge) {
2132
+ if (!hasFlag(edge, EdgeFlag.ParamScalar)) {
2133
+ return tagged;
2134
+ }
2135
+ const mask = getScalarMask(edge);
2136
+ if (mask === 0 || !matchesTaggedMask(tag, mask)) {
2137
+ return tagged;
2138
+ }
2139
+ const type = getTaggedPlaceholderType(tagged.$type);
2140
+ const decoded = decodeTaggedValue(tagged);
2141
+ return this.#getOrCreatePlaceholder(decoded, type);
2142
+ }
2143
+ /**
2144
+ * Handles parameterization of array values.
2145
+ */
2146
+ #handleArray(items, originalValue, edge) {
2147
+ if (hasFlag(edge, EdgeFlag.ParamScalar) && getScalarMask(edge) & ScalarMask.Json) {
2148
+ const jsonValue = safeJsonStringify(deserializeJsonObject(items));
2149
+ const type = { type: "Json" };
2150
+ return this.#getOrCreatePlaceholder(jsonValue, type);
2151
+ }
2152
+ if (hasFlag(edge, EdgeFlag.ParamEnum)) {
2153
+ const enumValues = this.#view.enumValues(edge);
2154
+ if (enumValues && items.every((item) => typeof item === "string" && Object.hasOwn(enumValues, item))) {
2155
+ const type = { type: "List", inner: { type: "Enum" } };
2156
+ return this.#getOrCreatePlaceholder(items, type);
2157
+ }
2158
+ }
2159
+ if (hasFlag(edge, EdgeFlag.ParamListScalar)) {
2160
+ const allValid = items.every((item) => validateListElement(item, edge));
2161
+ if (allValid && items.length > 0) {
2162
+ const decodedItems = items.map((item) => decodeIfTagged(item));
2163
+ const innerType = inferListElementType(items);
2164
+ const type = { type: "List", inner: innerType };
2165
+ return this.#getOrCreatePlaceholder(decodedItems, type);
2166
+ }
2167
+ }
2168
+ if (hasFlag(edge, EdgeFlag.ListObject)) {
2169
+ const childNode = this.#view.inputNode(edge.childNodeId);
2170
+ if (childNode) {
2171
+ return items.map((item) => {
2172
+ if (isPlainObject(item)) {
2173
+ return this.#parameterizeObject(item, childNode);
2174
+ }
2175
+ return item;
2176
+ });
2177
+ }
2178
+ }
2179
+ return originalValue;
2180
+ }
2181
+ /**
2182
+ * Handles parameterization of object values.
2183
+ */
2184
+ #handleObject(obj, edge) {
2185
+ if (hasFlag(edge, EdgeFlag.Object)) {
2186
+ const childNode = this.#view.inputNode(edge.childNodeId);
2187
+ if (childNode) {
2188
+ return this.#parameterizeObject(obj, childNode);
2189
+ }
2190
+ }
2191
+ const mask = getScalarMask(edge);
2192
+ if (mask & ScalarMask.Json) {
2193
+ const jsonValue = safeJsonStringify(deserializeJsonObject(obj));
2194
+ const type = { type: "Json" };
2195
+ return this.#getOrCreatePlaceholder(jsonValue, type);
2196
+ }
2197
+ return obj;
2198
+ }
2199
+ /**
2200
+ * Parameterizes a selection set using output nodes.
2201
+ */
2202
+ #parameterizeSelection(selection, node) {
2203
+ if (!selection || !node) {
2204
+ return selection;
2205
+ }
2206
+ const result = {};
2207
+ for (const [key, value] of Object.entries(selection)) {
2208
+ if (key === "$scalars" || key === "$composites" || typeof value === "boolean") {
2209
+ result[key] = value;
2210
+ continue;
2211
+ }
2212
+ const edge = this.#view.outputEdge(node, key);
2213
+ if (edge) {
2214
+ const nested = value;
2215
+ const argsNode = this.#view.inputNode(edge.argsNodeId);
2216
+ const childOutNode = this.#view.outputNode(edge.outputNodeId);
2217
+ const processedValue = {
2218
+ selection: nested.selection ? this.#parameterizeSelection(nested.selection, childOutNode) : {}
2219
+ };
2220
+ if (nested.arguments) {
2221
+ processedValue.arguments = this.#parameterizeObject(nested.arguments, argsNode);
2222
+ }
2223
+ result[key] = processedValue;
2224
+ } else {
2225
+ result[key] = value;
2226
+ }
2227
+ }
2228
+ return result;
2229
+ }
2230
+ };
2231
+ function createPlaceholder(name, type) {
2232
+ return { $type: "Param", value: { name, ...type } };
2233
+ }
2234
+ function serializePlaceholderType(type) {
2235
+ if (type.type === "List") {
2236
+ return `List<${serializePlaceholderType(type.inner)}>`;
2237
+ }
2238
+ return type.type;
2239
+ }
2240
+ function serializeValue(value) {
2241
+ if (ArrayBuffer.isView(value)) {
2242
+ const bufView = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
2243
+ return bufView.toString("base64");
2244
+ }
2245
+ return JSON.stringify(value);
2246
+ }
2247
+ function createValueKey(value, type) {
2248
+ const typeKey = serializePlaceholderType(type);
2249
+ const valueKey = serializeValue(value);
2250
+ return `${typeKey}:${valueKey}`;
2251
+ }
2252
+ var MAX_INT = 2 ** 31 - 1;
2253
+ var MIN_INT = -(2 ** 31);
2254
+ function getPrimitivePlaceholderType(value) {
2255
+ switch (typeof value) {
2256
+ case "boolean":
2257
+ return { type: "Boolean" };
2258
+ case "number":
2259
+ if (!Number.isInteger(value)) {
2260
+ return { type: "Float" };
2261
+ }
2262
+ if (MIN_INT <= value && value <= MAX_INT) {
2263
+ return { type: "Int" };
2264
+ }
2265
+ return { type: "BigInt" };
2266
+ case "string":
2267
+ return { type: "String" };
2268
+ default:
2269
+ throw new Error("unreachable");
2270
+ }
2271
+ }
2272
+ function matchesPrimitiveMask({ type }, mask) {
2273
+ switch (type) {
2274
+ case "Boolean":
2275
+ return (mask & ScalarMask.Boolean) !== 0;
2276
+ case "Int":
2277
+ return (mask & (ScalarMask.Int | ScalarMask.BigInt | ScalarMask.Float)) !== 0;
2278
+ case "BigInt":
2279
+ return (mask & ScalarMask.BigInt) !== 0;
2280
+ case "Float":
2281
+ return (mask & ScalarMask.Float) !== 0;
2282
+ case "String":
2283
+ return (mask & ScalarMask.String) !== 0;
2284
+ default:
2285
+ return false;
2286
+ }
2287
+ }
2288
+ function getTaggedPlaceholderType(tag) {
2289
+ switch (tag) {
2290
+ case "BigInt":
2291
+ case "Bytes":
2292
+ case "DateTime":
2293
+ case "Json":
2294
+ return { type: tag };
2295
+ case "Decimal":
2296
+ return { type: "Float" };
2297
+ default:
2298
+ return void 0;
2299
+ }
2300
+ }
2301
+ function inferListElementType(items) {
2302
+ let widest = { type: "Any" };
2303
+ for (const item of items) {
2304
+ const classified = classifyValue(item);
2305
+ let itemType;
2306
+ switch (classified.kind) {
2307
+ case "primitive":
2308
+ itemType = getPrimitivePlaceholderType(classified.value);
2309
+ break;
2310
+ case "taggedScalar":
2311
+ itemType = getTaggedPlaceholderType(classified.tag) ?? { type: "Any" };
2312
+ break;
2313
+ default:
2314
+ return { type: "Any" };
2315
+ }
2316
+ widest = widenType(widest, itemType);
2317
+ }
2318
+ return widest;
2319
+ }
2320
+ function widenType(a, b) {
2321
+ if (a.type === "Any") return b;
2322
+ if (b.type === "Any") return a;
2323
+ if (a.type === b.type) return a;
2324
+ const NUMERIC_WIDTH = { Int: 0, BigInt: 1, Float: 2 };
2325
+ const aWidth = NUMERIC_WIDTH[a.type];
2326
+ const bWidth = NUMERIC_WIDTH[b.type];
2327
+ if (aWidth !== void 0 && bWidth !== void 0) {
2328
+ return aWidth >= bWidth ? a : b;
2329
+ }
2330
+ return { type: "Any" };
2331
+ }
2332
+ function matchesTaggedMask(tag, mask) {
2333
+ switch (tag) {
2334
+ case "DateTime":
2335
+ return (mask & ScalarMask.DateTime) !== 0;
2336
+ case "Decimal":
2337
+ return (mask & ScalarMask.Decimal) !== 0;
2338
+ case "BigInt":
2339
+ return (mask & ScalarMask.BigInt) !== 0;
2340
+ case "Bytes":
2341
+ return (mask & ScalarMask.Bytes) !== 0;
2342
+ case "Json":
2343
+ return (mask & ScalarMask.Json) !== 0;
2344
+ default:
2345
+ return false;
2346
+ }
2347
+ }
2348
+ function validateListElement(item, edge) {
2349
+ const classified = classifyValue(item);
2350
+ switch (classified.kind) {
2351
+ case "structural":
2352
+ return false;
2353
+ case "null":
2354
+ return false;
2355
+ case "primitive": {
2356
+ const type = getPrimitivePlaceholderType(classified.value);
2357
+ const mask = getScalarMask(edge);
2358
+ return mask !== 0 && matchesPrimitiveMask(type, mask);
2359
+ }
2360
+ case "taggedScalar": {
2361
+ const mask = getScalarMask(edge);
2362
+ return mask !== 0 && matchesTaggedMask(classified.tag, mask);
2363
+ }
2364
+ default:
2365
+ return false;
2366
+ }
2367
+ }
2368
+ function decodeIfTagged(value) {
2369
+ if (isTaggedValue2(value)) {
2370
+ return decodeTaggedValue(value);
2371
+ }
2372
+ return value;
2373
+ }
2374
+ function decodeTaggedValue(tagged) {
2375
+ return tagged.value;
2376
+ }
2377
+
1940
2378
  // src/raw-json-protocol.ts
1941
2379
  import { Decimal as Decimal4 } from "@prisma/client-runtime-utils";
1942
2380
  function normalizeRawJsonProtocolResponse(response) {
@@ -2425,5 +2863,7 @@ export {
2425
2863
  noopTracingHelper,
2426
2864
  normalizeJsonProtocolValues,
2427
2865
  normalizeRawJsonProtocolResponse,
2866
+ parameterizeBatch,
2867
+ parameterizeQuery,
2428
2868
  safeJsonStringify
2429
2869
  };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Value classification for parameterization.
3
+ *
4
+ * This module classifies runtime values into categories before applying
5
+ * schema rules during parameterization.
6
+ */
7
+ import { JsonInputTaggedValue } from '@prisma/json-protocol';
8
+ /**
9
+ * Classification result for a runtime value.
10
+ * Used to determine how to handle the value during parameterization.
11
+ */
12
+ export type ValueClass = {
13
+ kind: 'null';
14
+ } | {
15
+ kind: 'primitive';
16
+ value: string | number | boolean;
17
+ } | {
18
+ kind: 'taggedScalar';
19
+ tag: JsonInputTaggedValue['$type'];
20
+ value: unknown;
21
+ } | {
22
+ kind: 'structural';
23
+ value: unknown;
24
+ } | {
25
+ kind: 'array';
26
+ items: unknown[];
27
+ } | {
28
+ kind: 'object';
29
+ entries: Record<string, unknown>;
30
+ };
31
+ /**
32
+ * Classifies a runtime value for parameterization purposes.
33
+ *
34
+ * @param value - The value to classify
35
+ * @returns The classification result indicating how to handle the value
36
+ */
37
+ export declare function classifyValue(value: unknown): ValueClass;
38
+ /**
39
+ * Checks if a value is a plain object (not a tagged value or array).
40
+ */
41
+ export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
42
+ /**
43
+ * Checks if a value is a tagged value with a $type property.
44
+ */
45
+ export declare function isTaggedValue(value: unknown): value is {
46
+ $type: string;
47
+ value: unknown;
48
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import { ParamGraph } from '@prisma/param-graph';
2
+ export declare const testRuntimeDataModel: {
3
+ models: {};
4
+ enums: {
5
+ Status: {
6
+ values: {
7
+ name: string;
8
+ dbName: null;
9
+ }[];
10
+ dbName: null;
11
+ };
12
+ };
13
+ types: {};
14
+ };
15
+ /**
16
+ * Returns the ParamGraph for the test schema, building it on first call.
17
+ */
18
+ export declare function getParamGraph(): ParamGraph;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Schema-aware traversal algorithm for parameterization.
3
+ *
4
+ * This module implements the core parameterization logic that walks the
5
+ * JsonQuery tree guided by ParamGraph. It only parameterizes values when
6
+ * both schema rules and runtime value types agree.
7
+ */
8
+ import type { JsonBatchQuery, JsonQuery } from '@prisma/json-protocol';
9
+ import { ParamGraph } from '@prisma/param-graph';
10
+ /**
11
+ * Result of parameterizing a single query.
12
+ */
13
+ export interface ParameterizeResult {
14
+ /** The query with user data values replaced by placeholders */
15
+ parameterizedQuery: JsonQuery;
16
+ /** Map of placeholder names to their actual values */
17
+ placeholderValues: Record<string, unknown>;
18
+ }
19
+ /**
20
+ * Result of parameterizing a batch of queries.
21
+ */
22
+ export interface ParameterizeBatchResult {
23
+ /** The batch with user data values replaced by placeholders */
24
+ parameterizedBatch: JsonBatchQuery;
25
+ /** Combined map of placeholder names to their actual values */
26
+ placeholderValues: Record<string, unknown>;
27
+ }
28
+ /**
29
+ * Parameterizes a single query using the schema-aware approach.
30
+ *
31
+ * @param query - The query to parameterize
32
+ * @param view - The ParamGraph for schema lookups
33
+ * @returns The parameterized query with extracted placeholder values
34
+ */
35
+ export declare function parameterizeQuery(query: JsonQuery, view: ParamGraph): ParameterizeResult;
36
+ /**
37
+ * Parameterizes a batch of queries using the schema-aware approach.
38
+ *
39
+ * @param batch - The batch to parameterize
40
+ * @param view - The ParamGraph for schema lookups
41
+ * @returns The parameterized batch with extracted placeholder values
42
+ */
43
+ export declare function parameterizeBatch(batch: JsonBatchQuery, view: ParamGraph): ParameterizeBatchResult;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/client-engine-runtime",
3
- "version": "7.6.0",
3
+ "version": "7.7.0-dev.2",
4
4
  "description": "This package is intended for Prisma's internal use",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -31,16 +31,20 @@
31
31
  "nanoid": "5.1.5",
32
32
  "ulid": "3.0.0",
33
33
  "uuid": "11.1.0",
34
- "@prisma/client-runtime-utils": "7.6.0",
35
- "@prisma/debug": "7.6.0",
36
- "@prisma/sqlcommenter": "7.6.0",
37
- "@prisma/driver-adapter-utils": "7.6.0"
34
+ "@prisma/client-runtime-utils": "7.7.0-dev.2",
35
+ "@prisma/param-graph": "7.7.0-dev.2",
36
+ "@prisma/debug": "7.7.0-dev.2",
37
+ "@prisma/sqlcommenter": "7.7.0-dev.2",
38
+ "@prisma/json-protocol": "7.7.0-dev.2",
39
+ "@prisma/driver-adapter-utils": "7.7.0-dev.2"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@codspeed/benchmark.js-plugin": "4.0.0",
41
43
  "@types/benchmark": "2.1.5",
42
44
  "@types/node": "~20.19.24",
43
- "benchmark": "2.1.4"
45
+ "benchmark": "2.1.4",
46
+ "@prisma/get-dmmf": "7.7.0-dev.2",
47
+ "@prisma/param-graph-builder": "7.7.0-dev.2"
44
48
  },
45
49
  "files": [
46
50
  "dist"