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

View File

@ -4,7 +4,9 @@
### Fields ### 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 - `[nonull]` field will be `NOT NULL` in table creation
- `[skip]` field will be skipped - `[skip]` field will be skipped
- `[sql: type]` sets the type which is used in sql (special type `serial`) - `[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 ### Insert
```v ignore ```v ignore

View File

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

View File

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

View File

@ -27,6 +27,9 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
if node.kind == .create { if node.kind == .create {
g.sql_create_table(node) g.sql_create_table(node)
return 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 g.sql_table_name = g.table.get_type_symbol(node.table_expr.typ).name
typ := g.parse_db_type(node.db_expr) 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) { 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 g.sql_table_name = g.table.get_type_symbol(node.table_expr.typ).name
typ := g.parse_db_type(node.db_expr) 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"));') 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) { fn (mut g Gen) sqlite3_bind(val string, len string, typ ast.Type) {
match g.sqlite3_type_from_v(typ) { match g.sqlite3_type_from_v(typ) {
'INTEGER' { '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.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
g.expr(node.db_expr) g.expr(node.db_expr)
g.writeln(', _SLIT("$create_string"));') 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) { 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 fields := []string{}
mut primary := '' // for mysql mut primary := '' // for mysql
mut unique := map[string][]string{}
for field in struct_data.fields { for field in struct_data.fields {
mut is_primary := false mut is_primary := false
mut no_null := false mut no_null := false
mut is_unique := false
for attr in field.attrs { for attr in field.attrs {
match attr.name { match attr.name {
'primary' { 'primary' {
is_primary = true is_primary = true
primary = field.name primary = field.name
} }
'unique' {
if attr.arg != '' {
unique[attr.arg] << field.name
} else {
is_unique = true
}
}
'nonull' { 'nonull' {
no_null = true no_null = true
} }
@ -840,11 +887,23 @@ fn (mut g Gen) table_gen(node ast.SqlStmt, typ SqlType) string {
if no_null { if no_null {
stmt += ' NOT NULL' stmt += ' NOT NULL'
} }
if is_unique {
stmt += ' UNIQUE'
}
if is_primary && typ == .sqlite3 { if is_primary && typ == .sqlite3 {
stmt += ' PRIMARY KEY' stmt += ' PRIMARY KEY'
} }
fields << stmt 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 { if typ == .mysql {
fields << 'PRIMARY KEY(`$primary`)' 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 // for left sides just add a string, for right sides, generate the bindings
if g.sql_side == .left { if g.sql_side == .left {
// println("sql gen left $expr.name") // println("sql gen left $expr.name")
eprintln(expr.name)
g.sql_left_type = g.get_struct_field_typ(expr.name) g.sql_left_type = g.get_struct_field_typ(expr.name)
g.write(expr.name) g.write(expr.name)
} else { } else {

View File

@ -146,6 +146,25 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
pos: typ_pos 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 inserted_var_name := ''
mut table_type := ast.Type(0) mut table_type := ast.Type(0)