Perbaikan generate

This commit is contained in:
2025-10-20 09:46:08 +07:00
parent 21cc6aacdb
commit f253e65736
2 changed files with 617 additions and 266 deletions

View File

@@ -6,6 +6,7 @@ import (
"log"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@@ -21,6 +22,7 @@ type HandlerData struct {
DirPath string // Path direktori lengkap
ModuleName string
TableName string
TableSchema []ColumnConfig // Untuk penyimpanan schema
HasGet bool
HasPost bool
HasPut bool
@@ -71,6 +73,20 @@ type ServiceConfig struct {
Endpoints map[string]EndpointConfig `yaml:"endpoints"`
}
// SchemaConfig represents a schema configuration
type SchemaConfig struct {
Columns []ColumnConfig `yaml:"columns"`
}
// ColumnConfig represents a column configuration
type ColumnConfig struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Nullable bool `yaml:"nullable,omitempty"`
GoType string `yaml:"go_type,omitempty"` // Untuk override tipe Go secara manual
PrimaryKey bool `yaml:"primary_key,omitempty"`
}
// EndpointConfig represents an endpoint configuration
type EndpointConfig struct {
Description string `yaml:"description"`
@@ -78,6 +94,7 @@ type EndpointConfig struct {
HandlerFile string `yaml:"handler_file"`
HandlerName string `yaml:"handler_name"`
TableName string `yaml:"table_name,omitempty"`
Schema SchemaConfig `yaml:"schema,omitempty"`
Functions map[string]FunctionConfig `yaml:"functions"`
}
@@ -403,6 +420,7 @@ func generateFromServicesConfig(config *ServicesConfig) {
DirPath: pathInfo.DirPath,
ModuleName: config.Global.ModuleName,
TableName: tableName,
TableSchema: endpoint.Schema.Columns,
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
}
@@ -444,14 +462,19 @@ func generateFromServicesConfig(config *ServicesConfig) {
continue
}
if len(data.TableSchema) > 0 {
if shouldSkipExistingFile(modelPath, "model") {
fmt.Printf("⚠️ Skipping model generation: %s\n", modelPath)
continue
} else {
generateModelFile(data, modelDir) // Memanggil fungsi baru
}
} else {
fmt.Printf("⚠️ Skipping model generation for '%s' because no schema is defined in the config.\n", entityName)
}
// Generate files (SEKALI SAJA per endpoint)
generateHandlerFile(data, handlerDir)
generateModelFile(data, modelDir)
// generateModelFile(data, modelDir)
// HANYA UPDATE ROUTES SEKALI PER ENDPOINT setelah semua fungsi di-aggregate
updateRoutesFile(data)
@@ -483,7 +506,8 @@ func main() {
}
// Check for services-config.yaml first (new format)
servicesConfig, err := loadServicesConfig(configPath)
servicesConfig, err :=
loadServicesConfig(configPath)
if err == nil {
// Use services config
if *verboseFlag {
@@ -2021,20 +2045,10 @@ func (h *` + data.Name + `Handler) delete` + data.Name + `(ctx context.Context,
// ================= MODEL GENERATION =====================
func generateModelFile(data HandlerData, modelDir string) {
// Tentukan nama file model
modelFileName := data.NameLower + ".go"
modelFilePath := filepath.Join(modelDir, modelFileName)
// Periksa apakah file model sudah ada
if _, err := os.Stat(modelFilePath); err == nil {
// File sudah ada, skip pembuatan model
fmt.Printf("Model %s already exists, skipping generation\n", data.Name)
return
}
// Tentukan import block
var importBlock, nullablePrefix string
if data.Category == "models" {
importBlock = `import (
"database/sql"
@@ -2053,144 +2067,304 @@ func generateModelFile(data HandlerData, modelDir string) {
`
}
modelContent := `package ` + data.Category + `
var modelContent strings.Builder
modelContent.WriteString(fmt.Sprintf("package %s\n\n", data.Category))
modelContent.WriteString(importBlock)
` + importBlock + `
// Generate main struct
modelContent.WriteString(fmt.Sprintf("// %s represents the data structure for the %s table\n", data.Name, data.TableName))
modelContent.WriteString("// with proper null handling and optimized JSON marshaling\n")
modelContent.WriteString(fmt.Sprintf("type %s struct {\n", data.Name))
// ` + data.Name + ` represents the data structure for the ` + data.NameLower + ` table
// with proper null handling and optimized JSON marshaling
type ` + data.Name + ` struct {
ID string ` + "`json:\"id\" db:\"id\"`" + `
Status string ` + "`json:\"status\" db:\"status\"`" + `
Sort ` + nullablePrefix + "NullableInt32 `json:\"sort,omitempty\" db:\"sort\"`" + `
UserCreated sql.NullString ` + "`json:\"user_created,omitempty\" db:\"user_created\"`" + `
DateCreated sql.NullTime ` + "`json:\"date_created,omitempty\" db:\"date_created\"`" + `
UserUpdated sql.NullString ` + "`json:\"user_updated,omitempty\" db:\"user_updated\"`" + `
DateUpdated sql.NullTime ` + "`json:\"date_updated,omitempty\" db:\"date_updated\"`" + `
Name sql.NullString ` + "`json:\"name,omitempty\" db:\"name\"`" + `
for _, col := range data.TableSchema {
fieldName := snakeToPascal(col.Name)
goType, _, _ := mapSQLTypeToGo(col.Type, col.Nullable, col.GoType)
jsonTag := snakeToCamel(col.Name)
dbTag := col.Name // Gunakan nama kolom langsung
jsonTagValue := jsonTag
if col.Nullable {
jsonTagValue += ",omitempty"
}
modelContent.WriteString(fmt.Sprintf(" %s %s `json:\"%s\" db:\"%s\"`\n", fieldName, goType, jsonTagValue, dbTag))
}
modelContent.WriteString("}\n\n")
// Generate MarshalJSON method
modelContent.WriteString(fmt.Sprintf("// Custom JSON marshaling for %s so NULL values don't appear in response\n", data.Name))
modelContent.WriteString(fmt.Sprintf("func (r %s) MarshalJSON() ([]byte, error) {\n", data.Name))
modelContent.WriteString(fmt.Sprintf(" type Alias %s\n", data.Name))
modelContent.WriteString(" aux := &struct {\n *Alias\n")
for _, col := range data.TableSchema {
if !col.Nullable {
continue
}
fieldName := snakeToPascal(col.Name)
_, baseType, _ := mapSQLTypeToGo(col.Type, col.Nullable, col.GoType)
auxType := "*" + baseType
jsonTag := snakeToCamel(col.Name) + ",omitempty"
modelContent.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", fieldName, auxType, jsonTag))
}
modelContent.WriteString(" }{\n Alias: (*Alias)(&r),\n }\n\n")
for _, col := range data.TableSchema {
if !col.Nullable {
continue
}
fieldName := snakeToPascal(col.Name)
_, _, valueType := mapSQLTypeToGo(col.Type, col.Nullable, col.GoType)
modelContent.WriteString(fmt.Sprintf(" if r.%s.Valid {\n aux.%s = &r.%s.%s\n }\n", fieldName, fieldName, fieldName, valueType))
}
modelContent.WriteString(" return json.Marshal(aux)\n}\n\n")
// Generate helper methods
for _, col := range data.TableSchema {
if !col.Nullable {
continue
}
fieldName := snakeToPascal(col.Name)
_, baseType, valueType := mapSQLTypeToGo(col.Type, col.Nullable, col.GoType)
var zeroValue string
switch baseType {
case "string":
zeroValue = `""`
case "int32", "int64", "float64":
zeroValue = "0"
case "bool":
zeroValue = "false"
case "time.Time":
zeroValue = "time.Time{}"
default:
zeroValue = "nil"
}
modelContent.WriteString(fmt.Sprintf("// Helper method to safely get %s\n", fieldName))
modelContent.WriteString(fmt.Sprintf("func (r *%s) Get%s() %s {\n", data.Name, fieldName, baseType))
modelContent.WriteString(fmt.Sprintf(" if r.%s.Valid {\n return r.%s.%s\n }\n return %s\n}\n\n", fieldName, fieldName, valueType, zeroValue))
}
// Custom JSON marshaling untuk ` + data.Name + ` agar NULL values tidak muncul di response
func (r ` + data.Name + `) MarshalJSON() ([]byte, error) {
type Alias ` + data.Name + `
aux := &struct {
Sort *int ` + "`json:\"sort,omitempty\"`" + `
UserCreated *string ` + "`json:\"user_created,omitempty\"`" + `
DateCreated *time.Time ` + "`json:\"date_created,omitempty\"`" + `
UserUpdated *string ` + "`json:\"user_updated,omitempty\"`" + `
DateUpdated *time.Time ` + "`json:\"date_updated,omitempty\"`" + `
Name *string ` + "`json:\"name,omitempty\"`" + `
*Alias
}{
Alias: (*Alias)(&r),
// Generate request/response structs
excludedFields := map[string]bool{"id": true, "date_created": true, "date_updated": true, "user_created": true, "user_updated": true}
var createFields, updateFields []ColumnConfig
for _, col := range data.TableSchema {
if excludedFields[strings.ToLower(col.Name)] {
continue
}
createFields = append(createFields, col)
updateCol := col
updateFields = append(updateFields, updateCol)
}
if r.Sort.Valid {
sort := int(r.Sort.Int32)
aux.Sort = &sort
}
if r.UserCreated.Valid {
aux.UserCreated = &r.UserCreated.String
}
if r.DateCreated.Valid {
aux.DateCreated = &r.DateCreated.Time
}
if r.UserUpdated.Valid {
aux.UserUpdated = &r.UserUpdated.String
}
if r.DateUpdated.Valid {
aux.DateUpdated = &r.DateUpdated.Time
}
if r.Name.Valid {
aux.Name = &r.Name.String
}
return json.Marshal(aux)
}
// Helper methods untuk mendapatkan nilai yang aman
func (r *` + data.Name + `) GetName() string {
if r.Name.Valid {
return r.Name.String
}
return ""
}
`
// Add request/response structs based on enabled methods
if data.HasGet {
modelContent += `
// Response struct untuk GET by ID
type ` + data.Name + `GetByIDResponse struct {
modelContent.WriteString(fmt.Sprintf(`// Response struct for GET by ID
type %sGetByIDResponse struct {
Message string `+"`json:\"message\"`"+`
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
Data *%s `+"`json:\"data\"`"+`
}
// Enhanced GET response dengan pagination dan aggregation
type ` + data.Name + `GetResponse struct {
// Enhanced GET response with pagination and aggregation
type %sGetResponse struct {
Message string `+"`json:\"message\"`"+`
Data []` + data.Name + ` ` + "`json:\"data\"`" + `
Meta ` + nullablePrefix + "MetaResponse `json:\"meta\"`" + `
Summary *` + nullablePrefix + "AggregateData `json:\"summary,omitempty\"`" + `
Data []%s `+"`json:\"data\"`"+`
Meta %sMetaResponse `+"`json:\"meta\"`"+`
Summary *%sAggregateData `+"`json:\"summary,omitempty\"`"+`
}
`
`, data.Name, data.Name, data.Name, data.Name, nullablePrefix, nullablePrefix))
}
if data.HasPost {
modelContent += `
// Request struct untuk create
type ` + data.Name + `CreateRequest struct {
Status string ` + "`json:\"status\" validate:\"required,oneof=draft active inactive\"`" + `
Name *string ` + "`json:\"name,omitempty\" validate:\"omitempty,min=1,max=255\"`" + `
modelContent.WriteString(fmt.Sprintf("\n// Request struct for create\ntype %sCreateRequest struct {\n", data.Name))
for _, col := range createFields {
fieldName := snakeToPascal(col.Name)
_, baseType, _ := mapSQLTypeToGo(col.Type, col.Nullable, col.GoType)
jsonTag := snakeToCamel(col.Name)
var requestType string
if col.Nullable {
requestType = "*" + baseType
} else {
requestType = baseType
}
// Response struct untuk create
type ` + data.Name + `CreateResponse struct {
modelContent.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", fieldName, requestType, jsonTag))
}
modelContent.WriteString("}\n\n")
modelContent.WriteString(fmt.Sprintf(`// Response struct for create
type %sCreateResponse struct {
Message string `+"`json:\"message\"`"+`
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
Data *%s `+"`json:\"data\"`"+`
}
`
`, data.Name, data.Name))
}
if data.HasPut {
modelContent += `
// 1. Bangun string tag terlebih dahulu
idTagContent := `json:"-" validate:"required,uuid4"`
// Update request
type ` + data.Name + `UpdateRequest struct {
ID string ` + "`json:\"-\" validate:\"required,uuid4\"`" + `
Status string ` + "`json:\"status\" validate:\"required,oneof=draft active inactive\"`" + `
Name *string ` + "`json:\"name,omitempty\" validate:\"omitempty,min=1,max=255\"`" + `
// 2. Gunakan strconv.Quote untuk membuatnya menjadi literal yang valid
// Hasilnya akan menjadi: "`json:\"-\" validate:\"required,uuid4\"`"
quotedIdTag := strconv.Quote(idTagContent)
// 3. Gunakan tag yang sudah di-"quote" dalam fmt.Sprintf
modelContent.WriteString(fmt.Sprintf("\n// Update request\ntype %sUpdateRequest struct {\n ID string %s\n", data.Name, quotedIdTag))
for _, col := range updateFields {
fieldName := snakeToPascal(col.Name)
_, baseType, _ := mapSQLTypeToGo(col.Type, col.Nullable, col.GoType)
jsonTag := snakeToCamel(col.Name)
var requestType string
if col.Nullable {
requestType = "*" + baseType
} else {
requestType = baseType
}
// Response struct untuk update
type ` + data.Name + `UpdateResponse struct {
modelContent.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", fieldName, requestType, jsonTag))
}
modelContent.WriteString("}\n\n")
modelContent.WriteString(fmt.Sprintf(`// Response struct for update
type %sUpdateResponse struct {
Message string `+"`json:\"message\"`"+`
Data *` + data.Name + ` ` + "`json:\"data\"`" + `
Data *%s `+"`json:\"data\"`"+`
}
`
`, data.Name, data.Name))
}
if data.HasDelete {
modelContent += `
// Response struct untuk delete
type ` + data.Name + `DeleteResponse struct {
modelContent.WriteString(fmt.Sprintf(`// Response struct for delete
type %sDeleteResponse struct {
Message string `+"`json:\"message\"`"+`
ID string `+"`json:\"id\"`"+`
}
`
`, data.Name))
}
if data.HasFilter {
modelContent.WriteString(fmt.Sprintf("\n// Filter struct for query parameters\ntype %sFilter struct {\n", data.Name))
modelContent.WriteString(" Search *string `json:\"search,omitempty\" form:\"search\"`\n")
modelContent.WriteString(" DateFrom *time.Time `json:\"date_from,omitempty\" form:\"date_from\"`\n")
modelContent.WriteString(" DateTo *time.Time `json:\"date_to,omitempty\" form:\"date_to\"`\n")
for _, col := range data.TableSchema {
lowerName := strings.ToLower(col.Name)
if strings.Contains(lowerName, "status") {
modelContent.WriteString(fmt.Sprintf(" Status *string `json:\"status,omitempty\" form:\"%s\"`\n", col.Name))
}
}
modelContent.WriteString("}\n")
}
// Add filter struct
modelContent += `
// Filter struct untuk query parameters
type ` + data.Name + `Filter struct {
Status *string ` + "`json:\"status,omitempty\" form:\"status\"`" + `
Search *string ` + "`json:\"search,omitempty\" form:\"search\"`" + `
DateFrom *time.Time ` + "`json:\"date_from,omitempty\" form:\"date_from\"`" + `
DateTo *time.Time ` + "`json:\"date_to,omitempty\" form:\"date_to\"`" + `
writeFile(modelFilePath, modelContent.String())
fmt.Printf("Successfully generated DYNAMIC model: %s\n", modelFileName)
}
`
writeFile(modelFilePath, modelContent)
fmt.Printf("Successfully generated model: %s\n", modelFileName)
// MODIFIKASI: Fungsi pembantu untuk memetakan tipe SQL ke Go
func mapSQLTypeToGo(sqlType string, nullable bool, explicitGoType string) (goType string, baseType string, valueType string) {
sqlType = strings.ToLower(sqlType)
if explicitGoType != "" {
baseType = explicitGoType
if nullable {
switch baseType {
case "string":
goType, valueType = "sql.NullString", "String"
case "int32":
goType, valueType = "sql.NullInt32", "Int32"
case "int64":
goType, valueType = "sql.NullInt64", "Int64"
case "bool":
goType, valueType = "sql.NullBool", "Bool"
case "float64":
goType, valueType = "sql.NullFloat64", "Float64"
case "time.Time":
goType, valueType = "sql.NullTime", "Time"
default:
goType, valueType = "sql.NullString", "String" // fallback
}
} else {
goType = baseType
}
return goType, baseType, valueType
}
switch {
case strings.Contains(sqlType, "serial") || sqlType == "int4":
if nullable {
return "sql.NullInt32", "int32", "Int32"
}
return "int32", "int32", ""
case sqlType == "int8" || sqlType == "bigint":
if nullable {
return "sql.NullInt64", "int64", "Int64"
}
return "int64", "int64", ""
case sqlType == "uuid":
if nullable {
return "sql.NullString", "string", "String"
}
return "string", "string", ""
case strings.Contains(sqlType, "varchar") || strings.Contains(sqlType, "text") || sqlType == "char":
if nullable {
return "sql.NullString", "string", "String"
}
return "string", "string", ""
case sqlType == "bool":
if nullable {
return "sql.NullBool", "bool", "Bool"
}
return "bool", "bool", ""
case strings.Contains(sqlType, "timestamp") || strings.Contains(sqlType, "date"):
if nullable {
return "sql.NullTime", "time.Time", "Time"
}
return "time.Time", "time.Time", ""
case strings.Contains(sqlType, "decimal") || strings.Contains(sqlType, "numeric") || sqlType == "float8" || sqlType == "real":
if nullable {
return "sql.NullFloat64", "float64", "Float64"
}
return "float64", "float64", ""
default:
if nullable {
return "sql.NullString", "string", "String"
}
return "string", "string", ""
}
}
func snakeToPascal(s string) string {
if s == "" {
return ""
}
// Pisahkan string berdasarkan underscore
parts := strings.Split(s, "_")
var pascal strings.Builder
for _, part := range parts {
if part == "" {
continue // Lewati bagian kosong jika ada double underscore
}
lowerPart := strings.ToLower(part)
// Handle common acronyms
if lowerPart == "id" {
pascal.WriteString("ID")
} else {
// Ubah huruf pertama menjadi kapital dan sisanya kecil
pascal.WriteString(strings.Title(lowerPart))
}
}
return pascal.String()
}
// snakeToCamel mengubah string dari snake_case menjadi camelCase.
// Contoh: "nama_hari" -> "namaHari"
func snakeToCamel(s string) string {
if s == "" {
return ""
}
parts := strings.Split(s, "_")
if len(parts) == 1 {
return strings.ToLower(parts[0])
}
// Bagian pertama: huruf pertama kecil
var camel strings.Builder
camel.WriteString(strings.ToLower(parts[0]))
// Bagian selanjutnya: huruf pertama besar (PascalCase)
for i := 1; i < len(parts); i++ {
if parts[i] == "" {
continue
}
camel.WriteString(strings.Title(strings.ToLower(parts[i])))
}
return camel.String()
}
// ================= ROUTES GENERATION =====================

View File

@@ -15,141 +15,141 @@ services:
retry_count: 3
endpoints:
# retribusi:
# description: "Retribusi tariff management"
# handler_folder: "retribusi"
# handler_file: "retribusi.go"
# handler_name: "Retribusi"
# table_name: "data_retribusi"
# functions:
# list:
# methods: ["GET"]
# path: "/"
# get_routes: "/"
# get_path: "/"
# model: "Retribusi"
# response_model: "RetribusiGetResponse"
# description: "Get retribusi list with pagination and filters"
# summary: "Get Retribusi List"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: true
# enable_database: true
# cache_ttl: 300
# has_pagination: true
# has_filter: true
# has_search: true
# has_stats: true
retribusi:
description: "Retribusi tariff management"
handler_folder: "retribusi"
handler_file: "retribusi.go"
handler_name: "Retribusi"
table_name: "data_retribusi"
functions:
list:
methods: ["GET"]
path: "/"
get_routes: "/"
get_path: "/"
model: "Retribusi"
response_model: "RetribusiGetResponse"
description: "Get retribusi list with pagination and filters"
summary: "Get Retribusi List"
tags: ["Retribusi"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
has_pagination: true
has_filter: true
has_search: true
has_stats: true
# get:
# methods: ["GET"]
# path: "/:id"
# get_routes: "/:id"
# get_path: "/:id"
# model: "Retribusi"
# response_model: "RetribusiGetByIDResponse"
# description: "Get retribusi by ID"
# summary: "Get Retribusi by ID"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: true
# enable_database: true
# cache_ttl: 300
get:
methods: ["GET"]
path: "/:id"
get_routes: "/:id"
get_path: "/:id"
model: "Retribusi"
response_model: "RetribusiGetByIDResponse"
description: "Get retribusi by ID"
summary: "Get Retribusi by ID"
tags: ["Retribusi"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
# dynamic:
# methods: ["GET"]
# path: "/dynamic"
# get_routes: "/dynamic"
# get_path: "/dynamic"
# model: "Retribusi"
# response_model: "RetribusiGetResponse"
# description: "Get retribusi with dynamic filtering"
# summary: "Get Retribusi Dynamic"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: true
# enable_database: true
# cache_ttl: 300
# has_dynamic: true
dynamic:
methods: ["GET"]
path: "/dynamic"
get_routes: "/dynamic"
get_path: "/dynamic"
model: "Retribusi"
response_model: "RetribusiGetResponse"
description: "Get retribusi with dynamic filtering"
summary: "Get Retribusi Dynamic"
tags: ["Retribusi"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
has_dynamic: true
# search:
# methods: ["GET"]
# path: "/search"
# get_routes: "/search"
# get_path: "/search"
# model: "Retribusi"
# response_model: "RetribusiGetResponse"
# description: "Search retribusi"
# summary: "Search Retribusi"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: true
# enable_database: true
# cache_ttl: 300
# has_search: true
search:
methods: ["GET"]
path: "/search"
get_routes: "/search"
get_path: "/search"
model: "Retribusi"
response_model: "RetribusiGetResponse"
description: "Search retribusi"
summary: "Search Retribusi"
tags: ["Retribusi"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
has_search: true
# create:
# methods: ["POST"]
# path: "/"
# post_routes: "/"
# post_path: "/"
# model: "RetribusiCreateRequest"
# response_model: "RetribusiCreateResponse"
# request_model: "RetribusiCreateRequest"
# description: "Create new retribusi"
# summary: "Create Retribusi"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: false
# enable_database: true
# cache_ttl: 0
create:
methods: ["POST"]
path: "/"
post_routes: "/"
post_path: "/"
model: "RetribusiCreateRequest"
response_model: "RetribusiCreateResponse"
request_model: "RetribusiCreateRequest"
description: "Create new retribusi"
summary: "Create Retribusi"
tags: ["Retribusi"]
require_auth: true
cache_enabled: false
enable_database: true
cache_ttl: 0
# update:
# methods: ["PUT"]
# path: "/:id"
# put_routes: "/:id"
# put_path: "/:id"
# model: "RetribusiUpdateRequest"
# response_model: "RetribusiUpdateResponse"
# request_model: "RetribusiUpdateRequest"
# description: "Update retribusi"
# summary: "Update Retribusi"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: false
# enable_database: true
# cache_ttl: 0
update:
methods: ["PUT"]
path: "/:id"
put_routes: "/:id"
put_path: "/:id"
model: "RetribusiUpdateRequest"
response_model: "RetribusiUpdateResponse"
request_model: "RetribusiUpdateRequest"
description: "Update retribusi"
summary: "Update Retribusi"
tags: ["Retribusi"]
require_auth: true
cache_enabled: false
enable_database: true
cache_ttl: 0
# delete:
# methods: ["DELETE"]
# path: "/:id"
# delete_routes: "/:id"
# delete_path: "/:id"
# model: "Retribusi"
# response_model: "RetribusiDeleteResponse"
# description: "Delete retribusi"
# summary: "Delete Retribusi"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: false
# enable_database: true
# cache_ttl: 0
delete:
methods: ["DELETE"]
path: "/:id"
delete_routes: "/:id"
delete_path: "/:id"
model: "Retribusi"
response_model: "RetribusiDeleteResponse"
description: "Delete retribusi"
summary: "Delete Retribusi"
tags: ["Retribusi"]
require_auth: true
cache_enabled: false
enable_database: true
cache_ttl: 0
# stats:
# methods: ["GET"]
# path: "/stats"
# get_routes: "/stats"
# get_path: "/stats"
# model: "AggregateData"
# response_model: "AggregateData"
# description: "Get retribusi statistics"
# summary: "Get Retribusi Stats"
# tags: ["Retribusi"]
# require_auth: true
# cache_enabled: true
# enable_database: true
# cache_ttl: 180
# has_stats: true
stats:
methods: ["GET"]
path: "/stats"
get_routes: "/stats"
get_path: "/stats"
model: "AggregateData"
response_model: "AggregateData"
description: "Get retribusi statistics"
summary: "Get Retribusi Stats"
tags: ["Retribusi"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 180
has_stats: true
# Example of another service
user:
@@ -248,3 +248,180 @@ services:
cache_enabled: false
enable_database: true
cache_ttl: 0
search:
methods: ["GET"]
path: "/search"
get_routes: "/search"
get_path: "/search"
model: "User"
response_model: "UserGetResponse"
description: "Search user"
summary: "Search User"
tags: ["User"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
has_search: true
schedule:
name: "Jadwal Dokter"
category: "schedule"
package: "schedule"
description: "Jadwal Dokter management"
base_url: ""
timeout: 30
retry_count: 3
endpoints:
schedule:
description: "Jadwal dokter management"
handler_folder: "master"
handler_file: "schedule.go"
handler_name: "schedule"
table_name: "daftar_jadwal_dokter"
# Definisikan skema tabel di sini
# =
schema:
columns:
- name: "id"
type: "serial4"
primary_key: true
go_type: "string" # Override tipe Go, UUID biasanya string
- name: "Hari"
type: "int4"
nullable: true
- name: "Nama_hari"
type: "varchar"
nullable: true
- name: "Waktu"
type: "varchar"
nullable: true
- name: "Dokter"
type: "uuid"
nullable: true
go_type: "string" # Override tipe Go
- name: "Spesialis"
type: "int4"
nullable: true
- name: "Sub_spesialis"
type: "int4"
nullable: true
- name: "Status"
type: "int4"
nullable: true
# ======================================================================
functions:
list:
methods: ["GET"]
path: "/"
get_routes: "/"
get_path: "/"
model: "Schedule"
response_model: "ScheduleGetResponse"
description: "Get schedule list with pagination and filters"
summary: "Get Schedule List"
tags: ["Schedule"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
has_pagination: true
has_filter: true
has_search: true
has_stats: true
get:
methods: ["GET"]
path: "/:id"
get_routes: "/:id"
get_path: "/:id"
model: "Schedule"
response_model: "ScheduleGetByIDResponse"
description: "Get schedule by ID"
summary: "Get schedule by ID"
tags: ["Schedule"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
search:
methods: ["GET"]
path: "/search"
get_routes: "/search"
get_path: "/search"
model: "Schedule"
response_model: "ScheduleGetResponse"
description: "Search schedule"
summary: "Search Schedule"
tags: ["Schedule"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 300
has_search: true
create:
methods: ["POST"]
path: "/"
post_routes: "/"
post_path: "/"
model: "Schedule"
response_model: "ScheduleCreateResponse"
request_model: "ScheduleCreateRequest"
description: "Create new schedule"
summary: "Create Schedule"
tags: ["Schedule"]
require_auth: true
cache_enabled: false
enable_database: true
cache_ttl: 0
update:
methods: ["PUT"]
path: "/:id"
put_routes: "/:id"
put_path: "/:id"
model: "Schedule"
response_model: "ScheduleUpdateResponse"
request_model: "ScheduleUpdateRequest"
description: "Update schedule"
summary: "Update Schedule"
tags: ["Schedule"]
require_auth: true
cache_enabled: false
enable_database: true
cache_ttl: 0
delete:
methods: ["DELETE"]
path: "/:id"
delete_routes: "/:id"
delete_path: "/:id"
model: "Schedule"
response_model: "ScheduleDeleteResponse"
description: "Delete schedule"
summary: "Delete Schedule"
tags: ["Schedule"]
require_auth: true
cache_enabled: false
enable_database: true
cache_ttl: 0
stats:
methods: ["GET"]
path: "/stats"
get_routes: "/stats"
get_path: "/stats"
model: "AggregateData"
response_model: "AggregateData"
description: "Get retribusi statistics"
summary: "Get Retribusi Stats"
tags: ["Retribusi"]
require_auth: true
cache_enabled: true
enable_database: true
cache_ttl: 180
has_stats: true