andresgutgon
andresgutgon
DTDrizzle Team
Created by andresgutgon on 7/7/2024 in #help
Generic Drizzle ActiveRecord pattern (kind of)
Hi, I'm trying to do a Drizzle model to inherit from it with some generic methods. Maybe is not the right idea but anyway is fun to try it. This is my current implementation:
import db from '$/db/client'
import { eq } from 'drizzle-orm'
import { PgColumn } from 'drizzle-orm/pg-core'

type DB = typeof db
type TableNames = keyof DB['query']

export type FindFirstArg<T extends TableNames> = Parameters<
DB['query'][T]['findFirst']
>[0]

type ModelArgs<N extends TableNames> = {
tableName: N
identifier: PgColumn
}

export class BaseModel<N extends TableNames> {
tableName: N
identifier: PgColumn

constructor({ tableName, identifier }: ModelArgs<N>) {
this.tableName = tableName
this.identifier = identifier
}

async findOne(args: FindFirstArg<N>) {
return this.query().findFirst(args)
}

private query() {
return db.query[this.tableName]
}
}
import db from '$/db/client'
import { eq } from 'drizzle-orm'
import { PgColumn } from 'drizzle-orm/pg-core'

type DB = typeof db
type TableNames = keyof DB['query']

export type FindFirstArg<T extends TableNames> = Parameters<
DB['query'][T]['findFirst']
>[0]

type ModelArgs<N extends TableNames> = {
tableName: N
identifier: PgColumn
}

export class BaseModel<N extends TableNames> {
tableName: N
identifier: PgColumn

constructor({ tableName, identifier }: ModelArgs<N>) {
this.tableName = tableName
this.identifier = identifier
}

async findOne(args: FindFirstArg<N>) {
return this.query().findFirst(args)
}

private query() {
return db.query[this.tableName]
}
}
The problem is that it does not detect relations with Using the model:
import { BaseModel } from '$/models/BaseModel'

export const UserModel = new BaseModel({
identifier: schema.users.id,
tableName: schema.users._.name,
})

const user = await UserModel.findOne({
with: { avatar: true, account: true },
where: eq(UserModel.identifier, '1'),
})

// TYPESCRIPT don't see this
console.log("Model User (avatar): ", user.avatar)
import { BaseModel } from '$/models/BaseModel'

export const UserModel = new BaseModel({
identifier: schema.users.id,
tableName: schema.users._.name,
})

const user = await UserModel.findOne({
with: { avatar: true, account: true },
where: eq(UserModel.identifier, '1'),
})

// TYPESCRIPT don't see this
console.log("Model User (avatar): ", user.avatar)
And now when I hover user I don't see avatar But with vanilla drizzle I see it. Where I'm lossing the types? Vanilla drizzle is this:
const vanillaUser: schema.User | undefined = await db.query.users.findFirst({
with: { avatar: true },
where: eq(schema.users.id, '1'),
})

// This works
console.log("Vanilla User (avatar): ", vanillaUser.avatar?.key)
const vanillaUser: schema.User | undefined = await db.query.users.findFirst({
with: { avatar: true },
where: eq(schema.users.id, '1'),
})

// This works
console.log("Vanilla User (avatar): ", vanillaUser.avatar?.key)
1 replies