github.com/blend/go-sdk@v1.20220411.3/testutil/db.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package testutil 9 10 import ( 11 "context" 12 "database/sql" 13 "reflect" 14 "unsafe" 15 16 "github.com/blend/go-sdk/db" 17 "github.com/blend/go-sdk/ex" 18 ) 19 20 // NOTE: Ensure that 21 // * `AlwaysFailDB` satisfies `db.DB`. 22 // * `PseudoQueryDB` satisfies `db.DB`. 23 var ( 24 _ db.DB = (*AlwaysFailDB)(nil) 25 _ db.DB = (*PseudoQueryDB)(nil) 26 ) 27 28 // AlwaysFailDB implements the `db.DB` interface, but each method always fails. 29 type AlwaysFailDB struct { 30 Errors ErrorProducer 31 } 32 33 // ExecContext implements the `db.DB` interface and returns and error. 34 func (afd *AlwaysFailDB) ExecContext(context.Context, string, ...interface{}) (sql.Result, error) { 35 return nil, afd.Errors.NextError() 36 } 37 38 // QueryContext implements the `db.DB` interface and returns and error. 39 func (afd *AlwaysFailDB) QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) { 40 return nil, afd.Errors.NextError() 41 } 42 43 // QueryRowContext implements the `db.DB` interface; the error value is embedded 44 // in the `sql.Row` value returned. 45 func (afd *AlwaysFailDB) QueryRowContext(context.Context, string, ...interface{}) *sql.Row { 46 return sqlRowWithError(afd.Errors.NextError()) 47 } 48 49 // PseudoQueryDB implements the `db.DB` interface, it intercepts calls to 50 // `QueryContext` and replaces the `query` / `args` arguments with custom 51 // values. 52 type PseudoQueryDB struct { 53 DB *sql.DB 54 Query string 55 Args []interface{} 56 } 57 58 // ExecContext implements the `db.DB` interface; this is not supported in 59 // `PseudoQueryDB`. It will **always** return a "not implemented" error. 60 func (pqd *PseudoQueryDB) ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error) { 61 return nil, ex.New("Not Implemented: ExecContext") 62 } 63 64 // QueryContext implements the `db.DB` interface. It intercepts the **actual** 65 // query and arguments and replaces them with the query and arguments stored 66 // on the current `PseudoQueryDB`. 67 func (pqd *PseudoQueryDB) QueryContext(ctx context.Context, _ string, _ ...interface{}) (*sql.Rows, error) { 68 return pqd.DB.QueryContext(ctx, pqd.Query, pqd.Args...) 69 } 70 71 // QueryRowContext implements the `db.DB` interface; this is not supported in 72 // `PseudoQueryDB`. It will **always** return a `sql.Row` with a "not implemented" 73 // error set on the row. 74 func (pqd *PseudoQueryDB) QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row { 75 err := ex.New("Not Implemented: QueryRowContext") 76 return sqlRowWithError(err) 77 } 78 79 func sqlRowWithError(err error) *sql.Row { 80 row := &sql.Row{} 81 e := reflect.ValueOf(row).Elem().FieldByName("err") 82 eMutable := reflect.NewAt(e.Type(), unsafe.Pointer(e.UnsafeAddr())).Elem() 83 eMutable.Set(reflect.ValueOf(err)) 84 return row 85 }