v4 / vlib / orm / orm_null_test.v
371 lines · 327 sloc · 8.68 KB · f581cbb1c964f89133439f4e303136998ddcfcfb
Raw
1// vtest retry: 3
2import orm
3import db.sqlite
4
5struct MockDBState {
6mut:
7 last string
8 data []orm.Primitive
9 where []orm.Primitive
10}
11
12struct MockDB {
13 use_num bool
14 st &MockDBState = unsafe { nil }
15 db sqlite.DB
16}
17
18fn MockDB.new() &MockDB {
19 return &MockDB{
20 st: &MockDBState{}
21 db: sqlite.connect(':memory:') or { panic(err) }
22 }
23}
24
25fn (db MockDB) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive {
26 mut st := db.st
27 st.last = orm.orm_select_gen(config, '`', false, '?', 5, where)
28 st.data = data.data
29 st.where = where.data
30 return db.db.select(config, data, where)
31}
32
33fn (db MockDB) insert(table orm.Table, data orm.QueryData) ! {
34 mut st := db.st
35 last, qdata :=
36 orm.orm_stmt_gen(.sqlite, table, '`', .insert, false, '?', 1, data, orm.QueryData{})
37 st.last = last
38 st.data = qdata.data
39 st.where = []orm.Primitive{}
40 return db.db.insert(table, data)
41}
42
43fn (db MockDB) update(table orm.Table, data orm.QueryData, where orm.QueryData) ! {
44 mut st := db.st
45 st.last, _ = orm.orm_stmt_gen(.sqlite, table, '`', .update, false, '?', 1, data, where)
46 st.data = data.data
47 st.where = where.data
48 return db.db.update(table, data, where)
49}
50
51fn (db MockDB) delete(table orm.Table, where orm.QueryData) ! {
52 mut st := db.st
53 st.last, _ = orm.orm_stmt_gen(.sqlite, table, '`', .delete, false, '?', 1, orm.QueryData{},
54 where)
55 return db.db.delete(table, where)
56}
57
58const typ_to_typename = {
59 typeof[i8]().idx: 'i8'
60 typeof[i16]().idx: 'i16'
61 typeof[int]().idx: 'int'
62 typeof[i64]().idx: 'i64'
63 typeof[u8]().idx: 'u8'
64 typeof[u16]().idx: 'u16'
65 typeof[u32]().idx: 'u32'
66 typeof[u64]().idx: 'u64'
67 typeof[f32]().idx: 'f32'
68 typeof[f64]().idx: 'f64'
69 typeof[string]().idx: 'string'
70 typeof[bool]().idx: 'bool'
71 orm.serial: 'serial'
72 orm.time_: 'time'
73 orm.enum_: 'enum'
74}
75
76fn mock_type_from_v(typ int) !string {
77 return if typ in typ_to_typename {
78 '${typ_to_typename[typ]}-type'
79 } else {
80 error('unknown type ${typ}')
81 }
82}
83
84fn (db MockDB) create(table orm.Table, fields []orm.TableField) ! {
85 mut st := db.st
86 st.last = orm.orm_table_gen(.sqlite, table, '`', true, 0, fields, mock_type_from_v, false)!
87 return db.db.create(table, fields)
88}
89
90fn (db MockDB) drop(table orm.Table) ! {
91 return db.db.drop(table)
92}
93
94fn (db MockDB) execute(query string) ![]orm.Row {
95 return db.db.execute(query)
96}
97
98fn (db MockDB) last_id() int {
99 return db.db.last_id()
100}
101
102// --
103
104@[table: 'foo']
105struct Foo {
106mut:
107 id u64 @[primary; sql: serial]
108 a string
109 b string @[default: '"yes"']
110 c ?string
111 d ?string = 'hi'
112 e int
113 f int @[default: 33]
114 g ?int
115 h ?int = 55
116}
117
118@[unique_key: 'role_id, api_id, source_type, source_id']
119@[table: 'core_role_api']
120struct CoreRoleApi {
121 role_id string
122 api_id string
123 source_type string
124 source_id string
125}
126
127fn test_struct_unique_key_attribute() {
128 db := MockDB.new()
129
130 sql db {
131 create table CoreRoleApi
132 }!
133 assert db.st.last == 'CREATE TABLE IF NOT EXISTS `core_role_api` (`role_id` string-type NOT NULL, `api_id` string-type NOT NULL, `source_type` string-type NOT NULL, `source_id` string-type NOT NULL, UNIQUE(`role_id`, `api_id`, `source_type`, `source_id`));'
134}
135
136fn test_option_struct_fields_and_none() {
137 db := MockDB.new()
138
139 sql db {
140 create table Foo
141 }!
142 assert db.st.last == 'CREATE TABLE IF NOT EXISTS `foo` (`id` serial-type NOT NULL, `a` string-type NOT NULL, `b` string-type DEFAULT "yes" NOT NULL, `c` string-type, `d` string-type, `e` int-type NOT NULL, `f` int-type DEFAULT 33 NOT NULL, `g` int-type, `h` int-type, PRIMARY KEY(`id`));'
143
144 _ := sql db {
145 select from Foo where e > 5 && c is none && c !is none && h == 2
146 }!
147 assert db.st.last == 'SELECT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `e` > ? AND `c` IS NULL AND `c` IS NOT NULL AND `h` = ?;'
148 assert db.st.data.len == 0
149 assert db.st.where.len == 2
150 assert db.st.where == [orm.Primitive(int(5)), orm.Primitive(int(2))]
151
152 foo := Foo{}
153 sql db {
154 insert foo into Foo
155 }!
156 assert db.st.last == 'INSERT INTO `foo` (`a`, `c`, `d`, `e`, `g`, `h`) VALUES (?, ?, ?, ?, ?, ?);'
157 assert db.st.data.len == 6
158 assert db.st.data == [orm.Primitive(string('')), orm.Null{}, orm.Primitive(string('hi')), int(0),
159 orm.Null{}, int(55)]
160 id := db.last_id()
161
162 res1 := sql db {
163 select from Foo where id == id
164 }!
165 assert db.st.last == 'SELECT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `id` = ?;'
166 assert db.st.data.len == 0
167 assert db.st.where.len == 1
168 assert db.st.where == [orm.Primitive(int(id))]
169 assert res1.len == 1
170 assert res1[0] == Foo{
171 id: 1
172 a: ''
173 b: 'yes'
174 c: none
175 d: 'hi'
176 e: 0
177 f: 33
178 g: none
179 h: 55
180 }
181
182 sql db {
183 update Foo set c = 'yo', d = none, g = 44, h = none where id == id
184 }!
185 assert db.st.last == 'UPDATE `foo` SET `c` = ?, `d` = ?, `g` = ?, `h` = ? WHERE `id` = ?;'
186 assert db.st.data.len == 4
187 assert db.st.data == [orm.Primitive(string('yo')), orm.Null{}, int(44), orm.Null{}]
188 assert db.st.where.len == 1
189 assert db.st.where == [orm.Primitive(int(id))]
190
191 res2 := sql db {
192 select from Foo where id == id
193 }!
194 assert db.st.last == 'SELECT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `id` = ?;'
195 assert db.st.data.len == 0
196 assert db.st.where.len == 1
197 assert db.st.where == [orm.Primitive(int(id))]
198 assert res2.len == 1
199 assert res2[0] == Foo{
200 id: 1
201 a: ''
202 b: 'yes'
203 c: 'yo'
204 d: none
205 e: 0
206 f: 33
207 g: 44
208 h: none
209 }
210
211 _ := sql db {
212 select from Foo where d == nil && c != nil && a == nil
213 }!
214 assert db.st.last == 'SELECT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `d` IS NULL AND `c` IS NOT NULL AND `a` IS NULL;'
215 assert db.st.data.len == 0
216 assert db.st.where.len == 0
217
218 assert sql db {
219 select count from Foo where a == 'yo'
220 }! == 0
221 assert sql db {
222 select count from Foo where b == 'yes'
223 }! == 1
224 assert sql db {
225 select count from Foo where d == 'yo'
226 }! == 0
227 assert sql db {
228 select count from Foo where f == 33
229 }! == 1
230 assert sql db {
231 select count from Foo where c == 'yo'
232 }! == 1
233 assert sql db {
234 select count from Foo where a == ''
235 }! == 1
236 assert sql db {
237 select count from Foo where d == ''
238 }! == 0
239 assert sql db {
240 select count from Foo where c == ''
241 }! == 0
242 assert sql db {
243 select count from Foo where a == nil
244 }! == 0
245 assert sql db {
246 select count from Foo where d == nil
247 }! == 1
248 assert sql db {
249 select count from Foo where c != nil
250 }! == 1
251 assert sql db {
252 select count from Foo where a is none
253 }! == 0
254 assert sql db {
255 select count from Foo where d is none
256 }! == 1
257 assert sql db {
258 select count from Foo where c is none
259 }! == 0
260 assert sql db {
261 select count from Foo where a !is none
262 }! == 1
263 assert sql db {
264 select count from Foo where d !is none
265 }! == 0
266 assert sql db {
267 select count from Foo where c !is none
268 }! == 1
269}
270
271struct Bar {
272 id u64 @[primary; sql: serial]
273 name ?string
274 age int
275}
276
277fn update_bar1(db MockDB, id u64, name ?string) ! {
278 foo := 66
279 sql db {
280 update Bar set name = name, age = age + 3 + foo where id == id
281 }!
282}
283
284fn update_bar2(db MockDB, name ?string, new_name ?string) ! {
285 sql db {
286 update Bar set name = new_name where name == name
287 }!
288}
289
290type NameFn = fn () ?string
291
292fn update_bar3(db MockDB, name_fn NameFn, new_name string) ! {
293 sql db {
294 update Bar set name = new_name where name == name_fn()
295 }!
296}
297
298fn test_inserting_passed_optionals() {
299 db := MockDB.new()
300
301 entry1 := Bar{}
302 entry2 := Bar{
303 name: 'Alice'
304 age: 55
305 }
306 entry3 := Bar{
307 name: 'Bob'
308 age: 66
309 }
310 sql db {
311 create table Bar
312 insert entry1 into Bar
313 insert entry2 into Bar
314 insert entry3 into Bar
315 }!
316
317 update_bar1(db, 2, none)!
318 update_bar1(db, 1, 'hi')!
319
320 res1 := sql db {
321 select from Bar
322 }!
323 assert res1.len == 3
324 assert res1[0].name or { '' } == 'hi'
325 assert res1[1].name == none
326 assert res1[2].name or { '' } == 'Bob'
327
328 update_bar2(db, none, 'xxx')! // no effect (select using "is none", not "== none")
329 update_bar2(db, 'hi', none)!
330
331 res2 := sql db {
332 select from Bar
333 }!
334 assert res2.len == 3
335 assert res2[0].name == none
336 assert res2[1].name == none
337 assert res2[2].name or { '' } == 'Bob'
338
339 update_bar3(db, fn () ?string {
340 return none // no effect (select using "is none", not "== none")
341 }, 'yyy')!
342 update_bar3(db, fn () ?string {
343 return 'Bob'
344 }, 'www')!
345
346 res3 := sql db {
347 select from Bar
348 }!
349 assert res3.len == 3
350 assert res3[0].name == none
351 assert res3[1].name == none
352 assert res3[2].name or { '' } == 'www'
353}
354
355fn test_distinct_select() {
356 db := MockDB.new()
357
358 sql db {
359 create table Foo
360 }!
361
362 _ := sql db {
363 select distinct from Foo
364 }!
365 assert db.st.last == 'SELECT DISTINCT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo`;'
366
367 _ := sql db {
368 select distinct from Foo where e > 5
369 }!
370 assert db.st.last == 'SELECT DISTINCT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `e` > ?;'
371}
372