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

orm: enforce that queries always return a Result, a query-resulting array can be used as a V array in place. (#17871)

This commit is contained in:
walking devel 2023-04-04 05:23:06 +00:00 committed by GitHub
parent 9addede0ea
commit 8452644ec3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 479 additions and 354 deletions

View File

@ -130,6 +130,7 @@ const (
'vlib/orm/orm_string_interpolation_in_where_test.v',
'vlib/orm/orm_interface_test.v',
'vlib/orm/orm_mut_db_test.v',
'vlib/orm/orm_result_test.v',
'vlib/db/sqlite/sqlite_test.v',
'vlib/db/sqlite/sqlite_orm_test.v',
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
@ -205,6 +206,7 @@ const (
'vlib/orm/orm_string_interpolation_in_where_test.v',
'vlib/orm/orm_interface_test.v',
'vlib/orm/orm_mut_db_test.v',
'vlib/orm/orm_result_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/v/tests/orm_joined_tables_select_test.v',

View File

@ -4850,18 +4850,18 @@ db := sqlite.connect('customers.db')!
// )
sql db {
create table Customer
}
}!
// select count(*) from customers
nr_customers := sql db {
select count from Customer
}
}!
println('number of all customers: ${nr_customers}')
// V syntax can be used to build queries
uk_customers := sql db {
select from Customer where country == 'uk' && nr_orders > 0
}
}!
println(uk_customers.len)
for customer in uk_customers {
println('${customer.id} - ${customer.name}')
@ -4874,7 +4874,7 @@ new_customer := Customer{
}
sql db {
insert new_customer into Customer
}
}!
```
For more examples and the docs, see [vlib/orm](https://github.com/vlang/v/tree/master/vlib/orm).

View File

@ -70,16 +70,16 @@ fn sqlite3_array() ! {
sql db {
drop table Parent
drop table Child
}
} or {}
db.close() or {}
}
//
sql db {
create table Parent
}
}!
sql db {
create table Child
}
}!
par := Parent{
name: 'test'
children: [
@ -93,10 +93,10 @@ fn sqlite3_array() ! {
}
sql db {
insert par into Parent
}
}!
parent := sql db {
select from Parent where id == 1
}
}!
eprintln(parent)
}
@ -113,16 +113,16 @@ fn msql_array() ! {
defer {
sql db {
drop table Parent
}
} or {}
db.close()
}
//
db.query('drop table if exists Parent')!
db.query('drop table if exists Child')!
sql db {
create table Parent
create table Child
}
}!
par := Parent{
name: 'test'
children: [
@ -136,10 +136,10 @@ fn msql_array() ! {
}
sql db {
insert par into Parent
}
}!
parent := sql db {
select from Parent where id == 1
}
}!
eprintln(parent)
}
@ -151,11 +151,11 @@ fn psql_array() ! {
db.close()
}
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
//
sql db {
create table Parent
create table Child
}
}!
par := Parent{
name: 'test'
children: [
@ -169,10 +169,10 @@ fn psql_array() ! {
}
sql db {
insert par into Parent
}
}!
parent := sql db {
select from Parent where id == 1
}
}!
eprintln(parent)
}
@ -182,19 +182,17 @@ fn sqlite3() ! {
defer {
sql db {
drop table Module
}
sql db {
drop table User
}
} or {}
db.close() or {}
}
//
sql db {
create table Module
}
}!
sql db {
create table User
}
}!
mod := Module{
name: 'test'
nr_downloads: 10
@ -206,10 +204,10 @@ fn sqlite3() ! {
}
sql db {
insert mod into Module
}
}!
modul := sql db {
select from Module where id == 1
}
}!
eprintln(modul)
}
@ -230,13 +228,13 @@ fn msql() ! {
}
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
//
sql conn {
create table Module
}
}!
sql conn {
create table User
}
}!
mod := Module{
name: 'test'
nr_downloads: 10
@ -248,10 +246,10 @@ fn msql() ! {
}
sql conn {
insert mod into Module
}
}!
m := sql conn {
select from Module where id == 1
}
}!
eprintln(m)
}
@ -266,7 +264,7 @@ fn psql() ! {
sql db {
create table Module
create table User
}
}!
mod := Module{
name: 'test'
nr_downloads: 10
@ -278,13 +276,13 @@ fn psql() ! {
}
sql db {
insert mod into Module
}
}!
modul := sql db {
select from Module where id == 1
}
}!
sql db {
drop table Module
}
}!
eprintln(modul)
}

View File

@ -44,7 +44,7 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sql db {
create table Task
}
}!
task_model := Task{
title: 'a'
@ -55,14 +55,14 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sw.start()
sql db {
insert task_model into Task
}
} or { []Task{} }
sw.stop()
insert_stopwatchs << int(sw.end - sw.start)
}
sql db {
drop table Task
}
}!
response := Response{
insert: insert_stopwatchs

View File

@ -31,7 +31,7 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sql db {
create table Task
}
} or { panic(err) }
task_model := Task{
title: 'a'
@ -42,14 +42,14 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sw.start()
sql db {
insert task_model into Task
}
} or { []Task{} }
sw.stop()
insert_stopwatchs << int(sw.end - sw.start)
}
sql db {
drop table Task
}
} or { panic(err) }
response := Response{
insert: insert_stopwatchs

View File

@ -50,7 +50,7 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sql db {
create table Task
}
} or { panic(err) }
task_model := Task{
title: 'a'
@ -62,7 +62,7 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sw.start()
sql db {
insert task_model into Task
}
} or { panic(err) }
sw.stop()
insert_stopwatchs << int(sw.end - sw.start)
}
@ -72,7 +72,7 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sw.start()
result := sql db {
select from Task
}
} or { []Task{} }
sw.stop()
eprintln(result)
select_stopwatchs << int(sw.end - sw.start)
@ -83,14 +83,14 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
sw.start()
sql db {
update Task set title = 'b', status = 'finish' where id == i
}
} or { panic(err) }
sw.stop()
update_stopwatchs << int(sw.end - sw.start)
}
sql db {
drop table Task
}
} or { panic(err) }
response := Response{
insert: insert_stopwatchs

View File

@ -36,7 +36,7 @@ fn (mut app App) service_auth(username string, password string) !string {
users := sql db {
select from User where username == username
}
}!
user := users.first()
if user.username != username {
return error('user not found')

View File

@ -37,7 +37,7 @@ fn (mut app App) service_get_all_products_from(user_id int) ![]Product {
results := sql db {
select from Product where user_id == user_id
}
}!
return results
}

View File

@ -42,7 +42,7 @@ fn (mut app App) service_get_all_user() ![]User {
results := sql db {
select from User
}
}!
return results
}
@ -59,7 +59,7 @@ fn (mut app App) service_get_user(id int) !User {
results := sql db {
select from User where id == id
}
}!
return results.first()
}

View File

@ -33,7 +33,7 @@ fn (mut app App) service_auth(username string, password string) !string {
users := sql db {
select from User where username == username
}
}!
if users.len == 0 {
return error('user not found')

View File

@ -66,7 +66,7 @@ pub fn (mut app App) delete() vweb.Result {
sql db {
drop table User
}
} or { panic(err) }
return app.text('Successfully deleted table')
}

View File

@ -33,7 +33,7 @@ fn (mut app App) service_add_user(username string, password string) !User {
users := sql db {
select from User where username == username limit 1
}
}!
return users.first()
}
@ -50,7 +50,7 @@ fn (mut app App) service_get_user_by_id(user_id int) !User {
users := sql db {
select from User where id == user_id
}
}!
return users.first()
}
@ -67,7 +67,7 @@ fn (mut app App) service_get_all_user() ![]User {
results := sql db {
select from User
}
}!
return results
}
@ -84,7 +84,7 @@ fn (mut app App) service_get_by_username(username string) !User {
results := sql db {
select from User where username == username
}
}!
if results.len == 0 {
return error('User not found')

View File

@ -9,5 +9,5 @@ struct Article {
pub fn (app &App) find_all_articles() []Article {
return sql app.db {
select from Article
}
} or { []Article{} }
}

View File

@ -18,7 +18,7 @@ fn main() {
}
sql app.db {
create table Article
}
}!
vweb.run(app, 8081)
}
@ -61,7 +61,7 @@ pub fn (mut app App) new_article(title string, text string) vweb.Result {
println(article)
sql app.db {
insert article into Article
}
} or {}
return app.redirect('/')
}

View File

@ -116,7 +116,7 @@ fn test_mysql_orm() {
*/
sql db {
create table TestCustomSqlType
}
}!
mut result_custom_sql := db.query("
SELECT DATA_TYPE, COLUMN_TYPE
@ -161,7 +161,7 @@ fn test_mysql_orm() {
sql db {
drop table TestCustomSqlType
}
}!
assert result_custom_sql.maps() == information_schema_custom_sql
@ -184,19 +184,19 @@ fn test_mysql_orm() {
sql db {
create table TestTimeType
}
}!
sql db {
insert model into TestTimeType
}
}!
results := sql db {
select from TestTimeType where username == 'hitalo'
}
}!
sql db {
drop table TestTimeType
}
}!
assert results[0].username == model.username
assert results[0].created_at == model.created_at
@ -207,7 +207,7 @@ fn test_mysql_orm() {
*/
sql db {
create table TestDefaultAtribute
}
}!
mut result_defaults := db.query("
SELECT COLUMN_DEFAULT
@ -222,7 +222,7 @@ fn test_mysql_orm() {
sql db {
drop table TestDefaultAtribute
}
}!
information_schema_column_default_sql := [{
'COLUMN_DEFAULT': ''

View File

@ -137,7 +137,7 @@ fn test_pg_orm() {
sql db {
create table TestCustomSqlType
}
}!
mut result_custom_sql := db.exec("
SELECT DATA_TYPE
@ -157,7 +157,7 @@ fn test_pg_orm() {
sql db {
drop table TestCustomSqlType
}
}!
assert information_schema_data_types_results == information_schema_custom_sql
@ -180,19 +180,19 @@ fn test_pg_orm() {
sql db {
create table TestTimeType
}
}!
sql db {
insert model into TestTimeType
}
}!
results := sql db {
select from TestTimeType where username == 'hitalo'
}
}!
sql db {
drop table TestTimeType
}
}!
assert results[0].username == model.username
assert results[0].created_at == model.created_at
@ -203,7 +203,7 @@ fn test_pg_orm() {
*/
sql db {
create table TestDefaultAtribute
}
}!
mut result_defaults := db.exec("
SELECT column_default
@ -221,6 +221,6 @@ fn test_pg_orm() {
}
sql db {
drop table TestDefaultAtribute
}
}!
assert ['gen_random_uuid()', '', 'CURRENT_TIMESTAMP'] == information_schema_defaults_results
}

View File

@ -101,7 +101,7 @@ fn test_sqlite_orm() {
sql db {
create table TestCustomSqlType
}
}!
mut result_custom_sql, mut exec_custom_code := db.exec('
pragma table_info(TestCustomSqlType);
@ -119,14 +119,14 @@ fn test_sqlite_orm() {
sql db {
drop table TestCustomSqlType
}
}!
/** test default attribute
*/
sql db {
create table TestDefaultAtribute
}
}!
mut result_default_sql, mut code := db.exec('
pragma table_info(TestDefaultAtribute);
@ -147,11 +147,11 @@ fn test_sqlite_orm() {
sql db {
insert test_default_atribute into TestDefaultAtribute
}
}!
test_default_atributes := sql db {
select from TestDefaultAtribute limit 1
}
}!
result_test_default_atribute := test_default_atributes.first()
assert result_test_default_atribute.name == 'Hitalo'
@ -164,7 +164,7 @@ fn test_sqlite_orm() {
sql db {
drop table TestDefaultAtribute
}
}!
}
fn test_get_affected_rows_count() {
@ -204,26 +204,26 @@ fn test_get_affected_rows_count() {
all := sql db {
select from EntityToTest
}
}!
assert 1 == all.len
sql db {
update EntityToTest set smth = '2' where id == 1
}
}!
assert db.get_affected_rows_count() == 1
sql db {
update EntityToTest set smth = '2' where id == 2
}
}!
assert db.get_affected_rows_count() == 0
sql db {
delete from EntityToTest where id == 2
}
}!
assert db.get_affected_rows_count() == 0
sql db {
delete from EntityToTest where id == 1
}
}!
assert db.get_affected_rows_count() == 1
}

View File

@ -19,10 +19,10 @@ fn (back Host) get_users() []User {
return []
}
fn create_host(db Connection) Host {
fn create_host(db Connection) !Host {
sql db {
create table User
}
}!
return Host{
db: db
@ -87,6 +87,6 @@ fn test_can_access_sqlite_result_consts() {
}
fn test_alias_db() {
create_host(sqlite.connect(':memory:')!)
create_host(sqlite.connect(':memory:')!)!
assert true
}

View File

@ -23,18 +23,24 @@ fn test_create_only_one_table() {
sql db {
create table Parent
}
}!
mut is_child_created := true
mut is_note_created := true
_ := sql db {
select count from Child
} or { is_child_created = false }
} or {
is_child_created = false
0
}
_ := sql db {
select count from Note
} or { is_note_created = false }
} or {
is_note_created = false
0
}
assert is_child_created == false
assert is_note_created == false
@ -45,13 +51,13 @@ fn test_drop_only_one_table() {
sql db {
create table Parent
}
}!
sql db {
create table Child
}
}!
sql db {
create table Note
}
}!
mut is_parent_dropped := false
mut is_child_dropped := false
@ -59,19 +65,28 @@ fn test_drop_only_one_table() {
sql db {
drop table Parent
}
}!
_ := sql db {
select count from Parent
} or { is_parent_dropped = true }
} or {
is_parent_dropped = true
0
}
_ := sql db {
select count from Child
} or { is_child_dropped = true }
} or {
is_child_dropped = true
0
}
_ := sql db {
select count from Note
} or { is_note_dropped = true }
} or {
is_note_dropped = true
0
}
assert is_parent_dropped
assert is_child_dropped == false

View File

@ -15,7 +15,7 @@ fn test_fn_calls() {
sql db {
create table User
}
}!
first_user := User{
name: 'first'
@ -30,18 +30,18 @@ fn test_fn_calls() {
sql db {
insert first_user into User
insert second_user into User
}
}!
users_with_acceptable_age := sql db {
select from User where age >= get_acceptable_age()
}
}!
assert users_with_acceptable_age.len == 1
assert users_with_acceptable_age.first().name == 'first'
users_with_non_acceptable_age := sql db {
select from User where age < get_acceptable_age()
}
}!
assert users_with_non_acceptable_age.len == 1
assert users_with_non_acceptable_age.first().name == 'second'

View File

@ -14,20 +14,20 @@ fn test_insert_with_reserved_name() {
}
sql db {
create table Bad
}
}!
sql db {
insert bad into Bad
}
}!
sql db {
insert bad into Bad
insert bad into Bad
insert bad into Bad
}
}!
rows := sql db {
select from Bad
}
}!
assert rows.len == 4
}

View File

@ -25,10 +25,10 @@ struct Account {
id int [primary; sql: serial]
}
pub fn insert_parent(db sqlite.DB, mut parent Parent) {
pub fn insert_parent(db sqlite.DB, mut parent Parent) ! {
sql db {
insert parent into Parent
}
}!
}
fn test_insert_empty_object() {
@ -39,11 +39,11 @@ fn test_insert_empty_object() {
sql db {
create table Account
insert account into Account
}
}!
accounts := sql db {
select from Account
}
}!
assert accounts.len == 1
}
@ -55,17 +55,17 @@ fn test_orm_insert_mut_object() {
create table Parent
create table Child
create table Note
}
}!
mut parent := Parent{
name: 'test'
}
insert_parent(db, mut parent)
insert_parent(db, mut parent)!
parents := sql db {
select from Parent
}
}!
assert parents.len == 1
}
@ -77,7 +77,7 @@ fn test_orm_insert_with_multiple_child_elements() {
create table Parent
create table Child
create table Note
}
}!
new_parent := Parent{
name: 'test'
@ -104,11 +104,11 @@ fn test_orm_insert_with_multiple_child_elements() {
sql db {
insert new_parent into Parent
}
}!
parents := sql db {
select from Parent where id == 1
}
}!
parent := parents.first()
assert parent.children.len == new_parent.children.len
@ -116,12 +116,12 @@ fn test_orm_insert_with_multiple_child_elements() {
children_count := sql db {
select count from Child
}
}!
assert children_count == new_parent.children.len
note_count := sql db {
select count from Note
}
}!
assert note_count == new_parent.notes.len
assert parent.children[0].name == 'Lisa'

View File

@ -12,7 +12,7 @@ fn test_orm_interface() {
sql db {
create table User
}
}!
user := User{
name: 'test'
@ -20,11 +20,11 @@ fn test_orm_interface() {
sql db {
insert user into User
}
}!
users := sql db {
select from User
}
}!
assert users.len == 1
assert users.first().name == user.name

View File

@ -10,7 +10,7 @@ fn test_last_id() {
sql db {
create table User
}
}!
first_user := User{
name: 'first'
@ -23,7 +23,7 @@ fn test_last_id() {
sql db {
insert first_user into User
insert second_user into User
}
}!
last_id := db.last_id()

View File

@ -5,10 +5,10 @@ struct User {
name string
}
fn get_users(mut db sqlite.DB) []User {
fn get_users(mut db sqlite.DB) ![]User {
return sql db {
select from User
}
}!
}
fn test_orm_mut_db() {
@ -16,7 +16,7 @@ fn test_orm_mut_db() {
sql db {
create table User
}
}!
first_user := User{
name: 'first'
@ -28,9 +28,9 @@ fn test_orm_mut_db() {
sql db {
insert first_user into User
insert second_user into User
}
}!
users := get_users(mut db)
users := get_users(mut db)!
assert users.len == 2
}

View File

@ -0,0 +1,82 @@
import db.sqlite
struct Account {
id int [primary; sql: serial]
name string
}
struct Note {
id int [primary; sql: serial]
content string
}
fn test_catch_table_is_not_created() {
mut db := sqlite.connect(':memory:')!
mut is_inserted := true
account := Account{}
sql db {
insert account into Account
} or { is_inserted = false }
assert !is_inserted
}
fn test_catch_one_of_queries() {
mut db := sqlite.connect(':memory:')!
sql db {
create table Account
}!
account := Account{}
sql db {
insert account into Account
}!
mut are_updated := true
sql db {
update Account set name = 'test' where id == 1
update Note set content = 'test' where id == 1
} or { are_updated = false }
assert !are_updated
}
fn test_print_results() {
mut db := sqlite.connect(':memory:')!
sql db {
create table Account
}!
account := Account{}
sql db {
insert account into Account
}!
count := sql db {
select count from Account
}!
println(count)
user := sql db {
select from Account
}!.first()
println(user)
users := sql db {
select from Account
}!
println(users)
assert true
}

View File

@ -38,20 +38,26 @@ fn test_sql_or_block_for_insert() {
user := User{1, 'bilbo'}
eprintln('> inserting user 1 (first try)...')
mut is_user_inserted := true
sql db {
insert user into User
} or {
println('user should have been inserted, but could not, err: ${err}')
assert false
is_user_inserted = false
}
assert is_user_inserted
eprintln('> inserting user 1 (second try)...')
sql db {
insert user into User
} or {
assert true
println('user could not be inserted, err: ${err}')
is_user_inserted = false
}
assert !is_user_inserted
eprintln('LINE: ${@LINE}')
db.close()!
}

View File

@ -10,7 +10,7 @@ fn test_string_interpolation() {
sql db {
create table User
}
}!
user_suffix := '_user'
@ -25,11 +25,11 @@ fn test_string_interpolation() {
sql db {
insert first_user into User
insert second_user into User
}
}!
users := sql db {
select from User where name == 'first${user_suffix}'
}
}!
assert users.len == 1
assert users.first().name == 'first${user_suffix}'

View File

@ -39,7 +39,7 @@ fn test_use_struct_field_as_limit() {
sql db {
create table User
}
}!
foo := Foo{
age: 10
@ -52,11 +52,11 @@ fn test_use_struct_field_as_limit() {
sql db {
insert sam into User
}
}!
users := sql db {
select from User limit foo.age
}
}!
assert users.len == 1
}
@ -66,10 +66,10 @@ fn test_orm() {
sql db {
create table Module
}
}!
sql db {
create table User
}
}!
name := 'Peter'
@ -93,47 +93,47 @@ fn test_orm() {
insert sam into User
insert peter into User
insert k into User
}
}!
c := sql db {
select count from User where id != 1
}
}!
assert c == 2
nr_all_users := sql db {
select count from User
}
}!
assert nr_all_users == 3
nr_users1 := sql db {
select count from User where id == 1
}
}!
assert nr_users1 == 1
nr_peters := sql db {
select count from User where id == 2 && name == 'Peter'
}
}!
assert nr_peters == 1
nr_peters2 := sql db {
select count from User where id == 2 && name == name
}
}!
assert nr_peters2 == 1
nr_peters3 := sql db {
select count from User where name == name
}
}!
assert nr_peters3 == 1
peters := sql db {
select from User where name == name
}
}!
assert peters.len == 1
assert peters[0].name == 'Peter'
mut users := sql db {
select from User where name == name limit 1
}
}!
one_peter := users.first()
assert one_peter.name == 'Peter'
@ -141,7 +141,7 @@ fn test_orm() {
users = sql db {
select from User where id == 1
}
}!
user := users.first()
assert user.name == 'Sam'
@ -150,7 +150,7 @@ fn test_orm() {
users = sql db {
select from User where id > 0
}
}!
assert users.len == 3
assert users[0].name == 'Sam'
assert users[1].name == 'Peter'
@ -158,12 +158,12 @@ fn test_orm() {
users2 := sql db {
select from User where id < 0
}
}!
assert users2.len == 0
users3 := sql db {
select from User where age == 29 || age == 31
}
}!
assert users3.len == 2
assert users3[0].age == 29
@ -175,11 +175,11 @@ fn test_orm() {
}
sql db {
insert new_user into User
}
}!
users = sql db {
select from User where id == 4
}
}!
x := users.first()
assert x.age == 30
@ -188,14 +188,14 @@ fn test_orm() {
users = sql db {
select from User where id == 3
}
}!
kate := users.first()
assert kate.is_customer == true
users = sql db {
select from User where is_customer == true limit 1
}
}!
customer := users.first()
assert customer.is_customer == true
@ -203,22 +203,22 @@ fn test_orm() {
sql db {
update User set age = 31 where name == 'Kate'
}
}!
users = sql db {
select from User where id == 3
}
}!
kate2 := users.first()
assert kate2.age == 31
assert kate2.name == 'Kate'
sql db {
update User set age = 32, name = 'Kate N' where name == 'Kate'
}
}!
users = sql db {
select from User where id == 3
}
}!
mut kate3 := users.first()
assert kate3.age == 32
assert kate3.name == 'Kate N'
@ -226,11 +226,11 @@ fn test_orm() {
new_age := 33
sql db {
update User set age = new_age, name = 'Kate N' where id == 3
}
}!
users = sql db {
select from User where id == 3
}
}!
kate3 = users.first()
assert kate3.age == 33
@ -239,42 +239,42 @@ fn test_orm() {
foo := Foo{34}
sql db {
update User set age = foo.age, name = 'Kate N' where id == 3
}
}!
users = sql db {
select from User where id == 3
}
}!
kate3 = users.first()
assert kate3.age == 34
assert kate3.name == 'Kate N'
no_user := sql db {
select from User where id == 30
}
}!
assert no_user.len == 0
two_users := sql db {
select from User limit 2
}
}!
assert two_users.len == 2
assert two_users[0].id == 1
y := sql db {
select from User limit 2 offset 1
}
}!
assert y.len == 2
assert y[0].id == 2
z := sql db {
select from User order by id limit 2 offset offset_const
}
}!
assert z.len == 2
assert z[0].id == 3
users = sql db {
select from User order by age desc limit 1
}
}!
oldest := users.first()
assert oldest.age == 34
@ -282,17 +282,17 @@ fn test_orm() {
offs := 1
users = sql db {
select from User order by age desc limit 1 offset offs
}
}!
second_oldest := users.first()
assert second_oldest.age == 31
sql db {
delete from User where age == 34
}
}!
users = sql db {
select from User order by age desc limit 1
}
}!
updated_oldest := users.first()
assert updated_oldest.age == 31
@ -300,41 +300,41 @@ fn test_orm() {
// db.exec('insert into User (name, age) values (NULL, 31)')
users = sql db {
select from User where id == 5
}
}!
assert users.len == 0
users = sql db {
select from User where id == 1
}
}!
age_test := users.first()
assert age_test.age == 29
sql db {
update User set age = age + 1 where id == 1
}
}!
users = sql db {
select from User where id == 1
}
}!
mut first := users.first()
assert first.age == 30
sql db {
update User set age = age * 2 where id == 1
}
}!
users = sql db {
select from User where id == 1
}
}!
first = users.first()
assert first.age == 60
sql db {
create table TestTime
}
}!
tnow := time.now()
@ -344,11 +344,11 @@ fn test_orm() {
sql db {
insert time_test into TestTime
}
}!
data := sql db {
select from TestTime where create == tnow
}
}!
assert data.len == 1
assert tnow.unix == data[0].create.unix
@ -357,26 +357,26 @@ fn test_orm() {
sql db {
insert mod into Module
}
}!
sql db {
update Module set test_id = 11 where id == 1
}
}!
mut modules := sql db {
select from Module where id == 1
}
}!
assert modules.first().test_id == 11
t := time.now()
sql db {
update Module set created = t where id == 1
}
}!
modules = sql db {
select from Module where id == 1
}
}!
// Note: usually updated_time_mod.created != t, because t has
// its microseconds set, while the value retrieved from the DB
@ -385,12 +385,12 @@ fn test_orm() {
users = sql db {
select from User where (name == 'Sam' && is_customer == true) || id == 1
}
}!
assert users.first() == first
sql db {
drop table Module
drop table TestTime
}
}!
}

View File

@ -1767,9 +1767,8 @@ pub:
pos token.Pos
where_expr Expr
update_exprs []Expr // for `update`
// is_top_level indicates that a statement is parsed from code
// and is not inserted by ORM for inserting in related tables.
is_top_level bool
// is_generated indicates a statement is generated by ORM for complex queries with related tables.
is_generated bool
scope &Scope = unsafe { nil }
pub mut:
object_var_name string // `user`
@ -1788,6 +1787,8 @@ pub:
has_offset bool
has_desc bool
is_array bool
// is_generated indicates a statement is generated by ORM for complex queries with related tables.
is_generated bool
or_expr OrExpr
pos token.Pos
pub mut:

View File

@ -11,6 +11,8 @@ const (
v_orm_prefix = 'V ORM'
)
type ORMExpr = ast.SqlExpr | ast.SqlStmt
fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
c.inside_sql = true
defer {
@ -47,12 +49,13 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
pos: node.pos
has_where: true
where_expr: ast.None{}
typ: typ
typ: typ.set_flag(.result)
db_expr: node.db_expr
table_expr: ast.TypeNode{
pos: node.table_expr.pos
typ: typ
}
is_generated: true
}
tmp_inside_sql := c.inside_sql
@ -141,33 +144,21 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
}
c.expr(node.db_expr)
if node.or_expr.kind == .block {
if node.or_expr.stmts.len == 0 {
c.orm_error('or block needs to return a default value', node.or_expr.pos)
}
if node.or_expr.stmts.len > 0 && node.or_expr.stmts.last() is ast.ExprStmt {
c.expected_or_type = node.typ
}
c.stmts_ending_with_expression(node.or_expr.stmts)
c.check_expr_opt_call(node, node.typ)
c.expected_or_type = ast.void_type
}
return node.typ
c.check_orm_or_expr(node)
return node.typ.clear_flag(.result)
}
fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) ast.Type {
node.db_expr_type = c.table.unaliased_type(c.expr(node.db_expr))
mut typ := ast.void_type
for mut line in node.lines {
a := c.sql_stmt_line(mut line)
if a != ast.void_type {
typ = a
c.sql_stmt_line(mut line)
}
}
if node.or_expr.kind == .block {
c.stmts_ending_with_expression(node.or_expr.stmts)
}
return typ
c.check_orm_or_expr(node)
return ast.void_type
}
fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
@ -183,7 +174,7 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
c.cur_orm_ts = old_ts
}
if node.kind == .insert && node.is_top_level {
if node.kind == .insert && !node.is_generated {
inserting_object_name := node.object_var_name
inserting_object := node.scope.find(inserting_object_name) or {
c.error('undefined ident: `${inserting_object_name}`', node.pos)
@ -238,6 +229,7 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
typ: typ
}
object_var_name: object_var_name
is_generated: true
}
tmp_inside_sql := c.inside_sql
c.sql_stmt_line(mut n)
@ -468,3 +460,39 @@ fn (_ &Checker) fn_return_type_flag_to_string(typ ast.Type) string {
''
}
}
fn (mut c Checker) check_orm_or_expr(expr ORMExpr) {
if expr is ast.SqlExpr {
if expr.is_generated {
return
}
}
return_type := if expr is ast.SqlExpr {
expr.typ
} else {
ast.void_type.set_flag(.result)
}
if expr.or_expr.kind == .absent {
if c.inside_defer {
c.error('V ORM returns a result, so it should have an `or {}` block at the end',
expr.pos)
} else {
c.error('V ORM returns a result, so it should have either an `or {}` block, or `!` at the end',
expr.pos)
}
} else {
c.check_or_expr(expr.or_expr, return_type.clear_flag(.result), return_type, if expr is ast.SqlExpr {
expr
} else {
ast.empty_expr
})
}
if expr.or_expr.kind == .block {
c.expected_or_type = return_type.clear_flag(.result)
c.stmts_ending_with_expression(expr.or_expr.stmts)
c.expected_or_type = ast.void_type
}
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_empty_struct.vv:9:15: error: V ORM: select: empty field
8 | _ := sql db {
9 | select from Person
| ~~~~~~
10 | }
10 | }!
11 | }

View File

@ -7,5 +7,5 @@ fn main() {
db := sqlite.connect(':memory:')!
_ := sql db {
select from Person
}
}!
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_fn_call_with_wrong_return_type.vv:52:37: error: V ORM:
51 | steve := sql db {
52 | select from Parent where child == get_second_child()
| ~~~~~~~~~~~~~~~~~~
53 | }
53 | }!
54 |

View File

@ -31,7 +31,7 @@ fn main() {
sql db {
create table Parent
create table Child
}
}!
new_parent := Parent{
name: 'test'
@ -40,17 +40,17 @@ fn main() {
sql db {
insert new_parent into Parent
}
}!
first_child := get_first_child()
sql db {
insert first_child into Child
}
}!
steve := sql db {
select from Parent where child == get_second_child()
}
}!
dump(steve)
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_insert_object_with_mismatched_type_error.vv:19:10: erro
18 | create table Tiddlers
19 | insert tiddler into Tiddlers
| ~~~~~~~
20 | }
20 | }!
21 | }

View File

@ -17,5 +17,5 @@ fn main() {
sql db {
create table Tiddlers
insert tiddler into Tiddlers
}
}!
}

View File

@ -4,5 +4,5 @@ vlib/v/checker/tests/orm_left_side_expr_in_infix_expr_has_no_struct_field_error.
17 | users := sql db {
18 | select from User where first == second
| ~~~~~
19 | }
19 | }!
20 |

View File

@ -9,14 +9,14 @@ fn main() {
sql db {
create table User
}
}!
first := 'first'
second := 'second'
users := sql db {
select from User where first == second
}
}!
println(users)
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_limit_less_than_zero_error.vv:18:26: error: V ORM: `lim
17 | users := sql db {
18 | select from User limit user_limit
| ~~~~~~~~~~
19 | }
19 | }!
20 |

