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

Feat: infer type helpers for relations

Open Angelelz opened this issue 1 year ago • 8 comments

close #695

  • Added InferManyRelationalResult and InferFirstRelationalResult generic types to infer the resulting object shape.
  • Added db.query.<tableName>.$inferFindManyArgs and db.query.<tableName>.$inferFindFirstArgs to infer the parameter of findMany and findFirst respectively.
  • Added type tests

Assuming you have the following schema:

export const posts = sqliteTable("posts", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  content: text("content").notNull(),
  authorId: integer("author_id").notNull(),
  json: text("json", { mode: "json" })
    .notNull()
    .$type<{ hola: string; hey: number }>(),
});

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));

export const users = sqliteTable("users", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  name: text("name").notNull(),
  managerId: integer("manager_id").references((): AnySQLiteColumn => users.id),
});

export const usersRelations = relations(users, ({ many, one }) => ({
  posts: many(posts),
  manager: one(users, { fields: [users.managerId], references: [users.id] }),
}));

export const db = drizzle(sqlite, {
  schema: { posts, users, usersRelations, postsRelations },
});

This is how you could use the new type helpers:

type UsersWithPosts = InferManyRelationalResult<
  typeof schema,
  'users',
  { with: { posts: true } }
>;

/* Resulting type */
type UserWithPosts = {
  id: number;
  name: string;
  managerId: number;
  posts: {
    id: number;
    content: string;
    authorId: number | null;
    json: { hola: string, hey: number };
  }[];
}[]

type UsersManyArgument = typeof db.query.users.$inferFindManyArgs;

/* Resulting type */
type UsersManyArgument = {
    columns?: {
        id?: boolean | undefined;
        name?: boolean | undefined;
        managerId?: boolean | undefined;
    } | undefined;
    with?: <Super Long Type> | undefined;
    extras?: Record<string, SQL.Aliased<unknown>> | ((fields: <Long Type>, operators: {
        sql: typeof sql;
    }) => Record<string, SQL.Aliased<unknown>>) | undefined;
    where?: SQL<unknown> | ((fields: <Long Type>, operators: <Long Type>) => SQL<unknown> | undefined) | undefined;
    orderBy?: ValueOrArray<SQL<unknown> | AnyColumn> | ((fields: <Long Type>, operators: {
        sql: typeof sql;
        asc: (column: SQLWrapper | AnyColumn) => SQL<unknown>;
        desc: (column: SQLWrapper | AnyColumn) => SQL<unknown>;
    }) => ValueOrArray<SQL<unknown> | AnyColumn>) | undefined;
    limit?: number | Placeholder<string, any> | undefined;
    offset?: number | Placeholder<string, any> | undefined;
}

The InferManyRelationalResult and InferFirstRelationalResult are also very helpful because after the first type parameter (typeof schema), the table name has intelisense and the arguments have intelisense as well.

Angelelz avatar Dec 19 '23 04:12 Angelelz

Any timeline on this release? Would love to be also to use it!

jonahallibone avatar Jan 13 '24 05:01 jonahallibone

@Angelelz does this also cover nested relations? i.e.

type UsersWithPosts = InferManyRelationalResult<
  typeof schema,
  'users',
  { 
    with: { 
      posts: {
        categories: true
      }
    }
 }
>;

NEO97online avatar Jan 17 '24 00:01 NEO97online

@Angelelz does this also cover nested relations?

Yeah, it looks like I didn't include a specific test for this, it will in fact work.

Angelelz avatar Jan 17 '24 02:01 Angelelz

Hi guys,

Is there any update on this and when will could be potentially released?

Thanks for the great job!

RazielTX avatar May 14 '24 19:05 RazielTX

any updates please ?

LargatSeif avatar Jul 05 '24 16:07 LargatSeif

LGTM, you can merge it!

akarabach avatar Jul 26 '24 22:07 akarabach

Does the documentation need to be updated somewhere as well? Or is that a different repo?

matthiasfeist avatar Jul 27 '24 05:07 matthiasfeist

Is there anything blocking the pull request?

emilienbidet avatar Aug 08 '24 09:08 emilienbidet

I really this feature to make things clean. Is there something more to do? I can contribute to it.

emilienbidet avatar Aug 31 '24 06:08 emilienbidet