Summary
.select('col') (single string argument) crashes with TypeError: columns2.join is not a function at runtime instead of either accepting the string or throwing a typed validation error. The array form .select(['col']) works correctly.
Reproducer
import { db } from '@stacksjs/database' // proxies bun-query-builder
// Crashes
await db.selectFrom('judge_reviews_likes')
.select('judge_review_id')
.where('user_id', '=', 1)
.execute()
// Works
await db.selectFrom('judge_reviews_likes')
.select(['judge_review_id'])
.where('user_id', '=', 1)
.execute()Error
TypeError: columns2.join is not a function. (In 'columns2.join(", ")', 'columns2.join' is undefined)
at select (bun-query-builder/dist/src/index.js:12852:41)Root cause
Looking at the bundled dist around the crash site, the select(columns2) implementation does:
select(columns2) {
if (!columns2 || columns2.length === 0)
return this;
const fromIndex = text.indexOf(' FROM ');
if (fromIndex !== -1) {
text = `SELECT ${columns2.join(', ')}${text.substring(fromIndex)}`;
} else {
text = `SELECT ${columns2.join(', ')} FROM ${table}`;
}
return this;
}The guard checks .length (a property both strings and arrays carry), but then unconditionally calls .join(', ') (only arrays have this). A bare string passes the guard and crashes on the next line.
Why it matters
Most query builders in this ecosystem (Kysely, Knex, Drizzle) accept both .select('col') and .select(['col']). The current shape silently accepts strings at compile time (the as any casts most codebases use mean TypeScript doesn't catch this) but fails at runtime with a confusing TypeError rather than a clear API error.
Suggested fix
Normalize the argument at the top of the method:
select(columns2) {
if (!columns2) return this;
const cols = Array.isArray(columns2) ? columns2 : [columns2];
if (cols.length === 0) return this;
// ...rest unchanged, using `cols.join(', ')`
}That gives Kysely-style ergonomics for free and keeps the array form working unchanged.
If single-string is intentionally unsupported, the guard should at minimum throw a typed error (select() expects an array of column names) so the failure mode is obvious.
Workaround in the meantime
Wrap single columns in an array: .select(['col']) — works, no other side effects.
Environment
- bun-query-builder vendored via stacks pantry (
pantry/bun-query-builder) - Bun 1.3.x
- SQLite driver
Caught while implementing a "people find this helpful" feature on a Stacks app — the lookup SELECT judge_review_id FROM judge_reviews_likes WHERE user_id = ? AND judge_review_id IN (...) 500'd until the column list was wrapped.