mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen, checker: add panic in ORM for invalid queries, when there are no or {}
blocks, add type checking for the fkey
attribute, add tests (#16977)
This commit is contained in:
parent
93ee6d107a
commit
2fb9bdce9a
@ -84,6 +84,7 @@ const (
|
|||||||
'vlib/x/json2/json2_test.v',
|
'vlib/x/json2/json2_test.v',
|
||||||
]
|
]
|
||||||
skip_test_files = [
|
skip_test_files = [
|
||||||
|
'do_not_remove',
|
||||||
'cmd/tools/vdoc/html_tag_escape_test.v', /* can't locate local module: markdown */
|
'cmd/tools/vdoc/html_tag_escape_test.v', /* can't locate local module: markdown */
|
||||||
'cmd/tools/vdoc/tests/vdoc_file_test.v', /* fails on Windows; order of output is not as expected */
|
'cmd/tools/vdoc/tests/vdoc_file_test.v', /* fails on Windows; order of output is not as expected */
|
||||||
'vlib/context/onecontext/onecontext_test.v',
|
'vlib/context/onecontext/onecontext_test.v',
|
||||||
@ -91,9 +92,10 @@ const (
|
|||||||
'vlib/db/mysql/mysql_orm_test.v' /* mysql not installed */,
|
'vlib/db/mysql/mysql_orm_test.v' /* mysql not installed */,
|
||||||
'vlib/db/pg/pg_orm_test.v' /* pg not installed */,
|
'vlib/db/pg/pg_orm_test.v' /* pg not installed */,
|
||||||
]
|
]
|
||||||
|
// These tests are too slow to be run in the CI on each PR/commit
|
||||||
|
// in the sanitized modes:
|
||||||
skip_fsanitize_too_slow = [
|
skip_fsanitize_too_slow = [
|
||||||
// These tests are too slow to be run in the CI on each PR/commit
|
'do_not_remove',
|
||||||
// in the sanitized modes:
|
|
||||||
'vlib/v/compiler_errors_test.v',
|
'vlib/v/compiler_errors_test.v',
|
||||||
'vlib/v/doc/doc_test.v',
|
'vlib/v/doc/doc_test.v',
|
||||||
'vlib/v/fmt/fmt_test.v',
|
'vlib/v/fmt/fmt_test.v',
|
||||||
@ -109,6 +111,7 @@ const (
|
|||||||
'vlib/v/slow_tests/valgrind/valgrind_test.v',
|
'vlib/v/slow_tests/valgrind/valgrind_test.v',
|
||||||
]
|
]
|
||||||
skip_with_fsanitize_memory = [
|
skip_with_fsanitize_memory = [
|
||||||
|
'do_not_remove',
|
||||||
'vlib/net/tcp_simple_client_server_test.v',
|
'vlib/net/tcp_simple_client_server_test.v',
|
||||||
'vlib/net/http/cookie_test.v',
|
'vlib/net/http/cookie_test.v',
|
||||||
'vlib/net/http/http_test.v',
|
'vlib/net/http/http_test.v',
|
||||||
@ -120,6 +123,8 @@ const (
|
|||||||
'vlib/net/tcp_test.v',
|
'vlib/net/tcp_test.v',
|
||||||
'vlib/orm/orm_test.v',
|
'vlib/orm/orm_test.v',
|
||||||
'vlib/orm/orm_sql_or_blocks_test.v',
|
'vlib/orm/orm_sql_or_blocks_test.v',
|
||||||
|
'vlib/orm/orm_create_and_drop_test.v',
|
||||||
|
'vlib/orm/orm_insert_test.v',
|
||||||
'vlib/db/sqlite/sqlite_test.v',
|
'vlib/db/sqlite/sqlite_test.v',
|
||||||
'vlib/db/sqlite/sqlite_orm_test.v',
|
'vlib/db/sqlite/sqlite_orm_test.v',
|
||||||
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
|
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
|
||||||
@ -128,6 +133,7 @@ const (
|
|||||||
'vlib/v/tests/orm_joined_tables_select_test.v',
|
'vlib/v/tests/orm_joined_tables_select_test.v',
|
||||||
'vlib/v/tests/sql_statement_inside_fn_call_test.v',
|
'vlib/v/tests/sql_statement_inside_fn_call_test.v',
|
||||||
'vlib/v/tests/orm_stmt_wrong_return_checking_test.v',
|
'vlib/v/tests/orm_stmt_wrong_return_checking_test.v',
|
||||||
|
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
|
||||||
'vlib/vweb/tests/vweb_test.v',
|
'vlib/vweb/tests/vweb_test.v',
|
||||||
'vlib/vweb/csrf/csrf_test.v',
|
'vlib/vweb/csrf/csrf_test.v',
|
||||||
'vlib/vweb/request_test.v',
|
'vlib/vweb/request_test.v',
|
||||||
@ -141,13 +147,20 @@ const (
|
|||||||
'vlib/v/tests/fn_literal_type_test.v',
|
'vlib/v/tests/fn_literal_type_test.v',
|
||||||
]
|
]
|
||||||
skip_with_fsanitize_address = [
|
skip_with_fsanitize_address = [
|
||||||
|
'do_not_remove',
|
||||||
'vlib/net/websocket/websocket_test.v',
|
'vlib/net/websocket/websocket_test.v',
|
||||||
|
'vlib/orm/orm_create_and_drop_test.v',
|
||||||
|
'vlib/orm/orm_insert_test.v',
|
||||||
'vlib/v/tests/websocket_logger_interface_should_compile_test.v',
|
'vlib/v/tests/websocket_logger_interface_should_compile_test.v',
|
||||||
'vlib/v/tests/orm_sub_array_struct_test.v',
|
'vlib/v/tests/orm_sub_array_struct_test.v',
|
||||||
|
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
|
||||||
]
|
]
|
||||||
skip_with_fsanitize_undefined = [
|
skip_with_fsanitize_undefined = [
|
||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
|
'vlib/orm/orm_create_and_drop_test.v',
|
||||||
|
'vlib/orm/orm_insert_test.v',
|
||||||
'vlib/v/tests/orm_sub_array_struct_test.v',
|
'vlib/v/tests/orm_sub_array_struct_test.v',
|
||||||
|
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
|
||||||
]
|
]
|
||||||
skip_with_werror = [
|
skip_with_werror = [
|
||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
@ -160,11 +173,13 @@ const (
|
|||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
]
|
]
|
||||||
skip_on_musl = [
|
skip_on_musl = [
|
||||||
|
'do_not_remove',
|
||||||
'vlib/v/slow_tests/profile/profile_test.v',
|
'vlib/v/slow_tests/profile/profile_test.v',
|
||||||
'vlib/gg/draw_fns_api_test.v',
|
'vlib/gg/draw_fns_api_test.v',
|
||||||
'vlib/v/tests/skip_unused/gg_code.vv',
|
'vlib/v/tests/skip_unused/gg_code.vv',
|
||||||
]
|
]
|
||||||
skip_on_ubuntu_musl = [
|
skip_on_ubuntu_musl = [
|
||||||
|
'do_not_remove',
|
||||||
//'vlib/v/gen/js/jsgen_test.v',
|
//'vlib/v/gen/js/jsgen_test.v',
|
||||||
'vlib/net/http/cookie_test.v',
|
'vlib/net/http/cookie_test.v',
|
||||||
'vlib/net/http/http_test.v',
|
'vlib/net/http/http_test.v',
|
||||||
@ -175,10 +190,13 @@ const (
|
|||||||
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
|
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
|
||||||
'vlib/orm/orm_test.v',
|
'vlib/orm/orm_test.v',
|
||||||
'vlib/orm/orm_sql_or_blocks_test.v',
|
'vlib/orm/orm_sql_or_blocks_test.v',
|
||||||
|
'vlib/orm/orm_create_and_drop_test.v',
|
||||||
|
'vlib/orm/orm_insert_test.v',
|
||||||
'vlib/v/tests/orm_sub_struct_test.v',
|
'vlib/v/tests/orm_sub_struct_test.v',
|
||||||
'vlib/v/tests/orm_sub_array_struct_test.v',
|
'vlib/v/tests/orm_sub_array_struct_test.v',
|
||||||
'vlib/v/tests/orm_joined_tables_select_test.v',
|
'vlib/v/tests/orm_joined_tables_select_test.v',
|
||||||
'vlib/v/tests/orm_stmt_wrong_return_checking_test.v',
|
'vlib/v/tests/orm_stmt_wrong_return_checking_test.v',
|
||||||
|
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
|
||||||
'vlib/v/tests/sql_statement_inside_fn_call_test.v',
|
'vlib/v/tests/sql_statement_inside_fn_call_test.v',
|
||||||
'vlib/clipboard/clipboard_test.v',
|
'vlib/clipboard/clipboard_test.v',
|
||||||
'vlib/vweb/tests/vweb_test.v',
|
'vlib/vweb/tests/vweb_test.v',
|
||||||
@ -208,6 +226,7 @@ const (
|
|||||||
'vlib/v/tests/const_and_global_with_same_name_test.v', // error C2099: initializer is not a constant
|
'vlib/v/tests/const_and_global_with_same_name_test.v', // error C2099: initializer is not a constant
|
||||||
]
|
]
|
||||||
skip_on_windows = [
|
skip_on_windows = [
|
||||||
|
'do_not_remove',
|
||||||
'vlib/context/cancel_test.v',
|
'vlib/context/cancel_test.v',
|
||||||
'vlib/context/deadline_test.v',
|
'vlib/context/deadline_test.v',
|
||||||
'vlib/context/empty_test.v',
|
'vlib/context/empty_test.v',
|
||||||
@ -215,6 +234,7 @@ const (
|
|||||||
'vlib/orm/orm_test.v',
|
'vlib/orm/orm_test.v',
|
||||||
'vlib/v/tests/orm_sub_struct_test.v',
|
'vlib/v/tests/orm_sub_struct_test.v',
|
||||||
'vlib/v/tests/orm_joined_tables_select_test.v',
|
'vlib/v/tests/orm_joined_tables_select_test.v',
|
||||||
|
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
|
||||||
'vlib/net/websocket/ws_test.v',
|
'vlib/net/websocket/ws_test.v',
|
||||||
'vlib/net/unix/unix_test.v',
|
'vlib/net/unix/unix_test.v',
|
||||||
'vlib/net/unix/use_net_and_net_unix_together_test.v',
|
'vlib/net/unix/use_net_and_net_unix_together_test.v',
|
||||||
@ -248,6 +268,7 @@ const (
|
|||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
]
|
]
|
||||||
skip_on_non_amd64_or_arm64 = [
|
skip_on_non_amd64_or_arm64 = [
|
||||||
|
'do_not_remove',
|
||||||
// closures aren't implemented yet:
|
// closures aren't implemented yet:
|
||||||
'vlib/v/tests/closure_test.v',
|
'vlib/v/tests/closure_test.v',
|
||||||
'vlib/context/cancel_test.v',
|
'vlib/context/cancel_test.v',
|
||||||
|
79
vlib/orm/orm_create_and_drop_test.v
Normal file
79
vlib/orm/orm_create_and_drop_test.v
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import db.sqlite
|
||||||
|
|
||||||
|
struct Parent {
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
children []Child [fkey: 'parent_id']
|
||||||
|
notes []Note [fkey: 'owner_id']
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Child {
|
||||||
|
mut:
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
parent_id int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Note {
|
||||||
|
mut:
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
owner_id int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_create_only_one_table() {
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
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 }
|
||||||
|
|
||||||
|
_ := sql db {
|
||||||
|
select count from Note
|
||||||
|
} or { is_note_created = false }
|
||||||
|
|
||||||
|
assert is_child_created == false
|
||||||
|
assert is_note_created == false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_drop_only_one_table() {
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
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
|
||||||
|
mut is_note_dropped := false
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
_ := sql db {
|
||||||
|
select count from Parent
|
||||||
|
} or { is_parent_dropped = true }
|
||||||
|
|
||||||
|
_ := sql db {
|
||||||
|
select count from Child
|
||||||
|
} or { is_child_dropped = true }
|
||||||
|
|
||||||
|
_ := sql db {
|
||||||
|
select count from Note
|
||||||
|
} or { is_note_dropped = true }
|
||||||
|
|
||||||
|
assert is_parent_dropped
|
||||||
|
assert is_child_dropped == false
|
||||||
|
assert is_note_dropped == false
|
||||||
|
}
|
87
vlib/orm/orm_insert_test.v
Normal file
87
vlib/orm/orm_insert_test.v
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import db.sqlite
|
||||||
|
|
||||||
|
struct Parent {
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
name string
|
||||||
|
children []Child [fkey: 'parent_id']
|
||||||
|
notes []Note [fkey: 'owner_id']
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Child {
|
||||||
|
mut:
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
parent_id int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Note {
|
||||||
|
mut:
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
owner_id int
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_orm_insert_with_multiple_child_elements() {
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
create table Parent
|
||||||
|
}
|
||||||
|
sql db {
|
||||||
|
create table Child
|
||||||
|
}
|
||||||
|
sql db {
|
||||||
|
create table Note
|
||||||
|
}
|
||||||
|
|
||||||
|
new_parent := Parent{
|
||||||
|
name: 'test'
|
||||||
|
children: [
|
||||||
|
Child{
|
||||||
|
name: 'Lisa'
|
||||||
|
},
|
||||||
|
Child{
|
||||||
|
name: 'Steve'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
notes: [
|
||||||
|
Note{
|
||||||
|
text: 'First note'
|
||||||
|
},
|
||||||
|
Note{
|
||||||
|
text: 'Second note'
|
||||||
|
},
|
||||||
|
Note{
|
||||||
|
text: 'Third note'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
insert new_parent into Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := sql db {
|
||||||
|
select from Parent where id == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert parent.children.len == new_parent.children.len
|
||||||
|
assert parent.notes.len == new_parent.notes.len
|
||||||
|
|
||||||
|
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'
|
||||||
|
assert parent.children[1].name == 'Steve'
|
||||||
|
|
||||||
|
assert parent.notes[0].text == 'First note'
|
||||||
|
assert parent.notes[1].text == 'Second note'
|
||||||
|
assert parent.notes[2].text == 'Third note'
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
// import os
|
|
||||||
// import term
|
|
||||||
// import db.mysql
|
// import db.mysql
|
||||||
// import db.pg
|
// import db.pg
|
||||||
import time
|
import time
|
||||||
@ -34,21 +32,13 @@ struct TestTime {
|
|||||||
|
|
||||||
fn test_orm() {
|
fn test_orm() {
|
||||||
db := sqlite.connect(':memory:') or { panic(err) }
|
db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
db.exec('drop table if exists User')
|
|
||||||
|
|
||||||
// db := pg.connect(host: 'localhost', port: 5432, user: 'louis', password: 'abc', dbname: 'orm') or { panic(err) }
|
|
||||||
/*
|
|
||||||
mut db := mysql.Connection{
|
|
||||||
host: '127.0.0.1'
|
|
||||||
username: 'root'
|
|
||||||
password: 'pw'
|
|
||||||
dbname: 'v'
|
|
||||||
}
|
|
||||||
db.connect() or { panic(err) }*/
|
|
||||||
|
|
||||||
sql db {
|
sql db {
|
||||||
create table Module
|
create table Module
|
||||||
}
|
}
|
||||||
|
sql db {
|
||||||
|
create table User
|
||||||
|
}
|
||||||
|
|
||||||
name := 'Peter'
|
name := 'Peter'
|
||||||
|
|
||||||
@ -84,38 +74,41 @@ fn test_orm() {
|
|||||||
}
|
}
|
||||||
assert nr_all_users == 3
|
assert nr_all_users == 3
|
||||||
println('nr_all_users=${nr_all_users}')
|
println('nr_all_users=${nr_all_users}')
|
||||||
//
|
|
||||||
nr_users1 := sql db {
|
nr_users1 := sql db {
|
||||||
select count from User where id == 1
|
select count from User where id == 1
|
||||||
}
|
}
|
||||||
assert nr_users1 == 1
|
assert nr_users1 == 1
|
||||||
println('nr_users1=${nr_users1}')
|
println('nr_users1=${nr_users1}')
|
||||||
//
|
|
||||||
nr_peters := sql db {
|
nr_peters := sql db {
|
||||||
select count from User where id == 2 && name == 'Peter'
|
select count from User where id == 2 && name == 'Peter'
|
||||||
}
|
}
|
||||||
assert nr_peters == 1
|
assert nr_peters == 1
|
||||||
println('nr_peters=${nr_peters}')
|
println('nr_peters=${nr_peters}')
|
||||||
//
|
|
||||||
nr_peters2 := sql db {
|
nr_peters2 := sql db {
|
||||||
select count from User where id == 2 && name == name
|
select count from User where id == 2 && name == name
|
||||||
}
|
}
|
||||||
assert nr_peters2 == 1
|
assert nr_peters2 == 1
|
||||||
|
|
||||||
nr_peters3 := sql db {
|
nr_peters3 := sql db {
|
||||||
select count from User where name == name
|
select count from User where name == name
|
||||||
}
|
}
|
||||||
assert nr_peters3 == 1
|
assert nr_peters3 == 1
|
||||||
|
|
||||||
peters := sql db {
|
peters := sql db {
|
||||||
select from User where name == name
|
select from User where name == name
|
||||||
}
|
}
|
||||||
assert peters.len == 1
|
assert peters.len == 1
|
||||||
assert peters[0].name == 'Peter'
|
assert peters[0].name == 'Peter'
|
||||||
|
|
||||||
one_peter := sql db {
|
one_peter := sql db {
|
||||||
select from User where name == name limit 1
|
select from User where name == name limit 1
|
||||||
}
|
}
|
||||||
assert one_peter.name == 'Peter'
|
assert one_peter.name == 'Peter'
|
||||||
assert one_peter.id == 2
|
assert one_peter.id == 2
|
||||||
//
|
|
||||||
user := sql db {
|
user := sql db {
|
||||||
select from User where id == 1
|
select from User where id == 1
|
||||||
}
|
}
|
||||||
@ -123,7 +116,7 @@ fn test_orm() {
|
|||||||
assert user.name == 'Sam'
|
assert user.name == 'Sam'
|
||||||
assert user.id == 1
|
assert user.id == 1
|
||||||
assert user.age == 29
|
assert user.age == 29
|
||||||
//
|
|
||||||
users := sql db {
|
users := sql db {
|
||||||
select from User where id > 0
|
select from User where id > 0
|
||||||
}
|
}
|
||||||
@ -132,13 +125,13 @@ fn test_orm() {
|
|||||||
assert users[0].name == 'Sam'
|
assert users[0].name == 'Sam'
|
||||||
assert users[1].name == 'Peter'
|
assert users[1].name == 'Peter'
|
||||||
assert users[1].age == 31
|
assert users[1].age == 31
|
||||||
//
|
|
||||||
users2 := sql db {
|
users2 := sql db {
|
||||||
select from User where id < 0
|
select from User where id < 0
|
||||||
}
|
}
|
||||||
println(users2)
|
println(users2)
|
||||||
assert users2.len == 0
|
assert users2.len == 0
|
||||||
//
|
|
||||||
users3 := sql db {
|
users3 := sql db {
|
||||||
select from User where age == 29 || age == 31
|
select from User where age == 29 || age == 31
|
||||||
}
|
}
|
||||||
@ -146,13 +139,13 @@ fn test_orm() {
|
|||||||
assert users3.len == 2
|
assert users3.len == 2
|
||||||
assert users3[0].age == 29
|
assert users3[0].age == 29
|
||||||
assert users3[1].age == 31
|
assert users3[1].age == 31
|
||||||
//
|
|
||||||
missing_user := sql db {
|
missing_user := sql db {
|
||||||
select from User where id == 8777
|
select from User where id == 8777
|
||||||
}
|
}
|
||||||
println('missing_user:')
|
println('missing_user:')
|
||||||
println(missing_user) // zero struct
|
println(missing_user) // zero struct
|
||||||
//
|
|
||||||
new_user := User{
|
new_user := User{
|
||||||
name: 'New user'
|
name: 'New user'
|
||||||
age: 30
|
age: 30
|
||||||
@ -161,7 +154,6 @@ fn test_orm() {
|
|||||||
insert new_user into User
|
insert new_user into User
|
||||||
}
|
}
|
||||||
|
|
||||||
// db.insert<User>(user2)
|
|
||||||
x := sql db {
|
x := sql db {
|
||||||
select from User where id == 4
|
select from User where id == 4
|
||||||
}
|
}
|
||||||
@ -169,18 +161,18 @@ fn test_orm() {
|
|||||||
assert x.age == 30
|
assert x.age == 30
|
||||||
assert x.id == 4
|
assert x.id == 4
|
||||||
assert x.name == 'New user'
|
assert x.name == 'New user'
|
||||||
//
|
|
||||||
kate := sql db {
|
kate := sql db {
|
||||||
select from User where id == 3
|
select from User where id == 3
|
||||||
}
|
}
|
||||||
assert kate.is_customer == true
|
assert kate.is_customer == true
|
||||||
//
|
|
||||||
customer := sql db {
|
customer := sql db {
|
||||||
select from User where is_customer == true limit 1
|
select from User where is_customer == true limit 1
|
||||||
}
|
}
|
||||||
assert customer.is_customer == true
|
assert customer.is_customer == true
|
||||||
assert customer.name == 'Kate'
|
assert customer.name == 'Kate'
|
||||||
//
|
|
||||||
sql db {
|
sql db {
|
||||||
update User set age = 31 where name == 'Kate'
|
update User set age = 31 where name == 'Kate'
|
||||||
}
|
}
|
||||||
@ -190,7 +182,7 @@ fn test_orm() {
|
|||||||
}
|
}
|
||||||
assert kate2.age == 31
|
assert kate2.age == 31
|
||||||
assert kate2.name == 'Kate'
|
assert kate2.name == 'Kate'
|
||||||
//
|
|
||||||
sql db {
|
sql db {
|
||||||
update User set age = 32, name = 'Kate N' where name == 'Kate'
|
update User set age = 32, name = 'Kate N' where name == 'Kate'
|
||||||
}
|
}
|
||||||
@ -200,18 +192,7 @@ fn test_orm() {
|
|||||||
}
|
}
|
||||||
assert kate3.age == 32
|
assert kate3.age == 32
|
||||||
assert kate3.name == 'Kate N'
|
assert kate3.name == 'Kate N'
|
||||||
//
|
|
||||||
/*
|
|
||||||
sql db {
|
|
||||||
update User set age = age + 1, name = 'Kate N' where name == 'Kate'
|
|
||||||
}
|
|
||||||
kate3 = sql db {
|
|
||||||
select from User where id == 3
|
|
||||||
}
|
|
||||||
println(kate3)
|
|
||||||
assert kate3.age == 32
|
|
||||||
assert kate3.name == 'Kate N'
|
|
||||||
*/
|
|
||||||
new_age := 33
|
new_age := 33
|
||||||
sql db {
|
sql db {
|
||||||
update User set age = new_age, name = 'Kate N' where id == 3
|
update User set age = new_age, name = 'Kate N' where id == 3
|
||||||
@ -222,7 +203,7 @@ fn test_orm() {
|
|||||||
}
|
}
|
||||||
assert kate3.age == 33
|
assert kate3.age == 33
|
||||||
assert kate3.name == 'Kate N'
|
assert kate3.name == 'Kate N'
|
||||||
//
|
|
||||||
foo := Foo{34}
|
foo := Foo{34}
|
||||||
sql db {
|
sql db {
|
||||||
update User set age = foo.age, name = 'Kate N' where id == 3
|
update User set age = foo.age, name = 'Kate N' where id == 3
|
||||||
@ -233,25 +214,25 @@ fn test_orm() {
|
|||||||
}
|
}
|
||||||
assert kate3.age == 34
|
assert kate3.age == 34
|
||||||
assert kate3.name == 'Kate N'
|
assert kate3.name == 'Kate N'
|
||||||
//
|
|
||||||
no_user := sql db {
|
no_user := sql db {
|
||||||
select from User where id == 30
|
select from User where id == 30
|
||||||
}
|
}
|
||||||
assert no_user.name == '' // TODO optional
|
assert no_user.name == '' // TODO optional
|
||||||
assert no_user.age == 0
|
assert no_user.age == 0
|
||||||
//
|
|
||||||
two_users := sql db {
|
two_users := sql db {
|
||||||
select from User limit 2
|
select from User limit 2
|
||||||
}
|
}
|
||||||
assert two_users.len == 2
|
assert two_users.len == 2
|
||||||
assert two_users[0].id == 1
|
assert two_users[0].id == 1
|
||||||
//
|
|
||||||
y := sql db {
|
y := sql db {
|
||||||
select from User limit 2 offset 1
|
select from User limit 2 offset 1
|
||||||
}
|
}
|
||||||
assert y.len == 2
|
assert y.len == 2
|
||||||
assert y[0].id == 2
|
assert y[0].id == 2
|
||||||
//
|
|
||||||
offset_const := 2
|
offset_const := 2
|
||||||
z := sql db {
|
z := sql db {
|
||||||
select from User order by id limit 2 offset offset_const
|
select from User order by id limit 2 offset offset_const
|
||||||
|
@ -5,6 +5,10 @@ module checker
|
|||||||
import v.ast
|
import v.ast
|
||||||
import v.token
|
import v.token
|
||||||
|
|
||||||
|
const (
|
||||||
|
fkey_attr_name = 'fkey'
|
||||||
|
)
|
||||||
|
|
||||||
fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
|
fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
|
||||||
c.inside_sql = true
|
c.inside_sql = true
|
||||||
defer {
|
defer {
|
||||||
@ -156,6 +160,8 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
|
|||||||
|| (c.table.sym(it.typ).kind == .array
|
|| (c.table.sym(it.typ).kind == .array
|
||||||
&& c.table.sym(c.table.sym(it.typ).array_info().elem_type).kind == .struct_))
|
&& c.table.sym(c.table.sym(it.typ).array_info().elem_type).kind == .struct_))
|
||||||
&& c.table.get_type_name(it.typ) != 'time.Time') {
|
&& c.table.get_type_name(it.typ) != 'time.Time') {
|
||||||
|
c.check_orm_struct_field_attributes(f)
|
||||||
|
|
||||||
typ := if c.table.sym(f.typ).kind == .struct_ {
|
typ := if c.table.sym(f.typ).kind == .struct_ {
|
||||||
f.typ
|
f.typ
|
||||||
} else if c.table.sym(f.typ).kind == .array {
|
} else if c.table.sym(f.typ).kind == .array {
|
||||||
@ -163,6 +169,7 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
|
|||||||
} else {
|
} else {
|
||||||
ast.Type(0)
|
ast.Type(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut object_var_name := '${node.object_var_name}.${f.name}'
|
mut object_var_name := '${node.object_var_name}.${f.name}'
|
||||||
if typ != f.typ {
|
if typ != f.typ {
|
||||||
object_var_name = node.object_var_name
|
object_var_name = node.object_var_name
|
||||||
@ -204,6 +211,52 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
|
|||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Checker) check_orm_struct_field_attributes(field ast.StructField) {
|
||||||
|
field_type := c.table.sym(field.typ)
|
||||||
|
mut has_fkey_attr := false
|
||||||
|
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == checker.fkey_attr_name {
|
||||||
|
if field_type.kind != .array && field_type.kind != .struct_ {
|
||||||
|
c.error('The `${checker.fkey_attr_name}` attribute must be used only with arrays and structures',
|
||||||
|
attr.pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !attr.has_arg {
|
||||||
|
c.error('The `${checker.fkey_attr_name}` attribute must have an argument',
|
||||||
|
attr.pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr.kind != .string {
|
||||||
|
c.error('`${checker.fkey_attr_name}` attribute must be string. Try [${checker.fkey_attr_name}: \'${attr.arg}\'] instead of [${checker.fkey_attr_name}: ${attr.arg}]',
|
||||||
|
attr.pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
field_struct_type := if field_type.info is ast.Array {
|
||||||
|
c.table.sym(field_type.info.elem_type)
|
||||||
|
} else {
|
||||||
|
field_type
|
||||||
|
}
|
||||||
|
|
||||||
|
field_struct_type.find_field(attr.arg) or {
|
||||||
|
c.error('`${field_struct_type.name}` struct has no field with name `${attr.arg}`',
|
||||||
|
attr.pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
has_fkey_attr = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if field_type.kind == .array && !has_fkey_attr {
|
||||||
|
c.error('A field that holds an array must be defined with the `${checker.fkey_attr_name}` attribute',
|
||||||
|
field.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, table_name string) []ast.StructField {
|
fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, table_name string) []ast.StructField {
|
||||||
fields := info.fields.filter(
|
fields := info.fields.filter(
|
||||||
(it.typ in [ast.string_type, ast.bool_type] || int(it.typ) in ast.number_type_idxs
|
(it.typ in [ast.string_type, ast.bool_type] || int(it.typ) in ast.number_type_idxs
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
module c
|
module c
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
|
import v.token
|
||||||
import v.util
|
import v.util
|
||||||
|
|
||||||
enum SqlExprSide {
|
enum SqlExprSide {
|
||||||
@ -29,7 +30,6 @@ fn (mut g Gen) sql_stmt_line(nd ast.SqlStmtLine, expr string, or_expr ast.OrExpr
|
|||||||
table_name := g.get_table_name(node.table_expr)
|
table_name := g.get_table_name(node.table_expr)
|
||||||
g.sql_table_name = g.table.sym(node.table_expr.typ).name
|
g.sql_table_name = g.table.sym(node.table_expr.typ).name
|
||||||
res := g.new_tmp_var()
|
res := g.new_tmp_var()
|
||||||
mut subs := false
|
|
||||||
|
|
||||||
if node.kind != .create {
|
if node.kind != .create {
|
||||||
mut fields := []ast.StructField{}
|
mut fields := []ast.StructField{}
|
||||||
@ -54,15 +54,13 @@ fn (mut g Gen) sql_stmt_line(nd ast.SqlStmtLine, expr string, or_expr ast.OrExpr
|
|||||||
if node.kind == .create {
|
if node.kind == .create {
|
||||||
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
||||||
g.sql_create_table(node, expr, table_name)
|
g.sql_create_table(node, expr, table_name)
|
||||||
subs = true
|
|
||||||
} else if node.kind == .drop {
|
} else if node.kind == .drop {
|
||||||
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
||||||
g.writeln('drop(${expr}._object, _SLIT("${table_name}"));')
|
g.writeln('drop(${expr}._object, _SLIT("${table_name}"));')
|
||||||
subs = true
|
|
||||||
} else if node.kind == .insert {
|
} else if node.kind == .insert {
|
||||||
arr := g.new_tmp_var()
|
arr := g.new_tmp_var()
|
||||||
g.writeln('Array_orm__Primitive ${arr} = __new_array_with_default_noscan(0, 0, sizeof(orm__Primitive), 0);')
|
g.writeln('Array_orm__Primitive ${arr} = __new_array_with_default_noscan(0, 0, sizeof(orm__Primitive), 0);')
|
||||||
g.sql_insert(node, expr, table_name, arr, res, '', false, '', or_expr)
|
g.sql_insert(node, expr, table_name, arr, res, '', '', or_expr)
|
||||||
} else if node.kind == .update {
|
} else if node.kind == .update {
|
||||||
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
||||||
g.sql_update(node, expr, table_name)
|
g.sql_update(node, expr, table_name)
|
||||||
@ -70,13 +68,11 @@ fn (mut g Gen) sql_stmt_line(nd ast.SqlStmtLine, expr string, or_expr ast.OrExpr
|
|||||||
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
||||||
g.sql_delete(node, expr, table_name)
|
g.sql_delete(node, expr, table_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if or_expr.kind == .block {
|
if or_expr.kind == .block {
|
||||||
g.or_block(res, or_expr, ast.int_type.set_flag(.result))
|
g.or_block(res, or_expr, ast.int_type.set_flag(.result))
|
||||||
}
|
} else if or_expr.kind == .absent {
|
||||||
if subs {
|
g.write_error_handling_for_orm_result(node.pos, res)
|
||||||
for _, sub in node.sub_structs {
|
|
||||||
g.sql_stmt_line(sub, expr, or_expr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +117,7 @@ fn (mut g Gen) sql_create_table(node ast.SqlStmtLine, expr string, table_name st
|
|||||||
g.writeln('));')
|
g.writeln('));')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sql_insert(node ast.SqlStmtLine, expr string, table_name string, last_ids_arr string, res string, pid string, is_array bool, fkey string, or_expr ast.OrExpr) {
|
fn (mut g Gen) sql_insert(node ast.SqlStmtLine, expr string, table_name string, last_ids_arr string, res string, pid string, fkey string, or_expr ast.OrExpr) {
|
||||||
mut subs := []ast.SqlStmtLine{}
|
mut subs := []ast.SqlStmtLine{}
|
||||||
mut arrs := []ast.SqlStmtLine{}
|
mut arrs := []ast.SqlStmtLine{}
|
||||||
mut fkeys := []string{}
|
mut fkeys := []string{}
|
||||||
@ -240,16 +236,13 @@ fn (mut g Gen) sql_insert(node ast.SqlStmtLine, expr string, table_name string,
|
|||||||
arr.fields = fff.clone()
|
arr.fields = fff.clone()
|
||||||
unsafe { fff.free() }
|
unsafe { fff.free() }
|
||||||
g.sql_insert(arr, expr, g.get_table_name(arr.table_expr), last_ids, res_,
|
g.sql_insert(arr, expr, g.get_table_name(arr.table_expr), last_ids, res_,
|
||||||
id_name, true, fkeys[i], or_expr)
|
id_name, fkeys[i], or_expr)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sql_update(node ast.SqlStmtLine, expr string, table_name string) {
|
fn (mut g Gen) sql_update(node ast.SqlStmtLine, expr string, table_name string) {
|
||||||
// println(table_name)
|
|
||||||
// println(expr)
|
|
||||||
// println(node)
|
|
||||||
g.write('update(${expr}._object, _SLIT("${table_name}"), (orm__QueryData){')
|
g.write('update(${expr}._object, _SLIT("${table_name}"), (orm__QueryData){')
|
||||||
g.write('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
g.write('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
||||||
g.write('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
g.write('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
||||||
@ -649,6 +642,8 @@ fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr as
|
|||||||
g.or_block(tmp_left, node.or_expr, node.typ.set_flag(.result))
|
g.or_block(tmp_left, node.or_expr, node.typ.set_flag(.result))
|
||||||
g.writeln('else {')
|
g.writeln('else {')
|
||||||
g.indent++
|
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);')
|
g.writeln('Array_Array_orm__Primitive ${res} = (*(Array_Array_orm__Primitive*)_o${res}.data);')
|
||||||
@ -849,3 +844,17 @@ fn (mut g Gen) get_field_name(field ast.StructField) string {
|
|||||||
}
|
}
|
||||||
return name
|
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('}')
|
||||||
|
}
|
||||||
|
@ -9,6 +9,8 @@ import v.util.vtest
|
|||||||
|
|
||||||
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true)
|
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true)
|
||||||
|
|
||||||
|
const v_ci_ubuntu_musl = os.getenv('V_CI_UBUNTU_MUSL').len > 0
|
||||||
|
|
||||||
const skip_files = [
|
const skip_files = [
|
||||||
'do_not_remove_this',
|
'do_not_remove_this',
|
||||||
'tmpl_parse_html.vv', // skipped, due to a V template compilation problem after b42c824
|
'tmpl_parse_html.vv', // skipped, due to a V template compilation problem after b42c824
|
||||||
@ -36,6 +38,13 @@ fn test_all() {
|
|||||||
println(term.bright_yellow('SKIP'))
|
println(term.bright_yellow('SKIP'))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if v_ci_ubuntu_musl {
|
||||||
|
if fname.contains('orm_') {
|
||||||
|
// the ORM programs use db.sqlite, which is not easy to install in a way usable by ubuntu-musl, so just skip them:
|
||||||
|
println(term.bright_yellow('SKIP on ubuntu musl'))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
program := path
|
program := path
|
||||||
tname := rand.ulid()
|
tname := rand.ulid()
|
||||||
compilation := os.execute('${os.quoted_path(vexe)} -o ${tname} -cflags "-w" -cg ${os.quoted_path(program)}')
|
compilation := os.execute('${os.quoted_path(vexe)} -o ${tname} -cflags "-w" -cg ${os.quoted_path(program)}')
|
||||||
|
@ -0,0 +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
|
@ -0,0 +1,18 @@
|
|||||||
|
import db.sqlite
|
||||||
|
|
||||||
|
struct User {
|
||||||
|
id int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
user := User{
|
||||||
|
name: 'test'
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
insert user into User
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +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
|
@ -0,0 +1,16 @@
|
|||||||
|
import db.sqlite
|
||||||
|
|
||||||
|
struct User {
|
||||||
|
id int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
users := sql db {
|
||||||
|
select from User
|
||||||
|
}
|
||||||
|
|
||||||
|
println(users)
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import db.sqlite
|
||||||
|
|
||||||
|
struct User {
|
||||||
|
id int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_or_block_error_handling_of_an_invalid_query() {
|
||||||
|
db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
|
||||||
|
users := sql db {
|
||||||
|
select from User
|
||||||
|
} or { []User{} }
|
||||||
|
|
||||||
|
println(users)
|
||||||
|
assert true
|
||||||
|
}
|
@ -18,6 +18,9 @@ fn test_orm_array() {
|
|||||||
sql db {
|
sql db {
|
||||||
create table Parent
|
create table Parent
|
||||||
}
|
}
|
||||||
|
sql db {
|
||||||
|
create table Child
|
||||||
|
}
|
||||||
|
|
||||||
par := Parent{
|
par := Parent{
|
||||||
name: 'test'
|
name: 'test'
|
||||||
@ -54,6 +57,9 @@ fn test_orm_relationship() {
|
|||||||
sql db {
|
sql db {
|
||||||
create table Parent
|
create table Parent
|
||||||
}
|
}
|
||||||
|
sql db {
|
||||||
|
create table Child
|
||||||
|
}
|
||||||
|
|
||||||
mut child := Child{
|
mut child := Child{
|
||||||
name: 'abc'
|
name: 'abc'
|
||||||
@ -111,5 +117,5 @@ fn test_orm_relationship() {
|
|||||||
select from Child
|
select from Child
|
||||||
}
|
}
|
||||||
|
|
||||||
assert children.len == 0
|
assert children.len == 2
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ fn test_orm_sub_structs() {
|
|||||||
sql db {
|
sql db {
|
||||||
create table Upper
|
create table Upper
|
||||||
}
|
}
|
||||||
|
sql db {
|
||||||
|
create table SubStruct
|
||||||
|
}
|
||||||
|
|
||||||
upper_1 := Upper{
|
upper_1 := Upper{
|
||||||
sub: SubStruct{
|
sub: SubStruct{
|
||||||
|
Loading…
Reference in New Issue
Block a user