The problem
Let’s say you want to write this query:upper function. You have several options:
Creating helper functions
Fortunately, Kysely allows you to create reusable, type-safe helpers:The recipe
The pattern for helper functions is simple:1
Accept expressions as input
Take inputs as
Expression<T> where T is the type of the expression.uppertakesExpression<string>(transforms strings)roundwould takeExpression<number>(only rounds numbers)
2
Return an expression
Use the inputs to create an output that’s also an
Expression. Everything in Kysely is an expression:- Expression builder outputs
sqltemplate tag resultsSelectQueryBuilderinstances- Pretty much everything else
Composing helpers
Since everything is an expression, helpers are composable:Using helpers anywhere
Helpers work in any part of a query:Helpers using ExpressionBuilder
You can create helpers that use the expression builder instead of raw SQL:Boolean expressions
You can create helpers that return boolean expressions:When using
eb as a function like eb(left, operator, right), it creates a binary expression. All binary expressions with comparison operators are Expression<SqlBool>. You can return any Expression<SqlBool> from the callback.Handling nullable expressions
To support nullable expressions, use conditional types:Converting subquery types
SQL allows single-column subqueries to be used as scalars. Use$asScalar() to convert the type:
$asScalar() has no effect on the generated SQL — it’s purely a type-level helper.Key takeaways
Everything is an expression
All Kysely constructs are composable expressions
Type-safe inputs
Use
Expression<T> for inputs to maintain type safetyReusable and composable
Helpers can be used together and anywhere in queries
No runtime overhead
Helpers are just TypeScript — they compile away