DSL Operators
All operators are used inside a lambda passed to findWhere, observeWhere, deleteWhere, or count. The lambda receiver is the generated <Entity>Columns object.
All values are bound as ? parameters — SQL injection is structurally impossible.
Imports
The operators are top-level functions in io.github.sufarook.kiln.runtime, so code in your own package must import the ones it uses:
import io.github.sufarook.kiln.runtime.eq
import io.github.sufarook.kiln.runtime.and
import io.github.sufarook.kiln.runtime.gte
Or bring in the whole set at once:
Unresolved reference eq?
That is a missing import, not a codegen failure. The IDE offers the import on the red symbol — the examples below omit the import lines for brevity.
Equality
| Operator | SQL equivalent | Example |
|---|---|---|
col eq value |
col = ? |
TaskColumns.status eq "DONE" |
col neq value |
col != ? |
TaskColumns.priority neq 0 |
Comparison
| Operator | SQL equivalent | Example |
|---|---|---|
col lt value |
col < ? |
TaskColumns.priority lt 3 |
col lte value |
col <= ? |
TaskColumns.priority lte 3 |
col gt value |
col > ? |
TaskColumns.priority gt 1 |
col gte value |
col >= ? |
TaskColumns.priority gte 2 |
Range
| Operator | SQL equivalent | Example |
|---|---|---|
col between lo and hi |
col BETWEEN ? AND ? |
TaskColumns.priority between 1 and 3 |
Collection
| Operator | SQL equivalent | Example |
|---|---|---|
col inList list |
col IN (?, ?, …) |
TaskColumns.status inList listOf("TODO","IN_PROGRESS") |
col notInList list |
col NOT IN (?, ?, …) |
TaskColumns.status notInList listOf("DONE","CANCELLED") |
Warning
Passing an empty list to inList or notInList throws IllegalArgumentException. Guard with if (list.isNotEmpty()).
Null checks
| Operator | SQL equivalent | Example |
|---|---|---|
col.isNull() |
col IS NULL |
TaskColumns.dueDate.isNull() |
col.isNotNull() |
col IS NOT NULL |
TaskColumns.dueDate.isNotNull() |
Note
isNull() and isNotNull() only make sense on nullable columns (property declared as String?, Long?, etc.). Using them on a non-nullable column is legal but always evaluates to IS NOT NULL = true and IS NULL = false.
Text
| Operator | SQL equivalent | Example |
|---|---|---|
col like pattern |
col LIKE ? |
TaskColumns.title like "%design%" |
col notLike pattern |
col NOT LIKE ? |
TaskColumns.title notLike "%archived%" |
SQLite LIKE is case-insensitive for ASCII letters by default. Percent % matches any sequence; underscore _ matches any single character.
Logical combinators
| Operator | SQL equivalent | Example |
|---|---|---|
a and b |
(a) AND (b) |
(TaskColumns.projectId eq id) and (TaskColumns.isCompleted eq false) |
a or b |
(a) OR (b) |
(TaskColumns.priority gt 2) or (TaskColumns.dueDate.isNull()) |
not(predicate) |
NOT (predicate) |
not(TaskColumns.isCompleted eq true) |
Combinators generate fully parenthesised SQL, so precedence is always explicit regardless of nesting depth.
Full example
// Tasks in a project that are either high-priority or overdue, and not cancelled
val tasks = taskRepo.findWhere {
(TaskColumns.projectId eq projectId) and
(
(TaskColumns.priority gte 3) or
TaskColumns.dueDate.isNotNull()
) and
not(TaskColumns.status eq "CANCELLED")
}
Generated SQL (values bound separately):