github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqx/daoopt.go (about)

     1  package sqx
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"fmt"
     7  	"reflect"
     8  
     9  	"github.com/bingoohuang/gg/pkg/defaults"
    10  	"github.com/bingoohuang/gg/pkg/reflector"
    11  )
    12  
    13  // CreateDaoOpt defines the options for CreateDao.
    14  type CreateDaoOpt struct {
    15  	Error              *error
    16  	Ctx                context.Context
    17  	QueryMaxRows       int `default:"-1"`
    18  	RowScanInterceptor RowScanInterceptor
    19  	DotSQL             func(name string) (SQLPart, error)
    20  	Logger             DaoLogger
    21  	ErrSetter          func(err error)
    22  	DBGetter           DBGetter
    23  }
    24  
    25  // CreateDaoOpter defines the option pattern interface for CreateDaoOpt.
    26  type CreateDaoOpter interface {
    27  	ApplyCreateOpt(*CreateDaoOpt)
    28  }
    29  
    30  // CreateDaoOptFn defines the func prototype to option applying.
    31  type CreateDaoOptFn func(*CreateDaoOpt)
    32  
    33  // ApplyCreateOpt applies the option.
    34  func (c CreateDaoOptFn) ApplyCreateOpt(opt *CreateDaoOpt) { c(opt) }
    35  
    36  // WithError specifies the err pointer to receive error.
    37  func WithError(err *error) CreateDaoOpter {
    38  	return CreateDaoOptFn(func(opt *CreateDaoOpt) { opt.Error = err })
    39  }
    40  
    41  // WithCtx specifies the context.Context to sdb execution processes.
    42  func WithCtx(ctx context.Context) CreateDaoOpter {
    43  	return CreateDaoOptFn(func(opt *CreateDaoOpt) { opt.Ctx = ctx })
    44  }
    45  
    46  // WithLimit specifies the max rows to be fetched when execute query.
    47  func WithLimit(maxRows int) CreateDaoOpter {
    48  	return CreateDaoOptFn(func(opt *CreateDaoOpt) { opt.QueryMaxRows = maxRows })
    49  }
    50  
    51  // WithSQLFile imports SQL queries from the file.
    52  func WithSQLFile(sqlFile string) CreateDaoOpter {
    53  	return CreateDaoOptFn(func(opt *CreateDaoOpt) {
    54  		ds, err := DotSQLLoadFile(sqlFile)
    55  		if err != nil {
    56  			panic(err)
    57  		}
    58  
    59  		opt.DotSQL = ds.Raw
    60  	})
    61  }
    62  
    63  // WithDB imports a db.
    64  func WithDB(db *sql.DB) CreateDaoOpter {
    65  	return CreateDaoOptFn(func(opt *CreateDaoOpt) { opt.DBGetter = &StdDB{db: db} })
    66  }
    67  
    68  // WithSQLStr imports SQL queries from the string.
    69  func WithSQLStr(s string) CreateDaoOpter {
    70  	return CreateDaoOptFn(func(opt *CreateDaoOpt) {
    71  		ds, err := DotSQLLoadString(s)
    72  		if err != nil {
    73  			panic(err)
    74  		}
    75  
    76  		opt.DotSQL = ds.Raw
    77  	})
    78  }
    79  
    80  // WithRowScanInterceptor specifies the RowScanInterceptor after a row fetched.
    81  func WithRowScanInterceptor(interceptor RowScanInterceptor) CreateDaoOpter {
    82  	return CreateDaoOptFn(func(opt *CreateDaoOpt) { opt.RowScanInterceptor = interceptor })
    83  }
    84  
    85  // RowScanInterceptor defines the interceptor after a row scanning.
    86  type RowScanInterceptor interface {
    87  	After(rowIndex int, v ...interface{}) (bool, error)
    88  }
    89  
    90  // RowScanInterceptorFn defines the interceptor function after a row scanning.
    91  type RowScanInterceptorFn func(rowIndex int, v ...interface{}) (bool, error)
    92  
    93  // After is revoked after a row scanning.
    94  func (r RowScanInterceptorFn) After(rowIndex int, v ...interface{}) (bool, error) {
    95  	return r(rowIndex, v...)
    96  }
    97  
    98  func applyCreateDaoOption(createDaoOpts []CreateDaoOpter) (*CreateDaoOpt, error) {
    99  	opt := &CreateDaoOpt{}
   100  	if err := defaults.Set(opt); err != nil {
   101  		return nil, fmt.Errorf("failed to set defaults for CreateDaoOpt error %w", err)
   102  	}
   103  
   104  	for _, v := range createDaoOpts {
   105  		v.ApplyCreateOpt(opt)
   106  	}
   107  
   108  	if opt.Ctx == nil {
   109  		opt.Ctx = context.Background()
   110  	}
   111  
   112  	if opt.DotSQL == nil {
   113  		opt.DotSQL = func(string) (SQLPart, error) { return nil, nil }
   114  	}
   115  
   116  	return opt, nil
   117  }
   118  
   119  func createErrorSetter(v reflect.Value, option *CreateDaoOpt) {
   120  	for i := 0; i < v.NumField(); i++ {
   121  		fv := v.Field(i)
   122  		f := v.Type().Field(i)
   123  
   124  		if f.PkgPath != "" /* not exportable? */ {
   125  			continue
   126  		}
   127  
   128  		if !reflector.IsError(f.Type) {
   129  			continue
   130  		}
   131  
   132  		option.ErrSetter = func(err error) {
   133  			if option.Error != nil {
   134  				*option.Error = err
   135  			}
   136  
   137  			if fv.IsNil() && err == nil {
   138  				return
   139  			}
   140  
   141  			if err == nil {
   142  				fv.Set(reflect.Zero(f.Type))
   143  			} else {
   144  				fv.Set(reflect.ValueOf(err))
   145  			}
   146  		}
   147  
   148  		return
   149  	}
   150  
   151  	option.ErrSetter = func(err error) {
   152  		if option.Error != nil {
   153  			*option.Error = err
   154  		}
   155  	}
   156  }