mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser: breaking change, let V ORM queries return arrays for *all* non-count queries, including limit = 1 (#17719)
This commit is contained in:
@@ -16,18 +16,19 @@ fn (mut p Parser) sql_expr() ast.Expr {
|
||||
}
|
||||
p.check(.lcbr)
|
||||
p.check(.key_select)
|
||||
n := p.check_name()
|
||||
is_count := n == 'count'
|
||||
is_count := p.check_name() == 'count'
|
||||
mut typ := ast.void_type
|
||||
|
||||
if is_count {
|
||||
p.check_name() // from
|
||||
typ = ast.int_type
|
||||
}
|
||||
|
||||
table_pos := p.tok.pos()
|
||||
table_type := p.parse_type() // `User`
|
||||
|
||||
mut where_expr := ast.empty_expr
|
||||
has_where := p.tok.kind == .name && p.tok.lit == 'where'
|
||||
mut query_one := false // one object is returned, not an array
|
||||
|
||||
if has_where {
|
||||
p.next()
|
||||
where_expr = p.expr(0)
|
||||
@@ -37,11 +38,8 @@ fn (mut p Parser) sql_expr() ast.Expr {
|
||||
if where_check_result is ast.NodeError {
|
||||
return where_check_result
|
||||
}
|
||||
|
||||
if !is_count {
|
||||
query_one = p.has_sql_where_expr_with_comparison_with_id(&where_expr)
|
||||
}
|
||||
}
|
||||
|
||||
mut has_limit := false
|
||||
mut limit_expr := ast.empty_expr
|
||||
mut has_offset := false
|
||||
@@ -64,29 +62,25 @@ fn (mut p Parser) sql_expr() ast.Expr {
|
||||
has_desc = true
|
||||
}
|
||||
}
|
||||
|
||||
if p.tok.kind == .name && p.tok.lit == 'limit' {
|
||||
// `limit 1` means that a single object is returned
|
||||
p.check_name() // `limit`
|
||||
if p.tok.kind == .number && p.tok.lit == '1' {
|
||||
query_one = true
|
||||
}
|
||||
has_limit = true
|
||||
limit_expr = p.expr(0)
|
||||
}
|
||||
|
||||
if p.tok.kind == .name && p.tok.lit == 'offset' {
|
||||
p.check_name() // `offset`
|
||||
has_offset = true
|
||||
offset_expr = p.expr(0)
|
||||
}
|
||||
if !query_one && !is_count {
|
||||
// return an array
|
||||
|
||||
if is_count {
|
||||
typ = ast.int_type
|
||||
} else {
|
||||
typ = ast.new_type(p.table.find_or_register_array(table_type))
|
||||
} else if !is_count {
|
||||
// return a single object
|
||||
// TODO optional
|
||||
// typ = table_type.set_flag(.optional)
|
||||
typ = table_type
|
||||
}
|
||||
|
||||
p.check(.rcbr)
|
||||
p.inside_match = false
|
||||
or_expr := p.parse_sql_or_block()
|
||||
@@ -105,7 +99,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
|
||||
has_order: has_order
|
||||
order_expr: order_expr
|
||||
has_desc: has_desc
|
||||
is_array: !query_one
|
||||
is_array: if is_count { false } else { true }
|
||||
pos: pos.extend(p.prev_tok.pos())
|
||||
table_expr: ast.TypeNode{
|
||||
typ: table_type
|
||||
@@ -304,26 +298,6 @@ fn (mut p Parser) check_sql_keyword(name string) ?bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// has_sql_where_expr_with_comparison_with_id tries to search comparison with the `id` field.
|
||||
// If `id` is found it means that a database "should" return one row,
|
||||
// but it is not true and depends on a database scheme.
|
||||
// For example, it will be hard to use V ORM in an existing database scheme which wrote before using V.
|
||||
fn (p &Parser) has_sql_where_expr_with_comparison_with_id(expr &ast.Expr) bool {
|
||||
// This method will be removed in the future when we refuse it.
|
||||
// A more difficult expression with `id` means a user tries to find more than one row or he is wrong.
|
||||
// And there is no point to get one structure instead of an array.
|
||||
// `id == x` means that a single object is returned.
|
||||
if expr is ast.InfixExpr {
|
||||
if expr.left is ast.Ident && expr.op == .eq {
|
||||
return expr.left.name == 'id'
|
||||
}
|
||||
} else if expr is ast.ParExpr {
|
||||
return p.has_sql_where_expr_with_comparison_with_id(expr.expr)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// check_sql_where_expr_has_no_undefined_variables recursively tries to find undefined variables in the right part of infix expressions.
|
||||
fn (mut p Parser) check_sql_where_expr_has_no_undefined_variables(expr &ast.Expr, unacceptable_variable_names []string) ast.Expr {
|
||||
if expr is ast.Ident {
|
||||
|
||||
@@ -38,7 +38,7 @@ fn test_orm_array() {
|
||||
insert par into Parent
|
||||
}
|
||||
|
||||
parent := sql db {
|
||||
parents := sql db {
|
||||
select from Parent where id == 1
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ fn test_orm_array() {
|
||||
drop table Parent
|
||||
}
|
||||
|
||||
parent := parents.first()
|
||||
assert parent.name == par.name
|
||||
assert parent.children.len == par.children.len
|
||||
assert parent.children[0].name == 'abc'
|
||||
@@ -74,10 +75,11 @@ fn test_orm_relationship() {
|
||||
insert par into Parent
|
||||
}
|
||||
|
||||
mut parent := sql db {
|
||||
mut parents := sql db {
|
||||
select from Parent where id == 1
|
||||
}
|
||||
|
||||
mut parent := parents.first()
|
||||
child.parent_id = parent.id
|
||||
child.name = 'atum'
|
||||
|
||||
@@ -94,10 +96,11 @@ fn test_orm_relationship() {
|
||||
assert parent.name == par.name
|
||||
assert parent.children.len == 0
|
||||
|
||||
parent = sql db {
|
||||
parents = sql db {
|
||||
select from Parent where id == 1
|
||||
}
|
||||
|
||||
parent = parents.first()
|
||||
assert parent.name == par.name
|
||||
assert parent.children.len == 2
|
||||
assert parent.children[0].name == 'atum'
|
||||
|
||||
@@ -29,9 +29,9 @@ fn test_orm_sub_structs() {
|
||||
insert upper_1 into Upper
|
||||
}
|
||||
|
||||
upper_s := sql db {
|
||||
uppers := sql db {
|
||||
select from Upper where id == 1
|
||||
}
|
||||
|
||||
assert upper_s.sub.name == upper_1.sub.name
|
||||
assert uppers.first().sub.name == upper_1.sub.name
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ fn test_sql_statement_inside_fn_call() {
|
||||
sql db {
|
||||
insert m into Movie
|
||||
}
|
||||
dump(x(sql db {
|
||||
dump(x((sql db {
|
||||
select from Movie where id == 1
|
||||
}))
|
||||
}).first()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user