codegen: implement "without rowid" tables
This commit is contained in:
parent
c1150954e5
commit
1bc7f9111f
@ -46,7 +46,6 @@ var generate_model = &cobra.Command{
|
||||
Specs: []ast.Spec{
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"database/sql"`}},
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"errors"`}},
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"fmt"`}},
|
||||
&ast.ImportSpec{
|
||||
Name: ast.NewIdent("."),
|
||||
Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.offline-twitter.com/offline-labs/gas-stack/pkg/db"`},
|
||||
@ -69,8 +68,16 @@ var generate_model = &cobra.Command{
|
||||
modelgenerate.GenerateSQLFieldsConst(table),
|
||||
modelgenerate.GenerateSaveItemFunc(table),
|
||||
modelgenerate.GenerateDeleteItemFunc(table),
|
||||
modelgenerate.GenerateGetItemByIDFunc(table),
|
||||
)
|
||||
if table.IsWithoutRowid {
|
||||
decls = append(decls,
|
||||
modelgenerate.GenerateGetItemBy(table, table.PrimaryKeyColumns()),
|
||||
)
|
||||
} else {
|
||||
decls = append(decls,
|
||||
modelgenerate.GenerateGetItemByIDFunc(table),
|
||||
)
|
||||
}
|
||||
for _, index := range schema.Indexes {
|
||||
if index.TableName != table.TableName {
|
||||
// Skip indexes on other tables
|
||||
|
||||
@ -46,11 +46,19 @@ create table items (
|
||||
created_at integer not null,
|
||||
updated_at integer not null
|
||||
) strict;
|
||||
|
||||
create table item_to_item (
|
||||
item1_id integer references items(rowid),
|
||||
item2_id integer references items(rowid),
|
||||
primary key (item1_id, item2_id)
|
||||
) strict, without rowid;
|
||||
|
||||
EOF
|
||||
|
||||
# Generate an item model and test file
|
||||
$gas generate items > pkg/db/item.go
|
||||
$gas generate items --test > pkg/db/item_test.go
|
||||
$gas generate item_to_item > pkg/db/item_to_item.go
|
||||
go mod tidy
|
||||
|
||||
# Run the tests
|
||||
|
||||
@ -54,6 +54,22 @@ func GoTypeForColumn(c schema.Column) ast.Expr {
|
||||
}
|
||||
}
|
||||
|
||||
func PanicIfRowsAffected(tbl schema.Table) *ast.IfStmt {
|
||||
return &ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: mustCall(&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: ast.NewIdent("result"), Sel: ast.NewIdent("RowsAffected")},
|
||||
Args: []ast.Expr{},
|
||||
}),
|
||||
Op: token.NEQ,
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "1"},
|
||||
},
|
||||
Body: &ast.BlockStmt{List: []ast.Stmt{
|
||||
&ast.ExprStmt{X: &ast.CallExpr{Fun: ast.NewIdent("panic"), Args: []ast.Expr{ast.NewIdent(tbl.VarName)}}},
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// Generators
|
||||
// ---------------
|
||||
@ -255,10 +271,29 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
if col.Name == "created_at" && hasCreatedAt {
|
||||
continue
|
||||
}
|
||||
updatePairs = append(updatePairs, col.Name+"="+val)
|
||||
if !col.IsPrimaryKey { // Don't try to update primary key columns (mainly for w/o rowid tables)
|
||||
updatePairs = append(updatePairs, col.Name+"="+val)
|
||||
}
|
||||
}
|
||||
insertStmt := fmt.Sprintf("\n\t\t insert into %s (%s)\n\t\t values (%s)\n\t\t",
|
||||
tbl.TableName,
|
||||
strings.Join(insertCols, ", "),
|
||||
strings.Join(insertVals, ", "),
|
||||
)
|
||||
updateStmt := fmt.Sprintf("\n\t\t update %s\n\t\t set %s\n\t\t where rowid = :rowid\n\t\t",
|
||||
tbl.TableName,
|
||||
strings.Join(updatePairs, ",\n\t\t "),
|
||||
)
|
||||
upsertStmt := fmt.Sprintf("\n\t insert into %s (%s)\n\t values (%s)\n\t",
|
||||
tbl.TableName,
|
||||
strings.Join(insertCols, ", "),
|
||||
strings.Join(insertVals, ", "),
|
||||
)
|
||||
if len(updatePairs) == 0 {
|
||||
upsertStmt = upsertStmt + " on conflict do nothing\n\t"
|
||||
} else {
|
||||
upsertStmt = upsertStmt + fmt.Sprintf(" on conflict do update\n\t set %s\n\t", strings.Join(updatePairs, ",\n\t "))
|
||||
}
|
||||
insertStmt := fmt.Sprintf("\n\t\t insert into %s (%s)\n\t\t values (%s)\n\t\t", tbl.TableName, strings.Join(insertCols, ", "), strings.Join(insertVals, ", "))
|
||||
updateStmt := fmt.Sprintf("\n\t\t update %s\n\t\t set %s\n\t\t where rowid = :rowid\n\t\t", tbl.TableName, strings.Join(updatePairs, ",\n\t\t "))
|
||||
|
||||
checkForeignKeyFailuresAssignment, hasFks := buildFKCheckLambda(tbl)
|
||||
|
||||
@ -276,139 +311,132 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
Rhs: []ast.Expr{&ast.CallExpr{Fun: ast.NewIdent("TimestampNow"), Args: []ast.Expr{}}},
|
||||
})
|
||||
}
|
||||
// if item.ID == 0 {...} else {...}
|
||||
ret = append(ret, &ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: &ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")},
|
||||
Op: token.EQL,
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "0"},
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
// Do create
|
||||
List: append(
|
||||
func() []ast.Stmt {
|
||||
ret1 := []ast.Stmt{Comment("Do create")}
|
||||
if hasCreatedAt {
|
||||
// Auto-timestamps: created_at
|
||||
ret1 = append(ret1, &ast.AssignStmt{
|
||||
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("CreatedAt")}},
|
||||
Tok: token.ASSIGN,
|
||||
Rhs: []ast.Expr{&ast.CallExpr{Fun: ast.NewIdent("TimestampNow"), Args: []ast.Expr{}}},
|
||||
})
|
||||
}
|
||||
namedExecStmt := &ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: dbDB, Sel: ast.NewIdent("NamedExec")},
|
||||
Args: []ast.Expr{
|
||||
&ast.BasicLit{Kind: token.STRING, Value: "`" + insertStmt + "`"},
|
||||
ast.NewIdent(tbl.VarName),
|
||||
},
|
||||
}
|
||||
if !hasFks {
|
||||
// No foreign key checking needed; just use `Must` for brevity
|
||||
return append(ret1, &ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ast.NewIdent("result")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{mustCall(namedExecStmt)},
|
||||
})
|
||||
}
|
||||
|
||||
return append(ret1,
|
||||
// result, err := db.DB.NamedExec(`...`, u)
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{
|
||||
ast.NewIdent("result"),
|
||||
ast.NewIdent("err"),
|
||||
},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{namedExecStmt},
|
||||
},
|
||||
|
||||
// if fkErr := checkForeignKeyFailures(err); fkErr != nil { return fkErr } else if err != nil { panic(err) }
|
||||
&ast.IfStmt{
|
||||
Init: &ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ast.NewIdent("fkErr")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{
|
||||
&ast.CallExpr{
|
||||
Fun: ast.NewIdent("checkForeignKeyFailures"),
|
||||
Args: []ast.Expr{ast.NewIdent("err")},
|
||||
},
|
||||
},
|
||||
},
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: ast.NewIdent("fkErr"),
|
||||
Op: token.NEQ,
|
||||
Y: ast.NewIdent("nil"),
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
List: []ast.Stmt{
|
||||
&ast.ReturnStmt{
|
||||
Results: []ast.Expr{ast.NewIdent("fkErr")},
|
||||
},
|
||||
},
|
||||
},
|
||||
Else: func() *ast.IfStmt {
|
||||
panicStmt := &ast.ExprStmt{
|
||||
X: &ast.CallExpr{
|
||||
Fun: ast.NewIdent("panic"),
|
||||
Args: []ast.Expr{ast.NewIdent("err")},
|
||||
},
|
||||
}
|
||||
TrailingComments[panicStmt] = "not a foreign key error"
|
||||
return &ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: ast.NewIdent("err"),
|
||||
Op: token.NEQ,
|
||||
Y: ast.NewIdent("nil"),
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
List: []ast.Stmt{panicStmt},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
},
|
||||
)
|
||||
}(),
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")}},
|
||||
Tok: token.ASSIGN,
|
||||
Rhs: []ast.Expr{&ast.CallExpr{
|
||||
Fun: ast.NewIdent(tbl.TypeIDName),
|
||||
Args: []ast.Expr{mustCall(&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: ast.NewIdent("result"), Sel: ast.NewIdent("LastInsertId")},
|
||||
Args: []ast.Expr{},
|
||||
})},
|
||||
}},
|
||||
},
|
||||
),
|
||||
},
|
||||
Else: &ast.BlockStmt{
|
||||
// Do update
|
||||
List: []ast.Stmt{
|
||||
Comment("Do update"),
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ast.NewIdent("result")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{mustCall(&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: dbDB, Sel: ast.NewIdent("NamedExec")},
|
||||
Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: "`" + updateStmt + "`"}, ast.NewIdent(tbl.VarName)},
|
||||
})},
|
||||
},
|
||||
|
||||
&ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: mustCall(&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: ast.NewIdent("result"), Sel: ast.NewIdent("RowsAffected")},
|
||||
Args: []ast.Expr{},
|
||||
}),
|
||||
Op: token.NEQ,
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "1"},
|
||||
},
|
||||
Body: &ast.BlockStmt{List: []ast.Stmt{&ast.ExprStmt{X: &ast.CallExpr{Fun: ast.NewIdent("panic"), Args: []ast.Expr{&ast.CallExpr{Fun: fmtErrorf, Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("\"got %s with ID (%%d), so attempted update, but it doesn't exist\"", strings.ToLower(tbl.GoTypeName))}, &ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")}}}}}}}},
|
||||
},
|
||||
namedExecStmt := func(stmt string) []ast.Stmt {
|
||||
queryStmt := &ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: dbDB, Sel: ast.NewIdent("NamedExec")},
|
||||
Args: []ast.Expr{
|
||||
&ast.BasicLit{Kind: token.STRING, Value: "`" + stmt + "`"},
|
||||
ast.NewIdent(tbl.VarName),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if !hasFks {
|
||||
// No foreign key checking needed; just use `Must` for brevity
|
||||
return []ast.Stmt{&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ast.NewIdent("result")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{mustCall(queryStmt)},
|
||||
}}
|
||||
}
|
||||
// There's foreign keys
|
||||
return []ast.Stmt{
|
||||
// result, err := db.DB.NamedExec(`...`, u)
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{
|
||||
ast.NewIdent("result"),
|
||||
ast.NewIdent("err"),
|
||||
},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{queryStmt},
|
||||
},
|
||||
// if fkErr := checkForeignKeyFailures(err); fkErr != nil { return fkErr } else if err != nil { panic(err) }
|
||||
&ast.IfStmt{
|
||||
Init: &ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ast.NewIdent("fkErr")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{
|
||||
&ast.CallExpr{
|
||||
Fun: ast.NewIdent("checkForeignKeyFailures"),
|
||||
Args: []ast.Expr{ast.NewIdent("err")},
|
||||
},
|
||||
},
|
||||
},
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: ast.NewIdent("fkErr"),
|
||||
Op: token.NEQ,
|
||||
Y: ast.NewIdent("nil"),
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
List: []ast.Stmt{
|
||||
&ast.ReturnStmt{
|
||||
Results: []ast.Expr{ast.NewIdent("fkErr")},
|
||||
},
|
||||
},
|
||||
},
|
||||
Else: func() *ast.IfStmt {
|
||||
panicStmt := &ast.ExprStmt{
|
||||
X: &ast.CallExpr{
|
||||
Fun: ast.NewIdent("panic"),
|
||||
Args: []ast.Expr{ast.NewIdent("err")},
|
||||
},
|
||||
}
|
||||
TrailingComments[panicStmt] = "not a foreign key error"
|
||||
return &ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: ast.NewIdent("err"),
|
||||
Op: token.NEQ,
|
||||
Y: ast.NewIdent("nil"),
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
List: []ast.Stmt{panicStmt},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if tbl.IsWithoutRowid {
|
||||
ret = append(ret, namedExecStmt(upsertStmt)...)
|
||||
ret = append(ret, PanicIfRowsAffected(tbl))
|
||||
} else {
|
||||
// if item.ID == 0 {...} else {...}
|
||||
ret = append(ret, &ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: &ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")},
|
||||
Op: token.EQL,
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "0"},
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
// Do create
|
||||
List: append(
|
||||
func() []ast.Stmt {
|
||||
ret1 := []ast.Stmt{Comment("Do create")}
|
||||
if hasCreatedAt {
|
||||
// Auto-timestamps: created_at
|
||||
ret1 = append(ret1, &ast.AssignStmt{
|
||||
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("CreatedAt")}},
|
||||
Tok: token.ASSIGN,
|
||||
Rhs: []ast.Expr{&ast.CallExpr{Fun: ast.NewIdent("TimestampNow"), Args: []ast.Expr{}}},
|
||||
})
|
||||
}
|
||||
return append(ret1, namedExecStmt(insertStmt)...)
|
||||
}(),
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")}},
|
||||
Tok: token.ASSIGN,
|
||||
Rhs: []ast.Expr{&ast.CallExpr{
|
||||
Fun: ast.NewIdent(tbl.TypeIDName),
|
||||
Args: []ast.Expr{mustCall(&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: ast.NewIdent("result"), Sel: ast.NewIdent("LastInsertId")},
|
||||
Args: []ast.Expr{},
|
||||
})},
|
||||
}},
|
||||
},
|
||||
),
|
||||
},
|
||||
Else: &ast.BlockStmt{
|
||||
// Do update
|
||||
List: append(
|
||||
[]ast.Stmt{Comment("Do update")},
|
||||
append(
|
||||
namedExecStmt(updateStmt),
|
||||
PanicIfRowsAffected(tbl),
|
||||
)...,
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
if hasFks {
|
||||
// If there's foreign key checking, it needs to return an error (or nil)
|
||||
ret = append(ret, &ast.ReturnStmt{Results: []ast.Expr{ast.NewIdent("nil")}})
|
||||
@ -442,6 +470,61 @@ func getByIDFuncName(tblname string) string {
|
||||
return "Get" + schema.TypenameFromTablename(tblname) + "ByID"
|
||||
}
|
||||
|
||||
func GenerateGetItemBy(tbl schema.Table, cols []schema.Column) *ast.FuncDecl {
|
||||
colNames := []string{}
|
||||
funcNameSuffix := []string{}
|
||||
funcParams := &ast.FieldList{List: []*ast.Field{}}
|
||||
sqlParams := []ast.Expr{}
|
||||
for _, col := range cols {
|
||||
funcParam := ast.NewIdent(col.LongGoVarName())
|
||||
funcParams.List = append(funcParams.List, &ast.Field{Names: []*ast.Ident{funcParam}, Type: GoTypeForColumn(col)})
|
||||
colNames = append(colNames, fmt.Sprintf("%s = :%s", col.Name, col.Name))
|
||||
funcNameSuffix = append(funcNameSuffix, col.GoFieldName())
|
||||
sqlParams = append(sqlParams, funcParam)
|
||||
}
|
||||
|
||||
selectExpr := &ast.BinaryExpr{
|
||||
X: &ast.BinaryExpr{
|
||||
X: &ast.BasicLit{Kind: token.STRING, Value: "`\n\t select `"},
|
||||
Op: token.ADD,
|
||||
Y: SQLFieldsConstIdent(tbl),
|
||||
},
|
||||
Op: token.ADD,
|
||||
Y: &ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("`\n\t from %s\n\t where %s = ?\n\t`", tbl.TableName, strings.Join(colNames, " and "))},
|
||||
}
|
||||
|
||||
return &ast.FuncDecl{
|
||||
Recv: dbRecv,
|
||||
Name: ast.NewIdent(fmt.Sprintf("Get%sBy%s", schema.TypenameFromTablename(tbl.TableName), strings.Join(funcNameSuffix, "And"))),
|
||||
Type: &ast.FuncType{
|
||||
Params: funcParams,
|
||||
Results: &ast.FieldList{List: []*ast.Field{
|
||||
{Names: []*ast.Ident{ast.NewIdent("ret")}, Type: ast.NewIdent(tbl.GoTypeName)},
|
||||
{Names: []*ast.Ident{ast.NewIdent("err")}, Type: ast.NewIdent("error")},
|
||||
}},
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
List: []ast.Stmt{
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ast.NewIdent("err")},
|
||||
Tok: token.ASSIGN,
|
||||
Rhs: []ast.Expr{&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: dbDB, Sel: ast.NewIdent("Get")},
|
||||
Args: append([]ast.Expr{&ast.UnaryExpr{Op: token.AND, X: ast.NewIdent("ret")}, selectExpr}, sqlParams...),
|
||||
}},
|
||||
},
|
||||
&ast.IfStmt{
|
||||
Cond: &ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: ast.NewIdent("errors"), Sel: ast.NewIdent("Is")},
|
||||
Args: []ast.Expr{ast.NewIdent("err"), &ast.SelectorExpr{X: ast.NewIdent("sql"), Sel: ast.NewIdent("ErrNoRows")}}},
|
||||
Body: &ast.BlockStmt{List: []ast.Stmt{&ast.ReturnStmt{Results: []ast.Expr{&ast.CompositeLit{Type: ast.NewIdent(tbl.GoTypeName)}, ast.NewIdent("ErrNotInDB")}}}},
|
||||
},
|
||||
&ast.ReturnStmt{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateGetItemByIDFunc produces an AST for the `GetXyzByID()` function.
|
||||
// E.g., a table with `table.TypeName = "foods"` will produce a "GetFoodByID()" function.
|
||||
func GenerateGetItemByIDFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
@ -474,13 +557,12 @@ func GenerateGetItemByIDFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
},
|
||||
}
|
||||
|
||||
funcDecl := &ast.FuncDecl{
|
||||
return &ast.FuncDecl{
|
||||
Recv: dbRecv,
|
||||
Name: ast.NewIdent(getByIDFuncName(tbl.TableName)),
|
||||
Type: &ast.FuncType{Params: arg, Results: result},
|
||||
Body: funcBody,
|
||||
}
|
||||
return funcDecl
|
||||
}
|
||||
|
||||
// GenerateGetItemByUniqColFunc produces an AST for the `GetXyzByID()` function.
|
||||
@ -581,10 +663,12 @@ func GenerateGetAllItemsFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
// GenerateDeleteItemFunc produces an AST for the `DeleteXyz()` function.
|
||||
// E.g., a table with `table.TypeName = "foods"` will produce a "DeleteFood()" function.
|
||||
func GenerateDeleteItemFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
arg := &ast.FieldList{List: []*ast.Field{{
|
||||
Names: []*ast.Ident{ast.NewIdent(tbl.VarName)},
|
||||
Type: ast.NewIdent(tbl.GoTypeName),
|
||||
}}}
|
||||
colNames := []string{}
|
||||
for _, c := range tbl.PrimaryKeyColumns() {
|
||||
colNames = append(colNames, fmt.Sprintf("%s = :%s", c.Name, c.Name))
|
||||
}
|
||||
|
||||
sqlStr := "`delete from " + tbl.TableName + fmt.Sprintf(" where %s`", strings.Join(colNames, " and "))
|
||||
|
||||
funcBody := &ast.BlockStmt{
|
||||
List: []ast.Stmt{
|
||||
@ -592,41 +676,24 @@ func GenerateDeleteItemFunc(tbl schema.Table) *ast.FuncDecl {
|
||||
Lhs: []ast.Expr{ast.NewIdent("result")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{mustCall(&ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{X: dbDB, Sel: ast.NewIdent("Exec")},
|
||||
Fun: &ast.SelectorExpr{X: dbDB, Sel: ast.NewIdent("NamedExec")},
|
||||
Args: []ast.Expr{
|
||||
&ast.BasicLit{Kind: token.STRING, Value: "`delete from " + tbl.TableName + " where rowid = ?`"},
|
||||
&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")},
|
||||
&ast.BasicLit{Kind: token.STRING, Value: sqlStr},
|
||||
ast.NewIdent(tbl.VarName),
|
||||
},
|
||||
})},
|
||||
},
|
||||
&ast.IfStmt{
|
||||
Cond: &ast.BinaryExpr{
|
||||
X: mustCall(
|
||||
&ast.CallExpr{Fun: &ast.SelectorExpr{X: ast.NewIdent("result"), Sel: ast.NewIdent("RowsAffected")}, Args: []ast.Expr{}},
|
||||
),
|
||||
Op: token.NEQ,
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "1"},
|
||||
},
|
||||
Body: &ast.BlockStmt{List: []ast.Stmt{
|
||||
&ast.ExprStmt{X: &ast.CallExpr{
|
||||
Fun: ast.NewIdent("panic"),
|
||||
Args: []ast.Expr{&ast.CallExpr{
|
||||
Fun: fmtErrorf,
|
||||
Args: []ast.Expr{
|
||||
&ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("\"tried to delete %s with ID (%%d) but it doesn't exist\"", strings.ToLower(tbl.GoTypeName))},
|
||||
&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
PanicIfRowsAffected(tbl),
|
||||
},
|
||||
}
|
||||
|
||||
funcDecl := &ast.FuncDecl{
|
||||
Recv: dbRecv,
|
||||
Name: ast.NewIdent("Delete" + tbl.GoTypeName),
|
||||
Type: &ast.FuncType{Params: arg, Results: nil},
|
||||
Type: &ast.FuncType{Params: &ast.FieldList{List: []*ast.Field{{
|
||||
Names: []*ast.Ident{ast.NewIdent(tbl.VarName)},
|
||||
Type: ast.NewIdent(tbl.GoTypeName),
|
||||
}}}, Results: nil},
|
||||
Body: funcBody,
|
||||
}
|
||||
return funcDecl
|
||||
|
||||
@ -52,7 +52,12 @@ func (c Column) GoVarName() string {
|
||||
return strings.ToLower(c.ForeignKeyTargetTable)[0:1] + "ID"
|
||||
}
|
||||
|
||||
// Otherwise, just lowercase the field name
|
||||
// Otherwise, just use the whole name
|
||||
return c.LongGoVarName()
|
||||
}
|
||||
|
||||
// LongGoVarName returns a lowercased version of the field name (Pascal => Camel).
|
||||
func (c Column) LongGoVarName() string {
|
||||
fieldname := c.GoFieldName()
|
||||
return strings.ToLower(fieldname)[0:1] + fieldname[1:]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user