-
Notifications
You must be signed in to change notification settings - Fork 17
/
db.go
187 lines (156 loc) · 5.01 KB
/
db.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package crud
import (
"context"
stdsql "database/sql"
"github.com/azer/crud/v2/sql"
"github.com/azer/logger"
"github.com/labstack/gommon/random"
)
var log = logger.New("crud")
type ExecFn func(string, ...interface{}) (stdsql.Result, error)
type QueryFn func(string, ...interface{}) (*stdsql.Rows, error)
type DB struct {
Client *stdsql.DB
Driver string
URL string
}
func (db *DB) Ping() error {
return db.Client.Ping()
}
// Run any query on the database client, passing parameters optionally. Returns sql.Result.
func (db *DB) Exec(sql string, params ...interface{}) (stdsql.Result, error) {
timer := log.Timer()
result, error := db.Client.Exec(sql, params...)
timer.End("SQL Query Executed: %s", sql)
return result, error
}
// Run any query on the database client, passing parameters optionally. Its difference with
// `Exec` method is returning `sql.Rows` instead of `sql.Result`.
func (db *DB) Query(sql string, params ...interface{}) (*stdsql.Rows, error) {
timer := log.Timer()
result, error := db.Client.Query(sql, params...)
timer.End("SQL Query Executed: %s", sql)
return result, error
}
// Takes any valid struct and creates a SQL table from it.
func (db *DB) CreateTable(st interface{}, ifexists bool) error {
t, err := NewTable(st)
if err != nil {
return err
}
_, err = db.Exec(sql.NewTableQuery(t.SQLName, t.SQLOptions(), ifexists))
return err
}
// Takes any valid struct, finds out its corresponding SQL table and drops it.
func (db *DB) DropTable(st interface{}, ifexists bool) error {
t, err := NewTable(st)
if err != nil {
return err
}
_, err = db.Exec(sql.DropTableQuery(t.SQLName, true))
return err
}
// Creates multiple tables from given any amount of structs. Calls `CreateTable` internally.
func (db *DB) CreateTables(structs ...interface{}) error {
for _, st := range structs {
if err := db.CreateTable(st, true); err != nil {
return err
}
}
return nil
}
// Drops correspoinding SQL tables of the given structs.
func (db *DB) DropTables(structs ...interface{}) error {
for _, st := range structs {
if err := db.DropTable(st, true); err != nil {
return err
}
}
return nil
}
// Drops (if they exist) and re-creates corresponding SQL tables for the given structs.
func (db *DB) ResetTables(structs ...interface{}) error {
if err := db.DropTables(structs...); err != nil {
return err
}
if err := db.CreateTables(structs...); err != nil {
return err
}
return nil
}
// Runs a query to check if the given table exists and returns bool
func (db *DB) CheckIfTableExists(name string) bool {
var result string
err := db.Client.QueryRow(sql.ShowTablesLikeQuery(name)).Scan(&result)
return err == nil && result == name
}
// Inserts given record into the database, generating an insert query for it.
func (db *DB) Create(record interface{}) error {
return create(db.Exec, record)
}
func (db *DB) CreateAndGetResult(record interface{}) (stdsql.Result, error) {
return createAndGetResult(db.Exec, record)
}
// Inserts given record and scans the inserted row back to the given row.
func (db *DB) CreateAndRead(record interface{}) error {
return createAndRead(db.Exec, db.Query, record)
}
// Runs given SQL query and scans the result rows into the given target interface. The target
// interface could be both a single record or a slice of records.
//
// Usage Example:
//
// user := &User{}
// err := tx.Read(user, "SELECT * FROM users WHERE id = ?", 1)
//
// users := &[]*User{}
// err := tx.Read(users, "SELECT * FROM users", 1)
//
func (db *DB) Read(scanTo interface{}, params ...interface{}) error {
return read(db.Query, scanTo, params)
}
// Finding out the primary-key field of the given row, updates the corresponding record on the table
// with the values in the given record.
func (db *DB) Update(record interface{}) error {
return mustUpdate(db.Exec, record)
}
// Generates and executes a DELETE query for given struct record. It matches the database row by finding
// out the primary key field defined in the table schema.
func (db *DB) Delete(record interface{}) error {
return mustDelete(db.Exec, record)
}
// Start a DB transaction. It returns an interface w/ most of the methods DB provides.
func (db *DB) Begin(ctx context.Context) (*Tx, error) {
client, err := db.Client.Begin()
if err != nil {
return nil, err
}
return &Tx{
Id: random.String(32),
IdKey: "Id",
Client: client,
Context: ctx,
}, nil
}
// Return a database client that wraps underlying SQL execution methods with the context specified
func (db *DB) WithContext(ctx context.Context) *WithContext {
return &WithContext{
Context: ctx,
DB: db.Client,
Id: random.String(32),
IdKey: "Id",
}
}
// Establish DB connection and return a crud.DB instance w/ methods needed for accessing / writing the database.
// Example call: Connect("mysql", "root:123456@tcp(localhost:3306)/database_name?parseTime=true")
func Connect(driver, url string) (*DB, error) {
client, err := stdsql.Open(driver, url)
if err != nil {
return nil, err
}
return &DB{
Client: client,
Driver: driver,
URL: url,
}, nil
}