Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,295 @@
|
||||
module sqlite
|
||||
|
||||
import orm
|
||||
import time
|
||||
|
||||
// select is used internally by V's ORM for processing `SELECT ` queries
|
||||
pub fn (db DB) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive {
|
||||
where_with_tenant := orm.apply_tenant_filter(config.table, where)
|
||||
$if trace_orm_where ? {
|
||||
eprintln('> sqlite.select: where.fields.len = ${where.fields.len}')
|
||||
eprintln('> sqlite.select: where.kinds.len = ${where.kinds.len}')
|
||||
}
|
||||
// 1. Create query and bind necessary data
|
||||
query := orm.orm_select_gen(config, '`', true, '?', 1, where_with_tenant)
|
||||
$if trace_sqlite ? {
|
||||
eprintln('> select query: "${query}"')
|
||||
}
|
||||
stmt := db.new_init_stmt(query)!
|
||||
defer {
|
||||
stmt.finalize()
|
||||
}
|
||||
mut c := 1
|
||||
sqlite_stmt_binder(stmt, where_with_tenant, query, mut c)!
|
||||
sqlite_stmt_binder(stmt, data, query, mut c)!
|
||||
|
||||
mut ret := [][]orm.Primitive{}
|
||||
for {
|
||||
// 2. Parse returned values
|
||||
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
|
||||
|
||||
// insert is used internally by V's ORM for processing `INSERT ` queries
|
||||
pub fn (db DB) insert(table orm.Table, data orm.QueryData) ! {
|
||||
query, converted_data :=
|
||||
orm.orm_stmt_gen(.sqlite, table, '`', .insert, true, '?', 1, data, orm.QueryData{})
|
||||
sqlite_stmt_worker(db, query, converted_data, orm.QueryData{})!
|
||||
}
|
||||
|
||||
// update is used internally by V's ORM for processing `UPDATE ` queries
|
||||
pub fn (db DB) update(table orm.Table, data orm.QueryData, where orm.QueryData) ! {
|
||||
where_with_tenant := orm.apply_tenant_filter(table, where)
|
||||
query, _ := orm.orm_stmt_gen(.sqlite, table, '`', .update, true, '?', 1, data,
|
||||
where_with_tenant)
|
||||
sqlite_stmt_worker(db, query, data, where_with_tenant)!
|
||||
}
|
||||
|
||||
// delete is used internally by V's ORM for processing `DELETE ` queries
|
||||
pub fn (db DB) delete(table orm.Table, where orm.QueryData) ! {
|
||||
where_with_tenant := orm.apply_tenant_filter(table, where)
|
||||
query, _ := orm.orm_stmt_gen(.sqlite, table, '`', .delete, true, '?', 1, orm.QueryData{},
|
||||
where_with_tenant)
|
||||
sqlite_stmt_worker(db, query, orm.QueryData{}, where_with_tenant)!
|
||||
}
|
||||
|
||||
// last_id is used internally by V's ORM for post-processing `INSERT ` queries
|
||||
pub fn (db DB) last_id() int {
|
||||
query := 'SELECT last_insert_rowid();'
|
||||
|
||||
return db.q_int(query) or { 0 }
|
||||
}
|
||||
|
||||
// DDL (table creation/destroying etc)
|
||||
|
||||
// create is used internally by V's ORM for processing table creation queries (DDL)
|
||||
pub fn (db DB) create(table orm.Table, fields []orm.TableField) ! {
|
||||
query := orm.orm_table_gen(.sqlite, table, '`', true, 0, fields, sqlite_type_from_v, false) or {
|
||||
return err
|
||||
}
|
||||
sqlite_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})!
|
||||
}
|
||||
|
||||
// drop is used internally by V's ORM for processing table destroying queries (DDL)
|
||||
pub fn (db DB) drop(table orm.Table) ! {
|
||||
query := 'DROP TABLE `${table.name}`;'
|
||||
sqlite_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})!
|
||||
}
|
||||
|
||||
// orm_begin starts a transaction for ORM helpers.
|
||||
pub fn (mut db DB) orm_begin() ! {
|
||||
db.begin()!
|
||||
}
|
||||
|
||||
// orm_commit commits a transaction for ORM helpers.
|
||||
pub fn (mut db DB) orm_commit() ! {
|
||||
db.commit()!
|
||||
}
|
||||
|
||||
// orm_rollback rolls back a transaction for ORM helpers.
|
||||
pub fn (mut db DB) orm_rollback() ! {
|
||||
db.rollback()!
|
||||
}
|
||||
|
||||
// orm_savepoint creates a savepoint for ORM helpers.
|
||||
pub fn (mut db DB) orm_savepoint(name string) ! {
|
||||
db.savepoint(name)!
|
||||
}
|
||||
|
||||
// orm_rollback_to rolls back to a savepoint for ORM helpers.
|
||||
pub fn (mut db DB) orm_rollback_to(name string) ! {
|
||||
db.rollback_to(name)!
|
||||
}
|
||||
|
||||
// orm_release_savepoint releases a savepoint for ORM helpers.
|
||||
pub fn (mut db DB) orm_release_savepoint(name string) ! {
|
||||
db.release_savepoint(name)!
|
||||
}
|
||||
|
||||
// helper
|
||||
|
||||
// Executes query and bind prepared statement data directly
|
||||
fn sqlite_stmt_worker(db DB, query string, data orm.QueryData, where orm.QueryData) ! {
|
||||
$if trace_sqlite ? {
|
||||
eprintln('> sqlite_stmt_worker query: "${query}"')
|
||||
}
|
||||
stmt := db.new_init_stmt(query)!
|
||||
defer {
|
||||
stmt.finalize()
|
||||
}
|
||||
mut c := 1
|
||||
sqlite_stmt_binder(stmt, data, query, mut c)!
|
||||
sqlite_stmt_binder(stmt, where, query, mut c)!
|
||||
stmt.orm_step(query)!
|
||||
}
|
||||
|
||||
// Binds all values of d in the prepared statement
|
||||
fn sqlite_stmt_binder(stmt Stmt, d orm.QueryData, query string, mut c &int) ! {
|
||||
for data in d.data {
|
||||
err := bind(stmt, mut c, data)
|
||||
|
||||
if err != 0 {
|
||||
return stmt.db.error_message(err, query)
|
||||
}
|
||||
if !sqlite_primitive_is_array(data) {
|
||||
c++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sqlite_primitive_is_array(data orm.Primitive) bool {
|
||||
return match data {
|
||||
[]orm.Primitive, []bool, []f32, []f64, []i16, []i64, []i8, []int, []string, []time.Time,
|
||||
[]u16, []u32, []u64, []u8, []orm.InfixType {
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bind_array[T](stmt Stmt, mut c &int, data []T) int {
|
||||
mut err := 0
|
||||
for element in data {
|
||||
tmp_err := bind(stmt, mut c, orm.Primitive(element))
|
||||
c++
|
||||
if tmp_err != 0 {
|
||||
err = tmp_err
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Universal bind function
|
||||
fn bind(stmt Stmt, mut c &int, data orm.Primitive) int {
|
||||
mut err := 0
|
||||
match data {
|
||||
i8, i16, int, u8, 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, f64(data))
|
||||
}
|
||||
string {
|
||||
err = stmt.bind_text(c, data)
|
||||
}
|
||||
time.Time {
|
||||
err = stmt.bind_int(c, int(data.unix()))
|
||||
}
|
||||
orm.InfixType {
|
||||
err = bind(stmt, mut c, data.right)
|
||||
}
|
||||
orm.Null {
|
||||
err = stmt.bind_null(c)
|
||||
}
|
||||
[]orm.Primitive {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]bool {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]f32 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]f64 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]i16 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]i64 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]i8 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]int {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]string {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]time.Time {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]u16 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]u32 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]u64 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]u8 {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
[]orm.InfixType {
|
||||
err = bind_array(stmt, mut c, data)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Selects column in result and converts it to an orm.Primitive
|
||||
fn (stmt Stmt) sqlite_select_column(idx int, typ int) !orm.Primitive {
|
||||
if typ in orm.nums || typ == -1 {
|
||||
return stmt.get_int(idx) or { return orm.Null{} }
|
||||
} else if typ in orm.num64 {
|
||||
return stmt.get_i64(idx) or { return orm.Null{} }
|
||||
} else if typ == typeof[f32]().idx {
|
||||
return f32(stmt.get_f64(idx) or { return orm.Null{} })
|
||||
} else if typ == typeof[f64]().idx {
|
||||
return stmt.get_f64(idx) or { return orm.Null{} }
|
||||
} else if typ == orm.type_string {
|
||||
if v := stmt.get_text(idx) {
|
||||
return v.clone()
|
||||
} else {
|
||||
return orm.Null{}
|
||||
}
|
||||
} else if typ == orm.enum_ {
|
||||
return stmt.get_i64(idx) or { return orm.Null{} }
|
||||
} else if typ == orm.time_ {
|
||||
if v := stmt.get_int(idx) {
|
||||
return time.unix(v)
|
||||
} else {
|
||||
return orm.Null{}
|
||||
}
|
||||
} else {
|
||||
return error('Unknown type ${typ}')
|
||||
}
|
||||
}
|
||||
|
||||
// Convert type int to sql type string
|
||||
fn sqlite_type_from_v(typ int) !string {
|
||||
return if typ in orm.nums || typ in orm.num64 || typ in [orm.serial, orm.time_, orm.enum_] {
|
||||
'INTEGER'
|
||||
} else if typ in orm.float {
|
||||
'REAL'
|
||||
} else if typ == orm.type_string {
|
||||
'TEXT'
|
||||
} else {
|
||||
error('Unknown type ${typ}')
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user