v2 / vlib / db / pg / orm.v
391 lines · 360 sloc · 9.25 KB · 3c0c27933ec8efde92625344dbfb286f4e7407bc
Raw
1module pg
2
3import orm
4import time
5import net.conv
6
7// sql expr
8
9// select is used internally by V's ORM for processing `SELECT ` queries
10pub fn (db DB) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive {
11 where_with_tenant := orm.apply_tenant_filter(config.table, where)
12 query := orm.orm_select_gen(config, '"', true, '$', 1, where_with_tenant)
13
14 rows := pg_stmt_worker(db, query, where_with_tenant, data)!
15
16 mut ret := [][]orm.Primitive{}
17
18 for row in rows {
19 mut row_data := []orm.Primitive{}
20 for i, val in row.vals {
21 row_data << val_to_primitive(val, config.types[i])!
22 }
23 ret << row_data
24 }
25
26 return ret
27}
28
29// sql stmt
30
31// insert is used internally by V's ORM for processing `INSERT ` queries
32pub fn (db DB) insert(table orm.Table, data orm.QueryData) ! {
33 query, converted_data :=
34 orm.orm_stmt_gen(.pg, table, '"', .insert, true, '$', 1, data, orm.QueryData{})
35 pg_stmt_worker(db, query, converted_data, orm.QueryData{})!
36}
37
38// update is used internally by V's ORM for processing `UPDATE ` queries
39pub fn (db DB) update(table orm.Table, data orm.QueryData, where orm.QueryData) ! {
40 where_with_tenant := orm.apply_tenant_filter(table, where)
41 query, _ := orm.orm_stmt_gen(.default, table, '"', .update, true, '$', 1, data,
42 where_with_tenant)
43 pg_stmt_worker(db, query, data, where_with_tenant)!
44}
45
46// delete is used internally by V's ORM for processing `DELETE ` queries
47pub fn (db DB) delete(table orm.Table, where orm.QueryData) ! {
48 where_with_tenant := orm.apply_tenant_filter(table, where)
49 query, _ := orm.orm_stmt_gen(.default, table, '"', .delete, true, '$', 1, orm.QueryData{},
50 where_with_tenant)
51 pg_stmt_worker(db, query, orm.QueryData{}, where_with_tenant)!
52}
53
54// last_id is used internally by V's ORM for post-processing `INSERT ` queries
55pub fn (db DB) last_id() int {
56 query := 'SELECT LASTVAL();'
57
58 return db.q_int(query) or { 0 }
59}
60
61// DDL (table creation/destroying etc)
62
63// create is used internally by V's ORM for processing table creation queries (DDL)
64pub fn (db DB) create(table orm.Table, fields []orm.TableField) ! {
65 query := orm.orm_table_gen(.pg, table, '"', true, 0, fields, pg_type_from_v, false) or {
66 return err
67 }
68 stmts := query.split(';')
69 for stmt in stmts {
70 if stmt != '' {
71 pg_stmt_worker(db, stmt + ';', orm.QueryData{}, orm.QueryData{})!
72 }
73 }
74}
75
76// drop is used internally by V's ORM for processing table destroying queries (DDL)
77pub fn (db DB) drop(table orm.Table) ! {
78 query := 'DROP TABLE "${table.name}";'
79 pg_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})!
80}
81
82// orm_begin starts a transaction for ORM helpers.
83pub fn (db DB) orm_begin() ! {
84 db.begin()!
85}
86
87// orm_commit commits a transaction for ORM helpers.
88pub fn (db DB) orm_commit() ! {
89 db.commit()!
90}
91
92// orm_rollback rolls back a transaction for ORM helpers.
93pub fn (db DB) orm_rollback() ! {
94 db.rollback()!
95}
96
97// orm_savepoint creates a savepoint for ORM helpers.
98pub fn (db DB) orm_savepoint(name string) ! {
99 db.savepoint(name)!
100}
101
102// orm_rollback_to rolls back to a savepoint for ORM helpers.
103pub fn (db DB) orm_rollback_to(name string) ! {
104 db.rollback_to(name)!
105}
106
107// orm_release_savepoint releases a savepoint for ORM helpers.
108pub fn (db DB) orm_release_savepoint(name string) ! {
109 db.release_savepoint(name)!
110}
111
112// utils
113
114fn pg_stmt_binder(mut types []u32, mut vals []&char, mut lens []int, mut formats []int, d orm.QueryData) {
115 for data in d.data {
116 pg_stmt_match(mut types, mut vals, mut lens, mut formats, data)
117 }
118}
119
120fn pg_stmt_match_array[T](mut types []u32, mut vals []&char, mut lens []int, mut formats []int, data []T) {
121 for element in data {
122 pg_stmt_match(mut types, mut vals, mut lens, mut formats, orm.Primitive(element))
123 }
124}
125
126fn pg_stmt_match(mut types []u32, mut vals []&char, mut lens []int, mut formats []int, data orm.Primitive) {
127 match data {
128 bool {
129 types << u32(Oid.t_bool)
130 vals << &char(&data)
131 lens << int(sizeof(bool))
132 formats << 1
133 }
134 u8 {
135 types << u32(Oid.t_char)
136 vals << &char(&data)
137 lens << int(sizeof(u8))
138 formats << 1
139 }
140 u16 {
141 types << u32(Oid.t_int2)
142 num := conv.hton16(data)
143 vals << &char(&num)
144 lens << int(sizeof(u16))
145 formats << 1
146 }
147 u32 {
148 types << u32(Oid.t_int4)
149 num := conv.hton32(data)
150 vals << &char(&num)
151 lens << int(sizeof(u32))
152 formats << 1
153 }
154 u64 {
155 types << u32(Oid.t_int8)
156 num := conv.hton64(data)
157 vals << &char(&num)
158 lens << int(sizeof(u64))
159 formats << 1
160 }
161 i8 {
162 types << u32(Oid.t_char)
163 vals << &char(&data)
164 lens << int(sizeof(i8))
165 formats << 1
166 }
167 i16 {
168 types << u32(Oid.t_int2)
169 num := conv.hton16(u16(data))
170 vals << &char(&num)
171 lens << int(sizeof(i16))
172 formats << 1
173 }
174 int {
175 types << u32(Oid.t_int4)
176 num := conv.hton32(u32(data))
177 vals << &char(&num)
178 lens << int(sizeof(int))
179 formats << 1
180 }
181 i64 {
182 types << u32(Oid.t_int8)
183 num := conv.hton64(u64(data))
184 vals << &char(&num)
185 lens << int(sizeof(i64))
186 formats << 1
187 }
188 f32 {
189 types << u32(Oid.t_float4)
190 num := conv.htonf32(f32(data))
191 vals << &char(&num)
192 lens << int(sizeof(f32))
193 formats << 1
194 }
195 f64 {
196 types << u32(Oid.t_float8)
197 num := conv.htonf64(f64(data))
198 vals << &char(&num)
199 lens << int(sizeof(f64))
200 formats << 1
201 }
202 string {
203 // If paramTypes is NULL, or any particular element in the array is zero,
204 // the server infers a data type for the parameter symbol in the same way
205 // it would do for an untyped literal string.
206 types << u32(0)
207 vals << &char(data.str)
208 lens << data.len
209 formats << 0
210 }
211 time.Time {
212 datetime := data.format_ss()
213 types << u32(0)
214 vals << &char(datetime.str)
215 lens << datetime.len
216 formats << 0
217 }
218 orm.InfixType {
219 pg_stmt_match(mut types, mut vals, mut lens, mut formats, data.right)
220 }
221 orm.Null {
222 types << u32(0) // we do not know col type, let server infer
223 vals << &char(unsafe { nil }) // NULL pointer indicates NULL
224 lens << int(0) // ignored
225 formats << 0 // ignored
226 }
227 []orm.Primitive {
228 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
229 }
230 []bool {
231 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
232 }
233 []f32 {
234 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
235 }
236 []f64 {
237 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
238 }
239 []i16 {
240 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
241 }
242 []i64 {
243 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
244 }
245 []i8 {
246 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
247 }
248 []int {
249 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
250 }
251 []string {
252 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
253 }
254 []time.Time {
255 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
256 }
257 []u16 {
258 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
259 }
260 []u32 {
261 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
262 }
263 []u64 {
264 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
265 }
266 []u8 {
267 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
268 }
269 []orm.InfixType {
270 pg_stmt_match_array(mut types, mut vals, mut lens, mut formats, data)
271 }
272 }
273}
274
275fn pg_type_from_v(typ int) !string {
276 str := match typ {
277 orm.type_idx['i8'], orm.type_idx['i16'], orm.type_idx['u8'], orm.type_idx['u16'] {
278 'SMALLINT'
279 }
280 orm.type_idx['bool'] {
281 'BOOLEAN'
282 }
283 orm.type_idx['int'], orm.type_idx['u32'] {
284 'INT'
285 }
286 orm.time_ {
287 'TIMESTAMP'
288 }
289 orm.enum_ {
290 'BIGINT'
291 }
292 orm.type_idx['i64'], orm.type_idx['u64'] {
293 'BIGINT'
294 }
295 orm.float[0] {
296 'REAL'
297 }
298 orm.float[1] {
299 'DOUBLE PRECISION'
300 }
301 orm.type_string {
302 'TEXT'
303 }
304 orm.serial {
305 'SERIAL'
306 }
307 else {
308 ''
309 }
310 }
311
312 if str == '' {
313 return error('Unknown type ${typ}')
314 }
315 return str
316}
317
318fn val_to_primitive(val ?string, typ int) !orm.Primitive {
319 if str := val {
320 match typ {
321 // bool
322 orm.type_idx['bool'] {
323 return orm.Primitive(str == 't')
324 }
325 // i8
326 orm.type_idx['i8'] {
327 return orm.Primitive(str.i8())
328 }
329 // i16
330 orm.type_idx['i16'] {
331 return orm.Primitive(str.i16())
332 }
333 // int
334 orm.type_idx['int'] {
335 return orm.Primitive(str.int())
336 }
337 // i64
338 orm.type_idx['i64'] {
339 return orm.Primitive(str.i64())
340 }
341 // u8
342 orm.type_idx['u8'] {
343 data := str.i8()
344 return orm.Primitive(*unsafe { &u8(&data) })
345 }
346 // u16
347 orm.type_idx['u16'] {
348 data := str.i16()
349 return orm.Primitive(*unsafe { &u16(&data) })
350 }
351 // u32
352 orm.type_idx['u32'] {
353 data := str.int()
354 return orm.Primitive(*unsafe { &u32(&data) })
355 }
356 // u64
357 orm.type_idx['u64'] {
358 data := str.i64()
359 return orm.Primitive(*unsafe { &u64(&data) })
360 }
361 // f32
362 orm.type_idx['f32'] {
363 return orm.Primitive(str.f32())
364 }
365 // f64
366 orm.type_idx['f64'] {
367 return orm.Primitive(str.f64())
368 }
369 orm.type_string {
370 return orm.Primitive(str)
371 }
372 orm.time_ {
373 if str.contains_any(' /:-') {
374 date_time_str := time.parse(str)!
375 return orm.Primitive(date_time_str)
376 }
377
378 timestamp := str.int()
379 return orm.Primitive(time.unix(timestamp))
380 }
381 orm.enum_ {
382 return orm.Primitive(str.i64())
383 }
384 else {}
385 }
386
387 return error('Unknown field type ${typ}')
388 } else {
389 return orm.Null{}
390 }
391}
392