aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/old/vlib/sqlite/orm.v
blob: a1df1c779384593016a232b931aa6e324f69f7a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
module sqlite

import orm
import time

// sql expr

pub fn (db DB) @select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ?[][]orm.Primitive {
	query := orm.orm_select_gen(config, '`', true, '?', 1, where)
	stmt := db.new_init_stmt(query) ?
	mut c := 1
	sqlite_stmt_binder(stmt, where, query, mut c) ?
	sqlite_stmt_binder(stmt, data, query, mut c) ?

	defer {
		stmt.finalize()
	}

	mut ret := [][]orm.Primitive{}

	if config.is_count {
		step := stmt.step()
		if step !in [sqlite_row, sqlite_ok, sqlite_done] {
			return db.error_message(step, query)
		}
		count := stmt.sqlite_select_column(0, 8) ?
		ret << [count]
		return ret
	}
	for {
		step := stmt.step()
		if step == sqlite_done {
			break
		}
		if step != sqlite_ok && step != sqlite_row {
			break
		}
		mut row := []orm.Primitive{}
		for i, typ in config.types {
			primitive := stmt.sqlite_select_column(i, typ) ?
			row << primitive
		}
		ret << row
	}
	return ret
}

// sql stmt

pub fn (db DB) insert(table string, data orm.QueryData) ? {
	query := orm.orm_stmt_gen(table, '`', .insert, true, '?', 1, data, orm.QueryData{})
	sqlite_stmt_worker(db, query, data, orm.QueryData{}) ?
}

pub fn (db DB) update(table string, data orm.QueryData, where orm.QueryData) ? {
	query := orm.orm_stmt_gen(table, '`', .update, true, '?', 1, data, where)
	sqlite_stmt_worker(db, query, data, where) ?
}

pub fn (db DB) delete(table string, where orm.QueryData) ? {
	query := orm.orm_stmt_gen(table, '`', .delete, true, '?', 1, orm.QueryData{}, where)
	sqlite_stmt_worker(db, query, orm.QueryData{}, where) ?
}

pub fn (db DB) last_id() orm.Primitive {
	query := 'SELECT last_insert_rowid();'
	id := db.q_int(query)
	return orm.Primitive(id)
}

// table
pub fn (db DB) create(table string, fields []orm.TableField) ? {
	query := orm.orm_table_gen(table, '`', true, 0, fields, sqlite_type_from_v, false) or {
		return err
	}
	sqlite_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{}) ?
}

pub fn (db DB) drop(table string) ? {
	query := 'DROP TABLE `$table`;'
	sqlite_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{}) ?
}

// helper

fn sqlite_stmt_worker(db DB, query string, data orm.QueryData, where orm.QueryData) ? {
	stmt := db.new_init_stmt(query) ?
	mut c := 1
	sqlite_stmt_binder(stmt, data, query, mut c) ?
	sqlite_stmt_binder(stmt, where, query, mut c) ?
	stmt.orm_step(query) ?
	stmt.finalize()
}

fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ? {
	for data in d.data {
		err := bind(stmt, c, data)

		if err != 0 {
			return stmt.db.error_message(err, query)
		}
		c++
	}
}

fn bind(stmt Stmt, c &int, data orm.Primitive) int {
	mut err := 0
	match data {
		i8, i16, int, byte, u16, u32, bool {
			err = stmt.bind_int(c, int(data))
		}
		i64, u64 {
			err = stmt.bind_i64(c, i64(data))
		}
		f32, f64 {
			err = stmt.bind_f64(c, unsafe { *(&f64(&data)) })
		}
		string {
			err = stmt.bind_text(c, data)
		}
		time.Time {
			err = stmt.bind_int(c, int(data.unix))
		}
		orm.InfixType {
			err = bind(stmt, c, data.right)
		}
	}
	return err
}

fn (stmt Stmt) sqlite_select_column(idx int, typ int) ?orm.Primitive {
	mut primitive := orm.Primitive(0)

	if typ in orm.nums || typ == -1 {
		primitive = stmt.get_int(idx)
	} else if typ in orm.num64 {
		primitive = stmt.get_i64(idx)
	} else if typ in orm.float {
		primitive = stmt.get_f64(idx)
	} else if typ == orm.string {
		primitive = stmt.get_text(idx).clone()
	} else if typ == orm.time {
		primitive = time.unix(stmt.get_int(idx))
	} else {
		return error('Unknown type $typ')
	}

	return primitive
}

fn sqlite_type_from_v(typ int) ?string {
	return if typ in orm.nums || typ < 0 || typ in orm.num64 {
		'INTEGER'
	} else if typ in orm.float {
		'REAL'
	} else if typ == orm.string {
		'TEXT'
	} else {
		error('Unknown type $typ')
	}
}