Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,12 @@
"pnpm": {
"overrides": {
"form-data": ">=4.0.4",
"hono": ">=4.12.2",
"hono": ">=4.12.4",
"@hono/node-server": ">=1.19.10",
"jws": ">=4.0.1",
"tar-fs": ">=2.1.4",
"lodash": ">=4.17.23"
"lodash": ">=4.17.23",
"@tootallnate/once": ">=3.0.1"
}
}
}
12 changes: 11 additions & 1 deletion packages/client-engine-runtime/src/interpreter/render-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,17 @@ export function evaluateArg(arg: unknown, scope: ScopeBindings, generators: Gene
if (found === undefined) {
throw new Error(`Missing value for query variable ${arg.prisma__value.name}`)
}
arg = found
if (arg.prisma__value.type === 'DateTime' && typeof found === 'string') {
// Convert input datetime strings to Date objects. This is done to prevent issues that
// arise when query input values end up being directly compared to values retrieved from
// the database. One example of this is a query containing a DateTime cursor value being
// used against a DATE MySQL column. The pagination logic doesn't have parameter type
// information, therefore it ends up comparing the two datetimes as strings and would yield
// false even if the two date datetime strings represent the same Date.
arg = new Date(found)
} else {
arg = found
}
} else if (isPrismaValueGenerator(arg)) {
const { name, args } = arg.prisma__value
const generator = generators[name]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { defineMatrix } from '../../_utils/defineMatrix'
import { Providers, sqlProviders } from '../../_utils/providers'

export default defineMatrix(() => [sqlProviders.filter(({ provider }) => provider !== Providers.SQLITE)])
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import testMatrix from '../_matrix'

export default testMatrix.setupSchema(({ provider }) => {
return /* Prisma */ `
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "${provider}"
}

model Event {
appId Int
createdAt DateTime @db.Date
value Int

@@id([appId, createdAt])
}
`
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import testMatrix from './_matrix'
// @ts-ignore
import type { Event, PrismaClient } from './generated/prisma/client'

declare let prisma: PrismaClient

testMatrix.setupTestSuite(
() => {
test('retrieves a cursor against a DATE column', async () => {
const rows: Event[] = []
for (let day = 1; day <= 10; day++) {
rows.push({
appId: 1,
createdAt: new Date(`2025-01-${String(day).padStart(2, '0')}Z`),
value: day * 100,
})
}
await prisma.event.createMany({ data: rows })

const firstThree = await prisma.event.findMany({
where: { appId: 1 },
orderBy: { createdAt: 'asc' },
take: 3,
})
const cursorRow = firstThree[2] // 2025-01-03

const withCursor = await prisma.event.findMany({
where: { appId: 1 },
cursor: {
appId_createdAt: {
appId: cursorRow.appId,
createdAt: cursorRow.createdAt,
},
},
orderBy: { createdAt: 'asc' },
take: 3,
skip: 1,
})

expect(withCursor).toEqual([
{
appId: 1,
createdAt: new Date('2025-01-04T00:00:00.000Z'),
value: 400,
},
{
appId: 1,
createdAt: new Date('2025-01-05T00:00:00.000Z'),
value: 500,
},
{
appId: 1,
createdAt: new Date('2025-01-06T00:00:00.000Z'),
value: 600,
},
])
})
},
{
optOut: {
from: ['mongodb', 'sqlite'],
reason: 'MongoDB and SQLite do not support DATE columns',
},
},
)
79 changes: 32 additions & 47 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading