mogi

package module
v0.0.0-...-ccf68ae Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2018 License: BSD-2-Clause, BSD-3-Clause Imports: 16 Imported by: 0

README

mogi GoDoc Coverage

import "github.com/guregu/mogi"

mogi is a fancy SQL mocking/stubbing library for Go. It uses the vitess SQL parser for maximum happiness.

Note: because vitess is a MySQL-flavored parser, other kinds of (non-)standard SQL may break mogi. Mogi isn't finished yet. You can't yet filter stubs based on subqueries and complex bits like ON DUPLICATED AT.

Usage

Getting started
import 	"github.com/guregu/mogi"
db, _ := sql.Open("mogi", "")
Stubbing SELECT queries
// Stub any SELECT query
mogi.Select().StubCSV(`1,Yona Yona Ale,Yo-Ho Brewing,5.5`)
rows, err := db.Query("SELECT id, name, brewery, pct FROM beer")

// Reset to clear all stubs
mogi.Reset()

// Stub SELECT queries by columns selected
mogi.Select("id", "name", "brewery", "pct").StubCSV(`1,Yona Yona Ale,Yo-Ho Brewing,5.5`)
// Aliased columns should be given as they are aliased.
// Qualified columns should be given as they are qualified.
// e.g. SELECT beer.name AS n, breweries.founded FROM beer JOIN breweries ON beer.brewery = breweries.name
mogi.Select("n", "breweries.founded").StubCSV(`Stone IPA,1996`)

// You can stub with driver.Values instead of CSV
mogi.Select("id", "deleted_at").Stub([][]driver.Value{{1, nil}})

// Filter by table name
mogi.Select().From("beer").StubCSV(`1,Yona Yona Ale,Yo-Ho Brewing,5.5`)

// You can supply multiple table names for JOIN queries
// e.g. SELECT beer.name, wine.name FROM beer JOIN wine ON beer.pct = wine.pct
// or   SELECT beer.name, wine.name FROM beer, wine WHERE beer.pct = wine.pct
mogi.Select().From("beer", "wine").StubCSV(`Westvleteren XII,Across the Pond Riesling`)

// Filter by WHERE clause params
mogi.Select().Where("id", 10).StubCSV(`10,Apex,Bear Republic Brewing Co.,8.95`)
mogi.Select().Where("id", 42).StubCSV(`42,Westvleteren XII,Brouwerij Westvleteren,10.2`)
rows, err := db.Query("SELECT id, name, brewery, pct FROM beer WHERE id = ?", 10)
...
rows, err = db.Query("SELECT id, name, brewery, pct FROM beer WHERE id = ?", 42)
...

// Pass multiple arguments to Where() for IN clauses.
mogi.Select().Where("id", 10, 42).StubCSV("Apex\nWestvleteren XII")
rows, err = db.Query("SELECT name FROM beer WHERE id IN (?, ?)", 10, 42)

// Stub an error while you're at it
mogi.Select().Where("id", 3).StubError(sql.ErrNoRows)
// FYI, unstubbed queries will return mogi.ErrUnstubbed

// Filter by args given
mogi.Select().Args(1).StubCSV(`1,Yona Yona Ale,Yo-Ho Brewing,5.5`)
rows, err := db.Query("SELECT id, name, brewery, pct FROM beer WHERE id = ?", 1)

// Chain filters as much as you'd like
mogi.Select("id", "name", "brewery", "pct").From("beer").Where("id", 1).StubCSV(`1,Yona Yona Ale,Yo-Ho Brewing,5.5`)
Stubbing INSERT queries
// Stub any INSERT query
// You can use StubResult to easily stub a driver.Result.
// You can pass -1 to StubResult to have it return an error for that particular bit.
// In this example, we have 1 row affected, but no LastInsertID.
mogi.Insert().StubResult(-1, 1)
// If you have your own driver.Result you want to pass, just use Stub.
// You can also stub an error with StubError.

// Filter by the columns used in the INSERT query
mogi.Insert("name", "brewery", "pct").StubResult(1, 1)
result, err := db.Exec("INSERT INTO beer (name, brewery, pct) VALUES (?, ?, ?)", "Yona Yona Ale", "Yo-Ho Brewing", 5.5)

// Filter by the table used in the query
mogi.Insert().Into("beer").StubResult(1, 1)

// Filter by the args passed to the query (the things replacing the ?s)
mogi.Insert().Args("Yona Yona Ale", "Yo-Ho Brewing", 5.5).StubResult(1, 1)

