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  }