kysely icon indicating copy to clipboard operation
kysely copied to clipboard

typing in $if builder

Open mendrik opened this issue 8 months ago • 1 comments

currently it is defined like this:

$if<O2>(
   condition: boolean,
   func: (qb: this) => SelectQueryBuilder<any, any, O & O2>
): ...;

however that means that if condition is a type-guard we must re-check it the 2nd argument (or use !). This could be improved by something like this:

$guard<O2, V, R extends V>(
    val: V, 
    condition: (val: V) => val is R ,
    func: (qb: this, val: R) => SelectQueryBuilder<any, any, O & O2>
): ...

then we could do something like so:

.$guard(x, isNotNil, (qb, x) => ....

mendrik avatar Mar 11 '25 20:03 mendrik

@koskimas, in #272, it seems as you were rather looking for replacing this function or renaming it. I just wanted to know what the current direction is for the $if function. If adding typing in the $if builder, as proposed here, is something you want to support, I could try adding a PR for it using the proposed way here.

In my use-case, the selection would even be possible to infer from the arguments of the caller. Given the example of your documentation (https://github.com/kysely-org/kysely/blob/master/site/docs/recipes/0005-conditional-selects.md), the function currently has the following type definition:

async function getPerson(
  id: number,
  withLastName: boolean,
): Promise<{ first_name: string; last_name?: string }> {
  return await db
    .selectFrom("person")
    .select("first_name")
    .$if(withLastName, (qb) => qb.select("last_name"))
    .where("id", "=", id)
    .executeTakeFirstOrThrow();
}

This function could have the following type definition:

async function getPerson<TLastName extends boolean>(
  id: number,
  withLastName: TLastName,
): Promise<
  TLastName extends true ? { first_name: string; last_name: string } : { first_name: string }
> {
  return await db
    .selectFrom('person')
    .select('first_name')
    .$if(withLastName, (qb) => qb.select('last_name'))
    .where('id', '=', id)
    .executeTakeFirstOrThrow()
}

SimonSimCity avatar Nov 21 '25 10:11 SimonSimCity