...

Source file src/github.com/letsencrypt/boulder/db/interfaces.go

Documentation: github.com/letsencrypt/boulder/db

     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, interface{}, string, ...interface{}) error
    22  }
    23  
    24  // A Selector is anything that provides a `Select` function.
    25  type Selector interface {
    26  	Select(context.Context, interface{}, string, ...interface{}) ([]interface{}, error)
    27  }
    28  
    29  // A Inserter is anything that provides an `Insert` function
    30  type Inserter interface {
    31  	Insert(context.Context, ...interface{}) error
    32  }
    33  
    34  // A Execer is anything that provides an `ExecContext` function
    35  type Execer interface {
    36  	ExecContext(context.Context, string, ...interface{}) (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  	Queryer
    62  	Delete(context.Context, ...interface{}) (int64, error)
    63  	Get(context.Context, interface{}, ...interface{}) (interface{}, error)
    64  	Update(context.Context, ...interface{}) (int64, error)
    65  }
    66  
    67  // Queryer offers the QueryContext method. Note that this is not read-only (i.e. not
    68  // Selector), since a QueryContext can be `INSERT`, `UPDATE`, etc. The difference
    69  // between QueryContext and ExecContext is that QueryContext can return rows. So for instance it is
    70  // suitable for inserting rows and getting back ids.
    71  type Queryer interface {
    72  	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
    73  }
    74  
    75  // Transaction extends an Executor and adds Rollback and Commit
    76  type Transaction interface {
    77  	Executor
    78  	Rollback() error
    79  	Commit() error
    80  }
    81  
    82  // MappedExecutor is anything that can map types to tables
    83  type MappedExecutor interface {
    84  	TableFor(reflect.Type, bool) (*borp.TableMap, error)
    85  	QueryContext(ctx context.Context, clauses string, args ...interface{}) (*sql.Rows, error)
    86  }
    87  
    88  // MappedSelector is anything that can execute various kinds of SQL statements
    89  // against a table automatically determined from the parameterized type.
    90  type MappedSelector[T any] interface {
    91  	QueryContext(ctx context.Context, clauses string, args ...interface{}) (Rows[T], error)
    92  	QueryFrom(ctx context.Context, tablename string, clauses string, args ...interface{}) (Rows[T], error)
    93  }
    94  
    95  // Rows is anything which lets you iterate over the result rows of a SELECT
    96  // query. It is similar to sql.Rows, but generic.
    97  type Rows[T any] interface {
    98  	Next() bool
    99  	Get() (*T, error)
   100  	Err() error
   101  	Close() error
   102  }
   103  
   104  // MockSqlExecutor implement SqlExecutor by returning errors from every call.
   105  //
   106  // TODO: To mock out WithContext, we needed to be able to return objects that satisfy
   107  // borp.SqlExecutor. That's a pretty big interface, so we specify one no-op mock
   108  // that we can embed everywhere we need to satisfy it.
   109  // Note: MockSqlExecutor does *not* implement WithContext. The expectation is
   110  // that structs that embed MockSqlExecutor will define their own WithContext
   111  // that returns a reference to themselves. That makes it easy for those structs
   112  // to override the specific methods they need to implement (e.g. SelectOne).
   113  type MockSqlExecutor struct{}
   114  
   115  func (mse MockSqlExecutor) Get(ctx context.Context, i interface{}, keys ...interface{}) (interface{}, error) {
   116  	return nil, errors.New("unimplemented")
   117  }
   118  func (mse MockSqlExecutor) Insert(ctx context.Context, list ...interface{}) error {
   119  	return errors.New("unimplemented")
   120  }
   121  func (mse MockSqlExecutor) Update(ctx context.Context, list ...interface{}) (int64, error) {
   122  	return 0, errors.New("unimplemented")
   123  }
   124  func (mse MockSqlExecutor) Delete(ctx context.Context, list ...interface{}) (int64, error) {
   125  	return 0, errors.New("unimplemented")
   126  }
   127  func (mse MockSqlExecutor) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
   128  	return nil, errors.New("unimplemented")
   129  }
   130  func (mse MockSqlExecutor) Select(ctx context.Context, i interface{}, query string, args ...interface{}) ([]interface{}, error) {
   131  	return nil, errors.New("unimplemented")
   132  }
   133  func (mse MockSqlExecutor) SelectInt(ctx context.Context, query string, args ...interface{}) (int64, error) {
   134  	return 0, errors.New("unimplemented")
   135  }
   136  func (mse MockSqlExecutor) SelectNullInt(ctx context.Context, query string, args ...interface{}) (sql.NullInt64, error) {
   137  	return sql.NullInt64{}, errors.New("unimplemented")
   138  }
   139  func (mse MockSqlExecutor) SelectFloat(ctx context.Context, query string, args ...interface{}) (float64, error) {
   140  	return 0, errors.New("unimplemented")
   141  }
   142  func (mse MockSqlExecutor) SelectNullFloat(ctx context.Context, query string, args ...interface{}) (sql.NullFloat64, error) {
   143  	return sql.NullFloat64{}, errors.New("unimplemented")
   144  }
   145  func (mse MockSqlExecutor) SelectStr(ctx context.Context, query string, args ...interface{}) (string, error) {
   146  	return "", errors.New("unimplemented")
   147  }
   148  func (mse MockSqlExecutor) SelectNullStr(ctx context.Context, query string, args ...interface{}) (sql.NullString, error) {
   149  	return sql.NullString{}, errors.New("unimplemented")
   150  }
   151  func (mse MockSqlExecutor) SelectOne(ctx context.Context, holder interface{}, query string, args ...interface{}) error {
   152  	return errors.New("unimplemented")
   153  }
   154  func (mse MockSqlExecutor) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
   155  	return nil, errors.New("unimplemented")
   156  }
   157  func (mse MockSqlExecutor) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
   158  	return nil
   159  }
   160  

View as plain text