orm: support arrays (#9936)
parent
b15156d465
commit
fb685eee18
|
@ -18,12 +18,145 @@ struct User {
|
||||||
skipped_string string [skip]
|
skipped_string string [skip]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Parent {
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
name string
|
||||||
|
chields []Chield [fkey: 'parent_id']
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Chield {
|
||||||
|
id int [primary; sql: serial]
|
||||||
|
parent_id int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
sqlite3_array()
|
||||||
|
mysql_array()
|
||||||
|
psql_array()
|
||||||
|
|
||||||
sqlite3()
|
sqlite3()
|
||||||
mysql()
|
mysql()
|
||||||
psql()
|
psql()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sqlite3_array() {
|
||||||
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
|
sql db {
|
||||||
|
create table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
par := Parent{
|
||||||
|
name: 'test'
|
||||||
|
chields: [
|
||||||
|
Chield{
|
||||||
|
name: 'abc'
|
||||||
|
},
|
||||||
|
Chield{
|
||||||
|
name: 'def'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
insert par into Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := sql db {
|
||||||
|
select from Parent where id == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Chield
|
||||||
|
drop table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mysql_array() {
|
||||||
|
mut db := mysql.Connection{
|
||||||
|
host: 'localhost'
|
||||||
|
port: 3306
|
||||||
|
username: 'root'
|
||||||
|
password: 'abc'
|
||||||
|
dbname: 'test'
|
||||||
|
}
|
||||||
|
db.connect() or { panic(err) }
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
create table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
par := Parent{
|
||||||
|
name: 'test'
|
||||||
|
chields: [
|
||||||
|
Chield{
|
||||||
|
name: 'abc'
|
||||||
|
},
|
||||||
|
Chield{
|
||||||
|
name: 'def'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
insert par into Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := sql db {
|
||||||
|
select from Parent where id == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln(parent)
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Chield
|
||||||
|
drop table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn psql_array() {
|
||||||
|
mut db := pg.connect(host: 'localhost', user: 'test', password: 'abc', dbname: 'test') or {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
create table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
par := Parent{
|
||||||
|
name: 'test'
|
||||||
|
chields: [
|
||||||
|
Chield{
|
||||||
|
name: 'abc'
|
||||||
|
},
|
||||||
|
Chield{
|
||||||
|
name: 'def'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
insert par into Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := sql db {
|
||||||
|
select from Parent where id == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln(parent)
|
||||||
|
|
||||||
|
sql db {
|
||||||
|
drop table Chield
|
||||||
|
drop table Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
}
|
||||||
|
|
||||||
fn sqlite3() {
|
fn sqlite3() {
|
||||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
sql db {
|
sql db {
|
||||||
|
|
|
@ -6439,15 +6439,24 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
|
||||||
info := sym.info as ast.Struct
|
info := sym.info as ast.Struct
|
||||||
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name)
|
fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name)
|
||||||
mut sub_structs := map[int]ast.SqlExpr{}
|
mut sub_structs := map[int]ast.SqlExpr{}
|
||||||
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_
|
||||||
|
|| (c.table.get_type_symbol(it.typ).kind == .array
|
||||||
|
&& c.table.get_type_symbol(c.table.get_type_symbol(it.typ).array_info().elem_type).kind == .struct_)) {
|
||||||
|
typ := if c.table.get_type_symbol(f.typ).kind == .struct_ {
|
||||||
|
f.typ
|
||||||
|
} else if c.table.get_type_symbol(f.typ).kind == .array {
|
||||||
|
c.table.get_type_symbol(f.typ).array_info().elem_type
|
||||||
|
} else {
|
||||||
|
ast.Type(0)
|
||||||
|
}
|
||||||
mut n := ast.SqlExpr{
|
mut n := ast.SqlExpr{
|
||||||
pos: node.pos
|
pos: node.pos
|
||||||
has_where: true
|
has_where: true
|
||||||
typ: f.typ
|
typ: typ
|
||||||
db_expr: node.db_expr
|
db_expr: node.db_expr
|
||||||
table_expr: ast.TypeNode{
|
table_expr: ast.TypeNode{
|
||||||
pos: node.table_expr.pos
|
pos: node.table_expr.pos
|
||||||
typ: f.typ
|
typ: typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmp_inside_sql := c.inside_sql
|
tmp_inside_sql := c.inside_sql
|
||||||
|
@ -6484,7 +6493,7 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
|
||||||
or_block: ast.OrExpr{}
|
or_block: ast.OrExpr{}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_structs[int(f.typ)] = n
|
sub_structs[int(typ)] = n
|
||||||
}
|
}
|
||||||
node.fields = fields
|
node.fields = fields
|
||||||
node.sub_structs = sub_structs.move()
|
node.sub_structs = sub_structs.move()
|
||||||
|
@ -6531,20 +6540,29 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) 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.SqlStmtLine{}
|
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_)
|
||||||
|
|| (c.table.get_type_symbol(it.typ).kind == .array
|
||||||
|
&& c.table.get_type_symbol(c.table.get_type_symbol(it.typ).array_info().elem_type).kind == .struct_)) {
|
||||||
|
typ := if c.table.get_type_symbol(f.typ).kind == .struct_ {
|
||||||
|
f.typ
|
||||||
|
} else if c.table.get_type_symbol(f.typ).kind == .array {
|
||||||
|
c.table.get_type_symbol(f.typ).array_info().elem_type
|
||||||
|
} else {
|
||||||
|
ast.Type(0)
|
||||||
|
}
|
||||||
mut n := ast.SqlStmtLine{
|
mut n := ast.SqlStmtLine{
|
||||||
pos: node.pos
|
pos: node.pos
|
||||||
kind: node.kind
|
kind: node.kind
|
||||||
table_expr: ast.TypeNode{
|
table_expr: ast.TypeNode{
|
||||||
pos: node.table_expr.pos
|
pos: node.table_expr.pos
|
||||||
typ: f.typ
|
typ: typ
|
||||||
}
|
}
|
||||||
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_line(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[typ] = n
|
||||||
}
|
}
|
||||||
node.fields = fields
|
node.fields = fields
|
||||||
node.sub_structs = sub_structs.move()
|
node.sub_structs = sub_structs.move()
|
||||||
|
@ -6562,7 +6580,10 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
|
||||||
|
|
||||||
fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Position, table_name string) []ast.StructField {
|
fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Position, table_name string) []ast.StructField {
|
||||||
fields := info.fields.filter((it.typ in [ast.string_type, ast.int_type, ast.bool_type]
|
fields := info.fields.filter((it.typ in [ast.string_type, ast.int_type, ast.bool_type]
|
||||||
|| c.table.type_symbols[int(it.typ)].kind == .struct_) && !it.attrs.contains('skip'))
|
|| c.table.type_symbols[int(it.typ)].kind == .struct_
|
||||||
|
|| (c.table.get_type_symbol(it.typ).kind == .array
|
||||||
|
&& c.table.get_type_symbol(c.table.get_type_symbol(it.typ).array_info().elem_type).kind == .struct_))
|
||||||
|
&& !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 []ast.StructField{}
|
return []ast.StructField{}
|
||||||
|
|
|
@ -121,6 +121,8 @@ mut:
|
||||||
sql_idents_types []ast.Type
|
sql_idents_types []ast.Type
|
||||||
sql_left_type ast.Type
|
sql_left_type ast.Type
|
||||||
sql_table_name string
|
sql_table_name string
|
||||||
|
sql_fkey string
|
||||||
|
sql_parent_id string
|
||||||
sql_side SqlExprSide // left or right, to distinguish idents in `name == name`
|
sql_side SqlExprSide // left or right, to distinguish idents in `name == name`
|
||||||
inside_vweb_tmpl bool
|
inside_vweb_tmpl bool
|
||||||
inside_return bool
|
inside_return bool
|
||||||
|
|
|
@ -157,12 +157,18 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr)
|
||||||
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)
|
||||||
g.writeln(');')
|
g.writeln(');')
|
||||||
|
mut arr_stmt := []ast.SqlStmtLine{}
|
||||||
|
mut arr_fkeys := []string{}
|
||||||
if node.kind == .insert {
|
if node.kind == .insert {
|
||||||
// build the object now (`x.name = ... x.id == ...`)
|
// build the object now (`x.name = ... x.id == ...`)
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
if g.get_sql_field_type(field) == ast.Type(-1) {
|
if g.get_sql_field_type(field) == ast.Type(-1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if field.name == g.sql_fkey && g.sql_fkey != '' {
|
||||||
|
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i + 0} , $g.sql_parent_id); // parent id')
|
||||||
|
continue
|
||||||
|
}
|
||||||
x := '${node.object_var_name}.$field.name'
|
x := '${node.object_var_name}.$field.name'
|
||||||
if field.typ == ast.string_type {
|
if field.typ == ast.string_type {
|
||||||
g.writeln('sqlite3_bind_text($g.sql_stmt_name, ${i + 0}, (char*)${x}.str, ${x}.len, 0);')
|
g.writeln('sqlite3_bind_text($g.sql_stmt_name, ${i + 0}, (char*)${x}.str, ${x}.len, 0);')
|
||||||
|
@ -180,6 +186,24 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr)
|
||||||
id_name := g.new_tmp_var()
|
id_name := g.new_tmp_var()
|
||||||
g.writeln('int $id_name = string_int((*(string*)array_get((*(sqlite__Row*)array_get($res, 0)).vals, 0)));')
|
g.writeln('int $id_name = string_int((*(string*)array_get((*(sqlite__Row*)array_get($res, 0)).vals, 0)));')
|
||||||
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i + 0} , $id_name); // id')
|
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i + 0} , $id_name); // id')
|
||||||
|
} else if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
t := g.table.get_type_symbol(field.typ).array_info().elem_type
|
||||||
|
if g.table.get_type_symbol(t).kind == .struct_ {
|
||||||
|
mut fkey := ''
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'fkey' && attr.arg != '' && attr.kind == .string {
|
||||||
|
fkey = attr.arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fkey == '' {
|
||||||
|
verror('fkey attribute has to be set for arrays in orm')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
arr_stmt << node.sub_structs[int(t)]
|
||||||
|
arr_fkeys << fkey
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i + 0} , $x); // stmt')
|
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i + 0} , $x); // stmt')
|
||||||
}
|
}
|
||||||
|
@ -193,6 +217,15 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr)
|
||||||
g.writeln('\tint $step_res = sqlite3_step($g.sql_stmt_name);')
|
g.writeln('\tint $step_res = sqlite3_step($g.sql_stmt_name);')
|
||||||
g.writeln('\tif( ($step_res != SQLITE_OK) && ($step_res != SQLITE_DONE)){ puts(sqlite3_errmsg(${db_name}.conn)); }')
|
g.writeln('\tif( ($step_res != SQLITE_OK) && ($step_res != SQLITE_DONE)){ puts(sqlite3_errmsg(${db_name}.conn)); }')
|
||||||
g.writeln('\tsqlite3_finalize($g.sql_stmt_name);')
|
g.writeln('\tsqlite3_finalize($g.sql_stmt_name);')
|
||||||
|
|
||||||
|
if arr_stmt.len > 0 {
|
||||||
|
res := g.new_tmp_var()
|
||||||
|
g.writeln('Array_sqlite__Row $res = sqlite__DB_exec($db_name, _SLIT("SELECT last_insert_rowid()")).arg0;')
|
||||||
|
id_name := g.new_tmp_var()
|
||||||
|
g.writeln('int $id_name = string_int((*(string*)array_get((*(sqlite__Row*)array_get($res, 0)).vals, 0)));')
|
||||||
|
|
||||||
|
g.sql_arr_stmt(arr_stmt, arr_fkeys, id_name, db_expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_typ SqlType) {
|
fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_typ SqlType) {
|
||||||
|
@ -287,7 +320,14 @@ fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_
|
||||||
// g.writeln('printf("RES: %d\\n", _step_res$tmp) ;')
|
// g.writeln('printf("RES: %d\\n", _step_res$tmp) ;')
|
||||||
g.writeln('\tif (_step_res$tmp == SQLITE_OK || _step_res$tmp == SQLITE_ROW) {')
|
g.writeln('\tif (_step_res$tmp == SQLITE_OK || _step_res$tmp == SQLITE_ROW) {')
|
||||||
}
|
}
|
||||||
|
mut primary := ''
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'primary' {
|
||||||
|
primary = '${tmp}.$field.name'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
mut func := 'sqlite3_column_int'
|
mut func := 'sqlite3_column_int'
|
||||||
if field.typ == ast.string_type {
|
if field.typ == ast.string_type {
|
||||||
func = 'sqlite3_column_text'
|
func = 'sqlite3_column_text'
|
||||||
|
@ -319,6 +359,8 @@ fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_
|
||||||
g.sql_buf = tmp_sql_buf
|
g.sql_buf = tmp_sql_buf
|
||||||
g.sql_i = tmp_sql_i
|
g.sql_i = tmp_sql_i
|
||||||
g.sql_table_name = tmp_sql_table_name
|
g.sql_table_name = tmp_sql_table_name
|
||||||
|
} else if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
g.sql_select_arr(field, node, primary, tmp)
|
||||||
} else {
|
} else {
|
||||||
g.writeln('${tmp}.$field.name = ${func}($g.sql_stmt_name, $i);')
|
g.writeln('${tmp}.$field.name = ${func}($g.sql_stmt_name, $i);')
|
||||||
}
|
}
|
||||||
|
@ -405,11 +447,28 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
bind := g.new_tmp_var()
|
bind := g.new_tmp_var()
|
||||||
g.writeln('MYSQL_BIND $bind[$g.sql_i];')
|
g.writeln('MYSQL_BIND $bind[$g.sql_i];')
|
||||||
g.writeln('memset($bind, 0, sizeof(MYSQL_BIND)*$g.sql_i);')
|
g.writeln('memset($bind, 0, sizeof(MYSQL_BIND)*$g.sql_i);')
|
||||||
|
mut arr_stmt := []ast.SqlStmtLine{}
|
||||||
|
mut arr_fkeys := []string{}
|
||||||
if node.kind == .insert {
|
if node.kind == .insert {
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
if g.get_sql_field_type(field) == ast.Type(-1) {
|
if g.get_sql_field_type(field) == ast.Type(-1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if field.name == g.sql_fkey && g.sql_fkey != '' {
|
||||||
|
t, sym := g.mysql_buffer_typ_from_field(field)
|
||||||
|
g.writeln('$bind[${i - 1}].buffer_type = $t;')
|
||||||
|
if sym == 'char' {
|
||||||
|
g.writeln('$bind[${i - 1}].buffer = ($sym*) ${g.sql_parent_id}.str;')
|
||||||
|
} else {
|
||||||
|
g.writeln('$bind[${i - 1}].buffer = ($sym*) &$g.sql_parent_id;')
|
||||||
|
}
|
||||||
|
if sym == 'char' {
|
||||||
|
g.writeln('$bind[${i - 1}].buffer_length = ${g.sql_parent_id}.len;')
|
||||||
|
}
|
||||||
|
g.writeln('$bind[${i - 1}].is_null = 0;')
|
||||||
|
g.writeln('$bind[${i - 1}].length = 0;')
|
||||||
|
continue
|
||||||
|
}
|
||||||
g.writeln('//$field.name ($field.typ)')
|
g.writeln('//$field.name ($field.typ)')
|
||||||
x := '${node.object_var_name}.$field.name'
|
x := '${node.object_var_name}.$field.name'
|
||||||
if g.table.get_type_symbol(field.typ).kind == .struct_ {
|
if g.table.get_type_symbol(field.typ).kind == .struct_ {
|
||||||
|
@ -434,6 +493,24 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
g.writeln('$bind[${i - 1}].buffer = &${x}.id;')
|
g.writeln('$bind[${i - 1}].buffer = &${x}.id;')
|
||||||
g.writeln('$bind[${i - 1}].is_null = 0;')
|
g.writeln('$bind[${i - 1}].is_null = 0;')
|
||||||
g.writeln('$bind[${i - 1}].length = 0;')
|
g.writeln('$bind[${i - 1}].length = 0;')
|
||||||
|
} else if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
t := g.table.get_type_symbol(field.typ).array_info().elem_type
|
||||||
|
if g.table.get_type_symbol(t).kind == .struct_ {
|
||||||
|
mut fkey := ''
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'fkey' && attr.arg != '' && attr.kind == .string {
|
||||||
|
fkey = attr.arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fkey == '' {
|
||||||
|
verror('fkey attribute has to be set for arrays in orm')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
arr_stmt << node.sub_structs[int(t)]
|
||||||
|
arr_fkeys << fkey
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t, sym := g.mysql_buffer_typ_from_field(field)
|
t, sym := g.mysql_buffer_typ_from_field(field)
|
||||||
g.writeln('$bind[${i - 1}].buffer_type = $t;')
|
g.writeln('$bind[${i - 1}].buffer_type = $t;')
|
||||||
|
@ -460,6 +537,20 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
g.writeln('if ($res != 0) { puts(mysql_error(${db_name}.conn)); puts(mysql_stmt_error($g.sql_stmt_name)); }')
|
g.writeln('if ($res != 0) { puts(mysql_error(${db_name}.conn)); puts(mysql_stmt_error($g.sql_stmt_name)); }')
|
||||||
g.writeln('mysql_stmt_close($g.sql_stmt_name);')
|
g.writeln('mysql_stmt_close($g.sql_stmt_name);')
|
||||||
g.writeln('mysql_stmt_free_result($g.sql_stmt_name);')
|
g.writeln('mysql_stmt_free_result($g.sql_stmt_name);')
|
||||||
|
|
||||||
|
if arr_stmt.len > 0 {
|
||||||
|
rs := g.new_tmp_var()
|
||||||
|
g.writeln('int ${rs}_err = mysql_real_query(${db_name}.conn, "SELECT LAST_INSERT_ID();", 24);')
|
||||||
|
g.writeln('if (${rs}_err != 0) { puts(mysql_error(${db_name}.conn)); }')
|
||||||
|
g.writeln('MYSQL_RES* $rs = mysql_store_result(${db_name}.conn);')
|
||||||
|
g.writeln('if (mysql_num_rows($rs) != 1) { puts("Something went wrong"); }')
|
||||||
|
g.writeln('MYSQL_ROW ${rs}_row = mysql_fetch_row($rs);')
|
||||||
|
id_name := g.new_tmp_var()
|
||||||
|
g.writeln('int $id_name = string_int(tos_clone(${rs}_row[0]));')
|
||||||
|
g.writeln('mysql_free_result($rs);')
|
||||||
|
|
||||||
|
g.sql_arr_stmt(arr_stmt, arr_fkeys, id_name, db_expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string, typ SqlType) {
|
fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string, typ SqlType) {
|
||||||
|
@ -536,7 +627,14 @@ fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sq
|
||||||
|
|
||||||
char_ptr := g.new_tmp_var()
|
char_ptr := g.new_tmp_var()
|
||||||
g.writeln('char* $char_ptr = "";')
|
g.writeln('char* $char_ptr = "";')
|
||||||
|
mut primary := ''
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'primary' {
|
||||||
|
primary = '${tmp}.$field.name'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
g.writeln('$char_ptr = $fields[$i];')
|
g.writeln('$char_ptr = $fields[$i];')
|
||||||
g.writeln('if ($char_ptr == NULL) { $char_ptr = ""; }')
|
g.writeln('if ($char_ptr == NULL) { $char_ptr = ""; }')
|
||||||
name := g.table.get_type_symbol(field.typ).cname
|
name := g.table.get_type_symbol(field.typ).cname
|
||||||
|
@ -563,6 +661,8 @@ fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sq
|
||||||
g.sql_buf = tmp_sql_buf
|
g.sql_buf = tmp_sql_buf
|
||||||
g.sql_i = tmp_sql_i
|
g.sql_i = tmp_sql_i
|
||||||
g.sql_table_name = tmp_sql_table_name
|
g.sql_table_name = tmp_sql_table_name
|
||||||
|
} else if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
g.sql_select_arr(field, node, primary, tmp)
|
||||||
} else if field.typ == ast.string_type {
|
} else if field.typ == ast.string_type {
|
||||||
g.writeln('${tmp}.$field.name = tos_clone($char_ptr);')
|
g.writeln('${tmp}.$field.name = tos_clone($char_ptr);')
|
||||||
} else if field.typ == ast.byte_type {
|
} else if field.typ == ast.byte_type {
|
||||||
|
@ -724,15 +824,23 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
g.sql_defaults(node, typ)
|
g.sql_defaults(node, typ)
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
|
|
||||||
|
mut arr_stmt := []ast.SqlStmtLine{}
|
||||||
|
mut arr_fkeys := []string{}
|
||||||
if node.kind == .insert {
|
if node.kind == .insert {
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
if g.get_sql_field_type(field) == ast.Type(-1) {
|
if g.get_sql_field_type(field) == ast.Type(-1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.sql_i = i
|
g.sql_i = i
|
||||||
|
field_type := g.get_sql_field_type(field)
|
||||||
|
if field.name == g.sql_fkey && g.sql_fkey != '' {
|
||||||
|
g.sql_buf = strings.new_builder(100)
|
||||||
|
g.sql_bind(g.sql_parent_id, '', field_type, typ)
|
||||||
|
g.writeln(g.sql_buf.str())
|
||||||
|
continue
|
||||||
|
}
|
||||||
g.writeln('//$field.name ($field.typ)')
|
g.writeln('//$field.name ($field.typ)')
|
||||||
x := '${node.object_var_name}.$field.name'
|
x := '${node.object_var_name}.$field.name'
|
||||||
field_type := g.get_sql_field_type(field)
|
|
||||||
if g.table.get_type_symbol(field.typ).kind == .struct_ {
|
if g.table.get_type_symbol(field.typ).kind == .struct_ {
|
||||||
// insert again
|
// insert again
|
||||||
expr := node.sub_structs[int(field.typ)]
|
expr := node.sub_structs[int(field.typ)]
|
||||||
|
@ -749,6 +857,24 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
g.sql_bind('string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)))',
|
g.sql_bind('string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)))',
|
||||||
'', ast.int_type, typ)
|
'', ast.int_type, typ)
|
||||||
g.writeln(g.sql_buf.str())
|
g.writeln(g.sql_buf.str())
|
||||||
|
} else if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
t := g.table.get_type_symbol(field.typ).array_info().elem_type
|
||||||
|
if g.table.get_type_symbol(t).kind == .struct_ {
|
||||||
|
mut fkey := ''
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'fkey' && attr.arg != '' && attr.kind == .string {
|
||||||
|
fkey = attr.arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fkey == '' {
|
||||||
|
verror('fkey attribute has to be set for arrays in orm')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
arr_stmt << node.sub_structs[int(t)]
|
||||||
|
arr_fkeys << fkey
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g.sql_buf = strings.new_builder(100)
|
g.sql_buf = strings.new_builder(100)
|
||||||
g.sql_bind(x, '', field_type, typ)
|
g.sql_bind(x, '', field_type, typ)
|
||||||
|
@ -761,6 +887,16 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
g.writeln(binds)
|
g.writeln(binds)
|
||||||
|
|
||||||
g.writeln('pg__DB_exec($db_name, $g.sql_stmt_name);')
|
g.writeln('pg__DB_exec($db_name, $g.sql_stmt_name);')
|
||||||
|
|
||||||
|
if arr_stmt.len > 0 {
|
||||||
|
res := g.new_tmp_var()
|
||||||
|
g.writeln('Option_pg__Row $res = pg__DB_exec_one($db_name, _SLIT("SELECT LASTVAL();"));')
|
||||||
|
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln(_STR("\\000%.*s", 2, IError_str(err))); }')
|
||||||
|
id_name := g.new_tmp_var()
|
||||||
|
g.writeln('int $id_name = string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)));')
|
||||||
|
|
||||||
|
g.sql_arr_stmt(arr_stmt, arr_fkeys, id_name, db_expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) psql_select_expr(node ast.SqlExpr, sub bool, line string, typ SqlType) {
|
fn (mut g Gen) psql_select_expr(node ast.SqlExpr, sub bool, line string, typ SqlType) {
|
||||||
|
@ -834,7 +970,18 @@ fn (mut g Gen) psql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sql
|
||||||
g.writeln('Array_string $fields = (*(pg__Row*) array_get($rows, $tmp_i)).vals;')
|
g.writeln('Array_string $fields = (*(pg__Row*) array_get($rows, $tmp_i)).vals;')
|
||||||
fld := g.new_tmp_var()
|
fld := g.new_tmp_var()
|
||||||
g.writeln('string $fld;')
|
g.writeln('string $fld;')
|
||||||
|
mut primary := ''
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'primary' {
|
||||||
|
primary = '${tmp}.$field.name'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
g.sql_select_arr(field, node, primary, tmp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
g.writeln('$fld = (*(string*)array_get($fields, $i));')
|
g.writeln('$fld = (*(string*)array_get($fields, $i));')
|
||||||
name := g.table.get_type_symbol(field.typ).cname
|
name := g.table.get_type_symbol(field.typ).cname
|
||||||
|
|
||||||
|
@ -965,6 +1112,87 @@ fn (mut g Gen) psql_bind(val string, typ ast.Type) {
|
||||||
|
|
||||||
// utils
|
// utils
|
||||||
|
|
||||||
|
fn (mut g Gen) sql_select_arr(field ast.StructField, node ast.SqlExpr, primary string, tmp string) {
|
||||||
|
t := g.table.get_type_symbol(field.typ).array_info().elem_type
|
||||||
|
if g.table.get_type_symbol(t).kind == .struct_ {
|
||||||
|
mut fkey := ''
|
||||||
|
for attr in field.attrs {
|
||||||
|
if attr.name == 'fkey' && attr.arg != '' && attr.kind == .string {
|
||||||
|
fkey = attr.arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fkey == '' {
|
||||||
|
verror('fkey attribute has to be set for arrays in orm')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeln('//parse array start')
|
||||||
|
|
||||||
|
e := node.sub_structs[int(t)]
|
||||||
|
mut where_expr := e.where_expr as ast.InfixExpr
|
||||||
|
mut lidt := where_expr.left as ast.Ident
|
||||||
|
mut ridt := where_expr.right as ast.Ident
|
||||||
|
ridt.name = primary
|
||||||
|
lidt.name = fkey
|
||||||
|
where_expr.right = ridt
|
||||||
|
where_expr.left = lidt
|
||||||
|
expr := ast.SqlExpr{
|
||||||
|
typ: field.typ
|
||||||
|
has_where: e.has_where
|
||||||
|
db_expr: e.db_expr
|
||||||
|
is_array: true
|
||||||
|
pos: e.pos
|
||||||
|
where_expr: where_expr
|
||||||
|
table_expr: e.table_expr
|
||||||
|
fields: e.fields
|
||||||
|
sub_structs: e.sub_structs
|
||||||
|
}
|
||||||
|
tmp_sql_i := g.sql_i
|
||||||
|
tmp_sql_stmt_name := g.sql_stmt_name
|
||||||
|
tmp_sql_buf := g.sql_buf
|
||||||
|
tmp_sql_table_name := g.sql_table_name
|
||||||
|
|
||||||
|
g.sql_select_expr(expr, true, '\t${tmp}.$field.name =')
|
||||||
|
g.writeln('//parse array end')
|
||||||
|
|
||||||
|
g.sql_stmt_name = tmp_sql_stmt_name
|
||||||
|
g.sql_buf = tmp_sql_buf
|
||||||
|
g.sql_i = tmp_sql_i
|
||||||
|
g.sql_table_name = tmp_sql_table_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) sql_arr_stmt(arr_stmt []ast.SqlStmtLine, arr_fkeys []string, id_name string, db_expr ast.Expr) {
|
||||||
|
for i, s in arr_stmt {
|
||||||
|
cnt := g.new_tmp_var()
|
||||||
|
g.writeln('for (int $cnt = 0; $cnt < ${s.object_var_name}.len; $cnt++) {')
|
||||||
|
name := g.table.get_type_symbol(s.table_expr.typ).cname
|
||||||
|
tmp_var := g.new_tmp_var()
|
||||||
|
g.writeln('\t$name $tmp_var = (*($name*)array_get($s.object_var_name, $cnt));')
|
||||||
|
|
||||||
|
stmt := ast.SqlStmtLine{
|
||||||
|
pos: s.pos
|
||||||
|
kind: s.kind
|
||||||
|
table_expr: s.table_expr
|
||||||
|
object_var_name: tmp_var
|
||||||
|
fields: s.fields
|
||||||
|
sub_structs: s.sub_structs
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_fkey := g.sql_fkey
|
||||||
|
tmp_parent_id := g.sql_parent_id
|
||||||
|
g.sql_fkey = arr_fkeys[i]
|
||||||
|
g.sql_parent_id = id_name
|
||||||
|
|
||||||
|
g.sql_stmt_line(stmt, db_expr)
|
||||||
|
|
||||||
|
g.sql_fkey = tmp_fkey
|
||||||
|
g.sql_parent_id = tmp_parent_id
|
||||||
|
|
||||||
|
g.writeln('}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sql_expr_defaults(node ast.SqlExpr, sql_typ SqlType) {
|
fn (mut g Gen) sql_expr_defaults(node ast.SqlExpr, sql_typ SqlType) {
|
||||||
if node.has_where && node.where_expr is ast.InfixExpr {
|
if node.has_where && node.where_expr is ast.InfixExpr {
|
||||||
g.expr_to_sql(node.where_expr, sql_typ)
|
g.expr_to_sql(node.where_expr, sql_typ)
|
||||||
|
@ -1003,9 +1231,10 @@ fn (mut g Gen) get_base_sql_select_query(node ast.SqlExpr, typ SqlType) string {
|
||||||
sql_query += 'COUNT(*) FROM $lit$table_name$lit '
|
sql_query += 'COUNT(*) FROM $lit$table_name$lit '
|
||||||
} else {
|
} else {
|
||||||
// `select id, name, country from User`
|
// `select id, name, country from User`
|
||||||
for i, field in node.fields {
|
fields := node.fields.filter(g.table.get_type_symbol(it.typ).kind != .array)
|
||||||
|
for i, field in fields {
|
||||||
sql_query += '$lit${g.get_field_name(field)}$lit'
|
sql_query += '$lit${g.get_field_name(field)}$lit'
|
||||||
if i < node.fields.len - 1 {
|
if i < fields.len - 1 {
|
||||||
sql_query += ', '
|
sql_query += ', '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1031,22 +1260,23 @@ fn (mut g Gen) sql_defaults(node ast.SqlStmtLine, typ SqlType) {
|
||||||
g.write('DELETE FROM $lit$table_name$lit ')
|
g.write('DELETE FROM $lit$table_name$lit ')
|
||||||
}
|
}
|
||||||
if node.kind == .insert {
|
if node.kind == .insert {
|
||||||
for i, field in node.fields {
|
fields := node.fields.filter(g.table.get_type_symbol(it.typ).kind != .array)
|
||||||
|
for i, field in fields {
|
||||||
if g.get_sql_field_type(field) == ast.Type(-1) {
|
if g.get_sql_field_type(field) == ast.Type(-1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.write('$lit${g.get_field_name(field)}$lit')
|
g.write('$lit${g.get_field_name(field)}$lit')
|
||||||
if i < node.fields.len - 1 {
|
if i < fields.len - 1 {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write(') VALUES (')
|
g.write(') VALUES (')
|
||||||
for i, field in node.fields {
|
for i, field in fields {
|
||||||
if g.get_sql_field_type(field) == ast.Type(-1) {
|
if g.get_sql_field_type(field) == ast.Type(-1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.inc_sql_i(typ)
|
g.inc_sql_i(typ)
|
||||||
if i < node.fields.len - 1 {
|
if i < fields.len - 1 {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1092,6 +1322,7 @@ fn (mut g Gen) table_gen(node ast.SqlStmtLine, typ SqlType, expr ast.Expr) strin
|
||||||
mut is_unique := false
|
mut is_unique := false
|
||||||
mut is_skip := false
|
mut is_skip := false
|
||||||
mut unique_len := 0
|
mut unique_len := 0
|
||||||
|
mut fkey := ''
|
||||||
for attr in field.attrs {
|
for attr in field.attrs {
|
||||||
match attr.name {
|
match attr.name {
|
||||||
'primary' {
|
'primary' {
|
||||||
|
@ -1117,6 +1348,14 @@ fn (mut g Gen) table_gen(node ast.SqlStmtLine, typ SqlType, expr ast.Expr) strin
|
||||||
'skip' {
|
'skip' {
|
||||||
is_skip = true
|
is_skip = true
|
||||||
}
|
}
|
||||||
|
'fkey' {
|
||||||
|
if attr.arg != '' {
|
||||||
|
if attr.kind == .string {
|
||||||
|
fkey = attr.arg
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1136,6 +1375,30 @@ fn (mut g Gen) table_gen(node ast.SqlStmtLine, typ SqlType, expr ast.Expr) strin
|
||||||
pos: node.table_expr.pos
|
pos: node.table_expr.pos
|
||||||
}
|
}
|
||||||
}, expr)
|
}, expr)
|
||||||
|
} else if g.table.get_type_symbol(field.typ).kind == .array {
|
||||||
|
arr_info := g.table.get_type_symbol(field.typ).array_info()
|
||||||
|
if arr_info.nr_dims > 1 {
|
||||||
|
verror('array with one dim are supported in orm')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
atyp := arr_info.elem_type
|
||||||
|
if g.table.get_type_symbol(atyp).kind == .struct_ {
|
||||||
|
if fkey == '' {
|
||||||
|
verror('array field ($field.name) needs a fkey')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
g.sql_create_table(ast.SqlStmtLine{
|
||||||
|
kind: node.kind
|
||||||
|
pos: node.pos
|
||||||
|
table_expr: ast.TypeNode{
|
||||||
|
typ: atyp
|
||||||
|
pos: node.table_expr.pos
|
||||||
|
}
|
||||||
|
}, expr)
|
||||||
|
} else {
|
||||||
|
verror('unknown type ($field.typ) for field $field.name in struct $table_name')
|
||||||
|
}
|
||||||
|
continue
|
||||||
} 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
|
||||||
|
|
Loading…
Reference in New Issue