16 Commits

Author SHA1 Message Date
8e7b0ab472 feat: search 2025-03-15 18:43:43 +07:00
b26de27165 fix: create method 2025-03-12 16:20:10 +07:00
50edeb07ca fix: readme 2025-03-12 16:15:37 +07:00
31c5c49589 fix: sorting method generation 2025-03-12 16:08:36 +07:00
51d8531792 upd: README.md 2025-03-12 16:01:53 +07:00
da19da2d63 update: README.md 2025-03-12 15:58:34 +07:00
e1012c234c feat: sorting 2025-03-12 15:57:30 +07:00
43c4fe36c0 upd: README 2025-03-12 13:42:21 +07:00
a51a2e063d fix: imports weren't added 2025-03-12 13:41:51 +07:00
ec87f02976 upd: README 2025-03-12 13:14:14 +07:00
c141b2a941 upd: README 2025-03-12 12:47:25 +07:00
6e9f5dd1eb feat: README 2025-03-12 12:46:02 +07:00
4a5ecc647d Merge pull request 'upd: template, imports' (#2) from dst into main
Reviewed-on: #2
2025-03-12 12:28:10 +07:00
be5e8b6140 upd: template, imports 2025-03-12 12:26:07 +07:00
c1b1d2d5f1 delete swap file 2025-02-16 21:50:49 +07:00
17047d2c71 feat: license 2025-02-16 21:50:23 +07:00
8 changed files with 231 additions and 74 deletions

21
LICENSE.md Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Georgiy Derbenev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

13
README.md Normal file
View File

@@ -0,0 +1,13 @@
# Crudgen
> Generate crud's at speed of thought
## Install
```shell
go install git.gogacoder.ru/NTO/crudgen/cmd/crudgen@v1.0.15
```
## Run
Specify path to internal directory
```shell
crudgen -p internal
```

View File

@@ -4,30 +4,66 @@ import (
"flag" "flag"
"git.gogacoder.ru/NTO/crudgen/internal" "git.gogacoder.ru/NTO/crudgen/internal"
"log" "log"
"os/exec"
"path/filepath" "path/filepath"
"strings"
) )
func ImplementServices(mainPkgDir string, reimplement bool) { func ImplementServices(mainPkgDir string, reimplement bool) (modified bool) {
modelsNames, err := internal.GetStructNames(filepath.Join(mainPkgDir, "models")) modelsNames, err := internal.GetStructNames(filepath.Join(mainPkgDir, "models"))
if err != nil { if err != nil {
log.Printf("Error: %s\n", err) log.Printf("Error: %s\n", err)
return return
} }
var wasModified bool
log.Printf("Found models: %v\n", modelsNames) log.Printf("Found models: %v\n", modelsNames)
for _, modelName := range modelsNames { for _, modelName := range modelsNames {
err := internal.ImplementService(mainPkgDir, modelName, reimplement) codeModified, err := internal.ImplementService(mainPkgDir, modelName, reimplement)
if codeModified {
wasModified = true
}
if err != nil { if err != nil {
log.Printf("Error implement service for model %s: %s\n", modelName, err) log.Printf("Error implement service for model %s: %s\n", modelName, err)
} }
} }
return wasModified
}
func runPostHook(postHook *string, wasModified bool) {
if wasModified && postHook != nil && *postHook != "" {
log.Printf("Running post hook %s\n", *postHook)
args := strings.Fields(*postHook)
var cmd *exec.Cmd
if len(args) == 0 {
log.Printf("Empty post hook %s\n", *postHook)
return
}
if len(args) == 1 {
cmd = exec.Command(args[0])
} else {
cmd = exec.Command(args[0], args[1:]...)
}
output, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("Error running post hook for %s: %s\n", *postHook, err)
} else {
log.Printf("Post hook output: %s\n", string(output))
}
}
} }
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
projectPath := flag.String("p", ".", "project path") projectPath := flag.String("p", ".", "project path")
reimplement := flag.Bool("f", false, "pass -f to allow tool to overwrite exist functions and service structure") reimplement := flag.Bool("f", false, "pass -f to allow tool to overwrite exist functions and service structure")
postHook := flag.String("h", "", "post hook to run command after code modifications")
flag.Parse() flag.Parse()
ImplementServices(*projectPath, *reimplement) wasModified := ImplementServices(*projectPath, *reimplement)
runPostHook(postHook, wasModified)
} }

11
go.mod
View File

