github.com/letsencrypt/boulder@v0.20251208.0/db/interfaces.go (about) 1 package db 2 3 import ( 4 "context" 5 "database/sql" 6 "errors" 7 "reflect" 8 9 "github.com/letsencrypt/borp" 10 ) 11 12 // These interfaces exist to aid in mocking database operations for unit tests. 13 // 14 // By convention, any function that takes a OneSelector, Selector, 15 // Inserter, Execer, or SelectExecer as as an argument expects 16 // that a context has already been applied to the relevant DbMap or 17 // Transaction object. 18 19 // A OneSelector is anything that provides a `SelectOne` function. 20 type OneSelector interface { 21 SelectOne(context.Context, any, string, ...any) error 22 } 23 24 // A Selector is anything that provides a `Select` function. 25 type Selector interface { 26 Select(context.Context, any, string, ...any) ([]any, error) 27 } 28 29 // A Inserter is anything that provides an `Insert` function 30 type Inserter interface { 31 Insert(context.Context, ...any) error 32 } 33 34 // A Execer is anything that provides an `ExecContext` function 35 type Execer interface { 36 ExecContext(context.Context, string, ...any) (sql.Result, error) 37 } 38 39 // SelectExecer offers a subset of borp.SqlExecutor's methods: Select and 40 // ExecContext. 41 type SelectExecer interface { 42 Selector 43 Execer 44 } 45 46 // DatabaseMap offers the full combination of OneSelector, Inserter, 47 // SelectExecer, and a Begin function for creating a Transaction. 48 type DatabaseMap interface { 49 OneSelector 50 Inserter 51 SelectExecer 52 BeginTx(context.Context) (Transaction, error) 53 } 54 55 // Executor offers the full combination of OneSelector, Inserter, SelectExecer 56 // and adds a handful of other high level borp methods we use in Boulder. 57 type Executor interface { 58 OneSelector 59 Inserter 60 SelectExecer 61 Delete(context.Context, ...any) (int64, error) 62 Get(context.Context, any, ...any) (any, error) 63 Update(context.Context, ...any) (int64, error) 64 QueryContext(context.Context, string, ...any) (*sql.Rows, error) 65 } 66 67 // Transaction extends an Executor and adds Rollback and Commit 68 type Transaction interface { 69 Executor 70 Rollback() error 71 Commit() error 72 } 73 74 // MappedExecutor is anything that can map types to tables 75 type MappedExecutor interface { 76 TableFor(reflect.Type, bool) (*borp.TableMap, error) 77 QueryContext(ctx context.Context, clauses string, args ...any) (*sql.Rows, error) 78 } 79 80 // MappedSelector is anything that can execute various kinds of SQL statements 81 // against a table automatically determined from the parameterized type. 82 type MappedSelector[T any] interface { 83 QueryContext(ctx context.Context, clauses string, args ...any) (Rows[T], error) 84 QueryFrom(ctx context.Context, tablename string, clauses string, args ...any) (Rows[T], error) 85 } 86 87 // Rows is anything which lets you iterate over the result rows of a SELECT 88 // query. It is similar to sql.Rows, but generic. 89 type Rows[T any] interface { 90 ForEach(func(*T) error) error 91 Next() bool 92 Get() (*T, error) 93 Err() error 94 Close() error 95 } 96 97 // MockSqlExecutor implement SqlExecutor by returning errors from every call. 98 // 99 // TODO: To mock out WithContext, we needed to be able to return objects that satisfy 100 // borp.SqlExecutor. That's a pretty big interface, so we specify one no-op mock 101 // that we can embed everywhere we need to satisfy it. 102 // Note: MockSqlExecutor does *not* implement WithContext. The expectation is 103 // that structs that embed MockSqlExecutor will define their own WithContext 104 // that returns a reference to themselves. That makes it easy for those structs 105 // to override the specific methods they need to implement (e.g. SelectOne). 106 type MockSqlExecutor struct{} 107 108 func (mse MockSqlExecutor) Get(ctx context.Context, i any, keys ...any) (any, error) { 109 return nil, errors.New("unimplemented") 110 } 111 func (mse MockSqlExecutor) Insert(ctx context.Context, list ...any) error { 112 return errors.New("unimplemented") 113 } 114 func (mse MockSqlExecutor) Update(ctx context.Context, list ...any) (int64, error) { 115 return 0, errors.New("unimplemented") 116 } 117 func (mse MockSqlExecutor) Delete(ctx context.Context, list ...any) (int64, error) { 118 return 0, errors.New("unimplemented") 119 } 120 func (mse MockSqlExecutor) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) { 121 return nil, errors.New("unimplemented") 122 } 123 func (mse MockSqlExecutor) Select(ctx context.Context, i any, query string, args ...any) ([]any, error) { 124 return nil, errors.New("unimplemented") 125 } 126 func (mse MockSqlExecutor) SelectInt(ctx context.Context, query string, args ...any) (int64, error) { 127 return 0, errors.New("unimplemented") 128 } 129 func (mse MockSqlExecutor) SelectNullInt(ctx context.Context, query string, args ...any) (sql.NullInt64, error) { 130 return sql.NullInt64{}, errors.New("unimplemented") 131 } 132 func (mse MockSqlExecutor) SelectFloat(ctx context.Context, query string, args ...any) (float64, error) { 133 return 0, errors.New("unimplemented") 134 } 135 func (mse MockSqlExecutor) SelectNullFloat(ctx context.Context, query string, args ...any) (sql.NullFloat64, error) { 136 return sql.NullFloat64{}, errors.New("unimplemented") 137 } 138 func (mse MockSqlExecutor) SelectStr(ctx context.Context, query string, args ...any) (string, error) { 139 return "", errors.New("unimplemented") 140 } 141 func (mse MockSqlExecutor) SelectNullStr(ctx context.Context, query string, args ...any) (sql.NullString, error) { 142 return sql.NullString{}, errors.New("unimplemented") 143 } 144 func (mse MockSqlExecutor) SelectOne(ctx context.Context, holder any, query string, args ...any) error { 145 return errors.New("unimplemented") 146 } 147 func (mse MockSqlExecutor) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) { 148 return nil, errors.New("unimplemented") 149 } 150 func (mse MockSqlExecutor) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row { 151 return nil 152 }