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
24.29k stars 625 forks source link

[BUG]: Custom type is set to ZodAny when creating zod schema #762

Closed markkkkas closed 9 months ago

markkkkas commented 1 year ago

What version of drizzle-orm are you using?

^0.26.1

What version of drizzle-kit are you using?

^0.18.1

Describe the Bug

I need to use custom type, to support nanoid, its just a simple postgres varchar data type with fixed length.

import { customType } from 'drizzle-orm/pg-core';

export const nanoid = customType<{ data: string; notNull: true }>({
  dataType: () => 'varchar(12)',
});

Lets assume this is my database table definition

import { pgTable, varchar } from 'drizzle-orm/pg-core';

import { nanoid } from './types/nanoid';

export const positions = pgTable('positions', {
  id: nanoid('id').primaryKey(),
  title: varchar('title').notNull(),
});

When I'm creating a zod schema from my positions table I can see, that id was set to ZodAny.

// const CreatePositionSchema: ZodObject<{
//   id: ZodAny;
//   title: ZodString;
// }, UnknownKeysParam, ZodTypeAny, {
//   title: string;
//   id?: any;
// }, {
//   title: string;
//   id?: any;
// }>
const CreatePositionSchema = createInsertSchema(positions);

I believe i can workaround this with refining the id field, but i don't feel that i need to explicitly set the type again for schema.

const CreatePositionSchema = createInsertSchema(positions, {
  id: (schema) => schema.id.pipe(z.string()),
});

Expected behavior

id is parsed as string to zod schema.

Environment & setup

No response

markkkkas commented 1 year ago

I've also tried to dig into createInsertSchema code and noticed that if the column is instance of *CustomColumn, then it's instantly set to z.any(). Can i rely on some properties from those classes to build different zod type or it requires some bigger refactoring?

dankochetov commented 1 year ago

check this out - https://discord.com/channels/1043890932593987624/1114275121851535431

markkkkas commented 1 year ago

@dankochetov Thanks for reply. Again this is not very convenient way to always specify the zod type. From DX side - i believe this should be done by create*Schema helper.

hanayashiki commented 1 year ago

this actually forbids me from using drizzle

emmbm commented 1 year ago

Could customType's param maybe leverage an optional schema or validation property?

AndriiSherman commented 9 months ago

check this out - https://discord.com/channels/1043890932593987624/1114275121851535431

This comment solved this issue. Feel free to create another ticket with feature request on how to improve the DX for this particular part

danielsharvey commented 3 months ago

@AndriiSherman I have implemented customNumberType<>(), customStringType<>() and customDateType<>() which mirror customType<>() but utilise additional ColumnDataTypes.

Specifically, I have added 'customNumber' | 'customString' | 'customDate' to ColumnDataType: https://github.com/drizzle-team/drizzle-orm/blob/15ff6b49bff580b8f07077a044be4cb52ec17183/drizzle-orm/src/column-builder.ts#L9-L18

These ColumnDataTypes are then picked up in drizzle-zod to build the correct types in the Zod schema. This allows custom types to push through to Zod schemas without the case-by-case refinement in your Discord suggestion.

Let me know what you think of the approach. I have done a limited implementation for MySQL to suit immediate needs but from what I can see it would extend to the other drivers relatively easily. Happy to work on a PR and/or share my current patches.