Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kovacou/go-database
Go databases manager (Context, Transactions & Profiler) w/ an intuitive SQL Builder on top of sqlx. Performances oriented.
https://github.com/kovacou/go-database
builder database go golang mysql profiler transactions
Last synced: 29 days ago
JSON representation
Go databases manager (Context, Transactions & Profiler) w/ an intuitive SQL Builder on top of sqlx. Performances oriented.
- Host: GitHub
- URL: https://github.com/kovacou/go-database
- Owner: kovacou
- License: mit
- Created: 2019-08-30T17:47:50.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-01-24T20:30:41.000Z (11 months ago)
- Last Synced: 2024-08-03T23:20:05.467Z (4 months ago)
- Topics: builder, database, go, golang, mysql, profiler, transactions
- Language: Go
- Homepage:
- Size: 83 KB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-golang-repositories - go-database
README
# go-database
Personal project.
`go-database` is a library made for `mysql` which provides a set of extensions on top of [`jmoiron/sqlx`](https://github.com/jmoiron/sqlx) such as a querybuilder, profiler, context & transactions for performances. **This is not an ORM**.
I plan to support `pgsql` in the future.## ➡ features
- Opening connection with environment variables :
- Global variables `DATABASE_*`
- Aliases variables for multiple connection `DATABASE_ALIAS_*`
- Opening connection with Environ
- A pool to manage all connections opened
- Transactions
- Profiling & Context
- Log out queries as string (formated) ordered by execution time grouped by context to detect slow queries.
**Example :** You can profile an application that uses goroutines such as webserver.
- Query builder for complex query at the SQL layer
- **This is not an ORM (yet)**## ➡ install
`go get github.com/kovacou/go-database`
## ➡ usage
Below is an example which shows some common use cases for go-database.
```ini
# .env file configuration (default settings)# You can use DSN
DATABASE_DSN=# Or use specfic variables
DATABASE_DRIVER=mysql
DATABASE_HOST=172.18.0.1
DATABASE_USER=test
DATABASE_PASS=test
DATABASE_SCHEMA=dbtest
DATABASE_PORT=3306
``````go
package mainimport (
"log""github.com/kovacou/go-database"
b "github.com/kovacou/go-database/builder"
)type User struct {
ID uint64
Name string
}func main() {
// Opening a new connection based on environment variables.
// By default, the connection is postponed until there is an action.
db, err := database.Open()
if err != nil {
log.Fatal(err)
}// Example of builder
s := b.Select{
Table: "users",
Where: b.ParseWhere("id < ?", 10)
}println(s.String()) // SELECT * FROM users WHERE id < ?
// Mapping through a map
// (faster than structscan if you look for performance)
out := []User{}
db.SelectMap(&s, func(values map[string]any){
out = append(out, User{
ID: values["id"].(int64),
Name: string(values["name"].([]byte)),
})
})// More faster than previous one.
out2 := []User{}
db.SelectSlice(&s, func(values []any) {
out2 = append(out2, User{
ID: values[0].(int64),
Name: string(values[1].([]byte)),
})
})// Using raw query
out3 := []User{}
db.QuerySlice(builder.NewQuery("SELECT * FROM users WHERE id < ?", 10), func(values []any) {
out3 = append(out3, User{
// ...
})
})// Using upsert
i := builder.Insert{
Table: "users",
Values: builder.H{
"id": 1,
"name": "John",
},
OnUpdateKeys: builder.Keys{"name"},
}
db.Exec(&i)
}
```## ➡ opening a new connection
### **With environment variables**
### **With environ**## ➡ closing all connections
```go
func main() {
// Defering the close in your main ensure closing
// the connection before exiting the program.
defer database.Close()// your code...
}
```## ➡ transactions
Support of transactions.
```go
// tx, err := db.Tx()
tx, err := db.Tx(sql.LevelSerializable)
if err != nil {
panic(err)
}// use tx to run some requests.
tx.Commit()
tx.Rollback()// You can't use tx anymore, else an error will occur.
```## ➡ profiling & context
## ➡ statements
### **Select**
```go
s := builder.Select{
Table: "users",
Columns: builder.ParseColumns("id", "name"),
Where: builder.ParseWhere("id > ?", 1),
OrderBy: builder.ParseOrderBy("name ASC"),
}
```#### Map
The columns can be read by key name.```go
// Parse 1 row only.
{
out := User{}
n, err := db.SelectMapRow(&s, func(v map[string]any) {
// If there is more than 1 row, an error occur.
// `n` return 0 or 1.
outRow.ID = v["id"].(int64)
outRow.Name = string(v["name"].([]byte))
})
}// Parse multiple rows.
{
out := []User{}
n, err := db.SelectMap(&s, func(v map[string]any) {
// `n` contains the number of rows returned.
out = append(out, User{
ID: v["id"].(int64),
Name: string(v["name"].([]byte)),
})
})
}
```#### Slice
The columns can be read by indexes from the Column clause (same order).
**Note:** Slice is faster than Map. Prefer use Slice when the columns have always the same order.
```go
// Parse 1 row only
{
out := User{}
n, err := db.SelectSliceRow(&s, func(v []any){
// If there is more than1 row, an error occur.
// `n` return 0 or 1
out.ID = v[0].(int64)
out.Name = string(v[1].([]byte))
})
}// Parse multiple rows
{
out := []User{}
n, err := db.SelectSlice(&s, func(v []any){
out = append(out, User{
ID: v[0].(int64),
Name: string(v[1].([]byte)),
})
})
}
```### **Exec**
#### Insert
```go
// Example of Insert
i := builder.Insert{
Table: "users",
IgnoreMode: false, // False by default
Values: builder.H{
"name": "John",
},
}println(i.String()) // INSERT INTO users(name) VALUES(?)
r, err := db.Exec(&i)
```#### Upsert
```go
// Example of Insert with upsert mode.
i := builder.Insert{
Table: "users",
Values: builder.H{
"id": 15,
"name": "John",
},
OnUpdateKeys: builder.Keys{"name"},
}println(i.String()) // INSERT INTO users(id, name) VALUES(?, ?)
// ON DUPLICATE KEY UPDATE name = VALUES(name)r, err := db.Exec(&i)
```#### Update
```go
// Example of Update
u := builder.Update{
Table: "users",
Values: builder.H{
"name": "John",
},
Where: builder.ParseWhere("id = ?", 1) // Used to initiate the value (if needed)
// To initiate empty value :
// builder.NewWhere()
}// You can also use where like following :
// u.Where.And("id = ?", 1)println(u.String()) // UPDATE users SET name = ? WHERE id = ?
r, err := db.Exec(&u)
```#### Delete
```go
// Example of Delete
d := builder.Delete{
Table: "users",
Where: builder.ParseWhere("id = ?", 1) // Used to initiate the value (if needed)
// To initiate empty value :
// builder.NewWhere()
}// You can also use where like following :
// d.Where.And("id = ?", 1)println(d.String()) // DELETE FROM users WHERE id = ?
r, err := db.Exec(&d)
```