drizzle-orm icon indicating copy to clipboard operation
drizzle-orm copied to clipboard

[BUG]: timestamp mode 'date' returns value.toISOString is not a function for parameterized inserts

Open Enalmada opened this issue 2 years ago • 21 comments

What version of drizzle-orm are you using?

0.28.5

What version of drizzle-kit are you using?

0.19.13

Describe the Bug

Trying to do a sql.placeholder of a timestamp mode 'date' returns value.toISOString is not a function at compile time. When I first load my page presumably it is doing the prepared statement and throwing error. Mode 'string' seems to work.

export const TaskTable = pgTable('task', {
  .... 
  title: varchar('name', { length: 256 }).notNull(),
  dueDate: timestamp('due_date', { mode: 'date' } )
});

const preparedInsert = db
  .insert(TaskTable)
  .values({
    title: sql.placeholder('title'),  // works             
    dueDate: sql.placeholder('dueDate'),   // crashes
  })
  .returning()
  .prepare('Task.create');

Exception

- error Error [TypeError]: value.toISOString is not a function
    at PgTimestamp.mapToDriverValue (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/alias-a0c6a0a1.mjs:1363:68)
    at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/alias-a0c6a0a1.mjs:3785:81)
    at Array.map (<anonymous>)
    at SQL.buildQueryFromSourceParams (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/alias-a0c6a0a1.mjs:3724:36)
    at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/alias-a0c6a0a1.mjs:3754:29)
    at Array.map (<anonymous>)
    at SQL.buildQueryFromSourceParams (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/alias-a0c6a0a1.mjs:3724:36)
    at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/alias-a0c6a0a1.mjs:3757:29)
    at Array.map (<anonymous>)

Note that this seems to work around it at parameterization:

    dueDate: sql`${sql.placeholder('dueDate')}`,

or in schema switch to string mode:

  dueDate: timestamp('due_date', { mode: 'string' } )

Expected behavior

I would expect placeholders of timestamp to not try to do toISOString.

Environment & setup

Windows. Postgres 15.

Enalmada avatar Aug 24 '23 23:08 Enalmada

This is likely related to the issue I created.

When we set mode to string, TypeScript shows the return type as string, however a date object is returned. I suspect the inverse might happen with string mode.

juanvilladev avatar Sep 07 '23 03:09 juanvilladev

any updates ?

alvinlal avatar Sep 08 '23 13:09 alvinlal

"drizzle-orm/mysql-core"'s datetime have same problem.

black7375 avatar Oct 26 '23 07:10 black7375

Same error on Version 0.29.0 👎

Releated: https://github.com/drizzle-team/drizzle-orm/issues/1407

approached avatar Nov 16 '23 19:11 approached

I tried to change from:

createdAt: timestamp("created_at", { mode: "string" })

To:

createdAt: text("created_at"),

But i get a still a Date object. Drizzle is so crazy

approached avatar Nov 16 '23 20:11 approached

had this error, but was a user land error, double check what you are passing

stunaz avatar Nov 16 '23 20:11 stunaz

still happening in 0.31.0 for me. having to use expiresAt: sql`${sql.placeholder("expiresAt")}`, because otherwise the toIsoString error happens.

but now excluded on onConflictDoUpdate doesn't work.

