mirror of
https://github.com/vlang/v.git
synced 2025-08-04 02:07:28 -04:00
orm: add IN and NOT IN (#24634)
This commit is contained in:
parent
566d22ab66
commit
73ebf42015
@ -248,6 +248,7 @@ const skip_on_ubuntu_musl = [
|
||||
'vlib/orm/orm_serial_attribute_test.v',
|
||||
'vlib/orm/orm_option_subselect_test.v',
|
||||
'vlib/orm/orm_func_test.v',
|
||||
'vlib/orm/orm_where_in_test.v',
|
||||
'vlib/v/tests/orm_enum_test.v',
|
||||
'vlib/v/tests/orm_sub_struct_test.v',
|
||||
'vlib/v/tests/orm_sub_array_struct_test.v',
|
||||
|
@ -247,6 +247,11 @@ fn stmt_bind_primitive(mut stmt Stmt, data orm.Primitive) {
|
||||
orm.Null {
|
||||
stmt.bind_null()
|
||||
}
|
||||
[]orm.Primitive {
|
||||
for element in data {
|
||||
stmt_bind_primitive(mut stmt, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,11 @@ fn pg_stmt_match(mut types []u32, mut vals []&char, mut lens []int, mut formats
|
||||
lens << int(0) // ignored
|
||||
formats << 0 // ignored
|
||||
}
|
||||
[]orm.Primitive {
|
||||
for element in data {
|
||||
pg_stmt_match(mut types, mut vals, mut lens, mut formats, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ fn sqlite_stmt_worker(db DB, query string, data orm.QueryData, where orm.QueryDa
|
||||
// Binds all values of d in the prepared statement
|
||||
fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ! {
|
||||
for data in d.data {
|
||||
err := bind(stmt, c, data)
|
||||
err := bind(stmt, mut c, data)
|
||||
|
||||
if err != 0 {
|
||||
return stmt.db.error_message(err, query)
|
||||
@ -124,7 +124,7 @@ fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ! {
|
||||
}
|
||||
|
||||
// Universal bind function
|
||||
fn bind(stmt Stmt, c &int, data orm.Primitive) int {
|
||||
fn bind(stmt Stmt, mut c &int, data orm.Primitive) int {
|
||||
mut err := 0
|
||||
match data {
|
||||
i8, i16, int, u8, u16, u32, bool {
|
||||
@ -143,11 +143,21 @@ fn bind(stmt Stmt, c &int, data orm.Primitive) int {
|
||||
err = stmt.bind_int(c, int(data.unix()))
|
||||
}
|
||||
orm.InfixType {
|
||||
err = bind(stmt, c, data.right)
|
||||
err = bind(stmt, mut c, data.right)
|
||||
}
|
||||
orm.Null {
|
||||
err = stmt.bind_null(c)
|
||||
}
|
||||
[]orm.Primitive {
|
||||
for element in data {
|
||||
tmp_err := bind(stmt, mut c, element)
|
||||
c++
|
||||
if tmp_err != 0 {
|
||||
err = tmp_err
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ pub type Primitive = InfixType
|
||||
| u32
|
||||
| u64
|
||||
| u8
|
||||
| []Primitive
|
||||
|
||||
pub struct Null {}
|
||||
|
||||
@ -66,6 +67,8 @@ pub enum OperationKind {
|
||||
orm_ilike // ILIKE
|
||||
is_null // IS NULL
|
||||
is_not_null // IS NOT NULL
|
||||
in // IN
|
||||
not_in // NOT IN
|
||||
}
|
||||
|
||||
pub enum MathOperationKind {
|
||||
@ -105,6 +108,8 @@ fn (kind OperationKind) to_str() string {
|
||||
.orm_ilike { 'ILIKE' }
|
||||
.is_null { 'IS NULL' }
|
||||
.is_not_null { 'IS NOT NULL' }
|
||||
.in { 'IN' }
|
||||
.not_in { 'NOT IN' }
|
||||
}
|
||||
return str
|
||||
}
|
||||
@ -402,12 +407,25 @@ fn gen_where_clause(where QueryData, q string, qm string, num bool, mut c &int)
|
||||
}
|
||||
str += '${q}${field}${q} ${where.kinds[i].to_str()}'
|
||||
if !where.kinds[i].is_unary() {
|
||||
if where.data.len > i && where.data[i] is []Primitive {
|
||||
len := (where.data[i] as []Primitive).len
|
||||
mut tmp := []string{len: len}
|
||||
for j in 0 .. len {
|
||||
tmp[j] = '${qm}'
|
||||
if num {
|
||||
tmp[j] += '${c}'
|
||||
c++
|
||||
}
|
||||
}
|
||||
str += ' (${tmp.join(', ')})'
|
||||
} else {
|
||||
str += ' ${qm}'
|
||||
if num {
|
||||
str += '${c}'
|
||||
c++
|
||||
}
|
||||
}
|
||||
}
|
||||
if current_post_par > 0 {
|
||||
str += ' ) '.repeat(current_post_par)
|
||||
}
|
||||
@ -629,6 +647,10 @@ fn option_bool_to_primitive(b ?bool) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_bool_to_primitive(b []bool) Primitive {
|
||||
return Primitive(b.map(bool_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn f32_to_primitive(b f32) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -637,6 +659,10 @@ fn option_f32_to_primitive(b ?f32) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_f32_to_primitive(b []f32) Primitive {
|
||||
return Primitive(b.map(f32_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn f64_to_primitive(b f64) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -645,6 +671,10 @@ fn option_f64_to_primitive(b ?f64) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_f64_to_primitive(b []f64) Primitive {
|
||||
return Primitive(b.map(f64_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn i8_to_primitive(b i8) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -653,6 +683,10 @@ fn option_i8_to_primitive(b ?i8) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_i8_to_primitive(b []i8) Primitive {
|
||||
return Primitive(b.map(i8_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn i16_to_primitive(b i16) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -661,6 +695,10 @@ fn option_i16_to_primitive(b ?i16) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_i16_to_primitive(b []i16) Primitive {
|
||||
return Primitive(b.map(i16_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn int_to_primitive(b int) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -669,6 +707,10 @@ fn option_int_to_primitive(b ?int) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_int_to_primitive(b []int) Primitive {
|
||||
return Primitive(b.map(int_to_primitive(it)))
|
||||
}
|
||||
|
||||
// int_literal_to_primitive handles int literal value
|
||||
fn int_literal_to_primitive(b int) Primitive {
|
||||
return Primitive(b)
|
||||
@ -678,6 +720,10 @@ fn option_int_literal_to_primitive(b ?int) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_int_literal_to_primitive(b []int) Primitive {
|
||||
return Primitive(b.map(int_literal_to_primitive(it)))
|
||||
}
|
||||
|
||||
// float_literal_to_primitive handles float literal value
|
||||
fn float_literal_to_primitive(b f64) Primitive {
|
||||
return Primitive(b)
|
||||
@ -687,6 +733,10 @@ fn option_float_literal_to_primitive(b ?f64) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_float_literal_to_primitive(b []f64) Primitive {
|
||||
return Primitive(b.map(float_literal_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn i64_to_primitive(b i64) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -695,6 +745,10 @@ fn option_i64_to_primitive(b ?i64) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_i64_to_primitive(b []i64) Primitive {
|
||||
return Primitive(b.map(i64_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn u8_to_primitive(b u8) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -703,6 +757,10 @@ fn option_u8_to_primitive(b ?u8) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_u8_to_primitive(b []u8) Primitive {
|
||||
return Primitive(b.map(u8_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn u16_to_primitive(b u16) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -711,6 +769,10 @@ fn option_u16_to_primitive(b ?u16) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_u16_to_primitive(b []u16) Primitive {
|
||||
return Primitive(b.map(u16_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn u32_to_primitive(b u32) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -719,6 +781,10 @@ fn option_u32_to_primitive(b ?u32) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_u32_to_primitive(b []u32) Primitive {
|
||||
return Primitive(b.map(u32_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn u64_to_primitive(b u64) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -727,6 +793,10 @@ fn option_u64_to_primitive(b ?u64) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_u64_to_primitive(b []u64) Primitive {
|
||||
return Primitive(b.map(u64_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn string_to_primitive(b string) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -735,6 +805,10 @@ fn option_string_to_primitive(b ?string) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_string_to_primitive(b []string) Primitive {
|
||||
return Primitive(b.map(string_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn time_to_primitive(b time.Time) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
@ -743,6 +817,10 @@ fn option_time_to_primitive(b ?time.Time) Primitive {
|
||||
return if b_ := b { Primitive(b_) } else { null_primitive }
|
||||
}
|
||||
|
||||
fn array_time_to_primitive(b []time.Time) Primitive {
|
||||
return Primitive(b.map(time_to_primitive(it)))
|
||||
}
|
||||
|
||||
fn infix_to_primitive(b InfixType) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
|
51
vlib/orm/orm_where_in_test.v
Normal file
51
vlib/orm/orm_where_in_test.v
Normal file
@ -0,0 +1,51 @@
|
||||
// vtest flaky: true
|
||||
// vtest retry: 3
|
||||
import db.sqlite
|
||||
|
||||
struct User {
|
||||
id int @[primary; sql: serial]
|
||||
name string
|
||||
}
|
||||
|
||||
fn get_users_in(mut db sqlite.DB, names []string) ![]User {
|
||||
return sql db {
|
||||
select from User where name in names
|
||||
}!
|
||||
}
|
||||
|
||||
fn get_users_not_in(mut db sqlite.DB, names []string) ![]User {
|
||||
return sql db {
|
||||
select from User where name !in names
|
||||
}!
|
||||
}
|
||||
|
||||
fn test_orm_mut_db() {
|
||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||
|
||||
sql db {
|
||||
create table User
|
||||
}!
|
||||
|
||||
first_user := User{
|
||||
name: 'first'
|
||||
}
|
||||
second_user := User{
|
||||
name: 'second'
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert first_user into User
|
||||
insert second_user into User
|
||||
}!
|
||||
|
||||
in_users := get_users_in(mut db, ['first'])!
|
||||
|
||||
assert in_users.len == 1
|
||||
|
||||
not_in_users := get_users_not_in(mut db, ['second'])!
|
||||
|
||||
assert not_in_users.len == 1
|
||||
|
||||
all_users := get_users_in(mut db, ['first', 'second'])!
|
||||
assert all_users.len == 2
|
||||
}
|
@ -625,6 +625,8 @@ fn (mut g Gen) write_orm_primitive(t ast.Type, expr ast.Expr) {
|
||||
typ = 'option_${typ}'
|
||||
} else if g.table.final_sym(t).kind == .enum {
|
||||
typ = g.table.sym(g.table.final_type(t)).cname
|
||||
} else if g.table.final_sym(t).kind == .array {
|
||||
typ = g.table.sym(g.table.final_type(t)).cname.to_lower()
|
||||
}
|
||||
g.write('orm__${typ}_to_primitive(')
|
||||
if expr is ast.CallExpr {
|
||||
@ -778,6 +780,12 @@ fn (mut g Gen) write_orm_where_expr(expr ast.Expr, mut fields []string, mut pare
|
||||
.not_is {
|
||||
'orm__OperationKind__is_not_null'
|
||||
}
|
||||
.key_in {
|
||||
'orm__OperationKind__in'
|
||||
}
|
||||
.not_in {
|
||||
'orm__OperationKind__not_in'
|
||||
}
|
||||
else {
|
||||
''
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user