Skip to content

Commit 73ebf42

Browse files
orm: add IN and NOT IN (#24634)
1 parent 566d22a commit 73ebf42

File tree

7 files changed

+165
-7
lines changed

7 files changed

+165
-7
lines changed

cmd/tools/vtest-self.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ const skip_on_ubuntu_musl = [
248248
'vlib/orm/orm_serial_attribute_test.v',
249249
'vlib/orm/orm_option_subselect_test.v',
250250
'vlib/orm/orm_func_test.v',
251+
'vlib/orm/orm_where_in_test.v',
251252
'vlib/v/tests/orm_enum_test.v',
252253
'vlib/v/tests/orm_sub_struct_test.v',
253254
'vlib/v/tests/orm_sub_array_struct_test.v',

vlib/db/mysql/orm.c.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ fn stmt_bind_primitive(mut stmt Stmt, data orm.Primitive) {
247247
orm.Null {
248248
stmt.bind_null()
249249
}
250+
[]orm.Primitive {
251+
for element in data {
252+
stmt_bind_primitive(mut stmt, element)
253+
}
254+
}
250255
}
251256
}
252257

vlib/db/pg/orm.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ fn pg_stmt_match(mut types []u32, mut vals []&char, mut lens []int, mut formats
180180
lens << int(0) // ignored
181181
formats << 0 // ignored
182182
}
183+
[]orm.Primitive {
184+
for element in data {
185+
pg_stmt_match(mut types, mut vals, mut lens, mut formats, element)
186+
}
187+
}
183188
}
184189
}
185190