// Filter by the values used in the query
mogi.Insert().Value("name", "Yona Yona Ale").Value("brewery", "Yo-Ho Brewing").StubResult(1, 1)
// Use ValueAt when you are inserting multiple rows. The first argument is the row #, starting with 0.
// Parameters are interpolated for you.
mogi.Insert().
	ValueAt(0, "brewery", "Mikkeller").ValueAt(0, "pct", 4.6).
	ValueAt(1, "brewery", "BrewDog").ValueAt(1, "pct", 18.2).
	StubResult(4, 2)
result, err = db.Exec(`INSERT INTO beer (name, brewery, pct) VALUES (?, "Mikkeller", 4.6), (?, ?, ?)`,
	"Mikkel’s Dream",
	"Tokyo*", "BrewDog", 18.2,
)
Stubbing UPDATE queries
// Stub any UPDATE query
// UPDATE stubs work the same as INSERT stubs
// This stubs all UPDATE queries to return 10 rows affected
mogi.Update().StubResult(-1, 10)
// This does the same thing
mogi.Update().StubRowsAffected(10)

// Filter by the columns used in the SET clause
mogi.Update("name", "brewery", "pct").StubRowsAffected(1)
_, err := db.Exec(`UPDATE beer
				   SET name = "Mikkel’s Dream", brewery = "Mikkeller", pct = 4.6
				   WHERE id = ? AND moon = ?`, 3, "full")

// Filter by values set by the SET clause
mogi.Update().Value("name", "Mikkel’s Dream").Value("brewery", "Mikkeller").StubRowsAffected(1)

// Filter by args (? placeholder values)
mogi.Update().Args(3, "full").StubRowsAffected(1)

// Filter by the table being updated
mogi.Update().Table("beer").StubRowsAffected(1)

// Filter by WHERE clause params
mogi.Update().Where("id", 3).Where("moon", "full").StubRowsAffected(1)
Stubbing DELETE queries

Works the same as UPDATE, docs later!

Other stuff
Reset

You can remove all the stubs you've set with mogi.Reset().

Verbose

mogi.Verbose(true) will enable verbose mode, logging unstubbed queries.

Parse time

Set the time layout with mogi.ParseTime(). CSV values matching that layout will be converted to time.Time. You can also stub time.Time directly using the Stub() method.

mogi.ParseTime(time.RFC3339)
mogi.Select("release").
		From("beer").
		Where("id", 42).
		StubCSV(`2014-06-30T12:00:00Z`)
Dump stubs

Dump all the stubs with mogi.Dump(). It will print something like this:

>>           Query stubs: (1 total)
             =========================
#1    [3]    SELECT (any)                               [+1]
             FROM device_tokens                         [+1]
             WHERE user_id ≈ [42]                       [+1]
             → error: sql: no rows in result set

>>           Exec stubs: (2 total)
             =========================
#1    [3]    INSERT (any)                               [+1]
             TABLE device_tokens                        [+1]
             VALUE device_type ≈ gunosy_lite (row 0)    [+1]
             → result ID: 1337, rows: 1
#2    [2]    INSERT (any)                               [+1]
             TABLE device_tokens                        [+1]
             → error: device_type should be overwriten

This is helpful when you're debugging and need to double-check the priorities and conditions you've stubbed. The numbers in [brackets] are the priorities. You can also add Dump() to a stub condition chain. It will dump lots of information about the query when matched.

License

BSD

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnstubbed is returned as the result for unstubbed queries.
	ErrUnstubbed = errors.New("mogi: query not stubbed")
	// ErrUnresolved is returned as the result of a stub that was matched,
	// but whose data could not be resolved. For example, exceeded LIMITs.
	ErrUnresolved = errors.New("mogi: query matched but no stub data")
)

Functions

func Dump

func Dump()

Dump prints all the current stubs, in order of priority. Helpful for debugging.

func ParseTime

func ParseTime(layout string)

ParseTime will configure mogi to convert dates of the given layout (e.g. time.RFC3339) to time.Time when using StubCSV. Give it an empty string to turn off time parsing.

func Reset

func Reset()

Reset removes all the stubs that have been set

func Verbose

func Verbose(v bool)

Verbose turns on unstubbed logging when v is true

Types

type ExecStub

type ExecStub struct {
	// contains filtered or unexported fields
}

ExecStub is a SQL exec stub (for INSERT, UPDATE, DELETE)

func Delete

func Delete() *ExecStub

Delete starts a new stub for DELETE statements.

func Insert

func Insert(cols ...string) *ExecStub

Insert starts a new stub for INSERT statements. You can filter out which columns to use this stub for. If you don't pass any columns, it will stub all INSERT queries.

func Update

func Update(cols ...string) *ExecStub

Update starts a new stub for UPDATE statements. You can filter out which columns (from the SET statement) this stub is for. If you don't pass any columns, it will stub all UPDATE queries.

func (*ExecStub) Args

func (s *ExecStub) Args(args ...driver.Value) *ExecStub

