v/vlib/v/gen/c/sql.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('}')
}