aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-06 23:01:58 +0530
committerBobby <[email protected]>2026-03-06 23:01:58 +0530
commited2a033d7c08e448f5c6fd035e2de8f51431b597 (patch)
treeabe46463fc761b2e4266aadedb6b88c5493ce29b
parent3f07a4b6c745707f135a7a97e93b0fa770b67873 (diff)
downloaddove-ed2a033d7c08e448f5c6fd035e2de8f51431b597.tar.xz
dove-ed2a033d7c08e448f5c6fd035e2de8f51431b597.zip
Implement database connection and routing system with HTTP method support
-rw-r--r--config/config.go2
-rw-r--r--database/constants.go11
-rw-r--r--database/database.go36
-rw-r--r--database/functions.go22
-rw-r--r--enums/http.go13
-rw-r--r--go.mod22
-rw-r--r--go.sum39
-rw-r--r--messages/config.go5
-rw-r--r--messages/database.go7
-rw-r--r--utils/collections/types.go2
-rw-r--r--utils/toml/load.go4
-rw-r--r--utils/urls/attach.go35
-rw-r--r--utils/urls/functions.go30
-rw-r--r--utils/urls/path.go37
-rw-r--r--utils/urls/registry.go13
-rw-r--r--utils/urls/types.go25
16 files changed, 296 insertions, 7 deletions
diff --git a/config/config.go b/config/config.go
index 358fe72..78eb6a8 100644
--- a/config/config.go
+++ b/config/config.go
@@ -33,4 +33,6 @@ func init() {
logger.Fatalf(LOG_PREFIX, messages.ConfigSectionParseFailed, parseError)
}
}
+
+ logger.Successf(LOG_PREFIX, messages.ConfigLoaded)
}
diff --git a/database/constants.go b/database/constants.go
new file mode 100644
index 0000000..e16dcde
--- /dev/null
+++ b/database/constants.go
@@ -0,0 +1,11 @@
+package database
+
+import "time"
+
+const (
+ DATABASE_FILE_NAME = "dove.db"
+ LOG_PREFIX = "Database"
+ MAX_IDLE_CONNECTIONS = 5
+ MAX_OPEN_CONNECTIONS = 25
+ MAX_CONNECTION_LIFETIME = time.Hour
+)
diff --git a/database/database.go b/database/database.go
new file mode 100644
index 0000000..27b99eb
--- /dev/null
+++ b/database/database.go
@@ -0,0 +1,36 @@
+package database
+
+import (
+ "dove/messages"
+ "dove/utils/logger"
+
+ "gorm.io/driver/sqlite"
+ "gorm.io/gorm"
+)
+
+var DB *gorm.DB
+
+func init() {
+ databaseDSN := resolveDatabasePath()
+ dialector := sqlite.Open(databaseDSN)
+
+ var connectionError error
+ DB, connectionError = gorm.Open(dialector, &gorm.Config{
+ Logger: resolveGORMLogLevel(),
+ })
+
+ if connectionError != nil {
+ logger.Fatalf(LOG_PREFIX, messages.DatabaseConnectionFailed, connectionError)
+ }
+
+ sqlDB, poolError := DB.DB()
+ if poolError != nil {
+ logger.Fatalf(LOG_PREFIX, messages.DatabasePoolConfigFailed, poolError)
+ }
+
+ sqlDB.SetMaxOpenConns(MAX_OPEN_CONNECTIONS)
+ sqlDB.SetMaxIdleConns(MAX_IDLE_CONNECTIONS)
+ sqlDB.SetConnMaxLifetime(MAX_CONNECTION_LIFETIME)
+
+ logger.Successf(LOG_PREFIX, messages.DatabaseConnected, databaseDSN)
+}
diff --git a/database/functions.go b/database/functions.go
new file mode 100644
index 0000000..71723ca
--- /dev/null
+++ b/database/functions.go
@@ -0,0 +1,22 @@
+package database
+
+import (
+ "path/filepath"
+
+ "dove/config"
+
+ "gorm.io/gorm/logger"
+)
+
+func resolveDatabasePath() string {
+ return filepath.Join(config.DataDir, DATABASE_FILE_NAME)
+}
+
+func resolveGORMLogLevel() logger.Interface {
+ switch config.Server.Debug {
+ case true:
+ return logger.Default.LogMode(logger.Info)
+ default:
+ return logger.Default.LogMode(logger.Silent)
+ }
+}
diff --git a/enums/http.go b/enums/http.go
new file mode 100644
index 0000000..fbd7591
--- /dev/null
+++ b/enums/http.go
@@ -0,0 +1,13 @@
+package enums
+
+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"
+)
diff --git a/go.mod b/go.mod
index f96ee60..dd4d734 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,26 @@ go 1.25.0
require (
github.com/pelletier/go-toml/v2 v2.2.4
go.uber.org/zap v1.27.1
+ gorm.io/driver/sqlite v1.6.0
+ gorm.io/gorm v1.31.1
)
-require go.uber.org/multierr v1.10.0 // indirect
+require (
+ github.com/andybalholm/brotli v1.1.0 // indirect
+ github.com/gofiber/fiber/v2 v2.52.12 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
+ github.com/mattn/go-sqlite3 v1.14.22 // indirect
+ github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasthttp v1.51.0 // indirect
+ github.com/valyala/tcplisten v1.0.0 // indirect
+ go.uber.org/multierr v1.10.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.20.0 // indirect
+)
diff --git a/go.sum b/go.sum
index a99001e..f00df89 100644
--- a/go.sum
+++ b/go.sum
@@ -1,16 +1,55 @@
+github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
+github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw=
+github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
+github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
+github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
+github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
+golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
+gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
+gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
+gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
diff --git a/messages/config.go b/messages/config.go
index fe44f45..fcb42c3 100644
--- a/messages/config.go
+++ b/messages/config.go
@@ -1,10 +1,9 @@
package messages
const (
+ ConfigFileLoadFailed = "failed to load config: %v"
ConfigFileReadFailed = "failed to read config file %s: %s"
- ConfigFileParseFailed = "failed to parse config file %s: %s"
- ConfigSectionNotFound = "config section '%s' not found"
+ ConfigLoaded = "configuration loaded successfully"
ConfigSectionInvalid = "config section '%s' has invalid data"
- ConfigFileLoadFailed = "failed to load config: %v"
ConfigSectionParseFailed = "failed to parse config section: %v"
)
diff --git a/messages/database.go b/messages/database.go
new file mode 100644
index 0000000..119bdef
--- /dev/null
+++ b/messages/database.go
@@ -0,0 +1,7 @@
+package messages
+
+const (
+ DatabaseConnected = "connected to %s"
+ DatabaseConnectionFailed = "failed to connect to database: %v"
+ DatabasePoolConfigFailed = "failed to configure connection pool: %v"
+)
diff --git a/utils/collections/types.go b/utils/collections/types.go
index c75d1ea..ac84e76 100644
--- a/utils/collections/types.go
+++ b/utils/collections/types.go
@@ -1,3 +1,3 @@
package collections
-type Record map[string]any
+type Record[T any] map[string]T
diff --git a/utils/toml/load.go b/utils/toml/load.go
index a0cab4b..7b3c31a 100644
--- a/utils/toml/load.go
+++ b/utils/toml/load.go
@@ -8,7 +8,7 @@ import (
"dove/utils/errors"
)
-var loadedData collections.Record
+var loadedData collections.Record[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)
+ loadedData = make(collections.Record[any])
return unmarshalContent(fileContent, &loadedData)
}
diff --git a/utils/urls/attach.go b/utils/urls/attach.go
new file mode 100644
index 0000000..df8a11a
--- /dev/null
+++ b/utils/urls/attach.go
@@ -0,0 +1,35 @@
+package urls
+
+import (
+ "dove/enums"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func Attach(application *fiber.App) {
+ registry.Mutex.Lock()
+ defer registry.Mutex.Unlock()
+
+ for _, route := range registry.Routes {
+ bindRoute(application, route)
+ }
+}
+
+func bindRoute(application *fiber.App, route registeredRoute) {
+ switch route.Method {
+ case enums.Delete:
+ application.Delete(route.FullPath, route.Handler)
+ case enums.Get:
+ application.Get(route.FullPath, route.Handler)
+ case enums.Head:
+ application.Head(route.FullPath, route.Handler)
+ case enums.Options:
+ application.Options(route.FullPath, route.Handler)
+ case enums.Patch:
+ application.Patch(route.FullPath, route.Handler)
+ case enums.Post:
+ application.Post(route.FullPath, route.Handler)
+ case enums.Put:
+ application.Put(route.FullPath, route.Handler)
+ }
+}
diff --git a/utils/urls/functions.go b/utils/urls/functions.go
new file mode 100644
index 0000000..6561025
--- /dev/null
+++ b/utils/urls/functions.go
@@ -0,0 +1,30 @@
+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
new file mode 100644
index 0000000..b865676
--- /dev/null
+++ b/utils/urls/path.go
@@ -0,0 +1,37 @@
+package urls
+
+import (
+ "dove/enums"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func Path(method enums.HTTPMethod, path string, handler fiber.Handler, name string) {
+ registry.Mutex.Lock()
+ defer registry.Mutex.Unlock()
+
+ namespace := registry.CurrentNamespace
+ fullName := resolveFullName(namespace, name)
+ fullPath := resolveFullPath(namespace, path)
+
+ registry.Routes[fullName] = registeredRoute{
+ Method: method,
+ Path: path,
+ Handler: handler,
+ Namespace: namespace,
+ Name: name,
+ FullPath: fullPath,
+ }
+}
+
+func GetFullPath(routeName string) (string, bool) {
+ registry.Mutex.Lock()
+ defer registry.Mutex.Unlock()
+
+ route, exists := registry.Routes[routeName]
+ if !exists {
+ return "", false
+ }
+
+ return route.FullPath, true
+}
diff --git a/utils/urls/registry.go b/utils/urls/registry.go
new file mode 100644
index 0000000..a713315
--- /dev/null
+++ b/utils/urls/registry.go
@@ -0,0 +1,13 @@
+package urls
+
+import "dove/utils/collections"
+
+var registry = &routeRegistry{
+ Routes: make(collections.Record[registeredRoute]),
+}
+
+func SetNamespace(namespace string) {
+ registry.Mutex.Lock()
+ defer registry.Mutex.Unlock()
+ registry.CurrentNamespace = namespace
+}
diff --git a/utils/urls/types.go b/utils/urls/types.go
new file mode 100644
index 0000000..499635b
--- /dev/null
+++ b/utils/urls/types.go
@@ -0,0 +1,25 @@
+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]
+}