Daniel Baulig
Daniel Baulig

Reputation: 11009

Drizzle ORM: Maintaining typing when wrapping Drizzle Query API calls

I am trying to wrap a Drizzle Query call into a reusable function that adds a little bit of an authorization layer on top of the database access. Here's an example:

async function loadMyThing(user: User, id: ThingId, opts?: Parameters<typeof db.query.myThings.findFirst>[0]) {
  return db.query.myThings.findFirst({
    ...opts,
    where: (t, {and, eq}) => and(eq(t.owner, user.id), eq(t.id, id)),
  });
}

The problem I have is that loadMyThing looses signifcant amounts of typing with this. The returned result still is of a myThings row type, but I pass in e.g. columns or with, those options are not correctly reflected on the return value type:

const thing = await loadMyThing(me, thingId, { with: { thingRelation: true } });

// E: Property thingRelation does not exist on thing
thing!.thingRelation

thingRelation obviously is a valid relation on the myThings table. Calling db.query.myThings.findFirst directlygives the correctly typed result.

How can I "forward" typing information correctly here?

I tried some simple approaches using generics, but that didn't work. E.g.:

async function loadMyThing<T extends Parameters<typeof db.query.myThings.findFirst>[0]>(user: User, id: ThingId, opts?: T) {
  return db.query.myThings.findFirst({
    ...opts,
    where: (t, {and, eq}) => and(eq(t.owner, user.id), eq(t.id, id)),
  });
}

I'm afraid my typescript foo is not strong enough to figure this out.

Upvotes: 1

Views: 39

Answers (0)

Related Questions