From 1e4f663b7e0952b1f1f6a42bac40cbab457fc7ba Mon Sep 17 00:00:00 2001 From: illud Date: Sat, 12 Jul 2025 17:08:02 -0500 Subject: [PATCH] feat: Add base templates for Go application structure - Created .env.tmpl for environment variable configuration. - Added .gitignore.tmpl to exclude unnecessary files from version control. - Introduced README.tmpl with project description and usage instructions. - Implemented bcrypt.go.tmpl for password hashing and verification. - Developed db.go.tmpl for database connection using GORM. - Added env.go.tmpl for loading environment variables. - Created errors.go.tmpl for standardized error handling. - Implemented getTasks_test.go.tmpl for testing task retrieval. - Developed jwt.go.tmpl for JWT token generation and validation. - Created main.go.tmpl as the entry point for the application. - Added router.go.tmpl for setting up HTTP routes. - Implemented tasks.controller.go.tmpl for task-related HTTP handlers. - Developed tasks.db.go.tmpl for task database operations. - Created tasks.model.go.tmpl for task data structure definition. - Added tasks.repository.go.tmpl for task repository interface. - Implemented tasks.service.go.tmpl for task business logic. - Created tracker.json.tmpl for module tracking configuration. - Developed gorm.tmpl for GORM database connection setup. - Added mysql.tmpl for MySQL database connection setup. - Created endpoint templates for post operations including controller, infrastructure, repository, and service. - Developed module templates for creating a modular application structure. --- README.md | 2 +- src/base/base.go | 883 +++--------------- src/base/db_client.go | 176 +--- src/base/module_crud.go | 469 ++-------- src/base/templates/base/.env.tmpl | 2 + src/base/templates/base/.gitignore.tmpl | 28 + src/base/templates/base/README.tmpl | 69 ++ src/base/templates/base/bcrypt.go.tmpl | 17 + src/base/templates/base/db.go.tmpl | 34 + src/base/templates/base/env.go.tmpl | 27 + src/base/templates/base/errors.go.tmpl | 21 + src/base/templates/base/getTasks_test.go.tmpl | 76 ++ src/base/templates/base/jwt.go.tmpl | 37 + src/base/templates/base/main.go.tmpl | 37 + src/base/templates/base/router.go.tmpl | 32 + .../templates/base/tasks.controller.go.tmpl | 137 +++ src/base/templates/base/tasks.db.go.tmpl | 58 ++ src/base/templates/base/tasks.model.go.tmpl | 7 + .../templates/base/tasks.repository.go.tmpl | 13 + src/base/templates/base/tasks.service.go.tmpl | 56 ++ src/base/templates/base/tracker.json.tmpl | 8 + src/base/templates/database/gorm.tmpl | 25 + src/base/templates/database/mysql.tmpl | 25 + .../endpoint/post/controller.post.go.tmpl | 28 + .../post/infraestructure.post.go.tmpl | 4 + .../endpoint/post/repository.go.tmpl | 2 + .../endpoint/post/service.post.go.tmpl | 7 + src/base/templates/module/controller.go.tmpl | 83 ++ .../templates/module/infraestructure.go.tmpl | 39 + src/base/templates/module/model.go.tmpl | 5 + src/base/templates/module/repository.go.tmpl | 13 + src/base/templates/module/service.go.tmpl | 56 ++ src/base/templates/module/test.go.tmpl | 67 ++ src/cli/cli.go | 82 +- 34 files changed, 1248 insertions(+), 1377 deletions(-) create mode 100644 src/base/templates/base/.env.tmpl create mode 100644 src/base/templates/base/.gitignore.tmpl create mode 100644 src/base/templates/base/README.tmpl create mode 100644 src/base/templates/base/bcrypt.go.tmpl create mode 100644 src/base/templates/base/db.go.tmpl create mode 100644 src/base/templates/base/env.go.tmpl create mode 100644 src/base/templates/base/errors.go.tmpl create mode 100644 src/base/templates/base/getTasks_test.go.tmpl create mode 100644 src/base/templates/base/jwt.go.tmpl create mode 100644 src/base/templates/base/main.go.tmpl create mode 100644 src/base/templates/base/router.go.tmpl create mode 100644 src/base/templates/base/tasks.controller.go.tmpl create mode 100644 src/base/templates/base/tasks.db.go.tmpl create mode 100644 src/base/templates/base/tasks.model.go.tmpl create mode 100644 src/base/templates/base/tasks.repository.go.tmpl create mode 100644 src/base/templates/base/tasks.service.go.tmpl create mode 100644 src/base/templates/base/tracker.json.tmpl create mode 100644 src/base/templates/database/gorm.tmpl create mode 100644 src/base/templates/database/mysql.tmpl create mode 100644 src/base/templates/endpoint/post/controller.post.go.tmpl create mode 100644 src/base/templates/endpoint/post/infraestructure.post.go.tmpl create mode 100644 src/base/templates/endpoint/post/repository.go.tmpl create mode 100644 src/base/templates/endpoint/post/service.post.go.tmpl create mode 100644 src/base/templates/module/controller.go.tmpl create mode 100644 src/base/templates/module/infraestructure.go.tmpl create mode 100644 src/base/templates/module/model.go.tmpl create mode 100644 src/base/templates/module/repository.go.tmpl create mode 100644 src/base/templates/module/service.go.tmpl create mode 100644 src/base/templates/module/test.go.tmpl diff --git a/README.md b/README.md index 7d85003..0bd8b7e 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ Build your application and after that, go to http://localhost:5000/swagger/index When you create a new module swagger will be added automatically then you only need to modified what you need, but remember each time you modified swagger use the next command ```shell -swag init +swag init --parseDependency github.com/volatiletech/null/v8 ``` To learn more visit (https://github.com/swaggo/gin-swagger) diff --git a/src/base/base.go b/src/base/base.go index f914ade..4439f5c 100644 --- a/src/base/base.go +++ b/src/base/base.go @@ -1,800 +1,171 @@ package base import ( + "bytes" + "embed" + "html/template" "os" ) -func BaseData(folderName string) { - //Add data to tracker.json - trackerString := - `{ - "modules": [{ - "moduleName": "tasks", - "endpointName": "tasks" - }] -}` - mainBytes := []byte(trackerString) - os.WriteFile(folderName+"/tracker.json", mainBytes, 0) - - //Add data to main.go - mainString := - `package main - -import ( - "fmt" - "strconv" - //Uncomment next line when you want to connect to a database - //db "github.com/` + folderName + `/adapters/database" - env "github.com/` + folderName + `/env" - router "github.com/` + folderName + `/router" -) - -//The next lines are for swagger docs -// @title ` + folderName + ` -// @version version(1.0) -// @description Description of specifications -// @Precautions when using termsOfService specifications - -// @host localhost:5000 -// @BasePath / - -// @securityDefinitions.apikey BearerAuth -// @in header -// @name Authorization -func main() { - //Uncomment next line when you want to connect to a database - //Connect to database - //db.Connect() - - //Load .env port - port := strconv.Itoa(env.Load().PORT) +//go:embed templates/**/*.tmpl +var tmplFS embed.FS - if port == "" { - fmt.Println("$PORT must be set") +func writeTemplateToFile(embedPath, outputPath string, data any) { + // Read the template content from the embedded filesystem + tmplContent, err := tmplFS.ReadFile(embedPath) + if err != nil { + panic("error reading embedded template: " + err.Error()) } - router.Router().Run(":" + port) -}` - mainBytes = []byte(mainString) - os.WriteFile(folderName+"/main.go", mainBytes, 0) - - //Add data to router.go - routingString := - `package router + // Create a new template and parse the content + tmpl := template.Must(template.New("embedded").Parse(string(tmplContent))) -import ( - tasksController "github.com/` + folderName + `/app/tasks/aplication" - "github.com/gin-contrib/cors" - "github.com/gin-gonic/gin" - - docs "github.com/` + folderName + `/docs" - swaggerfiles "github.com/swaggo/files" - ginSwagger "github.com/swaggo/gin-swagger" -) - -func Router() *gin.Engine { - //this sets gin to release mode - gin.SetMode(gin.ReleaseMode) - - router := gin.New() + // Execute the template with the provided data + var buf bytes.Buffer + if err := tmpl.Execute(&buf, data); err != nil { + panic("error executing template: " + err.Error()) + } - router.Use(cors.Default()) + // Ensure the directory exists + if err := os.WriteFile(outputPath, buf.Bytes(), 0644); err != nil { + panic("error writing output file: " + err.Error()) + } +} - //SWAGGER - docs.SwaggerInfo.BasePath = "/" - router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) +func BaseData(folderName string) { + //Add data to tracker.json + writeTemplateToFile("templates/base/tracker.json.tmpl", folderName+"/tracker.json", struct { + ModuleName string + EndpointName string + }{ + ModuleName: "tasks", + EndpointName: "tasks", + }) - router.POST("/tasks", tasksController.CreateTasks) - router.GET("/tasks", tasksController.GetTasks) - router.GET("/tasks/:taskId", tasksController.GetOneTasks) - router.PUT("/tasks/:taskId", tasksController.UpdateTasks) - router.DELETE("/tasks/:taskId", tasksController.DeleteTasks) + //Add data to main.go + writeTemplateToFile("templates/base/main.go.tmpl", folderName+"/main.go", struct { + FolderName string + }{ + FolderName: folderName, + }) - return router -}` - routingBytes := []byte(routingString) - os.WriteFile(folderName+"/router/router.go", routingBytes, 0) + //Add data to router.go + writeTemplateToFile("templates/base/router.go.tmpl", folderName+"/router/router.go", struct { + FolderName string + }{ + FolderName: folderName, + }) //Add data to .env - dotEnvString := - `PORT = 5000 - -VERSION = 1.0.0` - - dotEnvBytes := []byte(dotEnvString) - os.WriteFile(folderName+"/.env", dotEnvBytes, 0) + writeTemplateToFile("templates/base/.env.tmpl", folderName+"/.env", struct { + Port int + Version string + }{ + Port: 5000, + Version: "1.0.0", + }) //Add data to .gitignore - gitignoreString := - `# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with "go test -c" -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work - -# Env -*.env -*.env.test - -# Tmp folder -tmp/` - - gitignoreBytes := []byte(gitignoreString) - os.WriteFile(folderName+"/.gitignore", gitignoreBytes, 0) + writeTemplateToFile("templates/base/.gitignore.tmpl", folderName+"/.gitignore", nil) //Add data to README - readmeString := - ` - _____ _ - | __ \ | | - | | \/ ___ | |__ _____ __ - | | __ / _ \| '_ \ / _ \ \/ / - | |_\ \ (_) | | | | __/> < - \____/\___/|_| |_|\___/_/\_\ - -[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 -[circleci-url]: https://circleci.com/gh/nestjs/nest - -

A progressive Go framework for building efficient and scalable server-side applications.

-

