aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-08 02:27:15 +0530
committerBobby <[email protected]>2026-03-08 02:27:15 +0530
commitcca905d35412f1549400fc3d1aca6dc704d8cae6 (patch)
tree0c0231f5c2ebaeb7700e08a2c1f07373d3251658 /utils
parent547384c41181c034a5eaf340c5e569d36eb013be (diff)
downloaddove-cca905d35412f1549400fc3d1aca6dc704d8cae6.tar.xz
dove-cca905d35412f1549400fc3d1aca6dc704d8cae6.zip
feat(domains): add new TLD creation page and update sidebar
- Introduced a new HTMX template for creating TLDs. - Created a new Django template for the new TLD page. - Updated the sidebar to include a link to the domains section. refactor(types): remove unused types and consolidate request handling - Deleted unused type definitions related to authentication, errors, mailboxes, overview, requests, responses, and users. - Introduced a new collections package for generic data structures. - Refactored request handling to use a more streamlined approach with RequestInfo and Param types. fix(meta): improve pagination and sorting functionality - Updated pagination logic to handle default values and edge cases. - Introduced a new Sorting type for better sorting management in queries. chore(urls): refactor URL handling and registry - Replaced enums with string constants for HTTP methods. - Consolidated route registration logic and improved type safety with RegisteredRoute. style(shortcuts): clean up error handling and rendering functions - Enhanced error handling functions for better readability and maintainability. - Removed deprecated functions and improved the structure of rendering logic.
Diffstat (limited to 'utils')
-rw-r--r--utils/collections/record.go3
-rw-r--r--utils/collections/set.go38
-rw-r--r--utils/collections/types.go3
-rw-r--r--utils/meta/builder.go46
-rw-r--r--utils/meta/constants.go9
-rw-r--r--utils/meta/defaults.go9
-rw-r--r--utils/meta/functions.go53
-rw-r--r--utils/meta/messages.go5
-rw-r--r--utils/meta/pagination.go71
-rw-r--r--utils/meta/request.go78
-rw-r--r--utils/meta/sorting.go39
-rw-r--r--utils/meta/types.go26
-rw-r--r--utils/meta/value.go35
-rw-r--r--utils/shortcuts/error.go51
-rw-r--r--utils/shortcuts/functions.go110
-rw-r--r--utils/shortcuts/messages.go5
-rw-r--r--utils/shortcuts/render.go108
-rw-r--r--utils/toml/load.go4
-rw-r--r--utils/urls/attach.go22
-rw-r--r--utils/urls/functions.go30
-rw-r--r--utils/urls/path.go45
-rw-r--r--utils/urls/registry.go27
-rw-r--r--utils/urls/types.go25
23 files changed, 425 insertions, 417 deletions
diff --git a/utils/collections/record.go b/utils/collections/record.go
new file mode 100644
index 0000000..a204436
--- /dev/null
+++ b/utils/collections/record.go
@@ -0,0 +1,3 @@
+package collections
+
+type Record[K comparable, V any] map[K]V
diff --git a/utils/collections/set.go b/utils/collections/set.go
new file mode 100644
index 0000000..79e1ae2
--- /dev/null
+++ b/utils/collections/set.go
@@ -0,0 +1,38 @@
+package collections
+
+type Set[T comparable] struct {
+ items []T
+ index map[T]bool
+}
+
+func SetOf[T comparable](items ...T) Set[T] {
+ index := make(map[T]bool, len(items))
+ uniqueItems := make([]T, 0, len(items))
+
+ for _, item := range items {
+ if index[item] {
+ continue
+ }
+ index[item] = true
+ uniqueItems = append(uniqueItems, item)
+ }
+
+ return Set[T]{
+ items: uniqueItems,
+ index: index,
+ }
+}
+
+func (set Set[T]) Contains(item T) bool {
+ return set.index[item]
+}
+
+func (set Set[T]) All() []T {
+ copied := make([]T, len(set.items))
+ copy(copied, set.items)
+ return copied
+}
+
+func (set Set[T]) Len() int {
+ return len(set.items)
+}
diff --git a/utils/collections/types.go b/utils/collections/types.go
deleted file mode 100644
index ac84e76..0000000
--- a/utils/collections/types.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package collections
-
-type Record[T any] map[string]T
diff --git a/utils/meta/builder.go b/utils/meta/builder.go
index 4ae2648..3e4de93 100644
--- a/utils/meta/builder.go
+++ b/utils/meta/builder.go
@@ -1,13 +1,9 @@
package meta
-import (
- "dove/types"
+import "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2"
-)
-
-func BuildRequest(context *fiber.Ctx) types.Request {
- return types.Request{
+func BuildRequest(context *fiber.Ctx) RequestInfo {
+ return RequestInfo{
Path: context.Path(),
Method: context.Method(),
Query: buildQueryParams(context),
@@ -18,3 +14,39 @@ func BuildRequest(context *fiber.Ctx) types.Request {
URL: context.OriginalURL(),
}
}
+
+func buildQueryParams(context *fiber.Ctx) []Param {
+ params := make([]Param, 0)
+ context.Request().URI().QueryArgs().VisitAll(func(name []byte, paramValue []byte) {
+ params = append(params, Param{
+ Key: string(name),
+ Value: string(paramValue),
+ })
+ })
+
+ return params
+}
+
+func buildRouteParams(context *fiber.Ctx) []Param {
+ params := make([]Param, 0)
+ for name, routeValue := range context.AllParams() {
+ params = append(params, Param{
+ Key: name,
+ Value: routeValue,
+ })
+ }
+
+ return params
+}
+
+func buildHeaders(context *fiber.Ctx) []Param {
+ params := make([]Param, 0)
+ context.Request().Header.VisitAll(func(name []byte, headerValue []byte) {
+ params = append(params, Param{
+ Key: string(name),
+ Value: string(headerValue),
+ })
+ })
+
+ return params
+}
diff --git a/utils/meta/constants.go b/utils/meta/constants.go
deleted file mode 100644
index 13a2fde..0000000
--- a/utils/meta/constants.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package meta
-
-const (
- DEFAULT_PAGE = 1
- DEFAULT_PER_PAGE = 20
- LOG_PREFIX = "Meta"
- MAX_PER_PAGE = 50
- REQUEST_KEY = "Request"
-)
diff --git a/utils/meta/defaults.go b/utils/meta/defaults.go
new file mode 100644
index 0000000..9ba6dfe
--- /dev/null
+++ b/utils/meta/defaults.go
@@ -0,0 +1,9 @@
+package meta
+
+const (
+ DefaultPage = 1
+ DefaultPerPage = 20
+ LogPrefix = "Meta"
+ MaxPerPage = 50
+ RequestKey = "Request"
+)
diff --git a/utils/meta/functions.go b/utils/meta/functions.go
deleted file mode 100644
index 0b8f309..0000000
--- a/utils/meta/functions.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package meta
-
-import (
- "dove/types"
-
- "github.com/gofiber/fiber/v2"
-)
-
-func findParam(params []types.Param, key string) (string, bool) {
- for _, param := range params {
- if param.Key == key {
- return param.Value, true
- }
- }
-
- return "", false
-}
-
-func buildQueryParams(context *fiber.Ctx) []types.Param {
- params := make([]types.Param, 0)
- context.Request().URI().QueryArgs().VisitAll(func(name []byte, paramValue []byte) {
- params = append(params, types.Param{
- Key: string(name),
- Value: string(paramValue),
- })
- })
-
- return params
-}
-
-func buildRouteParams(context *fiber.Ctx) []types.Param {
- params := make([]types.Param, 0)
- for name, routeValue := range context.AllParams() {
- params = append(params, types.Param{
- Key: name,
- Value: routeValue,
- })
- }
-
- return params
-}
-
-func buildHeaders(context *fiber.Ctx) []types.Param {
- params := make([]types.Param, 0)
- context.Request().Header.VisitAll(func(name []byte, headerValue []byte) {
- params = append(params, types.Param{
- Key: string(name),
- Value: string(headerValue),
- })
- })
-
- return params
-}
diff --git a/utils/meta/messages.go b/utils/meta/messages.go
new file mode 100644
index 0000000..2814d7c
--- /dev/null
+++ b/utils/meta/messages.go
@@ -0,0 +1,5 @@
+package meta
+
+const (
+ RequestContextMissing = "Request context missing in fiber locals."
+)
diff --git a/utils/meta/pagination.go b/utils/meta/pagination.go
index 9244294..d0dda08 100644
--- a/utils/meta/pagination.go
+++ b/utils/meta/pagination.go
@@ -1,80 +1,59 @@
package meta
import (
- "dove/types"
"strconv"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
)
-func Paginate(context *fiber.Ctx) Pagination {
- requestData := Request(context)
-
- page := DEFAULT_PAGE
- perPage := DEFAULT_PER_PAGE
-
- if requestData != nil {
- if pageValue := requestData.Query("page"); pageValue != nil {
- parsed, _ := strconv.Atoi(pageValue.String())
- if parsed >= DEFAULT_PAGE {
- page = parsed
- }
- }
-
- if perPageValue := requestData.Query("per_page"); perPageValue != nil {
- parsed, _ := strconv.Atoi(perPageValue.String())
- if parsed >= DEFAULT_PAGE && parsed <= MAX_PER_PAGE {
- perPage = parsed
- }
- }
- }
+type Pagination struct {
+ Page int
+ PerPage int
+}
- return Pagination{Page: page, PerPage: perPage}
+type PaginatedResponse struct {
+ Items any `json:"items"`
+ Total int64 `json:"total"`
+ Page int `json:"page"`
+ PerPage int `json:"per_page"`
+ TotalPages int `json:"total_pages"`
}
-func Sort(context *fiber.Ctx, allowedFields []string, fallbackField string) Sorting {
+func Paginate(context *fiber.Ctx) Pagination {
requestData := Request(context)
- field := fallbackField
- direction := "desc"
+ page := DefaultPage
+ perPage := DefaultPerPage
- if requestData != nil {
- if sortValue := requestData.Query("sort"); sortValue != nil {
- for _, allowedField := range allowedFields {
- if sortValue.String() == allowedField {
- field = sortValue.String()
- break
- }
- }
+ if pageValue := requestData.Query("page"); pageValue != "" {
+ parsed, _ := strconv.Atoi(pageValue)
+ if parsed >= DefaultPage {
+ page = parsed
}
+ }
- if orderValue := requestData.Query("order"); orderValue != nil {
- switch orderValue.String() {
- case "asc", "desc":
- direction = orderValue.String()
- }
+ if perPageValue := requestData.Query("per_page"); perPageValue != "" {
+ parsed, _ := strconv.Atoi(perPageValue)
+ if parsed >= DefaultPage && parsed <= MaxPerPage {
+ perPage = parsed
}
}
- return Sorting{Field: field, Direction: direction}
+ return Pagination{Page: page, PerPage: perPage}
}
func (self Pagination) Apply(query *gorm.DB) *gorm.DB {
return query.Offset((self.Page - 1) * self.PerPage).Limit(self.PerPage)
}
-func (self Sorting) Apply(query *gorm.DB) *gorm.DB {
- return query.Order(self.Field + " " + self.Direction)
-}
-
-func (self Pagination) Response(items any, total int64) types.PaginatedResponse {
+func (self Pagination) Response(items any, total int64) PaginatedResponse {
totalPages := int(total) / self.PerPage
if int(total)%self.PerPage > 0 {
totalPages++
}
- return types.PaginatedResponse{
+ return PaginatedResponse{
Items: items,
Total: total,
Page: self.Page,
diff --git a/utils/meta/request.go b/utils/meta/request.go
index 34a659a..e9a3720 100644
--- a/utils/meta/request.go
+++ b/utils/meta/request.go
@@ -1,63 +1,75 @@
package meta
import (
- "dove/messages"
- "dove/types"
"dove/utils/logger"
"github.com/gofiber/fiber/v2"
)
-func Request(context *fiber.Ctx) *request {
- data, ok := context.Locals(REQUEST_KEY).(types.Request)
+type Param struct {
+ Key string
+ Value string
+}
+
+type RequestInfo struct {
+ Path string
+ Method string
+ Query []Param
+ Params []Param
+ Headers []Param
+ QueryString string
+ IP string
+ URL string
+}
+
+type RequestData struct {
+ RequestInfo
+ Context *fiber.Ctx
+}
+
+func Request(context *fiber.Ctx) *RequestData {
+ data, ok := context.Locals(RequestKey).(RequestInfo)
if !ok {
- logger.Errorf(LOG_PREFIX, messages.MetaRequestContextMissing)
+ logger.Errorf(LogPrefix, RequestContextMissing)
return nil
}
- return &request{
- Request: data,
- context: context,
+ return &RequestData{
+ RequestInfo: data,
+ Context: context,
}
}
-func (self *request) Param(key string) *value {
- if self == nil {
- return nil
- }
-
- if self.context != nil {
- result := self.context.Params(key)
- if result != "" {
- return &value{data: result}
- }
+func (self *RequestData) Param(key string) string {
+ if self == nil || self.Context == nil {
+ return ""
}
- return nil
+ return self.Context.Params(key)
}
-func (self *request) Query(key string) *value {
+func (self *RequestData) Query(key string) string {
if self == nil {
- return nil
- }
-
- result, found := findParam(self.Request.Query, key)
- if found {
- return &value{data: result}
+ return ""
}
- return nil
+ return findParam(self.RequestInfo.Query, key)
}
-func (self *request) Header(key string) *value {
+func (self *RequestData) Header(key string) string {
if self == nil {
- return nil
+ return ""
}
- result, found := findParam(self.Request.Headers, key)
- if found {
- return &value{data: result}
+ return findParam(self.RequestInfo.Headers, key)
+}
+
+func findParam(params []Param, key string) string {
+ for _, param := range params {
+ if param.Key == key {
+ return param.Value
+ }
}
- return nil
+ return ""
}
diff --git a/utils/meta/sorting.go b/utils/meta/sorting.go
new file mode 100644
index 0000000..93788f0
--- /dev/null
+++ b/utils/meta/sorting.go
@@ -0,0 +1,39 @@
+package meta
+
+import (
+ "slices"
+
+ "github.com/gofiber/fiber/v2"
+ "gorm.io/gorm"
+)
+
+type Sorting struct {
+ Field string
+ Direction string
+}
+
+func Sort(context *fiber.Ctx, allowedFields []string, fallbackField string) Sorting {
+ requestData := Request(context)
+
+ field := fallbackField
+ direction := "desc"
+
+ if sortValue := requestData.Query("sort"); sortValue != "" {
+ if slices.Contains(allowedFields, sortValue) {
+ field = sortValue
+ }
+ }
+
+ if orderValue := requestData.Query("order"); orderValue != "" {
+ switch orderValue {
+ case "asc", "desc":
+ direction = orderValue
+ }
+ }
+
+ return Sorting{Field: field, Direction: direction}
+}
+
+func (self Sorting) Apply(query *gorm.DB) *gorm.DB {
+ return query.Order(self.Field + " " + self.Direction)
+}
diff --git a/utils/meta/types.go b/utils/meta/types.go
deleted file mode 100644
index c7b8e4d..0000000
--- a/utils/meta/types.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package meta
-
-import (
- "dove/types"
-
- "github.com/gofiber/fiber/v2"
-)
-
-type request struct {
- types.Request
- context *fiber.Ctx
-}
-
-type value struct {
- data string
-}
-
-type Pagination struct {
- Page int
- PerPage int
-}
-
-type Sorting struct {
- Field string
- Direction string
-}
diff --git a/utils/meta/value.go b/utils/meta/value.go
deleted file mode 100644
index 889ba0e..0000000
--- a/utils/meta/value.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package meta
-
-import (
- "dove/messages"
- "dove/utils/logger"
-)
-
-func (self *value) String() string {
- if self == nil {
- return ""
- }
-
- return self.data
-}
-
-func (self *value) Exists() bool {
- return self != nil
-}
-
-func (self *value) Or(fallback string) string {
- if self == nil {
- return fallback
- }
-
- return self.data
-}
-
-func (self *value) Required() string {
- if self == nil {
- logger.Errorf(LOG_PREFIX, messages.MetaRequiredValueMissing)
- return ""
- }
-
- return self.data
-}
diff --git a/utils/shortcuts/error.go b/utils/shortcuts/error.go
index 71fa4bd..c22e6b2 100644
--- a/utils/shortcuts/error.go
+++ b/utils/shortcuts/error.go
@@ -1,29 +1,44 @@
package shortcuts
-import (
- "dove/enums"
- "dove/types"
+import "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2"
+type ErrorKind string
+
+const (
+ BadRequest ErrorKind = "bad_request"
+ Forbidden ErrorKind = "forbidden"
+ Internal ErrorKind = "internal"
+ NotFound ErrorKind = "not_found"
+ Unauthorized ErrorKind = "unauthorized"
+ Unprocessable ErrorKind = "unprocessable"
)
-var statusMap = map[enums.ErrorKind]int{
- enums.BadRequest: fiber.StatusBadRequest,
- enums.Forbidden: fiber.StatusForbidden,
- enums.Internal: fiber.StatusInternalServerError,
- enums.NotFound: fiber.StatusNotFound,
- enums.Unauthorized: fiber.StatusUnauthorized,
- enums.Unprocessable: fiber.StatusUnprocessableEntity,
+type Error struct {
+ Kind ErrorKind
+ Message string
+}
+
+func (self *Error) Error() string {
+ return self.Message
+}
+
+var statusMap = map[ErrorKind]int{
+ BadRequest: fiber.StatusBadRequest,
+ Forbidden: fiber.StatusForbidden,
+ Internal: fiber.StatusInternalServerError,
+ NotFound: fiber.StatusNotFound,
+ Unauthorized: fiber.StatusUnauthorized,
+ Unprocessable: fiber.StatusUnprocessableEntity,
}
-func ServiceError(kind enums.ErrorKind, message string) *types.ServiceError {
- return &types.ServiceError{
+func ServiceError(kind ErrorKind, message string) *Error {
+ return &Error{
Kind: kind,
Message: message,
}
}
-func HandleError(context *fiber.Ctx, serviceError *types.ServiceError) error {
+func HandleError(context *fiber.Ctx, serviceError *Error) error {
statusCode, exists := statusMap[serviceError.Kind]
if !exists {
statusCode = fiber.StatusInternalServerError
@@ -34,13 +49,13 @@ func HandleError(context *fiber.Ctx, serviceError *types.ServiceError) error {
}, statusCode)
}
-func BadRequest(context *fiber.Ctx, err error) error {
+func BadRequestError(context *fiber.Ctx, err error) error {
return RenderWithStatus(context, "error", fiber.Map{
"ErrorMessage": err.Error(),
}, fiber.StatusBadRequest)
}
-func Forbidden(context *fiber.Ctx, err error) error {
+func ForbiddenError(context *fiber.Ctx, err error) error {
return RenderWithStatus(context, "error", fiber.Map{
"ErrorMessage": err.Error(),
}, fiber.StatusForbidden)
@@ -52,13 +67,13 @@ func InternalServerError(context *fiber.Ctx, err error) error {
}, fiber.StatusInternalServerError)
}
-func NotFound(context *fiber.Ctx, err error) error {
+func NotFoundError(context *fiber.Ctx, err error) error {
return RenderWithStatus(context, "error", fiber.Map{
"ErrorMessage": err.Error(),
}, fiber.StatusNotFound)
}
-func Unauthorized(context *fiber.Ctx, err error) error {
+func UnauthorizedError(context *fiber.Ctx, err error) error {
return RenderWithStatus(context, "error", fiber.Map{
"ErrorMessage": err.Error(),
}, fiber.StatusUnauthorized)
diff --git a/utils/shortcuts/functions.go b/utils/shortcuts/functions.go
deleted file mode 100644
index 3e76a9a..0000000
--- a/utils/shortcuts/functions.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package shortcuts
-
-import (
- "fmt"
- "maps"
- "path"
- "reflect"
- "strings"
-
- "dove/messages"
- "dove/utils/errors"
-
- "github.com/gofiber/fiber/v2"
-)
-
-func resolveTemplate(context *fiber.Ctx, templateName string) string {
- switch {
- case context.Get("HX-Request") == "true" && context.Get("HX-Boosted") != "true":
- directory := path.Dir(templateName)
- filename := path.Base(templateName)
- return fmt.Sprintf("%s/htmx/%s.htmx", directory, filename)
- default:
- return templateName
- }
-}
-
-func mergeContextValues(context *fiber.Ctx, targetMap fiber.Map) {
- context.Context().VisitUserValues(func(key []byte, value any) {
- targetMap[string(key)] = value
- })
-}
-
-func mergeBindData(targetMap fiber.Map, data any) error {
- normalizedData, normalizeError := normalizeToMap(data)
- if normalizeError != nil {
- return normalizeError
- }
-
- maps.Copy(targetMap, normalizedData)
- return nil
-}
-
-func normalizeToMap(data any) (fiber.Map, error) {
- switch typedData := data.(type) {
- case fiber.Map:
- return typedData, nil
- case map[string]any:
- return fiber.Map(typedData), nil
- default:
- return convertStructToMap(data)
- }
-}
-
-func convertStructToMap(data any) (fiber.Map, error) {
- structValue := reflect.ValueOf(data)
-
- switch structValue.Kind() {
- case reflect.Pointer:
- structValue = structValue.Elem()
- }
-
- switch structValue.Kind() {
- case reflect.Struct:
- return extractStructFields(structValue), nil
- default:
- return nil, errors.Error(messages.ShortcutUnsupportedBindType)
- }
-}
-
-func extractStructFields(structValue reflect.Value) fiber.Map {
- structType := structValue.Type()
- fieldMap := make(fiber.Map, structValue.NumField())
-
- for fieldIndex := range structType.NumField() {
- fieldDescriptor := structType.Field(fieldIndex)
-
- if !fieldDescriptor.IsExported() {
- continue
- }
-
- fieldKey := resolveFieldKey(fieldDescriptor)
- fieldMap[fieldKey] = structValue.Field(fieldIndex).Interface()
- }
-
- return fieldMap
-}
-
-func resolveFieldKey(fieldDescriptor reflect.StructField) string {
- jsonTag := fieldDescriptor.Tag.Get("json")
-
- switch {
- case jsonTag == "" || jsonTag == "-":
- return fieldDescriptor.Name
- default:
- return extractTagName(jsonTag, fieldDescriptor.Name)
- }
-}
-
-func extractTagName(jsonTag string, fallbackName string) string {
- separatorIndex := strings.IndexByte(jsonTag, ',')
-
- switch {
- case separatorIndex < 0:
- return jsonTag
- case separatorIndex > 0:
- return jsonTag[:separatorIndex]
- default:
- return fallbackName
- }
-} \ No newline at end of file
diff --git a/utils/shortcuts/messages.go b/utils/shortcuts/messages.go
new file mode 100644
index 0000000..92df139
--- /dev/null
+++ b/utils/shortcuts/messages.go
@@ -0,0 +1,5 @@
+package shortcuts
+
+const (
+ UnsupportedBindType = "Bind data must be a struct, *struct, fiber.Map, or map[string]any."
+)
diff --git a/utils/shortcuts/render.go b/utils/shortcuts/render.go
index e91ccfa..89779cf 100644
--- a/utils/shortcuts/render.go
+++ b/utils/shortcuts/render.go
@@ -1,6 +1,16 @@
package shortcuts
-import "github.com/gofiber/fiber/v2"
+import (
+ "fmt"
+ "maps"
+ "path"
+ "reflect"
+ "strings"
+
+ "dove/utils/errors"
+
+ "github.com/gofiber/fiber/v2"
+)
func Render(context *fiber.Ctx, templateName string, data any) error {
templateData := make(fiber.Map)
@@ -20,3 +30,99 @@ func RenderWithStatus(context *fiber.Ctx, templateName string, data any, statusC
context.Status(statusCode)
return Render(context, templateName, data)
}
+
+func resolveTemplate(context *fiber.Ctx, templateName string) string {
+ switch {
+ case context.Get("HX-Request") == "true" && context.Get("HX-Boosted") != "true":
+ directory := path.Dir(templateName)
+ filename := path.Base(templateName)
+ return fmt.Sprintf("%s/htmx/%s.htmx", directory, filename)
+ default:
+ return templateName
+ }
+}
+
+func mergeContextValues(context *fiber.Ctx, targetMap fiber.Map) {
+ context.Context().VisitUserValues(func(key []byte, value any) {
+ targetMap[string(key)] = value
+ })
+}
+
+func mergeBindData(targetMap fiber.Map, data any) error {
+ normalizedData, normalizeError := normalizeToMap(data)
+ if normalizeError != nil {
+ return normalizeError
+ }
+
+ maps.Copy(targetMap, normalizedData)
+ return nil
+}
+
+func normalizeToMap(data any) (fiber.Map, error) {
+ switch typedData := data.(type) {
+ case fiber.Map:
+ return typedData, nil
+ case map[string]any:
+ return fiber.Map(typedData), nil
+ default:
+ return convertStructToMap(data)
+ }
+}
+
+func convertStructToMap(data any) (fiber.Map, error) {
+ structValue := reflect.ValueOf(data)
+
+ switch structValue.Kind() {
+ case reflect.Pointer:
+ structValue = structValue.Elem()
+ }
+
+ switch structValue.Kind() {
+ case reflect.Struct:
+ return extractStructFields(structValue), nil
+ default:
+ return nil, errors.Error(UnsupportedBindType)
+ }
+}
+
+func extractStructFields(structValue reflect.Value) fiber.Map {
+ structType := structValue.Type()
+ fieldMap := make(fiber.Map, structValue.NumField())
+
+ for fieldIndex := range structType.NumField() {
+ fieldDescriptor := structType.Field(fieldIndex)
+
+ if !fieldDescriptor.IsExported() {
+ continue
+ }
+
+ fieldKey := resolveFieldKey(fieldDescriptor)
+ fieldMap[fieldKey] = structValue.Field(fieldIndex).Interface()
+ }
+
+ return fieldMap
+}
+
+func resolveFieldKey(fieldDescriptor reflect.StructField) string {
+ jsonTag := fieldDescriptor.Tag.Get("json")
+
+ switch {
+ case jsonTag == "" || jsonTag == "-":
+ return fieldDescriptor.Name
+ default:
+ return extractTagName(jsonTag, fieldDescriptor.Name)
+ }
+}
+
+func extractTagName(jsonTag string, fallbackName string) string {
+ separatorIndex := strings.IndexByte(jsonTag, ',')
+
+ switch {
+ case separatorIndex < 0:
+ return jsonTag
+ case separatorIndex > 0:
+ return jsonTag[:separatorIndex]
+ default:
+ return fallbackName
+ }
+}
diff --git a/utils/toml/load.go b/utils/toml/load.go
index 7b3c31a..71fd0c0 100644
--- a/utils/toml/load.go
+++ b/utils/toml/load.go
@@ -8,7 +8,7 @@ import (
"dove/utils/errors"
)
-var loadedData collections.Record[any]
+var loadedData collections.Record[string, any]
func LoadFile(filePath string) error {
fileContent, readError := os.ReadFile(filePath)
@@ -16,6 +16,6 @@ func LoadFile(filePath string) error {
return errors.Error(messages.ConfigFileReadFailed, filePath, readError.Error())
}
- loadedData = make(collections.Record[any])
+ loadedData = make(collections.Record[string, any])
return unmarshalContent(fileContent, &loadedData)
}
diff --git a/utils/urls/attach.go b/utils/urls/attach.go
index df8a11a..baf9929 100644
--- a/utils/urls/attach.go
+++ b/utils/urls/attach.go
@@ -1,10 +1,6 @@
package urls
-import (
- "dove/enums"
-
- "github.com/gofiber/fiber/v2"
-)
+import "github.com/gofiber/fiber/v2"
func Attach(application *fiber.App) {
registry.Mutex.Lock()
@@ -15,21 +11,21 @@ func Attach(application *fiber.App) {
}
}
-func bindRoute(application *fiber.App, route registeredRoute) {
+func bindRoute(application *fiber.App, route RegisteredRoute) {
switch route.Method {
- case enums.Delete:
+ case Delete:
application.Delete(route.FullPath, route.Handler)
- case enums.Get:
+ case Get:
application.Get(route.FullPath, route.Handler)
- case enums.Head:
+ case Head:
application.Head(route.FullPath, route.Handler)
- case enums.Options:
+ case Options:
application.Options(route.FullPath, route.Handler)
- case enums.Patch:
+ case Patch:
application.Patch(route.FullPath, route.Handler)
- case enums.Post:
+ case Post:
application.Post(route.FullPath, route.Handler)
- case enums.Put:
+ case Put:
application.Put(route.FullPath, route.Handler)
}
}
diff --git a/utils/urls/functions.go b/utils/urls/functions.go
deleted file mode 100644
index 6561025..0000000
--- a/utils/urls/functions.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package urls
-
-import "strings"
-
-func resolveFullName(namespace string, name string) string {
- switch namespace {
- case "":
- return name
- default:
- return namespace + "." + name
- }
-}
-
-func resolveFullPath(namespace string, path string) string {
- switch namespace {
- case "":
- return ensureLeadingSlash(path)
- default:
- return "/" + namespace + ensureLeadingSlash(path)
- }
-}
-
-func ensureLeadingSlash(path string) string {
- switch strings.HasPrefix(path, "/") {
- case true:
- return path
- default:
- return "/" + path
- }
-}
diff --git a/utils/urls/path.go b/utils/urls/path.go
index b865676..a3b3ec9 100644
--- a/utils/urls/path.go
+++ b/utils/urls/path.go
@@ -1,12 +1,24 @@
package urls
import (
- "dove/enums"
+ "strings"
"github.com/gofiber/fiber/v2"
)
-func Path(method enums.HTTPMethod, path string, handler fiber.Handler, name string) {
+type HTTPMethod string
+
+const (
+ Delete HTTPMethod = "DELETE"
+ Get HTTPMethod = "GET"
+ Head HTTPMethod = "HEAD"
+ Options HTTPMethod = "OPTIONS"
+ Patch HTTPMethod = "PATCH"
+ Post HTTPMethod = "POST"
+ Put HTTPMethod = "PUT"
+)
+
+func Path(method HTTPMethod, path string, handler fiber.Handler, name string) {
registry.Mutex.Lock()
defer registry.Mutex.Unlock()
@@ -14,7 +26,7 @@ func Path(method enums.HTTPMethod, path string, handler fiber.Handler, name stri
fullName := resolveFullName(namespace, name)
fullPath := resolveFullPath(namespace, path)
- registry.Routes[fullName] = registeredRoute{
+ registry.Routes[fullName] = RegisteredRoute{
Method: method,
Path: path,
Handler: handler,
@@ -35,3 +47,30 @@ func GetFullPath(routeName string) (string, bool) {
return route.FullPath, true
}
+
+func resolveFullName(namespace string, name string) string {
+ switch namespace {
+ case "":
+ return name
+ default:
+ return namespace + "." + name
+ }
+}
+
+func resolveFullPath(namespace string, path string) string {
+ switch namespace {
+ case "":
+ return ensureLeadingSlash(path)
+ default:
+ return "/" + namespace + ensureLeadingSlash(path)
+ }
+}
+
+func ensureLeadingSlash(path string) string {
+ switch strings.HasPrefix(path, "/") {
+ case true:
+ return path
+ default:
+ return "/" + path
+ }
+}
diff --git a/utils/urls/registry.go b/utils/urls/registry.go
index a713315..e95d30c 100644
--- a/utils/urls/registry.go
+++ b/utils/urls/registry.go
@@ -1,9 +1,30 @@
package urls
-import "dove/utils/collections"
+import (
+ "sync"
-var registry = &routeRegistry{
- Routes: make(collections.Record[registeredRoute]),
+ "dove/utils/collections"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+type RegisteredRoute struct {
+ Method HTTPMethod
+ Path string
+ Handler fiber.Handler
+ Namespace string
+ Name string
+ FullPath string
+}
+
+type RouteRegistry struct {
+ Mutex sync.Mutex
+ CurrentNamespace string
+ Routes collections.Record[string, RegisteredRoute]
+}
+
+var registry = &RouteRegistry{
+ Routes: make(collections.Record[string, RegisteredRoute]),
}
func SetNamespace(namespace string) {
diff --git a/utils/urls/types.go b/utils/urls/types.go
deleted file mode 100644
index 499635b..0000000
--- a/utils/urls/types.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package urls
-
-import (
- "sync"
-
- "dove/enums"
- "dove/utils/collections"
-
- "github.com/gofiber/fiber/v2"
-)
-
-type registeredRoute struct {
- Method enums.HTTPMethod
- Path string
- Handler fiber.Handler
- Namespace string
- Name string
- FullPath string
-}
-
-type routeRegistry struct {
- Mutex sync.Mutex
- CurrentNamespace string
- Routes collections.Record[registeredRoute]
-}