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

db.sqlite: make functions return results, breaking change (#19093)

This commit is contained in:
jacksonmowry
2023-08-10 02:39:32 +00:00
committed by GitHub
parent d0cc564089
commit 76b4c92848
8 changed files with 75 additions and 81 deletions

View File

@@ -34,6 +34,6 @@ For instance:
import db.sqlite
db := sqlite.connect('foo.db') or { panic(err) }
db.synchronization_mode(sqlite.SyncMode.off)
db.journal_mode(sqlite.JournalMode.memory)
db.synchronization_mode(sqlite.SyncMode.off)!
db.journal_mode(sqlite.JournalMode.memory)!
```

View File

@@ -75,7 +75,7 @@ pub fn (db DB) delete(table string, where orm.QueryData) ! {
pub fn (db DB) last_id() int {
query := 'SELECT last_insert_rowid();'
return db.q_int(query)
return db.q_int(query) or { 0 }
}
// DDL (table creation/destroying etc)

View File

@@ -131,7 +131,7 @@ pub fn connect(path string) !DB {
code := C.sqlite3_open(&char(path.str), &db)
if code != 0 {
return &SQLError{
msg: unsafe { cstring_to_vstring(&char(C.sqlite3_errstr(code))) }
msg: unsafe { cstring_to_vstring(&char(C.sqlite3_errmsg(db))) }
code: code
}
}
@@ -150,7 +150,7 @@ pub fn (mut db DB) close() !bool {
db.is_open = false
} else {
return &SQLError{
msg: unsafe { cstring_to_vstring(&char(C.sqlite3_errstr(code))) }
msg: unsafe { cstring_to_vstring(&char(C.sqlite3_errmsg(db.conn))) }
code: code
}
}
@@ -180,41 +180,50 @@ pub fn (db &DB) get_affected_rows_count() int {
return C.sqlite3_changes(db.conn)
}
// q_int returns a single integer value, from the first column of the result of executing `query`
pub fn (db &DB) q_int(query string) int {
// q_int returns a single integer value, from the first column of the result of executing `query`, or an error on failure
pub fn (db &DB) q_int(query string) !int {
stmt := &C.sqlite3_stmt(unsafe { nil })
defer {
C.sqlite3_finalize(stmt)
}
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
C.sqlite3_step(stmt)
code := C.sqlite3_step(stmt)
if code != sqlite.sqlite_row {
return db.error_message(code, query)
}
res := C.sqlite3_column_int(stmt, 0)
return res
}
// q_string returns a single string value, from the first column of the result of executing `query`
pub fn (db &DB) q_string(query string) string {
// q_string returns a single string value, from the first column of the result of executing `query`, or an error on failure
pub fn (db &DB) q_string(query string) !string {
stmt := &C.sqlite3_stmt(unsafe { nil })
defer {
C.sqlite3_finalize(stmt)
}
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
C.sqlite3_step(stmt)
code := C.sqlite3_step(stmt)
if code != sqlite.sqlite_row {
return db.error_message(code, query)
}
val := unsafe { &u8(C.sqlite3_column_text(stmt, 0)) }
return if val != &u8(0) { unsafe { tos_clone(val) } } else { '' }
}
// exec executes the query on the given `db`, and returns an array of all the results, alongside any result code.
// Result codes: https://www.sqlite.org/rescode.html
// exec executes the query on the given `db`, and returns an array of all the results, or an error on failure
[manualfree]
pub fn (db &DB) exec(query string) ([]Row, int) {
pub fn (db &DB) exec(query string) ![]Row {
stmt := &C.sqlite3_stmt(unsafe { nil })
defer {
C.sqlite3_finalize(stmt)
}
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
mut code := C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
if code != sqlite.sqlite_ok {
return db.error_message(code, query)
}
nr_cols := C.sqlite3_column_count(stmt)
mut res := 0
mut rows := []Row{}
@@ -236,26 +245,21 @@ pub fn (db &DB) exec(query string) ([]Row, int) {
}
rows << row
}
return rows, res
return rows
}
// exec_one executes a query on the given `db`.
// It returns either the first row from the result, if the query was successful, or an error.
[manualfree]
pub fn (db &DB) exec_one(query string) !Row {
rows, code := db.exec(query)
rows := db.exec(query)!
defer {
unsafe { rows.free() }
}
if rows.len == 0 {
return &SQLError{
msg: 'No rows'
code: code
}
} else if code != 101 {
return &SQLError{
msg: unsafe { cstring_to_vstring(&char(C.sqlite3_errstr(code))) }
code: code
code: sqlite.sqlite_done
}
}
res := rows[0]
@@ -295,21 +299,13 @@ pub fn (db &DB) exec_param_many(query string, params []string) ![]Row {
mut code := C.sqlite3_prepare_v2(db.conn, &char(query.str), -1, &stmt, 0)
if code != 0 {
return &SQLError{
msg: unsafe {
cstring_to_vstring(&char(C.sqlite3_errstr(code)))
}
code: code
}
return db.error_message(code, query)
}
for i, param in params {
code = C.sqlite3_bind_text(stmt, i + 1, voidptr(param.str), param.len, 0)
if code != 0 {
return &SQLError{
msg: unsafe { cstring_to_vstring(&char(C.sqlite3_errstr(code))) }
code: code
}
return db.error_message(code, query)
}
}
@@ -345,8 +341,8 @@ pub fn (db &DB) exec_param(query string, param string) ![]Row {
// create_table issues a "create table if not exists" command to the db.
// It creates the table named 'table_name', with columns generated from 'columns' array.
// The default columns type will be TEXT.
pub fn (db &DB) create_table(table_name string, columns []string) {
db.exec('create table if not exists ${table_name} (' + columns.join(',\n') + ')')
pub fn (db &DB) create_table(table_name string, columns []string) ! {
db.exec('create table if not exists ${table_name} (' + columns.join(',\n') + ')')!
}
// busy_timeout sets a busy timeout in milliseconds.
@@ -359,37 +355,39 @@ pub fn (db &DB) busy_timeout(ms int) int {
// synchronization_mode sets disk synchronization mode, which controls how
// aggressively SQLite will write data to physical storage.
// If the command fails to execute an error is returned
// .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;')
db.exec('pragma synchronous = OFF;')!
} else if sync_mode == .full {
db.exec('pragma synchronous = FULL;')
db.exec('pragma synchronous = FULL;')!
} else {
db.exec('pragma synchronous = NORMAL;')
db.exec('pragma synchronous = NORMAL;')!
}
}
// journal_mode controls how the journal file is stored and processed.
// If the command fails to execute an error is returned
// .off: No journal record is kept. (fastest)
// .memory: Journal record is held in memory, rather than on disk.
// .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;')
db.exec('pragma journal_mode = OFF;')!
} else if journal_mode == .delete {
db.exec('pragma journal_mode = DELETE;')
db.exec('pragma journal_mode = DELETE;')!
} else if journal_mode == .truncate {
db.exec('pragma journal_mode = TRUNCATE;')
db.exec('pragma journal_mode = TRUNCATE;')!
} else if journal_mode == .persist {
db.exec('pragma journal_mode = PERSIST;')
db.exec('pragma journal_mode = PERSIST;')!
} else if journal_mode == .memory {
db.exec('pragma journal_mode = MEMORY;')
db.exec('pragma journal_mode = MEMORY;')!
} else {
db.exec('pragma journal_mode = MEMORY;')
db.exec('pragma journal_mode = MEMORY;')!
}
}

View File

@@ -103,11 +103,10 @@ fn test_sqlite_orm() {
create table TestCustomSqlType
}!
mut result_custom_sql, mut exec_custom_code := db.exec('
mut result_custom_sql := db.exec('
pragma table_info(TestCustomSqlType);
')
')!
assert exec_custom_code == 101
mut table_info_types_results := []string{}
information_schema_custom_sql := ['INTEGER', 'INTEGER', 'TEXT', 'REAL', 'NUMERIC', 'TEXT',
'INTEGER', 'INTEGER']
@@ -128,11 +127,10 @@ fn test_sqlite_orm() {
create table TestDefaultAtribute
}!
mut result_default_sql, mut code := db.exec('
mut result_default_sql := db.exec('
pragma table_info(TestDefaultAtribute);
')
')!
assert code == 101
mut information_schema_data_types_results := []string{}
information_schema_default_sql := ['', '', 'CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP']
@@ -176,7 +174,7 @@ fn test_get_affected_rows_count() {
db.exec('create table EntityToTest(
id integer not null constraint tbl_pk primary key,
smth integer
);')
);')!
fst := EntityToTest{
id: 1

View File

@@ -35,49 +35,48 @@ fn test_sqlite() {
}
mut db := sqlite.connect(':memory:') or { panic(err) }
assert db.is_open
db.exec('drop table if exists users')
db.exec("create table users (id integer primary key, name text default '');")
db.exec("insert into users (name) values ('Sam')")
db.exec('drop table if exists users')!
db.exec("create table users (id integer primary key, name text default '');")!
db.exec("insert into users (name) values ('Sam')")!
assert db.last_insert_rowid() == 1
assert db.get_affected_rows_count() == 1
db.exec("insert into users (name) values ('Peter')")
db.exec("insert into users (name) values ('Peter')")!
assert db.last_insert_rowid() == 2
db.exec("insert into users (name) values ('Kate')")
db.exec("insert into users (name) values ('Kate')")!
assert db.last_insert_rowid() == 3
db.exec_param('insert into users (name) values (?)', 'Tom')!
assert db.last_insert_rowid() == 4
nr_users := db.q_int('select count(*) from users')
nr_users := db.q_int('select count(*) from users')!
assert nr_users == 4
name := db.q_string('select name from users where id = 1')
name := db.q_string('select name from users where id = 1')!
assert name == 'Sam'
username := db.exec_param('select name from users where id = ?', '1')!
assert username[0].vals[0] == 'Sam'
// this insert will be rejected due to duplicated id
db.exec("insert into users (id,name) values (1,'Sam')")
db.exec("insert into users (id,name) values (1,'Sam')")!
assert db.get_affected_rows_count() == 0
users, mut code := db.exec('select * from users')
users := db.exec('select * from users')!
assert users.len == 4
assert code == 101
code = db.exec_none('vacuum')
code := db.exec_none('vacuum')
assert code == 101
user := db.exec_one('select * from users where id = 3') or { panic(err) }
println(user)
assert user.vals.len == 2
db.exec("update users set name='zzzz' where name='qqqq'")
db.exec("update users set name='zzzz' where name='qqqq'")!
assert db.get_affected_rows_count() == 0
db.exec("update users set name='Peter1' where name='Peter'")
db.exec("update users set name='Peter1' where name='Peter'")!
assert db.get_affected_rows_count() == 1
db.exec_param_many('update users set name=? where name=?', ['Peter', 'Peter1'])!
assert db.get_affected_rows_count() == 1
db.exec("delete from users where name='qqqq'")
db.exec("delete from users where name='qqqq'")!
assert db.get_affected_rows_count() == 0
db.exec("delete from users where name='Sam'")
db.exec("delete from users where name='Sam'")!
assert db.get_affected_rows_count() == 1
db.close() or { panic(err) }