- -[![Test Status](https://github.com/illud/gohex/actions/workflows/go.yml/badge.svg)](https://github.com/illud/gohex/actions/workflows/go.yml/badge.svg) -[![GoDoc](https://pkg.go.dev/badge/github.com/illud/gohex?status.svg)](https://pkg.go.dev/github.com/illud/gohex?tab=doc) -[![Go Report Card](https://goreportcard.com/badge/github.com/illud/gohex)](https://goreportcard.com/report/github.com/illud/gohex) - -

- - -## Description - -[Gohex](https://github.com/illud/gohex) CLI tool to create Hexagonal Architecture + Vertical Slicing. - -## Running the app - -` + "```" + `bash -# development -$ go run main.go - -# watch mode -# for more go to https://github.com/gravityblast/fresh -$ fresh - -# production mode -$ go build main.go -` + "```" + ` - -## Test - -` + "```" + `bash -# tests -$ go test -v ./... - -# to get coverage -$ go test -v -cover --coverprofile=coverage.out -coverpkg=./... ./... - -# to view test coverage on your browser -$ go tool cover -html=coverage.out - -# prints formatted test output, and a summary of the test run -# for more go to https://github.com/gotestyourself/gotestsum -$ gotestsum --format testname -` + "```" + ` - -## Support - -Gohex is an MIT-licensed open source project. - -## Stay in touch - -- Author - [Illud](https://github.com/illud) - -## License - -Nest is [MIT licensed](LICENSE). -"# Gohex" -` - - readmeBytes := []byte(readmeString) - os.WriteFile(folderName+"/README", readmeBytes, 0) + writeTemplateToFile("templates/base/README.tmpl", folderName+"/README.md", nil) //Add data to env.go - envString := - `package env - -import ( - "os" - "strconv" - - "github.com/joho/godotenv" -) - -//Add here your .env data -type Env struct { - PORT int - VERSION string -} - -func Load() Env { - godotenv.Load() //This loads your .env - - //Converts port string to int - port, _ := strconv.Atoi(os.Getenv("PORT")) - - //Returns .env data int Env struct - return Env{ - PORT: port, - VERSION: os.Getenv("VERSION"), - } -}` - - envBytes := []byte(envString) - os.WriteFile(folderName+"/env/env.go", envBytes, 0) + writeTemplateToFile("templates/base/env.go.tmpl", folderName+"/env/env.go", nil) //Add data to task-controller.go - taskControllerString := - `package tasks - -import ( - "strconv" - "net/http" - "github.com/gin-gonic/gin" - tasksService "github.com/` + folderName + `/app/tasks/domain/services" - tasksDatabase "github.com/` + folderName + `/app/tasks/infraestructure" - tasksModel "github.com/` + folderName + `/app/tasks/domain/models" -) - -// Create a TasksDb instance -var tasksDb = tasksDatabase.NewTasksDb() - -// Create a Service instance using the TasksDb -var service = tasksService.NewService(tasksDb) - -// CreateTasks handles the creation of a new task. -// @Summary Create Tasks -// @Description Create Tasks -// @Tags Tasks -// @Security BearerAuth -// @Accept json -// @Produce json -// @Param Body body tasksModel.Task true "Body to create Tasks" -// @Success 200 {string} string "Task created successfully" -// @Router /tasks [post] -func CreateTasks(c *gin.Context) { - var task tasksModel.Task - if err := c.ShouldBindJSON(&task); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - err := service.CreateTasks(task.Id, task.Title, task.Description) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{"data": "task created"}) -} - -// GetTasks retrieves all tasks. -// @Summary Get Tasks -// @Description Get Tasks -// @Tags Tasks -// @Security BearerAuth -// @Accept json -// @Produce json -// @Success 200 {object} tasksModel.Task[] -// @Router /tasks [Get] -func GetTasks(c *gin.Context) { - result, err := service.GetTasks() - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{"data": result}) -} - -// GetOneTasks retrieves a single task by taskId. -// @Summary Get Tasks -// @Description Get Tasks -// @Tags Tasks -// @Security BearerAuth -// @Param taskId path int true "taskId" -// @Accept json -// @Produce json -// @Success 200 {object} tasksModel.Task -// @Router /tasks/{taskId} [Get] -func GetOneTasks(c *gin.Context) { - taskId, err := strconv.Atoi(c.Param("taskId")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid taskId"}) - return - } - - result, err := service.GetOneTasks(taskId) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{"data": result}) -} - -// UpdateTasks handles updating an existing task by taskId. -// @Summary Update Tasks -// @Description Update Tasks -// @Tags Tasks -// @Security BearerAuth -// @Param taskId path int true "taskId" -// @Accept json -// @Produce json -// @Param Body body tasksModel.Task true "Body to update" -// @Success 200 {string} string "Task updated successfully" -// @Router /tasks/{taskId} [Put] -func UpdateTasks(c *gin.Context) { - taskId := c.Param("taskId") - var task tasksModel.Task - if err := c.ShouldBindJSON(&task); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - err := service.UpdateTasks(taskId, task.Title, task.Description) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{"data": "task updated"}) -} - -// DeleteTasks handles deleting a task by taskId. -// @Summary Delete Tasks -// @Description Delete Tasks -// @Tags Tasks -// @Security BearerAuth -// @Param taskId path int true "taskId" -// @Accept json -// @Produce json -// @Success 200 {string} string "Task deleted successfully" -// @Router /tasks/{taskId} [Delete] -func DeleteTasks(c *gin.Context) { - taskId := c.Param("taskId") - - err := service.DeleteTasks(taskId) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{"data": "task deleted"}) -}` - taskControllerBytes := []byte(taskControllerString) - os.WriteFile(folderName+"/app/tasks/aplication/tasks.controller.go", taskControllerBytes, 0) + writeTemplateToFile( + "templates/base/tasks.controller.go.tmpl", + folderName+"/app/tasks/aplication/tasks.controller.go", + struct { + FolderName string + }{ + FolderName: folderName, + }, + ) //Add data to models/task.model.go - taskModelString := - `package models - -type Task struct { - Id int - Title string - Description string -}` - taskModelBytes := []byte(taskModelString) - os.WriteFile(folderName+"/app/tasks/domain/models/tasks.model.go", taskModelBytes, 0) + writeTemplateToFile( + "templates/base/tasks.model.go.tmpl", + folderName+"/app/tasks/domain/models/tasks.model.go", + nil, + ) //Add data to repositories/tasks.repository.go - taskRepositoryString := - `package repositories - -import ( - tasksModel "github.com/` + folderName + `/app/tasks/domain/models" -) - -type ITasks interface { - CreateTasks(taskId int, title string, description string) error - GetTasks() ([]tasksModel.Task, error) - GetOneTasks(taskId int) (tasksModel.Task, error) - UpdateTasks(taskId string, title string, description string) error - DeleteTasks(taskId string) error -}` - taskRepositoryBytes := []byte(taskRepositoryString) - os.WriteFile(folderName+"/app/tasks/domain/repositories/tasks.repository.go", taskRepositoryBytes, 0) + writeTemplateToFile( + "templates/base/tasks.repository.go.tmpl", + folderName+"/app/tasks/domain/repositories/tasks.repository.go", + struct { + FolderName string + }{ + FolderName: folderName, + }, + ) //Add data to task.service.go - taskServiceString := - `package services - -import ( - tasksModel "github.com/` + folderName + `/app/tasks/domain/models" - tasksInterface "github.com/` + folderName + `/app/tasks/domain/repositories" -) - -type Service struct { - tasksRepository tasksInterface.ITasks -} - -func NewService(tasksRepository tasksInterface.ITasks) *Service { - return &Service{ - tasksRepository: tasksRepository, - } -} - -func (s *Service) CreateTasks(taskId int, title string, description string) error { - err := s.tasksRepository.CreateTasks(taskId, title, description) - if err != nil { - return err - } - return nil -} - -func (s *Service) GetTasks() ([]tasksModel.Task, error) { - tasks, err := s.tasksRepository.GetTasks() - if err != nil { - return nil, err - } - return tasks, nil -} - -func (s *Service) GetOneTasks(taskId int) (tasksModel.Task, error) { - task, err := s.tasksRepository.GetOneTasks(taskId) - if err != nil { - return tasksModel.Task{}, err - } - return task, nil -} - -func (s *Service) UpdateTasks(taskId string, title string, description string) error { - err := s.tasksRepository.UpdateTasks(taskId, title, description) - if err != nil { - return err - } - return nil -} - -func (s *Service) DeleteTasks(taskId string) error { - err := s.tasksRepository.DeleteTasks(taskId) - if err != nil { - return err - } - return nil -}` - taskServiceBytes := []byte(taskServiceString) - os.WriteFile(folderName+"/app/tasks/domain/services/tasks.service.go", taskServiceBytes, 0) + writeTemplateToFile( + "templates/base/tasks.service.go.tmpl", + folderName+"/app/tasks/domain/services/tasks.service.go", + struct { + FolderName string + }{ + FolderName: folderName, + }, + ) //Add data to tasks.db.go - taskInfraestructureString := - `package infraestructure - -import ( - tasksModel "github.com/` + folderName + `/app/tasks/domain/models" - // uncomment this a change _ for db when your are making database queries - _ "github.com/` + folderName + `/adapters/database" - "errors" -) - -type TasksDb struct { - // Add any dependencies or configurations related to the TasksRepository here, if needed. -} - -func NewTasksDb() *TasksDb { - // Initialize any dependencies and configurations for the TasksRepository here, if needed. - return &TasksDb{} -} - -func (t *TasksDb) CreateTasks(taskId int, title string, description string) error { - if taskId == 0 { - return errors.New("taskId is required") - } - - var task tasksModel.Task - task.Id = 1 - task.Title = title - task.Description = description - - return nil -} - -func (t *TasksDb) GetTasks() ([]tasksModel.Task, error) { - var tasks []tasksModel.Task - tasks = append(tasks, tasksModel.Task{Id: 1, Title: "Hello", Description: "World"}) - return tasks, nil -} - -func (t *TasksDb) GetOneTasks(taskId int) (tasksModel.Task, error) { - task := tasksModel.Task{Id: taskId, Title: "Sample Task", Description: "Sample Description"} - if task.Id == 0 { - return tasksModel.Task{}, errors.New("Task not found") - } - return task, nil -} - -func (t *TasksDb) UpdateTasks(taskId string, title string, description string) error { - if taskId == "" { - return errors.New("taskId is required") - } - return nil -} - -func (t *TasksDb) DeleteTasks(taskId string) error { - if taskId == "" { - return errors.New("taskId is required") - } - return nil -}` - taskInfraestructureBytes := []byte(taskInfraestructureString) - os.WriteFile(folderName+"/app/tasks/infraestructure/tasks.db.go", taskInfraestructureBytes, 0) + writeTemplateToFile( + "templates/base/tasks.db.go.tmpl", + folderName+"/app/tasks/infraestructure/tasks.db.go", + struct { + FolderName string + }{ + FolderName: folderName, + }, + ) //Add data to data/db.go - taskDataString := `package data - -import ( - "fmt" - tasksModel "github.com/` + folderName + `/app/tasks/domain/models" - - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -var ( - // DB The database connection - db *gorm.DB -) - -// Connect to database -func Connect() { - //CONNECTION - dbCon, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) - if err != nil { - fmt.Println("DATABASE CONNECTION ERROR: ", err) - } - - // Migrate the schema - dbCon.AutoMigrate(&tasksModel.Task{}) - - // defer db.Close() - db = dbCon - fmt.Println("CONNECTED") -} - -func Client() *gorm.DB { - return db -}` - - taskDataBytes := []byte(taskDataString) - os.WriteFile(folderName+"/adapters/database/db.go", taskDataBytes, 0) + writeTemplateToFile( + "templates/base/db.go.tmpl", + folderName+"/adapters/database/db.go", + struct { + FolderName string + }{ + FolderName: folderName, + }, + ) //Add data to adapters/bcrypt/bcrypt.go - bcrypt := `package bcrypt - -import ( - "golang.org/x/crypto/bcrypt" -) - -//hash password -func HashPassword(password string) (string, error) { - bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10) - return string(bytes), err -} - -//check password -func CheckPasswordHash(password, hash string) bool { - err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) - return err == nil -}` - - bcryptBytes := []byte(bcrypt) - os.WriteFile(folderName+"/adapters/bcrypt/bcrypt.go", bcryptBytes, 0) - - // ASYNC to helpers - asyncString := - `package helpers - -import "context" - -// Future interface has the method signature for await -type Future interface { - Await() interface{} -} - -type future struct { - await func(ctx context.Context) interface{} -} - -func (f future) Await() interface{} { - return f.await(context.Background()) -} - -// Exec executes the async function -func Exec(f func() interface{}) Future { - var result interface{} - c := make(chan struct{}) - go func() { - defer close(c) - result = f() - }() - return future{ - await: func(ctx context.Context) interface{} { - select { - case <-ctx.Done(): - return ctx.Err() - case <-c: - return result - } - }, - } -}` - //Add data to async.go - asyncBytes := []byte(asyncString) - os.WriteFile(folderName+"/helpers/async.go", asyncBytes, 0) + writeTemplateToFile( + "templates/base/bcrypt.go.tmpl", + folderName+"/adapters/bcrypt/bcrypt.go", + struct{}{}, + ) // jwt - jwtString := - `package jwt - -import ( - "fmt" - "github.com/dgrijalva/jwt-go" -) - -func GenerateToken(user string) string { - // Create a new token object, specifying signing method and the claims - // you would like it to contain. - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ - "user": user, - }) - - // Sign and get the complete encoded token as a string using the secret - tokenString, _ := token.SignedString([]byte("secret")) - - return tokenString -} - -func ValidateToken(validate string) string { - var tokenCheker string - tokenString := validate - claims := jwt.MapClaims{} - _, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { - return []byte("secret"), nil - }) - // ... error handling - if err != nil { - fmt.Println("Error: ", err) - tokenCheker = "Error" - } else { - tokenCheker = "Ok" - } - - return tokenCheker -}` - //Add data to jwt.go - jwtBytes := []byte(jwtString) - os.WriteFile(folderName+"/adapters/jwt/jwt.go", jwtBytes, 0) + writeTemplateToFile( + "templates/base/jwt.go.tmpl", + folderName+"/adapters/jwt/jwt.go", + struct{}{}, + ) // ERRORS - errorsString := - `package helpers -import ( - "encoding/json" -) - -type Error struct{ - Error string - Code int -} - -func ErrorJson(error string, code int) string { - jsondata := &Error{error, code} - encodejson, _ := json.Marshal(jsondata) - return string(encodejson) -} - -var BadRequest = ErrorJson("Bad Request", 400) -var Forbidden = ErrorJson("Forbidden", 403) -var NotFound = ErrorJson("Not Found", 404) -var Unauthorized = ErrorJson("Unauthorized", 401)` - - //Add data to errors.go - errorsBytes := []byte(errorsString) - os.WriteFile(folderName+"/helpers/errors.go", errorsBytes, 0) + writeTemplateToFile( + "templates/base/errors.go.tmpl", + folderName+"/helpers/errors.go", + struct{}{}, + ) // getTasks_test.go - tasksTestString := - `package tasks_test - -import ( - "bytes" - "encoding/json" - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - router "github.com/` + folderName + `/router" - token "github.com/` + folderName + `/adapters/jwt" - tasksModel "github.com/` + folderName + `/app/tasks/domain/models" - /* - - Uncomment this when you are testing real data coming from database. - db "github.com/app/` + folderName + `/adapters/database" - */ -) - -// Setup and Teardown -func setup(t *testing.T) func(t *testing.T) { - // Setup - t.Log("setup sub test") - - // For test db - t.Setenv("ENV", "TEST") - - /* - - Uncomment this when you are testing real data coming from test database. - db.Connect() - */ - - // Teardown - return func(t *testing.T) { - t.Log("teardown sub test") - } -} - -func TestGetTasks(t *testing.T) { - // Call Setup/Teardown - teardown := setup(t) - defer teardown(t) - - tokenData := token.GenerateToken("test") //Your token data - - router := router.Router() - - w := httptest.NewRecorder() - - values := map[string]interface{}{"token": tokenData} // this is the body in case you make a post, put - jsonValue, _ := json.Marshal(values) - - req, _ := http.NewRequest("GET", "/tasks", bytes.NewBuffer(jsonValue)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", tokenData) - - // In case you use cookies like for example token - req.Header.Set("Cookie", "token="+tokenData+";") - - router.ServeHTTP(w, req) - - // Deserialize response body - var responseData struct { - Data []tasksModel.Task - } - err := json.Unmarshal(w.Body.Bytes(), &responseData) - require.NoError(t, err) - - expected := tasksModel.Task{ - Id: 1, - } - - assert.Equal(t, []tasksModel.Task{expected}, responseData.Data) - assert.Equal(t, "200 OK", w.Result().Status) -}` + writeTemplateToFile( + "templates/base/getTasks_test.go.tmpl", + folderName+"/e2e/tasks/getTasks_test.go", + struct { + FolderName string + }{ + FolderName: folderName, + }, + ) - tasksTestBytes := []byte(tasksTestString) - os.WriteFile(folderName+"/e2e/tasks/getTasks_test.go", tasksTestBytes, 0) } diff --git a/src/base/db_client.go b/src/base/db_client.go index 757d2b8..18b7b5c 100644 --- a/src/base/db_client.go +++ b/src/base/db_client.go @@ -1,172 +1,20 @@ package base -import "os" +import "log" func BaseDbClient(clientName string) { - // Add database client - clientString := "" - if clientName == "mysql" { - clientString = - `package database - -import ( - "database/sql" - "fmt" - - _ "github.com/go-sql-driver/mysql" -) - -var ( - // db The database connection - db *sql.DB -) - -// Connect to database -func Connect() { - //CONNECTION - dbCon, err := sql.Open("mysql", "databaseUsername:databasePassword@tcp(localhost:3306)/yourDatabaseTablename") - - if err != nil { - fmt.Println("DATABASE CONNECTION ERROR: ", err) - } - - // defer db.Close() - db = dbCon - fmt.Println("CONNECTED") -} - -func Client() *sql.DB { - return db -}` - //Adds db conection to main.go - AppendDbConnectionToMain() + templatePath := "" + switch clientName { + case "mysql": + templatePath = "templates/database/mysql.tmpl" + case "gorm": + templatePath = "templates/database/gorm.tmpl" + default: + log.Fatalf("Unsupported client name: %s", clientName) } - if clientName == "gorm" { - clientString = - `package database - -import ( - "fmt" - - _ "github.com/go-sql-driver/mysql" - "github.com/jinzhu/gorm" -) - -var ( - // db The database connection - db *gorm.DB -) - -// Connect to database -func Connect() { - //CONNECTION - dbCon, err := gorm.Open("mysql", "databaseUsername:databasePassword@tcp(127.0.0.1:3306)/yourDatabaseTablename?charset=utf8mb4&parseTime=True&loc=Local") - - if err != nil { - fmt.Println("DATABASE CONNECTION ERROR: ", err) - } - - db = dbCon - fmt.Println("CONNECTED") -} - -func Client() *gorm.DB { - return db -}` - //Adds db conection to main.go - AppendDbConnectionToMain() - } - - // if clientName == "prisma" { - - // dir, err := os.Getwd() - // if err != nil { - // log.Fatal(err) - // } - // fmt.Println(dir) - // var ss []string - // if runtime.GOOS == "windows" { - // ss = strings.Split(dir, "\\") - // } else { - // ss = strings.Split(dir, "/") - // } - - // currentDirName := ss[len(ss)-1] - - // clientString = - // `package data - - // import ( - // "fmt" - - // "` + currentDirName + `/data/prisma/db" - // "golang.org/x/net/context" - // ) - - // var ( - // // db The database connection - // prismaDdb *db.PrismaClient - // ) - - // func Connect(){ - // client := db.NewClient() - // if err := client.Prisma.Connect(); err != nil { - // fmt.Println(err) - // } - - // // defer func() { - // // if err := client.Prisma.Disconnect(); err != nil { - // // panic(err) - // // } - // // }() - // prismaDdb = client - // fmt.Println("CONNECTED") - // } - - // func Client() *db.PrismaClient { - // return prismaDdb - // } - - // var Context = ContextService() - - // func ContextService() context.Context { - // ctx := context.Background() - // return ctx - // }` - - // //Adds db conection to main.go - // AppendDbConnectionToMain() - - // //Insertdata into prisma.schema - // prismaString := - // `datasource db { - // // could be postgresql or mysql - // provider = "sqlite" - // url = "file:dev.db" - // } - - // generator db { - // provider = "go run github.com/prisma/prisma-client-go" - // // set the output folder and package name - // output = "./infraestructure/databases/prisma/db" - // package = "db" - // } - - // //This is and example table add your own schemas - // model Tasks { - // id Int @id @default(autoincrement()) - // createdAt DateTime @default(now()) - // updatedAt DateTime @updatedAt - // title String - // description String - // }` - - // prismaSChemaBytes := []byte(prismaString) - // os.WriteFile("schema.prisma", prismaSChemaBytes, 0) - // } + // This function is used to create a database client based on the provided client name. + writeTemplateToFile(templatePath, "adapters/database/db.go", struct{}{}) - //Add data to db.go - clientBytes := []byte(clientString) - os.WriteFile("adapters/database/db.go", clientBytes, 0) + AppendDbConnectionToMain() } diff --git a/src/base/module_crud.go b/src/base/module_crud.go index 5093245..898f831 100644 --- a/src/base/module_crud.go +++ b/src/base/module_crud.go @@ -26,391 +26,100 @@ func BaseModuleCrud(moduleName string, moduleNameSnakeCase string, moduleNotModi currentDirName := ss[len(ss)-1] //Add data to controller.go - controllerString := - `package aplication - -import ( - "strconv" - "net/http" - "github.com/gin-gonic/gin" - ` + moduleName + `Services "github.com/` + currentDirName + `/app/` + moduleName + `/domain/services" - ` + moduleName + `Database "github.com/` + currentDirName + `/app/` + moduleName + `/infraestructure" - // Replace for dto - ` + moduleName + `Model "github.com/` + currentDirName + `/app/` + moduleName + `/domain/models" -) - -// Create a ` + moduleName + `Db instance -var ` + moduleName + `Db = ` + moduleName + `Database.New` + strings.Title(moduleName) + `Db() - -// Create a Service instance using the ` + moduleName + `Db -var service = ` + moduleName + `Services.NewService(` + moduleName + `Db) - -// Post ` + strings.Title(moduleName) + ` -// @Summary Post ` + strings.Title(moduleName) + ` -// @Schemes -// @Description Post ` + strings.Title(moduleName) + ` -// @Tags ` + strings.Title(moduleName) + ` -// @Security BearerAuth -// @Accept json -// @Produce json -// @Param Body body ` + moduleName + `Model.` + strings.Title(moduleName) + ` true "Body to create ` + strings.Title(moduleName) + `" -// @Success 200 -// @Router /` + str.ToKebabCase(moduleNotModify) + ` [Post] -func Create` + strings.Title(moduleName) + `(c *gin.Context) { - var ` + moduleName + ` ` + moduleName + `Model.` + strings.Title(moduleName) + ` - if err := c.ShouldBindJSON(&` + moduleName + `); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - err := service.Create` + strings.Title(moduleName) + `(` + moduleName + `) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{ - "data": "` + moduleName + ` created", - }) -} - -// Get ` + strings.Title(moduleName) + ` -// @Summary Get ` + strings.Title(moduleName) + ` -// @Schemes -// @Description Get ` + strings.Title(moduleName) + ` -// @Tags ` + strings.Title(moduleName) + ` -// @Security BearerAuth -// @Accept json -// @Produce json -// @Success 200 -// @Router /` + str.ToKebabCase(moduleNotModify) + ` [Get] -func Get` + strings.Title(moduleName) + `(c *gin.Context) { - result, err := service.Get` + strings.Title(moduleName) + `() - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{ - "data": result, - }) -} - -// Get ` + strings.Title(moduleName) + ` -// @Summary Get ` + strings.Title(moduleName) + ` -// @Schemes -// @Description Get ` + strings.Title(moduleName) + ` -// @Tags ` + strings.Title(moduleName) + ` -// @Security BearerAuth -// @Param ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id path int true "` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id" -// @Accept json -// @Produce json -// @Success 200 -// @Router /` + str.ToKebabCase(moduleNotModify) + `/{` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id} [Get] -func GetOne` + strings.Title(moduleName) + `(c *gin.Context) { - ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id, err := strconv.Atoi(c.Param("` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - result, err := service.GetOne` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{ - "data": result, - }) -} - -// Put ` + strings.Title(moduleName) + ` -// @Summary Put ` + strings.Title(moduleName) + ` -// @Schemes -// @Description Put ` + strings.Title(moduleName) + ` -// @Tags ` + strings.Title(moduleName) + ` -// @Security BearerAuth -// @Param ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id path int true "` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id" -// @Accept json -// @Produce json -// @Param Body body ` + moduleName + `Model.` + strings.Title(moduleName) + ` true "Body to update ` + strings.Title(moduleName) + `" -// @Success 200 -// @Router /` + str.ToKebabCase(moduleNotModify) + `/{` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id} [Put] -func Update` + strings.Title(moduleName) + `(c *gin.Context) { - var ` + moduleName + ` ` + moduleName + `Model.` + strings.Title(moduleName) + ` - if err := c.ShouldBindJSON(&` + moduleName + `); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id, err := strconv.Atoi(c.Param("` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - err = service.Update` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{ - "data": "` + moduleName + ` updated", - }) -} - -// Delete ` + strings.Title(moduleName) + ` -// @Summary Delete ` + strings.Title(moduleName) + ` -// @Schemes -// @Description Delete ` + strings.Title(moduleName) + ` -// @Tags ` + strings.Title(moduleName) + ` -// @Security BearerAuth -// @Param ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id path int true "` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id" -// @Accept json -// @Produce json -// @Success 200 -// @Router /` + str.ToKebabCase(moduleNotModify) + `/{` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id} [Delete] -func Delete` + strings.Title(moduleName) + `(c *gin.Context) { - ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id, err := strconv.Atoi(c.Param("` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - err = service.Delete` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{ - "data": "` + moduleName + ` deleted", - }) -} -` - controllerBytes := []byte(controllerString) - os.WriteFile("app/"+moduleName+"/aplication/"+moduleNameSnakeCase+".controller.go", controllerBytes, 0) + writeTemplateToFile( + "templates/module/controller.go.tmpl", + "app/"+moduleName+"/aplication/"+moduleNameSnakeCase+".controller.go", + struct { + CurrentDirName string + ModuleName string + ModuleNameTitle string + ModuleCamel string + }{ + CurrentDirName: currentDirName, + ModuleName: moduleName, + ModuleNameTitle: strings.Title(moduleName), + ModuleCamel: str.FormatSnakeCaseToCamelCase(moduleName), + }, + ) //Add data to moduleName.modle.go - modelString := - `package models - -type ` + strings.Title(moduleName) + ` struct { - Id int -}` - modelsBytes := []byte(modelString) - os.WriteFile("app/"+moduleName+"/domain/models/"+moduleNameSnakeCase+".model.go", modelsBytes, 0) - - //Add data to usecase.go - servicesString := - `package services - -import ( - ` + moduleName + `Model "github.com/` + currentDirName + `/app/` + moduleName + `/domain/models" - ` + moduleName + `Interface "github.com/` + currentDirName + `/app/` + moduleName + `/domain/repositories" -) - -type Service struct { - ` + moduleName + `Repository ` + moduleName + `Interface.I` + strings.Title(moduleName) + ` -} - -func NewService(` + moduleName + `Repository ` + moduleName + `Interface.I` + strings.Title(moduleName) + `) *Service { - return &Service{ - ` + moduleName + `Repository: ` + moduleName + `Repository, - } -} - -func (s *Service) Create` + strings.Title(moduleName) + `(` + moduleName + ` ` + moduleName + `Model.` + strings.Title(moduleName) + `) error { - err := s.` + moduleName + `Repository.Create` + strings.Title(moduleName) + `(` + moduleName + `) - if err != nil { - return err - } - return nil -} - -func (s *Service) Get` + strings.Title(moduleName) + `() ([]` + moduleName + `Model.` + strings.Title(moduleName) + `, error) { - result, err := s.` + moduleName + `Repository.Get` + strings.Title(moduleName) + `() - if err != nil { - return nil, err - } - return result, nil -} - -func (s *Service) GetOne` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) (` + moduleName + `Model.` + strings.Title(moduleName) + `, error) { - result, err := s.` + moduleName + `Repository.GetOne` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id) - if err != nil { - return ` + moduleName + `Model.` + strings.Title(moduleName) + `{} , err - } - return result, nil -} - -func (s *Service) Update` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) error { - err := s.` + moduleName + `Repository.Update` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id) - if err != nil { - return err - } - return nil -} - -func (s *Service) Delete` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) error { - err := s.` + moduleName + `Repository.Delete` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id) - if err != nil { - return err - } - return nil -}` - servicesBytes := []byte(servicesString) - os.WriteFile("app/"+moduleName+"/domain/services/"+moduleNameSnakeCase+".service.go", servicesBytes, 0) + writeTemplateToFile( + "templates/module/model.go.tmpl", + "app/"+moduleName+"/domain/models/"+moduleNameSnakeCase+".model.go", + struct { + StructName string + }{ + StructName: strings.Title(moduleName), + }, + ) + + //Add data to service.go + writeTemplateToFile( + "templates/module/service.go.tmpl", + "app/"+moduleName+"/domain/services/"+moduleNameSnakeCase+".service.go", + struct { + ModuleName string + CurrentDirName string + StructName string + ParamName string + }{ + ModuleName: moduleName, + CurrentDirName: currentDirName, + StructName: strings.Title(moduleName), + ParamName: str.FormatSnakeCaseToCamelCase(moduleNotModify), + }, + ) + + writeTemplateToFile( + "templates/module/repository.go.tmpl", + "app/"+moduleName+"/domain/repositories/"+moduleNameSnakeCase+".repository.go", + struct { + ModuleName string + CurrentDirName string + StructName string + IdName string + }{ + ModuleName: moduleName, + CurrentDirName: currentDirName, + StructName: strings.Title(moduleName), + IdName: str.FormatSnakeCaseToCamelCase(moduleNotModify) + "Id", + }, + ) //Add data to module/infraestructure/module.db.go - repositoryInterfaceString := - `package repositories - -import ( - ` + moduleName + `Model "github.com/` + currentDirName + `/app/` + moduleName + `/domain/models" -) - -type I` + strings.Title(moduleName) + ` interface { - Create` + strings.Title(moduleName) + `(` + moduleName + ` ` + moduleName + `Model.` + strings.Title(moduleName) + `) error - Get` + strings.Title(moduleName) + `() ([]` + moduleName + `Model.` + strings.Title(moduleName) + `, error) - GetOne` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) (` + moduleName + `Model.` + strings.Title(moduleName) + `, error) - Update` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) error - Delete` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) error -}` - repositoryInterfaceBytes := []byte(repositoryInterfaceString) - os.WriteFile("app/"+moduleName+"/domain/repositories/"+moduleNameSnakeCase+".repository.go", repositoryInterfaceBytes, 0) - - //Add data to module/infraestructure/module.db.go - infraestructureString := - `package infraestructure - -import ( - ` + moduleName + `Model "github.com/` + currentDirName + `/app/` + moduleName + `/domain/models" - // uncomment this a change _ for db when you are making database queries - _ "github.com/` + currentDirName + `/adapters/database" -) - -type ` + strings.Title(moduleName) + `Db struct { - // Add any dependencies or configurations related to the UserRepository here if needed. -} - -func New` + strings.Title(moduleName) + `Db() *` + strings.Title(moduleName) + `Db { - // Initialize any dependencies and configurations for the ` + strings.Title(moduleName) + `Repository here if needed. - return &` + strings.Title(moduleName) + `Db{} -} - -var ` + moduleName + ` []` + moduleName + `Model.` + strings.Title(moduleName) + ` - -func (` + str.GetFirstCharacterOfString(moduleName) + ` *` + strings.Title(moduleName) + `Db) Create` + strings.Title(moduleName) + `(` + moduleName + ` ` + moduleName + `Model.` + strings.Title(moduleName) + `) error { - // Implement your creation logic here - return nil -} - -func (` + str.GetFirstCharacterOfString(moduleName) + ` *` + strings.Title(moduleName) + `Db) Get` + strings.Title(moduleName) + `() ([]` + moduleName + `Model.` + strings.Title(moduleName) + `, error) { - // Implement your retrieval logic here - var ` + moduleName + ` []` + moduleName + `Model.` + strings.Title(moduleName) + ` - ` + moduleName + ` = append(` + moduleName + `, ` + moduleName + `Model.` + strings.Title(moduleName) + `{Id: 1}) - return ` + moduleName + `, nil -} - -func (` + str.GetFirstCharacterOfString(moduleName) + ` *` + strings.Title(moduleName) + `Db) GetOne` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) (` + moduleName + `Model.` + strings.Title(moduleName) + `, error) { - // Implement your single retrieval logic here - return ` + moduleName + `Model.` + strings.Title(moduleName) + `{Id: ` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id}, nil -} - -func (` + str.GetFirstCharacterOfString(moduleName) + ` ` + strings.Title(moduleName) + `Db) Update` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) error { - // Implement your update logic here - return nil -} - -func (` + str.GetFirstCharacterOfString(moduleName) + ` ` + strings.Title(moduleName) + `Db) Delete` + strings.Title(moduleName) + `(` + str.FormatSnakeCaseToCamelCase(moduleNotModify) + `Id int) error { - // Implement your deletion logic here - return nil -}` - infraestructureBytes := []byte(infraestructureString) - os.WriteFile("app/"+moduleName+"/infraestructure/"+moduleNameSnakeCase+".db.go", infraestructureBytes, 0) + writeTemplateToFile( + "templates/module/infraestructure.go.tmpl", + "app/"+moduleName+"/infraestructure/"+moduleNameSnakeCase+".db.go", + struct { + ModuleName string + CurrentDirName string + StructName string + ParamName string + FirstChar string + }{ + ModuleName: moduleName, + CurrentDirName: currentDirName, + StructName: strings.Title(moduleName), + ParamName: str.FormatSnakeCaseToCamelCase(moduleNotModify), + FirstChar: str.GetFirstCharacterOfString(moduleName), + }, + ) // TEST - testString := - `package ` + moduleName + `_test - -import ( - "bytes" - "encoding/json" - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - router "github.com/` + currentDirName + `/router" - token "github.com/` + currentDirName + `/adapters/jwt" - ` + moduleName + `Model "github.com/` + currentDirName + `/app/` + moduleName + `/domain/models" - /* - - Uncomment this when you are testing real data coming from database. - db "github.com/app/` + currentDirName + `/infraestructure" - */ -) - -// Setup and Teardown -func setup(t *testing.T) func(t *testing.T) { - // Setup - t.Log("setup sub test") - - // For test db - t.Setenv("ENV", "TEST") - - /* - - Uncomment this when you are testing real data coming from test database. - db.Connect() - */ - - // Teardown - return func(t *testing.T) { - t.Log("teardown sub test") - } -} - -func TestGet` + strings.Title(moduleName) + `(t *testing.T) { - // Call Setup/Teardown - teardown := setup(t) - defer teardown(t) - - tokenData := token.GenerateToken("test") //Your token data - - router := router.Router() - - w := httptest.NewRecorder() - - values := map[string]interface{}{"token": tokenData} // this is the body in case you make a post, put - jsonValue, _ := json.Marshal(values) - - req, _ := http.NewRequest("GET", "/` + regex.StringToHyphen(moduleName) + `", bytes.NewBuffer(jsonValue)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", tokenData) - - // In case you use cookies like for example token - req.Header.Set("Cookie", "token="+tokenData+";") - - router.ServeHTTP(w, req) - - // Deserialize response body - var responseData struct { - Data []` + moduleName + `Model.` + strings.Title(moduleName) + ` - } - err := json.Unmarshal(w.Body.Bytes(), &responseData) - require.NoError(t, err) - - expected := ` + moduleName + `Model.` + strings.Title(moduleName) + `{ - Id: 1, - } + writeTemplateToFile( + "templates/module/test.go.tmpl", + "e2e/"+moduleName+"/get_"+moduleNameSnakeCase+"_test.go", + struct { + ModuleName string + CurrentDirName string + StructName string + KebabCase string + }{ + ModuleName: moduleName, + CurrentDirName: currentDirName, + StructName: strings.Title(moduleName), + KebabCase: regex.StringToHyphen(moduleName), + }, + ) - assert.Equal(t, []` + moduleName + `Model.` + strings.Title(moduleName) + `{expected}, responseData.Data) - assert.Equal(t, "200 OK", w.Result().Status) -}` - //Add data to e2e - testBytes := []byte(testString) - os.WriteFile("e2e/"+moduleName+"/get_"+moduleNameSnakeCase+"_test.go", testBytes, 0) } diff --git a/src/base/templates/base/.env.tmpl b/src/base/templates/base/.env.tmpl new file mode 100644 index 0000000..9632461 --- /dev/null +++ b/src/base/templates/base/.env.tmpl @@ -0,0 +1,2 @@ +PORT = {{ .Port }} +VERSION = {{ .Version }} diff --git a/src/base/templates/base/.gitignore.tmpl b/src/base/templates/base/.gitignore.tmpl new file mode 100644 index 0000000..e765a37 --- /dev/null +++ b/src/base/templates/base/.gitignore.tmpl @@ -0,0 +1,28 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with "go test -c" +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# Env +*.env +*.env.test + +# Tmp folder +tmp/ diff --git a/src/base/templates/base/README.tmpl b/src/base/templates/base/README.tmpl new file mode 100644 index 0000000..7d15aa5 --- /dev/null +++ b/src/base/templates/base/README.tmpl @@ -0,0 +1,69 @@ + + _____ _ + | __ \ | | + | | \/ ___ | |__ _____ __ + | | __ / _ \| '_ \ / _ \ \/ / + | |_\ \ (_) | | | | __/> < + \____/\___/|_| |_|\___/_/\_\ + +[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 +[circleci-url]: https://circleci.com/gh/nestjs/nest + +

A progressive Go framework for building efficient and scalable server-side applications.

+

+ +[![Test Status](https://github.com/illud/gohex/actions/workflows/go.yml/badge.svg)](https://github.com/illud/gohex/actions/workflows/go.yml/badge.svg) +[![GoDoc](https://pkg.go.dev/badge/github.com/illud/gohex?status.svg)](https://pkg.go.dev/github.com/illud/gohex?tab=doc) +[![Go Report Card](https://goreportcard.com/badge/github.com/illud/gohex)](https://goreportcard.com/report/github.com/illud/gohex) + +

+ + +## Description + +[Gohex](https://github.com/illud/gohex) CLI tool to create Hexagonal Architecture + Vertical Slicing. + +## Running the app + +` + "```" + `bash +# development +$ go run main.go + +# watch mode +# for more go to https://github.com/gravityblast/fresh +$ fresh + +# production mode +$ go build main.go +` + "```" + ` + +## Test + +` + "```" + `bash +# tests +$ go test -v ./... + +# to get coverage +$ go test -v -cover --coverprofile=coverage.out -coverpkg=./... ./... + +# to view test coverage on your browser +$ go tool cover -html=coverage.out + +# prints formatted test output, and a summary of the test run +# for more go to https://github.com/gotestyourself/gotestsum +$ gotestsum --format testname +` + "```" + ` + +## Support + +Gohex is an MIT-licensed open source project. + +## Stay in touch + +- Author - [Illud](https://github.com/illud) + +## License + +Nest is [MIT licensed](LICENSE). +"# Gohex" \ No newline at end of file diff --git a/src/base/templates/base/bcrypt.go.tmpl b/src/base/templates/base/bcrypt.go.tmpl new file mode 100644 index 0000000..25ae413 --- /dev/null +++ b/src/base/templates/base/bcrypt.go.tmpl @@ -0,0 +1,17 @@ +package bcrypt + +import ( + "golang.org/x/crypto/bcrypt" +) + +// hash password +func HashPassword(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10) + return string(bytes), err +} + +// check password +func CheckPasswordHash(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} diff --git a/src/base/templates/base/db.go.tmpl b/src/base/templates/base/db.go.tmpl new file mode 100644 index 0000000..4f9af75 --- /dev/null +++ b/src/base/templates/base/db.go.tmpl @@ -0,0 +1,34 @@ +package data + +import ( + "fmt" + tasksModel "github.com/{{ .FolderName }}/app/tasks/domain/models" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +var ( + // DB The database connection + db *gorm.DB +) + +// Connect to database +func Connect() { + // CONNECTION + dbCon, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) + if err != nil { + fmt.Println("DATABASE CONNECTION ERROR: ", err) + } + + // Migrate the schema + dbCon.AutoMigrate(&tasksModel.Task{}) + + // defer db.Close() + db = dbCon + fmt.Println("CONNECTED") +} + +func Client() *gorm.DB { + return db +} diff --git a/src/base/templates/base/env.go.tmpl b/src/base/templates/base/env.go.tmpl new file mode 100644 index 0000000..28e5f62 --- /dev/null +++ b/src/base/templates/base/env.go.tmpl @@ -0,0 +1,27 @@ +package env + +import ( + "os" + "strconv" + + "github.com/joho/godotenv" +) + +// Add here your .env data +type Env struct { + PORT int + VERSION string +} + +func Load() Env { + godotenv.Load() // This loads your .env + + // Converts port string to int + port, _ := strconv.Atoi(os.Getenv("PORT")) + + // Returns .env data in Env struct + return Env{ + PORT: port, + VERSION: os.Getenv("VERSION"), + } +} diff --git a/src/base/templates/base/errors.go.tmpl b/src/base/templates/base/errors.go.tmpl new file mode 100644 index 0000000..ed949b9 --- /dev/null +++ b/src/base/templates/base/errors.go.tmpl @@ -0,0 +1,21 @@ +package helpers + +import ( + "encoding/json" +) + +type Error struct { + Error string + Code int +} + +func ErrorJson(error string, code int) string { + jsondata := &Error{error, code} + encodejson, _ := json.Marshal(jsondata) + return string(encodejson) +} + +var BadRequest = ErrorJson("Bad Request", 400) +var Forbidden = ErrorJson("Forbidden", 403) +var NotFound = ErrorJson("Not Found", 404) +var Unauthorized = ErrorJson("Unauthorized", 401) diff --git a/src/base/templates/base/getTasks_test.go.tmpl b/src/base/templates/base/getTasks_test.go.tmpl new file mode 100644 index 0000000..9a86181 --- /dev/null +++ b/src/base/templates/base/getTasks_test.go.tmpl @@ -0,0 +1,76 @@ +package tasks_test + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + router "github.com/{{.FolderName}}/router" + token "github.com/{{.FolderName}}/adapters/jwt" + tasksModel "github.com/{{.FolderName}}/app/tasks/domain/models" + /* + - Uncomment this when you are testing real data coming from database. + db "github.com/{{.FolderName}}/adapters/database" + */ +) + +// Setup and Teardown +func setup(t *testing.T) func(t *testing.T) { + // Setup + t.Log("setup sub test") + + // For test db + t.Setenv("ENV", "TEST") + + /* + - Uncomment this when you are testing real data coming from test database. + db.Connect() + */ + + // Teardown + return func(t *testing.T) { + t.Log("teardown sub test") + } +} + +func TestGetTasks(t *testing.T) { + // Call Setup/Teardown + teardown := setup(t) + defer teardown(t) + + tokenData := token.GenerateToken("test") //Your token data + + router := router.Router() + + w := httptest.NewRecorder() + + values := map[string]interface{}{"token": tokenData} // this is the body in case you make a post, put + jsonValue, _ := json.Marshal(values) + + req, _ := http.NewRequest("GET", "/tasks", bytes.NewBuffer(jsonValue)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", tokenData) + + // In case you use cookies like for example token + req.Header.Set("Cookie", "token=" + tokenData + ";") + + router.ServeHTTP(w, req) + + // Deserialize response body + var responseData struct { + Data []tasksModel.Task + } + err := json.Unmarshal(w.Body.Bytes(), &responseData) + require.NoError(t, err) + + expected := tasksModel.Task{ + Id: 1, + } + + assert.Equal(t, []tasksModel.Task{expected}, responseData.Data) + assert.Equal(t, "200 OK", w.Result().Status) +} diff --git a/src/base/templates/base/jwt.go.tmpl b/src/base/templates/base/jwt.go.tmpl new file mode 100644 index 0000000..5e7a7b8 --- /dev/null +++ b/src/base/templates/base/jwt.go.tmpl @@ -0,0 +1,37 @@ +package jwt + +import ( + "fmt" + "github.com/dgrijalva/jwt-go" +) + +func GenerateToken(user string) string { + // Create a new token object, specifying signing method and the claims + // you would like it to contain. + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "user": user, + }) + + // Sign and get the complete encoded token as a string using the secret + tokenString, _ := token.SignedString([]byte("secret")) + + return tokenString +} + +func ValidateToken(validate string) string { + var tokenCheker string + tokenString := validate + claims := jwt.MapClaims{} + _, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { + return []byte("secret"), nil + }) + // ... error handling + if err != nil { + fmt.Println("Error: ", err) + tokenCheker = "Error" + } else { + tokenCheker = "Ok" + } + + return tokenCheker +} diff --git a/src/base/templates/base/main.go.tmpl b/src/base/templates/base/main.go.tmpl new file mode 100644 index 0000000..755b34b --- /dev/null +++ b/src/base/templates/base/main.go.tmpl @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "strconv" + //Uncomment next line when you want to connect to a database + //db "github.com/{{ .FolderName }}/adapters/database" + env "github.com/{{ .FolderName }}/env" + router "github.com/{{ .FolderName }}/router" +) + +//The next lines are for swagger docs +// @title {{ .FolderName }} +// @version version(1.0) +// @description Description of specifications +// @Precautions when using termsOfService specifications + +// @host localhost:5000 +// @BasePath / + +// @securityDefinitions.apikey BearerAuth +// @in header +// @name Authorization +func main() { + //Uncomment next line when you want to connect to a database + //Connect to database + //db.Connect() + + //Load .env port + port := strconv.Itoa(env.Load().PORT) + + if port == "" { + fmt.Println("$PORT must be set") + } + + router.Router().Run(":" + port) +} diff --git a/src/base/templates/base/router.go.tmpl b/src/base/templates/base/router.go.tmpl new file mode 100644 index 0000000..29ffb13 --- /dev/null +++ b/src/base/templates/base/router.go.tmpl @@ -0,0 +1,32 @@ +package router + +import ( + tasksController "github.com/{{ .FolderName }}/app/tasks/aplication" + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + + docs "github.com/{{ .FolderName }}/docs" + swaggerfiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" +) + +func Router() *gin.Engine { + //this sets gin to release mode + gin.SetMode(gin.ReleaseMode) + + router := gin.New() + + router.Use(cors.Default()) + + //SWAGGER + docs.SwaggerInfo.BasePath = "/" + router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) + + router.POST("/tasks", tasksController.CreateTasks) + router.GET("/tasks", tasksController.GetTasks) + router.GET("/tasks/:taskId", tasksController.GetOneTasks) + router.PUT("/tasks/:taskId", tasksController.UpdateTasks) + router.DELETE("/tasks/:taskId", tasksController.DeleteTasks) + + return router +} diff --git a/src/base/templates/base/tasks.controller.go.tmpl b/src/base/templates/base/tasks.controller.go.tmpl new file mode 100644 index 0000000..c76fdd8 --- /dev/null +++ b/src/base/templates/base/tasks.controller.go.tmpl @@ -0,0 +1,137 @@ +package tasks + +import ( + "strconv" + "net/http" + "github.com/gin-gonic/gin" + tasksService "github.com/{{ .FolderName }}/app/tasks/domain/services" + tasksDatabase "github.com/{{ .FolderName }}/app/tasks/infraestructure" + tasksModel "github.com/{{ .FolderName }}/app/tasks/domain/models" +) + +// Create a TasksDb instance +var tasksDb = tasksDatabase.NewTasksDb() + +// Create a Service instance using the TasksDb +var service = tasksService.NewService(tasksDb) + +// CreateTasks handles the creation of a new task. +// @Summary Create Tasks +// @Description Create Tasks +// @Tags Tasks +// @Security BearerAuth +// @Accept json +// @Produce json +// @Param Body body tasksModel.Task true "Body to create Tasks" +// @Success 200 {string} string "Task created successfully" +// @Router /tasks [post] +func CreateTasks(c *gin.Context) { + var task tasksModel.Task + if err := c.ShouldBindJSON(&task); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err := service.CreateTasks(task.Id, task.Title, task.Description) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": "task created"}) +} + +// GetTasks retrieves all tasks. +// @Summary Get Tasks +// @Description Get Tasks +// @Tags Tasks +// @Security BearerAuth +// @Accept json +// @Produce json +// @Success 200 {object} tasksModel.Task[] +// @Router /tasks [get] +func GetTasks(c *gin.Context) { + result, err := service.GetTasks() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": result}) +} + +// GetOneTasks retrieves a single task by taskId. +// @Summary Get Tasks +// @Description Get Tasks +// @Tags Tasks +// @Security BearerAuth +// @Param taskId path int true "taskId" +// @Accept json +// @Produce json +// @Success 200 {object} tasksModel.Task +// @Router /tasks/{taskId} [get] +func GetOneTasks(c *gin.Context) { + taskId, err := strconv.Atoi(c.Param("taskId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid taskId"}) + return + } + + result, err := service.GetOneTasks(taskId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": result}) +} + +// UpdateTasks handles updating an existing task by taskId. +// @Summary Update Tasks +// @Description Update Tasks +// @Tags Tasks +// @Security BearerAuth +// @Param taskId path int true "taskId" +// @Accept json +// @Produce json +// @Param Body body tasksModel.Task true "Body to update" +// @Success 200 {string} string "Task updated successfully" +// @Router /tasks/{taskId} [put] +func UpdateTasks(c *gin.Context) { + taskId := c.Param("taskId") + var task tasksModel.Task + if err := c.ShouldBindJSON(&task); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err := service.UpdateTasks(taskId, task.Title, task.Description) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": "task updated"}) +} + +// DeleteTasks handles deleting a task by taskId. +// @Summary Delete Tasks +// @Description Delete Tasks +// @Tags Tasks +// @Security BearerAuth +// @Param taskId path int true "taskId" +// @Accept json +// @Produce json +// @Success 200 {string} string "Task deleted successfully" +// @Router /tasks/{taskId} [delete] +func DeleteTasks(c *gin.Context) { + taskId := c.Param("taskId") + + err := service.DeleteTasks(taskId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": "task deleted"}) +} diff --git a/src/base/templates/base/tasks.db.go.tmpl b/src/base/templates/base/tasks.db.go.tmpl new file mode 100644 index 0000000..4ee734a --- /dev/null +++ b/src/base/templates/base/tasks.db.go.tmpl @@ -0,0 +1,58 @@ +package infraestructure + +import ( + tasksModel "github.com/{{ .FolderName }}/app/tasks/domain/models" + // uncomment this and change _ for db when you are making database queries + _ "github.com/{{ .FolderName }}/adapters/database" + "errors" +) + +type TasksDb struct { + // Add any dependencies or configurations related to the TasksRepository here, if needed. +} + +func NewTasksDb() *TasksDb { + // Initialize any dependencies and configurations for the TasksRepository here, if needed. + return &TasksDb{} +} + +func (t *TasksDb) CreateTasks(taskId int, title string, description string) error { + if taskId == 0 { + return errors.New("taskId is required") + } + + var task tasksModel.Task + task.Id = 1 + task.Title = title + task.Description = description + + return nil +} + +func (t *TasksDb) GetTasks() ([]tasksModel.Task, error) { + var tasks []tasksModel.Task + tasks = append(tasks, tasksModel.Task{Id: 1, Title: "Hello", Description: "World"}) + return tasks, nil +} + +func (t *TasksDb) GetOneTasks(taskId int) (tasksModel.Task, error) { + task := tasksModel.Task{Id: taskId, Title: "Sample Task", Description: "Sample Description"} + if task.Id == 0 { + return tasksModel.Task{}, errors.New("Task not found") + } + return task, nil +} + +func (t *TasksDb) UpdateTasks(taskId string, title string, description string) error { + if taskId == "" { + return errors.New("taskId is required") + } + return nil +} + +func (t *TasksDb) DeleteTasks(taskId string) error { + if taskId == "" { + return errors.New("taskId is required") + } + return nil +} diff --git a/src/base/templates/base/tasks.model.go.tmpl b/src/base/templates/base/tasks.model.go.tmpl new file mode 100644 index 0000000..29abdf7 --- /dev/null +++ b/src/base/templates/base/tasks.model.go.tmpl @@ -0,0 +1,7 @@ +package models + +type Task struct { + Id int + Title string + Description string +} diff --git a/src/base/templates/base/tasks.repository.go.tmpl b/src/base/templates/base/tasks.repository.go.tmpl new file mode 100644 index 0000000..fb3892c --- /dev/null +++ b/src/base/templates/base/tasks.repository.go.tmpl @@ -0,0 +1,13 @@ +package repositories + +import ( + tasksModel "github.com/{{ .FolderName }}/app/tasks/domain/models" +) + +type ITasks interface { + CreateTasks(taskId int, title string, description string) error + GetTasks() ([]tasksModel.Task, error) + GetOneTasks(taskId int) (tasksModel.Task, error) + UpdateTasks(taskId string, title string, description string) error + DeleteTasks(taskId string) error +} diff --git a/src/base/templates/base/tasks.service.go.tmpl b/src/base/templates/base/tasks.service.go.tmpl new file mode 100644 index 0000000..3688a52 --- /dev/null +++ b/src/base/templates/base/tasks.service.go.tmpl @@ -0,0 +1,56 @@ +package services + +import ( + tasksModel "github.com/{{ .FolderName }}/app/tasks/domain/models" + tasksInterface "github.com/{{ .FolderName }}/app/tasks/domain/repositories" +) + +type Service struct { + tasksRepository tasksInterface.ITasks +} + +func NewService(tasksRepository tasksInterface.ITasks) *Service { + return &Service{ + tasksRepository: tasksRepository, + } +} + +func (s *Service) CreateTasks(taskId int, title string, description string) error { + err := s.tasksRepository.CreateTasks(taskId, title, description) + if err != nil { + return err + } + return nil +} + +func (s *Service) GetTasks() ([]tasksModel.Task, error) { + tasks, err := s.tasksRepository.GetTasks() + if err != nil { + return nil, err + } + return tasks, nil +} + +func (s *Service) GetOneTasks(taskId int) (tasksModel.Task, error) { + task, err := s.tasksRepository.GetOneTasks(taskId) + if err != nil { + return tasksModel.Task{}, err + } + return task, nil +} + +func (s *Service) UpdateTasks(taskId string, title string, description string) error { + err := s.tasksRepository.UpdateTasks(taskId, title, description) + if err != nil { + return err + } + return nil +} + +func (s *Service) DeleteTasks(taskId string) error { + err := s.tasksRepository.DeleteTasks(taskId) + if err != nil { + return err + } + return nil +} diff --git a/src/base/templates/base/tracker.json.tmpl b/src/base/templates/base/tracker.json.tmpl new file mode 100644 index 0000000..309e689 --- /dev/null +++ b/src/base/templates/base/tracker.json.tmpl @@ -0,0 +1,8 @@ +{ + "modules": [ + { + "moduleName": "{{ .ModuleName }}", + "endpointName": "{{ .EndpointName }}" + } + ] +} diff --git a/src/base/templates/database/gorm.tmpl b/src/base/templates/database/gorm.tmpl new file mode 100644 index 0000000..24842b7 --- /dev/null +++ b/src/base/templates/database/gorm.tmpl @@ -0,0 +1,25 @@ +package database + +import ( + "fmt" + + _ "github.com/go-sql-driver/mysql" + "github.com/jinzhu/gorm" +) + +var ( + db *gorm.DB +) + +func Connect() { + dbCon, err := gorm.Open("mysql", "databaseUsername:databasePassword@tcp(127.0.0.1:3306)/yourDatabaseTablename?charset=utf8mb4&parseTime=True&loc=Local") + if err != nil { + fmt.Println("DATABASE CONNECTION ERROR: ", err) + } + db = dbCon + fmt.Println("CONNECTED") +} + +func Client() *gorm.DB { + return db +} diff --git a/src/base/templates/database/mysql.tmpl b/src/base/templates/database/mysql.tmpl new file mode 100644 index 0000000..f5d2baa --- /dev/null +++ b/src/base/templates/database/mysql.tmpl @@ -0,0 +1,25 @@ +package database + +import ( + "database/sql" + "fmt" + + _ "github.com/go-sql-driver/mysql" +) + +var ( + db *sql.DB +) + +func Connect() { + dbCon, err := sql.Open("mysql", "databaseUsername:databasePassword@tcp(localhost:3306)/yourDatabaseTablename") + if err != nil { + fmt.Println("DATABASE CONNECTION ERROR: ", err) + } + db = dbCon + fmt.Println("CONNECTED") +} + +func Client() *sql.DB { + return db +} diff --git a/src/base/templates/endpoint/post/controller.post.go.tmpl b/src/base/templates/endpoint/post/controller.post.go.tmpl new file mode 100644 index 0000000..8e588e7 --- /dev/null +++ b/src/base/templates/endpoint/post/controller.post.go.tmpl @@ -0,0 +1,28 @@ +// Post {{.StructName}} +// @Summary Post {{.StructName}} +// @Schemes +// @Description Post {{.StructName}} +// @Tags {{.StructName}} +// @Security BearerAuth +// @Accept json +// @Produce json +// @Param Body body {{.ModuleName}}Model.{{.StructName}} true "Body to create {{.StructName}}" +// @Success 200 +// @Router /{{.EndpointName}}/{{.MethodNameLower}} [Post] +func {{.MethodFuncName}}(c *gin.Context) { + var {{.ModuleName}} {{.ModuleName}}Model.{{.StructName}} + if err := c.ShouldBindJSON(&{{.ModuleName}}); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + err := service.{{.MethodFuncName}}({{.ModuleName}}) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "data": "{{.ModuleName}} created", + }) +} diff --git a/src/base/templates/endpoint/post/infraestructure.post.go.tmpl b/src/base/templates/endpoint/post/infraestructure.post.go.tmpl new file mode 100644 index 0000000..c3406c5 --- /dev/null +++ b/src/base/templates/endpoint/post/infraestructure.post.go.tmpl @@ -0,0 +1,4 @@ +func ({{.ModuleInitial}} {{.StructName}}Db) {{.MethodFuncName}}({{.ModuleName}} {{.ModuleName}}Model.{{.StructName}}) error { + // Implement your creation logic here + return nil +} diff --git a/src/base/templates/endpoint/post/repository.go.tmpl b/src/base/templates/endpoint/post/repository.go.tmpl new file mode 100644 index 0000000..fb89db0 --- /dev/null +++ b/src/base/templates/endpoint/post/repository.go.tmpl @@ -0,0 +1,2 @@ + {{.MethodFuncName}}({{.ModuleName}} {{.ModuleName}}Model.{{.StructName}}) error +} diff --git a/src/base/templates/endpoint/post/service.post.go.tmpl b/src/base/templates/endpoint/post/service.post.go.tmpl new file mode 100644 index 0000000..f07c6b2 --- /dev/null +++ b/src/base/templates/endpoint/post/service.post.go.tmpl @@ -0,0 +1,7 @@ +func (s *Service) {{.MethodFuncName}}({{.ModuleName}} {{.ModuleName}}Model.{{.StructName}}) error { + err := s.{{.ModuleName}}Repository.{{.MethodFuncName}}({{.ModuleName}}) + if err != nil { + return err + } + return nil +} diff --git a/src/base/templates/module/controller.go.tmpl b/src/base/templates/module/controller.go.tmpl new file mode 100644 index 0000000..ec38eb1 --- /dev/null +++ b/src/base/templates/module/controller.go.tmpl @@ -0,0 +1,83 @@ +package aplication + +import ( + "strconv" + "net/http" + "github.com/gin-gonic/gin" + {{.ModuleName}}Services "github.com/{{.CurrentDirName}}/app/{{.ModuleName}}/domain/services" + {{.ModuleName}}Database "github.com/{{.CurrentDirName}}/app/{{.ModuleName}}/infraestructure" + {{.ModuleName}}Model "github.com/{{.CurrentDirName}}/app/{{.ModuleName}}/domain/models" +) + +var {{.ModuleName}}Db = {{.ModuleName}}Database.New{{.ModuleNameTitle}}Db() +var service = {{.ModuleName}}Services.NewService({{.ModuleName}}Db) + +func Create{{.ModuleNameTitle}}(c *gin.Context) { + var {{.ModuleName}} {{.ModuleName}}Model.{{.ModuleNameTitle}} + if err := c.ShouldBindJSON(&{{.ModuleName}}); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + err := service.Create{{.ModuleNameTitle}}({{.ModuleName}}) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"data": "{{.ModuleName}} created"}) +} + +func Get{{.ModuleNameTitle}}(c *gin.Context) { + result, err := service.Get{{.ModuleNameTitle}}() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"data": result}) +} + +func GetOne{{.ModuleNameTitle}}(c *gin.Context) { + {{.ModuleCamel}}Id, err := strconv.Atoi(c.Param("{{.ModuleCamel}}Id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + result, err := service.GetOne{{.ModuleNameTitle}}({{.ModuleCamel}}Id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"data": result}) +} + +func Update{{.ModuleNameTitle}}(c *gin.Context) { + var {{.ModuleName}} {{.ModuleName}}Model.{{.ModuleNameTitle}} + if err := c.ShouldBindJSON(&{{.ModuleName}}); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + {{.ModuleCamel}}Id, err := strconv.Atoi(c.Param("{{.ModuleCamel}}Id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + err = service.Update{{.ModuleNameTitle}}({{.ModuleCamel}}Id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"data": "{{.ModuleName}} updated"}) +} + +func Delete{{.ModuleNameTitle}}(c *gin.Context) { + {{.ModuleCamel}}Id, err := strconv.Atoi(c.Param("{{.ModuleCamel}}Id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + err = service.Delete{{.ModuleNameTitle}}({{.ModuleCamel}}Id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"data": "{{.ModuleName}} deleted"}) +} diff --git a/src/base/templates/module/infraestructure.go.tmpl b/src/base/templates/module/infraestructure.go.tmpl new file mode 100644 index 0000000..9580edd --- /dev/null +++ b/src/base/templates/module/infraestructure.go.tmpl @@ -0,0 +1,39 @@ +package infraestructure + +import ( + {{ .ModuleName }}Model "github.com/{{ .CurrentDirName }}/app/{{ .ModuleName }}/domain/models" + // uncomment this and change _ for db when you are making database queries + _ "github.com/{{ .CurrentDirName }}/adapters/database" +) + +type {{ .StructName }}Db struct { + // Add any dependencies or configurations related to the repository here if needed. +} + +func New{{ .StructName }}Db() *{{ .StructName }}Db { + return &{{ .StructName }}Db{} +} + +var {{ .ModuleName }} []{{ .ModuleName }}Model.{{ .StructName }} + +func ({{ .FirstChar }} *{{ .StructName }}Db) Create{{ .StructName }}({{ .ModuleName }} {{ .ModuleName }}Model.{{ .StructName }}) error { + return nil +} + +func ({{ .FirstChar }} *{{ .StructName }}Db) Get{{ .StructName }}() ([]{{ .ModuleName }}Model.{{ .StructName }}, error) { + var {{ .ModuleName }} []{{ .ModuleName }}Model.{{ .StructName }} + {{ .ModuleName }} = append({{ .ModuleName }}, {{ .ModuleName }}Model.{{ .StructName }}{Id: 1}) + return {{ .ModuleName }}, nil +} + +func ({{ .FirstChar }} *{{ .StructName }}Db) GetOne{{ .StructName }}({{ .ParamName }}Id int) ({{ .ModuleName }}Model.{{ .StructName }}, error) { + return {{ .ModuleName }}Model.{{ .StructName }}{Id: {{ .ParamName }}Id}, nil +} + +func ({{ .FirstChar }} *{{ .StructName }}Db) Update{{ .StructName }}({{ .ParamName }}Id int) error { + return nil +} + +func ({{ .FirstChar }} *{{ .StructName }}Db) Delete{{ .StructName }}({{ .ParamName }}Id int) error { + return nil +} diff --git a/src/base/templates/module/model.go.tmpl b/src/base/templates/module/model.go.tmpl new file mode 100644 index 0000000..a6a869d --- /dev/null +++ b/src/base/templates/module/model.go.tmpl @@ -0,0 +1,5 @@ +package models + +type {{ .StructName }} struct { + Id int +} diff --git a/src/base/templates/module/repository.go.tmpl b/src/base/templates/module/repository.go.tmpl new file mode 100644 index 0000000..bcdd010 --- /dev/null +++ b/src/base/templates/module/repository.go.tmpl @@ -0,0 +1,13 @@ +package repositories + +import ( + {{ .ModuleName }}Model "github.com/{{ .CurrentDirName }}/app/{{ .ModuleName }}/domain/models" +) + +type I{{ .StructName }} interface { + Create{{ .StructName }}({{ .ModuleName }} {{ .ModuleName }}Model.{{ .StructName }}) error + Get{{ .StructName }}() ([]{{ .ModuleName }}Model.{{ .StructName }}, error) + GetOne{{ .StructName }}({{ .IdName }} int) ({{ .ModuleName }}Model.{{ .StructName }}, error) + Update{{ .StructName }}({{ .IdName }} int) error + Delete{{ .StructName }}({{ .IdName }} int) error +} diff --git a/src/base/templates/module/service.go.tmpl b/src/base/templates/module/service.go.tmpl new file mode 100644 index 0000000..f392390 --- /dev/null +++ b/src/base/templates/module/service.go.tmpl @@ -0,0 +1,56 @@ +package services + +import ( + {{ .ModuleName }}Model "github.com/{{ .CurrentDirName }}/app/{{ .ModuleName }}/domain/models" + {{ .ModuleName }}Interface "github.com/{{ .CurrentDirName }}/app/{{ .ModuleName }}/domain/repositories" +) + +type Service struct { + {{ .ModuleName }}Repository {{ .ModuleName }}Interface.I{{ .StructName }} +} + +func NewService({{ .ModuleName }}Repository {{ .ModuleName }}Interface.I{{ .StructName }}) *Service { + return &Service{ + {{ .ModuleName }}Repository: {{ .ModuleName }}Repository, + } +} + +func (s *Service) Create{{ .StructName }}({{ .ModuleName }} {{ .ModuleName }}Model.{{ .StructName }}) error { + err := s.{{ .ModuleName }}Repository.Create{{ .StructName }}({{ .ModuleName }}) + if err != nil { + return err + } + return nil +} + +func (s *Service) Get{{ .StructName }}() ([]{{ .ModuleName }}Model.{{ .StructName }}, error) { + result, err := s.{{ .ModuleName }}Repository.Get{{ .StructName }}() + if err != nil { + return nil, err + } + return result, nil +} + +func (s *Service) GetOne{{ .StructName }}({{ .ParamName }}Id int) ({{ .ModuleName }}Model.{{ .StructName }}, error) { + result, err := s.{{ .ModuleName }}Repository.GetOne{{ .StructName }}({{ .ParamName }}Id) + if err != nil { + return {{ .ModuleName }}Model.{{ .StructName }}{}, err + } + return result, nil +} + +func (s *Service) Update{{ .StructName }}({{ .ParamName }}Id int) error { + err := s.{{ .ModuleName }}Repository.Update{{ .StructName }}({{ .ParamName }}Id) + if err != nil { + return err + } + return nil +} + +func (s *Service) Delete{{ .StructName }}({{ .ParamName }}Id int) error { + err := s.{{ .ModuleName }}Repository.Delete{{ .StructName }}({{ .ParamName }}Id) + if err != nil { + return err + } + return nil +} diff --git a/src/base/templates/module/test.go.tmpl b/src/base/templates/module/test.go.tmpl new file mode 100644 index 0000000..f9e3585 --- /dev/null +++ b/src/base/templates/module/test.go.tmpl @@ -0,0 +1,67 @@ +package {{ .ModuleName }}_test + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + router "github.com/{{ .CurrentDirName }}/router" + token "github.com/{{ .CurrentDirName }}/adapters/jwt" + {{ .ModuleName }}Model "github.com/{{ .CurrentDirName }}/app/{{ .ModuleName }}/domain/models" + /* + - Uncomment this when you are testing real data coming from database. + db "github.com/{{ .CurrentDirName }}/infraestructure" + */ +) + +// Setup and Teardown +func setup(t *testing.T) func(t *testing.T) { + t.Log("setup sub test") + t.Setenv("ENV", "TEST") + + /* + - Uncomment this when you are testing real data coming from test database. + db.Connect() + */ + + return func(t *testing.T) { + t.Log("teardown sub test") + } +} + +func TestGet{{ .StructName }}(t *testing.T) { + teardown := setup(t) + defer teardown(t) + + tokenData := token.GenerateToken("test") + + router := router.Router() + w := httptest.NewRecorder() + + values := map[string]interface{}{"token": tokenData} + jsonValue, _ := json.Marshal(values) + + req, _ := http.NewRequest("GET", "/{{ .KebabCase }}", bytes.NewBuffer(jsonValue)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", tokenData) + req.Header.Set("Cookie", "token="+tokenData+";") + + router.ServeHTTP(w, req) + + var responseData struct { + Data []{{ .ModuleName }}Model.{{ .StructName }} + } + err := json.Unmarshal(w.Body.Bytes(), &responseData) + require.NoError(t, err) + + expected := {{ .ModuleName }}Model.{{ .StructName }}{ + Id: 1, + } + + assert.Equal(t, []{{ .ModuleName }}Model.{{ .StructName }}{expected}, responseData.Data) + assert.Equal(t, "200 OK", w.Result().Status) +} diff --git a/src/cli/cli.go b/src/cli/cli.go index 2bb7173..5f99251 100644 --- a/src/cli/cli.go +++ b/src/cli/cli.go @@ -255,11 +255,6 @@ func Command() { bar.Add(1) time.Sleep(40 * time.Millisecond) - //helpers/async.go - os.Create(folderName + "/helpers/async.go") - bar.Add(1) - time.Sleep(40 * time.Millisecond) - //helpers/errors.go os.Create(folderName + "/helpers/errors.go") bar.Add(1) @@ -343,7 +338,7 @@ func Command() { installDependencies.Dir = folderName //SWAG INIT - swagInit := exec.Command("cmd", "/c", "swag init") + swagInit := exec.Command("cmd", "/c", "swag init --parseDependency github.com/volatiletech/null/v8") swagInit.Dir = folderName _, err = swagInit.Output() @@ -360,7 +355,7 @@ func Command() { // fmt.Println(string(installDependenciesOut)) //INSTALL TEST DEPENDENCIES - installTestDependencies := exec.Command("cmd", "/c", "go get -t ./...") + installTestDependencies := exec.Command("cmd", "/c", "go mod tidy") installTestDependencies.Dir = folderName _, err = installTestDependencies.Output() @@ -430,7 +425,7 @@ func Command() { installDependencies.Dir = folderName //SWAG INIT - swagInit := exec.Command("sh", "/c", "swag init") + swagInit := exec.Command("sh", "/c", "swag init --parseDependency github.com/volatiletech/null/v8") swagInit.Dir = folderName _, err = swagInit.Output() @@ -447,7 +442,7 @@ func Command() { // fmt.Println(string(installDependenciesOut)) //INSTALL TEST DEPENDENCIES - installTestDependencies := exec.Command("sh", "/c", "go get -t ./...") + installTestDependencies := exec.Command("sh", "/c", "go mod tidy") installTestDependencies.Dir = folderName _, err = installTestDependencies.Output() @@ -562,7 +557,7 @@ func Command() { //SWAG INIT Windows if runtime.GOOS == "windows" { - swagInit := exec.Command("cmd", "/c", "swag init") + swagInit := exec.Command("cmd", "/c", "swag init --parseDependency github.com/volatiletech/null/v8") _, err := swagInit.Output() if err != nil { @@ -573,7 +568,7 @@ func Command() { //SWAG INIT Linux if runtime.GOOS == "linux" { - swagInit := exec.Command("sh", "/c", "swag init") + swagInit := exec.Command("sh", "/c", "swag init --parseDependency github.com/volatiletech/null/v8") _, err := swagInit.Output() if err != nil { @@ -629,71 +624,6 @@ func Command() { if flagName == "gorm" { base.BaseDbClient("gorm") } - // if flagName == "prisma" { - // base.BaseDbClient("prisma") - // //create/schema.prisma - // os.MkdirAll("data/prisma/db", os.ModePerm) - - // os.Create("data/prisma/schema.prisma") - - // fmt.Println("") - - // fmt.Println("To get this up and running in your database, we use the Prisma migration tool migrate to create and migrate our database:") - // fmt.Println("sync the database with your schema go run github.com/prisma/prisma-client-go migrate dev --name init") - // fmt.Println("After the migration, the Prisma Client Go client is automatically generated in your project. If you just want to re-generate the client, run go run github.com/prisma/prisma-client-go generate.") - - // fmt.Println("For more visit https://github.com/prisma/prisma-client-go") - - // //Install db DEPENDENCIES - // if runtime.GOOS == "windows" { - // fmt.Println("") - // fmt.Println("executing go get github.com/prisma/prisma-client-go") - - // installDependencies := exec.Command("cmd", "/c", "go get github.com/prisma/prisma-client-go") - - // //INSTALL DEPENDENCIES - // _, err = installDependencies.Output() - // if err != nil { - // os.Stderr.WriteString(err.Error()) - // } - // // fmt.Println(string(installDependenciesOut)) - - // //Run prisma init - // installPrismaDependencies := exec.Command("cmd", "/c", "go run github.com/prisma/prisma-client-go migrate dev --name init") - - // //INSTALL DEPENDENCIES - // _, err = installPrismaDependencies.Output() - // if err != nil { - // os.Stderr.WriteString(err.Error()) - // } - // // fmt.Println(string(installPrismaDependenciesOut)) - // } - - // if runtime.GOOS == "linux" { - // fmt.Println("") - // fmt.Println("executing go get github.com/prisma/prisma-client-go") - - // installDependencies := exec.Command("sh", "/c", "go get github.com/prisma/prisma-client-go.") - - // //INSTALL DEPENDENCIES - // _, err = installDependencies.Output() - // if err != nil { - // os.Stderr.WriteString(err.Error()) - // } - // // fmt.Println(string(installDependenciesOut)) - - // //Run prisma init - // installPrismaDependencies := exec.Command("sh", "/c", "go run github.com/prisma/prisma-client-go migrate dev --name init") - - // //INSTALL DEPENDENCIES - // _, err = installPrismaDependencies.Output() - // if err != nil { - // os.Stderr.WriteString(err.Error()) - // } - // // fmt.Println(string(installPrismaDependenciesOut)) - // } - - // } //Install db DEPENDENCIES if runtime.GOOS == "windows" {