-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconnector.go
More file actions
131 lines (110 loc) · 4.47 KB
/
Copy pathconnector.go
File metadata and controls
131 lines (110 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package sqldb
import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql" // mysql
_ "github.com/lib/pq" // postgres
)
const (
tickInterval = 50 * time.Millisecond
)
// Conf represents the configuration structure for opening a connection to the
// database. It includes fields for specifying the database driver and Data
// Source Name (DSN) for connecting to the database.
type Conf struct {
Driver string `yaml:"driver"` // Database driver (e.g., "mysql", "postgres", etc.).
DSN string `yaml:"dsn"` // Data Source Name (DSN) for connecting to the database.
}
// Connector is a struct representing a database connector. It embeds a *sql.DB
// to provide the functionalities of a SQL database connection.
type Connector struct {
*sql.DB
}
// TryConnection attempts to establish a connection to the SQL database by
// repeatedly pinging it within a specified time duration. It takes an integer
// parameter 't' representing the maximum time duration in seconds for attempting
// the connection. The function returns an error if the connection cannot be
// established within the specified time or if an error occurs during the connection
// attempt.
func (con *Connector) TryConnection(t int) error {
// Create a ticker to ping the database at regular intervals.
ticker := time.NewTicker(tickInterval)
defer ticker.Stop()
// Set a timeout for the overall connection attempt.
timeout := time.After(time.Duration(t) * time.Second)
// Loop until the database connection is successful or the timeout occurs.
for {
select {
case <-ticker.C:
// Attempt to ping the database.
err := con.Ping()
if err == nil {
return nil // Successful connection.
}
case <-timeout:
// Return an error if the timeout is reached without a successful connection.
return fmt.Errorf("can't ping SqlDB: timeout after %d s", t)
}
}
}
// Commit commits the provided SQL transaction. It takes a *sql.Tx parameter and
// attempts to commit the transaction. If the commit is successful, the function
// returns nil; otherwise, it returns an error with relevant information.
func (con *Connector) Commit(tx *sql.Tx) error {
if err := tx.Commit(); err != nil {
return fmt.Errorf("fail to commit transaction: %w", err)
}
return nil
}
// Exec executes the provided SQL query within the specified transaction. It
// takes a *sql.Tx, a query string, and optional query arguments. The function
// prepares the query, executes the prepared statement with the given arguments,
// and returns the sql.Result. If any error occurs during preparation or execution,
// the function returns an error with relevant information.
func (con *Connector) Exec(tx *sql.Tx, query string, args ...interface{}) (sql.Result, error) {
var res sql.Result
// Prepare the SQL query.
stm, err := tx.Prepare(query)
if err != nil {
return res, fmt.Errorf("can't prepare query: %w", err)
}
// Execute the prepared statement with the provided arguments.
res, err = stm.Exec(args...)
if err != nil {
return res, fmt.Errorf("error when executing prepared statement: %w", err)
}
return res, nil
}
// ExecQueryRow executes the provided SQL query within the specified transaction
// and returns a *sql.Row representing the result. It takes a *sql.Tx, a query
// string, and optional query arguments. The function prepares the query, creates
// a *sql.Row with the prepared statement and the given arguments, and returns it.
// If any error occurs during preparation, the function returns an error with
// relevant information.
func (con *Connector) ExecQueryRow(tx *sql.Tx, query string, args ...interface{}) (*sql.Row, error) {
var row *sql.Row
// Prepare the SQL query.
stm, err := tx.Prepare(query)
if err != nil {
return row, fmt.Errorf("can't prepare query: %w", err)
}
// Create a *sql.Row with the prepared statement and arguments.
row = stm.QueryRow(args...)
return row, nil
}
// FactoryConnector creates and returns a new *Connector by opening a connection
// to the SQL database using the provided Conf configuration. It returns the
// initialized Connector and an error if the connection cannot be established.
// The function uses the database driver and Data Source Name (DSN) specified
// in the configuration.
func FactoryConnector(c Conf) (*Connector, error) {
var err error
con := new(Connector)
// Open a connection to the SQL database.
con.DB, err = sql.Open(c.Driver, c.DSN)
if err != nil {
return con, fmt.Errorf("can't open connection to SqlDB(driver: %s): %w", c.Driver, err)
}
return con, nil
}