v2 / vlib / db / pg / pg_orm_test.v
332 lines · 288 sloc · 7.26 KB · cc7fa551fe2aafe2ca055c409f40498e62a70653
Raw
1// vtest build: started_postgres?
2module main
3
4import orm
5import db.pg
6import time
7
8struct TestCustomSqlType {
9 id int @[primary; sql: serial]
10 custom string @[sql_type: 'TEXT']
11 custom1 string @[sql_type: 'VARCHAR(191)']
12 custom2 string @[sql_type: 'TIMESTAMP']
13 custom3 string @[sql_type: 'uuid']
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: 'TIMESTAMP']
29 updated_at string @[sql_type: 'TIMESTAMP']
30 deleted_at time.Time
31}
32
33struct TestDefaultAttribute {
34 id string @[default: 'gen_random_uuid()'; primary; sql_type: 'uuid']
35 name string
36 created_at string @[default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
37}
38
39struct TestInsertDefaultValues {
40 id int @[primary; sql: serial]
41 example string @[default: '']
42}
43
44@[comment: 'This is a table comment']
45struct TestCommentAttribute {
46 id string @[primary; sql: serial]
47 name string @[comment: 'real user name']
48 created_at string @[default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
49}
50
51fn test_pg_orm() {
52 $if !network ? {
53 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
54 eprintln('> This test requires a working postgres server running on localhost.')
55 return
56 }
57 mut db := pg.connect(
58 host: 'localhost'
59 user: 'postgres'
60 password: '12345678'
61 dbname: 'postgres'
62 ) or { panic(err) }
63
64 defer {
65 db.close() or {}
66 }
67 db.exec('create extension if not exists pgcrypto') or { panic(err) }
68 table := orm.Table{
69 name: 'Test'
70 }
71 db.drop(table) or {}
72
73 db.create(table, [
74 orm.TableField{
75 name: 'id'
76 typ: typeof[string]().idx
77 // is_time: false
78 default_val: ''
79 is_arr: false
80 attrs: [
81 VAttribute{
82 name: 'primary'
83 has_arg: false
84 arg: ''
85 kind: .plain
86 },
87 VAttribute{
88 name: 'sql'
89 has_arg: true
90 arg: 'serial'
91 kind: .plain
92 },
93 ]
94 },
95 orm.TableField{
96 name: 'name'
97 typ: typeof[string]().idx
98 // is_time: false
99 default_val: ''
100 is_arr: false
101 attrs: []
102 },
103 orm.TableField{
104 name: 'age'
105 typ: typeof[i64]().idx
106 // is_time: false
107 default_val: ''
108 is_arr: false
109 attrs: []
110 },
111 ]) or { panic(err) }
112
113 db.insert(table, orm.QueryData{
114 fields: ['name', 'age']
115 data: [orm.string_to_primitive('Louis'), orm.int_to_primitive(101)]
116 }) or { panic(err) }
117
118 res := db.select(orm.SelectConfig{
119 table: table
120 aggregate_kind: .none
121 has_where: true
122 has_order: false
123 order: ''
124 order_type: .asc
125 has_limit: false
126 primary: 'id'
127 has_offset: false
128 fields: ['id', 'name', 'age']
129 types: [typeof[int]().idx, typeof[string]().idx, typeof[i64]().idx]
130 }, orm.QueryData{}, orm.QueryData{
131 fields: ['name', 'age']
132 data: [orm.Primitive('Louis'), orm.Primitive(101)]
133 types: []
134 kinds: [.eq, .eq]
135 is_and: [true]
136 }) or { panic(err) }
137
138 id := res[0][0]
139 name := res[0][1]
140 age := res[0][2]
141
142 assert id is int
143 if id is int {
144 assert id == 1
145 }
146
147 assert name is string
148 if name is string {
149 assert name == 'Louis'
150 }
151
152 assert age is i64
153 if age is i64 {
154 assert age == 101
155 }
156
157 /** test orm sql type
158 * - verify if all type create by attribute sql_type has created
159 */
160 sql db {
161 drop table TestCustomSqlType
162 } or {}
163
164 sql db {
165 create table TestCustomSqlType
166 }!
167
168 mut result_custom_sql := db.exec("
169 SELECT DATA_TYPE
170 FROM INFORMATION_SCHEMA.COLUMNS
171 WHERE TABLE_NAME = 'testcustomsqltype'
172 ORDER BY ORDINAL_POSITION
173 ") or {
174 println(err)
175 panic(err)
176 }
177 mut information_schema_data_types_results := []string{}
178 information_schema_custom_sql := ['integer', 'text', 'character varying',
179 'timestamp without time zone', 'uuid']
180
181 for data_type in result_custom_sql {
182 x := data_type.vals[0]
183 information_schema_data_types_results << x?
184 }
185
186 assert information_schema_data_types_results == information_schema_custom_sql
187
188 /** test_orm_time_type
189 * - test time.Time v type with sql_type: 'TIMESTAMP'
190 * - test string v type with sql_type: 'TIMESTAMP'
191 * - test time.Time v type without
192 */
193 today := time.parse('2022-07-16 15:13:27') or {
194 println(err)
195 panic(err)
196 }
197
198 model := TestTimeType{
199 username: 'hitalo'
200 created_at: today
201 updated_at: today.str()
202 deleted_at: today
203 }
204
205 sql db {
206 create table TestTimeType
207 }!
208
209 sql db {
210 insert model into TestTimeType
211 }!
212
213 results := sql db {
214 select from TestTimeType where username == 'hitalo'
215 }!
216
217 sql db {
218 drop table TestTimeType
219 }!
220
221 assert results[0].username == model.username
222 assert results[0].created_at == model.created_at
223 assert results[0].updated_at == model.updated_at
224 assert results[0].deleted_at == model.deleted_at
225
226 /** test default attribute
227 */
228 sql db {
229 create table TestDefaultAttribute
230 }!
231
232 mut result_defaults := db.exec("
233 SELECT column_default
234 FROM INFORMATION_SCHEMA.COLUMNS
235 WHERE TABLE_NAME = 'testdefaultattribute'
236 ORDER BY ORDINAL_POSITION
237 ") or {
238 println(err)
239 panic(err)
240 }
241 mut information_schema_defaults_results := []string{}
242
243 for defaults in result_defaults {
244 x := defaults.vals[0]
245 information_schema_defaults_results << x or { '' }
246 }
247 sql db {
248 drop table TestDefaultAttribute
249 }!
250 assert ['gen_random_uuid()', '', 'CURRENT_TIMESTAMP'] == information_schema_defaults_results
251
252 /** test inserting only default values
253 */
254 sql db {
255 create table TestInsertDefaultValues
256 }!
257
258 model_default_values := TestInsertDefaultValues{
259 example: ''
260 }
261
262 sql db {
263 insert model_default_values into TestInsertDefaultValues
264 }!
265
266 inserted_default_values := sql db {
267 select from TestInsertDefaultValues
268 }!
269
270 sql db {
271 drop table TestInsertDefaultValues
272 }!
273
274 assert inserted_default_values.len == 1
275 assert inserted_default_values[0].example == ''
276
277 /** test comment attribute
278 */
279 sql db {
280 create table TestCommentAttribute
281 }!
282
283 mut column_comments := db.exec("
284 SELECT
285 a.attname AS column_name,
286 col_description(a.attrelid, a.attnum) AS column_comment
287 FROM pg_attribute a
288 JOIN pg_class c ON c.oid = a.attrelid
289 JOIN pg_namespace n ON n.oid = c.relnamespace
290 WHERE c.relname = 'testcommentattribute'
291 AND n.nspname = 'public'
292 AND a.attnum > 0
293 AND NOT a.attisdropped
294 ORDER BY a.attnum
295 ") or {
296 println(err)
297 panic(err)
298 }
299
300 mut table_comment := db.exec("
301 SELECT
302 nspname AS schema_name,
303 relname AS table_name,
304 obj_description(pc.oid) AS table_comment
305 FROM pg_class pc
306 JOIN pg_namespace pn ON pn.oid = pc.relnamespace
307 WHERE pc.relkind = 'r' AND pc.relname = 'testcommentattribute'
308 ORDER BY schema_name, table_name
309 ") or {
310 println(err)
311 panic(err)
312 }
313
314 sql db {
315 drop table TestCommentAttribute
316 }!
317
318 mut information_schema_column_comment_results := []string{}
319
320 for comment in column_comments {
321 x := comment.vals[1]
322 information_schema_column_comment_results << x or { '' }
323 }
324 assert information_schema_column_comment_results == ['', 'real user name', '']
325
326 mut information_schema_table_comment_result := []string{}
327 for comment in table_comment {
328 x := comment.vals[2]
329 information_schema_table_comment_result << x or { '' }
330 }
331 assert information_schema_table_comment_result == ['This is a table comment']
332}
333