v / vlib / orm / orm_null_test.v
367 lines · 324 sloc · 8.6 KB · 010335d971c98bcab8b52f1ab08173152eeeff70
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) last_id() int {
95 return db.db.last_id()
96}
97
98// --
99
100@[table: 'foo']
101struct Foo {
102mut:
103 id u64 @[primary; sql: serial]
104 a string
105 b string @[default: '"yes"']
106 c ?string
107 d ?string = 'hi'
108 e int
109 f int @[default: 33]
110 g ?int
111 h ?int = 55
112}
113
114@[unique_key: 'role_id, api_id, source_type, source_id']
115@[table: 'core_role_api']
116struct CoreRoleApi {
117 role_id string
118 api_id string
119 source_type string
120 source_id string
121}
122
123fn test_struct_unique_key_attribute() {
124 db := MockDB.new()
125
126 sql db {
127 create table CoreRoleApi
128 }!
129 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`));'
130}
131
132fn test_option_struct_fields_and_none() {
133 db := MockDB.new()
134
135 sql db {
136 create table Foo
137 }!
138 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`));'
139
140 _ := sql db {
141 select from Foo where e > 5 && c is none && c !is none && h == 2
142 }!
143 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` = ?;'
144 assert db.st.data.len == 0
145 assert db.st.where.len == 2
146 assert db.st.where == [orm.Primitive(int(5)), orm.Primitive(int(2))]
147
148 foo := Foo{}
149 sql db {
150 insert foo into Foo
151 }!
152 assert db.st.last == 'INSERT INTO `foo` (`a`, `c`, `d`, `e`, `g`, `h`) VALUES (?, ?, ?, ?, ?, ?);'
153 assert db.st.data.len == 6
154 assert db.st.data == [orm.Primitive(string('')), orm.Null{}, orm.Primitive(string('hi')), int(0),
155 orm.Null{}, int(55)]
156 id := db.last_id()
157
158 res1 := sql db {
159 select from Foo where id == id
160 }!
161 assert db.st.last == 'SELECT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `id` = ?;'
162 assert db.st.data.len == 0
163 assert db.st.where.len == 1
164 assert db.st.where == [orm.Primitive(int(id))]
165 assert res1.len == 1
166 assert res1[0] == Foo{
167 id: 1
168 a: ''
169 b: 'yes'
170 c: none
171 d: 'hi'
172 e: 0
173 f: 33
174 g: none
175 h: 55
176 }
177
178 sql db {
179 update Foo set c = 'yo', d = none, g = 44, h = none where id == id
180 }!
181 assert db.st.last == 'UPDATE `foo` SET `c` = ?, `d` = ?, `g` = ?, `h` = ? WHERE `id` = ?;'
182 assert db.st.data.len == 4
183 assert db.st.data == [orm.Primitive(string('yo')), orm.Null{}, int(44), orm.Null{}]
184 assert db.st.where.len == 1
185 assert db.st.where == [orm.Primitive(int(id))]
186
187 res2 := sql db {
188 select from Foo where id == id
189 }!
190 assert db.st.last == 'SELECT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `id` = ?;'
191 assert db.st.data.len == 0
192 assert db.st.where.len == 1
193 assert db.st.where == [orm.Primitive(int(id))]
194 assert res2.len == 1
195 assert res2[0] == Foo{
196 id: 1
197 a: ''
198 b: 'yes'
199 c: 'yo'
200 d: none
201 e: 0
202 f: 33
203 g: 44
204 h: none
205 }
206
207 _ := sql db {
208 select from Foo where d == nil && c != nil && a == nil
209 }!
210 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;'
211 assert db.st.data.len == 0
212 assert db.st.where.len == 0
213
214 assert sql db {
215 select count from Foo where a == 'yo'
216 }! == 0
217 assert sql db {
218 select count from Foo where b == 'yes'
219 }! == 1
220 assert sql db {
221 select count from Foo where d == 'yo'
222 }! == 0
223 assert sql db {
224 select count from Foo where f == 33
225 }! == 1
226 assert sql db {
227 select count from Foo where c == 'yo'
228 }! == 1
229 assert sql db {
230 select count from Foo where a == ''
231 }! == 1
232 assert sql db {
233 select count from Foo where d == ''
234 }! == 0
235 assert sql db {
236 select count from Foo where c == ''
237 }! == 0
238 assert sql db {
239 select count from Foo where a == nil
240 }! == 0
241 assert sql db {
242 select count from Foo where d == nil
243 }! == 1
244 assert sql db {
245 select count from Foo where c != nil
246 }! == 1
247 assert sql db {
248 select count from Foo where a is none
249 }! == 0
250 assert sql db {
251 select count from Foo where d is none
252 }! == 1
253 assert sql db {
254 select count from Foo where c is none
255 }! == 0
256 assert sql db {
257 select count from Foo where a !is none
258 }! == 1
259 assert sql db {
260 select count from Foo where d !is none
261 }! == 0
262 assert sql db {
263 select count from Foo where c !is none
264 }! == 1
265}
266
267struct Bar {
268 id u64 @[primary; sql: serial]
269 name ?string
270 age int
271}
272
273fn update_bar1(db MockDB, id u64, name ?string) ! {
274 foo := 66
275 sql db {
276 update Bar set name = name, age = age + 3 + foo where id == id
277 }!
278}
279
280fn update_bar2(db MockDB, name ?string, new_name ?string) ! {
281 sql db {
282 update Bar set name = new_name where name == name
283 }!
284}
285
286type NameFn = fn () ?string
287
288fn update_bar3(db MockDB, name_fn NameFn, new_name string) ! {
289 sql db {
290 update Bar set name = new_name where name == name_fn()
291 }!
292}
293
294fn test_inserting_passed_optionals() {
295 db := MockDB.new()
296
297 entry1 := Bar{}
298 entry2 := Bar{
299 name: 'Alice'
300 age: 55
301 }
302 entry3 := Bar{
303 name: 'Bob'
304 age: 66
305 }
306 sql db {
307 create table Bar
308 insert entry1 into Bar
309 insert entry2 into Bar
310 insert entry3 into Bar
311 }!
312
313 update_bar1(db, 2, none)!
314 update_bar1(db, 1, 'hi')!
315
316 res1 := sql db {
317 select from Bar
318 }!
319 assert res1.len == 3
320 assert res1[0].name or { '' } == 'hi'
321 assert res1[1].name == none
322 assert res1[2].name or { '' } == 'Bob'
323
324 update_bar2(db, none, 'xxx')! // no effect (select using "is none", not "== none")
325 update_bar2(db, 'hi', none)!
326
327 res2 := sql db {
328 select from Bar
329 }!
330 assert res2.len == 3
331 assert res2[0].name == none
332 assert res2[1].name == none
333 assert res2[2].name or { '' } == 'Bob'
334
335 update_bar3(db, fn () ?string {
336 return none // no effect (select using "is none", not "== none")
337 }, 'yyy')!
338 update_bar3(db, fn () ?string {
339 return 'Bob'
340 }, 'www')!
341
342 res3 := sql db {
343 select from Bar
344 }!
345 assert res3.len == 3
346 assert res3[0].name == none
347 assert res3[1].name == none
348 assert res3[2].name or { '' } == 'www'
349}
350
351fn test_distinct_select() {
352 db := MockDB.new()
353
354 sql db {
355 create table Foo
356 }!
357
358 _ := sql db {
359 select distinct from Foo
360 }!
361 assert db.st.last == 'SELECT DISTINCT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo`;'
362
363 _ := sql db {
364 select distinct from Foo where e > 5
365 }!
366 assert db.st.last == 'SELECT DISTINCT `id`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` FROM `foo` WHERE `e` > ?;'
367}
368