1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

orm: init or implementation (#14989)

This commit is contained in:
Louis Schmieder
2022-08-31 13:43:20 +02:00
committed by GitHub
parent bc06866b20
commit 6110373519
15 changed files with 312 additions and 86 deletions

View File

@@ -41,6 +41,7 @@ struct C.sqlite3 {
struct C.sqlite3_stmt {
}
[heap]
struct Stmt {
stmt &C.sqlite3_stmt
db &DB
@@ -51,6 +52,7 @@ struct SQLError {
}
//
[heap]
pub struct DB {
pub mut:
is_open bool
@@ -58,7 +60,7 @@ mut:
conn &C.sqlite3
}
pub fn (db DB) str() string {
pub fn (db &DB) str() string {
return 'sqlite.DB{ conn: ' + ptr_str(db.conn) + ' }'
}
@@ -149,23 +151,25 @@ fn get_int_from_stmt(stmt &C.sqlite3_stmt) int {
// Returns last insert rowid
// https://www.sqlite.org/c3ref/last_insert_rowid.html
pub fn (db DB) last_insert_rowid() i64 {
pub fn (db &DB) last_insert_rowid() i64 {
return C.sqlite3_last_insert_rowid(db.conn)
}
// Returns a single cell with value int.
pub fn (db DB) q_int(query string) int {
pub fn (db &DB) q_int(query string) int {
stmt := &C.sqlite3_stmt(0)
defer {
C.sqlite3_finalize(stmt)
}
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
C.sqlite3_step(stmt)
res := C.sqlite3_column_int(stmt, 0)
C.sqlite3_finalize(stmt)
return res
}
// Returns a single cell with value string.
pub fn (db DB) q_string(query string) string {
pub fn (db &DB) q_string(query string) string {
stmt := &C.sqlite3_stmt(0)
defer {
C.sqlite3_finalize(stmt)
@@ -179,8 +183,12 @@ pub fn (db DB) q_string(query string) string {
// Execute the query on db, return an array of all the results, alongside any result code.
// Result codes: https://www.sqlite.org/rescode.html
pub fn (db DB) exec(query string) ([]Row, int) {
[manualfree]
pub fn (db &DB) exec(query string) ([]Row, int) {
stmt := &C.sqlite3_stmt(0)
defer {
C.sqlite3_finalize(stmt)
}
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
nr_cols := C.sqlite3_column_count(stmt)
mut res := 0
@@ -203,14 +211,17 @@ pub fn (db DB) exec(query string) ([]Row, int) {
}
rows << row
}
C.sqlite3_finalize(stmt)
return rows, res
}
// Execute a query, handle error code
// Return the first row from the resulting table
pub fn (db DB) exec_one(query string) ?Row {
[manualfree]
pub fn (db &DB) exec_one(query string) ?Row {
rows, code := db.exec(query)
defer {
unsafe { rows.free() }
}
if rows.len == 0 {
return IError(&SQLError{
msg: 'No rows'
@@ -222,21 +233,25 @@ pub fn (db DB) exec_one(query string) ?Row {
code: code
})
}
return rows[0]
res := rows[0]
return res
}
pub fn (db DB) error_message(code int, query string) IError {
msg := unsafe { cstring_to_vstring(&char(C.sqlite3_errmsg(db.conn))) }
return IError(&SQLError{
msg: '$msg ($code) ($query)'
[manualfree]
pub fn (db &DB) error_message(code int, query string) IError {
errmsg := unsafe { cstring_to_vstring(&char(C.sqlite3_errmsg(db.conn))) }
msg := '$errmsg ($code) ($query)'
unsafe { errmsg.free() }
return SQLError{
msg: msg
code: code
})
}
}
// Execute a query returning only the result code.
// In case you don't expect any row results, but still want a result code.
// e.g. INSERT INTO ... VALUES (...)
pub fn (db DB) exec_none(query string) int {
pub fn (db &DB) exec_none(query string) int {
stmt := &C.sqlite3_stmt(0)
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
code := C.sqlite3_step(stmt)
@@ -246,14 +261,14 @@ pub fn (db DB) exec_none(query string) int {
/*
TODO
pub fn (db DB) exec_param(query string, param string) []Row {
pub fn (db &DB) exec_param(query string, param string) []Row {
}
*/
// Issue a "create table if not exists" command to the db.
// Creates table named 'table_name', with columns generated from 'columns' array.
// Default columns type will be TEXT.
pub fn (db DB) create_table(table_name string, columns []string) {
pub fn (db &DB) create_table(table_name string, columns []string) {
db.exec('create table if not exists $table_name (' + columns.join(',\n') + ')')
}
@@ -261,7 +276,7 @@ pub fn (db DB) create_table(table_name string, columns []string) {
// Sleeps for a specified amount of time when a table is locked. The handler
// will sleep multiple times until at least "ms" milliseconds of sleeping have accumulated.
// (see https://www.sqlite.org/c3ref/busy_timeout.html)
pub fn (db DB) busy_timeout(ms int) int {
pub fn (db &DB) busy_timeout(ms int) int {
return C.sqlite3_busy_timeout(db.conn, ms)
}
@@ -270,7 +285,7 @@ pub fn (db DB) busy_timeout(ms int) int {
// off: No syncs at all. (fastest)
// normal: Sync after each sequence of critical disk operations.
// full: Sync after each critical disk operation (slowest).
pub fn (db DB) synchronization_mode(sync_mode SyncMode) {
pub fn (db &DB) synchronization_mode(sync_mode SyncMode) {
if sync_mode == .off {
db.exec('pragma synchronous = OFF;')
} else if sync_mode == .full {
@@ -286,7 +301,7 @@ pub fn (db DB) synchronization_mode(sync_mode SyncMode) {
// delete: At the conclusion of a transaction, journal file is deleted.
// truncate: Journal file is truncated to a length of zero bytes.
// persist: Journal file is left in place, but the header is overwritten to indicate journal is no longer valid.
pub fn (db DB) journal_mode(journal_mode JournalMode) {
pub fn (db &DB) journal_mode(journal_mode JournalMode) {
if journal_mode == .off {
db.exec('pragma journal_mode = OFF;')
} else if journal_mode == .delete {

View File

@@ -6,50 +6,50 @@ fn C.sqlite3_bind_int64(&C.sqlite3_stmt, int, i64) int
fn C.sqlite3_bind_text(&C.sqlite3_stmt, int, &char, int, voidptr) int
// Only for V ORM
fn (db DB) init_stmt(query string) (&C.sqlite3_stmt, int) {
fn (db &DB) init_stmt(query string) (&C.sqlite3_stmt, int) {
// println('init_stmt("$query")')
stmt := &C.sqlite3_stmt(0)
err := C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
return stmt, err
}
fn (db DB) new_init_stmt(query string) ?Stmt {
fn (db &DB) new_init_stmt(query string) ?Stmt {
stmt, err := db.init_stmt(query)
if err != sqlite_ok {
return db.error_message(err, query)
}
return Stmt{stmt, unsafe { &db }}
return Stmt{stmt, db}
}
fn (stmt Stmt) bind_int(idx int, v int) int {
fn (stmt &Stmt) bind_int(idx int, v int) int {
return C.sqlite3_bind_int(stmt.stmt, idx, v)
}
fn (stmt Stmt) bind_i64(idx int, v i64) int {
fn (stmt &Stmt) bind_i64(idx int, v i64) int {
return C.sqlite3_bind_int64(stmt.stmt, idx, v)
}
fn (stmt Stmt) bind_f64(idx int, v f64) int {
fn (stmt &Stmt) bind_f64(idx int, v f64) int {
return C.sqlite3_bind_double(stmt.stmt, idx, v)
}
fn (stmt Stmt) bind_text(idx int, s string) int {
fn (stmt &Stmt) bind_text(idx int, s string) int {
return C.sqlite3_bind_text(stmt.stmt, idx, voidptr(s.str), s.len, 0)
}
fn (stmt Stmt) get_int(idx int) int {
fn (stmt &Stmt) get_int(idx int) int {
return C.sqlite3_column_int(stmt.stmt, idx)
}
fn (stmt Stmt) get_i64(idx int) i64 {
fn (stmt &Stmt) get_i64(idx int) i64 {
return C.sqlite3_column_int64(stmt.stmt, idx)
}
fn (stmt Stmt) get_f64(idx int) f64 {
fn (stmt &Stmt) get_f64(idx int) f64 {
return C.sqlite3_column_double(stmt.stmt, idx)
}
fn (stmt Stmt) get_text(idx int) string {
fn (stmt &Stmt) get_text(idx int) string {
b := &char(C.sqlite3_column_text(stmt.stmt, idx))
if b == &char(0) {
@@ -58,21 +58,21 @@ fn (stmt Stmt) get_text(idx int) string {
return unsafe { b.vstring() }
}
fn (stmt Stmt) get_count() int {
fn (stmt &Stmt) get_count() int {
return C.sqlite3_column_count(stmt.stmt)
}
fn (stmt Stmt) step() int {
fn (stmt &Stmt) step() int {
return C.sqlite3_step(stmt.stmt)
}
fn (stmt Stmt) orm_step(query string) ? {
fn (stmt &Stmt) orm_step(query string) ? {
res := stmt.step()
if res != sqlite_ok && res != sqlite_done && res != sqlite_row {
return stmt.db.error_message(res, query)
}
}
fn (stmt Stmt) finalize() {
fn (stmt &Stmt) finalize() {
C.sqlite3_finalize(stmt.stmt)
}