Hey π
v0.28 broke an undocumented TypeScript behavior our API had that allowed you to pass table name unions to query builders and enable some DRYing of queries. Seeing that this pattern was quite popular, we decided to support it officially with the addition of the table
method in the dynamic module.
You can pull off some crazy complex stuff like:
async function getRowByColumn<
T extends keyof Database,
C extends keyof Database[T] & string,
V extends SelectType<Database[T][C]>,
>(t: T, c: C, v: V) {
// We need to use the dynamic module since the table name
// is not known at compile time.
const { table, ref } = db.dynamic
return await db
.selectFrom(table(t).as('t'))
.selectAll()
.where(ref(c), '=', v)
// `id` can be directly referenced since every table has it.
.orderBy('t.id')
.executeTakeFirstOrThrow()
}
const person = await getRowByColumn('person', 'first_name', 'Arnold')
...and it'll narrow the downstream query context to the intersection of all the possible shapes of tables in the union type. (DONT DO THIS AT HOME KIDS!)
A simpler example would be:
async function deleteItem(id: string, table: 'person' | 'pet') {
await db
.deleteFrom(db.dynamic.table(table).as('t'))
.where('id', '=', id)
.executeTakeFirstOrThrow()
}
If you attempt to refer to a column that doesn't exist in both "person" and "pet" (e.g. "pet"'s "species" column), the compiler will correctly yell at you.
π Features
π Bugfixes
SQLite π
- fix: SQLite's introspector is printing deprecation errors for
orderBy(array)
. by @igalklebanov in #1435
π Documentation
π¦ CICD & Tooling
β οΈ Breaking Changes
π€ New Contributors
Full Changelog: 0.28.1...0.28.2