From 5c1e1dcb6aeea1681ab2fc4bd0191d19e90fef5e Mon Sep 17 00:00:00 2001 From: wispem-wantex Date: Sat, 10 Jan 2026 16:06:48 -0800 Subject: [PATCH] generator: add GetAllXyzs() function --- cmd/subcmd_generate_models.go | 1 + pkg/codegen/modelgenerate/generate_model.go | 54 ++++ .../modelgenerate/generate_testfile.go | 277 ++++++++++-------- 3 files changed, 206 insertions(+), 126 deletions(-) diff --git a/cmd/subcmd_generate_models.go b/cmd/subcmd_generate_models.go index 717f98d..9909d0a 100644 --- a/cmd/subcmd_generate_models.go +++ b/cmd/subcmd_generate_models.go @@ -72,6 +72,7 @@ var generate_model = &cobra.Command{ modelgenerate.GenerateSaveItemFunc(table), modelgenerate.GenerateDeleteItemFunc(table), modelgenerate.GenerateGetItemByIDFunc(table), + modelgenerate.GenerateGetAllItemsFunc(table), }, } diff --git a/pkg/codegen/modelgenerate/generate_model.go b/pkg/codegen/modelgenerate/generate_model.go index 2ece8b6..0675304 100644 --- a/pkg/codegen/modelgenerate/generate_model.go +++ b/pkg/codegen/modelgenerate/generate_model.go @@ -9,6 +9,7 @@ import ( "git.offline-twitter.com/offline-labs/gas-stack/pkg/schema" "git.offline-twitter.com/offline-labs/gas-stack/pkg/textutils" + "github.com/jinzhu/inflection" ) func GenerateIDType(table schema.Table) *ast.GenDecl { @@ -233,6 +234,59 @@ func GenerateGetItemByIDFunc(tbl schema.Table) *ast.FuncDecl { return funcDecl } +// GenerateGetAllItemsFunc produces an AST for the `GetAllXyzs()` function. +// E.g., a table with `table.TypeName = "foods"` will produce a "GetAllFoods()" function. +func GenerateGetAllItemsFunc(tbl schema.Table) *ast.FuncDecl { + funcName := "GetAll" + inflection.Plural(tbl.TypeName) + recv := &ast.FieldList{List: []*ast.Field{ + {Names: []*ast.Ident{ast.NewIdent("db")}, Type: ast.NewIdent("DB")}, + }} + result := &ast.FieldList{List: []*ast.Field{ + {Names: []*ast.Ident{ast.NewIdent("ret")}, Type: &ast.ArrayType{Elt: ast.NewIdent(tbl.TypeName)}}, + }} + + selectCall := &ast.CallExpr{ + Fun: ast.NewIdent("PanicIf"), + Args: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: ast.NewIdent("db.DB"), + Sel: ast.NewIdent("Select"), + }, + Args: []ast.Expr{ + &ast.UnaryExpr{Op: token.AND, X: ast.NewIdent("ret")}, + &ast.BinaryExpr{ + X: &ast.BinaryExpr{ + X: &ast.BasicLit{Kind: token.STRING, Value: "`SELECT `"}, + Op: token.ADD, + Y: SQLFieldsConstIdent(tbl), + }, + Op: token.ADD, + Y: &ast.BasicLit{Kind: token.STRING, Value: "` FROM " + tbl.TableName + "`"}, + }, + }, + }, + }, + } + + funcBody := &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{X: selectCall}, + &ast.ReturnStmt{}, + }, + } + + return &ast.FuncDecl{ + Recv: recv, + Name: ast.NewIdent(funcName), + Type: &ast.FuncType{ + Params: &ast.FieldList{}, + Results: result, + }, + Body: funcBody, + } +} + // 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 { diff --git a/pkg/codegen/modelgenerate/generate_testfile.go b/pkg/codegen/modelgenerate/generate_testfile.go index 1a86c59..760022c 100644 --- a/pkg/codegen/modelgenerate/generate_testfile.go +++ b/pkg/codegen/modelgenerate/generate_testfile.go @@ -6,6 +6,7 @@ import ( "go/token" "git.offline-twitter.com/offline-labs/gas-stack/pkg/schema" + "github.com/jinzhu/inflection" ) // GenerateModelTestAST produces an AST for a starter test file for a given model. @@ -87,6 +88,154 @@ func GenerateModelTestAST(tbl schema.Table, gomodName string) *ast.File { description1 := `"an item"` description2 := `"a big item"` + testCreateUpdateDelete := &ast.FuncDecl{ + Name: ast.NewIdent("TestCreateUpdateDelete" + tbl.TypeName), + Type: &ast.FuncType{ + Params: &ast.FieldList{ + List: []*ast.Field{{ + Names: []*ast.Ident{ast.NewIdent("t")}, + Type: ast.NewIdent("*testing.T"), + }}, + }, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + // item := Item{Description: "an item"} + &ast.AssignStmt{ + Lhs: []ast.Expr{testObj}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CompositeLit{ + Type: ast.NewIdent(tbl.TypeName), + Elts: []ast.Expr{ + &ast.KeyValueExpr{ + Key: fieldName, + Value: &ast.BasicLit{Kind: token.STRING, Value: description1}, + }, + }, + }}, + }, + + // TestDB.SaveItem(&item) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("TestDB.Save" + tbl.TypeName), + Args: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: testObj}}, + }}, + + // require.NotZero(t, item.ID) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("require.NotZero"), + Args: []ast.Expr{ast.NewIdent("t"), &ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, + }}, + + // item2 := Must(TestDB.GetItemByID(item.ID)) + &ast.AssignStmt{ + Lhs: []ast.Expr{testObj2}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: ast.NewIdent("Must"), + Args: []ast.Expr{&ast.CallExpr{ + Fun: ast.NewIdent("TestDB.Get" + tbl.TypeName + "ByID"), + Args: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, + }}, + }}, + }, + + // assert.Equal(t, "an item", item2.Description) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("assert.Equal"), + Args: []ast.Expr{ + ast.NewIdent("t"), + &ast.BasicLit{Kind: token.STRING, Value: description1}, + &ast.SelectorExpr{X: testObj2, Sel: fieldName}, + }, + }}, + + // item.Description = "a big item" + &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: fieldName}}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: description2}}, + }, + + // TestDB.SaveItem(&item) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("TestDB.Save" + tbl.TypeName), + Args: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: testObj}}, + }}, + + // item2 = Must(TestDB.GetItemByID(item.ID)) + &ast.AssignStmt{ + Lhs: []ast.Expr{testObj2}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: ast.NewIdent("Must"), + Args: []ast.Expr{&ast.CallExpr{ + Fun: ast.NewIdent("TestDB.Get" + tbl.TypeName + "ByID"), + Args: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, + }}, + }}, + }, + + // assert.Equal(t, item.Description, item2.Description) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("assert.Equal"), + Args: []ast.Expr{ + ast.NewIdent("t"), + &ast.SelectorExpr{X: testObj, Sel: fieldName}, + &ast.SelectorExpr{X: testObj2, Sel: fieldName}, + }, + }}, + + // TestDB.DeleteItem(item) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("TestDB.Delete" + tbl.TypeName), + Args: []ast.Expr{testObj}, + }}, + + // _, err := TestDB.GetItemByID(item.ID) + &ast.AssignStmt{ + Lhs: []ast.Expr{ast.NewIdent("_"), ast.NewIdent("err")}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: ast.NewIdent("TestDB.Get" + tbl.TypeName + "ByID"), + Args: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, + }}, + }, + + // assert.ErrorIs(t, err, db.ErrNotInDB) + &ast.ExprStmt{X: &ast.CallExpr{ + Fun: ast.NewIdent("assert.ErrorIs"), + Args: []ast.Expr{ + ast.NewIdent("t"), + ast.NewIdent("err"), + &ast.SelectorExpr{X: ast.NewIdent("db"), Sel: ast.NewIdent("ErrNotInDB")}, + }, + }}, + }, + }, + } + + testGetAll := &ast.FuncDecl{ + Name: ast.NewIdent("TestGetAll" + inflection.Plural(tbl.TypeName)), + Type: &ast.FuncType{Params: &ast.FieldList{List: []*ast.Field{ + {Names: []*ast.Ident{ast.NewIdent("t")}, Type: &ast.StarExpr{X: ast.NewIdent("testing.T")}}, + }}, Results: nil}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.AssignStmt{ + Lhs: []ast.Expr{ast.NewIdent("_")}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: ast.NewIdent("TestDB"), + Sel: ast.NewIdent("GetAll" + inflection.Plural(tbl.TypeName)), + }, + }}, + }, + }, + }, + } + return &ast.File{ Name: ast.NewIdent(testpackageName), Decls: []ast.Decl{ @@ -120,132 +269,8 @@ func GenerateModelTestAST(tbl schema.Table, gomodName string) *ast.File { // func MakeDB(dbName string) *DB { db := Must(Create(fmt.Sprintf("file:%s?mode=memory&cache=shared", dbName))); return db } makeDBHelperDecl, - &ast.FuncDecl{ - Name: ast.NewIdent("TestCreateUpdateDelete" + tbl.TypeName), - Type: &ast.FuncType{ - Params: &ast.FieldList{ - List: []*ast.Field{{ - Names: []*ast.Ident{ast.NewIdent("t")}, - Type: ast.NewIdent("*testing.T"), - }}, - }, - }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - // item := Item{Description: "an item"} - &ast.AssignStmt{ - Lhs: []ast.Expr{testObj}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CompositeLit{ - Type: ast.NewIdent(tbl.TypeName), - Elts: []ast.Expr{ - &ast.KeyValueExpr{ - Key: fieldName, - Value: &ast.BasicLit{Kind: token.STRING, Value: description1}, - }, - }, - }}, - }, - - // TestDB.SaveItem(&item) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("TestDB.Save" + tbl.TypeName), - Args: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: testObj}}, - }}, - - // require.NotZero(t, item.ID) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("require.NotZero"), - Args: []ast.Expr{ast.NewIdent("t"), &ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, - }}, - - // item2 := Must(TestDB.GetItemByID(item.ID)) - &ast.AssignStmt{ - Lhs: []ast.Expr{testObj2}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: ast.NewIdent("Must"), - Args: []ast.Expr{&ast.CallExpr{ - Fun: ast.NewIdent("TestDB.Get" + tbl.TypeName + "ByID"), - Args: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, - }}, - }}, - }, - - // assert.Equal(t, "an item", item2.Description) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("assert.Equal"), - Args: []ast.Expr{ - ast.NewIdent("t"), - &ast.BasicLit{Kind: token.STRING, Value: description1}, - &ast.SelectorExpr{X: testObj2, Sel: fieldName}, - }, - }}, - - // item.Description = "a big item" - &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: fieldName}}, - Tok: token.ASSIGN, - Rhs: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: description2}}, - }, - - // TestDB.SaveItem(&item) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("TestDB.Save" + tbl.TypeName), - Args: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: testObj}}, - }}, - - // item2 = Must(TestDB.GetItemByID(item.ID)) - &ast.AssignStmt{ - Lhs: []ast.Expr{testObj2}, - Tok: token.ASSIGN, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: ast.NewIdent("Must"), - Args: []ast.Expr{&ast.CallExpr{ - Fun: ast.NewIdent("TestDB.Get" + tbl.TypeName + "ByID"), - Args: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, - }}, - }}, - }, - - // assert.Equal(t, item.Description, item2.Description) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("assert.Equal"), - Args: []ast.Expr{ - ast.NewIdent("t"), - &ast.SelectorExpr{X: testObj, Sel: fieldName}, - &ast.SelectorExpr{X: testObj2, Sel: fieldName}, - }, - }}, - - // TestDB.DeleteItem(item) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("TestDB.Delete" + tbl.TypeName), - Args: []ast.Expr{testObj}, - }}, - - // _, err := TestDB.GetItemByID(item.ID) - &ast.AssignStmt{ - Lhs: []ast.Expr{ast.NewIdent("_"), ast.NewIdent("err")}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: ast.NewIdent("TestDB.Get" + tbl.TypeName + "ByID"), - Args: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, - }}, - }, - - // assert.ErrorIs(t, err, db.ErrNotInDB) - &ast.ExprStmt{X: &ast.CallExpr{ - Fun: ast.NewIdent("assert.ErrorIs"), - Args: []ast.Expr{ - ast.NewIdent("t"), - ast.NewIdent("err"), - &ast.SelectorExpr{X: ast.NewIdent("db"), Sel: ast.NewIdent("ErrNotInDB")}, - }, - }}, - }, - }, - }, + testCreateUpdateDelete, + testGetAll, }, } }