v orm: select
							parent
							
								
									23993d2264
								
							
						
					
					
						commit
						ed58192e4c
					
				|  | @ -1,6 +1,6 @@ | |||
| import os | ||||
| import pg | ||||
| import term | ||||
| //import os
 | ||||
| //import pg
 | ||||
| //import term
 | ||||
| import sqlite | ||||
| 
 | ||||
| struct Modules { | ||||
|  | @ -11,30 +11,48 @@ struct Modules { | |||
| 	//nr_downloads int
 | ||||
| } | ||||
| 
 | ||||
| struct User { | ||||
| 	id int | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| fn test_orm_sqlite() { | ||||
| 	db := sqlite.connect(':memory:') or { panic(err) } | ||||
| 	/* | ||||
| 	db.exec("drop table if exists users") | ||||
| 	db.exec("create table users (id integer primary key, name text default '');") | ||||
| 	db.exec("drop table if exists User") | ||||
| 	db.exec("create table User (id integer primary key, name text default '');") | ||||
| 
 | ||||
| 	db.exec("insert into users (name) values ('Sam')") | ||||
| 	db.exec("insert into users (name) values ('Peter')") | ||||
| 	db.exec("insert into users (name) values ('Kate')") | ||||
| 	nr_users := sql db { | ||||
| 		//select count from modules
 | ||||
| 	name := 'sam' | ||||
| 
 | ||||
| 	db.exec("insert into User (name) values ('Sam')") | ||||
| 	db.exec("insert into User (name) values ('Peter')") | ||||
| 	db.exec("insert into User (name) values ('Kate')") | ||||
| 	nr_all_users := sql db { | ||||
| 		select count from User | ||||
| 	} | ||||
| 	assert nr_users == 3 | ||||
| 	println('nr_users=') | ||||
| 	println(nr_users) | ||||
| 	//nr_modules := db.select count from modules
 | ||||
| 	//nr_modules := db.select count from Modules where id == 1
 | ||||
| 	//nr_modules := db.select count from Modules where
 | ||||
| 		//name == 'Bob' && id == 1
 | ||||
| 	*/ | ||||
| 	assert nr_all_users == 3 | ||||
| 	println('nr_all_users=$nr_all_users') | ||||
| 	//
 | ||||
| 	nr_users1 := sql db { | ||||
| 		select count from User where id == 1 | ||||
| 	} | ||||
| 	assert nr_users1 == 1 | ||||
| 	println('nr_users1=$nr_users1') | ||||
| 	//
 | ||||
| 	nr_peters := sql db { | ||||
| 		select count from User where id == 2 && name == 'Peter' | ||||
| 	} | ||||
| 	assert nr_peters == 1 | ||||
| 	println('nr_peters=$nr_peters') | ||||
| 	//
 | ||||
| 	nr_sams := sql db { | ||||
| 		select count from User where id == 1 && name == name | ||||
| 	} | ||||
| 	println('nr_sams=$nr_sams') | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| fn test_orm_pg() { | ||||
| /* | ||||
| 	dbname := os.getenv('VDB_NAME') | ||||
| 	dbuser := os.getenv('VDB_USER') | ||||
| 	if dbname == '' || dbuser == '' { | ||||
|  | @ -43,8 +61,7 @@ fn test_orm_pg() { | |||
| 	} | ||||
| 	db := pg.connect(dbname: dbname, user: dbuser) or { panic(err) } | ||||
| 	_ = db | ||||
| /* | ||||
| 	//nr_modules := db.select count from modules
 | ||||
| 	nr_modules := db.select count from modules | ||||
| 	//nr_modules := db.select count from Modules where id == 1
 | ||||
| 	nr_modules := db.select count from Modules where | ||||
| 		name == 'Bob' && id == 1 | ||||
|  | @ -61,6 +78,7 @@ fn test_orm_pg() { | |||
| 
 | ||||
| /* | ||||
| 	mod := db.retrieve<Module>(1) | ||||
| 	mod := db.select from Module where id = 1 | ||||
| 
 | ||||
| 	mod := db.update Module set name = name + '!' where id > 10 | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,6 +37,21 @@ pub fn connect(path string) ?DB { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Only for V ORM
 | ||||
| fn (db DB) init_stmt(query string) &C.sqlite3_stmt { | ||||
| 	stmt := &C.sqlite3_stmt(0) | ||||
| 	C.sqlite3_prepare_v2(db.conn, query.str, -1, &stmt, 0) | ||||
| 	return stmt | ||||
| } | ||||
| 
 | ||||
| // Only for V ORM
 | ||||
| fn get_int_from_stmt(stmt &C.sqlite3_stmt) int { | ||||
| 	C.sqlite3_step(stmt) | ||||
| 	res := C.sqlite3_column_int(stmt, 0) | ||||
| 	C.sqlite3_finalize(stmt) | ||||
| 	return res | ||||
| } | ||||
| 
 | ||||
| // Returns a single cell with value int.
 | ||||
| pub fn (db DB) q_int(query string) int { | ||||
| 	stmt := &C.sqlite3_stmt(0) | ||||
|  |  | |||
|  | @ -49,6 +49,24 @@ pub fn (mut b Builder) go_back(n int) { | |||
| 	b.len -= n | ||||
| } | ||||
| 
 | ||||
| pub fn (mut b Builder) cut_last(n int) string { | ||||
| 	buf := b.buf[b.len-n..] | ||||
| 	s := string(buf.clone()) | ||||
| 	b.buf.trim(b.buf.len-n) | ||||
| 	b.len -= n | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| pub fn (mut b Builder) cut_to(pos int) string { | ||||
| 	buf := b.buf[pos..] | ||||
| 	s := string(buf.clone()) | ||||
| 	b.buf.trim(pos) | ||||
| 	b.len = pos | ||||
| 	return s | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| pub fn (mut b Builder) go_back_to(pos int) { | ||||
| 	b.buf.trim(pos) | ||||
| 	b.len = pos | ||||
|  |  | |||
|  | @ -8,11 +8,25 @@ fn test_sb() { | |||
| 	assert sb.len == 8 | ||||
| 	assert sb.str() == 'hi!hello' | ||||
| 	assert sb.len == 0 | ||||
| 	///
 | ||||
| 	sb = strings.new_builder(10) | ||||
| 	sb.write('a') | ||||
| 	sb.write('b') | ||||
| 	assert sb.len == 2 | ||||
| 	assert sb.str() == 'ab' | ||||
| 	///
 | ||||
| 	sb = strings.new_builder(10) | ||||
| 	sb.write('123456') | ||||
| 	assert sb.cut_last(2) == '56' | ||||
| 	assert sb.str() == '1234' | ||||
| 	///
 | ||||
| 	/* | ||||
| 	sb = strings.new_builder(10) | ||||
| 	sb.write('123456') | ||||
| 	x := sb.cut_to(2) | ||||
| 	assert x == '456' | ||||
| 	assert sb.str() == '123' | ||||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
|  |  | |||
|  | @ -61,6 +61,10 @@ pub fn header(text, divider string) string { | |||
| } | ||||
| 
 | ||||
| fn supports_escape_sequences(fd int) bool { | ||||
| 	//println('TERM=' + os.getenv('TERM'))
 | ||||
| 	if os.getenv('TERM') == 'dumb' { | ||||
| 		return false | ||||
| 	} | ||||
| 	vcolors_override := os.getenv('VCOLORS') | ||||
| 	if vcolors_override == 'always' { | ||||
| 		return true | ||||
|  |  | |||
|  | @ -801,7 +801,13 @@ pub: | |||
| } | ||||
| 
 | ||||
| pub struct SqlExpr { | ||||
| 	typ table.Type | ||||
| pub: | ||||
| 	typ         table.Type | ||||
| 	is_count    bool | ||||
| 	db_var_name string // `db` in `sql db {`
 | ||||
| 	table_name  string | ||||
| 	where_expr Expr | ||||
| 	has_where bool | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
|  |  | |||
|  | @ -556,7 +556,8 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { | |||
| 				c.error('$infix_expr.op.str(): type `${typ_sym.name}` does not exist', type_expr.pos) | ||||
| 			} | ||||
| 			if left.kind != .interface_ && left.kind != .sum_type { | ||||
| 				c.error('`$infix_expr.op.str()` can only be used with interfaces and sum types', type_expr.pos) | ||||
| 				c.error('`$infix_expr.op.str()` can only be used with interfaces and sum types', | ||||
| 					type_expr.pos) | ||||
| 			} | ||||
| 			return table.bool_type | ||||
| 		} | ||||
|  | @ -681,9 +682,12 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_e | |||
| 		ast.AnonFn { | ||||
| 			if it.decl.args.len > 1 { | ||||
| 				c.error('function needs exactly 1 argument', call_expr.pos) | ||||
| 			} else if is_map && (it.decl.return_type != elem_typ || it.decl.args[0].typ != elem_typ) { | ||||
| 				c.error('type mismatch, should use `fn(a $elem_sym.name) $elem_sym.name {...}`', call_expr.pos) | ||||
| 			} else if !is_map && (it.decl.return_type != table.bool_type || it.decl.args[0].typ != elem_typ) { | ||||
| 			} else if is_map && (it.decl.return_type != elem_typ || it.decl.args[0].typ != | ||||
| 				elem_typ) { | ||||
| 				c.error('type mismatch, should use `fn(a $elem_sym.name) $elem_sym.name {...}`', | ||||
| 					call_expr.pos) | ||||
| 			} else if !is_map && (it.decl.return_type != table.bool_type || it.decl.args[0].typ != | ||||
| 				elem_typ) { | ||||
| 				c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`', call_expr.pos) | ||||
| 			} | ||||
| 		} | ||||
|  | @ -696,9 +700,12 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_e | |||
| 				if func.args.len > 1 { | ||||
| 					c.error('function needs exactly 1 argument', call_expr.pos) | ||||
| 				} else if is_map && (func.return_type != elem_typ || func.args[0].typ != elem_typ) { | ||||
| 					c.error('type mismatch, should use `fn(a $elem_sym.name) $elem_sym.name {...}`', call_expr.pos) | ||||
| 				} else if !is_map && (func.return_type != table.bool_type || func.args[0].typ != elem_typ) { | ||||
| 					c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`', call_expr.pos) | ||||
| 					c.error('type mismatch, should use `fn(a $elem_sym.name) $elem_sym.name {...}`', | ||||
| 						call_expr.pos) | ||||
| 				} else if !is_map && (func.return_type != table.bool_type || func.args[0].typ != | ||||
| 					elem_typ) { | ||||
| 					c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`', | ||||
| 						call_expr.pos) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -1948,15 +1955,29 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { | |||
| 		ast.None { | ||||
| 			return table.none_type | ||||
| 		} | ||||
| 		ast.OrExpr { | ||||
| 			// never happens
 | ||||
| 			return table.void_type | ||||
| 		} | ||||
| 		ast.ParExpr { | ||||
| 			return c.expr(it.expr) | ||||
| 		} | ||||
| 		ast.RangeExpr { | ||||
| 			// never happens
 | ||||
| 			return table.void_type | ||||
| 		} | ||||
| 		ast.SelectorExpr { | ||||
| 			return c.selector_expr(mut it) | ||||
| 		} | ||||
| 		ast.SizeOf { | ||||
| 			return table.u32_type | ||||
| 		} | ||||
| 		ast.SqlExpr { | ||||
| 			if it.has_where { | ||||
| 				c.expr(it.where_expr) | ||||
| 			} | ||||
| 			return it.typ | ||||
| 		} | ||||
| 		ast.StringLiteral { | ||||
| 			if it.language == .c { | ||||
| 				return table.byteptr_type | ||||
|  | @ -1986,12 +2007,6 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { | |||
| 			} | ||||
| 			return table.bool_type | ||||
| 		} | ||||
| 		else { | ||||
| 			tnode := typeof(node) | ||||
| 			if tnode != 'unknown v.ast.Expr' { | ||||
| 				println('checker.expr(): unhandled node with typeof(`${tnode}`)') | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return table.void_type | ||||
| } | ||||
|  |  | |||
|  | @ -66,6 +66,7 @@ mut: | |||
| 	options              strings.Builder // `Option_xxxx` types
 | ||||
| 	json_forward_decls   strings.Builder // json type forward decls
 | ||||
| 	enum_typedefs        strings.Builder // enum types
 | ||||
| 	sql_buf              strings.Builder // for writing exprs to args via `sqlite3_bind_int()` etc
 | ||||
| 	file                 ast.File | ||||
| 	fn_decl              &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
 | ||||
| 	last_fn_c_name       string | ||||
|  | @ -76,6 +77,7 @@ mut: | |||
| 	is_assign_rhs        bool // inside right part of assign after `=` (val expr)
 | ||||
| 	is_array_set         bool | ||||
| 	is_amp               bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
 | ||||
| 	is_sql               bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
 | ||||
| 	optionals            []string // to avoid duplicates TODO perf, use map
 | ||||
| 	inside_ternary       int // ?: comma separated statements on a single line
 | ||||
| 	ternary_names        map[string]string | ||||
|  | @ -102,6 +104,8 @@ mut: | |||
| 	fn_main              &ast.FnDecl // the FnDecl of the main function. Needed in order to generate the main function code *last*
 | ||||
| 	cur_fn               &ast.FnDecl | ||||
| 	cur_generic_type     table.Type // `int`, `string`, etc in `foo<T>()`
 | ||||
| 	sql_i                int | ||||
| 	sql_stmt_name        string | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
|  | @ -131,6 +135,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string | |||
| 		options: strings.new_builder(100) | ||||
| 		json_forward_decls: strings.new_builder(100) | ||||
| 		enum_typedefs: strings.new_builder(100) | ||||
| 		sql_buf: strings.new_builder(100) | ||||
| 		table: table | ||||
| 		pref: pref | ||||
| 		fn_decl: 0 | ||||
|  | @ -1544,7 +1549,7 @@ fn (mut g Gen) expr(node ast.Expr) { | |||
| 		} | ||||
| 		ast.RangeExpr { | ||||
| 			// Only used in IndexExpr
 | ||||
| 			} | ||||
| 		} | ||||
| 		ast.SizeOf { | ||||
| 			mut styp := it.type_name | ||||
| 			if it.type_name == '' { | ||||
|  | @ -1566,7 +1571,7 @@ fn (mut g Gen) expr(node ast.Expr) { | |||
| 			g.write('sizeof($styp)') | ||||
| 		} | ||||
| 		ast.SqlExpr { | ||||
| 			g.write('// sql expression') | ||||
| 			g.sql_expr(it) | ||||
| 		} | ||||
| 		ast.StringLiteral { | ||||
| 			if it.is_raw { | ||||
|  | @ -1630,10 +1635,6 @@ fn (mut g Gen) expr(node ast.Expr) { | |||
| 			g.expr(it.expr) | ||||
| 			g.write(')') | ||||
| 		} | ||||
| 		//else {
 | ||||
| 			// #printf("node=%d\n", node.typ);
 | ||||
| 			//println(term.red('cgen.expr(): bad node ' + typeof(node)))
 | ||||
| 		//}
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -3173,6 +3174,15 @@ fn (mut g Gen) insert_before_stmt(s string) { | |||
| 	g.write(cur_line) | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) write_expr_to_string(expr ast.Expr) string { | ||||
| 	pos := g.out.buf.len | ||||
| 	g.expr(expr) | ||||
| 	return g.out.cut_last(g.out.buf.len - pos) | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) start_tmp() { | ||||
| } | ||||
| 
 | ||||
| // If user is accessing the return value eg. in assigment, pass the variable name.
 | ||||
| // If the user is not using the optional return value. We need to pass a temp var
 | ||||
| // to access its fields (`.ok`, `.error` etc)
 | ||||
|  | @ -3263,7 +3273,6 @@ fn (mut g Gen) in_optimization(left ast.Expr, right ast.ArrayInit) { | |||
| 			ptr_typ := g.gen_array_equality_fn(right.elem_type) | ||||
| 			g.write('${ptr_typ}_arr_eq(') | ||||
| 		} | ||||
| 
 | ||||
| 		g.expr(left) | ||||
| 		if is_str || is_array { | ||||
| 			g.write(', ') | ||||
|  | @ -4208,7 +4217,6 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { | |||
| 	if it.exprs.len == 0 { | ||||
| 		elem_sym := g.table.get_type_symbol(it.elem_type) | ||||
| 		is_default_array := elem_sym.kind == .array && it.has_default | ||||
| 
 | ||||
| 		if is_default_array { | ||||
| 			g.write('__new_array_with_array_default(') | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -0,0 +1,93 @@ | |||
| // Copyright (c) 2019-2020 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 gen | ||||
| 
 | ||||
| import v.ast | ||||
| import strings | ||||
| 
 | ||||
| // pg,mysql etc
 | ||||
| const ( | ||||
| 	dbtype = 'sqlite' | ||||
| ) | ||||
| 
 | ||||
| fn (mut g Gen) sql_expr(node ast.SqlExpr) { | ||||
| 	g.sql_i = 0 | ||||
| 	/* | ||||
| 	`nr_users := sql db { ... }` => | ||||
| 	``` | ||||
| 	sql_init_stmt() | ||||
| 	sql_bind_int() | ||||
| 	sql_bind_string() | ||||
| 	... | ||||
| 	int nr_users = get_int(stmt) | ||||
| 	``` | ||||
| 	*/ | ||||
| 	cur_line := g.go_before_stmt(0) | ||||
| 	mut q := 'select ' | ||||
| 	if node.is_count { | ||||
| 		// select count(*) from User
 | ||||
| 		q += 'count(*) from $node.table_name' | ||||
| 	} | ||||
| 	if node.has_where { | ||||
| 		q += ' where ' | ||||
| 	} | ||||
| 	// g.write('${dbtype}__DB_q_int(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q')
 | ||||
| 	g.sql_stmt_name = g.new_tmp_var() | ||||
| 	db_name := g.new_tmp_var() | ||||
| 	g.writeln('\n\t// sql') | ||||
| 	g.write('${dbtype}__DB $db_name = *(${dbtype}__DB*)${node.db_var_name}.data;') | ||||
| 	g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q') | ||||
| 	if node.has_where && node.where_expr is ast.InfixExpr { | ||||
| 		g.expr_to_sql(node.where_expr) | ||||
| 	} | ||||
| 	g.writeln('"));') | ||||
| 	// Dump all sql parameters generated by our custom expr handler
 | ||||
| 	binds := g.sql_buf.str() | ||||
| 	g.sql_buf = strings.new_builder(100) | ||||
| 	g.writeln(binds) | ||||
| 	g.writeln('puts(sqlite3_errmsg(${db_name}.conn));') | ||||
| 	g.writeln('$cur_line ${dbtype}__get_int_from_stmt($g.sql_stmt_name);') | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) expr_to_sql(expr ast.Expr) { | ||||
| 	// Custom handling for infix exprs (since we need e.g. `and` instead of `&&` in SQL queries),
 | ||||
| 	// strings. Everything else (like numbers, a.b) is handled by g.expr()
 | ||||
| 	//
 | ||||
| 	// TODO `where id = some_column + 1` needs literal generation of `some_column` as a string,
 | ||||
| 	// not a V variable. Need to distinguish column names from V variables.
 | ||||
| 	match expr { | ||||
| 		ast.InfixExpr { | ||||
| 			g.expr_to_sql(it.left) | ||||
| 			match it.op { | ||||
| 				.eq { g.write(' = ') } | ||||
| 				.and { g.write(' and ') } | ||||
| 				else {} | ||||
| 			} | ||||
| 			g.expr_to_sql(it.right) | ||||
| 		} | ||||
| 		ast.StringLiteral { | ||||
| 			// g.write("'$it.val'")
 | ||||
| 			g.inc_sql_i() | ||||
| 			g.sql_buf.writeln('sqlite3_bind_text($g.sql_stmt_name, $g.sql_i, "$it.val", $it.val.len, 0);') | ||||
| 		} | ||||
| 		ast.IntegerLiteral { | ||||
| 			g.inc_sql_i() | ||||
| 			g.sql_buf.writeln('sqlite3_bind_int($g.sql_stmt_name, $g.sql_i, $it.val);') | ||||
| 		} | ||||
| 		else { | ||||
| 			g.expr(expr) | ||||
| 		} | ||||
| 	} | ||||
| 	/* | ||||
| 	ast.Ident { | ||||
| 			g.write('$it.name') | ||||
| 		} | ||||
| 		else {} | ||||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) inc_sql_i() { | ||||
| 	g.sql_i++ | ||||
| 	g.write('?$g.sql_i') | ||||
| } | ||||
|  | @ -4,7 +4,76 @@ | |||
| module parser | ||||
| 
 | ||||
| import v.ast | ||||
| import v.table | ||||
| 
 | ||||
| fn (mut p Parser) sql_expr() ast.SqlExpr { | ||||
| 	return ast.SqlExpr{} | ||||
| 	// `sql db {`
 | ||||
| 	p.check_name() | ||||
| 	db_var_name := p.check_name() | ||||
| 	p.check(.lcbr) | ||||
| 	//
 | ||||
| 	p.check(.key_select) | ||||
| 	n := p.check_name() | ||||
| 	is_count := n == 'count' | ||||
| 	mut typ := table.void_type | ||||
| 	if is_count { | ||||
| 		p.check_name() // from
 | ||||
| 		typ = table.int_type | ||||
| 	} | ||||
| 	table_type := p.parse_type() // `User`
 | ||||
| 	sym := p.table.get_type_symbol(table_type) | ||||
| 	table_name := sym.name | ||||
| 	mut where_expr := ast.Expr{} | ||||
| 	has_where := p.tok.kind == .name && p.tok.lit == 'where' | ||||
| 	if has_where { | ||||
| 		p.next() | ||||
| 		where_expr = p.expr(0) | ||||
| 	} | ||||
| 	p.check(.rcbr) | ||||
| 	// /////////
 | ||||
| 	// Register this type's fields as variables so they can be used in `where`
 | ||||
| 	// expressions
 | ||||
| 	// fields := typ.fields.filter(typ == 'string' || typ == 'int')
 | ||||
| 	// fields := typ.fields
 | ||||
| 	// get only string and int fields
 | ||||
| 	// mut fields := []Var
 | ||||
| 	info := sym.info as table.Struct | ||||
| 	fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type]) | ||||
| 	/* | ||||
| 	for i, field in info.fields { | ||||
|         if !(field.typ in ['string', 'int', 'bool']) { | ||||
|                 println('orm: skipping $field.name') | ||||
|                 continue | ||||
|         } | ||||
|         if field.attr.contains('skip') { | ||||
|                 continue | ||||
|         } | ||||
|         fields << field | ||||
| } | ||||
| 	*/ | ||||
| 	if fields.len == 0 { | ||||
| 		p.error('V orm: select: empty fields in `$table_name`') | ||||
| 	} | ||||
| 	if fields[0].name != 'id' { | ||||
| 		p.error('V orm: `id int` must be the first field in `$table_name`') | ||||
| 	} | ||||
| 	for field in fields { | ||||
| 		// println('registering sql field var $field.name')
 | ||||
| 		p.scope.register(field.name, ast.Var{ | ||||
| 			name: field.name | ||||
| 			typ: field.typ | ||||
| 			is_mut: true | ||||
| 			is_used: true | ||||
| 			is_changed: true | ||||
| 		}) | ||||
| 	} | ||||
| 	// ////////////
 | ||||
| 	return ast.SqlExpr{ | ||||
| 		is_count: is_count | ||||
| 		typ: typ | ||||
| 		db_var_name: db_var_name | ||||
| 		table_name: table_name | ||||
| 		where_expr: where_expr | ||||
| 		has_where: has_where | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue