diff --git a/command/generateCrud/domain.text b/command/generateCrud/domain.text new file mode 100644 index 0000000..2a9a93b --- /dev/null +++ b/command/generateCrud/domain.text @@ -0,0 +1,29 @@ +package domain + +import ( + "github.com/gin-gonic/gin" + "online-order/entity" +) + +type {Name}Repository interface { + List() ([]*entity.{Name}Display, error) + Create(p *entity.{Name}CreateUpdate) error + GetByID(id int) (*entity.{Name}Display, error) + Update(p *entity.{Name}CreateUpdate) error + Delete(id int) error +} + +type {Name}Service interface { + List() ([]*entity.{Name}Display, error) + Create(u *entity.{Name}CreateUpdate) error + GetByID(id int) (*entity.{Name}Display, error) + Update(u *entity.{Name}CreateUpdate) error + Delete(id int) error +} + +type {Name}Controller interface { + list{Name}(ctx *gin.Context) + get{Name}(ctx *gin.Context) + update{Name}(ctx *gin.Context) + delete{Name}(ctx *gin.Context) +} \ No newline at end of file diff --git a/command/generateCrud/entity.text b/command/generateCrud/entity.text new file mode 100644 index 0000000..e45fddd --- /dev/null +++ b/command/generateCrud/entity.text @@ -0,0 +1,38 @@ +package entity + +import ( + "time" +) + +// use to display a {name} +type {Name}Display struct { + ID int `json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// use to create or update a {name} +type {Name}CreateUpdate struct { + {Name}Display + BusinessID int `json:"business_id"` +} + +// Func that will check non empty field on {Name}Display and update {name} +func ValidateUpdate({name} *{Name}CreateUpdate, p *{Name}Display) *{Name}CreateUpdate { + + {name}.ID = p.ID + {name}.CreatedAt = p.CreatedAt + {name}.UpdatedAt = p.UpdatedAt + + return {name} +} + +func {Name}DisplayFormatter({name} *{Name}CreateUpdate) (p *{Name}Display) { + p = &{Name}Display{ + ID: {name}.ID, + CreatedAt: {name}.CreatedAt, + UpdatedAt: {name}.UpdatedAt, + } + + return +} \ No newline at end of file diff --git a/command/generateCrud/generate_crud.go b/command/generateCrud/generate_crud.go new file mode 100644 index 0000000..7b90d19 --- /dev/null +++ b/command/generateCrud/generate_crud.go @@ -0,0 +1,178 @@ +package main + +import ( + "fmt" + "github.com/ettle/strcase" + "io/ioutil" + "os" + "strings" +) + +func main() { + name := "order" + createDomain(name) + createEntity(name) + createHandler(name) + createRepository(name) + createUsecase(name) + createRouter(name) +} + +func createRouter(name string) { + fileName := "../../api/handlers/" + name + "s/router.go" + + os.Mkdir("../../api/handlers/"+name+"s", os.ModePerm) + + file, err := os.Create(fileName) + if err != nil { + fmt.Println("error in create file on route:", err) + return + } + defer file.Close() + + replaced := replace(getFile("router.text"), name) + + _, err = file.WriteString(replaced) + if err != nil { + fmt.Println("error in write file content on route:", err) + return + } + + fmt.Printf("%s file created.\n", fileName) +} +func createUsecase(name string) { + fileName := "../../usecase/" + name + "/service.go" + + os.Mkdir("../../usecase/"+name, os.ModePerm) + + file, err := os.Create(fileName) + if err != nil { + fmt.Println("error in create file on usecase:", err) + return + } + defer file.Close() + + replaced := replace(getFile("usecase.text"), name) + + _, err = file.WriteString(replaced) + if err != nil { + fmt.Println("error in write file content on usecase:", err) + return + } + + fmt.Printf("%s file created.\n", fileName) +} + +func createRepository(name string) { + fileName := "../../repository/" + name + "/" + name + ".go" + + os.Mkdir("../../repository/"+name, os.ModePerm) + + file, err := os.Create(fileName) + if err != nil { + fmt.Println("error in create file on repository:", err) + return + } + defer file.Close() + + replaced := replace(getFile("repository.text"), name) + + _, err = file.WriteString(replaced) + if err != nil { + fmt.Println("error in write file content on repository:", err) + return + } + + fmt.Printf("%s file created.\n", fileName) +} + +func createHandler(name string) { + fileName := "../../api/handlers/" + name + "s/" + name + ".go" + + os.Mkdir("../../api/handlers/"+name+"s", os.ModePerm) + + file, err := os.Create(fileName) + if err != nil { + fmt.Println("error in create file on handlers:", err) + return + } + defer file.Close() + + replaced := replace(getFile("handler.text"), name) + + _, err = file.WriteString(replaced) + if err != nil { + fmt.Println("error in write file content on handlers:", err) + return + } + + fmt.Printf("%s file created.\n", fileName) +} + +func createEntity(name string) { + fileName := "../../entity/" + name + ".go" + + file, err := os.Create(fileName) + if err != nil { + fmt.Println("error in create file on entity:", err) + return + } + defer file.Close() + + replaced := replace(getFile("entity.text"), name) + + _, err = file.WriteString(replaced) + if err != nil { + fmt.Println("error in write file content on entity:", err) + return + } + + fmt.Printf("%s file created.\n", fileName) +} + +func createDomain(name string) { + fileName := "../../domain/" + name + ".go" + + file, err := os.Create(fileName) + if err != nil { + fmt.Println("error in create file on domain:", err) + return + } + defer file.Close() + + replaced := replace(getFile("domain.text"), name) + + _, err = file.WriteString(replaced) + if err != nil { + fmt.Println("error in write file content on domain:", err) + return + } + + fmt.Printf("%s file created.\n", fileName) +} + +func getFile(path string) string { + file, err := os.Open(path) + if err != nil { + fmt.Println("error in open file:", err) + return "" + } + defer file.Close() + + // خواندن محتوای فایل + content, err := ioutil.ReadAll(file) + if err != nil { + fmt.Println("error in read file:", err) + return "" + } + + // تبدیل محتوا به رشته + return string(content) +} + +func replace(c string, name string) string { + c = strings.ReplaceAll(c, "{name}", name) + + pascalCaseName := strcase.ToPascal(name) + return strings.ReplaceAll(c, "{Name}", pascalCaseName) +} diff --git a/command/generateCrud/handler.text b/command/generateCrud/handler.text new file mode 100644 index 0000000..ed484aa --- /dev/null +++ b/command/generateCrud/handler.text @@ -0,0 +1,145 @@ +package handler_{name}s + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "online-order/domain" + "online-order/entity" + "online-order/utils" +) + +type controller struct { + service domain.{Name}Service +} + +func New{Name}Controller(svc domain.{Name}Service) *controller { + return &controller{ + service: svc, + } +} + +// List{Name}s godoc +// @Summary List {Name}s +// @Description get {Name}s +// @Tags {Name}s +// @Accept json +// @Produce json +// @Param q query string false "name search by q" Format(email) +// @Success 200 {array} entity.{Name}Display +// @Failure 400 {object} httputil.HTTPError +// @Failure 500 {object} httputil.HTTPError +// @Router /{name}s [get] +func (c *controller) list{Name}(ctx *gin.Context) { + {name}s, err := c.service.List() + if err != nil { + utils.ResponseJSON(ctx, http.StatusBadRequest, err.Error(), nil) + return + } + utils.ResponseJSON(ctx, http.StatusOK, "successful", {name}s) +} + +// Show{Name} godoc +// @Summary Show an {name} +// @Description get string by ID +// @Tags {Name}s +// @Accept json +// @Produce json +// @Param id path int true "{name} ID" +// @Success 200 {object} entity.{Name}Display +// @Failure 404 {object} httputil.HTTPError +// @Failure 500 {object} httputil.HTTPError +// @Router /{name}s/{id} [get] +func (c *controller) get{Name}(ctx *gin.Context) { + id := ctx.Param("id") + id_convert, err := strconv.Atoi(id) + if err != nil { + utils.ResponseJSON(ctx, http.StatusNotFound, err.Error(), nil) + return + } + {name}, err := c.service.GetByID(id_convert) + if err != nil || {name} == nil { + utils.ResponseJSON(ctx, http.StatusNotFound, err.Error(), nil) + return + } + utils.ResponseJSON(ctx, http.StatusOK, "successful", {name}) +} + +// Update{Name} godoc +// @Summary Update an {name} +// @Description update {Name} by ID +// @Tags {Name}s +// @Accept json +// @Produce json +// @Param id path int true "{name} ID" +// @Success 200 string message +// @Failure 400 {object} httputil.HTTPError +// @Failure 404 {object} httputil.HTTPError +// @Failure 500 {object} httputil.HTTPError +// @Router /{name}s/{id} [put] +func (c *controller) update(ctx *gin.Context) { + var data *entity.{Name}CreateUpdate + var id = ctx.Param("id") + + id_convert, err := strconv.Atoi(id) + if err != nil { + utils.ResponseJSON(ctx, http.StatusNotFound, err.Error(), nil) + return + } + + if err := ctx.ShouldBindJSON(&data); err != nil { + utils.ResponseJSON(ctx, http.StatusBadRequest, err.Error(), nil) + return + } + + {name}, err := c.service.GetByID(id_convert) + if err != nil || {name} == nil { + utils.ResponseJSON(ctx, http.StatusNotFound, entity.ErrNotFound.Error(), nil) + return + } + + data = entity.ValidateUpdate(data, {name}) + + err = c.service.Update(data) + if err != nil { + utils.ResponseJSON(ctx, http.StatusBadRequest, err.Error(), nil) + return + } + response := entity.{Name}DisplayFormatter(data) + utils.ResponseJSON(ctx, http.StatusAccepted, "successful", response) +} + +// Delete{Name} godoc +// @Summary Delete an {name} +// @Description Delete {Name} by ID +// @Tags {Name}s +// @Accept json +// @Produce json +// @Param id path int true "{name} ID" +// @Success 200 string successfully deleted +// @Failure 404 {object} httputil.HTTPError +// @Failure 400 {object} httputil.HTTPError +// @Failure 500 {object} httputil.HTTPError +// @Router /{name}s/{id} [delete] +func (c *controller) delete{Name}(ctx *gin.Context) { + var id = ctx.Param("id") + id_convert, err := strconv.Atoi(id) + if err != nil { + utils.ResponseJSON(ctx, http.StatusNotFound, err.Error(), nil) + return + } + + {name}, err := c.service.GetByID(id_convert) + if err != nil || {name} == nil { + utils.ResponseJSON(ctx, http.StatusNotFound, entity.ErrNotFound.Error(), nil) + return + } + + err = c.service.Delete(id_convert) + if err != nil { + utils.ResponseJSON(ctx, http.StatusBadRequest, err.Error(), nil) + return + } + utils.ResponseJSON(ctx, http.StatusAccepted, "successfully deleted", nil) +} \ No newline at end of file diff --git a/command/generateCrud/repository.text b/command/generateCrud/repository.text new file mode 100644 index 0000000..e254443 --- /dev/null +++ b/command/generateCrud/repository.text @@ -0,0 +1,98 @@ +package repository_{name} + +import ( + "context" + "online-order/ent" + "online-order/ent/{name}" + "online-order/entity" +) + +type {Name}Repository struct { + client *ent.Client + activeBusiness *entity.ActiveBusiness +} + +func New{Name}Repository(client *ent.Client, activeBusiness *entity.ActiveBusiness) *{Name}Repository { + return &{Name}Repository{ + client: client, + activeBusiness: activeBusiness, + } +} + +// List all {name}s +func (c *{Name}Repository) List() ([]*entity.{Name}Display, error) { + var u []*entity.{Name}Display + ctx := context.Background() + + err := c.client.{Name}. + Query(). + Where({name}.BusinessID(c.activeBusiness.BusinessID)). + Select({name}.FieldID, {name}.FieldCreatedAt, {name}.FieldUpdatedAt). + Scan(ctx, &u) + + if err != nil { + return nil, err + } + + return u, nil +} + +// Create a {name} +func (c *{Name}Repository) Create(p *entity.{Name}CreateUpdate) error { + ctx := context.Background() + + resp, err := c.client.{Name}. + Create(). + SetBusinessID(c.activeBusiness.BusinessID). + SetUserID(p.UserID). + Save(ctx) + + if err != nil { + return err + } + + return nil +} + +func (c *{Name}Repository) GetByID(id int) (*entity.{Name}Display, error) { + var p entity.{Name}Display + ctx := context.Background() + + resp := c.client.{Name}. + Query(). + Where({name}.BusinessID(c.activeBusiness.BusinessID)). + Where({name}.ID(id)). + AllX(ctx) + + if len(resp) > 0 { + p.ID = resp[0].ID + p.CreatedAt = resp[0].CreatedAt + p.UpdatedAt = resp[0].UpdatedAt + } else { + return nil, entity.ErrNotFound + } + + return &p, nil +} + +// Update {name} information +func (c *{Name}Repository) Update(p *entity.{Name}CreateUpdate) error { + ctx := context.Background() + + _, err := c.client.{Name}.UpdateOneID(p.ID). + Save(ctx) + if err != nil { + return err + } + return nil +} + +// Update user information, except password +func (c *{Name}Repository) Delete(id int) error { + ctx := context.Background() + + err := c.client.{Name}. + DeleteOneID(id). + Exec(ctx) + return err +} \ No newline at end of file diff --git a/command/generateCrud/router.text b/command/generateCrud/router.text new file mode 100644 index 0000000..b1c060f --- /dev/null +++ b/command/generateCrud/router.text @@ -0,0 +1,22 @@ +package handler_{name}s + +import ( + "online-order/entity" + "online-order/repository/{name}" + "online-order/usecase/{name}" +) + +func New{Name}Routers(server *entity.Routers) { + {name}Repo := repository_{name}.New{Name}Repository(server.Database, &server.ActiveBusiness) + + {name}Service := service_{name}.New{Name}Service({name}Repo) + + {name}Controller := New{Name}Controller({name}Service) + + // {name} management + api_{name} := server.OpenApp.Group("{name}s") + api_{name}.GET("/", {name}Controller.list{Name}) + api_{name}.GET(":id", {name}Controller.get{Name}) + api_{name}.PUT(":id", {name}Controller.update) + api_{name}.DELETE(":id", {name}Controller.delete{Name}) +} \ No newline at end of file diff --git a/command/generateCrud/usecase.text b/command/generateCrud/usecase.text new file mode 100644 index 0000000..7a792b3 --- /dev/null +++ b/command/generateCrud/usecase.text @@ -0,0 +1,41 @@ +package service_{name} + +import ( + "online-order/domain" + "online-order/entity" +) + +type {name}service struct { + repo domain.{Name}Repository +} + +func New{Name}Service(r domain.{Name}Repository) *{name}service { + return &{name}service{ + repo: r, + } +} + +func (s *{name}service) List() ([]*entity.{Name}Display, error) { + return s.repo.List() +} + +func (s *{name}service) Create(p *entity.{Name}CreateUpdate) error { + return s.repo.Create(p) +} + +// Retrieve a {name} +func (s *{name}service) GetByID(id int) (*entity.{Name}Display, error) { + u, err := s.repo.GetByID(id) + if err != nil { + return &entity.{Name}Display{}, entity.ErrNotFound + } + return u, nil +} + +func (s *{name}service) Update(p *entity.{Name}CreateUpdate) error { + return s.repo.Update(p) +} + +func (s *{name}service) Delete(id int) error { + return s.repo.Delete(id) +} \ No newline at end of file diff --git a/go.mod b/go.mod index e77b50c..36500fb 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/ettle/strcase v0.2.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect diff --git a/go.sum b/go.sum index 10acf31..aa574bf 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= +github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=