From 03593c11daa24eacf672b4dfe43b56789dbeb2b3 Mon Sep 17 00:00:00 2001 From: makubit Date: Tue, 5 Dec 2023 12:10:38 +0100 Subject: [PATCH] #152 Add proper comments to all functions and structures --- batch.go | 30 ++++++++++++++++++++++++++---- expectations.go | 8 +++++--- pgxmock.go | 22 ++++++++++++++++++++-- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/batch.go b/batch.go index 06478af..52446f1 100644 --- a/batch.go +++ b/batch.go @@ -12,8 +12,8 @@ type BatchElement struct { args []interface{} } -// NewBatchElement creates new query that will be queued in batch -// function accepts sql string and optionally arguments +// NewBatchElement creates new query that will be queued in batch. +// Function accepts sql string and optionally arguments func NewBatchElement(sql string, args ...interface{}) *BatchElement { return &BatchElement{ sql: sql, @@ -21,6 +21,8 @@ func NewBatchElement(sql string, args ...interface{}) *BatchElement { } } +// WithRewrittenSQL will match given expected expression to a rewritten SQL statement by +// a pgx.QueryRewriter argument func (be *BatchElement) WithRewrittenSQL(sql string) *BatchElement { be.rewrittenSQL = sql return be @@ -31,6 +33,8 @@ type Batch struct { elements []*BatchElement } +// AddBatchElements adds any number of BatchElement to Batch +// that is used for mocking pgx.SendBatch() func (b *Batch) AddBatchElements(bes ...*BatchElement) *Batch { for _, be := range bes { b.elements = append(b.elements, be) @@ -38,17 +42,19 @@ func (b *Batch) AddBatchElements(bes ...*BatchElement) *Batch { return b } -// NewBatch creates a structure that helps to combine multiple queries that will be used in batches -// this function should be used in .ExpectSendBatch() +// NewBatch creates a structure that helps to combine multiple queries +// that will be used in batches. This function should be used in .ExpectSendBatch() func NewBatch() *Batch { return &Batch{} } +// batchResults is a subsidiary structure for mocking BatchResults interface response type batchResults struct { br *BatchResults ex *ExpectedBatch } +// Query is a mock for Query() function in pgx.BatchResults interface func (b *batchResults) Query() (pgx.Rows, error) { if b.br.queryErr != nil { return nil, b.br.queryErr @@ -58,6 +64,7 @@ func (b *batchResults) Query() (pgx.Rows, error) { return rs, nil } +// Exec is a mock for Exec() function in pgx.BatchResults interface func (b *batchResults) Exec() (pgconn.CommandTag, error) { if b.br.execErr != nil { return pgconn.CommandTag{}, b.br.execErr @@ -65,17 +72,21 @@ func (b *batchResults) Exec() (pgconn.CommandTag, error) { return b.br.commandTag, nil } +// QueryRow is a mock for QueryRow() function in pgx.BatchResults interface func (b *batchResults) QueryRow() pgx.Row { rs := &rowSets{sets: []*Rows{b.br.rows}} rs.Next() return rs } +// Close is a mock for Close() function in pgx.BatchResults interface func (b *batchResults) Close() error { b.ex.batchWasClosed = true return b.br.closeErr } +// BatchResults is a subsidiary structure for mocking SendBatch() function +// response. There is an option to mock returned Rows, errors and commandTag type BatchResults struct { commandTag pgconn.CommandTag rows *Rows @@ -84,30 +95,41 @@ type BatchResults struct { closeErr error } +// NewBatchResults returns a mock response for SendBatch() function func NewBatchResults() *BatchResults { return &BatchResults{} } +// QueryError sets the error that will be returned by Query() function +// called using pgx.BatchResults interface func (b *BatchResults) QueryError(err error) *BatchResults { b.queryErr = err return b } +// ExecError sets the error that will be returned by Exec() function +// called using pgx.BatchResults interface func (b *BatchResults) ExecError(err error) *BatchResults { b.execErr = err return b } +// CloseError sets the error that will be returned by Close() function +// called using pgx.BatchResults interface func (b *BatchResults) CloseError(err error) *BatchResults { b.closeErr = err return b } +// WillReturnRows allows to return mocked Rows by Query() and QueryRow() +// functions in pgx.BatchResults interface func (b *BatchResults) WillReturnRows(rows *Rows) *BatchResults { b.rows = rows return b } +// AddCommandTag allows to add pgconn.CommandTag to batchResults struct +// that will be returned in Exec() function func (b *BatchResults) AddCommandTag(ct pgconn.CommandTag) *BatchResults { b.commandTag = ct return b diff --git a/expectations.go b/expectations.go index 7a87dd2..a877534 100644 --- a/expectations.go +++ b/expectations.go @@ -442,7 +442,7 @@ func (e *ExpectedRollback) String() string { } // ExpectedBatch is used to manage pgx.SendBatch, pgx.Tx.SendBatch expectations. -// Returned by pgxmock.ExpectBatch. +// Returned by pgxmock.ExpectBatch type ExpectedBatch struct { commonExpectation expectedBatch []queryBasedExpectation @@ -451,7 +451,7 @@ type ExpectedBatch struct { batchWasClosed bool } -// String returns string representation. +// String returns string representation func (e *ExpectedBatch) String() string { msg := "ExpectedBatch => expecting call to SendBatch():\n" for _, b := range e.expectedBatch { @@ -474,12 +474,14 @@ func (e *ExpectedBatch) String() string { return msg + e.commonExpectation.String() } -// WillReturnBatchResults arranges for an expected SendBatch() to return given batch results. +// WillReturnBatchResults arranges for an expected SendBatch() to return given batch results func (e *ExpectedBatch) WillReturnBatchResults(br *BatchResults) *ExpectedBatch { e.expectedBatchResponse = &batchResults{br: br, ex: e} return e } +// BatchResultsWillBeClosed indicates that batchResults has to be closed. +// batchMustBeClosed will be checked in pgxmock.ExpectationsWereMet() func (e *ExpectedBatch) BatchResultsWillBeClosed() *ExpectedBatch { e.batchMustBeClosed = true return e diff --git a/pgxmock.go b/pgxmock.go index e1e99d7..f591819 100644 --- a/pgxmock.go +++ b/pgxmock.go @@ -69,6 +69,8 @@ type pgxMockIface interface { // the *ExpectedRollback allows to mock database response ExpectRollback() *ExpectedRollback + // ExpectSendBatch expects pgx.Tx.SendBatch() to be called with expected Batch + // structure. The *ExpectedBatch allows to mock database response ExpectSendBatch(expectedBatch *Batch) *ExpectedBatch // ExpectPing expected pgx.Conn.Ping to be called. @@ -108,13 +110,19 @@ type pgxMockIface interface { // sql driver.Value slice with a definition of sql metadata NewRowsWithColumnDefinition(columns ...pgconn.FieldDescription) *Rows - // New Column allows to create a Column + // NewColumn allows to create a Column NewColumn(name string) *pgconn.FieldDescription + // NewBatchResults creates the mock structure for pgx.BatchResults interface + // which is returned by a SendBatch() function NewBatchResults() *BatchResults + // NewBatch creates the mock structure for pgx.Batch + // allows to validate correctly queries passed to SendBatch() function NewBatch() *Batch + // NewBatchElement allows to pass sql queries with arguments + // to the Batch mock structure used in SendBatch() NewBatchElement(sql string, args ...interface{}) *BatchElement Config() *pgxpool.Config @@ -322,14 +330,19 @@ func (c *pgxmock) NewColumn(name string) *pgconn.FieldDescription { return &pgconn.FieldDescription{Name: name} } +// NewBatchResults allows to mock a BatchResult interface with defined +// rows or errors to return func (c *pgxmock) NewBatchResults() *BatchResults { return NewBatchResults() } +// NewBatch allows to mock pgx.Batch structure func (c *pgxmock) NewBatch() *Batch { return NewBatch() } +// NewBatchElement is an element that consists of sql string and arguments +// that can be passed to AddBatchElements() function func (c *pgxmock) NewBatchElement(sql string, args ...interface{}) *BatchElement { return NewBatchElement(sql, args) } @@ -389,6 +402,11 @@ func (c *pgxmock) SendBatch(ctx context.Context, batch *pgx.Batch) pgx.BatchResu return fmt.Errorf("batch length has to match the expected batch length") } + // For now the solution is to use unsafe.Pointer() to retrieve unexported field 'queuedQueries', + // and inside pgx.QueuedQuery unexported fields 'query' and 'arguments' that allows + // to properly use queryMatcher.Match() and argsMatches() functions. + // Other way would be to use reflect.DeepCopy(), but the limitation of this solution is that + // batch passed to this func would have to be the exact as batch structure in mock. for i, q := range batchExp.expectedBatch { qqValue := v.FieldByName("queuedQueries").Index(i) qq := reflect.NewAt(qqValue.Type(), unsafe.Pointer(qqValue.UnsafeAddr())).Elem().Interface().(*pgx.QueuedQuery) @@ -416,7 +434,7 @@ func (c *pgxmock) SendBatch(ctx context.Context, batch *pgx.Batch) pgx.BatchResu return nil }) if err != nil { - //printing as we cannot return this error + // Printing, as we cannot return this error fmt.Println(err) return nil }