kysely
kysely copied to clipboard
typing in $if builder
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) => ....
@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()
}