orm: support multiline statements (#9888)

pull/9900/head
Louis Schmieder 2021-04-27 14:28:57 +02:00 committed by GitHub
parent 9f1ac39770
commit faf2656335
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 146 additions and 79 deletions

View File

@ -65,6 +65,7 @@ pub fn (mut app App) new_article() vweb.Result {
sql app.db { sql app.db {
insert article into Article insert article into Article
} }
return app.redirect('/') return app.redirect('/')
} }

View File

@ -28,10 +28,30 @@ fn test_orm_sqlite() {
sql db { sql db {
create table User create table User
} }
name := 'Peter' name := 'Peter'
db.exec("insert into userlist (username, age) values ('Sam', 29)")
db.exec("insert into userlist (username, age) values ('Peter', 31)") sam := User{
db.exec("insert into userlist (username, age, is_customer) values ('Kate', 30, 1)") age: 29
name: 'Sam'
}
peter := User{
age: 31
name: 'Peter'
}
k := User{
age: 30
name: 'Kate'
is_customer: true
}
sql db {
insert sam into User
insert peter into User
insert k into User
}
c := sql db { c := sql db {
select count from User where id != 1 select count from User where id != 1
@ -113,6 +133,7 @@ fn test_orm_sqlite() {
sql db { sql db {
insert new_user into User insert new_user into User
} }
// db.insert<User>(user2) // db.insert<User>(user2)
x := sql db { x := sql db {
select from User where id == 4 select from User where id == 4
@ -136,6 +157,7 @@ fn test_orm_sqlite() {
sql db { sql db {
update User set age = 31 where name == 'Kate' update User set age = 31 where name == 'Kate'
} }
kate2 := sql db { kate2 := sql db {
select from User where id == 3 select from User where id == 3
} }
@ -167,6 +189,7 @@ fn test_orm_sqlite() {
sql db { sql db {
update User set age = new_age, name = 'Kate N' where id == 3 update User set age = new_age, name = 'Kate N' where id == 3
} }
kate3 = sql db { kate3 = sql db {
select from User where id == 3 select from User where id == 3
} }
@ -177,6 +200,7 @@ fn test_orm_sqlite() {
sql db { sql db {
update User set age = foo.age, name = 'Kate N' where id == 3 update User set age = foo.age, name = 'Kate N' where id == 3
} }
kate3 = sql db { kate3 = sql db {
select from User where id == 3 select from User where id == 3
} }
@ -219,6 +243,7 @@ fn test_orm_sqlite() {
sql db { sql db {
delete from User where age == 34 delete from User where age == 34
} }
updated_oldest := sql db { updated_oldest := sql db {
select from User order by age desc limit 1 select from User order by age desc limit 1
} }

View File

@ -1440,8 +1440,15 @@ pub enum SqlStmtKind {
pub struct SqlStmt { pub struct SqlStmt {
pub: pub:
kind SqlStmtKind pos token.Position
db_expr Expr // `db` in `sql db {` db_expr Expr // `db` in `sql db {`
pub mut:
lines []SqlStmtLine
}
pub struct SqlStmtLine {
pub:
kind SqlStmtKind
object_var_name string // `user` object_var_name string // `user`
pos token.Position pos token.Position
where_expr Expr where_expr Expr
@ -1450,7 +1457,7 @@ pub:
pub mut: pub mut:
table_expr TypeNode table_expr TypeNode
fields []StructField fields []StructField
sub_structs map[int]SqlStmt sub_structs map[int]SqlStmtLine
} }
pub struct SqlExpr { pub struct SqlExpr {

View File

@ -6488,6 +6488,18 @@ 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 {
c.expr(node.db_expr)
mut typ := ast.void_type
for mut line in node.lines {
a := c.sql_stmt_line(mut line)
if a != ast.void_type {
typ = a
}
}
return typ
}
fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
c.inside_sql = true c.inside_sql = true
defer { defer {
c.inside_sql = false c.inside_sql = false
@ -6501,11 +6513,10 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) ast.Type {
} }
info := table_sym.info as ast.Struct info := table_sym.info as ast.Struct
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, table_sym.name) fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, table_sym.name)
mut sub_structs := map[int]ast.SqlStmt{} mut sub_structs := map[int]ast.SqlStmtLine{}
for f in fields.filter(c.table.type_symbols[int(it.typ)].kind == .struct_) { for f in fields.filter(c.table.type_symbols[int(it.typ)].kind == .struct_) {
mut n := ast.SqlStmt{ mut n := ast.SqlStmtLine{
pos: node.pos pos: node.pos
db_expr: node.db_expr
kind: node.kind kind: node.kind
table_expr: ast.TypeNode{ table_expr: ast.TypeNode{
pos: node.table_expr.pos pos: node.table_expr.pos
@ -6514,13 +6525,12 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) ast.Type {
object_var_name: '${node.object_var_name}.$f.name' object_var_name: '${node.object_var_name}.$f.name'
} }
tmp_inside_sql := c.inside_sql tmp_inside_sql := c.inside_sql
c.sql_stmt(mut n) c.sql_stmt_line(mut n)
c.inside_sql = tmp_inside_sql c.inside_sql = tmp_inside_sql
sub_structs[int(f.typ)] = n sub_structs[int(f.typ)] = n
} }
node.fields = fields node.fields = fields
node.sub_structs = sub_structs.move() node.sub_structs = sub_structs.move()
c.expr(node.db_expr)
if node.kind == .update { if node.kind == .update {
for expr in node.update_exprs { for expr in node.update_exprs {
c.expr(expr) c.expr(expr)

View File

@ -1215,6 +1215,15 @@ 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(' {')
for line in node.lines {
f.sql_stmt_line(line)
}
f.writeln('}')
}
pub fn (mut f Fmt) sql_stmt_line(node ast.SqlStmtLine) {
table_name := util.strip_mod_name(f.table.get_type_symbol(node.table_expr.typ).name) table_name := util.strip_mod_name(f.table.get_type_symbol(node.table_expr.typ).name)
f.write('\t') f.write('\t')
match node.kind { match node.kind {
@ -1249,7 +1258,6 @@ pub fn (mut f Fmt) sql_stmt(node ast.SqlStmt) {
f.writeln('drop table $table_name') f.writeln('drop table $table_name')
} }
} }
f.writeln('}')
} }
pub fn (mut f Fmt) type_decl(node ast.TypeDecl) { pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {

View File

@ -24,24 +24,30 @@ enum SqlType {
} }
fn (mut g Gen) sql_stmt(node ast.SqlStmt) { fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
for line in node.lines {
g.sql_stmt_line(line, node.db_expr)
}
}
fn (mut g Gen) sql_stmt_line(node ast.SqlStmtLine, expr ast.Expr) {
if node.kind == .create { if node.kind == .create {
g.sql_create_table(node) g.sql_create_table(node, expr)
return return
} else if node.kind == .drop { } else if node.kind == .drop {
g.sql_drop_table(node) g.sql_drop_table(node, expr)
return return
} }
g.sql_table_name = g.table.get_type_symbol(node.table_expr.typ).name g.sql_table_name = g.table.get_type_symbol(node.table_expr.typ).name
typ := g.parse_db_type(node.db_expr) typ := g.parse_db_type(expr)
match typ { match typ {
.sqlite3 { .sqlite3 {
g.sqlite3_stmt(node, typ) g.sqlite3_stmt(node, typ, expr)
} }
.mysql { .mysql {
g.mysql_stmt(node, typ) g.mysql_stmt(node, typ, expr)
} }
.psql { .psql {
g.psql_stmt(node, typ) g.psql_stmt(node, typ, expr)
} }
else { else {
verror('This database type `$typ` is not implemented yet in orm') // TODO add better error verror('This database type `$typ` is not implemented yet in orm') // TODO add better error
@ -49,17 +55,17 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
} }
} }
fn (mut g Gen) sql_create_table(node ast.SqlStmt) { fn (mut g Gen) sql_create_table(node ast.SqlStmtLine, expr ast.Expr) {
typ := g.parse_db_type(node.db_expr) typ := g.parse_db_type(expr)
match typ { match typ {
.sqlite3 { .sqlite3 {
g.sqlite3_create_table(node, typ) g.sqlite3_create_table(node, typ, expr)
} }
.mysql { .mysql {
g.mysql_create_table(node, typ) g.mysql_create_table(node, typ, expr)
} }
.psql { .psql {
g.psql_create_table(node, typ) g.psql_create_table(node, typ, expr)
} }
else { else {
verror('This database type `$typ` is not implemented yet in orm') // TODO add better error verror('This database type `$typ` is not implemented yet in orm') // TODO add better error
@ -67,17 +73,17 @@ fn (mut g Gen) sql_create_table(node ast.SqlStmt) {
} }
} }
fn (mut g Gen) sql_drop_table(node ast.SqlStmt) { fn (mut g Gen) sql_drop_table(node ast.SqlStmtLine, expr ast.Expr) {
typ := g.parse_db_type(node.db_expr) typ := g.parse_db_type(expr)
match typ { match typ {
.sqlite3 { .sqlite3 {
g.sqlite3_drop_table(node, typ) g.sqlite3_drop_table(node, typ, expr)
} }
.mysql { .mysql {
g.mysql_drop_table(node, typ) g.mysql_drop_table(node, typ, expr)
} }
.psql { .psql {
g.psql_create_table(node, typ) g.psql_create_table(node, typ, expr)
} }
else { else {
verror('This database type `$typ` is not implemented yet in orm') // TODO add better error verror('This database type `$typ` is not implemented yet in orm') // TODO add better error
@ -136,13 +142,13 @@ fn (mut g Gen) sql_type_from_v(typ SqlType, v_typ ast.Type) string {
// sqlite3 // sqlite3
fn (mut g Gen) sqlite3_stmt(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.sql_i = 0 g.sql_i = 0
g.writeln('\n\t// sql insert') g.writeln('\n\t// sql insert')
db_name := g.new_tmp_var() db_name := g.new_tmp_var()
g.sql_stmt_name = g.new_tmp_var() g.sql_stmt_name = g.new_tmp_var()
g.write('${c.dbtype}__DB $db_name = ') g.write('${c.dbtype}__DB $db_name = ')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(';') g.writeln(';')
g.write('sqlite3_stmt* $g.sql_stmt_name = ${c.dbtype}__DB_init_stmt($db_name, _SLIT("') g.write('sqlite3_stmt* $g.sql_stmt_name = ${c.dbtype}__DB_init_stmt($db_name, _SLIT("')
g.sql_defaults(node, typ) g.sql_defaults(node, typ)
@ -161,7 +167,7 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmt, typ SqlType) {
expr := node.sub_structs[int(field.typ)] expr := node.sub_structs[int(field.typ)]
tmp_sql_stmt_name := g.sql_stmt_name tmp_sql_stmt_name := g.sql_stmt_name
tmp_sql_table_name := g.sql_table_name tmp_sql_table_name := g.sql_table_name
g.sql_stmt(expr) g.sql_stmt_line(expr, db_expr)
g.sql_stmt_name = tmp_sql_stmt_name g.sql_stmt_name = tmp_sql_stmt_name
g.sql_table_name = tmp_sql_table_name g.sql_table_name = tmp_sql_table_name
// get last inserted id // get last inserted id
@ -326,20 +332,20 @@ fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_
} }
} }
fn (mut g Gen) sqlite3_create_table(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) sqlite3_create_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.writeln('// sqlite3 table creator') g.writeln('// sqlite3 table creator')
create_string := g.table_gen(node, typ) create_string := g.table_gen(node, typ, db_expr)
g.write('sqlite__DB_exec(') g.write('sqlite__DB_exec(')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(', _SLIT("$create_string"));') g.writeln(', _SLIT("$create_string"));')
} }
fn (mut g Gen) sqlite3_drop_table(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) sqlite3_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
table_name := g.get_table_name(node.table_expr) table_name := g.get_table_name(node.table_expr)
g.writeln('// sqlite3 table drop') g.writeln('// sqlite3 table drop')
drop_string := 'DROP TABLE `$table_name`;' drop_string := 'DROP TABLE `$table_name`;'
g.write('sqlite__DB_exec(') g.write('sqlite__DB_exec(')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(', _SLIT("$drop_string"));') g.writeln(', _SLIT("$drop_string"));')
} }
@ -377,13 +383,13 @@ fn (mut g Gen) sqlite3_type_from_v(v_typ ast.Type) string {
// mysql // mysql
fn (mut g Gen) mysql_stmt(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.sql_i = 0 g.sql_i = 0
g.writeln('\n\t//mysql insert') g.writeln('\n\t//mysql insert')
db_name := g.new_tmp_var() db_name := g.new_tmp_var()
g.sql_stmt_name = g.new_tmp_var() g.sql_stmt_name = g.new_tmp_var()
g.write('mysql__Connection $db_name = ') g.write('mysql__Connection $db_name = ')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(';') g.writeln(';')
stmt_name := g.new_tmp_var() stmt_name := g.new_tmp_var()
g.write('string $stmt_name = _SLIT("') g.write('string $stmt_name = _SLIT("')
@ -407,7 +413,7 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmt, typ SqlType) {
expr := node.sub_structs[int(field.typ)] expr := node.sub_structs[int(field.typ)]
tmp_sql_stmt_name := g.sql_stmt_name tmp_sql_stmt_name := g.sql_stmt_name
tmp_sql_table_name := g.sql_table_name tmp_sql_table_name := g.sql_table_name
g.sql_stmt(expr) g.sql_stmt_line(expr, db_expr)
g.sql_stmt_name = tmp_sql_stmt_name g.sql_stmt_name = tmp_sql_stmt_name
g.sql_table_name = tmp_sql_table_name g.sql_table_name = tmp_sql_table_name
@ -618,23 +624,23 @@ fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sq
} }
} }
fn (mut g Gen) mysql_create_table(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) mysql_create_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.writeln('// mysql table creator') g.writeln('// mysql table creator')
create_string := g.table_gen(node, typ) create_string := g.table_gen(node, typ, db_expr)
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&') g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(', _SLIT("$create_string"));') g.writeln(', _SLIT("$create_string"));')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }') g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
} }
fn (mut g Gen) mysql_drop_table(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) mysql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
table_name := g.get_table_name(node.table_expr) table_name := g.get_table_name(node.table_expr)
g.writeln('// mysql table drop') g.writeln('// mysql table drop')
drop_string := 'DROP TABLE `$table_name`;' drop_string := 'DROP TABLE `$table_name`;'
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&') g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(', _SLIT("$drop_string"));') g.writeln(', _SLIT("$drop_string"));')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }') g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
} }
@ -735,7 +741,7 @@ fn (mut g Gen) mysql_buffer_typ_from_field(field ast.StructField) (string, strin
// psql // psql
fn (mut g Gen) psql_stmt(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.sql_i = 0 g.sql_i = 0
g.sql_idents = []string{} g.sql_idents = []string{}
param_values := g.new_tmp_var() param_values := g.new_tmp_var()
@ -745,7 +751,7 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmt, typ SqlType) {
db_name := g.new_tmp_var() db_name := g.new_tmp_var()
g.sql_stmt_name = g.new_tmp_var() g.sql_stmt_name = g.new_tmp_var()
g.write('pg__DB $db_name = ') g.write('pg__DB $db_name = ')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(';') g.writeln(';')
stmt_name := g.new_tmp_var() stmt_name := g.new_tmp_var()
g.write('string $stmt_name = _SLIT("') g.write('string $stmt_name = _SLIT("')
@ -769,7 +775,7 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmt, typ SqlType) {
expr := node.sub_structs[int(field.typ)] expr := node.sub_structs[int(field.typ)]
tmp_sql_stmt_name := g.sql_stmt_name tmp_sql_stmt_name := g.sql_stmt_name
tmp_sql_table_name := g.sql_table_name tmp_sql_table_name := g.sql_table_name
g.sql_stmt(expr) g.sql_stmt_line(expr, db_expr)
g.sql_stmt_name = tmp_sql_stmt_name g.sql_stmt_name = tmp_sql_stmt_name
g.sql_table_name = tmp_sql_table_name g.sql_table_name = tmp_sql_table_name
@ -803,23 +809,23 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmt, typ SqlType) {
g.writeln('if (${res}_rows.state != 0) { IError err = ${res}_rows.err; eprintln(_STR("\\000%.*s", 2, IError_str(err))); }') g.writeln('if (${res}_rows.state != 0) { IError err = ${res}_rows.err; eprintln(_STR("\\000%.*s", 2, IError_str(err))); }')
} }
fn (mut g Gen) psql_create_table(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) psql_create_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.writeln('// psql table creator') g.writeln('// psql table creator')
create_string := g.table_gen(node, typ) create_string := g.table_gen(node, typ, db_expr)
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
g.write('Option_Array_pg__Row $tmp = pg__DB_exec(') g.write('Option_Array_pg__Row $tmp = pg__DB_exec(')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(', _SLIT("$create_string"));') g.writeln(', _SLIT("$create_string"));')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }') g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
} }
fn (mut g Gen) psql_drop_table(node ast.SqlStmt, typ SqlType) { fn (mut g Gen) psql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
table_name := g.get_table_name(node.table_expr) table_name := g.get_table_name(node.table_expr)
g.writeln('// psql table drop') g.writeln('// psql table drop')
drop_string := 'DROP TABLE "$table_name";' drop_string := 'DROP TABLE "$table_name";'
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
g.write('Option_Array_pg__Row $tmp = pg__DB_exec(&') g.write('Option_Array_pg__Row $tmp = pg__DB_exec(&')
g.expr(node.db_expr) g.expr(db_expr)
g.writeln(', _SLIT("$drop_string"));') g.writeln(', _SLIT("$drop_string"));')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }') g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
} }
@ -929,7 +935,7 @@ fn (mut g Gen) get_base_sql_select_query(node ast.SqlExpr) string {
return sql_query return sql_query
} }
fn (mut g Gen) sql_defaults(node ast.SqlStmt, typ SqlType, psql_data ...string) { fn (mut g Gen) sql_defaults(node ast.SqlStmtLine, typ SqlType, psql_data ...string) {
table_name := g.get_table_name(node.table_expr) table_name := g.get_table_name(node.table_expr)
mut lit := '`' mut lit := '`'
if typ == .psql { if typ == .psql {
@ -981,7 +987,7 @@ fn (mut g Gen) sql_defaults(node ast.SqlStmt, typ SqlType, psql_data ...string)
g.write(';")') g.write(';")')
} }
fn (mut g Gen) table_gen(node ast.SqlStmt, typ SqlType) string { fn (mut g Gen) table_gen(node ast.SqlStmtLine, typ SqlType, expr ast.Expr) string {
typ_sym := g.table.get_type_symbol(node.table_expr.typ) typ_sym := g.table.get_type_symbol(node.table_expr.typ)
struct_data := typ_sym.struct_info() struct_data := typ_sym.struct_info()
table_name := g.get_table_name(node.table_expr) table_name := g.get_table_name(node.table_expr)
@ -1032,15 +1038,14 @@ fn (mut g Gen) table_gen(node ast.SqlStmt, typ SqlType) string {
if converted_typ == '' { if converted_typ == '' {
if g.table.get_type_symbol(field.typ).kind == .struct_ { if g.table.get_type_symbol(field.typ).kind == .struct_ {
converted_typ = g.sql_type_from_v(typ, ast.int_type) converted_typ = g.sql_type_from_v(typ, ast.int_type)
g.sql_create_table(ast.SqlStmt{ g.sql_create_table(ast.SqlStmtLine{
db_expr: node.db_expr
kind: node.kind kind: node.kind
pos: node.pos pos: node.pos
table_expr: ast.TypeNode{ table_expr: ast.TypeNode{
typ: field.typ typ: field.typ
pos: node.table_expr.pos pos: node.table_expr.pos
} }
}) }, expr)
} else { } else {
verror('unknown type ($field.typ) for field $field.name in struct $table_name') verror('unknown type ($field.typ) for field $field.name in struct $table_name')
continue continue

View File

@ -97,8 +97,10 @@ pub fn (mut w Walker) stmt(node ast.Stmt) {
} }
ast.SqlStmt { ast.SqlStmt {
w.expr(node.db_expr) w.expr(node.db_expr)
w.expr(node.where_expr) for line in node.lines {
w.exprs(node.update_exprs) w.expr(line.where_expr)
w.exprs(line.update_exprs)
}
} }
ast.StructDecl { ast.StructDecl {
w.struct_fields(node.fields) w.struct_fields(node.fields)

View File

@ -125,9 +125,25 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
} }
// println(typeof(db_expr)) // println(typeof(db_expr))
p.check(.lcbr) p.check(.lcbr)
// kind := ast.SqlExprKind.select_
// mut lines := []ast.SqlStmtLine{}
for p.tok.kind != .rcbr {
lines << p.parse_sql_stmt_line()
}
p.next()
pos.last_line = p.prev_tok.line_nr
return ast.SqlStmt{
pos: pos.extend(p.prev_tok.position())
db_expr: db_expr
lines: lines
}
}
fn (mut p Parser) parse_sql_stmt_line() ast.SqlStmtLine {
mut n := p.check_name() // insert mut n := p.check_name() // insert
pos := p.tok.position()
mut kind := ast.SqlStmtKind.insert mut kind := ast.SqlStmtKind.insert
if n == 'delete' { if n == 'delete' {
kind = .delete kind = .delete
@ -138,13 +154,11 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
table := p.check_name() table := p.check_name()
if table != 'table' { if table != 'table' {
p.error('expected `table` got `$table`') p.error('expected `table` got `$table`')
return ast.SqlStmt{} return ast.SqlStmtLine{}
} }
typ := p.parse_type() typ := p.parse_type()
typ_pos := p.tok.position() typ_pos := p.tok.position()
p.check(.rcbr) return ast.SqlStmtLine{
return ast.SqlStmt{
db_expr: db_expr
kind: kind kind: kind
pos: pos.extend(p.prev_tok.position()) pos: pos.extend(p.prev_tok.position())
table_expr: ast.TypeNode{ table_expr: ast.TypeNode{
@ -157,13 +171,11 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
table := p.check_name() table := p.check_name()
if table != 'table' { if table != 'table' {
p.error('expected `table` got `$table`') p.error('expected `table` got `$table`')
return ast.SqlStmt{} return ast.SqlStmtLine{}
} }
typ := p.parse_type() typ := p.parse_type()
typ_pos := p.tok.position() typ_pos := p.tok.position()
p.check(.rcbr) return ast.SqlStmtLine{
return ast.SqlStmt{
db_expr: db_expr
kind: kind kind: kind
pos: pos.extend(p.prev_tok.position()) pos: pos.extend(p.prev_tok.position())
table_expr: ast.TypeNode{ table_expr: ast.TypeNode{
@ -183,7 +195,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
inserted_var_name = expr.name inserted_var_name = expr.name
} else { } else {
p.error('can only insert variables') p.error('can only insert variables')
return ast.SqlStmt{} return ast.SqlStmtLine{}
} }
} }
} }
@ -192,11 +204,11 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
mut update_exprs := []ast.Expr{cap: 5} mut update_exprs := []ast.Expr{cap: 5}
if kind == .insert && n != 'into' { if kind == .insert && n != 'into' {
p.error('expecting `into`') p.error('expecting `into`')
return ast.SqlStmt{} return ast.SqlStmtLine{}
} else if kind == .update { } else if kind == .update {
if n != 'set' { if n != 'set' {
p.error('expecting `set`') p.error('expecting `set`')
return ast.SqlStmt{} return ast.SqlStmtLine{}
} }
for { for {
column := p.check_name() column := p.check_name()
@ -211,7 +223,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
} }
} else if kind == .delete && n != 'from' { } else if kind == .delete && n != 'from' {
p.error('expecting `from`') p.error('expecting `from`')
return ast.SqlStmt{} return ast.SqlStmtLine{}
} }
mut table_pos := p.tok.position() mut table_pos := p.tok.position()
@ -220,24 +232,21 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
table_pos = p.tok.position() table_pos = p.tok.position()
table_type = p.parse_type() table_type = p.parse_type()
} else if kind == .update { } else if kind == .update {
p.check_sql_keyword('where') or { return ast.SqlStmt{} } p.check_sql_keyword('where') or { return ast.SqlStmtLine{} }
where_expr = p.expr(0) where_expr = p.expr(0)
} else if kind == .delete { } else if kind == .delete {
table_pos = p.tok.position() table_pos = p.tok.position()
table_type = p.parse_type() table_type = p.parse_type()
p.check_sql_keyword('where') or { return ast.SqlStmt{} } p.check_sql_keyword('where') or { return ast.SqlStmtLine{} }
where_expr = p.expr(0) where_expr = p.expr(0)
} }
p.check(.rcbr) return ast.SqlStmtLine{
pos.last_line = p.prev_tok.line_nr
return ast.SqlStmt{
db_expr: db_expr
table_expr: ast.TypeNode{ table_expr: ast.TypeNode{
typ: table_type typ: table_type
pos: table_pos pos: table_pos
} }
object_var_name: inserted_var_name object_var_name: inserted_var_name
pos: pos.extend(p.prev_tok.position()) pos: pos
updated_columns: updated_columns updated_columns: updated_columns
update_exprs: update_exprs update_exprs: update_exprs
kind: kind kind: kind