Args further filters this stub, matching based on the args passed to the query

func (*ExecStub) Dump

func (s *ExecStub) Dump() *ExecStub

Dump outputs debug information, without performing any matching.

func (*ExecStub) From

func (s *ExecStub) From(table string) *ExecStub

From further filters this stub, matching based on the FROM table specified.

func (*ExecStub) Into

func (s *ExecStub) Into(table string) *ExecStub

Into further filters this stub, matching based on the INTO table specified.

func (*ExecStub) Notify

func (s *ExecStub) Notify(ch chan<- struct{}) *ExecStub

Notify will have this stub send to the given channel when matched. You should put this as the last part of your stub chain.

func (*ExecStub) Priority

func (s *ExecStub) Priority(p int) *ExecStub

Priority adds the given priority to this stub, without performing any matching.

func (*ExecStub) Stub

func (s *ExecStub) Stub(res driver.Result)

Stub takes a driver.Result and registers this stub with the driver

func (*ExecStub) StubError

func (s *ExecStub) StubError(err error)

StubError takes an error and registers this stub with the driver

func (*ExecStub) StubResult

func (s *ExecStub) StubResult(lastInsertID, rowsAffected int64)

StubResult is an easy way to stub a driver.Result. Given a value of -1, the result will return an error for that particular part.

func (*ExecStub) StubRowsAffected

func (s *ExecStub) StubRowsAffected(rowsAffected int64)

StubRowsAffected is an easy way to stub a driver.Result when you only need to specify the rows affected.

func (*ExecStub) Table

func (s *ExecStub) Table(table string) *ExecStub

Table further filters this stub, matching the target table in INSERT, UPDATE, or DELETE.

func (*ExecStub) Value

func (s *ExecStub) Value(col string, v interface{}) *ExecStub

Value further filters this stub, matching based on values supplied to the query For INSERTs, it matches the first row of values, so it is a shortcut for ValueAt(0, ...) For UPDATEs, it matches on the SET clause.

func (*ExecStub) ValueAt

func (s *ExecStub) ValueAt(row int, col string, v interface{}) *ExecStub

ValueAt further filters this stub, matching based on values supplied to the query

func (*ExecStub) Where

func (s *ExecStub) Where(col string, v ...interface{}) *ExecStub

Where further filters this stub by values of input in the WHERE clause. You can pass multiple values for IN clause matching.

func (*ExecStub) WhereOp

func (s *ExecStub) WhereOp(col string, operator string, v ...interface{}) *ExecStub

WhereOp further filters this stub by values of input and the operator used in the WHERE clause.

type Stub

type Stub struct {
	// contains filtered or unexported fields
}

Stub is a SQL query stub (for SELECT)

func Select

func Select(cols ...string) *Stub

Select starts a new stub for SELECT statements. You can filter out which columns to use this stub for. If you don't pass any columns, it will stub all SELECT queries.

func (*Stub) Args

func (s *Stub) Args(args ...driver.Value) *Stub

Args further filters this stub, matching based on the args passed to the query

func (*Stub) Dump

func (s *Stub) Dump() *Stub

Dump outputs debug information, without performing any matching.

func (*Stub) From

func (s *Stub) From(tables ...string) *Stub

From further filters this stub by table names in the FROM and JOIN clauses (in order). You need to give it the un-aliased table names.

func (*Stub) Notify

func (s *Stub) Notify(ch chan<- struct{}) *Stub

Notify will have this stub send to the given channel when matched. You should put this as the last part of your stub chain.

func (*Stub) Priority

func (s *Stub) Priority(p int) *Stub

Priority adds the given priority to this stub, without performing any matching.

func (*Stub) Stub

func (s *Stub) Stub(rows [][]driver.Value)

Stub takes row data and registers this stub with the driver

func (*Stub) StubCSV

func (s *Stub) StubCSV(data string)

StubCSV takes CSV data and registers this stub with the driver

func (*Stub) StubError

func (s *Stub) StubError(err error)

StubError registers this stub to return the given error

func (*Stub) Subquery

func (s *Stub) Subquery() subquery

func (*Stub) Where

func (s *Stub) Where(col string, v ...interface{}) *Stub

Where further filters this stub by values of input in the WHERE clause. You can pass multiple values for IN clause matching.

func (*Stub) WhereOp

func (s *Stub) WhereOp(col string, operator string, v ...interface{}) *Stub

WhereOp further filters this stub by values of input and the operator used in the WHERE clause.

Directories

Path Synopsis
internal
proto/query
Package query is a generated protocol buffer package.
Package query is a generated protocol buffer package.
sqltypes
Package sqltypes implements interfaces and types that represent SQL values.
Package sqltypes implements interfaces and types that represent SQL values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL