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

[Feature Request] Pass a function to `default()`

Open ari-becker opened this issue 2 years ago • 6 comments

What version of drizzle-orm are you using?

0.22.0

Describe the Feature Request

I'm trying to port something from Prisma that uses a cuid type for the identifier column. Because the underlying database doesn't support cuid natively, Prisma implements it at the ORM level.

Of course it's not reasonable to ask drizzle to implement every possible function under the sun, but it would be nice if the default column type could take a user-defined function (e.g. from @paralleldrive/cuid2) to make this simple, something like:

import { pgTable, text } from 'drizzle-orm/pg-core'
import { createId } from '@paralleldrive/cuid2'

export const users = pgTable('users', {
  id: text('id').default(() => createId()).primaryKey(),
  name: text('name'),
})

Otherwise, the cuid isn't part of the schema, and instead needs to be added to every insert query, above the ORM layer.

ari-becker avatar Mar 21 '23 07:03 ari-becker

It won't work like this, because the .default() function is only used in drizzle-kit and not in ORM's runtime. What you can do, however, is to define custom type: https://github.com/drizzle-team/drizzle-orm/blob/main/docs/custom-types.lite.md

dankochetov avatar Mar 21 '23 08:03 dankochetov

@dankochetov Hmmm, I'm looking at the custom types and I have the following concerns / questions:

  1. The config field in the type parameter for customType is only available as a parameter for dataType, not for toDriver. What I would like to do is have config: { idGenerator?: () => string }, which would allow passing an override with a fixed seed, which is useful in test environments so that tests have determinism. However, this config is not available in toDriver, so I would need to change the entire customType for test environments, and therefore the entire schema, which is really not ideal....?

  2. The toDriver function is defined as (value: T['data']) => T['driverData'] not (value?: T['data']) => T['driverData']. Of course, if an identifier has already been established, then I want to re-use it. I only want to call createId() to generate a new ID if the row is being inserted for the first time, and the user has not provided a value. It doesn't seem like this matches toDriver's type signature?

ari-becker avatar Mar 22 '23 04:03 ari-becker

Thumbs up for this feature, I'd love to use my nanoid(prefix: string) util in this exact scenario.

export const user = pgTable('user', {
  id: text('id').default(() => nanoid("usr")).primaryKey(),
  ...
})

To create ids like usr_1suf98fdJA.

binajmen avatar Mar 28 '23 14:03 binajmen

I did manage getting it to work via a customType, but with a slight inconvenience:

const cuid = customType<{ data: string | undefined; notNull: true }>({
  dataType() {
    return 'varchar(191)' // match prisma
  },
  toDriver(value?: string) {
    return value ?? createId()
  },
})

Then use like id: cuid('id').primaryKey(), but the when you go to insert things it seems the query builder needs undefined id explicitly passed to the values in order to actually call the toDriver fn otherwise it won't if the id key is missing:

db.insert(users).values({
  id: undefined,
  username: input.username,
})

garlandcrow avatar Mar 30 '23 15:03 garlandcrow

@garlandcrow Did you make any headway on this?\

nmajor avatar Apr 28 '23 14:04 nmajor

The lack of this feature is the only thing stopping us from migrating from Prisma.

irshadahmad21 avatar May 07 '23 05:05 irshadahmad21

I'm not what has changed since but gave @garlandcrow's suggestion a go and its no longer working – this feature would be super useful!

matthewspear avatar Jul 08 '23 19:07 matthewspear

Any update on this @dankochetov?

Stefandasbach avatar Jul 17 '23 00:07 Stefandasbach

I'd also love some way to define some code that calculates a default for customTypes.

nmajor avatar Jul 28 '23 09:07 nmajor

FWIW, after days of research, the best lexicographical id (MySQL needs a lexicographical ids) I found was a re-implementation of Firebase's PushID. But yeah, having the ability just to give any random function for id generation is even better!

Edit: Here the link to the re-implementation of PushID, it's a bit more than 30 LoC, https://gist.github.com/mikelehen/3596a30bd69384624c11

205g0 avatar Aug 04 '23 12:08 205g0

This would be a great addition!

tuffstuff9 avatar Aug 13 '23 15:08 tuffstuff9