View File

@ -16,7 +16,7 @@ fn main() {
users := sql db {
select from User limit user_limit
}
}!
println(users)
}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/orm_no_default_value.vv:11:4: error: V ORM: or block needs to return a default value
vlib/v/checker/tests/orm_no_default_value.vv:11:4: error: assignment requires a non empty `or {}` block
9 | _ := sql db {
10 | select from Person
11 | } or {

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_not_a_struct.vv:10:15: error: V ORM: the table symbol `
9 | _ := sql db {
10 | select from Person
| ~~~~~~
11 | }
11 | }!
12 | }

View File

@ -8,5 +8,5 @@ fn main() {
db := sqlite.connect(':memory:')!
_ := sql db {
select from Person
}
}!
}

View File

@ -4,10 +4,10 @@ vlib/v/checker/tests/orm_using_non_struct_field_in_order_by_error.vv:14:29: erro
13 | users := sql db {
14 | select from User order by database
| ~~~~~~~~
15 | }
15 | }!
16 |
vlib/v/checker/tests/orm_using_non_struct_field_in_order_by_error.vv:17:2: error: `println` can not print void expressions
15 | }
15 | }!
16 |
17 | println(users)
| ~~~~~~~~~~~~~~

View File

@ -12,7 +12,7 @@ fn main() {
users := sql db {
select from User order by database
}
}!
println(users)
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_using_undefined_object_in_insert_error.vv:13:10: error:
12 | create table Node
13 | insert bug into Node
| ~~~
14 | }
14 | }!
15 | }

View File

@ -11,5 +11,5 @@ fn main() {
sql db {
create table Node
insert bug into Node
}
}!
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_using_undefined_var_in_where_err.vv:24:35: error: undef
23 | _ := sql db {
24 | select from User where email == email
| ~~~~~
25 | }
25 | }!
26 | }

View File

@ -14,13 +14,13 @@ fn main() {
db := sqlite.connect(':memory:')!
sql db {
create table User
}
}!
m := User{}
sql db {
insert m into User
}
}!
_ := sql db {
select from User where email == email
}
}!
}

View File

@ -3,5 +3,5 @@ vlib/v/checker/tests/orm_wrong_where_expr_error.vv:15:26: error: V ORM: `where`
14 | users := sql db {
15 | select from User where 3
| ^
16 | }
16 | }!
17 |

View File

@ -9,11 +9,11 @@ fn main() {
sql db {
create table User
}
}!
users := sql db {
select from User where 3
}
}!
println(users)
}

View File

@ -3,7 +3,6 @@
module c
import v.ast
import v.token
import v.util
enum SqlExprSide {
@ -65,11 +64,7 @@ fn (mut g Gen) sql_stmt_line(nd ast.SqlStmtLine, expr string, or_expr ast.OrExpr
g.sql_delete(node, expr, table_name)
}
if or_expr.kind == .block {
g.or_block(res, or_expr, ast.int_type.set_flag(.result))
} else if or_expr.kind == .absent {
g.write_error_handling_for_orm_result(node.pos, res)
}
}
fn (mut g Gen) sql_create_table(node ast.SqlStmtLine, expr string, table_name string) {
@ -554,10 +549,10 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
}
}
res := g.new_tmp_var()
select_result_var_name := g.new_tmp_var()
table_name := g.get_table_name(node.table_expr)
g.sql_table_name = g.table.sym(node.table_expr.typ).name
g.write('${result_name}_Array_Array_orm__Primitive _o${res} = orm__Connection_name_table[${expr}._typ]._method_select(${expr}._object, ')
g.write('${result_name}_Array_Array_orm__Primitive ${select_result_var_name} = orm__Connection_name_table[${expr}._typ]._method_select(${expr}._object, ')
g.write('(orm__SelectConfig){')
g.write('.table = _SLIT("${table_name}"),')
g.write('.is_count = ${node.is_count},')
@ -650,38 +645,37 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
}
g.writeln(');')
mut tmp_left := g.new_tmp_var()
g.writeln('${g.typ(node.typ.set_flag(.result))} ${tmp_left};')
unwrapped_typ := node.typ.clear_flag(.result)
unwrapped_c_typ := g.typ(unwrapped_typ)
c_typ := g.typ(node.typ)
if node.or_expr.kind == .block {
g.writeln('${tmp_left}.is_error = _o${res}.is_error;')
g.writeln('${tmp_left}.err = _o${res}.err;')
g.or_block(tmp_left, node.or_expr, node.typ.set_flag(.result))
mut non_orm_result_var_name := g.new_tmp_var()
g.writeln('${c_typ} ${non_orm_result_var_name};')
g.writeln('${non_orm_result_var_name}.is_error = ${select_result_var_name}.is_error;')
g.writeln('${non_orm_result_var_name}.err = ${select_result_var_name}.err;')
g.or_block(non_orm_result_var_name, node.or_expr, node.typ)
g.writeln('else {')
g.indent++
} else if node.or_expr.kind == .absent {
g.write_error_handling_for_orm_result(node.pos, '_o${res}')
}
g.writeln('Array_Array_orm__Primitive ${res} = (*(Array_Array_orm__Primitive*)_o${res}.data);')
select_unwrapped_result_var_name := g.new_tmp_var()
g.writeln('Array_Array_orm__Primitive ${select_unwrapped_result_var_name} = (*(Array_Array_orm__Primitive*)${select_result_var_name}.data);')
if node.is_count {
g.writeln('*(${g.typ(node.typ)}*) ${tmp_left}.data = *((*(orm__Primitive*) array_get((*(Array_orm__Primitive*)array_get(${res}, 0)), 0))._int);')
if node.or_expr.kind == .block {
g.writeln('*(${unwrapped_c_typ}*) ${non_orm_result_var_name}.data = *((*(orm__Primitive*) array_get((*(Array_orm__Primitive*)array_get(${select_unwrapped_result_var_name}, 0)), 0))._int);')
g.indent--
g.writeln('}')
}
} else {
tmp := g.new_tmp_var()
styp := g.typ(node.typ)
idx := g.new_tmp_var()
g.writeln('int ${idx} = 0;')
mut typ_str := ''
if node.is_array {
info := g.table.sym(node.typ).array_info()
typ_str = g.typ(info.elem_type)
g.writeln('${styp} ${tmp}_array = __new_array(0, ${res}.len, sizeof(${typ_str}));')
g.writeln('for (; ${idx} < ${res}.len; ${idx}++) {')
g.writeln('${unwrapped_c_typ} ${tmp}_array = __new_array(0, ${select_unwrapped_result_var_name}.len, sizeof(${typ_str}));')
g.writeln('for (; ${idx} < ${select_unwrapped_result_var_name}.len; ${idx}++) {')
g.indent++
g.write('${typ_str} ${tmp} = (${typ_str}) {')
inf := g.table.sym(info.elem_type).struct_info()
@ -693,7 +687,7 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
}
g.writeln('};')
} else {
g.write('${styp} ${tmp} = (${styp}){')
g.write('${unwrapped_c_typ} ${tmp} = (${unwrapped_c_typ}){')
info := g.table.sym(node.typ).struct_info()
for i, field in info.fields {
g.zero_struct_field(field)
@ -704,10 +698,10 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
g.writeln('};')
}
g.writeln('if (${res}.len > 0) {')
g.writeln('if (${select_unwrapped_result_var_name}.len > 0) {')
g.indent++
for i, field in fields {
sel := '(*(orm__Primitive*) array_get((*(Array_orm__Primitive*) array_get(${res}, ${idx})), ${i}))'
sel := '(*(orm__Primitive*) array_get((*(Array_orm__Primitive*) array_get(${select_unwrapped_result_var_name}, ${idx})), ${i}))'
sym := g.table.sym(field.typ)
if sym.kind == .struct_ && sym.name != 'time.Time' {
mut sub := node.sub_structs[int(field.typ)]
@ -758,7 +752,7 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
scope: 0
}
mut arr := ast.SqlExpr{
typ: field.typ
typ: field.typ.set_flag(.result)
is_count: sub.is_count
db_expr: sub.db_expr
has_where: sub.has_where
@ -768,6 +762,7 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
order_expr: sub.order_expr
has_desc: sub.has_desc
is_array: true
is_generated: true
pos: sub.pos
has_limit: sub.has_limit
limit_expr: sub.limit_expr
@ -791,19 +786,19 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
g.writeln('}')
}
g.write('*(${g.typ(node.typ)}*) ${tmp_left}.data = ${tmp}')
g.write('*(${unwrapped_c_typ}*) ${non_orm_result_var_name}.data = ${tmp}')
if node.is_array {
g.write('_array')
}
g.writeln(';')
if node.or_expr.kind == .block {
g.indent--
g.writeln('}')
}
}
g.write('${left} *(${g.typ(node.typ)}*) ${tmp_left}.data')
if !g.inside_call {
g.writeln(';')
g.write('${left} *(${unwrapped_c_typ}*) ${non_orm_result_var_name}.data')
if node.is_generated {
g.write(';')
}
}
@ -862,20 +857,6 @@ fn (mut g Gen) get_field_name(field ast.StructField) string {
return name
}
fn (mut g Gen) write_error_handling_for_orm_result(expr_pos &token.Pos, result_var_name string) {
g.writeln('if (${result_var_name}.is_error) {')
if g.pref.is_debug {
g.write_v_source_line_info(expr_pos)
paline, pafile, pamod, pafn := g.panic_debug_info(expr_pos)
g.write('\tpanic_debug(${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), IError_str(${result_var_name}.err) );')
} else {
g.writeln('\t_v_panic(IError_str(${result_var_name}.err));')
}
g.writeln('}')
}
fn (mut g Gen) write_orm_connection_init(connection_var_name string, db_expr &ast.Expr) {
db_expr_type := g.get_db_type(db_expr) or { verror('V ORM: unknown db type for ${db_expr}') }
@ -884,7 +865,7 @@ fn (mut g Gen) write_orm_connection_init(connection_var_name string, db_expr &as
reference_sign := if is_pointer { '' } else { '&' }
db_ctype_name = db_ctype_name.trim_right('*')
g.writeln('// orm')
g.writeln('// V ORM')
g.write('orm__Connection ${connection_var_name} = ')
if db_ctype_name == 'orm__Connection' {

View File

@ -85,9 +85,10 @@ fn (mut p Parser) sql_expr() ast.Expr {
p.inside_match = false
or_expr := p.parse_sql_or_block()
p.inside_match = tmp_inside_match
return ast.SqlExpr{
is_count: is_count
typ: typ
typ: typ.set_flag(.result)
or_expr: or_expr
db_expr: db_expr
where_expr: where_expr
@ -100,6 +101,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
order_expr: order_expr
has_desc: has_desc
is_array: if is_count { false } else { true }
is_generated: false
pos: pos.extend(p.prev_tok.pos())
table_expr: ast.TypeNode{
typ: table_type
@ -149,21 +151,11 @@ fn (mut p Parser) parse_sql_or_block() ast.OrExpr {
mut pos := p.tok.pos()
if p.tok.kind == .key_orelse {
was_inside_or_expr := p.inside_or_expr
p.inside_or_expr = true
p.next()
p.open_scope()
p.scope.register(ast.Var{
name: 'err'
typ: ast.error_type
pos: p.tok.pos()
is_used: true
})
kind = .block
stmts = p.parse_block_no_scope(false)
pos = pos.extend(p.prev_tok.pos())
p.close_scope()
p.inside_or_expr = was_inside_or_expr
stmts, pos = p.or_block(.with_err_var)
} else if p.tok.kind == .not {
kind = .propagate_result
p.next()
}
return ast.OrExpr{
@ -198,6 +190,7 @@ fn (mut p Parser) parse_sql_stmt_line() ast.SqlStmtLine {
pos: typ_pos
}
scope: p.scope
is_generated: false
}
} else if n == 'drop' {
kind = .drop
@ -215,6 +208,7 @@ fn (mut p Parser) parse_sql_stmt_line() ast.SqlStmtLine {
typ: typ
pos: typ_pos
}
is_generated: false
scope: p.scope
}
}
@ -285,14 +279,14 @@ fn (mut p Parser) parse_sql_stmt_line() ast.SqlStmtLine {
update_exprs: update_exprs
kind: kind
where_expr: where_expr
is_top_level: true
is_generated: false
scope: p.scope
}
}
fn (mut p Parser) check_sql_keyword(name string) ?bool {
if p.check_name() != name {
p.error('orm: expecting `${name}`')
p.error('V ORM: expecting `${name}`')
return none
}
return true

View File

@ -0,0 +1,7 @@
vlib/v/parser/tests/orm_no_error_handler.vv:8:7: error: V ORM returns a result, so it should have either an `or {}` block, or `!` at the end
6 | db := true
7 |
8 | _ := sql db {
| ~~~~~~~~
9 | select from User
10 | }

View File

@ -0,0 +1,11 @@
struct User {
id int
}
fn main() {
db := true
_ := sql db {
select from User
}
}

View File

@ -3,5 +3,5 @@ vlib/v/parser/tests/sql_undefined_variables_in_complex_exprs.vv:13:73: error: un
12 | _ := sql _ {
13 | select from User where (age > 18) && (city == 'London' || username == username)
| ~~~~~~~~
14 | }
14 | }!
15 | }

View File

@ -11,5 +11,5 @@ mut:
fn main() {
_ := sql _ {
select from User where (age > 18) && (city == 'London' || username == username)
}
}!
}

View File

@ -1,5 +1,5 @@
================ V panic ================
module: main
function: main()
message: db.sqlite.SQLError: no such table: User (1) (INSERT INTO `User` (`id`, `name`) VALUES (?1, ?2);); code: 1
file: vlib/v/slow_tests/inout/orm_panic_for_insert_into_not_created_table.vv:16
message: no such table: User (1) (INSERT INTO `User` (`id`, `name`) VALUES (?1, ?2);); code: 1
file: vlib/v/slow_tests/inout/orm_panic_for_insert_into_not_created_table.vv:17

View File

@ -14,5 +14,5 @@ fn main() {
sql db {
insert user into User
}
}!
}

View File

@ -1,5 +1,5 @@
================ V panic ================
module: main
function: main()
message: db.sqlite.SQLError: no such table: User (1) (SELECT `id`, `name` FROM `User`;); code: 1
file: vlib/v/slow_tests/inout/orm_panic_for_select_from_not_created_table.vv:11
message: no such table: User (1) (SELECT `id`, `name` FROM `User`;); code: 1
file: vlib/v/slow_tests/inout/orm_panic_for_select_from_not_created_table.vv:13

View File

@ -10,7 +10,7 @@ fn main() {
users := sql db {
select from User
}
}!
println(users)
}

View File

@ -19,7 +19,7 @@ pub mut:
arch []GitRepoArch [fkey: 'repo_id']
}
pub fn (db &VieterDb) get_git_repos() []GitRepo {
pub fn (db &VieterDb) get_git_repos() ![]GitRepo {
// NB: the query here, uses the `repo` field on GitRepo,
// while GitRepo is joined to GitRepoArch,
// which does *not* have a `repo` field.
@ -28,7 +28,7 @@ pub fn (db &VieterDb) get_git_repos() []GitRepo {
// a lingering c.cur_orm_ts state. The fix was to save/restore c.cur_orm_ts .
res := sql db.conn {
select from GitRepo where repo == 'something' order by id
}
}!
return res
}

View File

@ -17,10 +17,10 @@ fn test_orm_array() {
mut db := sqlite.connect(':memory:') or { panic(err) }
sql db {
create table Parent
}
}!
sql db {
create table Child
}
}!
par := Parent{
name: 'test'
@ -36,15 +36,15 @@ fn test_orm_array() {
sql db {
insert par into Parent
}
}!
parents := sql db {
select from Parent where id == 1
}
}!
sql db {
drop table Parent
}
}!
parent := parents.first()
assert parent.name == par.name
@ -57,10 +57,10 @@ fn test_orm_relationship() {
mut db := sqlite.connect(':memory:') or { panic(err) }
sql db {
create table Parent
}
}!
sql db {
create table Child
}
}!
mut child := Child{
name: 'abc'
@ -73,11 +73,11 @@ fn test_orm_relationship() {
sql db {
insert par into Parent
}
}!
mut parents := sql db {
select from Parent where id == 1
}
}!
mut parent := parents.first()
child.parent_id = parent.id
@ -85,20 +85,20 @@ fn test_orm_relationship() {
sql db {
insert child into Child
}
}!
child.name = 'bacon'
sql db {
insert child into Child
}
}!
assert parent.name == par.name
assert parent.children.len == 0
parents = sql db {
select from Parent where id == 1
}
}!
parent = parents.first()
assert parent.name == par.name
@ -108,17 +108,17 @@ fn test_orm_relationship() {
mut children := sql db {
select from Child
}
}!
assert children.len == 2
sql db {
drop table Parent
}
}!
children = sql db {
select from Child
}
}!
assert children.len == 2
}

View File

@ -14,10 +14,10 @@ fn test_orm_sub_structs() {
db := sqlite.connect(':memory:') or { panic(err) }
sql db {
create table Upper
}
}!
sql db {
create table SubStruct
}
}!
upper_1 := Upper{
sub: SubStruct{
@ -27,11 +27,11 @@ fn test_orm_sub_structs() {
sql db {
insert upper_1 into Upper
}
}!
uppers := sql db {
select from Upper where id == 1
}
}!
assert uppers.first().sub.name == upper_1.sub.name
}

View File

@ -13,12 +13,12 @@ fn test_sql_statement_inside_fn_call() {
db := sqlite.connect(':memory:') or { panic('failed') }
sql db {
create table Movie
}
}!
m := Movie{1, 'Maria'}
sql db {
insert m into Movie
}
dump(x((sql db {
}!
dump(x(sql db {
select from Movie where id == 1
}).first()))
}!.first()))
}

View File

@ -44,7 +44,7 @@ pub fn (mut app App) new_article() vweb.Result {
println(article)
sql app.db {
insert article into Article
}
} or {}
return app.redirect('/')
}