orm: add table creation (#9621)
							parent
							
								
									3a07fbc653
								
							
						
					
					
						commit
						ab03357a6e
					
				|  | @ -10,7 +10,7 @@ struct Module { | |||
| } | ||||
| 
 | ||||
| struct User { | ||||
| 	id             int | ||||
| 	id             int    [primary] | ||||
| 	age            int | ||||
| 	name           string | ||||
| 	is_customer    bool | ||||
|  | @ -24,7 +24,9 @@ struct Foo { | |||
| fn test_orm_sqlite() { | ||||
| 	db := sqlite.connect(':memory:') or { panic(err) } | ||||
| 	db.exec('drop table if exists User') | ||||
| 	db.exec("create table User (id integer primary key, age int default 0, name text default '', is_customer int default 0);") | ||||
| 	sql db { | ||||
| 		create table User | ||||
| 	} | ||||
| 	name := 'Peter' | ||||
| 	db.exec("insert into User (name, age) values ('Sam', 29)") | ||||
| 	db.exec("insert into User (name, age) values ('Peter', 31)") | ||||
|  |  | |||
|  | @ -1410,6 +1410,7 @@ pub enum SqlStmtKind { | |||
| 	insert | ||||
| 	update | ||||
| 	delete | ||||
| 	create | ||||
| } | ||||
| 
 | ||||
| pub struct SqlStmt { | ||||
|  |  | |||
|  | @ -1232,6 +1232,9 @@ pub fn (mut f Fmt) sql_stmt(node ast.SqlStmt) { | |||
| 			f.expr(node.where_expr) | ||||
| 			f.writeln('') | ||||
| 		} | ||||
| 		.create { | ||||
| 			f.writeln('create table $table_name') | ||||
| 		} | ||||
| 	} | ||||
| 	f.writeln('}') | ||||
| } | ||||
|  |  | |||
|  | @ -24,6 +24,10 @@ enum SqlType { | |||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sql_stmt(node ast.SqlStmt) { | ||||
| 	if node.kind == .create { | ||||
| 		g.sql_create_table(node) | ||||
| 		return | ||||
| 	} | ||||
| 	typ := g.parse_db_type(node.db_expr) | ||||
| 	match typ { | ||||
| 		.sqlite3 { | ||||
|  | @ -35,6 +39,18 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sql_create_table(node ast.SqlStmt) { | ||||
| 	typ := g.parse_db_type(node.db_expr) | ||||
| 	match typ { | ||||
| 		.sqlite3 { | ||||
| 			g.sqlite3_create_table(node, typ) | ||||
| 		} | ||||
| 		else { | ||||
| 			verror('This database type `$typ` is not implemented yet in orm') // TODO add better error
 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sql_select_expr(node ast.SqlExpr, sub bool, line string) { | ||||
| 	typ := g.parse_db_type(node.db_expr) | ||||
| 	match typ { | ||||
|  | @ -69,6 +85,18 @@ fn (mut g Gen) sql_bind_string(val string, len string, typ SqlType) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sql_type_from_v(typ SqlType, v_typ ast.Type) string { | ||||
| 	match typ { | ||||
| 		.sqlite3 { | ||||
| 			return g.sqlite3_type_from_v(typ, v_typ) | ||||
| 		} | ||||
| 		else { | ||||
| 			// add error
 | ||||
| 		} | ||||
| 	} | ||||
| 	return '' | ||||
| } | ||||
| 
 | ||||
| // sqlite3
 | ||||
| 
 | ||||
| fn (mut g Gen) sqlite3_stmt(node ast.SqlStmt, typ SqlType) { | ||||
|  | @ -337,6 +365,70 @@ fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_ | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sqlite3_create_table(node ast.SqlStmt, typ SqlType) { | ||||
| 	typ_sym := g.table.get_type_symbol(node.table_expr.typ) | ||||
| 	if typ_sym.info !is ast.Struct { | ||||
| 		verror('Type `$typ_sym.name` has to be a struct') | ||||
| 	} | ||||
| 	g.writeln('// sqlite3 table creator ($typ_sym.name)') | ||||
| 	struct_data := typ_sym.info as ast.Struct | ||||
| 	table_name := typ_sym.name.split('.').last() | ||||
| 	mut create_string := 'CREATE TABLE IF NOT EXISTS `$table_name` (' | ||||
| 
 | ||||
| 	mut fields := []string{} | ||||
| 
 | ||||
| 	outer: for field in struct_data.fields { | ||||
| 		mut is_primary := false | ||||
| 		for attr in field.attrs { | ||||
| 			match attr.name { | ||||
| 				'skip' { | ||||
| 					continue outer | ||||
| 				} | ||||
| 				'primary' { | ||||
| 					is_primary = true | ||||
| 				} | ||||
| 				else {} | ||||
| 			} | ||||
| 		} | ||||
| 		mut stmt := '' | ||||
| 		mut converted_typ := g.sql_type_from_v(typ, field.typ) | ||||
| 		mut name := field.name | ||||
| 		if converted_typ == '' { | ||||
| 			if g.table.get_type_symbol(field.typ).kind == .struct_ { | ||||
| 				converted_typ = g.sql_type_from_v(typ, ast.int_type) | ||||
| 				g.sql_create_table(ast.SqlStmt{ | ||||
| 					db_expr: node.db_expr | ||||
| 					kind: node.kind | ||||
| 					pos: node.pos | ||||
| 					table_expr: ast.TypeNode{ | ||||
| 						typ: field.typ | ||||
| 						pos: node.table_expr.pos | ||||
| 					} | ||||
| 				}) | ||||
| 			} else { | ||||
| 				eprintln(g.table.get_type_symbol(field.typ).kind) | ||||
| 				verror('unknown type ($field.typ)') | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		stmt = '`$name` $converted_typ' | ||||
| 
 | ||||
| 		if field.has_default_expr { | ||||
| 			stmt += ' DEFAULT ' | ||||
| 			stmt += field.default_expr.str() | ||||
| 		} | ||||
| 		if is_primary { | ||||
| 			stmt += ' PRIMARY KEY' | ||||
| 		} | ||||
| 		fields << stmt | ||||
| 	} | ||||
| 	create_string += fields.join(', ') | ||||
| 	create_string += ');' | ||||
| 	g.write('sqlite__DB_exec(') | ||||
| 	g.expr(node.db_expr) | ||||
| 	g.writeln(', _SLIT("$create_string"));') | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sqlite3_bind_int(val string) { | ||||
| 	g.sql_buf.writeln('sqlite3_bind_int($g.sql_stmt_name, $g.sql_i, $val);') | ||||
| } | ||||
|  | @ -345,6 +437,16 @@ fn (mut g Gen) sqlite3_bind_string(val string, len string) { | |||
| 	g.sql_buf.writeln('sqlite3_bind_text($g.sql_stmt_name, $g.sql_i, $val, $len, 0);') | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sqlite3_type_from_v(typ SqlType, v_typ ast.Type) string { | ||||
| 	if v_typ.is_number() || v_typ == ast.bool_type { | ||||
| 		return 'INTEGER' | ||||
| 	} | ||||
| 	if v_typ.is_string() { | ||||
| 		return 'TEXT' | ||||
| 	} | ||||
| 	return '' | ||||
| } | ||||
| 
 | ||||
| // mysql
 | ||||
| 
 | ||||
| fn (mut g Gen) mysql_stmt(node ast.SqlStmt) { | ||||
|  |  | |||
|  | @ -127,6 +127,25 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt { | |||
| 		kind = .delete | ||||
| 	} else if n == 'update' { | ||||
| 		kind = .update | ||||
| 	} else if n == 'create' { | ||||
| 		kind = .create | ||||
| 		table := p.check_name() | ||||
| 		if table != 'table' { | ||||
| 			p.error('expected `table` got `$table`') | ||||
| 			return ast.SqlStmt{} | ||||
| 		} | ||||
| 		typ := p.parse_type() | ||||
| 		typ_pos := p.tok.position() | ||||
| 		p.check(.rcbr) | ||||
| 		return ast.SqlStmt{ | ||||
| 			db_expr: db_expr | ||||
| 			kind: kind | ||||
| 			pos: pos.extend(p.prev_tok.position()) | ||||
| 			table_expr: ast.TypeNode{ | ||||
| 				typ: typ | ||||
| 				pos: typ_pos | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	mut inserted_var_name := '' | ||||
| 	mut table_type := ast.Type(0) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue