How can I extend drizzle tables?

I noticed that I write a lot of boilerplate code. When I had to update one of such types, I refactored them a bit, into reusable thing:
// /__prefabs.ts
import { sql } from "drizzle-orm"
import { datetime, varchar, int } from "drizzle-orm/mysql-core"
import { User } from "./NextAuth"

export const id = int("id").primaryKey().autoincrement()
export const name = varchar("name", { length: 191 }).notNull()
export const slug = varchar("slug", { length: 191 }).notNull()

export const Updated = {
updatedAt: datetime("updatedAt", { mode: "date", fsp: 3 })
.default(sql`CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)`)
.notNull(),
updatedById: varchar("updatedById", { length: 191 }).references(
() => User.id,
{ onDelete: "set null", onUpdate: "cascade" }
)
}
// /__prefabs.ts
import { sql } from "drizzle-orm"
import { datetime, varchar, int } from "drizzle-orm/mysql-core"
import { User } from "./NextAuth"

export const id = int("id").primaryKey().autoincrement()
export const name = varchar("name", { length: 191 }).notNull()
export const slug = varchar("slug", { length: 191 }).notNull()

export const Updated = {
updatedAt: datetime("updatedAt", { mode: "date", fsp: 3 })
.default(sql`CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)`)
.notNull(),
updatedById: varchar("updatedById", { length: 191 }).references(
() => User.id,
{ onDelete: "set null", onUpdate: "cascade" }
)
}
// Category.ts
import { mysqlTable, unique } from "drizzle-orm/mysql-core"
import { id, name, slug, Updated } from "./__prefabs"

export const Category = mysqlTable(
"Category",
{
id,
name,
slug,
...Updated
},
(table) => {
return {
Category_name_key: unique("Category_name_key").on(table.name),
Category_slug_key: unique("Category_slug_key").on(table.slug)
}
}
)
// Category.ts
import { mysqlTable, unique } from "drizzle-orm/mysql-core"
import { id, name, slug, Updated } from "./__prefabs"

export const Category = mysqlTable(
"Category",
{
id,
name,
slug,
...Updated
},
(table) => {
return {
Category_name_key: unique("Category_name_key").on(table.name),
Category_slug_key: unique("Category_slug_key").on(table.slug)
}
}
)
This worked out pretty well for that time. But now, I keep writing tons of services, and I want to make some reusable functions, but I struggle with TS trying to do that. i.e. I want to make a service getItems:
// services/getItems.ts
import { db } from "@/app/(db)"
import { type Table } from "drizzle-orm"

type ItemTable = {
id: number,
name: string,
slug: string
}

export async function getItems<T extends ItemTable>(table: Table<T>) {
return db
.select({
id: table.id,
name: table.name,
slug: table.slug
})
.from(table)
}
// services/getItems.ts
import { db } from "@/app/(db)"
import { type Table } from "drizzle-orm"

type ItemTable = {
id: number,
name: string,
slug: string
}

export async function getItems<T extends ItemTable>(table: Table<T>) {
return db
.select({
id: table.id,
name: table.name,
slug: table.slug
})
.from(table)
}
But types on this thing are totally wrong, and I'm not sure where should I start to approach this problem. Another example, I have some subqueries like these:
const getProblemId = db
.select({
id: Problem.id
})
.from(Problem)
.where(eq(Problem.slug, sql.placeholder("problemSlug")))
.limit(1)
const getProblemId = db
.select({
id: Problem.id
})
.from(Problem)
.where(eq(Problem.slug, sql.placeholder("problemSlug")))
.limit(1)
It would be nice if I could refactor it into getID, that takes Table as prop:
const getID = (Table) => db
.select({
id: Table.id
})
.from(Table)
.where(eq(Table.slug, sql.placeholder("slug")))
.limit(1)
const getID = (Table) => db
.select({
id: Table.id
})
.from(Table)
.where(eq(Table.slug, sql.placeholder("slug")))
.limit(1)
But I just don't get how to define the Table type in TS.
0 Replies
No replies yetBe the first to reply to this messageJoin