v2 / vlib / db / mysql / mysql_orm_test.v
361 lines · 323 sloc · 7.69 KB · 4118ee464d0c8849b18e6108f77f2871b29430e4
Raw
1// vtest build: started_mysqld?
2import orm
3import db.mysql
4import time
5
6struct TestCustomSqlType {
7 id int @[primary; sql: serial]
8 custom string @[sql_type: 'TEXT']
9 custom1 string @[sql_type: 'VARCHAR(191)']
10 custom2 string @[sql_type: 'datetime(3)']
11 custom3 string @[sql_type: 'MEDIUMINT']
12 custom4 string @[sql_type: 'DATETIME']
13 custom5 string @[sql_type: 'datetime']
14}
15
16struct TestCustomWrongSqlType {
17 id int @[primary; sql: serial]
18 custom string
19 custom1 string @[sql_type: 'VARCHAR']
20 custom2 string @[sql_type: 'money']
21 custom3 string @[sql_type: 'xml']
22}
23
24struct TestTimeType {
25mut:
26 id int @[primary; sql: serial]
27 username string
28 created_at time.Time @[sql_type: 'DATETIME']
29 updated_at string @[sql_type: 'DATETIME']
30 deleted_at time.Time
31 null_date ?time.Time @[sql_type: 'DATETIME']
32}
33
34struct TestDefaultAttribute {
35 id string @[primary; sql: serial]
36 name string
37 created_at string @[default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
38}
39
40@[comment: 'This is a table comment']
41struct TestCommentAttribute {
42 id string @[primary; sql: serial]
43 name string @[comment: 'real user name']
44 created_at string @[default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
45}
46
47fn test_mysql_orm() {
48 $if !network ? {
49 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
50 eprintln('> This test requires a working mysql server running on localhost.')
51 return
52 }
53 mut db := mysql.connect(
54 host: '127.0.0.1'
55 port: 3306
56 username: 'root'
57 password: '12345678'
58 dbname: 'mysql'
59 )!
60 defer {
61 db.close() or {}
62 }
63 table := orm.Table{
64 name: 'Test'
65 }
66 db.drop(table) or {}
67 db.create(table, [
68 orm.TableField{
69 name: 'id'
70 typ: typeof[int]().idx
71 attrs: [
72 VAttribute{
73 name: 'primary'
74 },
75 VAttribute{
76 name: 'sql'
77 has_arg: true
78 kind: .plain
79 arg: 'serial'
80 },
81 ]
82 },
83 orm.TableField{
84 name: 'name'
85 typ: typeof[string]().idx
86 attrs: []
87 },
88 orm.TableField{
89 name: 'age'
90 typ: typeof[int]().idx
91 },
92 ]) or { panic(err) }
93
94 db.insert(table, orm.QueryData{
95 fields: ['name', 'age']
96 data: [orm.string_to_primitive('Louis'), orm.int_to_primitive(101)]
97 }) or { panic(err) }
98
99 res := db.select(orm.SelectConfig{
100 table: table
101 has_where: true
102 fields: ['id', 'name', 'age']
103 types: [typeof[int]().idx, typeof[string]().idx, typeof[i64]().idx]
104 }, orm.QueryData{}, orm.QueryData{
105 fields: ['name', 'age']
106 data: [orm.Primitive('Louis'), i64(101)]
107 types: [typeof[string]().idx, typeof[i64]().idx]
108 is_and: [true, true]
109 kinds: [.eq, .eq]
110 }) or { panic(err) }
111
112 id := res[0][0]
113 name := res[0][1]
114 age := res[0][2]
115
116 assert id is int
117 if id is int {
118 assert id == 1
119 }
120
121 assert name is string
122 if name is string {
123 assert name == 'Louis'
124 }
125
126 assert age is i64
127 if age is i64 {
128 assert age == 101
129 }
130
131 sum_res := db.select(orm.SelectConfig{
132 table: table
133 aggregate_kind: .sum
134 aggregate_field: 'age'
135 fields: ['age']
136 types: [typeof[int]().idx]
137 }, orm.QueryData{}, orm.QueryData{}) or { panic(err) }
138 assert sum_res.len == 1
139 assert sum_res[0].len == 1
140 sum_val := sum_res[0][0]
141 assert sum_val is int
142 if sum_val is int {
143 assert sum_val == 101
144 }
145
146 avg_res := db.select(orm.SelectConfig{
147 table: table
148 aggregate_kind: .avg
149 aggregate_field: 'age'
150 fields: ['age']
151 types: [typeof[f64]().idx]
152 }, orm.QueryData{}, orm.QueryData{}) or { panic(err) }
153 assert avg_res.len == 1
154 assert avg_res[0].len == 1
155 avg_val := avg_res[0][0]
156 assert avg_val is f64
157 if avg_val is f64 {
158 assert avg_val == 101.0
159 }
160
161 /** test orm sql type
162 * - verify if all type create by attribute sql_type has created
163 */
164 sql db {
165 create table TestCustomSqlType
166 }!
167
168 mut result_custom_sql := db.query("
169 SELECT DATA_TYPE, COLUMN_TYPE
170 FROM INFORMATION_SCHEMA.COLUMNS
171 WHERE TABLE_NAME = 'testcustomsqltype'
172 ORDER BY ORDINAL_POSITION
173 ") or {
174 panic(err)
175 }
176
177 information_schema_custom_sql := [
178 {
179 'DATA_TYPE': 'bigint'
180 'COLUMN_TYPE': 'bigint unsigned'
181 },
182 {
183 'DATA_TYPE': 'text'
184 'COLUMN_TYPE': 'text'
185 },
186 {
187 'DATA_TYPE': 'varchar'
188 'COLUMN_TYPE': 'varchar(191)'
189 },
190 {
191 'DATA_TYPE': 'datetime'
192 'COLUMN_TYPE': 'datetime(3)'
193 },
194 {
195 'DATA_TYPE': 'mediumint'
196 'COLUMN_TYPE': 'mediumint'
197 },
198 {
199 'DATA_TYPE': 'datetime'
200 'COLUMN_TYPE': 'datetime'
201 },
202 {
203 'DATA_TYPE': 'datetime'
204 'COLUMN_TYPE': 'datetime'
205 },
206 ]
207
208 sql db {
209 drop table TestCustomSqlType
210 }!
211
212 assert result_custom_sql.maps() == information_schema_custom_sql
213
214 /** test_orm_time_type
215 * - test time.Time v type with sql_type: 'TIMESTAMP'
216 * - test string v type with sql_type: 'TIMESTAMP'
217 * - test time.Time v type without
218 */
219 today := time.parse('2022-07-16 15:13:27') or {
220 println(err)
221 panic(err)
222 }
223
224 model1 := TestTimeType{
225 username: 'hitalo'
226 created_at: today
227 updated_at: today.str()
228 deleted_at: today
229 // null_date is null
230 }
231 model2 := TestTimeType{
232 username: 'tom'
233 created_at: today
234 updated_at: today.str()
235 deleted_at: today
236 null_date: today
237 }
238 model3 := TestTimeType{
239 username: 'kitty'
240 created_at: today
241 updated_at: today.str()
242 deleted_at: today
243 // null_date is null
244 }
245
246 sql db {
247 create table TestTimeType
248 }!
249
250 sql db {
251 insert model1 into TestTimeType
252 insert model2 into TestTimeType
253 insert model3 into TestTimeType
254 }!
255
256 results := sql db {
257 select from TestTimeType
258 }!
259
260 sql db {
261 drop table TestTimeType
262 }!
263
264 assert results[0].created_at == model1.created_at
265 assert results[0].username == model1.username
266 assert results[0].updated_at == model1.updated_at
267 assert results[0].deleted_at == model1.deleted_at
268 assert results[0].null_date == none
269
270 assert results[1].created_at == model2.created_at
271 assert results[1].username == model2.username
272 assert results[1].updated_at == model2.updated_at
273 assert results[1].deleted_at == model2.deleted_at
274 if x := results[1].null_date {
275 // should not by `none`/`NULL`
276 assert x == model2.deleted_at
277 } else {
278 assert false
279 }
280
281 assert results[2].created_at == model3.created_at
282 assert results[2].username == model3.username
283 assert results[2].updated_at == model3.updated_at
284 assert results[2].deleted_at == model3.deleted_at
285 assert results[2].null_date == none
286
287 /** test default attribute
288 */
289 sql db {
290 create table TestDefaultAttribute
291 }!
292
293 mut result_defaults := db.query("
294 SELECT COLUMN_DEFAULT
295 FROM INFORMATION_SCHEMA.COLUMNS
296 WHERE TABLE_NAME = 'testdefaultattribute'
297 ORDER BY ORDINAL_POSITION
298 ") or {
299 println(err)
300 panic(err)
301 }
302 mut information_schema_defaults_results := []string{}
303
304 sql db {
305 drop table TestDefaultAttribute
306 }!
307
308 information_schema_column_default_sql := [{
309 'COLUMN_DEFAULT': ''
310 }, {
311 'COLUMN_DEFAULT': ''
312 }, {
313 'COLUMN_DEFAULT': 'CURRENT_TIMESTAMP'
314 }]
315 assert information_schema_column_default_sql == result_defaults.maps()
316
317 /** test comment attribute
318 */
319 sql db {
320 create table TestCommentAttribute
321 }!
322
323 mut column_comments := db.query("
324 SELECT COLUMN_COMMENT
325 FROM INFORMATION_SCHEMA.COLUMNS
326 WHERE TABLE_NAME = 'testcommentattribute'
327 ORDER BY ORDINAL_POSITION
328 ") or {
329 println(err)
330 panic(err)
331 }
332
333 mut table_comment := db.query("
334 SELECT TABLE_COMMENT
335 FROM INFORMATION_SCHEMA.TABLES
336 WHERE TABLE_NAME = 'testcommentattribute'
337 ") or {
338 println(err)
339 panic(err)
340 }
341
342 sql db {
343 drop table TestCommentAttribute
344 }!
345
346 information_schema_column_comment_sql := [{
347 'COLUMN_COMMENT': ''
348 }, {
349 'COLUMN_COMMENT': 'real user name'
350 }, {
351 'COLUMN_COMMENT': ''
352 }]
353 assert information_schema_column_comment_sql == column_comments.maps()
354
355 information_schema_table_comment_sql := [
356 {
357 'TABLE_COMMENT': 'This is a table comment'
358 },
359 ]
360 assert information_schema_table_comment_sql == table_comment.maps()
361}
362