github.com/eden-framework/sqlx@v0.0.2/db.go (about)

     1  package sqlx
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"errors"
     7  	"time"
     8  
     9  	"github.com/eden-framework/sqlx/builder"
    10  )
    11  
    12  var ErrNotTx = errors.New("db is not *sql.Tx")
    13  var ErrNotDB = errors.New("db is not *sql.DB")
    14  
    15  type SqlExecutor interface {
    16  	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
    17  	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
    18  }
    19  
    20  type SqlxExecutor interface {
    21  	SqlExecutor
    22  	ExecExpr(expr builder.SqlExpr) (sql.Result, error)
    23  	QueryExpr(expr builder.SqlExpr) (*sql.Rows, error)
    24  
    25  	QueryExprAndScan(expr builder.SqlExpr, v interface{}) error
    26  }
    27  
    28  type Migrator interface {
    29  	Migrate(ctx context.Context, db DBExecutor) error
    30  }
    31  
    32  type DBExecutor interface {
    33  	SqlxExecutor
    34  
    35  	// dialect of databases
    36  	Dialect() builder.Dialect
    37  	// return database which is connecting
    38  	D() *Database
    39  	// switch database schema
    40  	WithSchema(schema string) DBExecutor
    41  	// return table of the connecting database
    42  	T(model builder.Model) *builder.Table
    43  
    44  	Context() context.Context
    45  	WithContext(ctx context.Context) DBExecutor
    46  }
    47  
    48  type MaybeTxExecutor interface {
    49  	IsTx() bool
    50  	BeginTx(*sql.TxOptions) (DBExecutor, error)
    51  	Begin() (DBExecutor, error)
    52  	Commit() error
    53  	Rollback() error
    54  }
    55  
    56  type DB struct {
    57  	dialect builder.Dialect
    58  	*Database
    59  	SqlExecutor
    60  	ctx context.Context
    61  }
    62  
    63  func (d *DB) WithContext(ctx context.Context) DBExecutor {
    64  	dd := new(DB)
    65  	*dd = *d
    66  	dd.ctx = ctx
    67  	return dd
    68  }
    69  
    70  func (d *DB) Context() context.Context {
    71  	if d.ctx != nil {
    72  		return d.ctx
    73  	}
    74  	return context.Background()
    75  }
    76  
    77  func (d DB) WithSchema(schema string) DBExecutor {
    78  	d.Database = d.Database.WithSchema(schema)
    79  	return &d
    80  }
    81  
    82  func (d *DB) Dialect() builder.Dialect {
    83  	return d.dialect
    84  }
    85  
    86  func (d *DB) Migrate(ctx context.Context, db DBExecutor) error {
    87  	if migrator, ok := d.dialect.(Migrator); ok {
    88  		return migrator.Migrate(ctx, db)
    89  	}
    90  	return nil
    91  }
    92  
    93  func (d *DB) D() *Database {
    94  	return d.Database
    95  }
    96  
    97  func (d *DB) ExecExpr(expr builder.SqlExpr) (sql.Result, error) {
    98  	e := builder.ResolveExprContext(d.Context(), expr)
    99  	if builder.IsNilExpr(e) {
   100  		return nil, nil
   101  	}
   102  	if err := e.Err(); err != nil {
   103  		return nil, err
   104  	}
   105  	result, err := d.ExecContext(d.Context(), e.Query(), e.Args()...)
   106  	if err != nil {
   107  		if d.dialect.IsErrorConflict(err) {
   108  			return nil, NewSqlError(sqlErrTypeConflict, err.Error())
   109  		}
   110  		return nil, err
   111  	}
   112  	return result, nil
   113  }
   114  
   115  func (d *DB) QueryExpr(expr builder.SqlExpr) (*sql.Rows, error) {
   116  	e := builder.ResolveExprContext(d.Context(), expr)
   117  	if builder.IsNilExpr(e) {
   118  		return nil, nil
   119  	}
   120  	if err := e.Err(); err != nil {
   121  		return nil, err
   122  	}
   123  	return d.QueryContext(d.Context(), e.Query(), e.Args()...)
   124  }
   125  
   126  func (d *DB) QueryExprAndScan(expr builder.SqlExpr, v interface{}) error {
   127  	rows, err := d.QueryExpr(expr)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return Scan(rows, v)
   132  }
   133  
   134  func (d *DB) IsTx() bool {
   135  	_, ok := d.SqlExecutor.(*sql.Tx)
   136  	return ok
   137  }
   138  
   139  func (d *DB) Begin() (DBExecutor, error) {
   140  	return d.BeginTx(nil)
   141  }
   142  
   143  func (d *DB) BeginTx(opt *sql.TxOptions) (DBExecutor, error) {
   144  	if d.IsTx() {
   145  		return nil, ErrNotDB
   146  	}
   147  	db, err := d.SqlExecutor.(*sql.DB).BeginTx(d.Context(), opt)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	return &DB{
   152  		Database:    d.Database,
   153  		dialect:     d.dialect,
   154  		SqlExecutor: db,
   155  		ctx:         d.Context(),
   156  	}, nil
   157  }
   158  
   159  func (d *DB) Commit() error {
   160  	if !d.IsTx() {
   161  		return ErrNotTx
   162  	}
   163  	if d.Context().Err() == context.Canceled {
   164  		return context.Canceled
   165  	}
   166  	return d.SqlExecutor.(*sql.Tx).Commit()
   167  }
   168  
   169  func (d *DB) Rollback() error {
   170  	if !d.IsTx() {
   171  		return ErrNotTx
   172  	}
   173  	if d.Context().Err() == context.Canceled {
   174  		return context.Canceled
   175  	}
   176  	return d.SqlExecutor.(*sql.Tx).Rollback()
   177  }
   178  
   179  func (d *DB) SetMaxOpenConns(n int) {
   180  	d.SqlExecutor.(*sql.DB).SetMaxOpenConns(n)
   181  }
   182  
   183  func (d *DB) SetMaxIdleConns(n int) {
   184  	d.SqlExecutor.(*sql.DB).SetMaxIdleConns(n)
   185  }
   186  
   187  func (d *DB) SetConnMaxLifetime(t time.Duration) {
   188  	d.SqlExecutor.(*sql.DB).SetConnMaxLifetime(t)
   189  }