-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
172 lines (145 loc) · 5.27 KB
/
main.go
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Package db is the base package for database access at stellar. It primarily
// exposes Session which is a lightweight wrapper around a *sqlx.DB that
// provides utility methods (See the repo tests for examples).
//
// In addition to the query methods, this package provides query logging and
// stateful transaction management.
//
// In addition to the lower-level access facilities, this package exposes a
// system to build queries more dynamically using the help of
// https://github.com/Masterminds/squirrel. These builder method are access
// through the `Table` type.
package db
import (
"context"
"database/sql"
"time"
"github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
"github.com/AnneNamuli/go-stellar/support/errors"
// Enable postgres
_ "github.com/lib/pq"
)
const (
// postgresQueryMaxParams defines the maximum number of parameters in a query.
postgresQueryMaxParams = 65535
maxDBPingAttempts = 30
)
var (
// ErrCancelled is an error returned by Session methods when request has
// been cancelled (ex. context cancelled).
ErrCancelled = errors.New("canceling statement due to user request")
)
// Conn represents a connection to a single database.
type Conn interface {
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error
Rebind(sql string) string
QueryxContext(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error)
SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error
}
// DeleteBuilder is a helper struct used to construct sql queries of the DELETE
// variety.
type DeleteBuilder struct {
Table *Table
sql squirrel.DeleteBuilder
}
// InsertBuilder is a helper struct used to construct sql queries of the INSERT
// variety.
// NOTE: InsertBuilder will use "zero" value of a type in case of nil pointer values.
// If you need to insert `NULL` use sql.Null* or build your own type that implements
// database/sql/driver.Valuer.
type InsertBuilder struct {
Table *Table
rows []interface{}
ignoredCols map[string]bool
sql squirrel.InsertBuilder
}
// GetBuilder is a helper struct used to construct sql queries of the SELECT
// variety.
type GetBuilder struct {
Table *Table
dest interface{}
sql squirrel.SelectBuilder
}
// SelectBuilder is a helper struct used to construct sql queries of the SELECT
// variety.
type SelectBuilder struct {
Table *Table
dest interface{}
sql squirrel.SelectBuilder
}
// UpdateBuilder is a helper struct used to construct sql queries of the UPDATE
// variety.
type UpdateBuilder struct {
Table *Table
sql squirrel.UpdateBuilder
}
// Session provides helper methods for making queries against `DB` and provides
// utilities such as automatic query logging and transaction management. NOTE:
// A Session is designed to be lightweight and temporarily lived (usually
// request scoped) which is one reason it is acceptable for it to store a
// context. It is not presently intended to cross goroutine boundaries and is
// not concurrency safe.
type Session struct {
// DB is the database connection that queries should be executed against.
DB *sqlx.DB
// Ctx is the context in which the repo is operating under.
Ctx context.Context
tx *sqlx.Tx
txOptions *sql.TxOptions
}
type SessionInterface interface {
BeginTx(opts *sql.TxOptions) error
Begin() error
Rollback() error
TruncateTables(tables []string) error
Clone() *Session
Close() error
Get(dest interface{}, query squirrel.Sqlizer) error
GetRaw(dest interface{}, query string, args ...interface{}) error
Select(dest interface{}, query squirrel.Sqlizer) error
SelectRaw(dest interface{}, query string, args ...interface{}) error
GetTable(name string) *Table
Exec(query squirrel.Sqlizer) (sql.Result, error)
ExecRaw(query string, args ...interface{}) (sql.Result, error)
NoRows(err error) bool
}
// Table helps to build sql queries against a given table. It logically
// represents a SQL table on the database that `Session` is connected to.
type Table struct {
// Name is the name of the table
Name string
Session *Session
}
func pingDB(db *sqlx.DB) error {
var err error
for attempt := 0; attempt < maxDBPingAttempts; attempt++ {
if err = db.Ping(); err == nil {
return nil
}
time.Sleep(time.Second)
}
return errors.Wrapf(err, "failed to connect to DB after %v attempts", maxDBPingAttempts)
}
// Open the database at `dsn` and returns a new *Session using it.
func Open(dialect, dsn string) (*Session, error) {
db, err := sqlx.Open(dialect, dsn)
if err != nil {
return nil, errors.Wrap(err, "open failed")
}
if err = pingDB(db); err != nil {
return nil, errors.Wrap(err, "ping failed")
}
return &Session{DB: db, Ctx: context.Background()}, nil
}
// Wrap wraps a bare *sql.DB (from the database/sql stdlib package) in a
// *db.Session instance. It is meant to be used in cases where you do not
// control the instantiation of the database connection, but would still like to
// leverage the facilities provided in Session.
func Wrap(base *sql.DB, dialect string) *Session {
return &Session{DB: sqlx.NewDb(base, dialect), Ctx: context.Background()}
}
// ensure various types conform to Conn interface
var _ Conn = (*sqlx.Tx)(nil)
var _ Conn = (*sqlx.DB)(nil)