K
Kyselyโ€ข4mo ago
Marcel Overdijk

Error: don't await SelectQueryBuilder instances directly.

To execute the query you need to call execute or executeTakeFirst. I'm trying to create a function that enhances the query (SelectQueryBuilder) with pagination, sorting and filtering options that are derived from a HTTP request. This function looks like:
async applyQueryParams<DB, TB extends keyof DB, O>(qb: SelectQueryBuilder<DB, TB, O>): Promise<SelectQueryBuilder<DB, TB, O>> {
const data = await this.getValidatedData<PaginationSchema & SortSchema & FilterSchema>();
const page = .. // derive page
const pageSize = .. // derive page size
const sort = .. // derive sort
const filter = .. // derive filter

console.log("Query builder before pagination:", qb);

qb = qb.limit(pageSize);
qb = qb.offset((page - 1) * pageSize);

console.log("Query builder after pagination:", qb);

return qb;
}
async applyQueryParams<DB, TB extends keyof DB, O>(qb: SelectQueryBuilder<DB, TB, O>): Promise<SelectQueryBuilder<DB, TB, O>> {
const data = await this.getValidatedData<PaginationSchema & SortSchema & FilterSchema>();
const page = .. // derive page
const pageSize = .. // derive page size
const sort = .. // derive sort
const filter = .. // derive filter

console.log("Query builder before pagination:", qb);

qb = qb.limit(pageSize);
qb = qb.offset((page - 1) * pageSize);

console.log("Query builder after pagination:", qb);

return qb;
}
this function needs to async as the getValidatedData() is also async in a handler I call applyQueryParams like:
async handle(c: C) {

let qb = c.var.mydb
.selectFrom('customer')
.selectAll('customer');

console.log("Before applying query params:", qb);

qb = await this.applyQueryParams(qb);

console.log("After applying query params:", qb);

const customers = await qb.execute();
async handle(c: C) {

let qb = c.var.mydb
.selectFrom('customer')
.selectAll('customer');

console.log("Before applying query params:", qb);

qb = await this.applyQueryParams(qb);

console.log("After applying query params:", qb);

const customers = await qb.execute();
but this fails with:
Before applying query params: SelectQueryBuilderImpl {}
Query builder before pagination: SelectQueryBuilderImpl {}
Query builder after pagination: SelectQueryBuilderImpl {}
โœ˜ [ERROR] Error: don't await SelectQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.
Before applying query params: SelectQueryBuilderImpl {}
Query builder before pagination: SelectQueryBuilderImpl {}
Query builder after pagination: SelectQueryBuilderImpl {}
โœ˜ [ERROR] Error: don't await SelectQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.
and I don't understand what is wrong ๐Ÿ˜ฆ .... this seems not to be correct: qb = await this.applyQueryParams(qb);, but I need to await it. anybody an idea what I'm doing wrong?
Solution:
If you return a thenable object from an async function its then method gets called. Kysely query builders all have a then method that throws that exception. It's there because many other query builders and ORMs allow you to do stuff like
const result = await db.selectFrom('person').selectAll()
const result = await db.selectFrom('person').selectAll()
...
Jump to solution
6 Replies
Marcel Overdijk
Marcel OverdijkOPโ€ข4mo ago
I found this related issue as well: https://github.com/kysely-org/kysely/issues/838 but it does not give a solution, or maybe there is none, and an async function can't return a query builder?
GitHub
SelectQueryBuilder preventAwait makes it impossible to return a que...
Issue I have a database repository class that internally uses Kysely for querying. There are two methods that share a similar query, so I have a helper function to create the query. To fill where p...
Marcel Overdijk
Marcel OverdijkOPโ€ข4mo ago
GitHub
Using sql helper in promise chains causes unexpected preventAwait e...
Here's a simple example: import { sql } from 'kysely' // a plain promise for the example, but this could be a value determined inside a transaction // or as part of some other promise c...
Marcel Overdijk
Marcel OverdijkOPโ€ข4mo ago
GitHub
A way to disable 'preventAwait' by wirekang ยท Pull Request #748 ยท k...
Although @koskimas closed #693 as &#39;wontfix&#39;, I&#39;m suggesting a way to disable the behavior of preventAwait, with a small footprint. We often returning non-Promise value in as...
Solution
koskimas
koskimasโ€ข4mo ago
If you return a thenable object from an async function its then method gets called. Kysely query builders all have a then method that throws that exception. It's there because many other query builders and ORMs allow you to do stuff like
const result = await db.selectFrom('person').selectAll()
const result = await db.selectFrom('person').selectAll()
and Kysely doesn't. If we didn't have the then method, we'd get a lot of issues about queries not getting executed. Just wrap the return value to something not thenable. For example { qb }
Marcel Overdijk
Marcel OverdijkOPโ€ข4mo ago
thx @koskimas I already was using that (hopefully temporary) when I got the error:
async applyQueryParams<DB, TB extends keyof DB, O>(qb: SelectQueryBuilder<DB, TB, O>): Promise<{ qb: SelectQueryBuilder<DB, TB, O> }> {
..
return { qb };
}
async applyQueryParams<DB, TB extends keyof DB, O>(qb: SelectQueryBuilder<DB, TB, O>): Promise<{ qb: SelectQueryBuilder<DB, TB, O> }> {
..
return { qb };
}
and then using it like:
qb = (await this.applyQueryParams(qb)).qb;
qb = (await this.applyQueryParams(qb)).qb;
and that works. I must admit, it doesn't really look pretty ๐Ÿ˜‰ my other alternative is to split retrieving the async request data and enhancing the query. that way I can make it non async
Marcel Overdijk
Marcel OverdijkOPโ€ข4mo ago
I'm now using this:
const qb = c.var.mydb
.selectFrom('customer')
.selectAll('customer');

const { query } = await this.applyQueryParams(qb)

const customers = await query.execute();
const qb = c.var.mydb
.selectFrom('customer')
.selectAll('customer');

const { query } = await this.applyQueryParams(qb)

const customers = await query.execute();
Want results from more Discord servers?
Add your server