@@ -1,12 +1,13 @@
module git.gogacoder.ru/NTO/crudgen module git.gogacoder.ru/NTO/crudgen
go 1.22.12 go 1.23.0
toolchain go1.24.1
require github.com/dave/dst v0.27.3 require github.com/dave/dst v0.27.3
require ( require (
golang.org/x/mod v0.23.0 // indirect golang.org/x/mod v0.24.0 // indirect
golang.org/x/sync v0.11.0 // indirect golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.12.0 // indirect golang.org/x/tools v0.31.0 // indirect
golang.org/x/tools v0.13.0 // indirect
) )

16
go.sum
View File

@@ -6,13 +6,9 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=

View File

@@ -1,7 +1,12 @@
package internal package internal
const CreateRawTemplate = `func (service *{{.ServiceName}}) Create(item {{.EntityType}}) ({{.EntityType}}, error) { const CreateRawTemplate = `func (service *{{.ServiceName}}) Create(item {{.EntityType}}) ({{.EntityType}}, error) {
err := dal.{{.EntityType}}.Preload(field.Associations).Create(&item) utils.ReplaceEmptySlicesWithNil(&item)
err := dal.{{.EntityType}}.Create(&item)
if err != nil {
return item, err
}
err = utils.AppendAssociations(database.GetInstance(), &item)
return item, err return item, err
}` }`
@@ -24,16 +29,38 @@ const GetByIdRawTemplate = `func (service *{{.ServiceName}}) GetById(id uint) (*
}` }`
const UpdateRawTemplate = `func (service *{{.ServiceName}}) Update(item {{.EntityType}}) ({{.EntityType}}, error) { const UpdateRawTemplate = `func (service *{{.ServiceName}}) Update(item {{.EntityType}}) ({{.EntityType}}, error) {
err := dal.{{.EntityType}}.Preload(field.Associations).Save(&item) utils.ReplaceEmptySlicesWithNil(&item)
_, err := dal.Author.Updates(&item)
if err != nil {
return item, err
}
err = utils.UpdateAssociations(database.GetInstance(), &item)
if err != nil {
return item, err
}
return item, err return item, err
}` }`
const DeleteRawTemplate = `func (service *{{.ServiceName}}) Delete(item {{.EntityType}}) ({{.EntityType}}, error) { const DeleteRawTemplate = `func (service *{{.ServiceName}}) Delete(id uint) error {
_, err := dal.{{.EntityType}}.Unscoped().Preload(field.Associations).Delete(&item) _, err := dal.{{.EntityType}}.Unscoped().Where(dal.{{.EntityType}}.Id.Eq(id)).Delete()
return item, err return err
}` }`
const CountRawTemplate = `func (service *{{.ServiceName}}) Count() (int64, error) { const CountRawTemplate = `func (service *{{.ServiceName}}) Count() (int64, error) {
amount, err := dal.{{.EntityType}}.Count() amount, err := dal.{{.EntityType}}.Count()
return amount, err return amount, err
}` }`
const SortedByOrderTemplate = `func (service *{{.ServiceName}}) SortedByOrder(fieldsSortingOrder []utils.SortField) ([]*{{.EntityType}}, error) {
return utils.SortByOrder(fieldsSortingOrder, {{.EntityType}}{})
}`
const SearchByAllStringFields = `func (service *{{.ServiceName}}) SearchByAllTextFields(phrase string) ([]*{{.EntityType}}, error) {
return utils.FindPhraseByStringFields[{{.EntityType}}](phrase, {{.EntityType}}{})
}`
var implementedMethods = []string{CreateMethod, GetAllMethod, GetByIdMethod, UpdateMethod, DeleteMethod, CountMethod, SortedByOrderMethod, SearchByAllStringFields}

View File

@@ -8,7 +8,9 @@ type CrudTemplatesContext struct {
var ServiceImports = []string{ var ServiceImports = []string{
"app/internal/dal", "app/internal/dal",
"app/internal/database",
"app/internal/models", "app/internal/models",
"app/internal/utils",
"errors", "errors",
"gorm.io/gen/field", "gorm.io/gen/field",
"gorm.io/gorm", "gorm.io/gorm",
@@ -20,12 +22,15 @@ const GetByIdMethod = "GetById"
const UpdateMethod = "Update" const UpdateMethod = "Update"
const DeleteMethod = "Delete" const DeleteMethod = "Delete"
const CountMethod = "Count" const CountMethod = "Count"
const SortedByOrderMethod = "SortedByOrder"
var RawTemplates = map[string]string{ var RawTemplates = map[string]string{
CreateMethod: CreateRawTemplate, CreateMethod: CreateRawTemplate,
GetAllMethod: GetAllRawTemplate, GetAllMethod: GetAllRawTemplate,
GetByIdMethod: GetByIdRawTemplate, GetByIdMethod: GetByIdRawTemplate,
UpdateMethod: UpdateRawTemplate, UpdateMethod: UpdateRawTemplate,
DeleteMethod: DeleteRawTemplate, DeleteMethod: DeleteRawTemplate,
CountMethod: CountRawTemplate, CountMethod: CountRawTemplate,
SortedByOrderMethod: SortedByOrderTemplate,
SearchByAllStringFields: SearchByAllStringFields,
} }

View File

@@ -16,11 +16,13 @@ import (
"github.com/dave/dst/decorator" "github.com/dave/dst/decorator"
) )
func ImplementServiceStruct(modelName string, file *dst.File, reimplement bool) { func ImplementServiceStruct(modelName string, file *dst.File, reimplement bool) (wasModified bool) {
serviceName := modelName + "Service" serviceName := modelName + "Service"
isServiceStructDefined := false var (
var insertPos int isServiceStructDefined bool
var decls []dst.Decl insertPos int
decls []dst.Decl
)
for i, decl := range file.Decls { for i, decl := range file.Decls {
genDecl, ok := decl.(*dst.GenDecl) genDecl, ok := decl.(*dst.GenDecl)
@@ -53,7 +55,7 @@ func ImplementServiceStruct(modelName string, file *dst.File, reimplement bool)
} }
if isServiceStructDefined && !reimplement { if isServiceStructDefined && !reimplement {
return return false
} }
serviceStruct := &dst.GenDecl{ serviceStruct := &dst.GenDecl{
@@ -69,13 +71,16 @@ func ImplementServiceStruct(modelName string, file *dst.File, reimplement bool)
} }
file.Decls = append(decls[:insertPos], append([]dst.Decl{serviceStruct}, decls[insertPos:]...)...) file.Decls = append(decls[:insertPos], append([]dst.Decl{serviceStruct}, decls[insertPos:]...)...)
return true
} }
func ImplementModelAlias(modelName string, file *dst.File) { func ImplementModelAlias(modelName string, file *dst.File) (wasModified bool) {
isAliasDefined := false
aliasTypeStandard := fmt.Sprintf("models.%s", CapitalizeFirst(modelName)) aliasTypeStandard := fmt.Sprintf("models.%s", CapitalizeFirst(modelName))
var insertPos int var (
var decls []dst.Decl insertPos int
decls []dst.Decl
isAliasDefined bool
)
for i, decl := range file.Decls { for i, decl := range file.Decls {
genDecl, ok := decl.(*dst.GenDecl) genDecl, ok := decl.(*dst.GenDecl)
@@ -147,7 +152,7 @@ func ImplementModelAlias(modelName string, file *dst.File) {
Name: &dst.Ident{ Name: &dst.Ident{
Name: modelName, Name: modelName,
}, },
Assign: true, // quick and dirty Assign: true,
Type: &dst.Ident{ Type: &dst.Ident{
Name: aliasTypeStandard, Name: aliasTypeStandard,
}, },
@@ -157,6 +162,9 @@ func ImplementModelAlias(modelName string, file *dst.File) {
if !isAliasDefined { if !isAliasDefined {
file.Decls = append(decls[:insertPos], append([]dst.Decl{&typeAlias}, decls[insertPos:]...)...) file.Decls = append(decls[:insertPos], append([]dst.Decl{&typeAlias}, decls[insertPos:]...)...)
return true
} else {
return false
} }
} }
@@ -169,10 +177,32 @@ func importExists(file *dst.File, importPath string) bool {
return false return false
} }
func MaintainImports(file *dst.File) error { func MaintainImports(file *dst.File) (wasModified bool, e error) {
var (
modified bool
importDecl *dst.GenDecl
)
for _, decl := range file.Decls {
if genDecl, ok := decl.(*dst.GenDecl); ok && genDecl.Tok == token.IMPORT {
importDecl = genDecl
break
}
}
if importDecl == nil {
modified = true
importDecl = &dst.GenDecl{
Tok: token.IMPORT,
Specs: []dst.Spec{},
}
file.Decls = append([]dst.Decl{importDecl}, file.Decls...)
}
for _, importPath := range ServiceImports { for _, importPath := range ServiceImports {
if !importExists(file, importPath) { if !importExists(file, importPath) {
file.Imports = append(file.Imports, &dst.ImportSpec{ modified = true
importDecl.Specs = append(importDecl.Specs, &dst.ImportSpec{
Path: &dst.BasicLit{ Path: &dst.BasicLit{
Kind: token.STRING, Kind: token.STRING,
Value: `"` + importPath + `"`, Value: `"` + importPath + `"`,
@@ -180,7 +210,8 @@ func MaintainImports(file *dst.File) error {
}) })
} }
} }
return nil
return modified, nil
} }
func GenerateCrudMethodCode(methodName string, context CrudTemplatesContext) string { func GenerateCrudMethodCode(methodName string, context CrudTemplatesContext) string {
@@ -220,14 +251,15 @@ func MethodCodeToDeclaration(methodCode string) (*dst.FuncDecl, error) {
return methodDecl, nil return methodDecl, nil
} }
func ImplementCrudMethods(modelName string, serviceName string, file *dst.File, reimplement bool) error { func ImplementCrudMethods(modelName string, serviceName string, file *dst.File, reimplement bool) (wasModified bool, e error) {
templateContext := CrudTemplatesContext{ templateContext := CrudTemplatesContext{
ServiceName: serviceName, ServiceName: serviceName,
EntityType: modelName, EntityType: modelName,
EntityPlural: ToPlural(modelName), EntityPlural: ToPlural(modelName),
} }
modified := reimplement
for _, methodName := range []string{CreateMethod, GetAllMethod, GetByIdMethod, UpdateMethod, DeleteMethod, CountMethod} { for _, methodName := range implementedMethods {
methodCode := GenerateCrudMethodCode(methodName, templateContext) methodCode := GenerateCrudMethodCode(methodName, templateContext)
methodDecl, err := MethodCodeToDeclaration(methodCode) methodDecl, err := MethodCodeToDeclaration(methodCode)
fmt.Printf("%s\n", methodCode) fmt.Printf("%s\n", methodCode)
@@ -235,23 +267,27 @@ func ImplementCrudMethods(modelName string, serviceName string, file *dst.File,
fmt.Println(methodDecl) fmt.Println(methodDecl)
panic(err) panic(err)
} }
err = ImplementMethod(file, methodDecl, reimplement)
methodModified, err := ImplementMethod(file, methodDecl, reimplement)
if err != nil { if err != nil {
return err return false, err
}
if methodModified {
modified = true
} }
} }
return nil return modified, nil
} }
func ImplementMethod(file *dst.File, methodDecl *dst.FuncDecl, reimplement bool) error { func ImplementMethod(file *dst.File, methodDecl *dst.FuncDecl, reimplement bool) (wasModified bool, e error) {
var decls []dst.Decl var (
methodImplemented := false decls []dst.Decl
methodImplemented bool
)
modified := reimplement
methodStructure := methodDecl.Recv.List[0].Names[0].Name methodStructure := methodDecl.Recv.List[0].Names[0].Name
methodName := methodDecl.Name.Name methodName := methodDecl.Name.Name
log.Printf("Standard method structure: %s\n", methodStructure)
log.Printf("Standard method name: %s\n", methodName)
for _, decl := range file.Decls { for _, decl := range file.Decls {
decls = append(decls, decl) decls = append(decls, decl)
@@ -260,14 +296,14 @@ func ImplementMethod(file *dst.File, methodDecl *dst.FuncDecl, reimplement bool)
continue continue
} }
if len(funcDecl.Recv.List) > 0 && len(funcDecl.Recv.List[0].Names) > 0 { if len(funcDecl.Recv.List) > 0 && len(funcDecl.Recv.List[0].Names) > 0 {
fmt.Printf("Method structure: %s\n", funcDecl.Recv.List[0].Names[0].Name) log.Printf("Method structure: %s\n", funcDecl.Recv.List[0].Names[0].Name)
fmt.Printf("Method name: %s\n", funcDecl.Name.Name) log.Printf("Method name: %s\n", funcDecl.Name.Name)
if funcDecl.Recv.List[0].Names[0].Name == methodStructure { if funcDecl.Recv.List[0].Names[0].Name == methodStructure {
if funcDecl.Name != nil && funcDecl.Name.Name == methodName { if funcDecl.Name != nil && funcDecl.Name.Name == methodName {
if methodImplemented { if methodImplemented {
err := fmt.Sprintf("`%s` method redeclarated for struct `%s`", methodName, methodStructure) err := fmt.Sprintf("`%s` method redeclarated for struct `%s`", methodName, methodStructure)
log.Println(err) log.Println(err)
return errors.New(err) return false, errors.New(err)
} else { } else {
methodImplemented = true methodImplemented = true
} }
@@ -280,6 +316,7 @@ func ImplementMethod(file *dst.File, methodDecl *dst.FuncDecl, reimplement bool)
} }
if reimplement || !methodImplemented { if reimplement || !methodImplemented {
modified = true
file.Decls = append( file.Decls = append(
decls, decls,
&dst.FuncDecl{ &dst.FuncDecl{
@@ -293,72 +330,93 @@ func ImplementMethod(file *dst.File, methodDecl *dst.FuncDecl, reimplement bool)
) )
} }
return nil return modified, nil
} }
func CreateServiceFileIfNotExists(filePath string) error { func CreateServiceFileIfNotExists(filePath string) (wasModified bool, e error) {
var modified bool
if _, err := os.Stat(filePath); err != nil { if _, err := os.Stat(filePath); err != nil {
// file wasn't created // file wasn't created
f, err := os.Create(filePath) f, err := os.Create(filePath)
if err != nil { if err != nil {
log.Fatalf("Failed to create file: %s", filePath) log.Fatalf("Failed to create file: %s", filePath)
return err return false, err
} }
_, err = f.Write([]byte("package services\n")) _, err = f.Write([]byte("package services\n"))
if err != nil { if err != nil {
log.Fatalf("Failed to write file: %s", filePath) log.Fatalf("Failed to write file: %s", filePath)
return err return false, err
} }
modified = true
defer f.Close() defer f.Close()
} }
return nil return modified, nil
} }
func ImplementService(mainPkgPath string, modelName string, reimplement bool) error { func ImplementService(mainPkgPath string, modelName string, reimplement bool) (wasModified bool, e error) {
serviceRelativePath := fmt.Sprintf("services/%s.go", strings.ToLower(modelName)) serviceRelativePath := fmt.Sprintf("services/%s.go", strings.ToLower(modelName))
filePath := filepath.Join(mainPkgPath, serviceRelativePath) filePath := filepath.Join(mainPkgPath, serviceRelativePath)
serviceName := modelName + "Service" serviceName := modelName + "Service"
modified := reimplement
err := CreateServiceFileIfNotExists(filePath) fileModified, err := CreateServiceFileIfNotExists(filePath)
if err != nil { if err != nil {
return err return false, err
}
if fileModified {
modified = true
} }
fset := token.NewFileSet() fset := token.NewFileSet()
serviceFile, err := decorator.ParseFile(fset, filePath, nil, parser.ParseComments) serviceFile, err := decorator.ParseFile(fset, filePath, nil, parser.ParseComments)
if err != nil { if err != nil {
log.Fatalf("Parsing error: %s: %v", mainPkgPath, err) log.Fatalf("Parsing error: %s: %v", mainPkgPath, err)
return err return false, err
} }
err = MaintainImports(serviceFile) importsModified, err := MaintainImports(serviceFile)
if err != nil { if err != nil {
return err return false, err
}
if importsModified {
modified = true
} }
ImplementModelAlias(modelName, serviceFile) aliasAdded := ImplementModelAlias(modelName, serviceFile)
ImplementServiceStruct(modelName, serviceFile, reimplement) if aliasAdded {
err = ImplementCrudMethods(modelName, serviceName, serviceFile, reimplement) modified = true
}
serviceStructModified := ImplementServiceStruct(modelName, serviceFile, reimplement)
if serviceStructModified {
modified = true
}
methodsModified, err := ImplementCrudMethods(modelName, serviceName, serviceFile, reimplement)
if err != nil { if err != nil {
return err return false, err
}
if methodsModified {
modified = true
} }
file, err := os.Create(filePath) file, err := os.Create(filePath)
if err != nil { if err != nil {
return errors.New(fmt.Sprintf("Error occured to open `%s` service file: %v", modelName, err)) errMessage := errors.New(fmt.Sprintf("Error occured to open `%s` service file: %v", modelName, err))
return false, errMessage
} }
err = decorator.Fprint(file, serviceFile) err = decorator.Fprint(file, serviceFile)
if err != nil { if err != nil {
return errors.New( errMessage := errors.New(
fmt.Sprintf("Error occurred to writing changes in `%s` service file: %v", modelName, err), fmt.Sprintf("Error occurred to writing changes in `%s` service file: %v", modelName, err),
) )
return false, errMessage
} }
defer file.Close() defer file.Close()
return nil return modified, nil
} }