drizzle-team / drizzle-orm

Headless TypeScript ORM with a head. Runs on Node, Bun and Deno. Lives on the Edge and yes, it's a JavaScript ORM too 😅
https://orm.drizzle.team
Apache License 2.0
21.64k stars 491 forks source link

[BUG]: node-postgres date parser modified globally #2067

Open laszlo-zaptic opened 3 months ago

laszlo-zaptic commented 3 months ago

What version of drizzle-orm are you using?

0.30.0

What version of drizzle-kit are you using?

0.20.14

Describe the Bug

in drizzle-orm/src/node-postgres/driver.ts the default date parsers are modified. we're trying to gradually adopt drizzle along another orm which started breaking tests because it was relying on default pg date parsing. why was this needed? can there be an opt out for this in the drizzle() function?

    initMappers() {
        types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val);
        types.setTypeParser(types.builtins.TIMESTAMP, (val) => val);
        types.setTypeParser(types.builtins.DATE, (val) => val);
        types.setTypeParser(types.builtins.INTERVAL, (val) => val);
    }

Expected behavior

pg type parsers are not modified when calling drizzle()

Environment & setup

No response

AndriiSherman commented 3 months ago

Hey! We were discussing this part and planning to improve it by providing an option to create each driver instance ourselves rather than by the user, while still allowing the possibility to provide an existing driver.

https://orm.drizzle.team/docs/column-types/pg#timestamp

image

The reason we're doing this is to enable the possibility of having a mode string and mode date for dates/timestamps in Drizzle. We don't need a driver to handle these mappings; instead, we need to retrieve a raw value from the database and then either proxy it to the user (in string mode) or create a new Date (in date mode). This approach may not be ideal and shouldn't modify an instance for you, but it's necessary for Drizzle to work as expected.

Current Functionality: We are still changing(and will change) the behavior of timestamps, dates, and intervals to align with Drizzle modes, ideally making users aware of these changes when using the client outside of Drizzle. Apologies for not mentioning this earlier.

Improvements Currently In progress: The ability to specify the driver as a string and let Drizzle create a specific client instance for you, allowing for usage if needed and not modifying your client instance, that is owned by you and not Drizzle

Workarounds for You: You can try creating another pg client and providing it to Drizzle. And leave your previous client for other parts of application, so it won't be modified by Drizzle

carecki commented 5 hours ago

I was struggling with exactly same issue. And advice to "creating another pg client and providing it to Drizzle" didn't work, as Drizzle is just taking and modifying global pg types on its own.

The workaround I've used is to temporarily override the setTypeParser function of the global pg types and record all the custom parsers Drizzle want to register, and then apply them just to the connection pool instead of globally:

import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool, PoolConfig, types } from 'pg';
import TypeOverrides from 'pg/lib/type-overrides';

function prepareDrizzle(poolConfig: PoolConfig) {
  const typeOverrides = new TypeOverrides();

  const setTypeParserOrig = types.setTypeParser;
  types.setTypeParser = (...args: unknown[]) => {
    typeOverrides.setTypeParser(...args);
  };

  try {
    poolConfig = {
      ...poolConfig,
      types: typeOverrides,
    };

    const pool = new Pool(poolConfig);
    const db = drizzle(pool);
    return { pool, db };
  } finally {
    types.setTypeParser = setTypeParserOrig;
  }
}