.onConflictDoUpdate({target: [...], set: { ... expiresAt: sql`'excluded.expiresAt'`},)

I have to use the single quotes because otherwise postgres throws this error:

[...] column excluded.expiresat does not exist [...]
 code: '42703',
  hint: 'Perhaps you meant to reference the column "excluded.expiresAt".',
  position: '210',
  file: 'parse_relation.c',
  line: '3720',
  routine: 'errorMissingColumn'

But now postgres tells me invalid input syntax for type timestamp with time zone: "excluded.expiresAt"

@AndriiSherman any ideas?

cw-1988 avatar Jul 06 '24 19:07 cw-1988

I had the same issue in "drizzle-orm": "^0.31.2".

In order to workaround it, I had to create a new instance of Date when I set the value. The property communication.creationDate was already type Date and it had the proper values, but without the new Date, I had the error "value.toISOString is not a function"

await db.insert(communicationsSchema).values({
      id: communication.id,
      content: communication.content,
      creationDate: new Date(communication.creationDate),
    });

alberto-corrales avatar Jul 10 '24 10:07 alberto-corrales

This issue is also present in queries and using the magic sql string operator is a workaround.

noahkurz avatar Jul 22 '24 14:07 noahkurz

Works when I change folder node_mules/drizzle-orm/pg-core/columns change files: timestamp.js, timestamp.cjs

from

mapToDriverValue = (value) => {
   return value.toISOString
 };

to

 mapToDriverValue = (value) => {
    return value
  };

works in update and onConflictDoUpdate

"drizzle-orm": "^0.32.0", "drizzle-kit": "^0.23.0",

Qorapp avatar Jul 23 '24 05:07 Qorapp

same

childrentime avatar Jul 29 '24 10:07 childrentime

Hello, drizzle-orm/pg-core seems to have the same issue

fredhii avatar Aug 06 '24 18:08 fredhii

Based on this issue I did this as a temporal solution https://github.com/drizzle-team/drizzle-orm/issues/1113#issuecomment-2244273171

script.js

const fs = require('fs');
const path = require('path');

const filesToModify = [
  'node_mules/drizzle-orm/pg-core/columns/timestamp.js',
  'node_mules/drizzle-orm/pg-core/columns/timestamp.cjs'
];

filesToModify.forEach((file) => {
  const filePath = path.join(__dirname, file);
  console.log(`Checking path: ${filePath}`);
  
  if (fs.existsSync(filePath)) {
    let fileContent = fs.readFileSync(filePath, 'utf8');
    fileContent = fileContent.replace(
      'return value.toISOString()',
      'return value'
    );
    fs.writeFileSync(filePath, fileContent, 'utf8');
    console.log(`Modified: ${file}`);
  } else {
    console.error(`File not found: ${filePath}`);
  }
});

I implement this in a postinstall script package.json

"postinstall": "node ./script.js",

Note: The versions that I mention are "drizzle-orm": "^0.32.1", "drizzle-kit": "^0.23.1",

fredhii avatar Aug 06 '24 19:08 fredhii

Super weird - i'm also seeing this error. All im trying to do is set the value of a timestamp date mode field to the value of an existing table column (which is also a timestamp date mode field) and yet when i try and pass table.timestampfield (which should be a date), its actually a string!

benjamindell avatar Aug 08 '24 16:08 benjamindell

Similar issue here, but not using prepared statements.

When I changed my table definition from

updatedAt: timestamp("updated_at", { mode: "string" })
    .defaultNow()
    .$onUpdate(() => sql`CURRENT_TIMESTAMP`),

to

updatedAt: timestamp("updated_at")
    .defaultNow()
    .$onUpdate(() => sql`CURRENT_TIMESTAMP`),

Notice that I removed the "mode: string" option.

Updating a row results in an Exception:

TypeError: value.toISOString is not a function
    at PgTimestamp.mapToDriverValue (webpack-internal:///(action-browser)/./node_modules/.pnpm/[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/pg-core/columns/timestamp.js:44:18)
    at eval (webpack-internal:///(action-browser)/./node_modules/.pnpm/[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/sql/sql.js:146:73)
    at Array.map (<anonymous>)
    at SQL.buildQueryFromSourceParams (webpack-internal:///(action-browser)/./node_modules/.pnpm/[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/drizzle-orm/sql/sql.js:99:32)

Based on how my column is defined, it was expecting a "date" value as the result of the .onUpdate function in the second case.

Solution

Choose the correct combination

updatedAt: timestamp("updated_at", { mode: "string" }).$onUpdate(() => sql`CURRENT_TIMESTAMP`),
updatedAt: timestamp("updated_at", { mode: "date" }).$onUpdate(() => new Date()),

docs: https://orm.drizzle.team/learn/latest-releases/drizzle-orm-v0305#onupdate-functionality-for-postgresql-mysql-and-sqlite

jvalverdepa avatar Aug 15 '24 02:08 jvalverdepa