orm: fix empty struct and simplify (#8246)

pull/8281/head
Louis Schmieder 2021-01-22 23:28:26 +01:00 committed by GitHub
parent dbf84520f1
commit e06e8b10cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 64 additions and 49 deletions

View File

@ -1156,13 +1156,12 @@ pub:
kind SqlStmtKind kind SqlStmtKind
db_expr Expr // `db` in `sql db {` db_expr Expr // `db` in `sql db {`
object_var_name string // `user` object_var_name string // `user`
table_type table.Type
pos token.Position pos token.Position
where_expr Expr where_expr Expr
updated_columns []string // for `update set x=y` updated_columns []string // for `update set x=y`
update_exprs []Expr // for `update` update_exprs []Expr // for `update`
pub mut: pub mut:
table_name string table_expr Type
fields []table.Field fields []table.Field
} }
@ -1179,12 +1178,11 @@ pub:
order_expr Expr order_expr Expr
has_desc bool has_desc bool
is_array bool is_array bool
table_type table.Type
pos token.Position pos token.Position
has_limit bool has_limit bool
limit_expr Expr limit_expr Expr
pub mut: pub mut:
table_name string table_expr Type
fields []table.Field fields []table.Field
} }

View File

@ -5220,16 +5220,15 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) table.Type {
defer { defer {
c.inside_sql = false c.inside_sql = false
} }
sym := c.table.get_type_symbol(node.table_type) sym := c.table.get_type_symbol(node.table_expr.typ)
if sym.kind == .placeholder { if sym.kind == .placeholder {
c.error('orm: unknown type `$sym.name`', node.pos) c.error('orm: unknown type `$sym.name`', node.pos)
return table.void_type return table.void_type
} }
c.cur_orm_ts = sym c.cur_orm_ts = sym
info := sym.info as table.Struct info := sym.info as table.Struct
fields := c.fetch_and_verify_orm_fields(info, node.pos, node.table_name) fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name)
node.fields = fields node.fields = fields
node.table_name = sym.name
if node.has_where { if node.has_where {
c.expr(node.where_expr) c.expr(node.where_expr)
} }
@ -5251,17 +5250,18 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
defer { defer {
c.inside_sql = false c.inside_sql = false
} }
if node.table_type == 0 { sym := c.table.get_type_symbol(node.table_expr.typ)
c.error('orm: unknown type `$node.table_name`', node.pos) if node.table_expr.typ == 0 {
c.error('orm: unknown type `$sym.name`', node.pos)
} }
sym := c.table.get_type_symbol(node.table_type)
if sym.kind == .placeholder { if sym.kind == .placeholder {
c.error('orm: unknown type `$sym.name`', node.pos) c.error('orm: unknown type `$sym.name`', node.pos)
return table.void_type return table.void_type
} }
c.cur_orm_ts = sym c.cur_orm_ts = sym
info := sym.info as table.Struct info := sym.info as table.Struct
fields := c.fetch_and_verify_orm_fields(info, node.pos, node.table_name) table_sym := c.table.get_type_symbol(node.table_expr.typ)
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, table_sym.name)
node.fields = fields node.fields = fields
c.expr(node.db_expr) c.expr(node.db_expr)
if node.kind == .update { if node.kind == .update {
@ -5278,6 +5278,7 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Posi
[table.string_type, table.int_type, table.bool_type] && !it.attrs.contains('skip')) [table.string_type, table.int_type, table.bool_type] && !it.attrs.contains('skip'))
if fields.len == 0 { if fields.len == 0 {
c.error('V orm: select: empty fields in `$table_name`', pos) c.error('V orm: select: empty fields in `$table_name`', pos)
return []table.Field{}
} }
if fields[0].name != 'id' { if fields[0].name != 'id' {
c.error('V orm: `id int` must be the first field in `$table_name`', pos) c.error('V orm: `id int` must be the first field in `$table_name`', pos)

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/orm_empty_struct.vv:9:15: error: V orm: select: empty fields in `Person`
7 | db := sqlite.connect(':memory:')?
8 | _ := sql db {
9 | select from Person
| ~~~~~~
10 | }
11 | }

View File

@ -0,0 +1,11 @@
import sqlite
struct Person {
}
fn main() {
db := sqlite.connect(':memory:')?
_ := sql db {
select from Person
}
}

View File

@ -1327,8 +1327,8 @@ pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) {
f.writeln(' {') f.writeln(' {')
f.write('\t') f.write('\t')
f.write('select ') f.write('select ')
esym := f.table.get_type_symbol(node.table_type) esym := f.table.get_type_symbol(node.table_expr.typ)
table_name := esym.name table_name := util.strip_mod_name(esym.name)
if node.is_count { if node.is_count {
f.write('count ') f.write('count ')
} else { } else {
@ -1342,7 +1342,7 @@ pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) {
f.write(' ') f.write(' ')
} }
} }
f.write('from ${util.strip_mod_name(table_name)}') f.write('from $table_name')
if node.has_where { if node.has_where {
f.write(' where ') f.write(' where ')
f.expr(node.where_expr) f.expr(node.where_expr)
@ -2366,12 +2366,13 @@ pub fn (mut f Fmt) sql_stmt(node ast.SqlStmt) {
f.write('sql ') f.write('sql ')
f.expr(node.db_expr) f.expr(node.db_expr)
f.writeln(' {') f.writeln(' {')
table_name := util.strip_mod_name(f.table.get_type_symbol(node.table_expr.typ).name)
match node.kind { match node.kind {
.insert { .insert {
f.writeln('\tinsert $node.object_var_name into ${util.strip_mod_name(node.table_name)}') f.writeln('\tinsert $node.object_var_name into $table_name')
} }
.update { .update {
f.write('\tupdate ${util.strip_mod_name(node.table_name)} set ') f.write('\tupdate $table_name set ')
for i, col in node.updated_columns { for i, col in node.updated_columns {
f.write('$col = ') f.write('$col = ')
f.expr(node.update_exprs[i]) f.expr(node.update_exprs[i])
@ -2387,7 +2388,7 @@ pub fn (mut f Fmt) sql_stmt(node ast.SqlStmt) {
f.writeln('') f.writeln('')
} }
.delete { .delete {
f.write('\tdelete from ${util.strip_mod_name(node.table_name)} where ') f.write('\tdelete from $table_name where ')
f.expr(node.where_expr) f.expr(node.where_expr)
f.writeln('') f.writeln('')
} }

View File

@ -26,12 +26,13 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
g.expr(node.db_expr) g.expr(node.db_expr)
g.writeln(';') g.writeln(';')
g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, _SLIT("') g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, _SLIT("')
table_name := util.strip_mod_name(g.table.get_type_symbol(node.table_expr.typ).name)
if node.kind == .insert { if node.kind == .insert {
g.write('INSERT INTO `${util.strip_mod_name(node.table_name)}` (') g.write('INSERT INTO `$table_name` (')
} else if node.kind == .update { } else if node.kind == .update {
g.write('UPDATE `${util.strip_mod_name(node.table_name)}` SET ') g.write('UPDATE `$table_name` SET ')
} else if node.kind == .delete { } else if node.kind == .delete {
g.write('DELETE FROM `${util.strip_mod_name(node.table_name)}` ') g.write('DELETE FROM `$table_name` ')
} }
if node.kind == .insert { if node.kind == .insert {
for i, field in node.fields { for i, field in node.fields {
@ -108,9 +109,10 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
*/ */
cur_line := g.go_before_stmt(0) cur_line := g.go_before_stmt(0)
mut sql_query := 'SELECT ' mut sql_query := 'SELECT '
table_name := util.strip_mod_name(g.table.get_type_symbol(node.table_expr.typ).name)
if node.is_count { if node.is_count {
// `select count(*) from User` // `select count(*) from User`
sql_query += 'COUNT(*) FROM `${util.strip_mod_name(node.table_name)}` ' sql_query += 'COUNT(*) FROM `$table_name` '
} else { } else {
// `select id, name, country from User` // `select id, name, country from User`
for i, field in node.fields { for i, field in node.fields {
@ -119,7 +121,7 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
sql_query += ', ' sql_query += ', '
} }
} }
sql_query += ' FROM `${util.strip_mod_name(node.table_name)}`' sql_query += ' FROM `$table_name`'
} }
if node.has_where { if node.has_where {
sql_query += ' WHERE ' sql_query += ' WHERE '

View File

@ -20,6 +20,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
p.check_name() // from p.check_name() // from
typ = table.int_type typ = table.int_type
} }
table_pos := p.tok.position()
table_type := p.parse_type() // `User` table_type := p.parse_type() // `User`
mut where_expr := ast.Expr{} mut where_expr := ast.Expr{}
has_where := p.tok.kind == .name && p.tok.lit == 'where' has_where := p.tok.kind == .name && p.tok.lit == 'where'
@ -89,7 +90,6 @@ fn (mut p Parser) sql_expr() ast.Expr {
is_count: is_count is_count: is_count
typ: typ typ: typ
db_expr: db_expr db_expr: db_expr
table_type: table_type
where_expr: where_expr where_expr: where_expr
has_where: has_where has_where: has_where
has_limit: has_limit has_limit: has_limit
@ -101,6 +101,10 @@ fn (mut p Parser) sql_expr() ast.Expr {
has_desc: has_desc has_desc: has_desc
is_array: !query_one is_array: !query_one
pos: pos pos: pos
table_expr: ast.Type{
typ: table_type
pos: table_pos
}
} }
} }
@ -127,18 +131,15 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
kind = .update kind = .update
} }
mut inserted_var_name := '' mut inserted_var_name := ''
mut table_name := '' mut table_type := table.Type(0)
if kind != .delete { if kind != .delete {
expr := p.expr(0) if kind == .update {
match expr { table_type = p.parse_type()
ast.Ident { } else if kind == .insert {
if kind == .insert { expr := p.expr(0)
inserted_var_name = expr.name if expr is ast.Ident {
} else if kind == .update { inserted_var_name = expr.name
table_name = expr.name } else {
}
}
else {
p.error('can only insert variables') p.error('can only insert variables')
return ast.SqlStmt{} return ast.SqlStmt{}
} }
@ -170,26 +171,18 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
p.error('expecting `from`') p.error('expecting `from`')
return ast.SqlStmt{} return ast.SqlStmt{}
} }
mut table_type := table.Type(0)
mut table_pos := p.tok.position()
mut where_expr := ast.Expr{} mut where_expr := ast.Expr{}
if kind == .insert { if kind == .insert {
table_type = p.parse_type() // `User` table_pos = p.tok.position()
sym := p.table.get_type_symbol(table_type) table_type = p.parse_type()
// info := sym.info as table.Struct
// fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type])
table_name = sym.name
} else if kind == .update { } else if kind == .update {
if !p.pref.is_fmt {
// NB: in vfmt mode, v parses just a single file and table_name may not have been registered
idx := p.table.find_type_idx(p.prepend_mod(table_name))
table_type = table.new_type(idx)
}
p.check_sql_keyword('where') or { return ast.SqlStmt{} } p.check_sql_keyword('where') or { return ast.SqlStmt{} }
where_expr = p.expr(0) where_expr = p.expr(0)
} else if kind == .delete { } else if kind == .delete {
table_pos = p.tok.position()
table_type = p.parse_type() table_type = p.parse_type()
sym := p.table.get_type_symbol(table_type)
table_name = sym.name
p.check_sql_keyword('where') or { return ast.SqlStmt{} } p.check_sql_keyword('where') or { return ast.SqlStmt{} }
where_expr = p.expr(0) where_expr = p.expr(0)
} }
@ -197,8 +190,10 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
pos.last_line = p.prev_tok.line_nr pos.last_line = p.prev_tok.line_nr
return ast.SqlStmt{ return ast.SqlStmt{
db_expr: db_expr db_expr: db_expr
table_name: table_name table_expr: ast.Type{
table_type: table_type typ: table_type
pos: table_pos
}
object_var_name: inserted_var_name object_var_name: inserted_var_name
pos: pos pos: pos
updated_columns: updated_columns updated_columns: updated_columns