mirror of
https://github.com/vlang/v.git
synced 2025-09-14 23:12:33 +03:00
860 lines
24 KiB
V
860 lines
24 KiB
V
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
|
module c
|
|
|
|
import v.ast
|
|
import v.token
|
|
import v.util
|
|
|
|
enum SqlExprSide {
|
|
left
|
|
right
|
|
}
|
|
|
|
fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
|
conn := g.new_tmp_var()
|
|
g.writeln('')
|
|
g.writeln('// orm')
|
|
g.write('orm__Connection ${conn} = (orm__Connection){._')
|
|
db_expr_ctype_name := g.typ(node.db_expr_type)
|
|
g.write('${db_expr_ctype_name} = &')
|
|
g.expr(node.db_expr)
|
|
g.writeln(', ._typ = _orm__Connection_${db_expr_ctype_name}_index};')
|
|
for line in node.lines {
|
|
g.sql_stmt_line(line, conn, node.or_expr)
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) sql_stmt_line(nd ast.SqlStmtLine, expr string, or_expr ast.OrExpr) {
|
|
mut node := nd
|
|
table_name := g.get_table_name(node.table_expr)
|
|
g.sql_table_name = g.table.sym(node.table_expr.typ).name
|
|
res := g.new_tmp_var()
|
|
|
|
if node.kind != .create {
|
|
mut fields := []ast.StructField{}
|
|
for f in node.fields {
|
|
mut skip := false
|
|
mut primary := false
|
|
for attr in f.attrs {
|
|
if attr.name == 'primary' {
|
|
primary = true
|
|
}
|
|
if attr.name == 'skip' {
|
|
skip = true
|
|
}
|
|
}
|
|
if !skip && !primary {
|
|
fields << f
|
|
}
|
|
}
|
|
node.fields = fields.clone()
|
|
unsafe { fields.free() }
|
|
}
|
|
if node.kind == .create {
|
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
|
g.sql_create_table(node, expr, table_name)
|
|
} else if node.kind == .drop {
|
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
|
g.writeln('drop(${expr}._object, _SLIT("${table_name}"));')
|
|
} else if node.kind == .insert {
|
|
arr := g.new_tmp_var()
|
|
g.writeln('Array_orm__Primitive ${arr} = __new_array_with_default_noscan(0, 0, sizeof(orm__Primitive), 0);')
|
|
g.sql_insert(node, expr, table_name, arr, res, '', '', or_expr)
|
|
} else if node.kind == .update {
|
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
|
g.sql_update(node, expr, table_name)
|
|
} else if node.kind == .delete {
|
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
|
g.sql_delete(node, expr, table_name)
|
|
}
|
|
|
|
if or_expr.kind == .block {
|
|
g.or_block(res, or_expr, ast.int_type.set_flag(.result))
|
|
} else if or_expr.kind == .absent {
|
|
g.write_error_handling_for_orm_result(node.pos, res)
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) sql_create_table(node ast.SqlStmtLine, expr string, table_name string) {
|
|
g.write('create(${expr}._object, _SLIT("${table_name}"), new_array_from_c_array(${node.fields.len}, ${node.fields.len}, sizeof(orm__TableField),')
|
|
if node.fields.len > 0 {
|
|
g.write(' _MOV((orm__TableField[${node.fields.len}]){')
|
|
for field in node.fields {
|
|
sym := g.table.sym(field.typ)
|
|
g.write('(orm__TableField){')
|
|
g.write('.name = _SLIT("${field.name}"),')
|
|
mut typ := int(field.typ)
|
|
if sym.name == 'time.Time' {
|
|
typ = -2
|
|
}
|
|
g.write('.typ = ${typ},')
|
|
g.write('.is_arr = ${sym.kind == .array}, ')
|
|
g.write('.is_time = ${g.table.get_type_name(field.typ) == 'time__Time'},')
|
|
g.write('.default_val = (string){.str = (byteptr) "${field.default_val}", .is_lit = 1},')
|
|
g.write('.attrs = new_array_from_c_array(${field.attrs.len}, ${field.attrs.len}, sizeof(StructAttribute),')
|
|
if field.attrs.len > 0 {
|
|
g.write(' _MOV((StructAttribute[${field.attrs.len}]){')
|
|
for attr in field.attrs {
|
|
g.write('(StructAttribute){')
|
|
g.write('.name = _SLIT("${attr.name}"),')
|
|
g.write('.has_arg = ${attr.has_arg},')
|
|
g.write('.arg = _SLIT("${attr.arg}"),')
|
|
g.write('.kind = ${int(attr.kind)},')
|
|
g.write('},')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('NULL')
|
|
}
|
|
g.write(')')
|
|
g.write('},')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('NULL')
|
|
}
|
|
g.writeln('));')
|
|
}
|
|
|
|
fn (mut g Gen) sql_insert(node ast.SqlStmtLine, expr string, table_name string, last_ids_arr string, res string, pid string, fkey string, or_expr ast.OrExpr) {
|
|
mut subs := []ast.SqlStmtLine{}
|
|
mut arrs := []ast.SqlStmtLine{}
|
|
mut fkeys := []string{}
|
|
mut field_names := []string{}
|
|
|
|
for f in node.fields {
|
|
sym := g.table.sym(f.typ)
|
|
if sym.kind == .struct_ && sym.name != 'time.Time' {
|
|
subs << node.sub_structs[int(f.typ)]
|
|
} else if sym.kind == .array {
|
|
mut f_key := ''
|
|
for attr in f.attrs {
|
|
if attr.name == 'fkey' && attr.has_arg {
|
|
if attr.kind == .string {
|
|
f_key = attr.arg
|
|
} else {
|
|
verror("fkey attribute need be string. Try [fkey: '${attr.arg}'] instead of [fkey: ${attr.arg}]")
|
|
}
|
|
}
|
|
}
|
|
if f_key == '' {
|
|
verror('An field which holds an array, needs a fkey defined')
|
|
}
|
|
fkeys << f_key
|
|
info := sym.array_info()
|
|
if info.nr_dims == 1 {
|
|
arrs << node.sub_structs[int(info.elem_type)]
|
|
field_names << f.name
|
|
} else {
|
|
verror('V ORM only supports 1 dimensional arrays')
|
|
}
|
|
}
|
|
}
|
|
|
|
fields := node.fields.filter(g.table.sym(it.typ).kind != .array)
|
|
|
|
for sub in subs {
|
|
g.sql_stmt_line(sub, expr, or_expr)
|
|
g.writeln('array_push(&${last_ids_arr}, _MOV((orm__Primitive[]){orm__Connection_name_table[${expr}._typ]._method_last_id(${expr}._object)}));')
|
|
}
|
|
|
|
g.write('${result_name}_void ${res} = orm__Connection_name_table[${expr}._typ]._method_')
|
|
g.write('insert(${expr}._object, _SLIT("${table_name}"), (orm__QueryData){')
|
|
|
|
g.write('.fields = new_array_from_c_array(${fields.len}, ${fields.len}, sizeof(string),')
|
|
if fields.len > 0 {
|
|
g.write('_MOV((string[${fields.len}]){')
|
|
for f in fields {
|
|
g.write('_SLIT("${g.get_field_name(f)}"),')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('NULL')
|
|
}
|
|
g.write('),')
|
|
|
|
g.write('.data = new_array_from_c_array(${fields.len}, ${fields.len}, sizeof(orm__Primitive),')
|
|
if fields.len > 0 {
|
|
g.write(' _MOV((orm__Primitive[${fields.len}]){')
|
|
mut structs := 0
|
|
for f in fields {
|
|
if f.name == fkey {
|
|
g.write('${pid}, ')
|
|
continue
|
|
}
|
|
mut sym := g.table.sym(f.typ)
|
|
mut typ := sym.cname
|
|
if sym.kind == .struct_ && typ != 'time__Time' {
|
|
g.write('(*(orm__Primitive*) array_get(${last_ids_arr}, ${structs})),')
|
|
structs++
|
|
continue
|
|
}
|
|
if typ == 'time__Time' {
|
|
typ = 'time'
|
|
}
|
|
g.write('orm__${typ}_to_primitive(${node.object_var_name}.${f.name}),')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('NULL')
|
|
}
|
|
g.write('),')
|
|
g.write('.types = __new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
|
g.write('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
|
g.write('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
|
g.writeln('});')
|
|
|
|
if arrs.len > 0 {
|
|
mut id_name := g.new_tmp_var()
|
|
g.writeln('orm__Primitive ${id_name} = orm__Connection_name_table[${expr}._typ]._method_last_id(${expr}._object);')
|
|
for i, mut arr in arrs {
|
|
idx := g.new_tmp_var()
|
|
g.writeln('for (int ${idx} = 0; ${idx} < ${arr.object_var_name}.${field_names[i]}.len; ${idx}++) {')
|
|
last_ids := g.new_tmp_var()
|
|
res_ := g.new_tmp_var()
|
|
tmp_var := g.new_tmp_var()
|
|
ctyp := g.typ(arr.table_expr.typ)
|
|
g.writeln('${ctyp} ${tmp_var} = (*(${ctyp}*)array_get(${arr.object_var_name}.${field_names[i]}, ${idx}));')
|
|
arr.object_var_name = tmp_var
|
|
mut fff := []ast.StructField{}
|
|
for f in arr.fields {
|
|
mut skip := false
|
|
mut primary := false
|
|
for attr in f.attrs {
|
|
if attr.name == 'primary' {
|
|
primary = true
|
|
}
|
|
if attr.name == 'skip' {
|
|
skip = true
|
|
}
|
|
}
|
|
if !skip && !primary {
|
|
fff << f
|
|
}
|
|
}
|
|
arr.fields = fff.clone()
|
|
unsafe { fff.free() }
|
|
g.sql_insert(arr, expr, g.get_table_name(arr.table_expr), last_ids, res_,
|
|
id_name, fkeys[i], or_expr)
|
|
g.writeln('}')
|
|
}
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) sql_update(node ast.SqlStmtLine, expr string, table_name string) {
|
|
g.write('update(${expr}._object, _SLIT("${table_name}"), (orm__QueryData){')
|
|
g.write('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
|
g.write('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
|
g.write('.types = __new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
|
g.write('.parentheses = __new_array_with_default_noscan(0, 0, sizeof(Array_int), 0),')
|
|
if node.updated_columns.len > 0 {
|
|
g.write('.fields = new_array_from_c_array(${node.updated_columns.len}, ${node.updated_columns.len}, sizeof(string),')
|
|
g.write(' _MOV((string[${node.updated_columns.len}]){')
|
|
for field in node.updated_columns {
|
|
g.write('_SLIT("${field}"),')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('.fields = __new_array_with_default_noscan(${node.updated_columns.len}, ${node.updated_columns.len}, sizeof(string), 0')
|
|
}
|
|
g.write('),')
|
|
g.write('.data = new_array_from_c_array(${node.update_exprs.len}, ${node.update_exprs.len}, sizeof(orm__Primitive),')
|
|
if node.update_exprs.len > 0 {
|
|
g.write(' _MOV((orm__Primitive[${node.update_exprs.len}]){')
|
|
for e in node.update_exprs {
|
|
g.sql_expr_to_orm_primitive(e)
|
|
}
|
|
g.write('})')
|
|
}
|
|
g.write('),},')
|
|
g.sql_gen_where_data(node.where_expr)
|
|
g.writeln(');')
|
|
}
|
|
|
|
fn (mut g Gen) sql_delete(node ast.SqlStmtLine, expr string, table_name string) {
|
|
g.write('_v_delete(${expr}._object, _SLIT("${table_name}"),')
|
|
g.sql_gen_where_data(node.where_expr)
|
|
g.writeln(');')
|
|
}
|
|
|
|
fn (mut g Gen) sql_expr_to_orm_primitive(expr ast.Expr) {
|
|
match expr {
|
|
ast.InfixExpr {
|
|
g.sql_write_orm_primitive(g.table.find_type_idx('orm.InfixType'), expr)
|
|
}
|
|
ast.StringLiteral {
|
|
g.sql_write_orm_primitive(ast.string_type, expr)
|
|
}
|
|
ast.IntegerLiteral {
|
|
g.sql_write_orm_primitive(ast.int_type, expr)
|
|
}
|
|
ast.BoolLiteral {
|
|
g.sql_write_orm_primitive(ast.bool_type, expr)
|
|
}
|
|
ast.Ident {
|
|
info := expr.info as ast.IdentVar
|
|
g.sql_write_orm_primitive(info.typ, expr)
|
|
}
|
|
ast.SelectorExpr {
|
|
g.sql_write_orm_primitive(expr.typ, expr)
|
|
}
|
|
else {
|
|
eprintln(expr)
|
|
verror('Unknown expr')
|
|
}
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) sql_write_orm_primitive(t ast.Type, expr ast.Expr) {
|
|
mut sym := g.table.sym(t)
|
|
mut typ := sym.cname
|
|
if typ == 'orm__Primitive' {
|
|
g.expr(expr)
|
|
g.write(',')
|
|
return
|
|
}
|
|
if typ == 'time__Time' {
|
|
typ = 'time'
|
|
}
|
|
if typ == 'orm__InfixType' {
|
|
typ = 'infix'
|
|
}
|
|
g.write('orm__${typ}_to_primitive(')
|
|
if expr is ast.InfixExpr {
|
|
g.write('(orm__InfixType){')
|
|
g.write('.name = _SLIT("${expr.left}"),')
|
|
mut kind := match expr.op {
|
|
.plus {
|
|
'orm__MathOperationKind__add'
|
|
}
|
|
.minus {
|
|
'orm__MathOperationKind__sub'
|
|
}
|
|
.div {
|
|
'orm__MathOperationKind__div'
|
|
}
|
|
.mul {
|
|
'orm__MathOperationKind__mul'
|
|
}
|
|
else {
|
|
''
|
|
}
|
|
}
|
|
g.write('.operator = ${kind},')
|
|
g.write('.right = ')
|
|
g.sql_expr_to_orm_primitive(expr.right)
|
|
g.write('}')
|
|
} else {
|
|
g.expr(expr)
|
|
}
|
|
g.write('),')
|
|
}
|
|
|
|
fn (mut g Gen) sql_where_data(expr ast.Expr, mut fields []string, mut parentheses [][]int, mut kinds []string, mut data []ast.Expr, mut is_and []bool) {
|
|
match expr {
|
|
ast.InfixExpr {
|
|
g.sql_side = .left
|
|
g.sql_where_data(expr.left, mut fields, mut parentheses, mut kinds, mut data, mut
|
|
is_and)
|
|
mut kind := match expr.op {
|
|
.ne {
|
|
'orm__OperationKind__neq'
|
|
}
|
|
.eq {
|
|
'orm__OperationKind__eq'
|
|
}
|
|
.lt {
|
|
'orm__OperationKind__lt'
|
|
}
|
|
.gt {
|
|
'orm__OperationKind__gt'
|
|
}
|
|
.ge {
|
|
'orm__OperationKind__ge'
|
|
}
|
|
.le {
|
|
'orm__OperationKind__le'
|
|
}
|
|
else {
|
|
''
|
|
}
|
|
}
|
|
if kind == '' {
|
|
if expr.op == .logical_or {
|
|
is_and << false
|
|
} else if expr.op == .and {
|
|
is_and << true
|
|
} else {
|
|
kind = 'orm__OperationKind__eq'
|
|
}
|
|
}
|
|
if expr.left !is ast.InfixExpr && expr.right !is ast.InfixExpr && kind != '' {
|
|
kinds << kind
|
|
}
|
|
g.sql_side = .right
|
|
g.sql_where_data(expr.right, mut fields, mut parentheses, mut kinds, mut data, mut
|
|
is_and)
|
|
}
|
|
ast.ParExpr {
|
|
mut par := [fields.len]
|
|
g.sql_where_data(expr.expr, mut fields, mut parentheses, mut kinds, mut data, mut
|
|
is_and)
|
|
par << fields.len - 1
|
|
parentheses << par
|
|
}
|
|
ast.Ident {
|
|
if g.sql_side == .left {
|
|
fields << g.get_field_name(g.get_struct_field(expr.name))
|
|
} else {
|
|
data << expr
|
|
}
|
|
}
|
|
ast.StringLiteral {
|
|
data << expr
|
|
}
|
|
ast.IntegerLiteral {
|
|
data << expr
|
|
}
|
|
ast.SelectorExpr {
|
|
data << expr
|
|
}
|
|
ast.BoolLiteral {
|
|
data << expr
|
|
}
|
|
else {}
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) sql_gen_where_data(where_expr ast.Expr) {
|
|
g.write('(orm__QueryData){')
|
|
mut fields := []string{}
|
|
mut kinds := []string{}
|
|
mut parentheses := [][]int{}
|
|
mut data := []ast.Expr{}
|
|
mut is_and := []bool{}
|
|
g.sql_where_data(where_expr, mut fields, mut parentheses, mut kinds, mut data, mut
|
|
is_and)
|
|
g.write('.types = __new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
|
if fields.len > 0 {
|
|
g.write('.fields = new_array_from_c_array(${fields.len}, ${fields.len}, sizeof(string),')
|
|
g.write(' _MOV((string[${fields.len}]){')
|
|
for field in fields {
|
|
g.write('_SLIT("${field}"),')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('.fields = __new_array_with_default_noscan(${fields.len}, ${fields.len}, sizeof(string), 0')
|
|
}
|
|
g.write('),')
|
|
|
|
g.write('.data = new_array_from_c_array(${data.len}, ${data.len}, sizeof(orm__Primitive),')
|
|
if data.len > 0 {
|
|
g.write(' _MOV((orm__Primitive[${data.len}]){')
|
|
for e in data {
|
|
g.sql_expr_to_orm_primitive(e)
|
|
}
|
|
g.write('})')
|
|
}
|
|
g.write('),')
|
|
|
|
g.write('.parentheses = ')
|
|
if parentheses.len > 0 {
|
|
g.write('new_array_from_c_array(${parentheses.len}, ${parentheses.len}, sizeof(Array_int), _MOV((Array_int[${parentheses.len}]){')
|
|
for par in parentheses {
|
|
if par.len > 0 {
|
|
g.write('new_array_from_c_array(${par.len}, ${par.len}, sizeof(int), _MOV((int[${par.len}]){')
|
|
for val in par {
|
|
g.write('${val},')
|
|
}
|
|
g.write('})),')
|
|
} else {
|
|
g.write('__new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
|
}
|
|
}
|
|
g.write('}))')
|
|
} else {
|
|
g.write('__new_array_with_default_noscan(0, 0, sizeof(Array_int), 0)')
|
|
}
|
|
g.write(',')
|
|
|
|
if kinds.len > 0 {
|
|
g.write('.kinds = new_array_from_c_array(${kinds.len}, ${kinds.len}, sizeof(orm__OperationKind),')
|
|
g.write(' _MOV((orm__OperationKind[${kinds.len}]){')
|
|
for k in kinds {
|
|
g.write('${k},')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('.kinds = __new_array_with_default_noscan(${kinds.len}, ${kinds.len}, sizeof(orm__OperationKind), 0')
|
|
}
|
|
g.write('),')
|
|
|
|
if is_and.len > 0 {
|
|
g.write('.is_and = new_array_from_c_array(${is_and.len}, ${is_and.len}, sizeof(bool),')
|
|
g.write(' _MOV((bool[${is_and.len}]){')
|
|
for b in is_and {
|
|
g.write('${b}, ')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('.is_and = __new_array_with_default_noscan(${is_and.len}, ${is_and.len}, sizeof(bool), 0')
|
|
}
|
|
g.write('),}')
|
|
}
|
|
|
|
fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
|
left := g.go_before_stmt(0)
|
|
conn := g.new_tmp_var()
|
|
g.writeln('')
|
|
g.writeln('// orm')
|
|
g.write('orm__Connection ${conn} = (orm__Connection){._')
|
|
db_expr_type := g.get_db_type(node.db_expr) or {
|
|
verror('sql orm error - unknown db type for ${node.db_expr}')
|
|
}
|
|
db_expr_ctype_name := g.typ(db_expr_type)
|
|
g.write('${db_expr_ctype_name} = &')
|
|
g.expr(node.db_expr)
|
|
g.writeln(', ._typ = _orm__Connection_${db_expr_ctype_name}_index};')
|
|
g.sql_select(node, conn, left, node.or_expr)
|
|
}
|
|
|
|
fn (mut g Gen) sql_select(node ast.SqlExpr, expr string, left string, or_expr ast.OrExpr) {
|
|
mut fields := []ast.StructField{}
|
|
mut prim := ''
|
|
for f in node.fields {
|
|
mut skip := false
|
|
for attr in f.attrs {
|
|
if attr.name == 'primary' {
|
|
prim = f.name
|
|
}
|
|
if attr.name == 'skip' {
|
|
skip = true
|
|
}
|
|
}
|
|
if !skip {
|
|
fields << f
|
|
}
|
|
}
|
|
|
|
res := g.new_tmp_var()
|
|
table_name := g.get_table_name(node.table_expr)
|
|
g.sql_table_name = g.table.sym(node.table_expr.typ).name
|
|
g.write('${result_name}_Array_Array_orm__Primitive _o${res} = orm__Connection_name_table[${expr}._typ]._method_select(${expr}._object, ')
|
|
g.write('(orm__SelectConfig){')
|
|
g.write('.table = _SLIT("${table_name}"),')
|
|
g.write('.is_count = ${node.is_count},')
|
|
g.write('.has_where = ${node.has_where},')
|
|
g.write('.has_order = ${node.has_order},')
|
|
if node.has_order {
|
|
g.write('.order = _SLIT("')
|
|
g.expr(node.order_expr)
|
|
g.write('"),')
|
|
if node.has_desc {
|
|
g.write('.order_type = orm__OrderType__desc,')
|
|
} else {
|
|
g.write('.order_type = orm__OrderType__asc,')
|
|
}
|
|
}
|
|
g.write('.has_limit = ${node.has_limit},')
|
|
g.write('.has_offset = ${node.has_offset},')
|
|
if prim != '' {
|
|
g.write('.primary = _SLIT("${prim}"),')
|
|
}
|
|
select_fields := fields.filter(g.table.sym(it.typ).kind != .array)
|
|
g.write('.fields = new_array_from_c_array(${select_fields.len}, ${select_fields.len}, sizeof(string),')
|
|
mut types := []int{}
|
|
if select_fields.len > 0 {
|
|
g.write(' _MOV((string[${select_fields.len}]){')
|
|
for field in select_fields {
|
|
g.write('_SLIT("${g.get_field_name(field)}"),')
|
|
sym := g.table.sym(field.typ)
|
|
if sym.name == 'time.Time' {
|
|
types << -2
|
|
continue
|
|
}
|
|
if sym.kind == .struct_ {
|
|
types << int(ast.int_type)
|
|
continue
|
|
}
|
|
types << int(field.typ)
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('NULL')
|
|
}
|
|
g.write('),')
|
|
g.write('.types = new_array_from_c_array(${types.len}, ${types.len}, sizeof(int),')
|
|
if types.len > 0 {
|
|
g.write(' _MOV((int[${types.len}]){')
|
|
for typ in types {
|
|
g.write('${typ},')
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('NULL')
|
|
}
|
|
g.write('),},')
|
|
|
|
mut exprs := []ast.Expr{}
|
|
if node.has_limit {
|
|
exprs << node.limit_expr
|
|
}
|
|
if node.has_offset {
|
|
exprs << node.offset_expr
|
|
}
|
|
g.write('(orm__QueryData) {')
|
|
g.write('.types = __new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
|
g.write('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
|
g.write('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
|
g.write('.parentheses = __new_array_with_default_noscan(0, 0, sizeof(Array_int), 0),')
|
|
if exprs.len > 0 {
|
|
g.write('.data = new_array_from_c_array(${exprs.len}, ${exprs.len}, sizeof(orm__Primitive),')
|
|
g.write(' _MOV((orm__Primitive[${exprs.len}]){')
|
|
for e in exprs {
|
|
g.sql_expr_to_orm_primitive(e)
|
|
}
|
|
g.write('})')
|
|
} else {
|
|
g.write('.data = __new_array_with_default_noscan(${exprs.len}, ${exprs.len}, sizeof(orm__Primitive), 0')
|
|
}
|
|
g.write(')},')
|
|
|
|
if node.has_where {
|
|
g.sql_gen_where_data(node.where_expr)
|
|
} else {
|
|
g.write('(orm__QueryData) {')
|
|
g.write('.types = __new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
|
g.write('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
|
g.write('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
|
g.write('.parentheses = __new_array_with_default_noscan(0, 0, sizeof(Array_int), 0),')
|
|
g.write('.data = __new_array_with_default_noscan(0, 0, sizeof(orm__Primitive), 0)')
|
|
g.write('}')
|
|
}
|
|
g.writeln(');')
|
|
|
|
mut tmp_left := g.new_tmp_var()
|
|
g.writeln('${g.typ(node.typ.set_flag(.result))} ${tmp_left};')
|
|
|
|
if node.or_expr.kind == .block {
|
|
g.writeln('${tmp_left}.is_error = _o${res}.is_error;')
|
|
g.writeln('${tmp_left}.err = _o${res}.err;')
|
|
g.or_block(tmp_left, node.or_expr, node.typ.set_flag(.result))
|
|
g.writeln('else {')
|
|
g.indent++
|
|
} else if node.or_expr.kind == .absent {
|
|
g.write_error_handling_for_orm_result(node.pos, '_o${res}')
|
|
}
|
|
|
|
g.writeln('Array_Array_orm__Primitive ${res} = (*(Array_Array_orm__Primitive*)_o${res}.data);')
|
|
|
|
if node.is_count {
|
|
g.writeln('*(${g.typ(node.typ)}*) ${tmp_left}.data = *((*(orm__Primitive*) array_get((*(Array_orm__Primitive*)array_get(${res}, 0)), 0))._int);')
|
|
if node.or_expr.kind == .block {
|
|
g.indent--
|
|
g.writeln('}')
|
|
}
|
|
} else {
|
|
tmp := g.new_tmp_var()
|
|
styp := g.typ(node.typ)
|
|
idx := g.new_tmp_var()
|
|
g.writeln('int ${idx} = 0;')
|
|
mut typ_str := ''
|
|
if node.is_array {
|
|
info := g.table.sym(node.typ).array_info()
|
|
typ_str = g.typ(info.elem_type)
|
|
g.writeln('${styp} ${tmp}_array = __new_array(0, ${res}.len, sizeof(${typ_str}));')
|
|
g.writeln('for (; ${idx} < ${res}.len; ${idx}++) {')
|
|
g.indent++
|
|
g.write('${typ_str} ${tmp} = (${typ_str}) {')
|
|
inf := g.table.sym(info.elem_type).struct_info()
|
|
for i, field in inf.fields {
|
|
g.zero_struct_field(field)
|
|
if i != inf.fields.len - 1 {
|
|
g.write(', ')
|
|
}
|
|
}
|
|
g.writeln('};')
|
|
} else {
|
|
g.write('${styp} ${tmp} = (${styp}){')
|
|
info := g.table.sym(node.typ).struct_info()
|
|
for i, field in info.fields {
|
|
g.zero_struct_field(field)
|
|
if i != info.fields.len - 1 {
|
|
g.write(', ')
|
|
}
|
|
}
|
|
g.writeln('};')
|
|
}
|
|
|
|
g.writeln('if (${res}.len > 0) {')
|
|
g.indent++
|
|
for i, field in fields {
|
|
sel := '(*(orm__Primitive*) array_get((*(Array_orm__Primitive*) array_get(${res}, ${idx})), ${i}))'
|
|
sym := g.table.sym(field.typ)
|
|
if sym.kind == .struct_ && sym.name != 'time.Time' {
|
|
mut sub := node.sub_structs[int(field.typ)]
|
|
mut where_expr := sub.where_expr as ast.InfixExpr
|
|
mut ident := where_expr.right as ast.Ident
|
|
name := sel
|
|
s := g.table.find_type_idx('orm.Primitive')
|
|
if s != 0 {
|
|
if mut ident.info is ast.IdentVar {
|
|
ident.info.typ = s
|
|
}
|
|
}
|
|
ident.name = name
|
|
where_expr.right = ident
|
|
sub.where_expr = where_expr
|
|
|
|
g.sql_select(sub, expr, '${tmp}.${field.name} = ', or_expr)
|
|
} else if sym.kind == .array {
|
|
mut fkey := ''
|
|
for attr in field.attrs {
|
|
if attr.name == 'fkey' && attr.has_arg {
|
|
if attr.kind == .string {
|
|
fkey = attr.arg
|
|
} else {
|
|
verror("fkey attribute need be string. Try [fkey: '${attr.arg}'] instead of [fkey: ${attr.arg}]")
|
|
}
|
|
}
|
|
}
|
|
if fkey == '' {
|
|
verror('An field which holds an array, needs a fkey defined')
|
|
}
|
|
info := sym.array_info()
|
|
arr_typ := info.elem_type
|
|
sub := node.sub_structs[int(arr_typ)]
|
|
mut where_expr := sub.where_expr as ast.InfixExpr
|
|
mut l := where_expr.left as ast.Ident
|
|
mut r := where_expr.right as ast.Ident
|
|
l.name = fkey
|
|
r.name = tmp
|
|
where_expr.left = l
|
|
where_expr.right = ast.SelectorExpr{
|
|
pos: r.pos
|
|
field_name: prim
|
|
is_mut: false
|
|
expr: r
|
|
expr_type: (r.info as ast.IdentVar).typ
|
|
typ: ast.int_type
|
|
scope: 0
|
|
}
|
|
mut arr := ast.SqlExpr{
|
|
typ: field.typ
|
|
is_count: sub.is_count
|
|
db_expr: sub.db_expr
|
|
has_where: sub.has_where
|
|
has_offset: sub.has_offset
|
|
offset_expr: sub.offset_expr
|
|
has_order: sub.has_order
|
|
order_expr: sub.order_expr
|
|
has_desc: sub.has_desc
|
|
is_array: true
|
|
pos: sub.pos
|
|
has_limit: sub.has_limit
|
|
limit_expr: sub.limit_expr
|
|
table_expr: sub.table_expr
|
|
fields: sub.fields
|
|
where_expr: where_expr
|
|
}
|
|
|
|
g.sql_select(arr, expr, '${tmp}.${field.name} = ', or_expr)
|
|
} else {
|
|
mut typ := sym.cname
|
|
g.writeln('${tmp}.${field.name} = *(${sel}._${typ});')
|
|
}
|
|
}
|
|
g.indent--
|
|
g.writeln('}')
|
|
|
|
if node.is_array {
|
|
g.writeln('array_push(&${tmp}_array, _MOV((${typ_str}[]){ ${tmp} }));')
|
|
g.indent--
|
|
g.writeln('}')
|
|
}
|
|
|
|
g.write('*(${g.typ(node.typ)}*) ${tmp_left}.data = ${tmp}')
|
|
if node.is_array {
|
|
g.write('_array')
|
|
}
|
|
g.writeln(';')
|
|
if node.or_expr.kind == .block {
|
|
g.indent--
|
|
g.writeln('}')
|
|
}
|
|
}
|
|
g.write('${left} *(${g.typ(node.typ)}*) ${tmp_left}.data')
|
|
if !g.inside_call {
|
|
g.writeln(';')
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) get_db_type(expr ast.Expr) ?ast.Type {
|
|
match expr {
|
|
ast.Ident {
|
|
if expr.info is ast.IdentVar {
|
|
return g.table.unaliased_type(expr.info.typ)
|
|
}
|
|
}
|
|
ast.SelectorExpr {
|
|
return g.table.unaliased_type(expr.typ)
|
|
}
|
|
else {
|
|
return none
|
|
}
|
|
}
|
|
return none
|
|
}
|
|
|
|
fn (mut g Gen) get_table_name(table_expr ast.TypeNode) string {
|
|
info := g.table.sym(table_expr.typ).struct_info()
|
|
mut tablename := util.strip_mod_name(g.table.sym(table_expr.typ).name)
|
|
for attr in info.attrs {
|
|
if attr.kind == .string && attr.name == 'table' && attr.arg != '' {
|
|
tablename = attr.arg
|
|
break
|
|
}
|
|
}
|
|
return tablename
|
|
}
|
|
|
|
fn (mut g Gen) get_struct_field(name string) ast.StructField {
|
|
info := g.table.sym(g.table.type_idxs[g.sql_table_name]).struct_info()
|
|
mut f := ast.StructField{}
|
|
for field in info.fields {
|
|
if field.name == name {
|
|
f = field
|
|
}
|
|
}
|
|
return f
|
|
}
|
|
|
|
fn (mut g Gen) get_field_name(field ast.StructField) string {
|
|
mut name := field.name
|
|
for attr in field.attrs {
|
|
if attr.kind == .string && attr.name == 'sql' && attr.arg != '' {
|
|
name = attr.arg
|
|
break
|
|
}
|
|
}
|
|
sym := g.table.sym(field.typ)
|
|
if sym.kind == .struct_ && sym.name != 'time.Time' {
|
|
name = '${name}_id'
|
|
}
|
|
return name
|
|
}
|
|
|
|
fn (mut g Gen) write_error_handling_for_orm_result(expr_pos &token.Pos, result_var_name string) {
|
|
g.writeln('if (${result_var_name}.is_error) {')
|
|
|
|
if g.pref.is_debug {
|
|
g.write_v_source_line_info(expr_pos)
|
|
paline, pafile, pamod, pafn := g.panic_debug_info(expr_pos)
|
|
g.write('\tpanic_debug(${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), IError_str(${result_var_name}.err) );')
|
|
} else {
|
|
g.writeln('\t_v_panic(IError_str(${result_var_name}.err));')
|
|
}
|
|
|
|
g.writeln('}')
|
|
}
|