mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
307 lines
6.9 KiB
V
307 lines
6.9 KiB
V
// vtest flaky: true
|
|
// vtest retry: 3
|
|
import orm
|
|
import db.sqlite
|
|
|
|
struct MockDBState {
|
|
mut:
|
|
last string
|
|
data []orm.Primitive
|
|
where []orm.Primitive
|
|
}
|
|
|
|
struct MockDB {
|
|
use_num bool
|
|
st &MockDBState = unsafe { nil }
|
|
db sqlite.DB
|
|
}
|
|
|
|
fn MockDB.new() &MockDB {
|
|
return &MockDB{
|
|
st: &MockDBState{}
|
|
db: sqlite.connect(':memory:') or { panic(err) }
|
|
}
|
|
}
|
|
|
|
fn (db MockDB) select(config orm.SelectConfig, data orm.QueryData, where orm.QueryData) ![][]orm.Primitive {
|
|
mut st := db.st
|
|
st.last = orm.orm_select_gen(config, '`', false, '?', 5, where)
|
|
st.data = data.data
|
|
st.where = where.data
|
|
return db.db.select(config, data, where)
|
|
}
|
|
|
|
fn (db MockDB) insert(table string, data orm.QueryData) ! {
|
|
mut st := db.st
|
|
last, qdata := orm.orm_stmt_gen(.sqlite, table, '`', .insert, false, '?', 1, data,
|
|
orm.QueryData{})
|
|
st.last = last
|
|
st.data = qdata.data
|
|
st.where = []orm.Primitive{}
|
|
return db.db.insert(table, data)
|
|
}
|
|
|
|
fn (db MockDB) update(table string, data orm.QueryData, where orm.QueryData) ! {
|
|
mut st := db.st
|
|
st.last, _ = orm.orm_stmt_gen(.sqlite, table, '`', .update, false, '?', 1, data, where)
|
|
st.data = data.data
|
|
st.where = where.data
|
|
return db.db.update(table, data, where)
|
|
}
|
|
|
|
fn (db MockDB) delete(table string, where orm.QueryData) ! {
|
|
mut st := db.st
|
|
st.last, _ = orm.orm_stmt_gen(.sqlite, table, '`', .delete, false, '?', 1, orm.QueryData{},
|
|
where)
|
|
return db.db.delete(table, where)
|
|
}
|
|
|
|
const typ_to_typename = {
|
|
typeof[i8]().idx: 'i8'
|
|
typeof[i16]().idx: 'i16'
|
|
typeof[int]().idx: 'int'
|
|
typeof[i64]().idx: 'i64'
|
|
typeof[u8]().idx: 'u8'
|
|
typeof[u16]().idx: 'u16'
|
|
typeof[u32]().idx: 'u32'
|
|
typeof[u64]().idx: 'u64'
|
|
typeof[f32]().idx: 'f32'
|
|
typeof[f64]().idx: 'f64'
|
|
typeof[string]().idx: 'string'
|
|
typeof[bool]().idx: 'bool'
|
|
orm.serial: 'serial'
|
|
orm.time_: 'time'
|
|
orm.enum_: 'enum'
|
|
}
|
|
|
|
fn mock_type_from_v(typ int) !string {
|
|
return if typ in typ_to_typename {
|
|
'${typ_to_typename[typ]}-type'
|
|
} else {
|
|
error('unknown type ${typ}')
|
|
}
|
|
}
|
|
|
|
fn (db MockDB) create(table string, fields []orm.TableField) ! {
|
|
mut st := db.st
|
|
st.last = orm.orm_table_gen(table, '`', true, 0, fields, mock_type_from_v, false)!
|
|
return db.db.create(table, fields)
|
|
}
|
|
|
|
fn (db MockDB) drop(table string) ! {
|
|
return db.db.drop(table)
|
|
}
|
|
|
|
fn (db MockDB) last_id() int {
|
|
return db.db.last_id()
|
|
}
|
|
|
|
// --
|
|
|
|
@[table: 'foo']
|
|
struct Foo {
|
|
mut:
|
|
id u64 @[primary; sql: serial]
|
|
a string
|
|
// b string [default: '"yes"']
|
|
c ?string
|
|
d ?string = 'hi'
|
|
e int
|
|
// f int [default: 33]
|
|
g ?int
|
|
h ?int = 55
|
|
}
|
|
|
|
fn test_option_struct_fields_and_none() {
|
|
db := MockDB.new()
|
|
|
|
sql db {
|
|
create table Foo
|
|
}!
|
|
assert db.st.last == 'CREATE TABLE IF NOT EXISTS `foo` (`id` serial-type NOT NULL, `a` string-type NOT NULL, `c` string-type, `d` string-type, `e` int-type NOT NULL, `g` int-type, `h` int-type, PRIMARY KEY(`id`));'
|
|
|
|
_ := sql db {
|
|
select from Foo where e > 5 && c is none && c !is none && h == 2
|
|
}!
|
|
assert db.st.last == 'SELECT `id`, `a`, `c`, `d`, `e`, `g`, `h` FROM `foo` WHERE `e` > ? AND `c` IS NULL AND `c` IS NOT NULL AND `h` = ?;'
|
|
assert db.st.data.len == 0
|
|
assert db.st.where.len == 2
|
|
assert db.st.where == [orm.Primitive(int(5)), orm.Primitive(int(2))]
|
|
|
|
foo := Foo{}
|
|
sql db {
|
|
insert foo into Foo
|
|
}!
|
|
assert db.st.last == 'INSERT INTO `foo` (`a`, `c`, `d`, `e`, `g`, `h`) VALUES (?, ?, ?, ?, ?, ?);'
|
|
assert db.st.data.len == 6
|
|
assert db.st.data == [orm.Primitive(string('')), orm.Null{}, orm.Primitive(string('hi')), int(0),
|
|
orm.Null{}, int(55)]
|
|
id := db.last_id()
|
|
|
|
res1 := sql db {
|
|
select from Foo where id == id
|
|
}!
|
|
assert db.st.last == 'SELECT `id`, `a`, `c`, `d`, `e`, `g`, `h` FROM `foo` WHERE `id` = ?;'
|
|
assert db.st.data.len == 0
|
|
assert db.st.where.len == 1
|
|
assert db.st.where == [orm.Primitive(int(id))]
|
|
assert res1.len == 1
|
|
assert res1[0] == Foo{
|
|
id: 1
|
|
a: ''
|
|
c: none
|
|
d: 'hi'
|
|
e: 0
|
|
g: none
|
|
h: 55
|
|
}
|
|
|
|
sql db {
|
|
update Foo set c = 'yo', d = none, g = 44, h = none where id == id
|
|
}!
|
|
assert db.st.last == 'UPDATE `foo` SET `c` = ?, `d` = ?, `g` = ?, `h` = ? WHERE `id` = ?;'
|
|
assert db.st.data.len == 4
|
|
assert db.st.data == [orm.Primitive(string('yo')), orm.Null{}, int(44), orm.Null{}]
|
|
assert db.st.where.len == 1
|
|
assert db.st.where == [orm.Primitive(int(id))]
|
|
|
|
res2 := sql db {
|
|
select from Foo where id == id
|
|
}!
|
|
assert db.st.last == 'SELECT `id`, `a`, `c`, `d`, `e`, `g`, `h` FROM `foo` WHERE `id` = ?;'
|
|
assert db.st.data.len == 0
|
|
assert db.st.where.len == 1
|
|
assert db.st.where == [orm.Primitive(int(id))]
|
|
assert res2.len == 1
|
|
assert res2[0] == Foo{
|
|
id: 1
|
|
a: ''
|
|
c: 'yo'
|
|
d: none
|
|
e: 0
|
|
g: 44
|
|
h: none
|
|
}
|
|
|
|
assert sql db {
|
|
select count from Foo where a == 'yo'
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where d == 'yo'
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where c == 'yo'
|
|
}! == 1
|
|
assert sql db {
|
|
select count from Foo where a == ''
|
|
}! == 1
|
|
assert sql db {
|
|
select count from Foo where d == ''
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where c == ''
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where a is none
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where d is none
|
|
}! == 1
|
|
assert sql db {
|
|
select count from Foo where c is none
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where a !is none
|
|
}! == 1
|
|
assert sql db {
|
|
select count from Foo where d !is none
|
|
}! == 0
|
|
assert sql db {
|
|
select count from Foo where c !is none
|
|
}! == 1
|
|
}
|
|
|
|
struct Bar {
|
|
id u64 @[primary; sql: serial]
|
|
name ?string
|
|
age int
|
|
}
|
|
|
|
fn update_bar1(db MockDB, id u64, name ?string) ! {
|
|
foo := 66
|
|
sql db {
|
|
update Bar set name = name, age = age + 3 + foo where id == id
|
|
}!
|
|
}
|
|
|
|
fn update_bar2(db MockDB, name ?string, new_name ?string) ! {
|
|
sql db {
|
|
update Bar set name = new_name where name == name
|
|
}!
|
|
}
|
|
|
|
type NameFn = fn () ?string
|
|
|
|
fn update_bar3(db MockDB, name_fn NameFn, new_name string) ! {
|
|
sql db {
|
|
update Bar set name = new_name where name == name_fn()
|
|
}!
|
|
}
|
|
|
|
fn test_inserting_passed_optionals() {
|
|
db := MockDB.new()
|
|
|
|
entry1 := Bar{}
|
|
entry2 := Bar{
|
|
name: 'Alice'
|
|
age: 55
|
|
}
|
|
entry3 := Bar{
|
|
name: 'Bob'
|
|
age: 66
|
|
}
|
|
sql db {
|
|
create table Bar
|
|
insert entry1 into Bar
|
|
insert entry2 into Bar
|
|
insert entry3 into Bar
|
|
}!
|
|
|
|
update_bar1(db, 2, none)!
|
|
update_bar1(db, 1, 'hi')!
|
|
|
|
res1 := sql db {
|
|
select from Bar
|
|
}!
|
|
assert res1.len == 3
|
|
assert res1[0].name or { '' } == 'hi'
|
|
assert res1[1].name == none
|
|
assert res1[2].name or { '' } == 'Bob'
|
|
|
|
update_bar2(db, none, 'xxx')! // no effect (select using "is none", not "== none")
|
|
update_bar2(db, 'hi', none)!
|
|
|
|
res2 := sql db {
|
|
select from Bar
|
|
}!
|
|
assert res2.len == 3
|
|
assert res2[0].name == none
|
|
assert res2[1].name == none
|
|
assert res2[2].name or { '' } == 'Bob'
|
|
|
|
update_bar3(db, fn () ?string {
|
|
return none // no effect (select using "is none", not "== none")
|
|
}, 'yyy')!
|
|
update_bar3(db, fn () ?string {
|
|
return 'Bob'
|
|
}, 'www')!
|
|
|
|
res3 := sql db {
|
|
select from Bar
|
|
}!
|
|
assert res3.len == 3
|
|
assert res3[0].name == none
|
|
assert res3[1].name == none
|
|
assert res3[2].name or { '' } == 'www'
|
|
}
|