Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If Date Object input is specified as DateTime type gte, lte, lt,gt operator in include's where condition doesn't work #56

Open
tkow opened this issue Dec 10, 2022 · 8 comments

Comments

@tkow
Copy link

tkow commented Dec 10, 2022

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.

スクリーンショット 2022-12-10 23 17 17

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 created_at Datetime @default(now()) to example-prj' user model. I try to find how to reproduce it asap.

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

スクリーンショット 2022-12-11 13 37 08

Proxy client(both jestPrisma.client and jestPrisma.originalClient)

スクリーンショット 2022-12-11 13 36 57

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.

@tkow tkow changed the title If Date Object input is specified as DateTime type gte, lte, lt,gt operator doesn't work If Date Object input is specified as DateTime type gte, lte, lt,gt operator in include's where condition doesn't work Dec 10, 2022
@Quramy
Copy link
Owner

Quramy commented Dec 11, 2022

jest-prisma does not touch Date class. I think this is not jest-prisma issue but Jest issue.

@tkow
Copy link
Author

tkow commented Dec 11, 2022

@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.

Proxy client
スクリーンショット 2022-12-11 15 08 17

Prisma using in Jest directely
スクリーンショット 2022-12-11 15 09 09

It may be related to jestjs/jest#7246.

@tkow
Copy link
Author

tkow commented Dec 11, 2022

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
    }

@tkow
Copy link
Author

tkow commented Dec 11, 2022

@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.

@Quramy
Copy link
Owner

Quramy commented Dec 12, 2022

@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()]);
  }
}
  1. Would you try the above example and confirm to solve your date le / lte / ge / gte problem?

@tkow
Copy link
Author

tkow commented Dec 12, 2022

@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?

@Quramy
Copy link
Owner

Quramy commented Dec 12, 2022

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.

@tkow
Copy link
Author

tkow commented Dec 12, 2022

Of course. I bypass this pitfall by extending environment now as you told me. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants