Conditions
Field, JSON, full-text, group, and subquery condition reference.
Oro conditions are designed to be readable at the call site while preserving SQL expressiveness.
Where forms
Where("Price", 100) // Price = 100
Where("Price", ">=", 100) // Price >= 100
Where(oro.Field("Price").Gte(100))
Where does not accept callback functions. Use WhereGroup, OrWhereGroup, or WhereWhen for callbacks.
Model queries use Go field names. Table queries use database column names.
Operator allowlist
The three-argument form Where(field, op, value) validates op against a fixed allowlist. An unknown operator returns ErrInvalidArgument instead of being interpolated into SQL.
Value conditions allow (case-insensitive, whitespace-normalized):
= != <> < <= > >= like not like ilike not ilike is is not
Column conditions (WhereColumn) allow: = != <> < <= > >=.
ilike / not ilike only render natively on PostgreSQL.
Field expressions
query.Where(
oro.Field("Status").Eq("active"),
oro.Field("Price").Gte(100),
)
Value comparison methods:
| Method | SQL |
|---|---|
Eq(value) |
= |
NotEq(value) |
!= |
Gt(value) |
> |
Gte(value) |
>= |
Lt(value) |
< |
Lte(value) |
<= |
Like(value) |
LIKE |
NotLike(value) |
NOT LIKE |
In(values...) |
IN |
NotIn(values...) |
NOT IN |
Between(start, end) |
BETWEEN |
NotBetween(start, end) |
NOT (BETWEEN) |
IsNull() |
IS NULL |
IsNotNull() |
IS NOT NULL |
Column comparison methods:
| Method | SQL |
|---|---|
EqCol(right) |
left = right |
NotEqCol(right) |
left != right |
GtCol(right) |
left > right |
GteCol(right) |
left >= right |
LtCol(right) |
left < right |
LteCol(right) |
left <= right |
Literal LIKE helpers
Like(value) and NotLike(value) use the value as-is, so % and _ stay wildcards. When the input is user data that must be matched literally, use the helpers that escape it for you:
| Method | LIKE pattern |
|---|---|
Contains(value) |
%value% |
StartsWith(value) |
value% |
EndsWith(value) |
%value |
oro.Field("Name").Contains("100%") // matches the literal substring "100%"
oro.Field("Code").StartsWith("VIP")
oro.Field("Code").Like("P%") // % is still a wildcard (unchanged)
These escape \, %, and _ in the input and emit LIKE ? ESCAPE '\' on SQLite, MySQL, and PostgreSQL, so characters like % or _ are matched literally.
To build a custom pattern with Like while keeping user input literal, escape it with oro.EscapeLike:
oro.Field("Name").Like("%" + oro.EscapeLike(userInput) + "%") // manual escaping
Time and date ranges
Use oro.Time(field) when the condition is about a time column. Explicit boundary methods keep their SQL meaning, while calendar buckets are compiled as half-open ranges: field >= start AND field < end. This keeps indexes usable and works the same on SQLite, MySQL, and PostgreSQL.
orders, err := db.Use[Order]().
Where(oro.Time("CreatedAt").InRange(start, end)).
Get(ctx)
orders, err = db.Use[Order]().
Where(oro.Time("CreatedAt").OnDate(dayInUserLocation)).
Get(ctx)
Boundary methods:
| Method | SQL meaning |
|---|---|
Between(start, end) |
closed BETWEEN |
NotBetween(start, end) |
NOT (BETWEEN) |
After(value) |
> |
Before(value) |
< |
From(value) |
>= |
Until(value) |
< |
InRange(start, end) |
half-open [start, end) |
Calendar bucket methods:
| Method | Range |
|---|---|
OnDate(day) |
local day [00:00, next day 00:00) |
InMonth(value) |
local month [1st 00:00, next month 1st 00:00) |
InYear(value) |
local year [Jan 1 00:00, next Jan 1 00:00) |
Today(loc...) |
current day in loc, default UTC |
LastDays(n, loc...) |
last n calendar days including today, default UTC |
OnDate, InMonth, and InYear use the location on the input time.Time. Today and LastDays accept an optional location and default to UTC. Bounds stay in that location; Oro normalizes time arguments to UTC at execution.
shanghai := time.FixedZone("CST", 8*60*60)
day := time.Date(2026, 6, 30, 0, 0, 0, 0, shanghai)
orders, err := db.Use[Order]().
Where(oro.Time("CreatedAt").OnDate(day)).
Get(ctx)
For advanced composition or testing, use the exported bound helpers:
start, end := oro.DayBounds(day, shanghai)
start, end = oro.MonthBounds(day, shanghai)
start, end = oro.YearBounds(day, shanghai)
Groups
products, err := db.Use[Product]().
Where("Status", "active").
WhereGroup(func(w *oro.WhereBuilder) {
w.Where("Price", ">=", 100).
OrWhere("Code", "like", "VIP%")
}).
Get(ctx)
OR group:
query.OrWhereGroup(func(w *oro.WhereBuilder) {
w.Where("Status", "draft").Where("Price", 0)
})
Conditional group:
query.WhereWhen(keyword != "", func(w *oro.WhereBuilder) {
w.Where("Code", "like", keyword+"%")
})
Condition object helpers
activeOrDraft := oro.Or(
oro.Field("Status").Eq("active"),
oro.Field("Status").Eq("draft"),
)
products, err := db.Use[Product]().Where(activeOrDraft).Get(ctx)
Helpers include:
| Function | Purpose |
|---|---|
oro.And(...) |
AND group |
oro.Or(...) |
OR group |
oro.Not(condition) |
NOT condition |
oro.Exists(oro.Query(query)) |
EXISTS subquery |
oro.RawCondition(sql, args...) |
raw condition |
JSON conditions
products, err := db.Use[Product]().
Where(oro.JSON("Meta").Path("color").Eq("red")).
Get(ctx)
JSON support depends on database capabilities. The dialect compiles path expressions.
Full-text conditions
posts, err := db.Use[Post]().
Where(oro.FullText("Title", "Body").Match("orm")).
Get(ctx)
Create matching full-text indexes in Define where the database supports them.
Subqueries
activeUsers := oro.Query(db.Table("users").Select("id").Where("status", "active"))
orders, err := db.Table("orders").WhereIn("user_id", activeUsers).Get(ctx)
WhereExists and OrWhereExists are available on the query and where builder.