vlib/db/sqlite/orm.v

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ fn sqlite_stmt_worker(db DB, query string, data orm.QueryData, where orm.QueryDa
114114
// Binds all values of d in the prepared statement
115115
fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ! {
116116
for data in d.data {
117-
err := bind(stmt, c, data)
117+
err := bind(stmt, mut c, data)
118118

119119
if err != 0 {
120120
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) ! {
124124
}
125125

126126
// Universal bind function
127-
fn bind(stmt Stmt, c &int, data orm.Primitive) int {
127+
fn bind(stmt Stmt, mut c &int, data orm.Primitive) int {
128128
mut err := 0
129129
match data {
130130
i8, i16, int, u8, u16, u32, bool {
@@ -143,11 +143,21 @@ fn bind(stmt Stmt, c &int, data orm.Primitive) int {
143143
err = stmt.bind_int(c, int(data.unix()))
144144
}
145145
orm.InfixType {
146-
err = bind(stmt, c, data.right)
146+
err = bind(stmt, mut c, data.right)
147147
}
148148
orm.Null {
149149
err = stmt.bind_null(c)
150150
}
151+
[]orm.Primitive {
152+
for element in data {
153+
tmp_err := bind(stmt, mut c, element)
154+
c++
155+
if tmp_err != 0 {
156+
err = tmp_err
157+
break
158+
}
159+
}
160+
}
151161
}
152162
return err
153163
}

vlib/orm/orm.v

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub type Primitive = InfixType
5252
| u32
5353
| u64
5454
| u8
55+
| []Primitive
5556

5657
pub struct Null {}
5758

@@ -66,6 +67,8 @@ pub enum OperationKind {
6667
orm_ilike // ILIKE
6768
is_null // IS NULL
6869
is_not_null // IS NOT NULL
70+
in // IN
71+
not_in // NOT IN
6972
}
7073

7174
pub enum MathOperationKind {
@@ -105,6 +108,8 @@ fn (kind OperationKind) to_str() string {
105108
.orm_ilike { 'ILIKE' }
106109
.is_null { 'IS NULL' }
107110
.is_not_null { 'IS NOT NULL' }
111+
.in { 'IN' }
112+
.not_in { 'NOT IN' }
108113
}
109114
return str
110115
}
@@ -402,10 +407,23 @@ fn gen_where_clause(where QueryData, q string, qm string, num bool, mut c &int)
402407
}
403408
str += '${q}${field}${q} ${where.kinds[i].to_str()}'
404409
if !where.kinds[i].is_unary() {
405-
str += ' ${qm}'
406-
if num {
407-
str += '${c}'
408-
c++
410+
if where.data.len > i && where.data[i] is []Primitive {
411+
len := (where.data[i] as []Primitive).len
412+
mut tmp := []string{len: len}
413+
for j in 0 .. len {
414+
tmp[j] = '${qm}'
415+
if num {
416+
tmp[j] += '${c}'
417+
c++
418+
}
419+
}
420+
str += ' (${tmp.join(', ')})'
421+
} else {
422+
str += ' ${qm}'
423+
if num {
424+
str += '${c}'
425+
c++
426+
}
409427
}
410428
}
411429
if current_post_par > 0 {
@@ -629,6 +647,10 @@ fn option_bool_to_primitive(b ?bool) Primitive {
629647
return if b_ := b { Primitive(b_) } else { null_primitive }
630648
}
631649

650+
fn array_bool_to_primitive(b []bool) Primitive {
651+
return Primitive(b.map(bool_to_primitive(it)))
652+
}
653+
632654
fn f32_to_primitive(b f32) Primitive {
633655
return Primitive(b)
634656
}
@@ -637,6 +659,10 @@ fn option_f32_to_primitive(b ?f32) Primitive {
637659
return if b_ := b { Primitive(b_) } else { null_primitive }
638660
}
639661

662+
fn array_f32_to_primitive(b []f32) Primitive {
663+
return Primitive(b.map(f32_to_primitive(it)))
664+
}
665+
640666
fn f64_to_primitive(b f64) Primitive {
641667
return Primitive(b)
642668
}
@@ -645,6 +671,10 @@ fn option_f64_to_primitive(b ?f64) Primitive {
645671
return if b_ := b { Primitive(b_) } else { null_primitive }
646672
}
647673

674+
fn array_f64_to_primitive(b []f64) Primitive {
675+
return Primitive(b.map(f64_to_primitive(it)))
676+
}
677+
648678
fn i8_to_primitive(b i8) Primitive {
649679
return Primitive(b)
650680
}
@@ -653,6 +683,10 @@ fn option_i8_to_primitive(b ?i8) Primitive {
653683
return if b_ := b { Primitive(b_) } else { null_primitive }
654684
}
655685

686+
fn array_i8_to_primitive(b []i8) Primitive {
687+
return Primitive(b.map(i8_to_primitive(it)))
688+
}
689+
656690
fn i16_to_primitive(b i16) Primitive {
657691
return Primitive(b)
658692
}
@@ -661,6 +695,10 @@ fn option_i16_to_primitive(b ?i16) Primitive {
661695
return if b_ := b { Primitive(b_) } else { null_primitive }
662696
}
663697

698+
fn array_i16_to_primitive(b []i16) Primitive {
699+
return Primitive(b.map(i16_to_primitive(it)))
700+
}
701+
664702
fn int_to_primitive(b int) Primitive {
665703
return Primitive(b)
666704
}
@@ -669,6 +707,10 @@ fn option_int_to_primitive(b ?int) Primitive {
669707
return if b_ := b { Primitive(b_) } else { null_primitive }
670708
}
671709

710+
fn array_int_to_primitive(b []int) Primitive {
711+
return Primitive(b.map(int_to_primitive(it)))
712+
}
713+
672714
// int_literal_to_primitive handles int literal value
673715
fn int_literal_to_primitive(b int) Primitive {
674716
return Primitive(b)
@@ -678,6 +720,10 @@ fn option_int_literal_to_primitive(b ?int) Primitive {
678720
return if b_ := b { Primitive(b_) } else { null_primitive }
679721
}
680722

723+
fn array_int_literal_to_primitive(b []int) Primitive {
724+
return Primitive(b.map(int_literal_to_primitive(it)))
725+
}
726+
681727
// float_literal_to_primitive handles float literal value
682728
fn float_literal_to_primitive(b f64) Primitive {
683729
return Primitive(b)
@@ -687,6 +733,10 @@ fn option_float_literal_to_primitive(b ?f64) Primitive {
687733
return if b_ := b { Primitive(b_) } else { null_primitive }
688734
}
689735

736+
fn array_float_literal_to_primitive(b []f64) Primitive {
737+
return Primitive(b.map(float_literal_to_primitive(it)))
738+
}
739+
690740
fn i64_to_primitive(b i64) Primitive {
691741
return Primitive(b)
692742
}
@@ -695,6 +745,10 @@ fn option_i64_to_primitive(b ?i64) Primitive {
695745
return if b_ := b { Primitive(b_) } else { null_primitive }
696746
}
697747

748+
fn array_i64_to_primitive(b []i64) Primitive {
749+
return Primitive(b.map(i64_to_primitive(it)))
750+
}
751+
698752
fn u8_to_primitive(b u8) Primitive {
699753
return Primitive(b)
700754
}
@@ -703,6 +757,10 @@ fn option_u8_to_primitive(b ?u8) Primitive {
703757
return if b_ := b { Primitive(b_) } else { null_primitive }
704758
}
705759

760+
fn array_u8_to_primitive(b []u8) Primitive {
761+
return Primitive(b.map(u8_to_primitive(it)))
762+
}
763+
706764
fn u16_to_primitive(b u16) Primitive {
707765
return Primitive(b)
708766
}
@@ -711,6 +769,10 @@ fn option_u16_to_primitive(b ?u16) Primitive {
711769
return if b_ := b { Primitive(b_) } else { null_primitive }
712770
}
713771

772+
fn array_u16_to_primitive(b []u16) Primitive {
773+
return Primitive(b.map(u16_to_primitive(it)))
774+
}
775+
714776
fn u32_to_primitive(b u32) Primitive {
715777
return Primitive(b)
716778
}
@@ -719,6 +781,10 @@ fn option_u32_to_primitive(b ?u32) Primitive {
719781
return if b_ := b { Primitive(b_) } else { null_primitive }
720782
}
721783

784+
fn array_u32_to_primitive(b []u32) Primitive {
785+
return Primitive(b.map(u32_to_primitive(it)))
786+
}
787+
722788
fn u64_to_primitive(b u64) Primitive {
723789
return Primitive(b)
724790
}
@@ -727,6 +793,10 @@ fn option_u64_to_primitive(b ?u64) Primitive {
727793
return if b_ := b { Primitive(b_) } else { null_primitive }
728794
}
729795

796+
fn array_u64_to_primitive(b []u64) Primitive {
797+
return Primitive(b.map(u64_to_primitive(it)))
798+
}
799+
730800
fn string_to_primitive(b string) Primitive {
731801
return Primitive(b)
732802
}
@@ -735,6 +805,10 @@ fn option_string_to_primitive(b ?string) Primitive {
735805
return if b_ := b { Primitive(b_) } else { null_primitive }
736806
}
737807

808+
fn array_string_to_primitive(b []string) Primitive {
809+
return Primitive(b.map(string_to_primitive(it)))
810+
}
811+
738812
fn time_to_primitive(b time.Time) Primitive {
739813
return Primitive(b)
740814
}
@@ -743,6 +817,10 @@ fn option_time_to_primitive(b ?time.Time) Primitive {
743817
return if b_ := b { Primitive(b_) } else { null_primitive }
744818
}
745819

820+
fn array_time_to_primitive(b []time.Time) Primitive {
821+
return Primitive(b.map(time_to_primitive(it)))
822+
}
823+
746824
fn infix_to_primitive(b InfixType) Primitive {
747825
return Primitive(b)
748826
}

vlib/orm/orm_where_in_test.v

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// vtest flaky: true
2+
// vtest retry: 3
3+
import db.sqlite
4+
5+
struct User {
6+
id int @[primary; sql: serial]
7+
name string
8+
}
9+
10+
fn get_users_in(mut db sqlite.DB, names []string) ![]User {
11+
return sql db {
12+
select from User where name in names
13+
}!
14+
}
15+
16+
fn get_users_not_in(mut db sqlite.DB, names []string) ![]User {
17+
return sql db {
18+
select from User where name !in names
19+
}!
20+
}
21+
22+
fn test_orm_mut_db() {
23+
mut db := sqlite.connect(':memory:') or { panic(err) }
24+
25+
sql db {
26+
create table User
27+
}!
28+
29+
first_user := User{
30+
name: 'first'
31+
}
32+
second_user := User{
33+
name: 'second'
34+
}
35+
36+
sql db {
37+
insert first_user into User
38+
insert second_user into User
39+
}!
40+
41+
in_users := get_users_in(mut db, ['first'])!
42+
43+
assert in_users.len == 1
44+
45+
not_in_users := get_users_not_in(mut db, ['second'])!
46+
47+
assert not_in_users.len == 1
48+
49+
all_users := get_users_in(mut db, ['first', 'second'])!
50+
assert all_users.len == 2
51+
}

vlib/v/gen/c/orm.v

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ fn (mut g Gen) write_orm_primitive(t ast.Type, expr ast.Expr) {
625625
typ = 'option_${typ}'
626626
} else if g.table.final_sym(t).kind == .enum {
627627
typ = g.table.sym(g.table.final_type(t)).cname
628+
} else if g.table.final_sym(t).kind == .array {
629+
typ = g.table.sym(g.table.final_type(t)).cname.to_lower()
628630
}
629631
g.write('orm__${typ}_to_primitive(')
630632
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
778780
.not_is {
779781
'orm__OperationKind__is_not_null'
780782
}
783+
.key_in {
784+
'orm__OperationKind__in'
785+
}
786+
.not_in {
787+
'orm__OperationKind__not_in'
788+
}
781789
else {
782790
''
783791
}

0 commit comments

Comments
 (0)