checker: do not allow {} for aliases; orm: update stmt

pull/5483/head
Alexander Medvednikov 2020-06-24 16:35:18 +02:00
parent 0ea2e687d1
commit 9df29d0dd2
5 changed files with 83 additions and 32 deletions

View File

@ -126,10 +126,9 @@ fn test_orm_sqlite() {
//
/*
sql db {
update User set age = 31 where name = 'Kate'
update User set age = 31 where name == 'Kate'
}
*/
}

View File

@ -343,6 +343,10 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
if type_sym.kind == .interface_ {
c.error('cannot instantiate interface `$type_sym.name`', struct_init.pos)
}
if type_sym.kind == .alias {
c.error('cannot instantiate type alias `$type_sym.name`', struct_init.pos)
return table.void_type
}
if !type_sym.is_public && type_sym.kind != .placeholder && type_sym.mod != c.mod {
c.error('type `$type_sym.name` is private', struct_init.pos)
}

View File

@ -501,7 +501,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
.name, .key_mut, .key_static, .mul {
if p.tok.kind == .name {
if p.tok.lit == 'sql' {
return p.sql_insert_expr()
return p.sql_stmt()
}
if p.peek_tok.kind == .colon {
// `label:`

View File

@ -31,7 +31,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
sym := p.table.get_type_symbol(table_type)
table_name := sym.name
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'
mut query_one := false // one object is returned, not an array
if has_where {
p.next()
@ -47,7 +47,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
}
}
}
if p.tok.kind ==.name && p.tok.lit == 'limit' {
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' {
@ -73,7 +73,8 @@ fn (mut p Parser) sql_expr() ast.Expr {
// get only string and int fields
// mut fields := []Var
info := sym.info as table.Struct
fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type] && 'skip' !in it.attrs)
fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type] &&
'skip' !in it.attrs)
if fields.len == 0 {
p.error('V orm: select: empty fields in `$table_name`')
}
@ -103,37 +104,79 @@ fn (mut p Parser) sql_expr() ast.Expr {
}
}
fn (mut p Parser) sql_insert_expr() ast.SqlStmt{
// insert user into User
// update User set nr_oders=nr_orders+1 where id == user_id
fn (mut p Parser) sql_stmt() ast.SqlStmt {
p.inside_match = true
defer { p.inside_match = false }
defer {
p.inside_match = false
}
// `sql db {`
p.check_name()
db_expr := p.expr(0)
//println(typeof(db_expr))
// println(typeof(db_expr))
p.check(.lcbr)
// kind := ast.SqlExprKind.select_
//
p.check_name() // insert
mut object_var_name := ''
mut n := p.check_name() // insert
mut kind := ast.SqlStmtKind.insert
if n == 'delete' {
kind = .delete
} else if n == 'update' {
kind = .update
}
mut inserted_var_name := ''
mut table_name := ''
expr := p.expr(0)
match expr {
ast.Ident { object_var_name = expr.name }
else { p.error('can only insert variables') }
ast.Ident {
if kind == .insert {
inserted_var_name = expr.name
} else if kind == .update {
table_name = expr.name
}
}
else {
p.error('can only insert variables')
}
}
n := p.check_name() // into
if n != 'into' {
n = p.check_name() // into
mut updated_columns := []string{}
if kind == .insert && n != 'into' {
p.error('expecting `into`')
} else if kind == .update {
if n != 'set' {
p.error('expecting `set`')
}
column := p.check_name()
updated_columns << column
p.check(.assign)
p.expr(0)
}
mut table_type := table.Type(0)
if kind == .insert {
table_type = p.parse_type() // `User`
sym := p.table.get_type_symbol(table_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 {
idx := p.table.find_type_idx(table_name)
table_type = table.new_type(idx)
p.check_sql_keyword('where')
p.expr(0)
}
table_type := p.parse_type() // `User`
sym := p.table.get_type_symbol(table_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
p.check(.rcbr)
return ast.SqlStmt{
db_expr: db_expr
table_name: table_name
table_type: table_type
object_var_name: object_var_name
object_var_name: inserted_var_name
}
}
fn (mut p Parser) check_sql_keyword(name string) {
if p.check_name() != name {
p.error('orm: expecting `$name`')
}
}

View File

@ -62,11 +62,13 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
mut comments := []ast.Comment{}
for p.tok.kind == .comment {
comments << p.comment()
if p.tok.kind == .rcbr {break}
if p.tok.kind == .rcbr {
break
}
}
if p.tok.kind == .rcbr {
end_comments = comments
break
break
}
if p.tok.kind == .key_pub {
p.next()
@ -112,17 +114,19 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
}
for p.tok.kind == .comment {
comments << p.comment()
if p.tok.kind == .rcbr {break}
if p.tok.kind == .rcbr {
break
}
}
field_start_pos := p.tok.position()
field_name := p.check_name()
// p.warn('field $field_name')
for p.tok.kind == .comment {
comments << p.comment()
if p.tok.kind == .rcbr {break}
if p.tok.kind == .rcbr {
break
}
}
// println(p.tok.position())
typ := p.parse_type()
// field_pos := field_start_pos.extend(p.tok.position())
@ -139,14 +143,15 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
*/
// Comments after type (same line)
line_pos := field_pos.line_nr
for p.tok.kind == .comment && line_pos + 1 == p.tok.line_nr{
for p.tok.kind == .comment && line_pos + 1 == p.tok.line_nr {
if p.tok.lit.contains('\n') {
break
}
comments << p.comment()
if p.tok.kind == .rcbr {break}
if p.tok.kind == .rcbr {
break
}
}
mut attrs := []string{}
if p.tok.kind == .lsbr {
parsed_attrs := p.attributes(false)
@ -163,7 +168,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
// p.expr(0)
default_expr = p.expr(0)
match default_expr {
ast.EnumVal { it.typ = typ }
ast.EnumVal { default_expr.typ = typ }
// TODO: implement all types??
else {}
}
@ -340,7 +345,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
p.error('interface methods cannot contain uppercase letters, use snake_case instead')
}
// field_names << name
args2, _ := p.fn_args()
args2, _ := p.fn_args() // TODO merge table.Arg and ast.Arg to avoid this
mut args := [table.Arg{
name: 'x'
typ: typ