If Date Object input is specified as DateTime type gte, lte, lt,gt operator in include's where condition doesn't work
tkow opened this issue · 8 comments
I'm sorry if it's already known, but I can't input Date JS object as DateTime type fields at where operators using jestPrisma.client
in my environment though original prisma client passes tests.
where: {
created_at: {
gte: {},
~~~
lt: {}
~~~~
}
},
The photo shows running first test with prisma-jest, and second with original client.
Version Spec
## node
node: v16.15.0
## DB
Postgresql
## packages
"@quramy/jest-prisma": "^1.3.1",
"jest": "^29.3.1",
"ts-jest": "^29.0.3",
"ts-loader": "^8.0.4",
## prisma
prisma : 4.7.1
@prisma/client : 4.7.1
Current platform : darwin
Query Engine (Node-API) : libquery-engine 272861e07ab64f234d3ffc4094e32bd61775599c (at node_modules/@prisma/engines/libquery_engine-darwin.dylib.node)
Migration Engine : migration-engine-cli 272861e07ab64f234d3ffc4094e32bd61775599c (at node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine : introspection-core 272861e07ab64f234d3ffc4094e32bd61775599c (at node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary : prisma-fmt 272861e07ab64f234d3ffc4094e32bd61775599c (at node_modules/@prisma/engines/prisma-fmt-darwin)
Format Wasm : @prisma/prisma-fmt-wasm 4.7.1-1.272861e07ab64f234d3ffc4094e32bd61775599c
Default Engines Hash : 272861e07ab64f234d3ffc4094e32bd61775599c
Studio : 0.477.0
(Addition)
It doesn't reproduce it only just to add I try to find how to reproduce it asap.created_at Datetime @default(now())
to example-prj' user model.
I could reproduce it when condition has include: { where: { [$dateFiledName]: { lt: new Date } } }
, so on. Both sqlite and postgresql are reproduced so it may have the problem in js layer .
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
previewFeatures = ["clientExtensions"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id String @id
name String
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id String @id
title String
author User @relation(fields: [authorId], references: [id])
authorId String
createdAt DateTime @default(now())
}
/**
*
* @jest-environment-options { "verboseQuery": true }
*
*/
import { PrismaClient } from "@prisma/client";
describe("Should include date type work around", () => {
/* NG */
const prisma = jestPrisma.client;
/* NG */
// const prisma = jestPrisma.originalClient;
/* OK */
// const prisma = new PrismaClient();
beforeEach(async () => {
await prisma.post.create({
data: {
id: "post0",
title: "post",
author: {
create: {
id: "user0",
name: "quramy",
},
},
},
});
});
test("include api should work using date type condition", async () => {
const user = await prisma.user.findFirst({
where: {
createdAt: {
lt: new Date(),
gte: new Date(new Date().getTime() - 1000 * 60 * 60 * 24),
},
},
include: {
posts: {
where: {
createdAt: {
lt: new Date(),
gte: new Date(new Date().getTime() - 1000 * 60 * 60 * 24),
},
},
},
},
});
expect(
(await prisma.post.findFirst({
where: {
author: {
createdAt: {
lt: new Date(),
gte: new Date(new Date().getTime() - 1000 * 60 * 60 * 24),
},
},
},
include: {
author: {
include: {
posts: {
where: {
createdAt: {
lt: new Date(),
gte: new Date(new Date().getTime() - 1000 * 60 * 60 * 24),
},
},
},
},
},
},
}))!.author,
).toStrictEqual(user);
});
});
I confirmed that internal jest-prisma-core originalClient and jest-prisma jestPrisma.originalClient works by force creating and fetch data with overwriting in node_modules folder. In addition, I noticed that validate method in prisma calls with same data, but slightly different though I don't know why. It may be clues.
Original client
Proxy client(both jestPrisma.client and jestPrisma.originalClient)
I also found invalidChildren' value exists in node_modules/@prisma/client/runtime/index.js validate method with jest-prisma proxy though manually PrismaClient in jest test case doesn't.
jest-prisma does not touch Date class. I think this is not jest-prisma issue but Jest issue.
@Quramy
I think so, too. I could read all your code in this repository and I know nothing fancy process PrismaClient. Your work is very awesome and I want to use this in our product. So, I keep trying to find the reason. I found objectToArgs
in prisma client method args(initialObj) are different so I try to understand where this difference comes from. Proxy client's initialObj of include-where parameter becomes empty object.
I also found first inputed values are same in every cases.
It may mean prisma have problem it parse nested date object in different ways though it's not related to this issue.
Sorry, this is my fault. I call toISOString() in my code.
Prisma using in Jest directely
It may be related to jestjs/jest#7246.
I found inserting this.global.Date = Date
to setup function in environment entrypoint fix this issue. But, jest may extend it for inspecting Date with matcher or each environment, so I don't know whether this fix is appropriate.
async setup() {
const jestPrisma = await this.delegate.preSetup();
await super.setup();
this.global.jestPrisma = jestPrisma;
this.global.Date = Date
}
@Quramy
I create the PR and global.Date is not overwritten in it, because I don't know how large the influence is.
As I thought it, jestPrisma exports Date constructor from same environment is most safety way.
In addition the Date class doesn't have problem as long as using only it as prisma api argument, because it run only environment set up scope.
Please check it if you feel like it.
@tkow Thanks for your investigating and sending the PR.
this.global.Date = Date
I think this problem is caused by jestjs/jest#2549 ( It's famous jest issue, and tooooo long to read 😭 )
And 3rd party jest environments to tackle the issue are published:
e.g. https://www.npmjs.com/package/jest-environment-node-single-context
For now, I don't know whether jest-prisma should extend the "workaround" environment or not.
But users can weave jest-prisma function to their own environment like this:
import type { Circus } from "@jest/types";
import type { JestEnvironmentConfig, EnvironmentContext } from "@jest/environment";
import { PrismaEnvironmentDelegate } from "@quramy/jest-prisma-core";
import Environment from "jest-environment-node-single-context";
export default class PrismaEnvironment extends Environment {
private readonly delegate: PrismaEnvironmentDelegate;
constructor(config: JestEnvironmentConfig, context: EnvironmentContext) {
super(config, context);
this.delegate = new PrismaEnvironmentDelegate(config, context);
}
async setup() {
const jestPrisma = await this.delegate.preSetup();
await super.setup();
this.global.jestPrisma = jestPrisma;
}
handleTestEvent(event: Circus.Event) {
return this.delegate.handleTestEvent(event);
}
async teardown() {
await Promise.all([super.teardown(), this.delegate.teardown()]);
}
}
- Would you try the above example and confirm to solve your date
le
/lte
/ge
/gte
problem?
@Quramy
Thank you for checking and telling me why it happens.
I tested your patch in example application overwrite jest-prisma environment, and it works. (For I did asap, I force ts file to be transpiled to js and the compiled file set to jest environement. So I'l remove the branch near future. (https://github.com/tkow/jest-prisma/pull/1/files) (pass test)
So, what's the way to resolve this you prefer? At least, I think in anyway this library seem to need some patches for testing all prisma api.
As I thought it, jest-prisma includes jest-environment-node-single-context relatively better than the others in the point of
whether we can test intuitively (no attention and extra config). If you are busy, may I reimplement this referring to the patch?
Thanks for reply and testing.
So, what's the way to resolve this you prefer? At least, I think in anyway this library seem to need some patches for testing all prisma api
Hummm, I'm thinking about this. Please give me some time before I answer the question.
Of course. I bypass this pitfall by extending environment now as you told me. Thank you.