Creat Service BPJS
This commit is contained in:
@@ -209,3 +209,5 @@ const products = await axios.get('/api/v1/products');
|
|||||||
|
|
||||||
---
|
---
|
||||||
**Total waktu setup: 5 menit** | **Generate CRUD: 30 detik** | **Testing: Langsung di Swagger**
|
**Total waktu setup: 5 menit** | **Generate CRUD: 30 detik** | **Testing: Langsung di Swagger**
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
bpjsPesertaHandlers "api-service/internal/handlers/bpjs"
|
bpjsPesertaHandlers "api-service/internal/handlers/bpjs/reference"
|
||||||
retribusiHandlers "api-service/internal/handlers/retribusi"
|
retribusiHandlers "api-service/internal/handlers/retribusi"
|
||||||
|
|
||||||
"api-service/internal/config"
|
"api-service/internal/config"
|
||||||
|
|||||||
689
tools/generate-bpjs-handler.go
Normal file
689
tools/generate-bpjs-handler.go
Normal file
@@ -0,0 +1,689 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BpjsHandlerData contains template data for BPJS handler generation
|
||||||
|
type BpjsHandlerData struct {
|
||||||
|
Name string
|
||||||
|
NameLower string
|
||||||
|
NamePlural string
|
||||||
|
ModuleName string
|
||||||
|
Category string
|
||||||
|
HasGet bool
|
||||||
|
HasGetByID bool
|
||||||
|
HasPost bool
|
||||||
|
HasPut bool
|
||||||
|
HasDelete bool
|
||||||
|
HasStats bool
|
||||||
|
HasFilter bool
|
||||||
|
Timestamp string
|
||||||
|
Endpoints []BpjsEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// BpjsEndpoint represents a BPJS API endpoint configuration
|
||||||
|
type BpjsEndpoint struct {
|
||||||
|
Name string
|
||||||
|
Method string
|
||||||
|
Path string
|
||||||
|
Description string
|
||||||
|
Parameters []EndpointParam
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointParam represents an endpoint parameter
|
||||||
|
type EndpointParam struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Required bool
|
||||||
|
Description string
|
||||||
|
Location string // "path", "query", "body"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Println("Usage: go run generate-bpjs-handler.go [category/]entity [methods]")
|
||||||
|
fmt.Println("Example: go run generate-bpjs-handler.go reference/peserta get getbyid")
|
||||||
|
fmt.Println("Example: go run generate-bpjs-handler.go peserta get getbyid")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse entity input (could be "entity" or "category/entity")
|
||||||
|
entityInput := os.Args[1]
|
||||||
|
var category, entityName string
|
||||||
|
|
||||||
|
if strings.Contains(entityInput, "/") {
|
||||||
|
parts := strings.Split(entityInput, "/")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
fmt.Println("Invalid format. Use: category/entity or entity")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
category = parts[0]
|
||||||
|
entityName = strings.Title(parts[1]) // PascalCase entity name
|
||||||
|
} else {
|
||||||
|
category = ""
|
||||||
|
entityName = strings.Title(entityInput) // PascalCase entity name
|
||||||
|
}
|
||||||
|
|
||||||
|
methods := []string{}
|
||||||
|
if len(os.Args) > 2 {
|
||||||
|
methods = os.Args[2:]
|
||||||
|
} else {
|
||||||
|
// Default methods if none specified
|
||||||
|
methods = []string{"get", "getbyid"}
|
||||||
|
}
|
||||||
|
|
||||||
|
entityLower := strings.ToLower(entityName)
|
||||||
|
entityPlural := entityLower + "s"
|
||||||
|
data := BpjsHandlerData{
|
||||||
|
Name: entityName,
|
||||||
|
NameLower: entityLower,
|
||||||
|
NamePlural: entityPlural,
|
||||||
|
ModuleName: "api-service",
|
||||||
|
Category: category,
|
||||||
|
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set methods based on arguments
|
||||||
|
for _, m := range methods {
|
||||||
|
switch strings.ToLower(m) {
|
||||||
|
case "get":
|
||||||
|
data.HasGet = true
|
||||||
|
case "getbyid":
|
||||||
|
data.HasGetByID = true
|
||||||
|
case "post":
|
||||||
|
data.HasPost = true
|
||||||
|
case "put":
|
||||||
|
data.HasPut = true
|
||||||
|
case "delete":
|
||||||
|
data.HasDelete = true
|
||||||
|
case "stats":
|
||||||
|
data.HasStats = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define default endpoints based on entity
|
||||||
|
data.Endpoints = generateDefaultEndpoints(data)
|
||||||
|
|
||||||
|
// Create directories based on category
|
||||||
|
var handlerDir, modelDir string
|
||||||
|
if category != "" {
|
||||||
|
handlerDir = filepath.Join("internal", "handlers", "bpjs", category)
|
||||||
|
modelDir = filepath.Join("internal", "models", "bpjs", category)
|
||||||
|
} else {
|
||||||
|
handlerDir = filepath.Join("internal", "handlers", "bpjs", entityLower)
|
||||||
|
modelDir = filepath.Join("internal", "models", "bpjs", entityLower)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range []string{handlerDir, modelDir} {
|
||||||
|
if err := os.MkdirAll(d, 0755); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate files
|
||||||
|
generateBpjsHandlerFile(data, handlerDir)
|
||||||
|
generateBpjsModelFile(data, modelDir)
|
||||||
|
updateBpjsRoutesFile(data)
|
||||||
|
|
||||||
|
fmt.Printf("✅ Successfully generated BPJS handler: %s\n", entityName)
|
||||||
|
if category != "" {
|
||||||
|
fmt.Printf("📁 Category: %s\n", category)
|
||||||
|
}
|
||||||
|
fmt.Printf("📁 Handler: %s\n", filepath.Join(handlerDir, entityLower+".go"))
|
||||||
|
fmt.Printf("📁 Model: %s\n", filepath.Join(modelDir, entityLower+".go"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateDefaultEndpoints creates default endpoints based on entity type
|
||||||
|
func generateDefaultEndpoints(data BpjsHandlerData) []BpjsEndpoint {
|
||||||
|
endpoints := []BpjsEndpoint{}
|
||||||
|
|
||||||
|
switch data.NameLower {
|
||||||
|
case "peserta":
|
||||||
|
endpoints = append(endpoints, BpjsEndpoint{
|
||||||
|
Name: "GetByNIK",
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/Peserta/nik/%s/tglSEP/%s",
|
||||||
|
Description: "Get participant data by NIK and service date",
|
||||||
|
Parameters: []EndpointParam{
|
||||||
|
{Name: "nik", Type: "string", Required: true, Description: "NIK KTP", Location: "path"},
|
||||||
|
{Name: "tglSEP", Type: "string", Required: true, Description: "Service date (yyyy-MM-dd)", Location: "path"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
case "poli":
|
||||||
|
endpoints = append(endpoints, BpjsEndpoint{
|
||||||
|
Name: "GetAll",
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/referensi/poli",
|
||||||
|
Description: "Get all poli reference data",
|
||||||
|
Parameters: []EndpointParam{},
|
||||||
|
})
|
||||||
|
|
||||||
|
case "diagnosa":
|
||||||
|
endpoints = append(endpoints, BpjsEndpoint{
|
||||||
|
Name: "GetAll",
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/referensi/diagnosa",
|
||||||
|
Description: "Get all diagnosa reference data",
|
||||||
|
Parameters: []EndpointParam{},
|
||||||
|
})
|
||||||
|
|
||||||
|
case "provider":
|
||||||
|
endpoints = append(endpoints, BpjsEndpoint{
|
||||||
|
Name: "GetByJenis",
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/referensi/faskes/%s/%s",
|
||||||
|
Description: "Get provider data by type and level",
|
||||||
|
Parameters: []EndpointParam{
|
||||||
|
{Name: "jnsFaskes", Type: "string", Required: true, Description: "Jenis Faskes (1=Faskes 1, 2=Faskes 2)", Location: "path"},
|
||||||
|
{Name: "kdFaskes", Type: "string", Required: true, Description: "Kode Faskes", Location: "path"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Generic endpoint
|
||||||
|
endpoints = append(endpoints, BpjsEndpoint{
|
||||||
|
Name: "GetAll",
|
||||||
|
Method: "GET",
|
||||||
|
Path: fmt.Sprintf("/referensi/%s", data.NameLower),
|
||||||
|
Description: fmt.Sprintf("Get all %s reference data", data.NameLower),
|
||||||
|
Parameters: []EndpointParam{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= BPJS HANDLER GENERATION =====================
|
||||||
|
|
||||||
|
func generateBpjsHandlerFile(data BpjsHandlerData, handlerDir string) {
|
||||||
|
// Determine import path based on category
|
||||||
|
var modelsImportPath string
|
||||||
|
if data.Category != "" {
|
||||||
|
modelsImportPath = `models "` + data.ModuleName + `/internal/models/bpjs/` + data.Category + `"`
|
||||||
|
} else {
|
||||||
|
modelsImportPath = `models "` + data.ModuleName + `/internal/models/bpjs/` + data.NameLower + `"`
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerContent := `package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
"` + data.ModuleName + `/internal/config"
|
||||||
|
services "` + data.ModuleName + `/internal/services/bpjs"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ` + data.Name + `Handler handles BPJS ` + data.NameLower + ` operations
|
||||||
|
type ` + data.Name + `Handler struct {
|
||||||
|
bpjsService services.VClaimService
|
||||||
|
}
|
||||||
|
|
||||||
|
// New` + data.Name + `Handler creates a new ` + data.Name + `Handler instance
|
||||||
|
func New` + data.Name + `Handler(cfg config.BpjsConfig) *` + data.Name + `Handler {
|
||||||
|
return &` + data.Name + `Handler{
|
||||||
|
bpjsService: services.NewService(cfg),
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// Add methods based on endpoints
|
||||||
|
for _, endpoint := range data.Endpoints {
|
||||||
|
handlerContent += generateBpjsEndpointMethod(data, endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add helper methods
|
||||||
|
handlerContent += generateBpjsHelperMethods(data)
|
||||||
|
|
||||||
|
writeFile(filepath.Join(handlerDir, data.NameLower+".go"), handlerContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateBpjsEndpointMethod(data BpjsHandlerData, endpoint BpjsEndpoint) string {
|
||||||
|
methodName := endpoint.Name
|
||||||
|
|
||||||
|
// Generate parameter extraction
|
||||||
|
paramExtraction := ""
|
||||||
|
paramValidation := ""
|
||||||
|
pathParams := []string{}
|
||||||
|
|
||||||
|
for _, param := range endpoint.Parameters {
|
||||||
|
if param.Location == "path" {
|
||||||
|
paramExtraction += "\t" + param.Name + ` := c.Param("` + param.Name + `")` + "\n"
|
||||||
|
pathParams = append(pathParams, param.Name)
|
||||||
|
|
||||||
|
if param.Required {
|
||||||
|
paramValidation += `
|
||||||
|
if ` + param.Name + ` == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "` + strings.Title(param.Name) + ` parameter is required",
|
||||||
|
"message": "` + param.Description + ` tidak boleh kosong",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add date validation if parameter contains date
|
||||||
|
if strings.Contains(param.Name, "tgl") || strings.Contains(param.Name, "date") {
|
||||||
|
paramValidation += `
|
||||||
|
// Validate date format
|
||||||
|
if _, err := time.Parse("2006-01-02", ` + param.Name + `); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "Invalid date format",
|
||||||
|
"message": "Format tanggal harus yyyy-MM-dd",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate endpoint URL building
|
||||||
|
endpointURL := endpoint.Path
|
||||||
|
if len(pathParams) > 0 {
|
||||||
|
endpointURL = `fmt.Sprintf("` + endpoint.Path + `", ` + strings.Join(pathParams, ", ") + `)`
|
||||||
|
} else {
|
||||||
|
endpointURL = `"` + endpoint.Path + `"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate route path for documentation
|
||||||
|
routePath := endpoint.Path
|
||||||
|
for _, param := range endpoint.Parameters {
|
||||||
|
if param.Location == "path" {
|
||||||
|
routePath = strings.Replace(routePath, "%s", "{"+param.Name+"}", 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate category prefix for router documentation
|
||||||
|
categoryPrefix := ""
|
||||||
|
if data.Category != "" {
|
||||||
|
categoryPrefix = "/" + data.Category
|
||||||
|
}
|
||||||
|
|
||||||
|
swaggerParams := generateSwaggerParams(endpoint.Parameters)
|
||||||
|
|
||||||
|
return `
|
||||||
|
|
||||||
|
// ` + methodName + ` godoc
|
||||||
|
// @Summary ` + endpoint.Description + `
|
||||||
|
// @Description ` + endpoint.Description + `
|
||||||
|
// @Tags bpjs` + categoryPrefix + `
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json` + swaggerParams + `
|
||||||
|
// @Success 200 {object} models.` + data.Name + `Response "Success response"
|
||||||
|
// @Failure 400 {object} map[string]interface{} "Bad request"
|
||||||
|
// @Failure 404 {object} map[string]interface{} "Data not found"
|
||||||
|
// @Failure 500 {object} map[string]interface{} "Internal server error"
|
||||||
|
// @Router /api/v1/bpjs` + categoryPrefix + routePath + ` [` + strings.ToLower(endpoint.Method) + `]
|
||||||
|
func (h *` + data.Name + `Handler) ` + methodName + `(c *gin.Context) {
|
||||||
|
` + paramExtraction + paramValidation + `
|
||||||
|
// Create context with timeout
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Build endpoint URL
|
||||||
|
endpoint := ` + endpointURL + `
|
||||||
|
|
||||||
|
// Call BPJS service
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := h.bpjsService.Get(ctx, endpoint, &result); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"error": "Failed to fetch ` + data.NameLower + ` data",
|
||||||
|
"message": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return successful response
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "Data ` + data.NameLower + ` berhasil diambil",
|
||||||
|
"data": result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSwaggerParams(params []EndpointParam) string {
|
||||||
|
result := ""
|
||||||
|
for _, param := range params {
|
||||||
|
required := "false"
|
||||||
|
if param.Required {
|
||||||
|
required = "true"
|
||||||
|
}
|
||||||
|
result += `
|
||||||
|
// @Param ` + param.Name + ` ` + param.Location + ` ` + param.Type + ` ` + required + ` "` + param.Description + `"`
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateBpjsHelperMethods(data BpjsHandlerData) string {
|
||||||
|
handlerName := data.Name
|
||||||
|
|
||||||
|
return `
|
||||||
|
|
||||||
|
// Helper methods for error handling and response formatting
|
||||||
|
|
||||||
|
// handleBPJSError handles BPJS service errors and returns appropriate HTTP responses
|
||||||
|
func (h *` + handlerName + `Handler) handleBPJSError(c *gin.Context, err error, operation string) {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"error": fmt.Sprintf("Failed to %s", operation),
|
||||||
|
"message": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateDateFormat validates if the date string is in yyyy-MM-dd format
|
||||||
|
func (h *` + handlerName + `Handler) validateDateFormat(dateStr string) error {
|
||||||
|
_, err := time.Parse("2006-01-02", dateStr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildSuccessResponse builds a standardized success response
|
||||||
|
func (h *` + handlerName + `Handler) buildSuccessResponse(message string, data interface{}) gin.H {
|
||||||
|
return gin.H{
|
||||||
|
"message": message,
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= BPJS MODEL GENERATION =====================
|
||||||
|
|
||||||
|
func generateBpjsModelFile(data BpjsHandlerData, modelDir string) {
|
||||||
|
modelContent := `package models
|
||||||
|
|
||||||
|
// ` + data.Name + `Response represents the response structure for BPJS ` + data.NameLower + ` data
|
||||||
|
type ` + data.Name + `Response struct {
|
||||||
|
Message string ` + "`json:\"message\"`" + `
|
||||||
|
Data map[string]interface{} ` + "`json:\"data\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// ` + data.Name + `RawResponse represents the raw response structure from BPJS API
|
||||||
|
type ` + data.Name + `RawResponse struct {
|
||||||
|
MetaData struct {
|
||||||
|
Code string ` + "`json:\"code\"`" + `
|
||||||
|
Message string ` + "`json:\"message\"`" + `
|
||||||
|
} ` + "`json:\"metaData\"`" + `
|
||||||
|
Response interface{} ` + "`json:\"response\"`" + `
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// Add entity-specific models
|
||||||
|
switch data.NameLower {
|
||||||
|
case "peserta":
|
||||||
|
modelContent += generatePesertaModels()
|
||||||
|
case "poli":
|
||||||
|
modelContent += generatePoliModels()
|
||||||
|
case "diagnosa":
|
||||||
|
modelContent += generateDiagnosaModels()
|
||||||
|
case "provider":
|
||||||
|
modelContent += generateProviderModels()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add common request/response models
|
||||||
|
modelContent += generateCommonBpjsModels(data)
|
||||||
|
|
||||||
|
writeFile(filepath.Join(modelDir, data.NameLower+".go"), modelContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generatePesertaModels() string {
|
||||||
|
return `
|
||||||
|
|
||||||
|
// PesertaRequest represents the request structure for BPJS participant search
|
||||||
|
type PesertaRequest struct {
|
||||||
|
NIK string ` + "`json:\"nik\" binding:\"required\"`" + `
|
||||||
|
TglSEP string ` + "`json:\"tglSEP\" binding:\"required\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// PesertaData represents the participant data structure
|
||||||
|
type PesertaData struct {
|
||||||
|
NoKartu string ` + "`json:\"noKartu\"`" + `
|
||||||
|
NIK string ` + "`json:\"nik\"`" + `
|
||||||
|
Nama string ` + "`json:\"nama\"`" + `
|
||||||
|
Pisa string ` + "`json:\"pisa\"`" + `
|
||||||
|
Sex string ` + "`json:\"sex\"`" + `
|
||||||
|
TglLahir string ` + "`json:\"tglLahir\"`" + `
|
||||||
|
Pob string ` + "`json:\"pob\"`" + `
|
||||||
|
KdProvider string ` + "`json:\"kdProvider\"`" + `
|
||||||
|
NmProvider string ` + "`json:\"nmProvider\"`" + `
|
||||||
|
KelasRawat string ` + "`json:\"kelasRawat\"`" + `
|
||||||
|
Keterangan string ` + "`json:\"keterangan\"`" + `
|
||||||
|
NoTelepon string ` + "`json:\"noTelepon\"`" + `
|
||||||
|
Alamat string ` + "`json:\"alamat\"`" + `
|
||||||
|
KdPos string ` + "`json:\"kdPos\"`" + `
|
||||||
|
Pekerjaan string ` + "`json:\"pekerjaan\"`" + `
|
||||||
|
StatusKawin string ` + "`json:\"statusKawin\"`" + `
|
||||||
|
TglCetakKartu string ` + "`json:\"tglCetakKartu\"`" + `
|
||||||
|
TglTAT string ` + "`json:\"tglTAT\"`" + `
|
||||||
|
TglTMT string ` + "`json:\"tglTMT\"`" + `
|
||||||
|
ProvUmum struct {
|
||||||
|
KdProvider string ` + "`json:\"kdProvider\"`" + `
|
||||||
|
NmProvider string ` + "`json:\"nmProvider\"`" + `
|
||||||
|
} ` + "`json:\"provUmum\"`" + `
|
||||||
|
JenisPeserta struct {
|
||||||
|
KdJenisPeserta string ` + "`json:\"kdJenisPeserta\"`" + `
|
||||||
|
NmJenisPeserta string ` + "`json:\"nmJenisPeserta\"`" + `
|
||||||
|
} ` + "`json:\"jenisPeserta\"`" + `
|
||||||
|
KelasTanggungan struct {
|
||||||
|
KdKelas string ` + "`json:\"kdKelas\"`" + `
|
||||||
|
NmKelas string ` + "`json:\"nmKelas\"`" + `
|
||||||
|
} ` + "`json:\"kelasTanggungan\"`" + `
|
||||||
|
Informasi struct {
|
||||||
|
Dinsos string ` + "`json:\"dinsos\"`" + `
|
||||||
|
NoSKTM string ` + "`json:\"noSKTM\"`" + `
|
||||||
|
ProlanisPRB string ` + "`json:\"prolanisPRB\"`" + `
|
||||||
|
} ` + "`json:\"informasi\"`" + `
|
||||||
|
Cob struct {
|
||||||
|
NoAsuransi string ` + "`json:\"noAsuransi\"`" + `
|
||||||
|
NmAsuransi string ` + "`json:\"nmAsuransi\"`" + `
|
||||||
|
TglTAT string ` + "`json:\"tglTAT\"`" + `
|
||||||
|
TglTMT string ` + "`json:\"tglTMT\"`" + `
|
||||||
|
} ` + "`json:\"cob\"`" + `
|
||||||
|
HakKelas struct {
|
||||||
|
Kode string ` + "`json:\"kode\"`" + `
|
||||||
|
Nama string ` + "`json:\"nama\"`" + `
|
||||||
|
} ` + "`json:\"hakKelas\"`" + `
|
||||||
|
Mr struct {
|
||||||
|
NoMR string ` + "`json:\"noMR\"`" + `
|
||||||
|
NoTelepon string ` + "`json:\"noTelepon\"`" + `
|
||||||
|
} ` + "`json:\"mr\"`" + `
|
||||||
|
ProvRujuk struct {
|
||||||
|
KdProvider string ` + "`json:\"kdProvider\"`" + `
|
||||||
|
NmProvider string ` + "`json:\"nmProvider\"`" + `
|
||||||
|
} ` + "`json:\"provRujuk\"`" + `
|
||||||
|
StatusPeserta struct {
|
||||||
|
Kode string ` + "`json:\"kode\"`" + `
|
||||||
|
Nama string ` + "`json:\"nama\"`" + `
|
||||||
|
} ` + "`json:\"statusPeserta\"`" + `
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func generatePoliModels() string {
|
||||||
|
return `
|
||||||
|
|
||||||
|
// PoliData represents the poli reference data structure
|
||||||
|
type PoliData struct {
|
||||||
|
KdPoli string ` + "`json:\"kdPoli\"`" + `
|
||||||
|
NmPoli string ` + "`json:\"nmPoli\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// PoliListResponse represents the response structure for poli list
|
||||||
|
type PoliListResponse struct {
|
||||||
|
List []PoliData ` + "`json:\"list\"`" + `
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateDiagnosaModels() string {
|
||||||
|
return `
|
||||||
|
|
||||||
|
// DiagnosaData represents the diagnosa reference data structure
|
||||||
|
type DiagnosaData struct {
|
||||||
|
KdDiag string ` + "`json:\"kdDiag\"`" + `
|
||||||
|
NmDiag string ` + "`json:\"nmDiag\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiagnosaListResponse represents the response structure for diagnosa list
|
||||||
|
type DiagnosaListResponse struct {
|
||||||
|
Diagnosa []DiagnosaData ` + "`json:\"diagnosa\"`" + `
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateProviderModels() string {
|
||||||
|
return `
|
||||||
|
|
||||||
|
// ProviderData represents the provider reference data structure
|
||||||
|
type ProviderData struct {
|
||||||
|
KdProvider string ` + "`json:\"kdProvider\"`" + `
|
||||||
|
NmProvider string ` + "`json:\"nmProvider\"`" + `
|
||||||
|
JnsFaskes string ` + "`json:\"jnsFaskes\"`" + `
|
||||||
|
Alamat string ` + "`json:\"alamat\"`" + `
|
||||||
|
NoTelp string ` + "`json:\"noTelp\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderListResponse represents the response structure for provider list
|
||||||
|
type ProviderListResponse struct {
|
||||||
|
Faskes []ProviderData ` + "`json:\"faskes\"`" + `
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCommonBpjsModels(data BpjsHandlerData) string {
|
||||||
|
return `
|
||||||
|
|
||||||
|
// ErrorResponse represents error response structure
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Error string ` + "`json:\"error\"`" + `
|
||||||
|
Message string ` + "`json:\"message\"`" + `
|
||||||
|
Code int ` + "`json:\"code,omitempty\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// BPJSMetaData represents BPJS API metadata structure
|
||||||
|
type BPJSMetaData struct {
|
||||||
|
Code string ` + "`json:\"code\"`" + `
|
||||||
|
Message string ` + "`json:\"message\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
// ` + data.Name + `Filter represents filter parameters for ` + data.NameLower + ` queries
|
||||||
|
type ` + data.Name + `Filter struct {
|
||||||
|
NIK *string ` + "`form:\"nik\" json:\"nik,omitempty\"`" + `
|
||||||
|
TglSEP *string ` + "`form:\"tglSEP\" json:\"tglSEP,omitempty\"`" + `
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= ROUTES GENERATION =====================
|
||||||
|
|
||||||
|
func updateBpjsRoutesFile(data BpjsHandlerData) {
|
||||||
|
routesFile := "internal/routes/v1/routes.go"
|
||||||
|
content, err := os.ReadFile(routesFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("⚠️ Could not read routes.go: %v\n", err)
|
||||||
|
fmt.Printf("📝 Please manually add these routes to your routes.go file:\n")
|
||||||
|
printBpjsRoutesSample(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
routesContent := string(content)
|
||||||
|
|
||||||
|
// Determine import path based on category
|
||||||
|
var importPath string
|
||||||
|
if data.Category != "" {
|
||||||
|
importPath = data.ModuleName + "/internal/handlers/bpjs/" + data.Category
|
||||||
|
} else {
|
||||||
|
importPath = data.ModuleName + "/internal/handlers/bpjs/" + data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add import
|
||||||
|
importPattern := `bpjs` + strings.Title(data.NameLower) + `Handlers "` + importPath + `"`
|
||||||
|
|
||||||
|
if !strings.Contains(routesContent, importPattern) {
|
||||||
|
importToAdd := "\t" + `bpjs` + strings.Title(data.NameLower) + `Handlers "` + importPath + `"`
|
||||||
|
if strings.Contains(routesContent, "import (") {
|
||||||
|
routesContent = strings.Replace(routesContent, "import (",
|
||||||
|
"import (\n"+importToAdd, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate routes
|
||||||
|
newRoutes := "\t\t// BPJS " + data.Name + " endpoints\n"
|
||||||
|
newRoutes += "\t\tbpjs" + strings.Title(data.NameLower) + "Handler := bpjs" + strings.Title(data.NameLower) + "Handlers.New" + data.Name + "Handler(cfg.Bpjs)\n"
|
||||||
|
|
||||||
|
// Add routes based on endpoints
|
||||||
|
for _, endpoint := range data.Endpoints {
|
||||||
|
routePath := endpoint.Path
|
||||||
|
for _, param := range endpoint.Parameters {
|
||||||
|
if param.Location == "path" {
|
||||||
|
routePath = strings.Replace(routePath, "%s", ":"+param.Name, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
methodName := endpoint.Name
|
||||||
|
routePrefix := "/bpjs"
|
||||||
|
if data.Category != "" {
|
||||||
|
routePrefix = "/bpjs/" + data.Category
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoutes += "\t\tv1." + strings.ToUpper(endpoint.Method) + `("` + routePrefix + routePath + `", bpjs` + strings.Title(data.NameLower) + "Handler." + methodName + ")\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoutes += "\n"
|
||||||
|
insertMarker := "\t\tprotected := v1.Group(\"/\")"
|
||||||
|
if strings.Contains(routesContent, insertMarker) {
|
||||||
|
if !strings.Contains(routesContent, "New"+data.Name+"Handler") {
|
||||||
|
routesContent = strings.Replace(routesContent, insertMarker,
|
||||||
|
newRoutes+insertMarker, 1)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("✅ Routes for BPJS %s already exist, skipping...\n", data.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(routesFile, []byte(routesContent), 0644); err != nil {
|
||||||
|
fmt.Printf("Error writing routes.go: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("✅ Updated routes.go with BPJS %s endpoints\n", data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printBpjsRoutesSample(data BpjsHandlerData) {
|
||||||
|
fmt.Printf(`
|
||||||
|
// BPJS %s endpoints
|
||||||
|
bpjs%sHandler := bpjs%sHandlers.New%sHandler(cfg.Bpjs)
|
||||||
|
`, data.Name, strings.Title(data.NameLower), strings.Title(data.NameLower), data.Name)
|
||||||
|
|
||||||
|
for _, endpoint := range data.Endpoints {
|
||||||
|
routePath := endpoint.Path
|
||||||
|
for _, param := range endpoint.Parameters {
|
||||||
|
if param.Location == "path" {
|
||||||
|
routePath = strings.Replace(routePath, "%s", ":"+param.Name, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
routePrefix := "/bpjs"
|
||||||
|
if data.Category != "" {
|
||||||
|
routePrefix = "/bpjs/" + data.Category
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\tv1.%s(\"%s%s\", bpjs%sHandler.%s)\n",
|
||||||
|
strings.ToUpper(endpoint.Method), routePrefix, routePath, strings.Title(data.NameLower), endpoint.Name)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= UTILITY FUNCTIONS =====================
|
||||||
|
|
||||||
|
func writeFile(filename, content string) {
|
||||||
|
if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
|
||||||
|
fmt.Printf("❌ Error creating file %s: %v\n", filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("✅ Generated: %s\n", filename)
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ type HandlerData struct {
|
|||||||
Name string
|
Name string
|
||||||
NameLower string
|
NameLower string
|
||||||
NamePlural string
|
NamePlural string
|
||||||
|
Category string
|
||||||
|
CategoryPath string
|
||||||
ModuleName string
|
ModuleName string
|
||||||
TableName string
|
TableName string
|
||||||
HasGet bool
|
HasGet bool
|
||||||
@@ -27,12 +29,16 @@ type HandlerData struct {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
fmt.Println("Usage: go run generate-handler.go entity [methods]")
|
fmt.Println("Usage: go run generate-handler.go [category/]entity [methods]")
|
||||||
fmt.Println("Example: go run generate-handler.go order get post put delete stats")
|
fmt.Println("Examples:")
|
||||||
|
fmt.Println(" go run generate-handler.go product get post")
|
||||||
|
fmt.Println(" go run generate-handler.go reference/peserta get post put delete")
|
||||||
|
fmt.Println(" go run generate-handler.go master/wilayah get")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
entityName := strings.Title(os.Args[1]) // PascalCase entity name
|
// Parse entity path (could be "entity" or "category/entity")
|
||||||
|
entityPath := os.Args[1]
|
||||||
methods := []string{}
|
methods := []string{}
|
||||||
if len(os.Args) > 2 {
|
if len(os.Args) > 2 {
|
||||||
methods = os.Args[2:]
|
methods = os.Args[2:]
|
||||||
@@ -41,14 +47,40 @@ func main() {
|
|||||||
methods = []string{"get", "post", "put", "delete"}
|
methods = []string{"get", "post", "put", "delete"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse category and entity
|
||||||
|
var category, entityName string
|
||||||
|
if strings.Contains(entityPath, "/") {
|
||||||
|
parts := strings.Split(entityPath, "/")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
fmt.Println("❌ Error: Invalid path format. Use 'category/entity' or just 'entity'")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
category = parts[0]
|
||||||
|
entityName = parts[1]
|
||||||
|
} else {
|
||||||
|
category = ""
|
||||||
|
entityName = entityPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format names
|
||||||
|
entityName = strings.Title(entityName) // PascalCase entity name
|
||||||
entityLower := strings.ToLower(entityName)
|
entityLower := strings.ToLower(entityName)
|
||||||
entityPlural := entityLower + "s"
|
entityPlural := entityLower + "s"
|
||||||
tableName := "data_" + entityLower
|
|
||||||
|
// Table name: include category if exists
|
||||||
|
var tableName string
|
||||||
|
if category != "" {
|
||||||
|
tableName = "data_" + category + "_" + entityLower
|
||||||
|
} else {
|
||||||
|
tableName = "data_" + entityLower
|
||||||
|
}
|
||||||
|
|
||||||
data := HandlerData{
|
data := HandlerData{
|
||||||
Name: entityName,
|
Name: entityName,
|
||||||
NameLower: entityLower,
|
NameLower: entityLower,
|
||||||
NamePlural: entityPlural,
|
NamePlural: entityPlural,
|
||||||
|
Category: category,
|
||||||
|
CategoryPath: category,
|
||||||
ModuleName: "api-service",
|
ModuleName: "api-service",
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
HasPagination: true,
|
HasPagination: true,
|
||||||
@@ -77,10 +109,20 @@ func main() {
|
|||||||
data.HasStats = true
|
data.HasStats = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create directories
|
// Create directories with improved logic
|
||||||
handlerDir := filepath.Join("internal", "handlers", entityLower)
|
var handlerDir, modelDir string
|
||||||
modelDir := filepath.Join("internal", "models", entityLower)
|
|
||||||
|
if category != "" {
|
||||||
|
// Dengan kategori: internal/handlers/category/
|
||||||
|
handlerDir = filepath.Join("internal", "handlers", category)
|
||||||
|
modelDir = filepath.Join("internal", "models", category)
|
||||||
|
} else {
|
||||||
|
// Tanpa kategori: langsung internal/handlers/
|
||||||
|
handlerDir = filepath.Join("internal", "handlers")
|
||||||
|
modelDir = filepath.Join("internal", "models")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buat direktori
|
||||||
for _, d := range []string{handlerDir, modelDir} {
|
for _, d := range []string{handlerDir, modelDir} {
|
||||||
if err := os.MkdirAll(d, 0755); err != nil {
|
if err := os.MkdirAll(d, 0755); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -93,20 +135,29 @@ func main() {
|
|||||||
updateRoutesFile(data)
|
updateRoutesFile(data)
|
||||||
|
|
||||||
fmt.Printf("✅ Successfully generated handler: %s\n", entityName)
|
fmt.Printf("✅ Successfully generated handler: %s\n", entityName)
|
||||||
|
if category != "" {
|
||||||
|
fmt.Printf("📁 Category: %s\n", category)
|
||||||
|
}
|
||||||
fmt.Printf("📁 Handler: %s\n", filepath.Join(handlerDir, entityLower+".go"))
|
fmt.Printf("📁 Handler: %s\n", filepath.Join(handlerDir, entityLower+".go"))
|
||||||
fmt.Printf("📁 Model: %s\n", filepath.Join(modelDir, entityLower+".go"))
|
fmt.Printf("📁 Model: %s\n", filepath.Join(modelDir, entityLower+".go"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= HANDLER GENERATION =====================
|
// ================= HANDLER GENERATION =====================
|
||||||
|
|
||||||
func generateHandlerFile(data HandlerData, handlerDir string) {
|
func generateHandlerFile(data HandlerData, handlerDir string) {
|
||||||
// FIXED: Proper string formatting
|
// Build import path based on category
|
||||||
|
var modelsImportPath string
|
||||||
|
if data.Category != "" {
|
||||||
|
modelsImportPath = data.ModuleName + "/internal/models/" + data.Category
|
||||||
|
} else {
|
||||||
|
modelsImportPath = data.ModuleName + "/internal/models"
|
||||||
|
}
|
||||||
|
|
||||||
handlerContent := `package handlers
|
handlerContent := `package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"` + data.ModuleName + `/internal/config"
|
"` + data.ModuleName + `/internal/config"
|
||||||
"` + data.ModuleName + `/internal/database"
|
"` + data.ModuleName + `/internal/database"
|
||||||
models "` + data.ModuleName + `/internal/models/` + data.NameLower + `"
|
models "` + modelsImportPath + `"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -123,8 +174,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db database.Service
|
db database.Service
|
||||||
once sync.Once
|
once sync.Once
|
||||||
validate *validator.Validate
|
validate *validator.Validate
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -156,35 +207,47 @@ func New` + data.Name + `Handler() *` + data.Name + `Handler {
|
|||||||
return &` + data.Name + `Handler{
|
return &` + data.Name + `Handler{
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
|
|
||||||
// Add methods
|
// Add methods
|
||||||
if data.HasGet {
|
if data.HasGet {
|
||||||
handlerContent += generateGetMethods(data)
|
handlerContent += generateGetMethods(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPost {
|
if data.HasPost {
|
||||||
handlerContent += generateCreateMethod(data)
|
handlerContent += generateCreateMethod(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPut {
|
if data.HasPut {
|
||||||
handlerContent += generateUpdateMethod(data)
|
handlerContent += generateUpdateMethod(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasDelete {
|
if data.HasDelete {
|
||||||
handlerContent += generateDeleteMethod(data)
|
handlerContent += generateDeleteMethod(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasStats {
|
if data.HasStats {
|
||||||
handlerContent += generateStatsMethod(data)
|
handlerContent += generateStatsMethod(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add helper methods
|
// Add helper methods
|
||||||
handlerContent += generateHelperMethods(data)
|
handlerContent += generateHelperMethods(data)
|
||||||
|
|
||||||
writeFile(filepath.Join(handlerDir, data.NameLower+".go"), handlerContent)
|
writeFile(filepath.Join(handlerDir, data.NameLower+".go"), handlerContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateGetMethods(data HandlerData) string {
|
func generateGetMethods(data HandlerData) string {
|
||||||
// FIXED: Proper formatting without printf placeholders
|
// Build route path based on category
|
||||||
|
var routePath, singleRoutePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routePath = data.Category + "/" + data.NamePlural
|
||||||
|
singleRoutePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
routePath = data.NamePlural
|
||||||
|
singleRoutePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
|
||||||
// Get` + data.Name + ` godoc
|
// Get` + data.Name + ` godoc
|
||||||
// @Summary Get ` + data.NameLower + ` with pagination and optional aggregation
|
// @Summary Get ` + data.NameLower + ` with pagination and optional aggregation
|
||||||
// @Description Returns a paginated list of ` + data.NamePlural + ` with optional summary statistics
|
// @Description Returns a paginated list of ` + data.NamePlural + ` with optional summary statistics
|
||||||
@@ -199,7 +262,7 @@ func generateGetMethods(data HandlerData) string {
|
|||||||
// @Success 200 {object} models.` + data.Name + `GetResponse "Success response"
|
// @Success 200 {object} models.` + data.Name + `GetResponse "Success response"
|
||||||
// @Failure 400 {object} models.ErrorResponse "Bad request"
|
// @Failure 400 {object} models.ErrorResponse "Bad request"
|
||||||
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
// @Router /api/v1/` + data.NamePlural + ` [get]
|
// @Router /api/v1/` + routePath + ` [get]
|
||||||
func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) {
|
func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) {
|
||||||
// Parse pagination parameters
|
// Parse pagination parameters
|
||||||
limit, offset, err := h.parsePaginationParams(c)
|
limit, offset, err := h.parsePaginationParams(c)
|
||||||
@@ -225,12 +288,12 @@ func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) {
|
|||||||
|
|
||||||
// Execute concurrent operations
|
// Execute concurrent operations
|
||||||
var (
|
var (
|
||||||
items []models.` + data.Name + `
|
items []models.` + data.Name + `
|
||||||
total int
|
total int
|
||||||
aggregateData *models.AggregateData
|
aggregateData *models.AggregateData
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
errChan = make(chan error, 3)
|
errChan = make(chan error, 3)
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fetch total count
|
// Fetch total count
|
||||||
@@ -244,7 +307,7 @@ func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Fetch main data - FIXED: Proper method name
|
// Fetch main data
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
@@ -290,8 +353,8 @@ func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) {
|
|||||||
meta := h.calculateMeta(limit, offset, total)
|
meta := h.calculateMeta(limit, offset, total)
|
||||||
response := models.` + data.Name + `GetResponse{
|
response := models.` + data.Name + `GetResponse{
|
||||||
Message: "Data ` + data.NameLower + ` berhasil diambil",
|
Message: "Data ` + data.NameLower + ` berhasil diambil",
|
||||||
Data: items,
|
Data: items,
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
}
|
}
|
||||||
|
|
||||||
if includeAggregation && aggregateData != nil {
|
if includeAggregation && aggregateData != nil {
|
||||||
@@ -312,7 +375,7 @@ func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) {
|
|||||||
// @Failure 400 {object} models.ErrorResponse "Invalid ID format"
|
// @Failure 400 {object} models.ErrorResponse "Invalid ID format"
|
||||||
// @Failure 404 {object} models.ErrorResponse "` + data.Name + ` not found"
|
// @Failure 404 {object} models.ErrorResponse "` + data.Name + ` not found"
|
||||||
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
// @Router /api/v1/` + data.NameLower + `/{id} [get]
|
// @Router /api/v1/` + singleRoutePath + `/{id} [get]
|
||||||
func (h *` + data.Name + `Handler) Get` + data.Name + `ByID(c *gin.Context) {
|
func (h *` + data.Name + `Handler) Get` + data.Name + `ByID(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
|
|
||||||
@@ -343,16 +406,23 @@ func (h *` + data.Name + `Handler) Get` + data.Name + `ByID(c *gin.Context) {
|
|||||||
|
|
||||||
response := models.` + data.Name + `GetByIDResponse{
|
response := models.` + data.Name + `GetByIDResponse{
|
||||||
Message: "` + data.Name + ` details retrieved successfully",
|
Message: "` + data.Name + ` details retrieved successfully",
|
||||||
Data: item,
|
Data: item,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateCreateMethod(data HandlerData) string {
|
func generateCreateMethod(data HandlerData) string {
|
||||||
|
var routePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routePath = data.Category + "/" + data.NamePlural
|
||||||
|
} else {
|
||||||
|
routePath = data.NamePlural
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
|
||||||
// Create` + data.Name + ` godoc
|
// Create` + data.Name + ` godoc
|
||||||
// @Summary Create ` + data.NameLower + `
|
// @Summary Create ` + data.NameLower + `
|
||||||
// @Description Creates a new ` + data.NameLower + ` record
|
// @Description Creates a new ` + data.NameLower + ` record
|
||||||
@@ -363,9 +433,10 @@ func generateCreateMethod(data HandlerData) string {
|
|||||||
// @Success 201 {object} models.` + data.Name + `CreateResponse "` + data.Name + ` created successfully"
|
// @Success 201 {object} models.` + data.Name + `CreateResponse "` + data.Name + ` created successfully"
|
||||||
// @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
|
// @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
|
||||||
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
// @Router /api/v1/` + data.NamePlural + ` [post]
|
// @Router /api/v1/` + routePath + ` [post]
|
||||||
func (h *` + data.Name + `Handler) Create` + data.Name + `(c *gin.Context) {
|
func (h *` + data.Name + `Handler) Create` + data.Name + `(c *gin.Context) {
|
||||||
var req models.` + data.Name + `CreateRequest
|
var req models.` + data.Name + `CreateRequest
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
|
h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -394,16 +465,23 @@ func (h *` + data.Name + `Handler) Create` + data.Name + `(c *gin.Context) {
|
|||||||
|
|
||||||
response := models.` + data.Name + `CreateResponse{
|
response := models.` + data.Name + `CreateResponse{
|
||||||
Message: "` + data.Name + ` berhasil dibuat",
|
Message: "` + data.Name + ` berhasil dibuat",
|
||||||
Data: item,
|
Data: item,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusCreated, response)
|
c.JSON(http.StatusCreated, response)
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateUpdateMethod(data HandlerData) string {
|
func generateUpdateMethod(data HandlerData) string {
|
||||||
|
var singleRoutePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
singleRoutePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
singleRoutePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
|
||||||
// Update` + data.Name + ` godoc
|
// Update` + data.Name + ` godoc
|
||||||
// @Summary Update ` + data.NameLower + `
|
// @Summary Update ` + data.NameLower + `
|
||||||
// @Description Updates an existing ` + data.NameLower + ` record
|
// @Description Updates an existing ` + data.NameLower + ` record
|
||||||
@@ -416,7 +494,7 @@ func generateUpdateMethod(data HandlerData) string {
|
|||||||
// @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
|
// @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
|
||||||
// @Failure 404 {object} models.ErrorResponse "` + data.Name + ` not found"
|
// @Failure 404 {object} models.ErrorResponse "` + data.Name + ` not found"
|
||||||
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
// @Router /api/v1/` + data.NameLower + `/{id} [put]
|
// @Router /api/v1/` + singleRoutePath + `/{id} [put]
|
||||||
func (h *` + data.Name + `Handler) Update` + data.Name + `(c *gin.Context) {
|
func (h *` + data.Name + `Handler) Update` + data.Name + `(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
|
|
||||||
@@ -462,16 +540,23 @@ func (h *` + data.Name + `Handler) Update` + data.Name + `(c *gin.Context) {
|
|||||||
|
|
||||||
response := models.` + data.Name + `UpdateResponse{
|
response := models.` + data.Name + `UpdateResponse{
|
||||||
Message: "` + data.Name + ` berhasil diperbarui",
|
Message: "` + data.Name + ` berhasil diperbarui",
|
||||||
Data: item,
|
Data: item,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateDeleteMethod(data HandlerData) string {
|
func generateDeleteMethod(data HandlerData) string {
|
||||||
|
var singleRoutePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
singleRoutePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
singleRoutePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
|
||||||
// Delete` + data.Name + ` godoc
|
// Delete` + data.Name + ` godoc
|
||||||
// @Summary Delete ` + data.NameLower + `
|
// @Summary Delete ` + data.NameLower + `
|
||||||
// @Description Soft deletes a ` + data.NameLower + ` by setting status to 'deleted'
|
// @Description Soft deletes a ` + data.NameLower + ` by setting status to 'deleted'
|
||||||
@@ -483,7 +568,7 @@ func generateDeleteMethod(data HandlerData) string {
|
|||||||
// @Failure 400 {object} models.ErrorResponse "Invalid ID format"
|
// @Failure 400 {object} models.ErrorResponse "Invalid ID format"
|
||||||
// @Failure 404 {object} models.ErrorResponse "` + data.Name + ` not found"
|
// @Failure 404 {object} models.ErrorResponse "` + data.Name + ` not found"
|
||||||
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
// @Router /api/v1/` + data.NameLower + `/{id} [delete]
|
// @Router /api/v1/` + singleRoutePath + `/{id} [delete]
|
||||||
func (h *` + data.Name + `Handler) Delete` + data.Name + `(c *gin.Context) {
|
func (h *` + data.Name + `Handler) Delete` + data.Name + `(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
|
|
||||||
@@ -514,16 +599,23 @@ func (h *` + data.Name + `Handler) Delete` + data.Name + `(c *gin.Context) {
|
|||||||
|
|
||||||
response := models.` + data.Name + `DeleteResponse{
|
response := models.` + data.Name + `DeleteResponse{
|
||||||
Message: "` + data.Name + ` berhasil dihapus",
|
Message: "` + data.Name + ` berhasil dihapus",
|
||||||
ID: id,
|
ID: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateStatsMethod(data HandlerData) string {
|
func generateStatsMethod(data HandlerData) string {
|
||||||
|
var routePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routePath = data.Category + "/" + data.NamePlural
|
||||||
|
} else {
|
||||||
|
routePath = data.NamePlural
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
|
||||||
// Get` + data.Name + `Stats godoc
|
// Get` + data.Name + `Stats godoc
|
||||||
// @Summary Get ` + data.NameLower + ` statistics
|
// @Summary Get ` + data.NameLower + ` statistics
|
||||||
// @Description Returns comprehensive statistics about ` + data.NameLower + ` data
|
// @Description Returns comprehensive statistics about ` + data.NameLower + ` data
|
||||||
@@ -533,7 +625,7 @@ func generateStatsMethod(data HandlerData) string {
|
|||||||
// @Param status query string false "Filter statistics by status"
|
// @Param status query string false "Filter statistics by status"
|
||||||
// @Success 200 {object} models.AggregateData "Statistics data"
|
// @Success 200 {object} models.AggregateData "Statistics data"
|
||||||
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
// @Router /api/v1/` + data.NamePlural + `/stats [get]
|
// @Router /api/v1/` + routePath + `/stats [get]
|
||||||
func (h *` + data.Name + `Handler) Get` + data.Name + `Stats(c *gin.Context) {
|
func (h *` + data.Name + `Handler) Get` + data.Name + `Stats(c *gin.Context) {
|
||||||
dbConn, err := h.db.GetDB("satudata")
|
dbConn, err := h.db.GetDB("satudata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -553,15 +645,14 @@ func (h *` + data.Name + `Handler) Get` + data.Name + `Stats(c *gin.Context) {
|
|||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "Statistik ` + data.NameLower + ` berhasil diambil",
|
"message": "Statistik ` + data.NameLower + ` berhasil diambil",
|
||||||
"data": aggregateData,
|
"data": aggregateData,
|
||||||
})
|
})
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateHelperMethods(data HandlerData) string {
|
func generateHelperMethods(data HandlerData) string {
|
||||||
// FIXED: All method names and types properly formatted
|
|
||||||
return `
|
return `
|
||||||
|
|
||||||
// Database operations
|
// Database operations
|
||||||
func (h *` + data.Name + `Handler) get` + data.Name + `ByID(ctx context.Context, dbConn *sql.DB, id string) (*models.` + data.Name + `, error) {
|
func (h *` + data.Name + `Handler) get` + data.Name + `ByID(ctx context.Context, dbConn *sql.DB, id string) (*models.` + data.Name + `, error) {
|
||||||
query := "SELECT id, status, date_created, date_updated, name FROM ` + data.TableName + ` WHERE id = $1 AND status != 'deleted'"
|
query := "SELECT id, status, date_created, date_updated, name FROM ` + data.TableName + ` WHERE id = $1 AND status != 'deleted'"
|
||||||
@@ -609,6 +700,7 @@ func (h *` + data.Name + `Handler) update` + data.Name + `(ctx context.Context,
|
|||||||
|
|
||||||
func (h *` + data.Name + `Handler) delete` + data.Name + `(ctx context.Context, dbConn *sql.DB, id string) error {
|
func (h *` + data.Name + `Handler) delete` + data.Name + `(ctx context.Context, dbConn *sql.DB, id string) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
query := "UPDATE ` + data.TableName + ` SET status = 'deleted', date_updated = $2 WHERE id = $1 AND status != 'deleted'"
|
query := "UPDATE ` + data.TableName + ` SET status = 'deleted', date_updated = $2 WHERE id = $1 AND status != 'deleted'"
|
||||||
result, err := dbConn.ExecContext(ctx, query, id, now)
|
result, err := dbConn.ExecContext(ctx, query, id, now)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -630,8 +722,8 @@ func (h *` + data.Name + `Handler) delete` + data.Name + `(ctx context.Context,
|
|||||||
func (h *` + data.Name + `Handler) fetch` + data.Name + `s(ctx context.Context, dbConn *sql.DB, filter models.` + data.Name + `Filter, limit, offset int) ([]models.` + data.Name + `, error) {
|
func (h *` + data.Name + `Handler) fetch` + data.Name + `s(ctx context.Context, dbConn *sql.DB, filter models.` + data.Name + `Filter, limit, offset int) ([]models.` + data.Name + `, error) {
|
||||||
whereClause, args := h.buildWhereClause(filter)
|
whereClause, args := h.buildWhereClause(filter)
|
||||||
query := fmt.Sprintf("SELECT id, status, date_created, date_updated, name FROM ` + data.TableName + ` WHERE %s ORDER BY date_created DESC NULLS LAST LIMIT $%d OFFSET $%d", whereClause, len(args)+1, len(args)+2)
|
query := fmt.Sprintf("SELECT id, status, date_created, date_updated, name FROM ` + data.TableName + ` WHERE %s ORDER BY date_created DESC NULLS LAST LIMIT $%d OFFSET $%d", whereClause, len(args)+1, len(args)+2)
|
||||||
|
|
||||||
args = append(args, limit, offset)
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
rows, err := dbConn.QueryContext(ctx, query, args...)
|
rows, err := dbConn.QueryContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("fetch ` + data.NamePlural + ` query failed: %w", err)
|
return nil, fmt.Errorf("fetch ` + data.NamePlural + ` query failed: %w", err)
|
||||||
@@ -658,9 +750,11 @@ func (h *` + data.Name + `Handler) fetch` + data.Name + `s(ctx context.Context,
|
|||||||
func (h *` + data.Name + `Handler) getTotalCount(ctx context.Context, dbConn *sql.DB, filter models.` + data.Name + `Filter, total *int) error {
|
func (h *` + data.Name + `Handler) getTotalCount(ctx context.Context, dbConn *sql.DB, filter models.` + data.Name + `Filter, total *int) error {
|
||||||
whereClause, args := h.buildWhereClause(filter)
|
whereClause, args := h.buildWhereClause(filter)
|
||||||
countQuery := fmt.Sprintf("SELECT COUNT(*) FROM ` + data.TableName + ` WHERE %s", whereClause)
|
countQuery := fmt.Sprintf("SELECT COUNT(*) FROM ` + data.TableName + ` WHERE %s", whereClause)
|
||||||
|
|
||||||
if err := dbConn.QueryRowContext(ctx, countQuery, args...).Scan(total); err != nil {
|
if err := dbConn.QueryRowContext(ctx, countQuery, args...).Scan(total); err != nil {
|
||||||
return fmt.Errorf("total count query failed: %w", err)
|
return fmt.Errorf("total count query failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,7 +765,7 @@ func (h *` + data.Name + `Handler) getAggregateData(ctx context.Context, dbConn
|
|||||||
|
|
||||||
whereClause, args := h.buildWhereClause(filter)
|
whereClause, args := h.buildWhereClause(filter)
|
||||||
statusQuery := fmt.Sprintf("SELECT status, COUNT(*) FROM ` + data.TableName + ` WHERE %s GROUP BY status ORDER BY status", whereClause)
|
statusQuery := fmt.Sprintf("SELECT status, COUNT(*) FROM ` + data.TableName + ` WHERE %s GROUP BY status ORDER BY status", whereClause)
|
||||||
|
|
||||||
rows, err := dbConn.QueryContext(ctx, statusQuery, args...)
|
rows, err := dbConn.QueryContext(ctx, statusQuery, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("status query failed: %w", err)
|
return nil, fmt.Errorf("status query failed: %w", err)
|
||||||
@@ -684,8 +778,8 @@ func (h *` + data.Name + `Handler) getAggregateData(ctx context.Context, dbConn
|
|||||||
if err := rows.Scan(&status, &count); err != nil {
|
if err := rows.Scan(&status, &count); err != nil {
|
||||||
return nil, fmt.Errorf("status scan failed: %w", err)
|
return nil, fmt.Errorf("status scan failed: %w", err)
|
||||||
}
|
}
|
||||||
aggregate.ByStatus[status] = count
|
|
||||||
|
|
||||||
|
aggregate.ByStatus[status] = count
|
||||||
switch status {
|
switch status {
|
||||||
case "active":
|
case "active":
|
||||||
aggregate.TotalActive = count
|
aggregate.TotalActive = count
|
||||||
@@ -712,9 +806,9 @@ func (h *` + data.Name + `Handler) respondError(c *gin.Context, message string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(statusCode, models.ErrorResponse{
|
c.JSON(statusCode, models.ErrorResponse{
|
||||||
Error: errorMessage,
|
Error: errorMessage,
|
||||||
Code: statusCode,
|
Code: statusCode,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -728,12 +822,15 @@ func (h *` + data.Name + `Handler) parsePaginationParams(c *gin.Context) (int, i
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, fmt.Errorf("invalid limit parameter: %s", limitStr)
|
return 0, 0, fmt.Errorf("invalid limit parameter: %s", limitStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsedLimit <= 0 {
|
if parsedLimit <= 0 {
|
||||||
return 0, 0, fmt.Errorf("limit must be greater than 0")
|
return 0, 0, fmt.Errorf("limit must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsedLimit > 100 {
|
if parsedLimit > 100 {
|
||||||
return 0, 0, fmt.Errorf("limit cannot exceed 100")
|
return 0, 0, fmt.Errorf("limit cannot exceed 100")
|
||||||
}
|
}
|
||||||
|
|
||||||
limit = parsedLimit
|
limit = parsedLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,9 +839,11 @@ func (h *` + data.Name + `Handler) parsePaginationParams(c *gin.Context) (int, i
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, fmt.Errorf("invalid offset parameter: %s", offsetStr)
|
return 0, 0, fmt.Errorf("invalid offset parameter: %s", offsetStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsedOffset < 0 {
|
if parsedOffset < 0 {
|
||||||
return 0, 0, fmt.Errorf("offset cannot be negative")
|
return 0, 0, fmt.Errorf("offset cannot be negative")
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = parsedOffset
|
offset = parsedOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,26 +916,25 @@ func (h *` + data.Name + `Handler) buildWhereClause(filter models.` + data.Name
|
|||||||
func (h *` + data.Name + `Handler) calculateMeta(limit, offset, total int) models.MetaResponse {
|
func (h *` + data.Name + `Handler) calculateMeta(limit, offset, total int) models.MetaResponse {
|
||||||
totalPages := 0
|
totalPages := 0
|
||||||
currentPage := 1
|
currentPage := 1
|
||||||
|
|
||||||
if limit > 0 {
|
if limit > 0 {
|
||||||
totalPages = (total + limit - 1) / limit // Ceiling division
|
totalPages = (total + limit - 1) / limit // Ceiling division
|
||||||
currentPage = (offset / limit) + 1
|
currentPage = (offset / limit) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return models.MetaResponse{
|
return models.MetaResponse{
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
Offset: offset,
|
Offset: offset,
|
||||||
Total: total,
|
Total: total,
|
||||||
TotalPages: totalPages,
|
TotalPages: totalPages,
|
||||||
CurrentPage: currentPage,
|
CurrentPage: currentPage,
|
||||||
HasNext: offset+limit < total,
|
HasNext: offset+limit < total,
|
||||||
HasPrev: offset > 0,
|
HasPrev: offset > 0,
|
||||||
}
|
}
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= MODEL GENERATION =====================
|
// ================= MODEL GENERATION =====================
|
||||||
|
|
||||||
func generateModelFile(data HandlerData, modelDir string) {
|
func generateModelFile(data HandlerData, modelDir string) {
|
||||||
modelContent := `package models
|
modelContent := `package models
|
||||||
|
|
||||||
@@ -850,7 +948,7 @@ import (
|
|||||||
// NullableInt32 is a custom type to replace sql.NullInt32 for swagger compatibility
|
// NullableInt32 is a custom type to replace sql.NullInt32 for swagger compatibility
|
||||||
type NullableInt32 struct {
|
type NullableInt32 struct {
|
||||||
Int32 int32 ` + "`json:\"int32,omitempty\"`" + `
|
Int32 int32 ` + "`json:\"int32,omitempty\"`" + `
|
||||||
Valid bool ` + "`json:\"valid\"`" + `
|
Valid bool ` + "`json:\"valid\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements the sql.Scanner interface for NullableInt32
|
// Scan implements the sql.Scanner interface for NullableInt32
|
||||||
@@ -859,6 +957,7 @@ func (n *NullableInt32) Scan(value interface{}) error {
|
|||||||
if err := ni.Scan(value); err != nil {
|
if err := ni.Scan(value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Int32 = ni.Int32
|
n.Int32 = ni.Int32
|
||||||
n.Valid = ni.Valid
|
n.Valid = ni.Valid
|
||||||
return nil
|
return nil
|
||||||
@@ -869,31 +968,32 @@ func (n NullableInt32) Value() (driver.Value, error) {
|
|||||||
if !n.Valid {
|
if !n.Valid {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.Int32, nil
|
return n.Int32, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ` + data.Name + ` represents the data structure for the ` + data.NameLower + ` table
|
// ` + data.Name + ` represents the data structure for the ` + data.NameLower + ` table
|
||||||
type ` + data.Name + ` struct {
|
type ` + data.Name + ` struct {
|
||||||
ID string ` + "`json:\"id\" db:\"id\"`" + `
|
ID string ` + "`json:\"id\" db:\"id\"`" + `
|
||||||
Status string ` + "`json:\"status\" db:\"status\"`" + `
|
Status string ` + "`json:\"status\" db:\"status\"`" + `
|
||||||
Sort NullableInt32 ` + "`json:\"sort,omitempty\" db:\"sort\"`" + `
|
Sort NullableInt32 ` + "`json:\"sort,omitempty\" db:\"sort\"`" + `
|
||||||
UserCreated sql.NullString ` + "`json:\"user_created,omitempty\" db:\"user_created\"`" + `
|
UserCreated sql.NullString ` + "`json:\"user_created,omitempty\" db:\"user_created\"`" + `
|
||||||
DateCreated sql.NullTime ` + "`json:\"date_created,omitempty\" db:\"date_created\"`" + `
|
DateCreated sql.NullTime ` + "`json:\"date_created,omitempty\" db:\"date_created\"`" + `
|
||||||
UserUpdated sql.NullString ` + "`json:\"user_updated,omitempty\" db:\"user_updated\"`" + `
|
UserUpdated sql.NullString ` + "`json:\"user_updated,omitempty\" db:\"user_updated\"`" + `
|
||||||
DateUpdated sql.NullTime ` + "`json:\"date_updated,omitempty\" db:\"date_updated\"`" + `
|
DateUpdated sql.NullTime ` + "`json:\"date_updated,omitempty\" db:\"date_updated\"`" + `
|
||||||
Name sql.NullString ` + "`json:\"name,omitempty\" db:\"name\"`" + `
|
Name sql.NullString ` + "`json:\"name,omitempty\" db:\"name\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom JSON marshaling for ` + data.Name + `
|
// Custom JSON marshaling for ` + data.Name + `
|
||||||
func (r ` + data.Name + `) MarshalJSON() ([]byte, error) {
|
func (r ` + data.Name + `) MarshalJSON() ([]byte, error) {
|
||||||
type Alias ` + data.Name + `
|
type Alias ` + data.Name + `
|
||||||
aux := &struct {
|
aux := &struct {
|
||||||
Sort *int ` + "`json:\"sort,omitempty\"`" + `
|
Sort *int ` + "`json:\"sort,omitempty\"`" + `
|
||||||
UserCreated *string ` + "`json:\"user_created,omitempty\"`" + `
|
UserCreated *string ` + "`json:\"user_created,omitempty\"`" + `
|
||||||
DateCreated *time.Time ` + "`json:\"date_created,omitempty\"`" + `
|
DateCreated *time.Time ` + "`json:\"date_created,omitempty\"`" + `
|
||||||
UserUpdated *string ` + "`json:\"user_updated,omitempty\"`" + `
|
UserUpdated *string ` + "`json:\"user_updated,omitempty\"`" + `
|
||||||
DateUpdated *time.Time ` + "`json:\"date_updated,omitempty\"`" + `
|
DateUpdated *time.Time ` + "`json:\"date_updated,omitempty\"`" + `
|
||||||
Name *string ` + "`json:\"name,omitempty\"`" + `
|
Name *string ` + "`json:\"name,omitempty\"`" + `
|
||||||
*Alias
|
*Alias
|
||||||
}{
|
}{
|
||||||
Alias: (*Alias)(&r),
|
Alias: (*Alias)(&r),
|
||||||
@@ -903,18 +1003,23 @@ func (r ` + data.Name + `) MarshalJSON() ([]byte, error) {
|
|||||||
sort := int(r.Sort.Int32)
|
sort := int(r.Sort.Int32)
|
||||||
aux.Sort = &sort
|
aux.Sort = &sort
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.UserCreated.Valid {
|
if r.UserCreated.Valid {
|
||||||
aux.UserCreated = &r.UserCreated.String
|
aux.UserCreated = &r.UserCreated.String
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.DateCreated.Valid {
|
if r.DateCreated.Valid {
|
||||||
aux.DateCreated = &r.DateCreated.Time
|
aux.DateCreated = &r.DateCreated.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.UserUpdated.Valid {
|
if r.UserUpdated.Valid {
|
||||||
aux.UserUpdated = &r.UserUpdated.String
|
aux.UserUpdated = &r.UserUpdated.String
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.DateUpdated.Valid {
|
if r.DateUpdated.Valid {
|
||||||
aux.DateUpdated = &r.DateUpdated.Time
|
aux.DateUpdated = &r.DateUpdated.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Name.Valid {
|
if r.Name.Valid {
|
||||||
aux.Name = &r.Name.String
|
aux.Name = &r.Name.String
|
||||||
}
|
}
|
||||||
@@ -928,117 +1033,117 @@ func (r *` + data.Name + `) GetName() string {
|
|||||||
return r.Name.String
|
return r.Name.String
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
|
|
||||||
// Add request/response structs
|
// Add request/response structs based on enabled methods
|
||||||
if data.HasGet {
|
if data.HasGet {
|
||||||
modelContent += `
|
modelContent += `
|
||||||
|
|
||||||
// Response struct for GET by ID
|
// Response struct for GET by ID
|
||||||
type ` + data.Name + `GetByIDResponse struct {
|
type ` + data.Name + `GetByIDResponse struct {
|
||||||
Message string ` + "`json:\"message\"`" + `
|
Message string ` + "`json:\"message\"`" + `
|
||||||
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
|
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhanced GET response with pagination and aggregation
|
// Enhanced GET response with pagination and aggregation
|
||||||
type ` + data.Name + `GetResponse struct {
|
type ` + data.Name + `GetResponse struct {
|
||||||
Message string ` + "`json:\"message\"`" + `
|
Message string ` + "`json:\"message\"`" + `
|
||||||
Data []` + data.Name + ` ` + "`json:\"data\"`" + `
|
Data []` + data.Name + ` ` + "`json:\"data\"`" + `
|
||||||
Meta MetaResponse ` + "`json:\"meta\"`" + `
|
Meta MetaResponse ` + "`json:\"meta\"`" + `
|
||||||
Summary *AggregateData ` + "`json:\"summary,omitempty\"`" + `
|
Summary *AggregateData ` + "`json:\"summary,omitempty\"`" + `
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPost {
|
if data.HasPost {
|
||||||
modelContent += `
|
modelContent += `
|
||||||
|
|
||||||
// Request struct for create
|
// Request struct for create
|
||||||
type ` + data.Name + `CreateRequest struct {
|
type ` + data.Name + `CreateRequest struct {
|
||||||
Status string ` + "`json:\"status\" validate:\"required,oneof=draft active inactive\"`" + `
|
Status string ` + "`json:\"status\" validate:\"required,oneof=draft active inactive\"`" + `
|
||||||
Name *string ` + "`json:\"name,omitempty\" validate:\"omitempty,min=1,max=255\"`" + `
|
Name *string ` + "`json:\"name,omitempty\" validate:\"omitempty,min=1,max=255\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response struct for create
|
// Response struct for create
|
||||||
type ` + data.Name + `CreateResponse struct {
|
type ` + data.Name + `CreateResponse struct {
|
||||||
Message string ` + "`json:\"message\"`" + `
|
Message string ` + "`json:\"message\"`" + `
|
||||||
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
|
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPut {
|
if data.HasPut {
|
||||||
modelContent += `
|
modelContent += `
|
||||||
|
|
||||||
// Update request
|
// Update request
|
||||||
type ` + data.Name + `UpdateRequest struct {
|
type ` + data.Name + `UpdateRequest struct {
|
||||||
ID string ` + "`json:\"-\" validate:\"required,uuid4\"`" + ` // ID dari URL path
|
ID string ` + "`json:\"-\" validate:\"required,uuid4\"`" + ` // ID dari URL path
|
||||||
Status string ` + "`json:\"status\" validate:\"required,oneof=draft active inactive\"`" + `
|
Status string ` + "`json:\"status\" validate:\"required,oneof=draft active inactive\"`" + `
|
||||||
Name *string ` + "`json:\"name,omitempty\" validate:\"omitempty,min=1,max=255\"`" + `
|
Name *string ` + "`json:\"name,omitempty\" validate:\"omitempty,min=1,max=255\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response struct for update
|
// Response struct for update
|
||||||
type ` + data.Name + `UpdateResponse struct {
|
type ` + data.Name + `UpdateResponse struct {
|
||||||
Message string ` + "`json:\"message\"`" + `
|
Message string ` + "`json:\"message\"`" + `
|
||||||
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
|
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasDelete {
|
if data.HasDelete {
|
||||||
modelContent += `
|
modelContent += `
|
||||||
|
|
||||||
// Response struct for delete
|
// Response struct for delete
|
||||||
type ` + data.Name + `DeleteResponse struct {
|
type ` + data.Name + `DeleteResponse struct {
|
||||||
Message string ` + "`json:\"message\"`" + `
|
Message string ` + "`json:\"message\"`" + `
|
||||||
ID string ` + "`json:\"id\"`" + `
|
ID string ` + "`json:\"id\"`" + `
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add common structs
|
// Add common structs
|
||||||
modelContent += `
|
modelContent += `
|
||||||
|
|
||||||
// Metadata for pagination
|
// Metadata for pagination
|
||||||
type MetaResponse struct {
|
type MetaResponse struct {
|
||||||
Limit int ` + "`json:\"limit\"`" + `
|
Limit int ` + "`json:\"limit\"`" + `
|
||||||
Offset int ` + "`json:\"offset\"`" + `
|
Offset int ` + "`json:\"offset\"`" + `
|
||||||
Total int ` + "`json:\"total\"`" + `
|
Total int ` + "`json:\"total\"`" + `
|
||||||
TotalPages int ` + "`json:\"total_pages\"`" + `
|
TotalPages int ` + "`json:\"total_pages\"`" + `
|
||||||
CurrentPage int ` + "`json:\"current_page\"`" + `
|
CurrentPage int ` + "`json:\"current_page\"`" + `
|
||||||
HasNext bool ` + "`json:\"has_next\"`" + `
|
HasNext bool ` + "`json:\"has_next\"`" + `
|
||||||
HasPrev bool ` + "`json:\"has_prev\"`" + `
|
HasPrev bool ` + "`json:\"has_prev\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate data for summary
|
// Aggregate data for summary
|
||||||
type AggregateData struct {
|
type AggregateData struct {
|
||||||
TotalActive int ` + "`json:\"total_active\"`" + `
|
TotalActive int ` + "`json:\"total_active\"`" + `
|
||||||
TotalDraft int ` + "`json:\"total_draft\"`" + `
|
TotalDraft int ` + "`json:\"total_draft\"`" + `
|
||||||
TotalInactive int ` + "`json:\"total_inactive\"`" + `
|
TotalInactive int ` + "`json:\"total_inactive\"`" + `
|
||||||
ByStatus map[string]int ` + "`json:\"by_status\"`" + `
|
ByStatus map[string]int ` + "`json:\"by_status\"`" + `
|
||||||
LastUpdated *time.Time ` + "`json:\"last_updated,omitempty\"`" + `
|
LastUpdated *time.Time ` + "`json:\"last_updated,omitempty\"`" + `
|
||||||
CreatedToday int ` + "`json:\"created_today\"`" + `
|
CreatedToday int ` + "`json:\"created_today\"`" + `
|
||||||
UpdatedToday int ` + "`json:\"updated_today\"`" + `
|
UpdatedToday int ` + "`json:\"updated_today\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error response
|
// Error response
|
||||||
type ErrorResponse struct {
|
type ErrorResponse struct {
|
||||||
Error string ` + "`json:\"error\"`" + `
|
Error string ` + "`json:\"error\"`" + `
|
||||||
Code int ` + "`json:\"code\"`" + `
|
Code int ` + "`json:\"code\"`" + `
|
||||||
Message string ` + "`json:\"message\"`" + `
|
Message string ` + "`json:\"message\"`" + `
|
||||||
Timestamp time.Time ` + "`json:\"timestamp\"`" + `
|
Timestamp time.Time ` + "`json:\"timestamp\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter struct for query parameters
|
// Filter struct for query parameters
|
||||||
type ` + data.Name + `Filter struct {
|
type ` + data.Name + `Filter struct {
|
||||||
Status *string ` + "`json:\"status,omitempty\" form:\"status\"`" + `
|
Status *string ` + "`json:\"status,omitempty\" form:\"status\"`" + `
|
||||||
Search *string ` + "`json:\"search,omitempty\" form:\"search\"`" + `
|
Search *string ` + "`json:\"search,omitempty\" form:\"search\"`" + `
|
||||||
DateFrom *time.Time ` + "`json:\"date_from,omitempty\" form:\"date_from\"`" + `
|
DateFrom *time.Time ` + "`json:\"date_from,omitempty\" form:\"date_from\"`" + `
|
||||||
DateTo *time.Time ` + "`json:\"date_to,omitempty\" form:\"date_to\"`" + `
|
DateTo *time.Time ` + "`json:\"date_to,omitempty\" form:\"date_to\"`" + `
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation constants
|
// Validation constants
|
||||||
const (
|
const (
|
||||||
StatusDraft = "draft"
|
StatusDraft = "draft"
|
||||||
StatusActive = "active"
|
StatusActive = "active"
|
||||||
StatusInactive = "inactive"
|
StatusInactive = "inactive"
|
||||||
StatusDeleted = "deleted"
|
StatusDeleted = "deleted"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidStatuses for validation
|
// ValidStatuses for validation
|
||||||
@@ -1052,41 +1157,13 @@ func IsValidStatus(status string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}`
|
||||||
`
|
|
||||||
|
|
||||||
writeFile(filepath.Join(modelDir, data.NameLower+".go"), modelContent)
|
writeFile(filepath.Join(modelDir, data.NameLower+".go"), modelContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= ROUTES GENERATION =====================
|
// ================= ROUTES GENERATION =====================
|
||||||
|
|
||||||
func updateRoutesFile(data HandlerData) {
|
func updateRoutesFile(data HandlerData) {
|
||||||
// routesFile := "internal/routes/v1/routes.go"
|
|
||||||
// content, err := os.ReadFile(routesFile)
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Printf("⚠️ Could not read routes.go: %v\n", err)
|
|
||||||
// fmt.Printf("📝 Please manually add these routes to your routes.go file:\n")
|
|
||||||
// printRoutesSample(data)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// routesContent := string(content)
|
|
||||||
|
|
||||||
// // Add import
|
|
||||||
// importPattern := data.NameLower + `Handlers "` + data.ModuleName + `/internal/handlers/` + data.NameLower + `"`
|
|
||||||
// if !strings.Contains(routesContent, importPattern) {
|
|
||||||
// fmt.Printf("⚠️ Please add this import to your routes.go file:\n")
|
|
||||||
// fmt.Printf("import %sHandlers \"%s/internal/handlers/%s\"\n\n", data.NameLower, data.ModuleName, data.NameLower)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Check if routes already exist
|
|
||||||
// if strings.Contains(routesContent, fmt.Sprintf("New%sHandler", data.Name)) {
|
|
||||||
// fmt.Printf("⚠️ Routes for %s already exist, skipping...\n", data.Name)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fmt.Printf("📝 Please manually add these routes to your routes.go file:\n")
|
|
||||||
// printRoutesSample(data)
|
|
||||||
routesFile := "internal/routes/v1/routes.go"
|
routesFile := "internal/routes/v1/routes.go"
|
||||||
content, err := os.ReadFile(routesFile)
|
content, err := os.ReadFile(routesFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1095,43 +1172,71 @@ func updateRoutesFile(data HandlerData) {
|
|||||||
printRoutesSample(data)
|
printRoutesSample(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
routesContent := string(content)
|
routesContent := string(content)
|
||||||
|
|
||||||
|
// Build import path - PERBAIKAN UTAMA
|
||||||
|
var importPath, importAlias string
|
||||||
|
if data.Category != "" {
|
||||||
|
importPath = fmt.Sprintf("%s/internal/handlers/%s", data.ModuleName, data.Category)
|
||||||
|
importAlias = data.NameLower + "Handlers"
|
||||||
|
} else {
|
||||||
|
importPath = fmt.Sprintf("%s/internal/handlers", data.ModuleName)
|
||||||
|
importAlias = data.NameLower + "Handlers"
|
||||||
|
}
|
||||||
|
|
||||||
// import
|
// import
|
||||||
importPattern := fmt.Sprintf("%sHandlers \"%s/internal/handlers/%s\"",
|
importPattern := fmt.Sprintf("%s \"%s\"", importAlias, importPath)
|
||||||
data.NameLower, data.ModuleName, data.NameLower)
|
|
||||||
if !strings.Contains(routesContent, importPattern) {
|
if !strings.Contains(routesContent, importPattern) {
|
||||||
importToAdd := fmt.Sprintf("\t%sHandlers \"%s/internal/handlers/%s\"",
|
importToAdd := fmt.Sprintf("\t%s \"%s\"", importAlias, importPath)
|
||||||
data.NameLower, data.ModuleName, data.NameLower)
|
|
||||||
if strings.Contains(routesContent, "import (") {
|
if strings.Contains(routesContent, "import (") {
|
||||||
routesContent = strings.Replace(routesContent, "import (",
|
routesContent = strings.Replace(routesContent, "import (",
|
||||||
"import (\n"+importToAdd, 1)
|
"import (\n"+importToAdd, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build route paths
|
||||||
|
var routesPath, singleRoutePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routesPath = data.Category + "/" + data.NamePlural
|
||||||
|
singleRoutePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
routesPath = data.NamePlural
|
||||||
|
singleRoutePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
// routes
|
// routes
|
||||||
newRoutes := fmt.Sprintf("\t\t// %s endpoints\n", data.Name)
|
newRoutes := fmt.Sprintf("\t\t// %s endpoints\n", data.Name)
|
||||||
newRoutes += fmt.Sprintf("\t\t%sHandler := %sHandlers.New%sHandler()\n",
|
newRoutes += fmt.Sprintf("\t\t%sHandler := %s.New%sHandler()\n",
|
||||||
data.NameLower, data.NameLower, data.Name)
|
data.NameLower, importAlias, data.Name)
|
||||||
|
|
||||||
if data.HasGet {
|
if data.HasGet {
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s\", %sHandler.Get%s)\n",
|
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s\", %sHandler.Get%s)\n",
|
||||||
data.NamePlural, data.NameLower, data.Name)
|
routesPath, data.NameLower, data.Name)
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n",
|
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n",
|
||||||
data.NameLower, data.NameLower, data.Name)
|
singleRoutePath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPost {
|
if data.HasPost {
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.POST(\"/%s\", %sHandler.Create%s)\n",
|
newRoutes += fmt.Sprintf("\t\tv1.POST(\"/%s\", %sHandler.Create%s)\n",
|
||||||
data.NamePlural, data.NameLower, data.Name)
|
routesPath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPut {
|
if data.HasPut {
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.PUT(\"/%s/:id\", %sHandler.Update%s)\n",
|
newRoutes += fmt.Sprintf("\t\tv1.PUT(\"/%s/:id\", %sHandler.Update%s)\n",
|
||||||
data.NameLower, data.NameLower, data.Name)
|
singleRoutePath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasDelete {
|
if data.HasDelete {
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n",
|
newRoutes += fmt.Sprintf("\t\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n",
|
||||||
data.NameLower, data.NameLower, data.Name)
|
singleRoutePath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if data.HasStats {
|
||||||
|
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/stats\", %sHandler.Get%sStats)\n",
|
||||||
|
routesPath, data.NameLower, data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
newRoutes += "\n"
|
newRoutes += "\n"
|
||||||
|
|
||||||
insertMarker := "\t\tprotected := v1.Group(\"/\")"
|
insertMarker := "\t\tprotected := v1.Group(\"/\")"
|
||||||
@@ -1141,6 +1246,7 @@ func updateRoutesFile(data HandlerData) {
|
|||||||
newRoutes+insertMarker, 1)
|
newRoutes+insertMarker, 1)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("✅ Routes for %s already exist, skipping...\n", data.Name)
|
fmt.Printf("✅ Routes for %s already exist, skipping...\n", data.Name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1148,36 +1254,57 @@ func updateRoutesFile(data HandlerData) {
|
|||||||
fmt.Printf("Error writing routes.go: %v\n", err)
|
fmt.Printf("Error writing routes.go: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("✅ Updated routes.go with %s endpoints\n", data.Name)
|
fmt.Printf("✅ Updated routes.go with %s endpoints\n", data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printRoutesSample(data HandlerData) {
|
func printRoutesSample(data HandlerData) {
|
||||||
|
var routesPath, singleRoutePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routesPath = data.Category + "/" + data.NamePlural
|
||||||
|
singleRoutePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
routesPath = data.NamePlural
|
||||||
|
singleRoutePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
|
var importAlias string
|
||||||
|
if data.Category != "" {
|
||||||
|
importAlias = data.NameLower + "Handlers"
|
||||||
|
} else {
|
||||||
|
importAlias = data.NameLower + "Handlers"
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf(`
|
fmt.Printf(`
|
||||||
// %s endpoints
|
// %s endpoints
|
||||||
%sHandler := %sHandlers.New%sHandler()
|
%sHandler := %s.New%sHandler()
|
||||||
`, data.Name, data.NameLower, data.NameLower, data.Name)
|
`, data.Name, data.NameLower, importAlias, data.Name)
|
||||||
|
|
||||||
if data.HasGet {
|
if data.HasGet {
|
||||||
fmt.Printf("\tv1.GET(\"/%s\", %sHandler.Get%s)\n", data.NamePlural, data.NameLower, data.Name)
|
fmt.Printf("\tv1.GET(\"/%s\", %sHandler.Get%s)\n", routesPath, data.NameLower, data.Name)
|
||||||
fmt.Printf("\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n", data.NameLower, data.NameLower, data.Name)
|
fmt.Printf("\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n", singleRoutePath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPost {
|
if data.HasPost {
|
||||||
fmt.Printf("\tv1.POST(\"/%s\", %sHandler.Create%s)\n", data.NamePlural, data.NameLower, data.Name)
|
fmt.Printf("\tv1.POST(\"/%s\", %sHandler.Create%s)\n", routesPath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPut {
|
if data.HasPut {
|
||||||
fmt.Printf("\tv1.PUT(\"/%s/:id\", %sHandler.Update%s)\n", data.NameLower, data.NameLower, data.Name)
|
fmt.Printf("\tv1.PUT(\"/%s/:id\", %sHandler.Update%s)\n", singleRoutePath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasDelete {
|
if data.HasDelete {
|
||||||
fmt.Printf("\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n", data.NameLower, data.NameLower, data.Name)
|
fmt.Printf("\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n", singleRoutePath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasStats {
|
if data.HasStats {
|
||||||
fmt.Printf("\tv1.GET(\"/%s/stats\", %sHandler.Get%sStats)\n", data.NamePlural, data.NameLower, data.Name)
|
fmt.Printf("\tv1.GET(\"/%s/stats\", %sHandler.Get%sStats)\n", routesPath, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= UTILITY FUNCTIONS =====================
|
// ================= UTILITY FUNCTIONS =====================
|
||||||
|
|
||||||
func writeFile(filename, content string) {
|
func writeFile(filename, content string) {
|
||||||
if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
|
if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
|
||||||
fmt.Printf("❌ Error creating file %s: %v\n", filename, err)
|
fmt.Printf("❌ Error creating file %s: %v\n", filename, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user