orm: add unique fields & add drop table stmt (#9684)

pull/9700/head
Louis Schmieder 2021-04-11 23:57:25 +02:00 committed by GitHub
parent b0b3c51658
commit 67d8639917
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 7 deletions

View File

@ -10,15 +10,14 @@ struct Module {
struct User {
id int [primary; sql: serial]
age int
name string [nonull]
is_customer bool
age int [unique: 'user']
name string [unique]
is_customer bool [unique: 'user']
skipped_string string [skip]
}
fn main() {
db := sqlite.connect(':memory:') or { panic(err) }
db.exec('drop table if exists User')
sql db {
create table Module
}
@ -40,6 +39,10 @@ fn main() {
select from Module where id == 1
}
sql db {
drop table Module
}
eprintln(modul)
mysql()

View File

@ -4,7 +4,9 @@
### Fields
- `[primary]` set the field as the primary key
- `[primary]` sets the field as the primary key
- `[unique]` sets the field as unique
- `[unique: 'foo']` adds the field to a unique group
- `[nonull]` field will be `NOT NULL` in table creation
- `[skip]` field will be skipped
- `[sql: type]` sets the type which is used in sql (special type `serial`)
@ -26,6 +28,14 @@ sql db {
}
```
### Drop
```v ignore
sql db {
drop table Foo
}
```
### Insert
```v ignore

View File

@ -1407,6 +1407,7 @@ pub enum SqlStmtKind {
update
delete
create
drop
}
pub struct SqlStmt {

View File

@ -1237,6 +1237,9 @@ pub fn (mut f Fmt) sql_stmt(node ast.SqlStmt) {
.create {
f.writeln('create table $table_name')
}
.drop {
f.writeln('drop table $table_name')
}
}
f.writeln('}')
}

View File

@ -27,6 +27,9 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
if node.kind == .create {
g.sql_create_table(node)
return
} else if node.kind == .drop {
g.sql_drop_table(node)
return
}
g.sql_table_name = g.table.get_type_symbol(node.table_expr.typ).name
typ := g.parse_db_type(node.db_expr)
@ -58,6 +61,21 @@ fn (mut g Gen) sql_create_table(node ast.SqlStmt) {
}
}
fn (mut g Gen) sql_drop_table(node ast.SqlStmt) {
typ := g.parse_db_type(node.db_expr)
match typ {
.sqlite3 {
g.sqlite3_drop_table(node, typ)
}
.mysql {
g.mysql_drop_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) {
g.sql_table_name = g.table.get_type_symbol(node.table_expr.typ).name
typ := g.parse_db_type(node.db_expr)
@ -300,6 +318,15 @@ fn (mut g Gen) sqlite3_create_table(node ast.SqlStmt, typ SqlType) {
g.writeln(', _SLIT("$create_string"));')
}
fn (mut g Gen) sqlite3_drop_table(node ast.SqlStmt, typ SqlType) {
table_name := util.strip_mod_name(g.table.get_type_symbol(node.table_expr.typ).name)
g.writeln('// sqlite3 table drop')
create_string := 'DROP TABLE $table_name;'
g.write('sqlite__DB_exec(')
g.expr(node.db_expr)
g.writeln(', _SLIT("$create_string"));')
}
fn (mut g Gen) sqlite3_bind(val string, len string, typ ast.Type) {
match g.sqlite3_type_from_v(typ) {
'INTEGER' {
@ -582,7 +609,18 @@ fn (mut g Gen) mysql_create_table(node ast.SqlStmt, typ SqlType) {
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
g.expr(node.db_expr)
g.writeln(', _SLIT("$create_string"));')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; _STR("Something went wrong\\000%.*s", 2, IError_str(err)); }')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
}
fn (mut g Gen) mysql_drop_table(node ast.SqlStmt, typ SqlType) {
table_name := util.strip_mod_name(g.table.get_type_symbol(node.table_expr.typ).name)
g.writeln('// mysql table drop')
create_string := 'DROP TABLE $table_name;'
tmp := g.new_tmp_var()
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
g.expr(node.db_expr)
g.writeln(', _SLIT("$create_string"));')
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
}
fn (mut g Gen) mysql_bind(val string, _ ast.Type) {
@ -794,16 +832,25 @@ fn (mut g Gen) table_gen(node ast.SqlStmt, typ SqlType) string {
mut fields := []string{}
mut primary := '' // for mysql
mut unique := map[string][]string{}
for field in struct_data.fields {
mut is_primary := false
mut no_null := false
mut is_unique := false
for attr in field.attrs {
match attr.name {
'primary' {
is_primary = true
primary = field.name
}
'unique' {
if attr.arg != '' {
unique[attr.arg] << field.name
} else {
is_unique = true
}
}
'nonull' {
no_null = true
}
@ -840,11 +887,23 @@ fn (mut g Gen) table_gen(node ast.SqlStmt, typ SqlType) string {
if no_null {
stmt += ' NOT NULL'
}
if is_unique {
stmt += ' UNIQUE'
}
if is_primary && typ == .sqlite3 {
stmt += ' PRIMARY KEY'
}
fields << stmt
}
if unique.len > 0 {
for k, v in unique {
mut tmp := []string{}
for f in v {
tmp << '`$f`'
}
fields << '/* $k */UNIQUE(${tmp.join(', ')})'
}
}
if typ == .mysql {
fields << 'PRIMARY KEY(`$primary`)'
}
@ -903,7 +962,6 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr, typ SqlType) {
// for left sides just add a string, for right sides, generate the bindings
if g.sql_side == .left {
// println("sql gen left $expr.name")
eprintln(expr.name)
g.sql_left_type = g.get_struct_field_typ(expr.name)
g.write(expr.name)
} else {

View File

@ -146,6 +146,25 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
pos: typ_pos
}
}
} else if n == 'drop' {
kind = .drop
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)