Browse Source

Add debug ability

Volodymyr Tkach 2 years ago
parent
commit
baaad93fd1
2 changed files with 87 additions and 5 deletions
  1. 1 1
      gosql/common/common.go
  2. 86 4
      gosql/common/dbmethods.go

+ 1 - 1
gosql/common/common.go

@@ -22,7 +22,7 @@ type Engine interface {
 	Prepare(ctx context.Context, query string) (*sql.Stmt, error)
 	Prepare(ctx context.Context, query string) (*sql.Stmt, error)
 	Query(ctx context.Context, query string, args ...any) (*sql.Rows, error)
 	Query(ctx context.Context, query string, args ...any) (*sql.Rows, error)
 	QueryRow(ctx context.Context, query string, args ...any) *sql.Row
 	QueryRow(ctx context.Context, query string, args ...any) *sql.Row
-	Transaction(ctx context.Context, queries qFunc) error
+	Transaction(ctx context.Context, queries queryFunc) error
 }
 }
 
 
 func ParseUrl(dbURL string) (*url.URL, error) {
 func ParseUrl(dbURL string) (*url.URL, error) {

+ 86 - 4
gosql/common/dbmethods.go

@@ -4,7 +4,10 @@ import (
 	"context"
 	"context"
 	"database/sql"
 	"database/sql"
 	"fmt"
 	"fmt"
+	"os"
 	"regexp"
 	"regexp"
+	"strings"
+	"time"
 
 
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
@@ -16,46 +19,125 @@ type DBMethods struct {
 	Driver string
 	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 {
 func (db *DBMethods) fixQuery(query string) string {
 	if db.Driver == "mysql" {
 	if db.Driver == "mysql" {
-		return r.ReplaceAllString(query, "?")
+		return rSqlParam.ReplaceAllString(query, "?")
 	}
 	}
 	return query
 	return query
 }
 }
 
 
 func (db *DBMethods) Begin(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) {
 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)
 	return db.DB.BeginTx(ctx, opts)
 }
 }
 
 
 func (db *DBMethods) Close() error {
 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()
 	return db.DB.Close()
 }
 }
 
 
 func (db *DBMethods) Exec(ctx context.Context, query string, args ...any) (sql.Result, error) {
 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...)
 	return db.DB.ExecContext(ctx, db.fixQuery(query), args...)
 }
 }
 
 
 func (db *DBMethods) Ping(ctx context.Context) error {
 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)
 	return db.DB.PingContext(ctx)
 }
 }
 
 
 func (db *DBMethods) Prepare(ctx context.Context, query string) (*sql.Stmt, error) {
 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))
 	return db.DB.PrepareContext(ctx, db.fixQuery(query))
 }
 }
 
 
 func (db *DBMethods) Query(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
 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...)
 	return db.DB.QueryContext(ctx, db.fixQuery(query), args...)
 }
 }
 
 
 func (db *DBMethods) QueryRow(ctx context.Context, query string, args ...any) *sql.Row {
 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...)
 	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 {
 	if queries == nil {
 		return fmt.Errorf("queries is not set for transaction")
 		return fmt.Errorf("queries is not set for transaction")
 	}
 	}