forked from geoffreybauduin/yaorm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dbprovider.go
141 lines (126 loc) · 3.63 KB
/
dbprovider.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
package yaorm
import (
"context"
"github.com/geoffreybauduin/yaorm/_vendor/github.com/lann/squirrel"
"github.com/geoffreybauduin/yaorm/_vendor/github.com/loopfz/gadgeto/zesty"
"github.com/geoffreybauduin/yaorm/_vendor/github.com/satori/go.uuid"
"github.com/geoffreybauduin/yaorm/tools"
"github.com/go-gorp/gorp"
)
// DBProvider provides an abstracted way of accessing the database
type DBProvider interface {
zesty.DBProvider
EscapeValue(value string) string
CanSelectForUpdate() bool
getStatementGenerator() squirrel.StatementBuilderType
Context() context.Context
UUID() string
getDialect() gorp.Dialect
HasCapacity(capacity DatabaseCapacity) bool
RunInTransaction(func() error) error
}
type dbprovider struct {
zesty.DBProvider
name string
ctx context.Context
uuid string
}
// NewDBProvider creates a new db provider
func NewDBProvider(ctx context.Context, name string) (DBProvider, error) {
dblock.RLock()
defer dblock.RUnlock()
zestyDbp, err := zesty.NewDBProvider(name)
if err != nil {
return nil, err
}
uuid4 := uuid.NewV4()
if err != nil {
return nil, err
}
dbp := &dbprovider{DBProvider: zestyDbp, name: name, ctx: ctx, uuid: uuid4.String()}
return dbp, dbp.getDb().DBSpecific().OnSessionCreated(dbp)
}
// DB returns a SQL Executor interface
func (dbp *dbprovider) DB() gorp.SqlExecutor {
dbRetrieved := dbp.getDb()
dbUsed := dbp.DBProvider.DB()
return &SqlExecutor{
SqlExecutor: dbUsed,
db: dbRetrieved,
ctx: dbp.Context(),
dbp: dbp,
}
}
// EscapeValue escapes the value sent according to the dialect
func (dbp *dbprovider) EscapeValue(value string) string {
return dbp.getDialect().QuoteField(value)
}
// CanSelectForUpdate returns true if the current dialect can perform select for update statements
func (dbp *dbprovider) CanSelectForUpdate() bool {
db := registry[dbp.name]
switch db.System() {
case DatabasePostgreSQL:
return true
}
return false
}
func (dbp *dbprovider) getDb() DB {
return registry[dbp.name]
}
func (dbp *dbprovider) getDialect() gorp.Dialect {
v := tools.GetNonPtrValue(dbp.getDb())
dbField := tools.GetNonPtrValue(v.FieldByName("DB").Interface())
field := dbField.FieldByName("DbMap")
s := field.Interface().(*gorp.DbMap)
return s.Dialect
}
func (dbp *dbprovider) getStatementGenerator() squirrel.StatementBuilderType {
switch dbp.getDb().System() {
case DatabaseMySQL:
return squirrel.StatementBuilder.PlaceholderFormat(squirrel.Question)
}
return squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar)
}
// Context returns the context stored inside this DBProvider instance
func (dbp *dbprovider) Context() context.Context {
return dbp.ctx
}
// UUID returns an unique identifier for this DBProvider instance
func (dbp *dbprovider) UUID() string {
return dbp.uuid
}
// HasCapacity returns true if used database has the provided capacity
func (dbp *dbprovider) HasCapacity(capacity DatabaseCapacity) bool {
system := dbp.getDb().System()
if _, ok := databaseCapacities[system]; !ok {
return false
}
return databaseCapacities[system][capacity]
}
// RunInTraction will run the provided function inside a transaction.
// if an error occurs, the transaction is automatically rolled back.
// at the end of the transaction, the transaction is commit inside the
// dbms
func (dbp *dbprovider) RunInTransaction(fn func() error) error {
shouldRollback := true
errTx := dbp.Tx()
if errTx != nil {
return errTx
}
defer func() {
if !shouldRollback {
return
}
dbp.Rollback() //nolint:errcheck
}()
errFn := fn()
if errFn != nil {
return errFn
}
errCommit := dbp.Commit()
if errCommit != nil {
return errCommit
}
shouldRollback = false
return nil
}