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

Missing Documentation: Types

Open rizen opened this issue 1 year ago • 7 comments

I spent the past 6 weeks trying out over a dozen different ORMs in the typescript world. They all have their pros and cons, but Drizzle seems to be one of the best when it comes to type safety. However, those strong types are wasted because there's basically no documentation on how to use them in a more powerful way.

You should declare what types you need for passing around different parts of Drizzle:

  • queries - if you want to pass a query to a function, what type is that?
  • drizzle - I think it might be this: import type { MySql2Database } from 'drizzle-orm/mysql2', but I'm only guessing
  • tables/models - no idea

You should also be able to declare what types you need for the major part of query building, so that queries can be built programatically. For example

  • where() - I think maybe import type { SQL } from 'drizzle-orm/sql'
  • orderBy() - SQL is part of it, but there's certainly more
  • groupBy()
  • limit() - probably just number
  • offset() - probably just number

rizen avatar Mar 16 '23 14:03 rizen

Yep, we plan to add the "Advanced" section to the docs where we'd explain all the user-facing types and how to use them. Thanks!

dankochetov avatar Mar 16 '23 14:03 dankochetov

I just came here because this tripped me up. I'm still pretty new to TypeScript and didn't know how to use the InferModel type when the data I'm sending to a wrapper function to add a row leaves out fields with defaults or that are autogenerated.

Say I have...

export const videos = sqliteTable(
  'videos',
  {
    id: integer('id').primaryKey({ autoIncrement: true }),
    videoId: text('videoId').notNull(),
    title: text('title').notNull(),
    createdAt: integer('createdAt', { mode: 'timestamp' }).defaultNow().notNull(),
  },
  (videos) => ({
    nameIdx: uniqueIndex('videoIdx').on(videos.videoId),
  })
);

export type Video = InferModel<typeof videos>;

...and the following wrapper:

export const addVideo = (data: Video) => db.insert(videos).values(data).run();

Then I couldn't figure out how to call the wrapper without as Video because otherwise it complains about the missing id and createdAt fields:

    addVideo({
      videoId: uuidv4(),
      title: lorem.generateWords(randomNumber(20, 6)),
    } as Video);

jschuur avatar Mar 16 '23 21:03 jschuur

@jschuur try to use

export type Video = InferModel<typeof videos, 'insert'>;

It will generated needed types for insert. By default InferModel generates types for select

AndriiSherman avatar Mar 16 '23 21:03 AndriiSherman

how to you infermodel with relations ?

MkrierPharmanity avatar Jun 02 '23 08:06 MkrierPharmanity

Since there is no advanced documentation yet, does anybody have a hint regarding the types of the parameters of the mentioned functions in the meantime?

  • where()
  • orderBy()
  • groupBy()

This would be great!

flauschi avatar Aug 08 '23 13:08 flauschi

how to you infermodel with relations ?

On the enhancement backlog - see #695.

danielsharvey avatar Aug 28 '23 04:08 danielsharvey

Since there is no advanced documentation yet, does anybody have a hint regarding the types of the parameters of the mentioned functions in the meantime?

  • where()
  • orderBy()
  • groupBy()

This would be great!

Here is what I used for orderBy

const model = mysqlTable(...)
type ModelColumns = keyof InferSelectModel<typeof modal>

function get(orderBy: ModelColumns, orderDir: "asc" | "desc") {
    db.query.model.findMany({
        orderBy: (model, {asc, desc}) => orderDir === "asc" ? asc(model[orderBy]) : desc(model[orderBy])
    })
}

ghardin1314 avatar Oct 12 '23 23:10 ghardin1314