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_serial_attribute_test.v',
|
||||||
'vlib/orm/orm_option_subselect_test.v',
|
'vlib/orm/orm_option_subselect_test.v',
|
||||||
'vlib/orm/orm_func_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_enum_test.v',
|
||||||
'vlib/v/tests/orm_sub_struct_test.v',
|
'vlib/v/tests/orm_sub_struct_test.v',
|
||||||
'vlib/v/tests/orm_sub_array_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 {
|
orm.Null {
|
||||||
stmt.bind_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
|
lens << int(0) // ignored
|
||||||
formats << 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
|
// Binds all values of d in the prepared statement
|
||||||
fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ! {
|
fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ! {
|
||||||
for data in d.data {
|
for data in d.data {
|
||||||
err := bind(stmt, c, data)
|
err := bind(stmt, mut c, data)
|
||||||
|
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
return stmt.db.error_message(err, query)
|
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
|
// 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
|
mut err := 0
|
||||||
match data {
|
match data {
|
||||||
i8, i16, int, u8, u16, u32, bool {
|
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()))
|
err = stmt.bind_int(c, int(data.unix()))
|
||||||
}
|
}
|
||||||
orm.InfixType {
|
orm.InfixType {
|
||||||
err = bind(stmt, c, data.right)
|
err = bind(stmt, mut c, data.right)
|
||||||
}
|
}
|
||||||
orm.Null {
|
orm.Null {
|
||||||
err = stmt.bind_null(c)
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ pub type Primitive = InfixType
|
|||||||
| u32
|
| u32
|
||||||
| u64
|
| u64
|
||||||
| u8
|
| u8
|
||||||
|
| []Primitive
|
||||||
|
|
||||||
pub struct Null {}
|
pub struct Null {}
|
||||||
|
|
||||||
@ -66,6 +67,8 @@ pub enum OperationKind {
|
|||||||
orm_ilike // ILIKE
|
orm_ilike // ILIKE
|
||||||
is_null // IS NULL
|
is_null // IS NULL
|
||||||
is_not_null // IS NOT NULL
|
is_not_null // IS NOT NULL
|
||||||
|
in // IN
|
||||||
|
not_in // NOT IN
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MathOperationKind {
|
pub enum MathOperationKind {
|
||||||
@ -105,6 +108,8 @@ fn (kind OperationKind) to_str() string {
|
|||||||
.orm_ilike { 'ILIKE' }
|
.orm_ilike { 'ILIKE' }
|
||||||
.is_null { 'IS NULL' }
|
.is_null { 'IS NULL' }
|
||||||
.is_not_null { 'IS NOT NULL' }
|
.is_not_null { 'IS NOT NULL' }
|
||||||
|
.in { 'IN' }
|
||||||
|
.not_in { 'NOT IN' }
|
||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
@ -402,10 +407,23 @@ fn gen_where_clause(where QueryData, q string, qm string, num bool, mut c &int)
|
|||||||
}
|
}
|
||||||
str += '${q}${field}${q} ${where.kinds[i].to_str()}'
|
str += '${q}${field}${q} ${where.kinds[i].to_str()}'
|
||||||
if !where.kinds[i].is_unary() {
|
if !where.kinds[i].is_unary() {
|
||||||
str += ' ${qm}'
|
if where.data.len > i && where.data[i] is []Primitive {
|
||||||
if num {
|
len := (where.data[i] as []Primitive).len
|
||||||
str += '${c}'
|
mut tmp := []string{len: len}
|
||||||
c++
|
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 {
|
if current_post_par > 0 {
|
||||||
@ -629,6 +647,10 @@ fn option_bool_to_primitive(b ?bool) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn f32_to_primitive(b f32) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -637,6 +659,10 @@ fn option_f32_to_primitive(b ?f32) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn f64_to_primitive(b f64) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -645,6 +671,10 @@ fn option_f64_to_primitive(b ?f64) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn i8_to_primitive(b i8) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -653,6 +683,10 @@ fn option_i8_to_primitive(b ?i8) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn i16_to_primitive(b i16) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -661,6 +695,10 @@ fn option_i16_to_primitive(b ?i16) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn int_to_primitive(b int) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -669,6 +707,10 @@ fn option_int_to_primitive(b ?int) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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
|
// int_literal_to_primitive handles int literal value
|
||||||
fn int_literal_to_primitive(b int) Primitive {
|
fn int_literal_to_primitive(b int) Primitive {
|
||||||
return Primitive(b)
|
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 }
|
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
|
// float_literal_to_primitive handles float literal value
|
||||||
fn float_literal_to_primitive(b f64) Primitive {
|
fn float_literal_to_primitive(b f64) Primitive {
|
||||||
return Primitive(b)
|
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 }
|
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 {
|
fn i64_to_primitive(b i64) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -695,6 +745,10 @@ fn option_i64_to_primitive(b ?i64) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn u8_to_primitive(b u8) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -703,6 +757,10 @@ fn option_u8_to_primitive(b ?u8) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn u16_to_primitive(b u16) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -711,6 +769,10 @@ fn option_u16_to_primitive(b ?u16) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn u32_to_primitive(b u32) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -719,6 +781,10 @@ fn option_u32_to_primitive(b ?u32) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn u64_to_primitive(b u64) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -727,6 +793,10 @@ fn option_u64_to_primitive(b ?u64) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn string_to_primitive(b string) Primitive {
|
||||||
return Primitive(b)
|
return Primitive(b)
|
||||||
}
|
}
|
||||||
@ -735,6 +805,10 @@ fn option_string_to_primitive(b ?string) Primitive {
|
|||||||
return if b_ := b { Primitive(b_) } else { null_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 {
|
fn time_to_primitive(b time.Time) Primitive {
|
||||||
return Primitive(b)
|
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 }
|
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 {
|
fn infix_to_primitive(b InfixType) Primitive {
|
||||||
return Primitive(b)
|
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}'
|
typ = 'option_${typ}'
|
||||||
} else if g.table.final_sym(t).kind == .enum {
|
} else if g.table.final_sym(t).kind == .enum {
|
||||||
typ = g.table.sym(g.table.final_type(t)).cname
|
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(')
|
g.write('orm__${typ}_to_primitive(')
|
||||||
if expr is ast.CallExpr {
|
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 {
|
.not_is {
|
||||||
'orm__OperationKind__is_not_null'
|
'orm__OperationKind__is_not_null'
|
||||||
}
|
}
|
||||||
|
.key_in {
|
||||||
|
'orm__OperationKind__in'
|
||||||
|
}
|
||||||
|
.not_in {
|
||||||
|
'orm__OperationKind__not_in'
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user