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 import v.util
const ( const (
fkey_attr_name = 'fkey' fkey_attr_name = 'fkey'
v_orm_prefix = 'V ORM' v_orm_prefix = 'V ORM'
connection_interface_name = 'orm.Connection'
) )
type ORMExpr = ast.SqlExpr | ast.SqlStmt type ORMExpr = ast.SqlExpr | ast.SqlStmt
@ -18,8 +19,13 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
defer { defer {
c.inside_sql = false 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 } 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 old_ts := c.cur_orm_ts
c.cur_orm_ts = *sym c.cur_orm_ts = *sym
defer { 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 { 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)) node.db_expr_type = c.table.unaliased_type(c.expr(node.db_expr))
for mut line in node.lines { 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 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 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
8 | 10 |
9 | println(sql db { 11 | println(sql db {
10 | select from User where name like 10 12 | select from User where name like 10
| ~~ | ~~
11 | }!) 13 | }!)
12 | 14 |
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 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
12 | 14 |
13 | println(sql db { 15 | println(sql db {
14 | select from User where 10 like true 16 | select from User where 10 like true
| ~~ | ~~
15 | }!) 17 | }!)
16 | } 18 | }

View File

@ -1,10 +1,12 @@
import db.sqlite
struct User { struct User {
id int [primary] id int [primary]
name string name string
} }
fn main() { fn main() {
db := '' db := sqlite.connect(':memory:')!
println(sql db { println(sql db {
select from User where name like 10 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 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
6 | db := true 8 | db := sqlite.connect(':memory:')!
7 | 9 |
8 | _ := sql db { 10 | _ := sql db {
| ~~~~~~~~ | ~~~~~~~~
9 | select from User 11 | select from User
10 | } 12 | }

View File

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