From c6f3304d4369b32d777f36b261f2a7f8a8d0d8fe Mon Sep 17 00:00:00 2001
From: Antonio Pagano
Date: Fri, 14 Nov 2025 09:54:23 -0500
Subject: [PATCH 1/4] task: adding connection params
---
db/connection.go | 29 ++++++++++++++++++++--
db/connection_test.go | 57 ++++++++++++++++++++++++++++++++++---------
2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/db/connection.go b/db/connection.go
index b2384b1..0fc2bce 100644
--- a/db/connection.go
+++ b/db/connection.go
@@ -2,6 +2,7 @@ package db
import (
"database/sql"
+ "net/url"
"sync"
)
@@ -9,8 +10,11 @@ var (
dbPool = map[string]*sql.DB{}
cmux sync.Mutex
- //DriverName defaults to postgres
+ // DriverName defaults to postgres
driverName = "postgres"
+
+ // Connection params to be appended to the connection string
+ connParams string
)
// ConnFn is the database connection builder function that
@@ -39,7 +43,7 @@ func ConnectionFn(url string, opts ...connectionOption) ConnFn {
v()
}
- conn, err := sql.Open(driverName, url)
+ conn, err := sql.Open(driverName, url+connParams)
if err != nil {
return nil, err
}
@@ -57,3 +61,24 @@ func WithDriver(name string) connectionOption {
driverName = name
}
}
+
+// Params allows to specify additional connection parameters
+// that will be encoded as URL params next to the connection string.
+// params should to be in key,value,key,value,... format.
+// e.g Params("sslmode", "disable", "timezone", "UTC")
+func Params(params ...string) connectionOption {
+ vals := url.Values{}
+ for i := 0; i < len(params); i += 2 {
+ key := params[i]
+ if i+1 >= len(params) {
+ vals.Add(key, "")
+ break
+ }
+
+ vals.Add(key, params[i+1])
+ }
+
+ return func() {
+ connParams = "?" + vals.Encode()
+ }
+}
diff --git a/db/connection_test.go b/db/connection_test.go
index 6519127..24ae814 100644
--- a/db/connection_test.go
+++ b/db/connection_test.go
@@ -11,17 +11,17 @@ func TestConnection(t *testing.T) {
urls := []string{"test_1.db", "test_2.db", "test_3.db"}
createDatabases := func() {
- for _, dbUrl := range urls {
- if err := db.Create(dbUrl); err != nil {
+ for _, url := range urls {
+ if err := db.Create(url); err != nil {
t.Errorf("error creating db: %v", err)
}
}
-
}
+
t.Run("Correct - creating multiple connections", func(t *testing.T) {
t.Cleanup(func() {
- for _, dbUrl := range urls {
- if err := db.Drop(dbUrl); err != nil {
+ for _, url := range urls {
+ if err := db.Drop(url); err != nil {
t.Errorf("error dropping db: %v", err)
}
}
@@ -29,8 +29,8 @@ func TestConnection(t *testing.T) {
createDatabases()
- for _, dbUrl := range urls {
- conFn := db.ConnectionFn(dbUrl, db.WithDriver("sqlite3"))
+ for _, url := range urls {
+ conFn := db.ConnectionFn(url, db.WithDriver("sqlite3"))
conn, err := conFn()
if err != nil {
@@ -42,10 +42,11 @@ func TestConnection(t *testing.T) {
}
}
})
+
t.Run("Correct - using current exiting connection if already created", func(t *testing.T) {
t.Cleanup(func() {
- for _, dbUrl := range urls {
- if err := db.Drop(dbUrl); err != nil {
+ for _, url := range urls {
+ if err := db.Drop(url); err != nil {
t.Errorf("error dropping db: %v", err)
}
}
@@ -55,15 +56,15 @@ func TestConnection(t *testing.T) {
var currentConn *sql.DB
- for _, dbUrl := range urls {
- conFn := db.ConnectionFn(dbUrl, db.WithDriver("sqlite3"))
+ for _, url := range urls {
+ conFn := db.ConnectionFn(url, db.WithDriver("sqlite3"))
conn, err := conFn()
if err != nil {
t.Errorf("Expected nil, got err %v", err)
}
- if dbUrl == urls[0] {
+ if url == urls[0] {
currentConn = conn
}
@@ -83,4 +84,36 @@ func TestConnection(t *testing.T) {
t.Errorf("Expected current connection to be %v, got %v", currentConn, conn)
}
})
+
+ t.Run("connection params", func(t *testing.T) {
+ connFn := db.ConnectionFn(
+ "memory.db",
+
+ db.WithDriver("sqlite3"),
+ db.Params("_cache_size", "54321"), // Applying cache size parameter to check it later.
+ )
+
+ conn, err := connFn()
+ if err != nil {
+ t.Errorf("Expected nil, got err %v", err)
+ }
+ defer conn.Close()
+
+ rows, err := conn.Query("pragma cache_size;")
+ if err != nil {
+ t.Errorf("Expected nil, got err %v", err)
+ }
+ defer rows.Close()
+
+ var size int
+ for rows.Next() {
+ if err := rows.Scan(&size); err != nil {
+ t.Errorf("Expected nil, got err %v", err)
+ }
+ }
+
+ if size != 54321 {
+ t.Fatalf("Expected cache size to be 54321, got %v", size)
+ }
+ })
}
From 41037d37106b1d265994adeb77bb20dc42cecc6d Mon Sep 17 00:00:00 2001
From: Antonio Pagano
Date: Fri, 14 Nov 2025 10:01:50 -0500
Subject: [PATCH 2/4] task: covering some of the issues mentioned by copilot
---
db/connection.go | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/db/connection.go b/db/connection.go
index 0fc2bce..e51d0b1 100644
--- a/db/connection.go
+++ b/db/connection.go
@@ -3,6 +3,7 @@ package db
import (
"database/sql"
"net/url"
+ "strings"
"sync"
)
@@ -43,7 +44,14 @@ func ConnectionFn(url string, opts ...connectionOption) ConnFn {
v()
}
- conn, err := sql.Open(driverName, url+connParams)
+ url := url
+ if strings.Contains(url, "?") {
+ url = url + "&" + connParams
+ } else if connParams != "" {
+ url = url + "?" + connParams
+ }
+
+ conn, err := sql.Open(driverName, url)
if err != nil {
return nil, err
}
@@ -64,7 +72,7 @@ func WithDriver(name string) connectionOption {
// Params allows to specify additional connection parameters
// that will be encoded as URL params next to the connection string.
-// params should to be in key,value,key,value,... format.
+// params should be in key,value,key,value,... format.
// e.g Params("sslmode", "disable", "timezone", "UTC")
func Params(params ...string) connectionOption {
vals := url.Values{}
@@ -79,6 +87,6 @@ func Params(params ...string) connectionOption {
}
return func() {
- connParams = "?" + vals.Encode()
+ connParams = vals.Encode()
}
}
From 2335218510b36f8c3bd7478168ed531a769c5883 Mon Sep 17 00:00:00 2001
From: Antonio Pagano
Date: Fri, 14 Nov 2025 10:09:15 -0500
Subject: [PATCH 3/4] task: adding some comments
---
db/connection.go | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/db/connection.go b/db/connection.go
index e51d0b1..6cf1b60 100644
--- a/db/connection.go
+++ b/db/connection.go
@@ -44,18 +44,22 @@ func ConnectionFn(url string, opts ...connectionOption) ConnFn {
v()
}
- url := url
- if strings.Contains(url, "?") {
- url = url + "&" + connParams
+ // Modify the URL to include connection params
+ // if any.
+ modURL := url
+ if strings.Contains(modURL, "?") {
+ modURL = modURL + "&" + connParams
} else if connParams != "" {
- url = url + "?" + connParams
+ modURL = modURL + "?" + connParams
}
- conn, err := sql.Open(driverName, url)
+ conn, err := sql.Open(driverName, modURL)
if err != nil {
return nil, err
}
+ // This uses url instead of modURL while the params apply
+ // to all connections.
dbPool[url] = conn
return conn, nil
From ae6afe3ba31e7853e2403950f874f646393959cb Mon Sep 17 00:00:00 2001
From: Antonio Pagano
Date: Fri, 14 Nov 2025 10:26:40 -0500
Subject: [PATCH 4/4] task: adding a few other cases
---
db/connection_test.go | 57 ++++++++++++++++++++++++++-----------------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/db/connection_test.go b/db/connection_test.go
index 24ae814..fa718d7 100644
--- a/db/connection_test.go
+++ b/db/connection_test.go
@@ -86,34 +86,45 @@ func TestConnection(t *testing.T) {
})
t.Run("connection params", func(t *testing.T) {
- connFn := db.ConnectionFn(
- "memory.db",
+ cases := []string{
+ ":memory:",
+ "file::memory:?cache=shared",
+ t.TempDir() + "memory.db",
+ t.TempDir() + "memory.db?mode=memory",
+ }
- db.WithDriver("sqlite3"),
- db.Params("_cache_size", "54321"), // Applying cache size parameter to check it later.
- )
+ for _, tcase := range cases {
+ t.Run(tcase, func(t *testing.T) {
+ connFn := db.ConnectionFn(
+ tcase,
- conn, err := connFn()
- if err != nil {
- t.Errorf("Expected nil, got err %v", err)
- }
- defer conn.Close()
+ db.WithDriver("sqlite3"),
+ db.Params("_cache_size", "54321"), // Applying cache size parameter to check it later.
+ )
- rows, err := conn.Query("pragma cache_size;")
- if err != nil {
- t.Errorf("Expected nil, got err %v", err)
- }
- defer rows.Close()
+ conn, err := connFn()
+ if err != nil {
+ t.Errorf("Expected nil, got err %v", err)
+ }
+ defer conn.Close()
- var size int
- for rows.Next() {
- if err := rows.Scan(&size); err != nil {
- t.Errorf("Expected nil, got err %v", err)
- }
- }
+ rows, err := conn.Query("pragma cache_size;")
+ if err != nil {
+ t.Errorf("Expected nil, got err %v", err)
+ }
+ defer rows.Close()
+
+ var size int
+ for rows.Next() {
+ if err := rows.Scan(&size); err != nil {
+ t.Errorf("Expected nil, got err %v", err)
+ }
+ }
- if size != 54321 {
- t.Fatalf("Expected cache size to be 54321, got %v", size)
+ if size != 54321 {
+ t.Fatalf("Expected cache size to be 54321, got %v", size)
+ }
+ })
}
})
}