diff --git a/packages/client-engine-runtime/bench/sample-query-plans.ts b/packages/client-engine-runtime/bench/sample-query-plans.ts index 6098ae1a2a6f..b0a96c7895ed 100644 --- a/packages/client-engine-runtime/bench/sample-query-plans.ts +++ b/packages/client-engine-runtime/bench/sample-query-plans.ts @@ -111,6 +111,7 @@ export const JOIN_PLAN: QueryPlanNode = { isRelationUnique: false, }, ], + canAssumeStrictEquality: true, }, }, structure: { @@ -231,6 +232,7 @@ export const DEEP_JOIN_PLAN: QueryPlanNode = { isRelationUnique: true, }, ], + canAssumeStrictEquality: true, }, }, children: [ @@ -278,6 +280,7 @@ export const DEEP_JOIN_PLAN: QueryPlanNode = { isRelationUnique: false, }, ], + canAssumeStrictEquality: true, }, }, on: [['id', 'authorId']], @@ -285,6 +288,7 @@ export const DEEP_JOIN_PLAN: QueryPlanNode = { isRelationUnique: false, }, ], + canAssumeStrictEquality: true, }, }, structure: { diff --git a/packages/client-engine-runtime/src/events.ts b/packages/client-engine-runtime/src/events.ts index e87fe630cfc1..b5cae9e8ec6b 100644 --- a/packages/client-engine-runtime/src/events.ts +++ b/packages/client-engine-runtime/src/events.ts @@ -1,6 +1,6 @@ export type QueryEvent = { timestamp: Date query: string - params: unknown[] + params: readonly unknown[] duration: number } diff --git a/packages/client-engine-runtime/src/interpreter/in-memory-processing.ts b/packages/client-engine-runtime/src/interpreter/in-memory-processing.ts index 9da17a174f5c..afd7dc5fb9a5 100644 --- a/packages/client-engine-runtime/src/interpreter/in-memory-processing.ts +++ b/packages/client-engine-runtime/src/interpreter/in-memory-processing.ts @@ -111,6 +111,9 @@ function paginateSingleList(list: {}[], { cursor, skip, take }: Pagination): {}[ /* * Generate a key string for a record based on the values of the specified fields. */ -export function getRecordKey(record: {}, fields: string[]): string { - return JSON.stringify(fields.map((field) => record[field])) +export function getRecordKey(record: {}, fields: readonly string[], mappers?: ((value: unknown) => unknown)[]): string { + const array = fields.map((field, index) => + mappers?.[index] ? (record[field] !== null ? mappers[index](record[field]) : null) : record[field], + ) + return JSON.stringify(array) } diff --git a/packages/client-engine-runtime/src/interpreter/query-interpreter.ts b/packages/client-engine-runtime/src/interpreter/query-interpreter.ts index b2c25ac4eda4..f63fd9cb271c 100644 --- a/packages/client-engine-runtime/src/interpreter/query-interpreter.ts +++ b/packages/client-engine-runtime/src/interpreter/query-interpreter.ts @@ -1,5 +1,6 @@ import { ConnectionInfo, SqlQuery, SqlQueryable, SqlResultSet } from '@prisma/driver-adapter-utils' import type { SqlCommenterPlugin, SqlCommenterQueryInfo } from '@prisma/sqlcommenter' +import { klona } from 'klona' import { QueryEvent } from '../events' import { FieldInitializer, FieldOperation, InMemoryOps, JoinExpression, QueryPlanNode } from '../query-plan' @@ -8,7 +9,7 @@ import { appendSqlComment, buildSqlComment } from '../sql-commenter' import { type TracingHelper, withQuerySpanAndEvent } from '../tracing' import { type TransactionManager } from '../transaction-manager/transaction-manager' import { rethrowAsUserFacing, rethrowAsUserFacingRawError } from '../user-facing-error' -import { assertNever } from '../utils' +import { assertNever, DeepReadonly, DeepUnreadonly } from '../utils' import { applyDataMap } from './data-mapper' import { GeneratorRegistry, GeneratorRegistrySnapshot } from './generators' import { getRecordKey, processRecords } from './in-memory-processing' @@ -89,7 +90,7 @@ export class QueryInterpreter { }) } - async run(queryPlan: QueryPlanNode, options: QueryRuntimeOptions): Promise { + async run(queryPlan: DeepReadonly, options: QueryRuntimeOptions): Promise { const { value } = await this.interpretNode(queryPlan, { ...options, generators: this.#generators.snapshot(), @@ -98,7 +99,10 @@ export class QueryInterpreter { return value } - private async interpretNode(node: QueryPlanNode, context: QueryRuntimeContext): Promise { + private async interpretNode( + node: DeepReadonly, + context: QueryRuntimeContext, + ): Promise { switch (node.type) { case 'value': { return { @@ -163,7 +167,7 @@ export class QueryInterpreter { const commentedQuery = applyComments(query, context.sqlCommenter) sum += await this.#withQuerySpanAndEvent(commentedQuery, context.queryable, () => context.queryable - .executeRaw(commentedQuery) + .executeRaw(cloneObject(commentedQuery)) .catch((err) => node.args.type === 'rawSql' ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err), ), @@ -181,7 +185,7 @@ export class QueryInterpreter { const commentedQuery = applyComments(query, context.sqlCommenter) const result = await this.#withQuerySpanAndEvent(commentedQuery, context.queryable, () => context.queryable - .queryRaw(commentedQuery) + .queryRaw(cloneObject(commentedQuery)) .catch((err) => node.args.type === 'rawSql' ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err), ), @@ -236,14 +240,14 @@ export class QueryInterpreter { return { value: null, lastInsertId } } - const children = (await Promise.all( + const children = await Promise.all( node.args.children.map(async (joinExpr) => ({ joinExpr, childRecords: (await this.interpretNode(joinExpr.child, context)).value, })), - )) satisfies JoinExpressionWithRecords[] + ) - return { value: attachChildrenToParents(parent, children), lastInsertId } + return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId } } case 'transaction': { @@ -301,8 +305,9 @@ export class QueryInterpreter { case 'process': { const { value, lastInsertId } = await this.interpretNode(node.args.expr, context) - evaluateProcessingParameters(node.args.operations, context.scope, context.generators) - return { value: processRecords(value, node.args.operations), lastInsertId } + const ops = cloneObject(node.args.operations) + evaluateProcessingParameters(ops, context.scope, context.generators) + return { value: processRecords(value, ops), lastInsertId } } case 'initializeRecord': { @@ -360,7 +365,11 @@ export class QueryInterpreter { } } - #withQuerySpanAndEvent(query: SqlQuery, queryable: SqlQueryable, execute: () => Promise): Promise { + #withQuerySpanAndEvent( + query: DeepReadonly, + queryable: SqlQueryable, + execute: () => Promise, + ): Promise { return withQuerySpanAndEvent({ query, execute, @@ -420,13 +429,20 @@ type JoinExpressionWithRecords = { childRecords: Value } -function attachChildrenToParents(parentRecords: unknown, children: JoinExpressionWithRecords[]) { +type KeyCast = (value: Value) => Value + +function attachChildrenToParents( + parentRecords: unknown, + children: DeepReadonly, + canAssumeStrictEquality: boolean, +) { for (const { joinExpr, childRecords } of children) { const parentKeys = joinExpr.on.map(([k]) => k) const childKeys = joinExpr.on.map(([, k]) => k) const parentMap = {} - for (const parent of Array.isArray(parentRecords) ? parentRecords : [parentRecords]) { + const parentArray = Array.isArray(parentRecords) ? parentRecords : [parentRecords] + for (const parent of parentArray) { const parentRecord = asRecord(parent) const key = getRecordKey(parentRecord, parentKeys) if (!parentMap[key]) { @@ -441,12 +457,13 @@ function attachChildrenToParents(parentRecords: unknown, children: JoinExpressio } } + const mappers = canAssumeStrictEquality ? undefined : inferKeyCasts(parentArray, parentKeys) for (const childRecord of Array.isArray(childRecords) ? childRecords : [childRecords]) { if (childRecord === null) { continue } - const key = getRecordKey(asRecord(childRecord), childKeys) + const key = getRecordKey(asRecord(childRecord), childKeys, mappers) for (const parentRecord of parentMap[key] ?? []) { if (joinExpr.isRelationUnique) { parentRecord[joinExpr.parentField] = childRecord @@ -460,8 +477,45 @@ function attachChildrenToParents(parentRecords: unknown, children: JoinExpressio return parentRecords } +function inferKeyCasts(rows: unknown[], keys: string[]): KeyCast[] { + function getKeyCast(type: string): KeyCast | undefined { + switch (type) { + case 'number': + return Number + case 'string': + return String + case 'boolean': + return Boolean + case 'bigint': + return BigInt as KeyCast + default: + return + } + } + + const keyCasts: KeyCast[] = Array.from({ length: keys.length }) + let keysFound = 0 + for (const parent of rows) { + const parentRecord = asRecord(parent) + for (const [i, key] of keys.entries()) { + if (parentRecord[key] !== null && keyCasts[i] === undefined) { + const keyCast = getKeyCast(typeof parentRecord[key]) + if (keyCast !== undefined) { + keyCasts[i] = keyCast + } + keysFound++ + } + } + if (keysFound === keys.length) { + break + } + } + + return keyCasts +} + function evalFieldInitializer( - initializer: FieldInitializer, + initializer: DeepReadonly, lastInsertId: string | undefined, scope: ScopeBindings, generators: GeneratorRegistrySnapshot, @@ -477,7 +531,7 @@ function evalFieldInitializer( } function evalFieldOperation( - op: FieldOperation, + op: DeepReadonly, value: Value, scope: ScopeBindings, generators: GeneratorRegistrySnapshot, @@ -508,7 +562,10 @@ function evalFieldOperation( } } -function applyComments(query: SqlQuery, sqlCommenter?: QueryInterpreterSqlCommenter): SqlQuery { +function applyComments( + query: DeepReadonly, + sqlCommenter?: QueryInterpreterSqlCommenter, +): DeepReadonly { if (!sqlCommenter || sqlCommenter.plugins.length === 0) { return query } @@ -543,3 +600,7 @@ function evaluateProcessingParameters( evaluateProcessingParameters(nested, scope, generators) } } + +function cloneObject(value: T): DeepUnreadonly { + return klona(value) as DeepUnreadonly +} diff --git a/packages/client-engine-runtime/src/interpreter/render-query.ts b/packages/client-engine-runtime/src/interpreter/render-query.ts index 732ea3c08345..cbb4441e9ba9 100644 --- a/packages/client-engine-runtime/src/interpreter/render-query.ts +++ b/packages/client-engine-runtime/src/interpreter/render-query.ts @@ -11,16 +11,16 @@ import { type QueryPlanDbQuery, } from '../query-plan' import { UserFacingError } from '../user-facing-error' -import { assertNever } from '../utils' +import { assertNever, DeepReadonly } from '../utils' import { GeneratorRegistrySnapshot } from './generators' import { ScopeBindings } from './scope' export function renderQuery( - dbQuery: QueryPlanDbQuery, + dbQuery: DeepReadonly, scope: ScopeBindings, generators: GeneratorRegistrySnapshot, maxChunkSize?: number, -): SqlQuery[] { +): DeepReadonly[] { const args = dbQuery.args.map((arg) => evaluateArg(arg, scope, generators)) switch (dbQuery.type) { @@ -69,10 +69,10 @@ export function evaluateArg(arg: unknown, scope: ScopeBindings, generators: Gene } function renderTemplateSql( - fragments: Fragment[], + fragments: DeepReadonly, placeholderFormat: PlaceholderFormat, params: unknown[], - argTypes: DynamicArgType[], + argTypes: DeepReadonly, ): SqlQuery { let sql = '' const ctx = { placeholderNumber: 1 } @@ -112,7 +112,7 @@ function renderTemplateSql( } } -function renderFragment( +function renderFragment | undefined>( fragment: FragmentWithParams, placeholderFormat: PlaceholderFormat, ctx: { placeholderNumber: number }, @@ -158,10 +158,14 @@ function formatPlaceholder(placeholderFormat: PlaceholderFormat, placeholderNumb return placeholderFormat.hasNumbering ? `${placeholderFormat.prefix}${placeholderNumber}` : placeholderFormat.prefix } -function renderRawSql(sql: string, args: unknown[], argTypes: ArgType[]): SqlQuery { +function renderRawSql( + sql: string, + args: readonly unknown[], + argTypes: DeepReadonly, +): DeepReadonly { return { sql, - args: args, + args, argTypes, } } @@ -170,7 +174,7 @@ function doesRequireEvaluation(param: unknown): param is PrismaValuePlaceholder return isPrismaValuePlaceholder(param) || isPrismaValueGenerator(param) } -type FragmentWithParams = Fragment & +type FragmentWithParams | undefined = undefined> = Fragment & ( | { type: 'stringChunk' } | { type: 'parameter'; value: unknown; argType: Type } @@ -179,10 +183,12 @@ type FragmentWithParams = F ) function* pairFragmentsWithParams( - fragments: Fragment[], + fragments: DeepReadonly, params: unknown[], argTypes: Types, -): Generator> { +): Generator< + FragmentWithParams ? DeepReadonly : undefined> +> { let index = 0 for (const fragment of fragments) { @@ -239,7 +245,7 @@ function* pairFragmentsWithParams( } } -function* flattenedFragmentParams( +function* flattenedFragmentParams | undefined>( fragment: FragmentWithParams, ): Generator { switch (fragment.type) { @@ -259,7 +265,7 @@ function* flattenedFragmentParams( } } -function chunkParams(fragments: Fragment[], params: unknown[], maxChunkSize?: number): unknown[][] { +function chunkParams(fragments: DeepReadonly, params: unknown[], maxChunkSize?: number): unknown[][] { // Find out the total number of parameters once flattened and what the maximum number of // parameters in a single fragment is. let totalParamCount = 0 diff --git a/packages/client-engine-runtime/src/interpreter/validation.ts b/packages/client-engine-runtime/src/interpreter/validation.ts index 0af7d8a16f19..87c47d387d51 100644 --- a/packages/client-engine-runtime/src/interpreter/validation.ts +++ b/packages/client-engine-runtime/src/interpreter/validation.ts @@ -1,8 +1,8 @@ import { DataRule, ValidationError } from '../query-plan' import { UserFacingError } from '../user-facing-error' -import { assertNever } from '../utils' +import { assertNever, DeepReadonly } from '../utils' -export function performValidation(data: unknown, rules: DataRule[], error: ValidationError) { +export function performValidation(data: unknown, rules: DeepReadonly, error: ValidationError) { if (!rules.every((rule) => doesSatisfyRule(data, rule))) { const message = renderMessage(data, error) const code = getErrorCode(error) @@ -42,7 +42,7 @@ export function doesSatisfyRule(data: unknown, rule: DataRule): boolean { } function renderMessage(data: unknown, error: ValidationError): string { - switch (error.error_identifier) { + switch (error.errorIdentifier) { case 'RELATION_VIOLATION': return `The change you are trying to make would violate the required relation '${error.context.relation}' between the \`${error.context.modelA}\` and \`${error.context.modelB}\` models.` case 'MISSING_RECORD': @@ -70,7 +70,7 @@ function renderMessage(data: unknown, error: ValidationError): string { } function getErrorCode(error: ValidationError): string { - switch (error.error_identifier) { + switch (error.errorIdentifier) { case 'RELATION_VIOLATION': return 'P2014' case 'RECORDS_NOT_CONNECTED': diff --git a/packages/client-engine-runtime/src/query-plan.ts b/packages/client-engine-runtime/src/query-plan.ts index 35bc710d0ded..751a56e3dab3 100644 --- a/packages/client-engine-runtime/src/query-plan.ts +++ b/packages/client-engine-runtime/src/query-plan.ts @@ -154,6 +154,7 @@ export type QueryPlanNode = args: { parent: QueryPlanNode children: JoinExpression[] + canAssumeStrictEquality: boolean } } | { @@ -266,7 +267,7 @@ export type DataRule = export type ValidationError = | { - error_identifier: 'RELATION_VIOLATION' + errorIdentifier: 'RELATION_VIOLATION' context: { relation: string modelA: string @@ -274,7 +275,7 @@ export type ValidationError = } } | { - error_identifier: 'MISSING_RELATED_RECORD' + errorIdentifier: 'MISSING_RELATED_RECORD' context: { model: string relation: string @@ -284,19 +285,19 @@ export type ValidationError = } } | { - error_identifier: 'MISSING_RECORD' + errorIdentifier: 'MISSING_RECORD' context: { operation: string } } | { - error_identifier: 'INCOMPLETE_CONNECT_INPUT' + errorIdentifier: 'INCOMPLETE_CONNECT_INPUT' context: { expectedRows: number } } | { - error_identifier: 'INCOMPLETE_CONNECT_OUTPUT' + errorIdentifier: 'INCOMPLETE_CONNECT_OUTPUT' context: { expectedRows: number relation: string @@ -304,7 +305,7 @@ export type ValidationError = } } | { - error_identifier: 'RECORDS_NOT_CONNECTED' + errorIdentifier: 'RECORDS_NOT_CONNECTED' context: { relation: string parent: string diff --git a/packages/client-engine-runtime/src/tracing.ts b/packages/client-engine-runtime/src/tracing.ts index 82234c641572..5be434403c3d 100644 --- a/packages/client-engine-runtime/src/tracing.ts +++ b/packages/client-engine-runtime/src/tracing.ts @@ -3,7 +3,7 @@ import type { SqlQuery } from '@prisma/driver-adapter-utils' import { QueryEvent } from './events' import type { SchemaProvider } from './schema' -import { assertNever } from './utils' +import { assertNever, DeepReadonly } from './utils' export type SpanCallback = (span?: Span, context?: Context) => R @@ -51,7 +51,7 @@ export async function withQuerySpanAndEvent({ onQuery, execute, }: { - query: SqlQuery + query: DeepReadonly tracingHelper: TracingHelper provider: SchemaProvider onQuery?: (event: QueryEvent) => void diff --git a/packages/client-engine-runtime/src/utils.ts b/packages/client-engine-runtime/src/utils.ts index 744333c245ef..a5948f1d2739 100644 --- a/packages/client-engine-runtime/src/utils.ts +++ b/packages/client-engine-runtime/src/utils.ts @@ -1,5 +1,21 @@ import { Decimal } from '@prisma/client-runtime-utils' +export type DeepReadonly = T extends undefined | null | boolean | string | number | symbol | Function | Date + ? T + : T extends Array + ? ReadonlyArray> + : unknown extends T + ? unknown + : { readonly [K in keyof T]: DeepReadonly } + +export type DeepUnreadonly = T extends undefined | null | boolean | string | number | symbol | Function | Date + ? T + : T extends ReadonlyArray + ? Array> + : unknown extends T + ? unknown + : { -readonly [K in keyof T]: DeepUnreadonly } + // Copied over to avoid the heavy dependency on `@prisma/internals` with its // transitive dependencies that are not needed for other query plan executor // implementations outside of Prisma Client (e.g. test executor for query diff --git a/packages/client-generator-js/package.json b/packages/client-generator-js/package.json index ab2b05eec8eb..0f35d2bb8703 100644 --- a/packages/client-generator-js/package.json +++ b/packages/client-generator-js/package.json @@ -28,7 +28,7 @@ "@prisma/client-common": "workspace:*", "@prisma/debug": "workspace:*", "@prisma/dmmf": "workspace:*", - "@prisma/engines-version": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/fetch-engine": "workspace:*", "@prisma/generator": "workspace:*", "@prisma/get-platform": "workspace:*", diff --git a/packages/client-generator-ts/package.json b/packages/client-generator-ts/package.json index 8bba740e8bb1..a80322797155 100644 --- a/packages/client-generator-ts/package.json +++ b/packages/client-generator-ts/package.json @@ -28,7 +28,7 @@ "@prisma/client-common": "workspace:*", "@prisma/debug": "workspace:*", "@prisma/dmmf": "workspace:*", - "@prisma/engines-version": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/fetch-engine": "workspace:*", "@prisma/generator": "workspace:*", "@prisma/get-platform": "workspace:*", diff --git a/packages/client/package.json b/packages/client/package.json index 97275cf6e8f1..a86e9cd4fa18 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -198,7 +198,7 @@ "@prisma/dmmf": "workspace:*", "@prisma/driver-adapter-utils": "workspace:*", "@prisma/engines": "workspace:*", - "@prisma/engines-version": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/fetch-engine": "workspace:*", "@prisma/generator": "workspace:*", "@prisma/generator-helper": "workspace:*", @@ -210,7 +210,7 @@ "@prisma/migrate": "workspace:*", "@prisma/param-graph": "workspace:*", "@prisma/param-graph-builder": "workspace:*", - "@prisma/query-compiler-wasm": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/query-compiler-wasm": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/query-plan-executor": "workspace:*", "@prisma/sqlcommenter": "workspace:*", "@prisma/sqlcommenter-trace-context": "workspace:*", diff --git a/packages/client/src/runtime/core/engines/client/parameterization/parameterize.ts b/packages/client/src/runtime/core/engines/client/parameterization/parameterize.ts index 9619b487ce0b..3edb3402b18a 100644 --- a/packages/client/src/runtime/core/engines/client/parameterization/parameterize.ts +++ b/packages/client/src/runtime/core/engines/client/parameterization/parameterize.ts @@ -6,7 +6,7 @@ * both schema rules and runtime value types agree. */ -import { deserializeJsonObject } from '@prisma/client-engine-runtime' +import { deserializeJsonObject, safeJsonStringify } from '@prisma/client-engine-runtime' import type { JsonArgumentValue, JsonBatchQuery, @@ -273,7 +273,7 @@ class Parameterizer { */ #handleArray(items: unknown[], originalValue: unknown, edge: InputEdge): unknown { if (hasFlag(edge, EdgeFlag.ParamScalar) && getScalarMask(edge) & ScalarMask.Json) { - const jsonValue = JSON.stringify(deserializeJsonObject(items)) + const jsonValue = safeJsonStringify(deserializeJsonObject(items)) const type: PlaceholderType = { type: 'Json' } return this.#getOrCreatePlaceholder(jsonValue, type) } @@ -324,7 +324,7 @@ class Parameterizer { const mask = getScalarMask(edge) if (mask & ScalarMask.Json) { - const jsonValue = JSON.stringify(deserializeJsonObject(obj)) + const jsonValue = safeJsonStringify(deserializeJsonObject(obj)) const type: PlaceholderType = { type: 'Json' } return this.#getOrCreatePlaceholder(jsonValue, type) } diff --git a/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/_matrix.ts b/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/_matrix.ts new file mode 100644 index 000000000000..3585f7b579f9 --- /dev/null +++ b/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/_matrix.ts @@ -0,0 +1,4 @@ +import { defineMatrix } from '../../_utils/defineMatrix' +import { Providers } from '../../_utils/providers' + +export default defineMatrix(() => [[{ provider: Providers.MYSQL }]]) diff --git a/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/prisma/_schema.ts b/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/prisma/_schema.ts new file mode 100644 index 000000000000..8bbbc863390e --- /dev/null +++ b/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/prisma/_schema.ts @@ -0,0 +1,36 @@ +import testMatrix from '../_matrix' + +export default testMatrix.setupSchema(({ provider }) => { + return /* Prisma */ ` + generator client { + provider = "prisma-client-js" + previewFeatures = ["views"] + } + + datasource db { + provider = "${provider}" + } + + model users { + id Int @id @default(autoincrement()) + posts posts[] + userPostSummary user_post_summary[] + } + + model posts { + id Int @id @default(autoincrement()) + user_id Int + users users @relation(fields: [user_id], references: [id]) + userPostSummary user_post_summary[] + + @@index([user_id]) + } + + view user_post_summary { + user_id Int @unique + last_post_id Int? + users users? @relation(fields: [user_id], references: [id]) + last_post posts? @relation(fields: [last_post_id], references: [id]) + } + ` +}) diff --git a/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/tests.ts b/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/tests.ts new file mode 100644 index 000000000000..946fbd414347 --- /dev/null +++ b/packages/client/tests/functional/issues/29122-mysql-bigint-view-relation/tests.ts @@ -0,0 +1,62 @@ +import testMatrix from './_matrix' +// @ts-ignore +import type { PrismaClient } from './generated/prisma/client' + +declare let prisma: PrismaClient + +testMatrix.setupTestSuite( + () => { + test('correctly handles an integer key returned from a view relation in MySQL', async () => { + await prisma.$executeRawUnsafe(` + CREATE OR REPLACE VIEW user_post_summary AS + SELECT users.id AS user_id, + ( + SELECT posts.id + FROM posts + WHERE posts.user_id = users.id + ORDER BY posts.id DESC + LIMIT 1 + ) AS last_post_id + FROM users + `) + + await prisma.users.create({ + data: { + id: 1, + posts: { + create: [ + { + id: 1, + }, + ], + }, + }, + }) + + const result = await prisma.user_post_summary.findMany({ + include: { + last_post: true, + }, + }) + + expect(result).toMatchInlineSnapshot(` + [ + { + "last_post": { + "id": 1, + "user_id": 1, + }, + "last_post_id": 1, + "user_id": 1, + }, + ] + `) + }) + }, + { + optOut: { + from: ['postgresql', 'sqlite', 'cockroachdb', 'sqlserver', 'mongodb'], + reason: 'This test is only relevant for MySQL, as it tests a MySQL specific regression.', + }, + }, +) diff --git a/packages/client/tests/functional/issues/29212-array-push-regression/_matrix.ts b/packages/client/tests/functional/issues/29212-array-push-regression/_matrix.ts new file mode 100644 index 000000000000..4002505d9f7a --- /dev/null +++ b/packages/client/tests/functional/issues/29212-array-push-regression/_matrix.ts @@ -0,0 +1,8 @@ +import { defineMatrix } from '../../_utils/defineMatrix' +import { allProviders, Providers } from '../../_utils/providers' + +export default defineMatrix(() => [ + allProviders.filter( + ({ provider }) => provider !== Providers.MYSQL && provider !== Providers.SQLITE && provider !== Providers.SQLSERVER, + ), +]) diff --git a/packages/client/tests/functional/issues/29212-array-push-regression/prisma/_schema.ts b/packages/client/tests/functional/issues/29212-array-push-regression/prisma/_schema.ts new file mode 100644 index 000000000000..ee79bf95663e --- /dev/null +++ b/packages/client/tests/functional/issues/29212-array-push-regression/prisma/_schema.ts @@ -0,0 +1,20 @@ +import { idForProvider } from '../../../_utils/idForProvider' +import testMatrix from '../_matrix' + +export default testMatrix.setupSchema(({ provider }) => { + return /* Prisma */ ` + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "${provider}" + } + + model Item { + id ${idForProvider(provider, { includeDefault: true })} + name String + tags String[] + } + ` +}) diff --git a/packages/client/tests/functional/issues/29212-array-push-regression/tests.ts b/packages/client/tests/functional/issues/29212-array-push-regression/tests.ts new file mode 100644 index 000000000000..847b7ac2b1ba --- /dev/null +++ b/packages/client/tests/functional/issues/29212-array-push-regression/tests.ts @@ -0,0 +1,35 @@ +import testMatrix from './_matrix' +// @ts-ignore +import type { PrismaClient } from './generated/prisma/client' + +declare let prisma: PrismaClient + +testMatrix.setupTestSuite( + () => { + test('correctly pushes to array field', async () => { + const item = await prisma.item.create({ + data: { + name: 'Test', + tags: ['a', 'b', 'c'], + }, + }) + + const updated = await prisma.item.update({ + where: { id: item.id }, + data: { tags: { push: ['foo', 'bar'] } }, + }) + + expect(updated).toMatchObject({ + id: item.id, + name: 'Test', + tags: ['a', 'b', 'c', 'foo', 'bar'], + }) + }) + }, + { + optOut: { + from: ['mysql', 'sqlite', 'sqlserver'], + reason: 'Array push is not supported on these providers', + }, + }, +) diff --git a/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/_matrix.ts b/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/_matrix.ts new file mode 100644 index 000000000000..d56f2f6b7702 --- /dev/null +++ b/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/_matrix.ts @@ -0,0 +1,4 @@ +import { defineMatrix } from '../../_utils/defineMatrix' +import { allProviders } from '../../_utils/providers' + +export default defineMatrix(() => [allProviders]) diff --git a/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/prisma/_schema.ts b/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/prisma/_schema.ts new file mode 100644 index 000000000000..624eedad7a1a --- /dev/null +++ b/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/prisma/_schema.ts @@ -0,0 +1,19 @@ +import { idForProvider } from '../../../_utils/idForProvider' +import testMatrix from '../_matrix' + +export default testMatrix.setupSchema(({ provider }) => { + return /* Prisma */ ` + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "${provider}" + } + + model Item { + id ${idForProvider(provider, { includeDefault: true })} + price Float? + } + ` +}) diff --git a/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/tests.ts b/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/tests.ts new file mode 100644 index 000000000000..35f536a00e87 --- /dev/null +++ b/packages/client/tests/functional/issues/29254-query-plan-cache-mutation/tests.ts @@ -0,0 +1,47 @@ +import { faker } from '@snaplet/copycat' + +import testMatrix from './_matrix' +// @ts-ignore +import type { PrismaClient } from './generated/prisma/client' + +declare let prisma: PrismaClient + +testMatrix.setupTestSuite(() => { + const id1 = faker.database.mongodbObjectId() + const id2 = faker.database.mongodbObjectId() + const id3 = faker.database.mongodbObjectId() + + afterEach(async () => { + await prisma.item.deleteMany() + }) + + beforeEach(async () => { + await prisma.item.createMany({ + data: [ + { id: id1, price: 10 }, + { id: id2, price: 20 }, + { id: id3, price: 30 }, + ], + }) + }) + + test('correctly handles two subsequent queries with a different cursor', async () => { + const ORDER_BY_NULLABLE = [{ price: 'asc' as const }, { id: 'asc' as const }] + + const result1 = await prisma.item.findMany({ + orderBy: ORDER_BY_NULLABLE, + cursor: { id: id1 }, + skip: 1, + take: 1, + }) + expect(result1).toEqual([{ id: id2, price: 20 }]) + + const result2 = await prisma.item.findMany({ + orderBy: ORDER_BY_NULLABLE, + cursor: { id: id2 }, + skip: 1, + take: 1, + }) + expect(result2).toEqual([{ id: id3, price: 30 }]) + }) +}) diff --git a/packages/client/tests/functional/issues/29267-uint8array-in-json/_matrix.ts b/packages/client/tests/functional/issues/29267-uint8array-in-json/_matrix.ts new file mode 100644 index 000000000000..169663a76317 --- /dev/null +++ b/packages/client/tests/functional/issues/29267-uint8array-in-json/_matrix.ts @@ -0,0 +1,4 @@ +import { defineMatrix } from '../../_utils/defineMatrix' +import { allProviders, Providers } from '../../_utils/providers' + +export default defineMatrix(() => [allProviders.filter(({ provider }) => provider !== Providers.SQLSERVER)]) diff --git a/packages/client/tests/functional/issues/29267-uint8array-in-json/prisma/_schema.ts b/packages/client/tests/functional/issues/29267-uint8array-in-json/prisma/_schema.ts new file mode 100644 index 000000000000..04ec2a7bf437 --- /dev/null +++ b/packages/client/tests/functional/issues/29267-uint8array-in-json/prisma/_schema.ts @@ -0,0 +1,19 @@ +import { idForProvider } from '../../../_utils/idForProvider' +import testMatrix from '../_matrix' + +export default testMatrix.setupSchema(({ provider }) => { + return /* Prisma */ ` + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "${provider}" + } + + model TestRecord { + id ${idForProvider(provider)} + data Json + } + ` +}) diff --git a/packages/client/tests/functional/issues/29267-uint8array-in-json/tests.ts b/packages/client/tests/functional/issues/29267-uint8array-in-json/tests.ts new file mode 100644 index 000000000000..d4665451d2fb --- /dev/null +++ b/packages/client/tests/functional/issues/29267-uint8array-in-json/tests.ts @@ -0,0 +1,68 @@ +import testMatrix from './_matrix' +// @ts-ignore +import type { PrismaClient } from './generated/prisma/client' + +declare let prisma: PrismaClient + +testMatrix.setupTestSuite( + () => { + test('serializes Uint8Array nested in object as base64', async () => { + const uint8 = new Uint8Array([72, 101, 108, 108, 111]) + + const record = await prisma.testRecord.create({ + data: { + data: { payload: uint8, label: 'test' } as any, + }, + }) + + expect(record.data).toEqual({ + payload: 'SGVsbG8=', + label: 'test', + }) + }) + + test('serializes Uint8Array nested in array as base64', async () => { + const uint8 = new Uint8Array([72, 101, 108, 108, 111]) + + const record = await prisma.testRecord.create({ + data: { + data: [uint8, 'hello'] as any, + }, + }) + + expect(record.data).toEqual(['SGVsbG8=', 'hello']) + }) + + test('serializes Uint8Array directly as base64', async () => { + const uint8 = new Uint8Array([72, 101, 108, 108, 111]) + + const record = await prisma.testRecord.create({ + data: { + data: uint8 as any, + }, + }) + + expect(record.data).toBe('SGVsbG8=') + }) + + test('serializes deeply nested Uint8Array as base64', async () => { + const uint8 = new Uint8Array([1, 2, 3]) + + const record = await prisma.testRecord.create({ + data: { + data: { outer: { inner: uint8 } } as any, + }, + }) + + expect(record.data).toEqual({ + outer: { inner: 'AQID' }, + }) + }) + }, + { + optOut: { + from: ['sqlserver'], + reason: 'SQL Server does not support JSON fields', + }, + }, +) diff --git a/packages/engines/package.json b/packages/engines/package.json index fdf1ff58dab6..11ebc17867e8 100644 --- a/packages/engines/package.json +++ b/packages/engines/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "@prisma/debug": "workspace:*", - "@prisma/engines-version": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/fetch-engine": "workspace:*", "@prisma/get-platform": "workspace:*" }, diff --git a/packages/fetch-engine/package.json b/packages/fetch-engine/package.json index 95ba352e7ec8..3d85667e9756 100644 --- a/packages/fetch-engine/package.json +++ b/packages/fetch-engine/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@prisma/debug": "workspace:*", - "@prisma/engines-version": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/get-platform": "workspace:*" }, "scripts": { diff --git a/packages/internals/package.json b/packages/internals/package.json index 15bd53fe12dc..6140e802d16d 100644 --- a/packages/internals/package.json +++ b/packages/internals/package.json @@ -79,8 +79,8 @@ "@prisma/generator": "workspace:*", "@prisma/generator-helper": "workspace:*", "@prisma/get-platform": "workspace:*", - "@prisma/prisma-schema-wasm": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", - "@prisma/schema-engine-wasm": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/prisma-schema-wasm": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", + "@prisma/schema-engine-wasm": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/schema-files-loader": "workspace:*", "arg": "5.0.2", "prompts": "2.4.2" diff --git a/packages/migrate/package.json b/packages/migrate/package.json index b4b7584587bd..6bb1d153752e 100644 --- a/packages/migrate/package.json +++ b/packages/migrate/package.json @@ -54,7 +54,7 @@ "@prisma/config": "workspace:*", "@prisma/debug": "workspace:*", "@prisma/driver-adapter-utils": "workspace:*", - "@prisma/engines-version": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/engines-version": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "@prisma/generator": "workspace:*", "@prisma/get-platform": "workspace:*", "@prisma/internals": "workspace:*", diff --git a/packages/schema-files-loader/package.json b/packages/schema-files-loader/package.json index 99732ab2452e..3ab27ce258a2 100644 --- a/packages/schema-files-loader/package.json +++ b/packages/schema-files-loader/package.json @@ -22,7 +22,7 @@ ], "sideEffects": false, "dependencies": { - "@prisma/prisma-schema-wasm": "7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21", + "@prisma/prisma-schema-wasm": "7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919", "fs-extra": "11.3.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1455db5521d1..fe4f12147dad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -730,8 +730,8 @@ importers: specifier: workspace:* version: link:../engines '@prisma/engines-version': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/fetch-engine': specifier: workspace:* version: link:../fetch-engine @@ -766,8 +766,8 @@ importers: specifier: workspace:* version: link:../param-graph-builder '@prisma/query-compiler-wasm': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/query-plan-executor': specifier: workspace:* version: link:../query-plan-executor @@ -1010,8 +1010,8 @@ importers: specifier: workspace:* version: link:../dmmf '@prisma/engines-version': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/fetch-engine': specifier: workspace:* version: link:../fetch-engine @@ -1083,8 +1083,8 @@ importers: specifier: workspace:* version: link:../dmmf '@prisma/engines-version': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/fetch-engine': specifier: workspace:* version: link:../fetch-engine @@ -1199,8 +1199,8 @@ importers: specifier: workspace:* version: link:../debug '@prisma/engines-version': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/fetch-engine': specifier: workspace:* version: link:../fetch-engine @@ -1233,8 +1233,8 @@ importers: specifier: workspace:* version: link:../debug '@prisma/engines-version': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/get-platform': specifier: workspace:* version: link:../get-platform @@ -1516,11 +1516,11 @@ importers: specifier: workspace:* version: link:../get-platform '@prisma/prisma-schema-wasm': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/schema-engine-wasm': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/schema-files-loader': specifier: workspace:* version: link:../schema-files-loader @@ -1675,8 +1675,8 @@ importers: specifier: workspace:* version: link:../driver-adapter-utils '@prisma/engines-version': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/generator': specifier: workspace:* version: link:../generator @@ -1837,8 +1837,8 @@ importers: packages/schema-files-loader: dependencies: '@prisma/prisma-schema-wasm': - specifier: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 - version: 7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21 + specifier: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + version: 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 fs-extra: specifier: 11.3.0 version: 11.3.0 @@ -1883,7 +1883,7 @@ importers: dependencies: '@ark/attest': specifier: 0.48.2 - version: 0.48.2(typescript@5.4.5) + version: 0.48.2(typescript@5.8.2) '@prisma/client': specifier: workspace:* version: link:../client @@ -3596,8 +3596,8 @@ packages: '@prisma/dev@0.20.0': resolution: {integrity: sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==} - '@prisma/engines-version@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': - resolution: {integrity: sha512-eWgBDH+mS98J4VKqYjC6PHWXRP0RbA2ZTZ8Nagj2JT+/wQGYHyXq4q2kkBWU2fXnmBLnyQBsaKbugYOzHHyomQ==} + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + resolution: {integrity: sha512-5FIKY3KoYQlBuZC2yc16EXfVRQ8HY+fLqgxkYfWCtKhRb3ajCRzP/rPeoSx11+NueJDANdh4hjY36mdmrTcGSg==} '@prisma/get-platform@7.2.0': resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} @@ -3608,17 +3608,17 @@ packages: '@prisma/ppg@1.0.1': resolution: {integrity: sha512-rRRXuPPerXwNWjSA3OE0e/bqXSTfsE82EsMvoiluc0fN0DizQSe3937/Tnl5+DPbxY5rdAOlYjWXG0A2wwTbKA==} - '@prisma/prisma-schema-wasm@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': - resolution: {integrity: sha512-nF5n4gz4bX1hKQMlt/BZZSBjjuhzTlBkaru3dm86H1oGuRJ4ZY88pUKtvoezV/VLPsoF/MSYgMcIWT+HsKz0Sw==} + '@prisma/prisma-schema-wasm@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + resolution: {integrity: sha512-DV5lGaN01UD4t9kilHXekw7oruBvigjkvYspaCq+D961zAYJrXuSDVXe4wM0EDVml0ujoa3apNf/QRxv0ecVuA==} - '@prisma/query-compiler-wasm@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': - resolution: {integrity: sha512-bbQW/gOLPkunQGOeAV9+PoN8KJY3QShoTfx+MBF4ZETnlO5zmY4zFq497Rzam0qMR82kb39BbpxVaO0dEcVwBQ==} + '@prisma/query-compiler-wasm@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + resolution: {integrity: sha512-kjrNCKHwoEWp+5TNDPJPYtkjnA23QQaqiOnxb04Tq31fDd1d17ilMnq9nDjxzx7//WgGXONbXQBHvnLG5+GZSw==} '@prisma/query-plan-executor@7.2.0': resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} - '@prisma/schema-engine-wasm@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': - resolution: {integrity: sha512-KMJHUMIhqxgfzBeOYCKaeiUMZ2kM+JYGVt3idqM60PUhuE6agNQdYWkZKURwU8G64MUy26IEcFKWXj8kTz01Ag==} + '@prisma/schema-engine-wasm@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + resolution: {integrity: sha512-v7E/pxOvzJyILTK5ZvBs7fLjcoFPG2t6BdnAsfKIZtQZlQz7TyTC3kkZvcigtnV/6/ktVOsd0RQFIk0rD4e5lg==} '@prisma/studio-core@0.13.1': resolution: {integrity: sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg==} @@ -8436,16 +8436,16 @@ snapshots: '@antfu/ni@0.21.12': {} - '@ark/attest@0.48.2(typescript@5.4.5)': + '@ark/attest@0.48.2(typescript@5.8.2)': dependencies: '@ark/fs': 0.46.0 '@ark/util': 0.46.0 '@prettier/sync': 0.5.5(prettier@3.5.3) '@typescript/analyze-trace': 0.10.1 - '@typescript/vfs': 1.6.1(typescript@5.4.5) + '@typescript/vfs': 1.6.1(typescript@5.8.2) arktype: 2.1.20 prettier: 3.5.3 - typescript: 5.4.5 + typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -10088,7 +10088,7 @@ snapshots: transitivePeerDependencies: - typescript - '@prisma/engines-version@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': {} + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} '@prisma/get-platform@7.2.0': dependencies: @@ -10105,13 +10105,13 @@ snapshots: - bufferutil - utf-8-validate - '@prisma/prisma-schema-wasm@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': {} + '@prisma/prisma-schema-wasm@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} - '@prisma/query-compiler-wasm@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': {} + '@prisma/query-compiler-wasm@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} '@prisma/query-plan-executor@7.2.0': {} - '@prisma/schema-engine-wasm@7.5.0-9.c6be8e68bf8e4a36534064f9323a343f2fcafe21': {} + '@prisma/schema-engine-wasm@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} '@prisma/studio-core@0.13.1': {} @@ -10700,10 +10700,10 @@ snapshots: treeify: 1.1.0 yargs: 16.2.0 - '@typescript/vfs@1.6.1(typescript@5.4.5)': + '@typescript/vfs@1.6.1(typescript@5.8.2)': dependencies: debug: 4.4.1 - typescript: 5.4.5 + typescript: 5.8.2 transitivePeerDependencies: - supports-color