drizzle-team/drizzle-orm

[BUG]: $onUpdate/$onUpdateFn doesn't work with sql``

Closed this issue · 3 comments

What version of drizzle-orm are you using?

0.30.9

What version of drizzle-kit are you using?

0.20.17

Describe the Bug

$onUpdate/$onUpdateFn with sql`now()` throws an TypeError: value.toISOString is not a function error when updating the model.

export const users = pgTable('users', {
  id: uuid('id').primaryKey().notNull(),
  createdAt: timestamp('created_at').notNull().defaultNow(),
  updatedAt: timestamp('updated_at')
    .notNull()
    .$onUpdateFn(() => sql`now()`),
});

// throws 
const [result] = await db
  .update(users)
  .set({ ...whatever })
  .where(eq(users.id, user.id))
  .returning();

The reason for using now() instead of new Date() is that I want the full timestamp with the same precision as .defaultNow()

Expected behavior

Model is updated with the now() value

Environment & setup

N/A

On first drizzle-kit generate

image

On 2nd drizzle-kit generate

I add .default() to the updatedAt, but it says no schema changes

image

Is this the expected behaviour? Is it currently not able to detect the function level changes?
If so, what's the recommended thing to do? delete the sql and regenerate or what?

Plus, in case of .$onUpdate(), even if I delete the old migration sql and generate a new one it doesn't detect it.

image

@alexandernanberg $onUpdateFn, $default, and basically anything with a $ sign in the Drizzle schema are runtime values used exclusively at runtime. This means they won't be added to the database schema and can't be used in the migration process. As long as $onUpdateFn is a JavaScript runtime-generated value, you can't use sql``.

I'll close this issue as long as you can't use sql templates inside runtime functions.

@Pranav-Bobde If .default is not detected in Drizzle Kit, it's a bug. However, I would suggest creating a specific bug issue for this case

@AndriiSherman Interesting, I expected it to work since you can do

await db.insert(users).values({ /*...*/ updatedAt: sql`now()` })

Isn't that also runtime? Or maybe I'm missing something