From 1569a821cdcbab29cb68b57bd03ae586420781bb Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Mon, 4 Aug 2025 10:57:44 +0530 Subject: [PATCH] orm: support lowercase operators `like`, `in`, `not in` etc (fix #25032) (#25035) --- vlib/orm/orm_func.v | 9 +++++---- vlib/orm/orm_func_test.v | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/vlib/orm/orm_func.v b/vlib/orm/orm_func.v index 33fe870f0b..8d9061522b 100644 --- a/vlib/orm/orm_func.v +++ b/vlib/orm/orm_func.v @@ -93,17 +93,18 @@ fn (mut ss MyTextScanner) next_tok() string { mut ret := '' ss.skip_whitespace() ss.last_tok_start = ss.pos + ss_upper := ss.input.to_upper() // check for longest token first - if ss.input[ss.pos..].starts_with('IS NOT NULL') { + if ss_upper[ss.pos..].starts_with('IS NOT NULL') { ss.pos += 11 return 'IS NOT NULL' } - if ss.input[ss.pos..].starts_with('IS NULL') { + if ss_upper[ss.pos..].starts_with('IS NULL') { ss.pos += 7 return 'IS NULL' } - if ss.input[ss.pos..].starts_with('NOT IN') { + if ss_upper[ss.pos..].starts_with('NOT IN') { ss.pos += 6 return 'NOT IN' } @@ -186,7 +187,7 @@ fn (qb_ &QueryBuilder[T]) parse_conditions(conds string, params []Primitive) ! { } } .op { - current_op = match tok { + current_op = match tok.to_upper() { '=' { OperationKind.eq } diff --git a/vlib/orm/orm_func_test.v b/vlib/orm/orm_func_test.v index a64648c311..d648039397 100644 --- a/vlib/orm/orm_func_test.v +++ b/vlib/orm/orm_func_test.v @@ -86,6 +86,12 @@ fn test_orm_func_where() { qb.where('(salary >= ? AND (age <= ? OR title LIKE ?))', 50000, 35, '%Manager%')! assert qb.where.parentheses == [[1, 2], [0, 2]] + // test lowercase `like` + qb.reset() + qb.where('(salary >= ? AND (age <= ? OR title like ?))', 50000, 35, '%Manager%')! + assert qb.where.parentheses == [[1, 2], [0, 2]] + assert qb.where.kinds == [.ge, .le, .orm_like] + // complex_nesting qb.reset() qb.where('((age = ? OR (salary > ? AND id < ?)) AND (name LIKE ?))', 1, 2, 3, '%test%')! @@ -96,6 +102,12 @@ fn test_orm_func_where() { qb.where('name IN ? AND age NOT IN ?', ['Tom'], [2])! assert qb.where.fields == ['name', 'age'] assert qb.where.kinds == [.in, .not_in] + + // lowercase in and not in + qb.reset() + qb.where('name in ? AND age not in ?', ['Tom'], [2])! + assert qb.where.fields == ['name', 'age'] + assert qb.where.kinds == [.in, .not_in] } fn test_orm_func_stmts() { @@ -503,6 +515,12 @@ fn test_orm_func_stmts() { assert selected_users[0].name == 'Silly' assert selected_users.len == 1 + // complex select with lowercase `is null` and `like` + selected_users1 := qb.where('created_at is null && ((salary > ? && age < ?) || (role like ?))', + 2000, 30, '%employee%')!.query()! + assert selected_users1[0].name == 'Silly' + assert selected_users1.len == 1 + // chain where and_where := qb.where('salary > ?', 2000)!.where('age > ?', 40)!.query()! assert and_where.len == 1