|
@@ -4,7 +4,10 @@ import (
|
|
|
"context"
|
|
|
"database/sql"
|
|
|
"fmt"
|
|
|
+ "os"
|
|
|
"regexp"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
)
|
|
@@ -16,46 +19,125 @@ type DBMethods struct {
|
|
|
Driver string
|
|
|
}
|
|
|
|
|
|
-type qFunc func(ctx context.Context, tx *sql.Tx) error
|
|
|
+var rLogSpacesAll = regexp.MustCompile(`[\s\t]+`)
|
|
|
+var rLogSpacesEnd = regexp.MustCompile(`[\s\t]+;$`)
|
|
|
+var rSqlParam = regexp.MustCompile(`\$\d+`)
|
|
|
|
|
|
-var r = regexp.MustCompile(`\$\d+`)
|
|
|
+type queryFunc func(ctx context.Context, tx *sql.Tx) error
|
|
|
+
|
|
|
+func (db *DBMethods) log(m string, s time.Time, e error, tx bool, query string, args ...any) {
|
|
|
+ var tmsg string
|
|
|
+
|
|
|
+ if tx {
|
|
|
+ tmsg = " [TX]"
|
|
|
+ }
|
|
|
+ if m != "" {
|
|
|
+ tmsg = tmsg + " " + m
|
|
|
+ }
|
|
|
+
|
|
|
+ qmsg := query
|
|
|
+ if qmsg != "" {
|
|
|
+ qmsg = strings.Trim(rLogSpacesAll.ReplaceAllString(qmsg, " "), " ")
|
|
|
+ qmsg = rLogSpacesEnd.ReplaceAllString(qmsg, ";")
|
|
|
+ qmsg = " " + qmsg
|
|
|
+ }
|
|
|
+
|
|
|
+ astr := " (empty)"
|
|
|
+ if len(args) > 0 {
|
|
|
+ astr = fmt.Sprintf(" (%v)", args)
|
|
|
+ }
|
|
|
+
|
|
|
+ estr := " (nil)"
|
|
|
+ if e != nil {
|
|
|
+ estr = " \033[0m\033[0;31m(" + e.Error() + ")"
|
|
|
+ }
|
|
|
+
|
|
|
+ color := "0;33"
|
|
|
+ if tx {
|
|
|
+ color = "1;33"
|
|
|
+ }
|
|
|
+
|
|
|
+ fmt.Fprintln(os.Stdout, "\033["+color+"m[SQL]"+tmsg+qmsg+astr+estr+fmt.Sprintf(" %.3f ms", time.Since(s).Seconds())+"\033[0m")
|
|
|
+}
|
|
|
|
|
|
func (db *DBMethods) fixQuery(query string) string {
|
|
|
if db.Driver == "mysql" {
|
|
|
- return r.ReplaceAllString(query, "?")
|
|
|
+ return rSqlParam.ReplaceAllString(query, "?")
|
|
|
}
|
|
|
return query
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) Begin(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ tx, err := db.DB.BeginTx(ctx, opts)
|
|
|
+ db.log("[func Begin]", t, err, true, "")
|
|
|
+ return tx, err
|
|
|
+ }
|
|
|
return db.DB.BeginTx(ctx, opts)
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) Close() error {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ err := db.DB.Close()
|
|
|
+ db.log("[func Close]", t, err, false, "")
|
|
|
+ return err
|
|
|
+ }
|
|
|
return db.DB.Close()
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) Exec(ctx context.Context, query string, args ...any) (sql.Result, error) {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ res, err := db.DB.ExecContext(ctx, db.fixQuery(query), args...)
|
|
|
+ db.log("[func Exec]", t, err, false, db.fixQuery(query), args...)
|
|
|
+ return res, err
|
|
|
+ }
|
|
|
return db.DB.ExecContext(ctx, db.fixQuery(query), args...)
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) Ping(ctx context.Context) error {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ err := db.DB.PingContext(ctx)
|
|
|
+ db.log("[func Ping]", t, err, false, "")
|
|
|
+ return err
|
|
|
+ }
|
|
|
return db.DB.PingContext(ctx)
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) Prepare(ctx context.Context, query string) (*sql.Stmt, error) {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ stm, err := db.DB.PrepareContext(ctx, db.fixQuery(query))
|
|
|
+ db.log("[func Prepare]", t, err, false, db.fixQuery(query))
|
|
|
+ return stm, err
|
|
|
+ }
|
|
|
return db.DB.PrepareContext(ctx, db.fixQuery(query))
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) Query(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ rows, err := db.DB.QueryContext(ctx, db.fixQuery(query), args...)
|
|
|
+ db.log("[func Query]", t, err, false, db.fixQuery(query), args...)
|
|
|
+ return rows, err
|
|
|
+ }
|
|
|
return db.DB.QueryContext(ctx, db.fixQuery(query), args...)
|
|
|
}
|
|
|
|
|
|
func (db *DBMethods) QueryRow(ctx context.Context, query string, args ...any) *sql.Row {
|
|
|
+ if db.Debug {
|
|
|
+ t := time.Now()
|
|
|
+ row := db.DB.QueryRowContext(ctx, db.fixQuery(query), args...)
|
|
|
+ db.log("[func QueryRow]", t, nil, false, db.fixQuery(query), args...)
|
|
|
+ return row
|
|
|
+ }
|
|
|
return db.DB.QueryRowContext(ctx, db.fixQuery(query), args...)
|
|
|
}
|
|
|
|
|
|
-func (db *DBMethods) Transaction(ctx context.Context, queries qFunc) error {
|
|
|
+func (db *DBMethods) Transaction(ctx context.Context, queries queryFunc) error {
|
|
|
if queries == nil {
|
|
|
return fmt.Errorf("queries is not set for transaction")
|
|
|
}
|