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

checker: check db type implements orm.Connection and isn't an Option. (#18078)

This commit is contained in:
Mark aka walkingdevel 2023-04-29 08:36:21 +00:00 committed by GitHub
parent 9eee131423
commit e8df5a7861
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 121 additions and 23 deletions

View File

@ -7,8 +7,9 @@ import v.token
import v.util
const (
fkey_attr_name = 'fkey'
v_orm_prefix = 'V ORM'
fkey_attr_name = 'fkey'
v_orm_prefix = 'V ORM'
connection_interface_name = 'orm.Connection'
)
type ORMExpr = ast.SqlExpr | ast.SqlStmt
@ -18,8 +19,13 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
defer {
c.inside_sql = false
}
sym := c.table.sym(node.table_expr.typ)
if !c.check_db_expr(node.db_expr) {
return ast.void_type
}
c.ensure_type_exists(node.table_expr.typ, node.pos) or { return ast.void_type }
sym := c.table.sym(node.table_expr.typ)
old_ts := c.cur_orm_ts
c.cur_orm_ts = *sym
defer {
@ -150,6 +156,9 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
}
fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) ast.Type {
if !c.check_db_expr(node.db_expr) {
return ast.void_type
}
node.db_expr_type = c.table.unaliased_type(c.expr(node.db_expr))
for mut line in node.lines {
@ -496,3 +505,27 @@ fn (mut c Checker) check_orm_or_expr(expr ORMExpr) {
c.expected_or_type = ast.void_type
}
}
fn (mut c Checker) check_db_expr(db_expr &ast.Expr) bool {
connection_type_index := c.table.find_type_idx(checker.connection_interface_name)
connection_typ := ast.Type(connection_type_index)
db_expr_type := c.expr(db_expr)
// If we didn't find `orm.Connection`, we don't have any imported modules
// that depend on `orm` and implement the `orm.Connection` interface.
if connection_type_index == 0 {
c.error('expected a type that implements the `${checker.connection_interface_name}` interface',
db_expr.pos())
return false
}
is_implemented := c.type_implements(db_expr_type, connection_typ, db_expr.pos())
is_option := db_expr_type.has_flag(.option)
if is_implemented && is_option {
c.error(c.expected_msg(db_expr_type, db_expr_type.clear_flag(.option)), db_expr.pos())
return false
}
return true
}

View File

@ -1,14 +1,14 @@
vlib/v/checker/tests/like_operator_with_non_string_type_error.vv:10:36: error: the right operand of the `like` operator must be a string type
8 |
9 | println(sql db {
10 | select from User where name like 10
vlib/v/checker/tests/like_operator_with_non_string_type_error.vv:12:36: error: the right operand of the `like` operator must be a string type
10 |
11 | println(sql db {
12 | select from User where name like 10
| ~~
11 | }!)
12 |
vlib/v/checker/tests/like_operator_with_non_string_type_error.vv:14:26: error: the left operand of the `like` operator must be an identifier with a string type
12 |
13 | println(sql db {
14 | select from User where 10 like true
13 | }!)
14 |
vlib/v/checker/tests/like_operator_with_non_string_type_error.vv:16:26: error: the left operand of the `like` operator must be an identifier with a string type
14 |
15 | println(sql db {
16 | select from User where 10 like true
| ~~
15 | }!)
16 | }
17 | }!)
18 | }

View File

@ -1,10 +1,12 @@
import db.sqlite
struct User {
id int [primary]
name string
}
fn main() {
db := ''
db := sqlite.connect(':memory:')!
println(sql db {
select from User where name like 10

View File

@ -0,0 +1,28 @@
vlib/v/checker/tests/orm_db_expr_option_error.vv:16:11: error: expected `sqlite.DB`, not `?sqlite.DB`
14 | db_option := connect_option()
15 |
16 | _ := sql db_option {
| ~~~~~~~~~
17 | select from Account
18 | }!
vlib/v/checker/tests/orm_db_expr_option_error.vv:22:11: error: `Account` doesn't implement method `select` of interface `orm.Connection`
20 | account := Account{}
21 |
22 | _ := sql account {
| ~~~~~~~
23 | select from Account
24 | }!
vlib/v/checker/tests/orm_db_expr_option_error.vv:26:6: error: `Account` doesn't implement method `select` of interface `orm.Connection`
24 | }!
25 |
26 | sql account {
| ~~~~~~~
27 | insert account into Account
28 | }!
vlib/v/checker/tests/orm_db_expr_option_error.vv:30:6: error: expected `sqlite.DB`, not `?sqlite.DB`
28 | }!
29 |
30 | sql db_option {
| ~~~~~~~~~
31 | insert account into Account
32 | }!

View File

@ -0,0 +1,33 @@
module main
import db.sqlite
struct Account {
id int [primary]
}
fn connect_option() ?sqlite.DB {
return sqlite.connect(':memory:') or { return none }
}
fn main() {
db_option := connect_option()
_ := sql db_option {
select from Account
}!
account := Account{}
_ := sql account {
select from Account
}!
sql account {
insert account into Account
}!
sql db_option {
insert account into Account
}!
}

View File

@ -1,7 +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 {
vlib/v/parser/tests/orm_no_error_handler.vv:10:7: error: V ORM returns a result, so it should have either an `or {}` block, or `!` at the end
8 | db := sqlite.connect(':memory:')!
9 |
10 | _ := sql db {
| ~~~~~~~~
9 | select from User
10 | }
11 | select from User
12 | }

View File

@ -1,9 +1,11 @@
import db.sqlite
struct User {
id int
}
fn main() {
db := true
db := sqlite.connect(':memory:')!
_ := sql db {
select from User