Repository: Masterminds/squirrel
Branch: master
Commit: 1ded5784535d
Files: 48
Total size: 134.4 KB
Directory structure:
gitextract_422pidv7/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── case.go
├── case_test.go
├── delete.go
├── delete_ctx.go
├── delete_ctx_test.go
├── delete_test.go
├── expr.go
├── expr_test.go
├── go.mod
├── go.sum
├── insert.go
├── insert_ctx.go
├── insert_ctx_test.go
├── insert_test.go
├── integration/
│ ├── doc.go
│ ├── go.mod
│ ├── go.sum
│ └── integration_test.go
├── part.go
├── placeholder.go
├── placeholder_test.go
├── row.go
├── row_test.go
├── select.go
├── select_ctx.go
├── select_ctx_test.go
├── select_test.go
├── squirrel.go
├── squirrel_ctx.go
├── squirrel_ctx_test.go
├── squirrel_test.go
├── statement.go
├── statement_test.go
├── stmtcacher.go
├── stmtcacher_ctx.go
├── stmtcacher_ctx_test.go
├── stmtcacher_noctx.go
├── stmtcacher_test.go
├── update.go
├── update_ctx.go
├── update_ctx_test.go
├── update_test.go
├── where.go
└── where_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
squirrel.test
================================================
FILE: .travis.yml
================================================
language: go
go:
- 1.11.x
- 1.12.x
- 1.13.x
services:
- mysql
- postgresql
# Setting sudo access to false will let Travis CI use containers rather than
# VMs to run the tests. For more details see:
# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
sudo: false
before_script:
- mysql -e 'CREATE DATABASE squirrel;'
- psql -c 'CREATE DATABASE squirrel;' -U postgres
script:
- go test
- cd integration
- go test -args -driver sqlite3
- go test -args -driver mysql -dataSource travis@/squirrel
- go test -args -driver postgres -dataSource 'postgres://postgres@localhost/squirrel?sslmode=disable'
notifications:
irc: "irc.freenode.net#masterminds"
================================================
FILE: LICENSE
================================================
MIT License
Squirrel: The Masterminds
Copyright (c) 2014-2015, Lann Martin. Copyright (C) 2015-2016, Google. Copyright (C) 2015, Matt Farina and Matt Butcher.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[](https://masterminds.github.io/stability/maintenance.html)
### Squirrel is "complete".
Bug fixes will still be merged (slowly). Bug reports are welcome, but I will not necessarily respond to them. If another fork (or substantially similar project) actively improves on what Squirrel does, let me know and I may link to it here.
# Squirrel - fluent SQL generator for Go
```go
import "github.com/Masterminds/squirrel"
```
[](https://godoc.org/github.com/Masterminds/squirrel)
[](https://travis-ci.org/Masterminds/squirrel)
**Squirrel is not an ORM.** For an application of Squirrel, check out
[structable, a table-struct mapper](https://github.com/Masterminds/structable)
Squirrel helps you build SQL queries from composable parts:
```go
import sq "github.com/Masterminds/squirrel"
users := sq.Select("*").From("users").Join("emails USING (email_id)")
active := users.Where(sq.Eq{"deleted_at": nil})
sql, args, err := active.ToSql()
sql == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL"
```
```go
sql, args, err := sq.
Insert("users").Columns("name", "age").
Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)).
ToSql()
sql == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
```
Squirrel can also execute queries directly:
```go
stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}})
three_stooges := stooges.Limit(3)
rows, err := three_stooges.RunWith(db).Query()
// Behaves like:
rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3",
"moe", "larry", "curly", "shemp")
```
Squirrel makes conditional query building a breeze:
```go
if len(q) > 0 {
users = users.Where("name LIKE ?", fmt.Sprint("%", q, "%"))
}
```
Squirrel wants to make your life easier:
```go
// StmtCache caches Prepared Stmts for you
dbCache := sq.NewStmtCache(db)
// StatementBuilder keeps your syntax neat
mydb := sq.StatementBuilder.RunWith(dbCache)
select_users := mydb.Select("*").From("users")
```
Squirrel loves PostgreSQL:
```go
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
// You use question marks for placeholders...
sql, _, _ := psql.Select("*").From("elephants").Where("name IN (?,?)", "Dumbo", "Verna").ToSql()
/// ...squirrel replaces them using PlaceholderFormat.
sql == "SELECT * FROM elephants WHERE name IN ($1,$2)"
/// You can retrieve id ...
query := sq.Insert("nodes").
Columns("uuid", "type", "data").
Values(node.Uuid, node.Type, node.Data).
Suffix("RETURNING \"id\"").
RunWith(m.db).
PlaceholderFormat(sq.Dollar)
query.QueryRow().Scan(&node.id)
```
You can escape question marks by inserting two question marks:
```sql
SELECT * FROM nodes WHERE meta->'format' ??| array[?,?]
```
will generate with the Dollar Placeholder:
```sql
SELECT * FROM nodes WHERE meta->'format' ?| array[$1,$2]
```
## FAQ
* **How can I build an IN query on composite keys / tuples, e.g. `WHERE (col1, col2) IN ((1,2),(3,4))`? ([#104](https://github.com/Masterminds/squirrel/issues/104))**
Squirrel does not explicitly support tuples, but you can get the same effect with e.g.:
```go
sq.Or{
sq.Eq{"col1": 1, "col2": 2},
sq.Eq{"col1": 3, "col2": 4}}
```
```sql
WHERE (col1 = 1 AND col2 = 2) OR (col1 = 3 AND col2 = 4)
```
(which should produce the same query plan as the tuple version)
* **Why doesn't `Eq{"mynumber": []uint8{1,2,3}}` turn into an `IN` query? ([#114](https://github.com/Masterminds/squirrel/issues/114))**
Values of type `[]byte` are handled specially by `database/sql`. In Go, [`byte` is just an alias of `uint8`](https://golang.org/pkg/builtin/#byte), so there is no way to distinguish `[]uint8` from `[]byte`.
* **Some features are poorly documented!**
This isn't a frequent complaints section!
* **Some features are poorly documented?**
Yes. The tests should be considered a part of the documentation; take a look at those for ideas on how to express more complex queries.
## License
Squirrel is released under the
[MIT License](http://www.opensource.org/licenses/MIT).
================================================
FILE: case.go
================================================
package squirrel
import (
"bytes"
"errors"
"github.com/lann/builder"
)
func init() {
builder.Register(CaseBuilder{}, caseData{})
}
// sqlizerBuffer is a helper that allows to write many Sqlizers one by one
// without constant checks for errors that may come from Sqlizer
type sqlizerBuffer struct {
bytes.Buffer
args []interface{}
err error
}
// WriteSql converts Sqlizer to SQL strings and writes it to buffer
func (b *sqlizerBuffer) WriteSql(item Sqlizer) {
if b.err != nil {
return
}
var str string
var args []interface{}
str, args, b.err = nestedToSql(item)
if b.err != nil {
return
}
b.WriteString(str)
b.WriteByte(' ')
b.args = append(b.args, args...)
}
func (b *sqlizerBuffer) ToSql() (string, []interface{}, error) {
return b.String(), b.args, b.err
}
// whenPart is a helper structure to describe SQLs "WHEN ... THEN ..." expression
type whenPart struct {
when Sqlizer
then Sqlizer
}
func newWhenPart(when interface{}, then interface{}) whenPart {
return whenPart{newPart(when), newPart(then)}
}
// caseData holds all the data required to build a CASE SQL construct
type caseData struct {
What Sqlizer
WhenParts []whenPart
Else Sqlizer
}
// ToSql implements Sqlizer
func (d *caseData) ToSql() (sqlStr string, args []interface{}, err error) {
if len(d.WhenParts) == 0 {
err = errors.New("case expression must contain at lease one WHEN clause")
return
}
sql := sqlizerBuffer{}
sql.WriteString("CASE ")
if d.What != nil {
sql.WriteSql(d.What)
}
for _, p := range d.WhenParts {
sql.WriteString("WHEN ")
sql.WriteSql(p.when)
sql.WriteString("THEN ")
sql.WriteSql(p.then)
}
if d.Else != nil {
sql.WriteString("ELSE ")
sql.WriteSql(d.Else)
}
sql.WriteString("END")
return sql.ToSql()
}
// CaseBuilder builds SQL CASE construct which could be used as parts of queries.
type CaseBuilder builder.Builder
// ToSql builds the query into a SQL string and bound args.
func (b CaseBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(caseData)
return data.ToSql()
}
// MustSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b CaseBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
if err != nil {
panic(err)
}
return sql, args
}
// what sets optional value for CASE construct "CASE [value] ..."
func (b CaseBuilder) what(expr interface{}) CaseBuilder {
return builder.Set(b, "What", newPart(expr)).(CaseBuilder)
}
// When adds "WHEN ... THEN ..." part to CASE construct
func (b CaseBuilder) When(when interface{}, then interface{}) CaseBuilder {
// TODO: performance hint: replace slice of WhenPart with just slice of parts
// where even indices of the slice belong to "when"s and odd indices belong to "then"s
return builder.Append(b, "WhenParts", newWhenPart(when, then)).(CaseBuilder)
}
// What sets optional "ELSE ..." part for CASE construct
func (b CaseBuilder) Else(expr interface{}) CaseBuilder {
return builder.Set(b, "Else", newPart(expr)).(CaseBuilder)
}
================================================
FILE: case_test.go
================================================
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCaseWithVal(t *testing.T) {
caseStmt := Case("number").
When("1", "one").
When("2", "two").
Else(Expr("?", "big number"))
qb := Select().
Column(caseStmt).
From("table")
sql, args, err := qb.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT CASE number " +
"WHEN 1 THEN one " +
"WHEN 2 THEN two " +
"ELSE ? " +
"END " +
"FROM table"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"big number"}
assert.Equal(t, expectedArgs, args)
}
func TestCaseWithComplexVal(t *testing.T) {
caseStmt := Case("? > ?", 10, 5).
When("true", "'T'")
qb := Select().
Column(Alias(caseStmt, "complexCase")).
From("table")
sql, args, err := qb.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT (CASE ? > ? " +
"WHEN true THEN 'T' " +
"END) AS complexCase " +
"FROM table"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{10, 5}
assert.Equal(t, expectedArgs, args)
}
func TestCaseWithNoVal(t *testing.T) {
caseStmt := Case().
When(Eq{"x": 0}, "x is zero").
When(Expr("x > ?", 1), Expr("CONCAT('x is greater than ', ?)", 2))
qb := Select().Column(caseStmt).From("table")
sql, args, err := qb.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT CASE " +
"WHEN x = ? THEN x is zero " +
"WHEN x > ? THEN CONCAT('x is greater than ', ?) " +
"END " +
"FROM table"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{0, 1, 2}
assert.Equal(t, expectedArgs, args)
}
func TestCaseWithExpr(t *testing.T) {
caseStmt := Case(Expr("x = ?", true)).
When("true", Expr("?", "it's true!")).
Else("42")
qb := Select().Column(caseStmt).From("table")
sql, args, err := qb.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT CASE x = ? " +
"WHEN true THEN ? " +
"ELSE 42 " +
"END " +
"FROM table"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{true, "it's true!"}
assert.Equal(t, expectedArgs, args)
}
func TestMultipleCase(t *testing.T) {
caseStmtNoval := Case(Expr("x = ?", true)).
When("true", Expr("?", "it's true!")).
Else("42")
caseStmtExpr := Case().
When(Eq{"x": 0}, "'x is zero'").
When(Expr("x > ?", 1), Expr("CONCAT('x is greater than ', ?)", 2))
qb := Select().
Column(Alias(caseStmtNoval, "case_noval")).
Column(Alias(caseStmtExpr, "case_expr")).
From("table")
sql, args, err := qb.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT " +
"(CASE x = ? WHEN true THEN ? ELSE 42 END) AS case_noval, " +
"(CASE WHEN x = ? THEN 'x is zero' WHEN x > ? THEN CONCAT('x is greater than ', ?) END) AS case_expr " +
"FROM table"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{
true, "it's true!",
0, 1, 2,
}
assert.Equal(t, expectedArgs, args)
}
func TestCaseWithNoWhenClause(t *testing.T) {
caseStmt := Case("something").
Else("42")
qb := Select().Column(caseStmt).From("table")
_, _, err := qb.ToSql()
assert.Error(t, err)
assert.Equal(t, "case expression must contain at lease one WHEN clause", err.Error())
}
func TestCaseBuilderMustSql(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("TestCaseBuilderMustSql should have panicked!")
}
}()
Case("").MustSql()
}
================================================
FILE: delete.go
================================================
package squirrel
import (
"bytes"
"database/sql"
"fmt"
"strings"
"github.com/lann/builder"
)
type deleteData struct {
PlaceholderFormat PlaceholderFormat
RunWith BaseRunner
Prefixes []Sqlizer
From string
WhereParts []Sqlizer
OrderBys []string
Limit string
Offset string
Suffixes []Sqlizer
}
func (d *deleteData) Exec() (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return ExecWith(d.RunWith, d)
}
func (d *deleteData) ToSql() (sqlStr string, args []interface{}, err error) {
if len(d.From) == 0 {
err = fmt.Errorf("delete statements must specify a From table")
return
}
sql := &bytes.Buffer{}
if len(d.Prefixes) > 0 {
args, err = appendToSql(d.Prefixes, sql, " ", args)
if err != nil {
return
}
sql.WriteString(" ")
}
sql.WriteString("DELETE FROM ")
sql.WriteString(d.From)
if len(d.WhereParts) > 0 {
sql.WriteString(" WHERE ")
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
if err != nil {
return
}
}
if len(d.OrderBys) > 0 {
sql.WriteString(" ORDER BY ")
sql.WriteString(strings.Join(d.OrderBys, ", "))
}
if len(d.Limit) > 0 {
sql.WriteString(" LIMIT ")
sql.WriteString(d.Limit)
}
if len(d.Offset) > 0 {
sql.WriteString(" OFFSET ")
sql.WriteString(d.Offset)
}
if len(d.Suffixes) > 0 {
sql.WriteString(" ")
args, err = appendToSql(d.Suffixes, sql, " ", args)
if err != nil {
return
}
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
return
}
// Builder
// DeleteBuilder builds SQL DELETE statements.
type DeleteBuilder builder.Builder
func init() {
builder.Register(DeleteBuilder{}, deleteData{})
}
// Format methods
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
// query.
func (b DeleteBuilder) PlaceholderFormat(f PlaceholderFormat) DeleteBuilder {
return builder.Set(b, "PlaceholderFormat", f).(DeleteBuilder)
}
// Runner methods
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
func (b DeleteBuilder) RunWith(runner BaseRunner) DeleteBuilder {
return setRunWith(b, runner).(DeleteBuilder)
}
// Exec builds and Execs the query with the Runner set by RunWith.
func (b DeleteBuilder) Exec() (sql.Result, error) {
data := builder.GetStruct(b).(deleteData)
return data.Exec()
}
// SQL methods
// ToSql builds the query into a SQL string and bound args.
func (b DeleteBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(deleteData)
return data.ToSql()
}
// MustSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b DeleteBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
if err != nil {
panic(err)
}
return sql, args
}
// Prefix adds an expression to the beginning of the query
func (b DeleteBuilder) Prefix(sql string, args ...interface{}) DeleteBuilder {
return b.PrefixExpr(Expr(sql, args...))
}
// PrefixExpr adds an expression to the very beginning of the query
func (b DeleteBuilder) PrefixExpr(expr Sqlizer) DeleteBuilder {
return builder.Append(b, "Prefixes", expr).(DeleteBuilder)
}
// From sets the table to be deleted from.
func (b DeleteBuilder) From(from string) DeleteBuilder {
return builder.Set(b, "From", from).(DeleteBuilder)
}
// Where adds WHERE expressions to the query.
//
// See SelectBuilder.Where for more information.
func (b DeleteBuilder) Where(pred interface{}, args ...interface{}) DeleteBuilder {
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(DeleteBuilder)
}
// OrderBy adds ORDER BY expressions to the query.
func (b DeleteBuilder) OrderBy(orderBys ...string) DeleteBuilder {
return builder.Extend(b, "OrderBys", orderBys).(DeleteBuilder)
}
// Limit sets a LIMIT clause on the query.
func (b DeleteBuilder) Limit(limit uint64) DeleteBuilder {
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(DeleteBuilder)
}
// Offset sets a OFFSET clause on the query.
func (b DeleteBuilder) Offset(offset uint64) DeleteBuilder {
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(DeleteBuilder)
}
// Suffix adds an expression to the end of the query
func (b DeleteBuilder) Suffix(sql string, args ...interface{}) DeleteBuilder {
return b.SuffixExpr(Expr(sql, args...))
}
// SuffixExpr adds an expression to the end of the query
func (b DeleteBuilder) SuffixExpr(expr Sqlizer) DeleteBuilder {
return builder.Append(b, "Suffixes", expr).(DeleteBuilder)
}
func (b DeleteBuilder) Query() (*sql.Rows, error) {
data := builder.GetStruct(b).(deleteData)
return data.Query()
}
func (d *deleteData) Query() (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return QueryWith(d.RunWith, d)
}
================================================
FILE: delete_ctx.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
"github.com/lann/builder"
)
func (d *deleteData) ExecContext(ctx context.Context) (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(ExecerContext)
if !ok {
return nil, NoContextSupport
}
return ExecContextWith(ctx, ctxRunner, d)
}
func (d *deleteData) QueryContext(ctx context.Context) (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(QueryerContext)
if !ok {
return nil, NoContextSupport
}
return QueryContextWith(ctx, ctxRunner, d)
}
func (d *deleteData) QueryRowContext(ctx context.Context) RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRowerContext)
if !ok {
if _, ok := d.RunWith.(QueryerContext); !ok {
return &Row{err: RunnerNotQueryRunner}
}
return &Row{err: NoContextSupport}
}
return QueryRowContextWith(ctx, queryRower, d)
}
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
func (b DeleteBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
data := builder.GetStruct(b).(deleteData)
return data.ExecContext(ctx)
}
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
func (b DeleteBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
data := builder.GetStruct(b).(deleteData)
return data.QueryContext(ctx)
}
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
func (b DeleteBuilder) QueryRowContext(ctx context.Context) RowScanner {
data := builder.GetStruct(b).(deleteData)
return data.QueryRowContext(ctx)
}
// ScanContext is a shortcut for QueryRowContext().Scan.
func (b DeleteBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
return b.QueryRowContext(ctx).Scan(dest...)
}
================================================
FILE: delete_ctx_test.go
================================================
// +build go1.8
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDeleteBuilderContextRunners(t *testing.T) {
db := &DBStub{}
b := Delete("test").Where("x = ?", 1).RunWith(db)
expectedSql := "DELETE FROM test WHERE x = ?"
b.ExecContext(ctx)
assert.Equal(t, expectedSql, db.LastExecSql)
b.QueryContext(ctx)
assert.Equal(t, expectedSql, db.LastQuerySql)
b.QueryRowContext(ctx)
assert.Equal(t, expectedSql, db.LastQueryRowSql)
err := b.ScanContext(ctx)
assert.NoError(t, err)
}
func TestDeleteBuilderContextNoRunner(t *testing.T) {
b := Delete("test").Where("x != ?", 0).Suffix("RETURNING x")
_, err := b.ExecContext(ctx)
assert.Equal(t, RunnerNotSet, err)
_, err = b.QueryContext(ctx)
assert.Equal(t, RunnerNotSet, err)
err = b.ScanContext(ctx)
assert.Equal(t, RunnerNotSet, err)
}
================================================
FILE: delete_test.go
================================================
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDeleteBuilderToSql(t *testing.T) {
b := Delete("").
Prefix("WITH prefix AS ?", 0).
From("a").
Where("b = ?", 1).
OrderBy("c").
Limit(2).
Offset(3).
Suffix("RETURNING ?", 4)
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql :=
"WITH prefix AS ? " +
"DELETE FROM a WHERE b = ? ORDER BY c LIMIT 2 OFFSET 3 " +
"RETURNING ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{0, 1, 4}
assert.Equal(t, expectedArgs, args)
}
func TestDeleteBuilderToSqlErr(t *testing.T) {
_, _, err := Delete("").ToSql()
assert.Error(t, err)
}
func TestDeleteBuilderMustSql(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("TestDeleteBuilderMustSql should have panicked!")
}
}()
Delete("").MustSql()
}
func TestDeleteBuilderPlaceholders(t *testing.T) {
b := Delete("test").Where("x = ? AND y = ?", 1, 2)
sql, _, _ := b.PlaceholderFormat(Question).ToSql()
assert.Equal(t, "DELETE FROM test WHERE x = ? AND y = ?", sql)
sql, _, _ = b.PlaceholderFormat(Dollar).ToSql()
assert.Equal(t, "DELETE FROM test WHERE x = $1 AND y = $2", sql)
}
func TestDeleteBuilderRunners(t *testing.T) {
db := &DBStub{}
b := Delete("test").Where("x = ?", 1).RunWith(db)
expectedSql := "DELETE FROM test WHERE x = ?"
b.Exec()
assert.Equal(t, expectedSql, db.LastExecSql)
}
func TestDeleteBuilderNoRunner(t *testing.T) {
b := Delete("test")
_, err := b.Exec()
assert.Equal(t, RunnerNotSet, err)
}
func TestDeleteWithQuery(t *testing.T) {
db := &DBStub{}
b := Delete("test").Where("id=55").Suffix("RETURNING path").RunWith(db)
expectedSql := "DELETE FROM test WHERE id=55 RETURNING path"
b.Query()
assert.Equal(t, expectedSql, db.LastQuerySql)
}
================================================
FILE: expr.go
================================================
package squirrel
import (
"bytes"
"database/sql/driver"
"fmt"
"reflect"
"sort"
"strings"
)
const (
// Portable true/false literals.
sqlTrue = "(1=1)"
sqlFalse = "(1=0)"
)
type expr struct {
sql string
args []interface{}
}
// Expr builds an expression from a SQL fragment and arguments.
//
// Ex:
// Expr("FROM_UNIXTIME(?)", t)
func Expr(sql string, args ...interface{}) Sqlizer {
return expr{sql: sql, args: args}
}
func (e expr) ToSql() (sql string, args []interface{}, err error) {
simple := true
for _, arg := range e.args {
if _, ok := arg.(Sqlizer); ok {
simple = false
}
}
if simple {
return e.sql, e.args, nil
}
buf := &bytes.Buffer{}
ap := e.args
sp := e.sql
var isql string
var iargs []interface{}
for err == nil && len(ap) > 0 && len(sp) > 0 {
i := strings.Index(sp, "?")
if i < 0 {
// no more placeholders
break
}
if len(sp) > i+1 && sp[i+1:i+2] == "?" {
// escaped "??"; append it and step past
buf.WriteString(sp[:i+2])
sp = sp[i+2:]
continue
}
if as, ok := ap[0].(Sqlizer); ok {
// sqlizer argument; expand it and append the result
isql, iargs, err = as.ToSql()
buf.WriteString(sp[:i])
buf.WriteString(isql)
args = append(args, iargs...)
} else {
// normal argument; append it and the placeholder
buf.WriteString(sp[:i+1])
args = append(args, ap[0])
}
// step past the argument and placeholder
ap = ap[1:]
sp = sp[i+1:]
}
// append the remaining sql and arguments
buf.WriteString(sp)
return buf.String(), append(args, ap...), err
}
type concatExpr []interface{}
func (ce concatExpr) ToSql() (sql string, args []interface{}, err error) {
for _, part := range ce {
switch p := part.(type) {
case string:
sql += p
case Sqlizer:
pSql, pArgs, err := p.ToSql()
if err != nil {
return "", nil, err
}
sql += pSql
args = append(args, pArgs...)
default:
return "", nil, fmt.Errorf("%#v is not a string or Sqlizer", part)
}
}
return
}
// ConcatExpr builds an expression by concatenating strings and other expressions.
//
// Ex:
// name_expr := Expr("CONCAT(?, ' ', ?)", firstName, lastName)
// ConcatExpr("COALESCE(full_name,", name_expr, ")")
func ConcatExpr(parts ...interface{}) concatExpr {
return concatExpr(parts)
}
// aliasExpr helps to alias part of SQL query generated with underlying "expr"
type aliasExpr struct {
expr Sqlizer
alias string
}
// Alias allows to define alias for column in SelectBuilder. Useful when column is
// defined as complex expression like IF or CASE
// Ex:
// .Column(Alias(caseStmt, "case_column"))
func Alias(expr Sqlizer, alias string) aliasExpr {
return aliasExpr{expr, alias}
}
func (e aliasExpr) ToSql() (sql string, args []interface{}, err error) {
sql, args, err = e.expr.ToSql()
if err == nil {
sql = fmt.Sprintf("(%s) AS %s", sql, e.alias)
}
return
}
// Eq is syntactic sugar for use with Where/Having/Set methods.
type Eq map[string]interface{}
func (eq Eq) toSQL(useNotOpr bool) (sql string, args []interface{}, err error) {
if len(eq) == 0 {
// Empty Sql{} evaluates to true.
sql = sqlTrue
return
}
var (
exprs []string
equalOpr = "="
inOpr = "IN"
nullOpr = "IS"
inEmptyExpr = sqlFalse
)
if useNotOpr {
equalOpr = "<>"
inOpr = "NOT IN"
nullOpr = "IS NOT"
inEmptyExpr = sqlTrue
}
sortedKeys := getSortedKeys(eq)
for _, key := range sortedKeys {
var expr string
val := eq[key]
switch v := val.(type) {
case driver.Valuer:
if val, err = v.Value(); err != nil {
return
}
}
r := reflect.ValueOf(val)
if r.Kind() == reflect.Ptr {
if r.IsNil() {
val = nil
} else {
val = r.Elem().Interface()
}
}
if val == nil {
expr = fmt.Sprintf("%s %s NULL", key, nullOpr)
} else {
if isListType(val) {
valVal := reflect.ValueOf(val)
if valVal.Len() == 0 {
expr = inEmptyExpr
if args == nil {
args = []interface{}{}
}
} else {
for i := 0; i < valVal.Len(); i++ {
args = append(args, valVal.Index(i).Interface())
}
expr = fmt.Sprintf("%s %s (%s)", key, inOpr, Placeholders(valVal.Len()))
}
} else {
expr = fmt.Sprintf("%s %s ?", key, equalOpr)
args = append(args, val)
}
}
exprs = append(exprs, expr)
}
sql = strings.Join(exprs, " AND ")
return
}
func (eq Eq) ToSql() (sql string, args []interface{}, err error) {
return eq.toSQL(false)
}
// NotEq is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(NotEq{"id": 1}) == "id <> 1"
type NotEq Eq
func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {
return Eq(neq).toSQL(true)
}
// Like is syntactic sugar for use with LIKE conditions.
// Ex:
// .Where(Like{"name": "%irrel"})
type Like map[string]interface{}
func (lk Like) toSql(opr string) (sql string, args []interface{}, err error) {
var exprs []string
for key, val := range lk {
expr := ""
switch v := val.(type) {
case driver.Valuer:
if val, err = v.Value(); err != nil {
return
}
}
if val == nil {
err = fmt.Errorf("cannot use null with like operators")
return
} else {
if isListType(val) {
err = fmt.Errorf("cannot use array or slice with like operators")
return
} else {
expr = fmt.Sprintf("%s %s ?", key, opr)
args = append(args, val)
}
}
exprs = append(exprs, expr)
}
sql = strings.Join(exprs, " AND ")
return
}
func (lk Like) ToSql() (sql string, args []interface{}, err error) {
return lk.toSql("LIKE")
}
// NotLike is syntactic sugar for use with LIKE conditions.
// Ex:
// .Where(NotLike{"name": "%irrel"})
type NotLike Like
func (nlk NotLike) ToSql() (sql string, args []interface{}, err error) {
return Like(nlk).toSql("NOT LIKE")
}
// ILike is syntactic sugar for use with ILIKE conditions.
// Ex:
// .Where(ILike{"name": "sq%"})
type ILike Like
func (ilk ILike) ToSql() (sql string, args []interface{}, err error) {
return Like(ilk).toSql("ILIKE")
}
// NotILike is syntactic sugar for use with ILIKE conditions.
// Ex:
// .Where(NotILike{"name": "sq%"})
type NotILike Like
func (nilk NotILike) ToSql() (sql string, args []interface{}, err error) {
return Like(nilk).toSql("NOT ILIKE")
}
// Lt is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(Lt{"id": 1})
type Lt map[string]interface{}
func (lt Lt) toSql(opposite, orEq bool) (sql string, args []interface{}, err error) {
var (
exprs []string
opr = "<"
)
if opposite {
opr = ">"
}
if orEq {
opr = fmt.Sprintf("%s%s", opr, "=")
}
sortedKeys := getSortedKeys(lt)
for _, key := range sortedKeys {
var expr string
val := lt[key]
switch v := val.(type) {
case driver.Valuer:
if val, err = v.Value(); err != nil {
return
}
}
if val == nil {
err = fmt.Errorf("cannot use null with less than or greater than operators")
return
}
if isListType(val) {
err = fmt.Errorf("cannot use array or slice with less than or greater than operators")
return
}
expr = fmt.Sprintf("%s %s ?", key, opr)
args = append(args, val)
exprs = append(exprs, expr)
}
sql = strings.Join(exprs, " AND ")
return
}
func (lt Lt) ToSql() (sql string, args []interface{}, err error) {
return lt.toSql(false, false)
}
// LtOrEq is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(LtOrEq{"id": 1}) == "id <= 1"
type LtOrEq Lt
func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err error) {
return Lt(ltOrEq).toSql(false, true)
}
// Gt is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(Gt{"id": 1}) == "id > 1"
type Gt Lt
func (gt Gt) ToSql() (sql string, args []interface{}, err error) {
return Lt(gt).toSql(true, false)
}
// GtOrEq is syntactic sugar for use with Where/Having/Set methods.
// Ex:
// .Where(GtOrEq{"id": 1}) == "id >= 1"
type GtOrEq Lt
func (gtOrEq GtOrEq) ToSql() (sql string, args []interface{}, err error) {
return Lt(gtOrEq).toSql(true, true)
}
type conj []Sqlizer
func (c conj) join(sep, defaultExpr string) (sql string, args []interface{}, err error) {
if len(c) == 0 {
return defaultExpr, []interface{}{}, nil
}
var sqlParts []string
for _, sqlizer := range c {
partSQL, partArgs, err := nestedToSql(sqlizer)
if err != nil {
return "", nil, err
}
if partSQL != "" {
sqlParts = append(sqlParts, partSQL)
args = append(args, partArgs...)
}
}
if len(sqlParts) > 0 {
sql = fmt.Sprintf("(%s)", strings.Join(sqlParts, sep))
}
return
}
// And conjunction Sqlizers
type And conj
func (a And) ToSql() (string, []interface{}, error) {
return conj(a).join(" AND ", sqlTrue)
}
// Or conjunction Sqlizers
type Or conj
func (o Or) ToSql() (string, []interface{}, error) {
return conj(o).join(" OR ", sqlFalse)
}
func getSortedKeys(exp map[string]interface{}) []string {
sortedKeys := make([]string, 0, len(exp))
for k := range exp {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
return sortedKeys
}
func isListType(val interface{}) bool {
if driver.IsValue(val) {
return false
}
valVal := reflect.ValueOf(val)
return valVal.Kind() == reflect.Array || valVal.Kind() == reflect.Slice
}
================================================
FILE: expr_test.go
================================================
package squirrel
import (
"database/sql"
"testing"
"github.com/stretchr/testify/assert"
)
func TestConcatExpr(t *testing.T) {
b := ConcatExpr("COALESCE(name,", Expr("CONCAT(?,' ',?)", "f", "l"), ")")
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "COALESCE(name,CONCAT(?,' ',?))"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"f", "l"}
assert.Equal(t, expectedArgs, args)
}
func TestConcatExprBadType(t *testing.T) {
b := ConcatExpr("prefix", 123, "suffix")
_, _, err := b.ToSql()
assert.Error(t, err)
assert.Contains(t, err.Error(), "123 is not")
}
func TestEqToSql(t *testing.T) {
b := Eq{"id": 1}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id = ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestEqEmptyToSql(t *testing.T) {
sql, args, err := Eq{}.ToSql()
assert.NoError(t, err)
expectedSql := "(1=1)"
assert.Equal(t, expectedSql, sql)
assert.Empty(t, args)
}
func TestEqInToSql(t *testing.T) {
b := Eq{"id": []int{1, 2, 3}}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id IN (?,?,?)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, 2, 3}
assert.Equal(t, expectedArgs, args)
}
func TestNotEqToSql(t *testing.T) {
b := NotEq{"id": 1}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id <> ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestEqNotInToSql(t *testing.T) {
b := NotEq{"id": []int{1, 2, 3}}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id NOT IN (?,?,?)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, 2, 3}
assert.Equal(t, expectedArgs, args)
}
func TestEqInEmptyToSql(t *testing.T) {
b := Eq{"id": []int{}}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "(1=0)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{}
assert.Equal(t, expectedArgs, args)
}
func TestNotEqInEmptyToSql(t *testing.T) {
b := NotEq{"id": []int{}}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "(1=1)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{}
assert.Equal(t, expectedArgs, args)
}
func TestEqBytesToSql(t *testing.T) {
b := Eq{"id": []byte("test")}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id = ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{[]byte("test")}
assert.Equal(t, expectedArgs, args)
}
func TestLtToSql(t *testing.T) {
b := Lt{"id": 1}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id < ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestLtOrEqToSql(t *testing.T) {
b := LtOrEq{"id": 1}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id <= ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestGtToSql(t *testing.T) {
b := Gt{"id": 1}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id > ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestGtOrEqToSql(t *testing.T) {
b := GtOrEq{"id": 1}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "id >= ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestExprNilToSql(t *testing.T) {
var b Sqlizer
b = NotEq{"name": nil}
sql, args, err := b.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
expectedSql := "name IS NOT NULL"
assert.Equal(t, expectedSql, sql)
b = Eq{"name": nil}
sql, args, err = b.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
expectedSql = "name IS NULL"
assert.Equal(t, expectedSql, sql)
}
func TestNullTypeString(t *testing.T) {
var b Sqlizer
var name sql.NullString
b = Eq{"name": name}
sql, args, err := b.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "name IS NULL", sql)
name.Scan("Name")
b = Eq{"name": name}
sql, args, err = b.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{"Name"}, args)
assert.Equal(t, "name = ?", sql)
}
func TestNullTypeInt64(t *testing.T) {
var userID sql.NullInt64
userID.Scan(nil)
b := Eq{"user_id": userID}
sql, args, err := b.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "user_id IS NULL", sql)
userID.Scan(int64(10))
b = Eq{"user_id": userID}
sql, args, err = b.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{int64(10)}, args)
assert.Equal(t, "user_id = ?", sql)
}
func TestNilPointer(t *testing.T) {
var name *string = nil
eq := Eq{"name": name}
sql, args, err := eq.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "name IS NULL", sql)
neq := NotEq{"name": name}
sql, args, err = neq.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "name IS NOT NULL", sql)
var ids *[]int = nil
eq = Eq{"id": ids}
sql, args, err = eq.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "id IS NULL", sql)
neq = NotEq{"id": ids}
sql, args, err = neq.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "id IS NOT NULL", sql)
var ida *[3]int = nil
eq = Eq{"id": ida}
sql, args, err = eq.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "id IS NULL", sql)
neq = NotEq{"id": ida}
sql, args, err = neq.ToSql()
assert.NoError(t, err)
assert.Empty(t, args)
assert.Equal(t, "id IS NOT NULL", sql)
}
func TestNotNilPointer(t *testing.T) {
c := "Name"
name := &c
eq := Eq{"name": name}
sql, args, err := eq.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{"Name"}, args)
assert.Equal(t, "name = ?", sql)
neq := NotEq{"name": name}
sql, args, err = neq.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{"Name"}, args)
assert.Equal(t, "name <> ?", sql)
s := []int{1, 2, 3}
ids := &s
eq = Eq{"id": ids}
sql, args, err = eq.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{1, 2, 3}, args)
assert.Equal(t, "id IN (?,?,?)", sql)
neq = NotEq{"id": ids}
sql, args, err = neq.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{1, 2, 3}, args)
assert.Equal(t, "id NOT IN (?,?,?)", sql)
a := [3]int{1, 2, 3}
ida := &a
eq = Eq{"id": ida}
sql, args, err = eq.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{1, 2, 3}, args)
assert.Equal(t, "id IN (?,?,?)", sql)
neq = NotEq{"id": ida}
sql, args, err = neq.ToSql()
assert.NoError(t, err)
assert.Equal(t, []interface{}{1, 2, 3}, args)
assert.Equal(t, "id NOT IN (?,?,?)", sql)
}
func TestEmptyAndToSql(t *testing.T) {
sql, args, err := And{}.ToSql()
assert.NoError(t, err)
expectedSql := "(1=1)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{}
assert.Equal(t, expectedArgs, args)
}
func TestEmptyOrToSql(t *testing.T) {
sql, args, err := Or{}.ToSql()
assert.NoError(t, err)
expectedSql := "(1=0)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{}
assert.Equal(t, expectedArgs, args)
}
func TestLikeToSql(t *testing.T) {
b := Like{"name": "%irrel"}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "name LIKE ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"%irrel"}
assert.Equal(t, expectedArgs, args)
}
func TestNotLikeToSql(t *testing.T) {
b := NotLike{"name": "%irrel"}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "name NOT LIKE ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"%irrel"}
assert.Equal(t, expectedArgs, args)
}
func TestILikeToSql(t *testing.T) {
b := ILike{"name": "sq%"}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "name ILIKE ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"sq%"}
assert.Equal(t, expectedArgs, args)
}
func TestNotILikeToSql(t *testing.T) {
b := NotILike{"name": "sq%"}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "name NOT ILIKE ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"sq%"}
assert.Equal(t, expectedArgs, args)
}
func TestSqlEqOrder(t *testing.T) {
b := Eq{"a": 1, "b": 2, "c": 3}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "a = ? AND b = ? AND c = ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, 2, 3}
assert.Equal(t, expectedArgs, args)
}
func TestSqlLtOrder(t *testing.T) {
b := Lt{"a": 1, "b": 2, "c": 3}
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "a < ? AND b < ? AND c < ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, 2, 3}
assert.Equal(t, expectedArgs, args)
}
func TestExprEscaped(t *testing.T) {
b := Expr("count(??)", Expr("x"))
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "count(??)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{Expr("x")}
assert.Equal(t, expectedArgs, args)
}
func TestExprRecursion(t *testing.T) {
{
b := Expr("count(?)", Expr("nullif(a,?)", "b"))
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "count(nullif(a,?))"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"b"}
assert.Equal(t, expectedArgs, args)
}
{
b := Expr("extract(? from ?)", Expr("epoch"), "2001-02-03")
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "extract(epoch from ?)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{"2001-02-03"}
assert.Equal(t, expectedArgs, args)
}
{
b := Expr("JOIN t1 ON ?", And{Eq{"id": 1}, Expr("NOT c1"), Expr("? @@ ?", "x", "y")})
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "JOIN t1 ON (id = ? AND NOT c1 AND ? @@ ?)"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, "x", "y"}
assert.Equal(t, expectedArgs, args)
}
}
func ExampleEq() {
Select("id", "created", "first_name").From("users").Where(Eq{
"company": 20,
})
}
================================================
FILE: go.mod
================================================
module github.com/Masterminds/squirrel
go 1.14
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)
================================================
FILE: go.sum
================================================
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
================================================
FILE: insert.go
================================================
package squirrel
import (
"bytes"
"database/sql"
"errors"
"fmt"
"io"
"sort"
"strings"
"github.com/lann/builder"
)
type insertData struct {
PlaceholderFormat PlaceholderFormat
RunWith BaseRunner
Prefixes []Sqlizer
StatementKeyword string
Options []string
Into string
Columns []string
Values [][]interface{}
Suffixes []Sqlizer
Select *SelectBuilder
}
func (d *insertData) Exec() (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return ExecWith(d.RunWith, d)
}
func (d *insertData) Query() (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return QueryWith(d.RunWith, d)
}
func (d *insertData) QueryRow() RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRower)
if !ok {
return &Row{err: RunnerNotQueryRunner}
}
return QueryRowWith(queryRower, d)
}
func (d *insertData) ToSql() (sqlStr string, args []interface{}, err error) {
if len(d.Into) == 0 {
err = errors.New("insert statements must specify a table")
return
}
if len(d.Values) == 0 && d.Select == nil {
err = errors.New("insert statements must have at least one set of values or select clause")
return
}
sql := &bytes.Buffer{}
if len(d.Prefixes) > 0 {
args, err = appendToSql(d.Prefixes, sql, " ", args)
if err != nil {
return
}
sql.WriteString(" ")
}
if d.StatementKeyword == "" {
sql.WriteString("INSERT ")
} else {
sql.WriteString(d.StatementKeyword)
sql.WriteString(" ")
}
if len(d.Options) > 0 {
sql.WriteString(strings.Join(d.Options, " "))
sql.WriteString(" ")
}
sql.WriteString("INTO ")
sql.WriteString(d.Into)
sql.WriteString(" ")
if len(d.Columns) > 0 {
sql.WriteString("(")
sql.WriteString(strings.Join(d.Columns, ","))
sql.WriteString(") ")
}
if d.Select != nil {
args, err = d.appendSelectToSQL(sql, args)
} else {
args, err = d.appendValuesToSQL(sql, args)
}
if err != nil {
return
}
if len(d.Suffixes) > 0 {
sql.WriteString(" ")
args, err = appendToSql(d.Suffixes, sql, " ", args)
if err != nil {
return
}
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
return
}
func (d *insertData) appendValuesToSQL(w io.Writer, args []interface{}) ([]interface{}, error) {
if len(d.Values) == 0 {
return args, errors.New("values for insert statements are not set")
}
io.WriteString(w, "VALUES ")
valuesStrings := make([]string, len(d.Values))
for r, row := range d.Values {
valueStrings := make([]string, len(row))
for v, val := range row {
if vs, ok := val.(Sqlizer); ok {
vsql, vargs, err := vs.ToSql()
if err != nil {
return nil, err
}
valueStrings[v] = vsql
args = append(args, vargs...)
} else {
valueStrings[v] = "?"
args = append(args, val)
}
}
valuesStrings[r] = fmt.Sprintf("(%s)", strings.Join(valueStrings, ","))
}
io.WriteString(w, strings.Join(valuesStrings, ","))
return args, nil
}
func (d *insertData) appendSelectToSQL(w io.Writer, args []interface{}) ([]interface{}, error) {
if d.Select == nil {
return args, errors.New("select clause for insert statements are not set")
}
selectClause, sArgs, err := d.Select.ToSql()
if err != nil {
return args, err
}
io.WriteString(w, selectClause)
args = append(args, sArgs...)
return args, nil
}
// Builder
// InsertBuilder builds SQL INSERT statements.
type InsertBuilder builder.Builder
func init() {
builder.Register(InsertBuilder{}, insertData{})
}
// Format methods
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
// query.
func (b InsertBuilder) PlaceholderFormat(f PlaceholderFormat) InsertBuilder {
return builder.Set(b, "PlaceholderFormat", f).(InsertBuilder)
}
// Runner methods
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
func (b InsertBuilder) RunWith(runner BaseRunner) InsertBuilder {
return setRunWith(b, runner).(InsertBuilder)
}
// Exec builds and Execs the query with the Runner set by RunWith.
func (b InsertBuilder) Exec() (sql.Result, error) {
data := builder.GetStruct(b).(insertData)
return data.Exec()
}
// Query builds and Querys the query with the Runner set by RunWith.
func (b InsertBuilder) Query() (*sql.Rows, error) {
data := builder.GetStruct(b).(insertData)
return data.Query()
}
// QueryRow builds and QueryRows the query with the Runner set by RunWith.
func (b InsertBuilder) QueryRow() RowScanner {
data := builder.GetStruct(b).(insertData)
return data.QueryRow()
}
// Scan is a shortcut for QueryRow().Scan.
func (b InsertBuilder) Scan(dest ...interface{}) error {
return b.QueryRow().Scan(dest...)
}
// SQL methods
// ToSql builds the query into a SQL string and bound args.
func (b InsertBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(insertData)
return data.ToSql()
}
// MustSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b InsertBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
if err != nil {
panic(err)
}
return sql, args
}
// Prefix adds an expression to the beginning of the query
func (b InsertBuilder) Prefix(sql string, args ...interface{}) InsertBuilder {
return b.PrefixExpr(Expr(sql, args...))
}
// PrefixExpr adds an expression to the very beginning of the query
func (b InsertBuilder) PrefixExpr(expr Sqlizer) InsertBuilder {
return builder.Append(b, "Prefixes", expr).(InsertBuilder)
}
// Options adds keyword options before the INTO clause of the query.
func (b InsertBuilder) Options(options ...string) InsertBuilder {
return builder.Extend(b, "Options", options).(InsertBuilder)
}
// Into sets the INTO clause of the query.
func (b InsertBuilder) Into(into string) InsertBuilder {
return builder.Set(b, "Into", into).(InsertBuilder)
}
// Columns adds insert columns to the query.
func (b InsertBuilder) Columns(columns ...string) InsertBuilder {
return builder.Extend(b, "Columns", columns).(InsertBuilder)
}
// Values adds a single row's values to the query.
func (b InsertBuilder) Values(values ...interface{}) InsertBuilder {
return builder.Append(b, "Values", values).(InsertBuilder)
}
// Suffix adds an expression to the end of the query
func (b InsertBuilder) Suffix(sql string, args ...interface{}) InsertBuilder {
return b.SuffixExpr(Expr(sql, args...))
}
// SuffixExpr adds an expression to the end of the query
func (b InsertBuilder) SuffixExpr(expr Sqlizer) InsertBuilder {
return builder.Append(b, "Suffixes", expr).(InsertBuilder)
}
// SetMap set columns and values for insert builder from a map of column name and value
// note that it will reset all previous columns and values was set if any
func (b InsertBuilder) SetMap(clauses map[string]interface{}) InsertBuilder {
// Keep the columns in a consistent order by sorting the column key string.
cols := make([]string, 0, len(clauses))
for col := range clauses {
cols = append(cols, col)
}
sort.Strings(cols)
vals := make([]interface{}, 0, len(clauses))
for _, col := range cols {
vals = append(vals, clauses[col])
}
b = builder.Set(b, "Columns", cols).(InsertBuilder)
b = builder.Set(b, "Values", [][]interface{}{vals}).(InsertBuilder)
return b
}
// Select set Select clause for insert query
// If Values and Select are used, then Select has higher priority
func (b InsertBuilder) Select(sb SelectBuilder) InsertBuilder {
return builder.Set(b, "Select", &sb).(InsertBuilder)
}
func (b InsertBuilder) statementKeyword(keyword string) InsertBuilder {
return builder.Set(b, "StatementKeyword", keyword).(InsertBuilder)
}
================================================
FILE: insert_ctx.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
"github.com/lann/builder"
)
func (d *insertData) ExecContext(ctx context.Context) (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(ExecerContext)
if !ok {
return nil, NoContextSupport
}
return ExecContextWith(ctx, ctxRunner, d)
}
func (d *insertData) QueryContext(ctx context.Context) (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(QueryerContext)
if !ok {
return nil, NoContextSupport
}
return QueryContextWith(ctx, ctxRunner, d)
}
func (d *insertData) QueryRowContext(ctx context.Context) RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRowerContext)
if !ok {
if _, ok := d.RunWith.(QueryerContext); !ok {
return &Row{err: RunnerNotQueryRunner}
}
return &Row{err: NoContextSupport}
}
return QueryRowContextWith(ctx, queryRower, d)
}
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
func (b InsertBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
data := builder.GetStruct(b).(insertData)
return data.ExecContext(ctx)
}
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
func (b InsertBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
data := builder.GetStruct(b).(insertData)
return data.QueryContext(ctx)
}
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
func (b InsertBuilder) QueryRowContext(ctx context.Context) RowScanner {
data := builder.GetStruct(b).(insertData)
return data.QueryRowContext(ctx)
}
// ScanContext is a shortcut for QueryRowContext().Scan.
func (b InsertBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
return b.QueryRowContext(ctx).Scan(dest...)
}
================================================
FILE: insert_ctx_test.go
================================================
// +build go1.8
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestInsertBuilderContextRunners(t *testing.T) {
db := &DBStub{}
b := Insert("test").Values(1).RunWith(db)
expectedSql := "INSERT INTO test VALUES (?)"
b.ExecContext(ctx)
assert.Equal(t, expectedSql, db.LastExecSql)
b.QueryContext(ctx)
assert.Equal(t, expectedSql, db.LastQuerySql)
b.QueryRowContext(ctx)
assert.Equal(t, expectedSql, db.LastQueryRowSql)
err := b.ScanContext(ctx)
assert.NoError(t, err)
}
func TestInsertBuilderContextNoRunner(t *testing.T) {
b := Insert("test").Values(1)
_, err := b.ExecContext(ctx)
assert.Equal(t, RunnerNotSet, err)
_, err = b.QueryContext(ctx)
assert.Equal(t, RunnerNotSet, err)
err = b.ScanContext(ctx)
assert.Equal(t, RunnerNotSet, err)
}
================================================
FILE: insert_test.go
================================================
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestInsertBuilderToSql(t *testing.T) {
b := Insert("").
Prefix("WITH prefix AS ?", 0).
Into("a").
Options("DELAYED", "IGNORE").
Columns("b", "c").
Values(1, 2).
Values(3, Expr("? + 1", 4)).
Suffix("RETURNING ?", 5)
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSQL :=
"WITH prefix AS ? " +
"INSERT DELAYED IGNORE INTO a (b,c) VALUES (?,?),(?,? + 1) " +
"RETURNING ?"
assert.Equal(t, expectedSQL, sql)
expectedArgs := []interface{}{0, 1, 2, 3, 4, 5}
assert.Equal(t, expectedArgs, args)
}
func TestInsertBuilderToSqlErr(t *testing.T) {
_, _, err := Insert("").Values(1).ToSql()
assert.Error(t, err)
_, _, err = Insert("x").ToSql()
assert.Error(t, err)
}
func TestInsertBuilderMustSql(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("TestInsertBuilderMustSql should have panicked!")
}
}()
Insert("").MustSql()
}
func TestInsertBuilderPlaceholders(t *testing.T) {
b := Insert("test").Values(1, 2)
sql, _, _ := b.PlaceholderFormat(Question).ToSql()
assert.Equal(t, "INSERT INTO test VALUES (?,?)", sql)
sql, _, _ = b.PlaceholderFormat(Dollar).ToSql()
assert.Equal(t, "INSERT INTO test VALUES ($1,$2)", sql)
}
func TestInsertBuilderRunners(t *testing.T) {
db := &DBStub{}
b := Insert("test").Values(1).RunWith(db)
expectedSQL := "INSERT INTO test VALUES (?)"
b.Exec()
assert.Equal(t, expectedSQL, db.LastExecSql)
}
func TestInsertBuilderNoRunner(t *testing.T) {
b := Insert("test").Values(1)
_, err := b.Exec()
assert.Equal(t, RunnerNotSet, err)
}
func TestInsertBuilderSetMap(t *testing.T) {
b := Insert("table").SetMap(Eq{"field1": 1, "field2": 2, "field3": 3})
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSQL := "INSERT INTO table (field1,field2,field3) VALUES (?,?,?)"
assert.Equal(t, expectedSQL, sql)
expectedArgs := []interface{}{1, 2, 3}
assert.Equal(t, expectedArgs, args)
}
func TestInsertBuilderSelect(t *testing.T) {
sb := Select("field1").From("table1").Where(Eq{"field1": 1})
ib := Insert("table2").Columns("field1").Select(sb)
sql, args, err := ib.ToSql()
assert.NoError(t, err)
expectedSQL := "INSERT INTO table2 (field1) SELECT field1 FROM table1 WHERE field1 = ?"
assert.Equal(t, expectedSQL, sql)
expectedArgs := []interface{}{1}
assert.Equal(t, expectedArgs, args)
}
func TestInsertBuilderReplace(t *testing.T) {
b := Replace("table").Values(1)
expectedSQL := "REPLACE INTO table VALUES (?)"
sql, _, err := b.ToSql()
assert.NoError(t, err)
assert.Equal(t, expectedSQL, sql)
}
================================================
FILE: integration/doc.go
================================================
// This is a tests-only package.
package integration
================================================
FILE: integration/go.mod
================================================
module github.com/Masterminds/squirrel/integration
go 1.12
require (
github.com/Masterminds/squirrel v1.1.0
github.com/go-sql-driver/mysql v1.4.1
github.com/lib/pq v1.2.0
github.com/mattn/go-sqlite3 v1.13.0
github.com/stretchr/testify v1.4.0
google.golang.org/appengine v1.6.5 // indirect
)
replace github.com/Masterminds/squirrel => ../
================================================
FILE: integration/go.sum
================================================
github.com/Masterminds/squirrel v1.1.0 h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs=
github.com/Masterminds/squirrel v1.1.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
github.com/mattn/go-sqlite3 v1.13.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
================================================
FILE: integration/integration_test.go
================================================
package integration
import (
"context"
"database/sql"
"flag"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
sqrl "github.com/Masterminds/squirrel"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
const (
testSchema = `
CREATE TABLE squirrel_integration ( k INT, v TEXT )`
testData = `
INSERT INTO squirrel_integration VALUES
(1, 'foo'),
(3, 'bar'),
(2, 'foo'),
(4, 'baz')
`
)
var (
sb sqrl.StatementBuilderType
)
func TestMain(m *testing.M) {
var driver, dataSource string
flag.StringVar(&driver, "driver", "", "integration database driver")
flag.StringVar(&dataSource, "dataSource", "", "integration database data source")
flag.Parse()
if driver == "" {
driver = "sqlite3"
}
if driver == "sqlite3" && dataSource == "" {
dataSource = ":memory:"
}
db, err := sql.Open(driver, dataSource)
if err != nil {
fmt.Printf("error opening database: %v\n", err)
os.Exit(-1)
}
_, err = db.Exec(testSchema)
if err != nil {
fmt.Printf("error creating test schema: %v\n", err)
os.Exit(-2)
}
defer func() {
_, err = db.Exec("DROP TABLE squirrel_integration")
fmt.Printf("error removing test schema: %v\n", err)
}()
_, err = db.Exec(testData)
if err != nil {
fmt.Printf("error inserting test data: %v\n", err)
os.Exit(-3)
}
sb = sqrl.StatementBuilder.RunWith(db)
if driver == "postgres" {
sb = sb.PlaceholderFormat(sqrl.Dollar)
}
os.Exit(m.Run())
}
func assertVals(t *testing.T, s sqrl.SelectBuilder, expected ...string) {
rows, err := s.Query()
assert.NoError(t, err)
defer rows.Close()
vals := make([]string, len(expected))
for i := range vals {
assert.True(t, rows.Next())
assert.NoError(t, rows.Scan(&vals[i]))
}
assert.False(t, rows.Next())
if expected != nil {
assert.Equal(t, expected, vals)
}
}
func TestSimpleSelect(t *testing.T) {
assertVals(
t,
sb.Select("v").From("squirrel_integration"),
"foo", "bar", "foo", "baz")
}
func TestEq(t *testing.T) {
s := sb.Select("v").From("squirrel_integration")
assertVals(t, s.Where(sqrl.Eq{"k": 4}), "baz")
assertVals(t, s.Where(sqrl.NotEq{"k": 2}), "foo", "bar", "baz")
assertVals(t, s.Where(sqrl.Eq{"k": []int{1, 4}}), "foo", "baz")
assertVals(t, s.Where(sqrl.NotEq{"k": []int{1, 4}}), "bar", "foo")
assertVals(t, s.Where(sqrl.Eq{"k": nil}))
assertVals(t, s.Where(sqrl.NotEq{"k": nil}), "foo", "bar", "foo", "baz")
assertVals(t, s.Where(sqrl.Eq{"k": []int{}}))
assertVals(t, s.Where(sqrl.NotEq{"k": []int{}}), "foo", "bar", "foo", "baz")
}
func TestIneq(t *testing.T) {
s := sb.Select("v").From("squirrel_integration")
assertVals(t, s.Where(sqrl.Lt{"k": 3}), "foo", "foo")
assertVals(t, s.Where(sqrl.Gt{"k": 3}), "baz")
}
func TestConj(t *testing.T) {
s := sb.Select("v").From("squirrel_integration")
assertVals(t, s.Where(sqrl.And{sqrl.Gt{"k": 1}, sqrl.Lt{"k": 4}}), "bar", "foo")
assertVals(t, s.Where(sqrl.Or{sqrl.Gt{"k": 3}, sqrl.Lt{"k": 2}}), "foo", "baz")
}
func TestContext(t *testing.T) {
s := sb.Select("v").From("squirrel_integration")
ctx := context.Background()
_, err := s.QueryContext(ctx)
assert.NoError(t, err)
}
================================================
FILE: part.go
================================================
package squirrel
import (
"fmt"
"io"
)
type part struct {
pred interface{}
args []interface{}
}
func newPart(pred interface{}, args ...interface{}) Sqlizer {
return &part{pred, args}
}
func (p part) ToSql() (sql string, args []interface{}, err error) {
switch pred := p.pred.(type) {
case nil:
// no-op
case Sqlizer:
sql, args, err = nestedToSql(pred)
case string:
sql = pred
args = p.args
default:
err = fmt.Errorf("expected string or Sqlizer, not %T", pred)
}
return
}
func nestedToSql(s Sqlizer) (string, []interface{}, error) {
if raw, ok := s.(rawSqlizer); ok {
return raw.toSqlRaw()
} else {
return s.ToSql()
}
}
func appendToSql(parts []Sqlizer, w io.Writer, sep string, args []interface{}) ([]interface{}, error) {
for i, p := range parts {
partSql, partArgs, err := nestedToSql(p)
if err != nil {
return nil, err
} else if len(partSql) == 0 {
continue
}
if i > 0 {
_, err := io.WriteString(w, sep)
if err != nil {
return nil, err
}
}
_, err = io.WriteString(w, partSql)
if err != nil {
return nil, err
}
args = append(args, partArgs...)
}
return args, nil
}
================================================
FILE: placeholder.go
================================================
package squirrel
import (
"bytes"
"fmt"
"strings"
)
// PlaceholderFormat is the interface that wraps the ReplacePlaceholders method.
//
// ReplacePlaceholders takes a SQL statement and replaces each question mark
// placeholder with a (possibly different) SQL placeholder.
type PlaceholderFormat interface {
ReplacePlaceholders(sql string) (string, error)
}
type placeholderDebugger interface {
debugPlaceholder() string
}
var (
// Question is a PlaceholderFormat instance that leaves placeholders as
// question marks.
Question = questionFormat{}
// Dollar is a PlaceholderFormat instance that replaces placeholders with
// dollar-prefixed positional placeholders (e.g. $1, $2, $3).
Dollar = dollarFormat{}
// Colon is a PlaceholderFormat instance that replaces placeholders with
// colon-prefixed positional placeholders (e.g. :1, :2, :3).
Colon = colonFormat{}
// AtP is a PlaceholderFormat instance that replaces placeholders with
// "@p"-prefixed positional placeholders (e.g. @p1, @p2, @p3).
AtP = atpFormat{}
)
type questionFormat struct{}
func (questionFormat) ReplacePlaceholders(sql string) (string, error) {
return sql, nil
}
func (questionFormat) debugPlaceholder() string {
return "?"
}
type dollarFormat struct{}
func (dollarFormat) ReplacePlaceholders(sql string) (string, error) {
return replacePositionalPlaceholders(sql, "$")
}
func (dollarFormat) debugPlaceholder() string {
return "$"
}
type colonFormat struct{}
func (colonFormat) ReplacePlaceholders(sql string) (string, error) {
return replacePositionalPlaceholders(sql, ":")
}
func (colonFormat) debugPlaceholder() string {
return ":"
}
type atpFormat struct{}
func (atpFormat) ReplacePlaceholders(sql string) (string, error) {
return replacePositionalPlaceholders(sql, "@p")
}
func (atpFormat) debugPlaceholder() string {
return "@p"
}
// Placeholders returns a string with count ? placeholders joined with commas.
func Placeholders(count int) string {
if count < 1 {
return ""
}
return strings.Repeat(",?", count)[1:]
}
func replacePositionalPlaceholders(sql, prefix string) (string, error) {
buf := &bytes.Buffer{}
i := 0
for {
p := strings.Index(sql, "?")
if p == -1 {
break
}
if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
buf.WriteString(sql[:p])
buf.WriteString("?")
if len(sql[p:]) == 1 {
break
}
sql = sql[p+2:]
} else {
i++
buf.WriteString(sql[:p])
fmt.Fprintf(buf, "%s%d", prefix, i)
sql = sql[p+1:]
}
}
buf.WriteString(sql)
return buf.String(), nil
}
================================================
FILE: placeholder_test.go
================================================
package squirrel
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestQuestion(t *testing.T) {
sql := "x = ? AND y = ?"
s, _ := Question.ReplacePlaceholders(sql)
assert.Equal(t, sql, s)
}
func TestDollar(t *testing.T) {
sql := "x = ? AND y = ?"
s, _ := Dollar.ReplacePlaceholders(sql)
assert.Equal(t, "x = $1 AND y = $2", s)
}
func TestColon(t *testing.T) {
sql := "x = ? AND y = ?"
s, _ := Colon.ReplacePlaceholders(sql)
assert.Equal(t, "x = :1 AND y = :2", s)
}
func TestAtp(t *testing.T) {
sql := "x = ? AND y = ?"
s, _ := AtP.ReplacePlaceholders(sql)
assert.Equal(t, "x = @p1 AND y = @p2", s)
}
func TestPlaceholders(t *testing.T) {
assert.Equal(t, Placeholders(2), "?,?")
}
func TestEscapeDollar(t *testing.T) {
sql := "SELECT uuid, \"data\" #> '{tags}' AS tags FROM nodes WHERE \"data\" -> 'tags' ??| array['?'] AND enabled = ?"
s, _ := Dollar.ReplacePlaceholders(sql)
assert.Equal(t, "SELECT uuid, \"data\" #> '{tags}' AS tags FROM nodes WHERE \"data\" -> 'tags' ?| array['$1'] AND enabled = $2", s)
}
func TestEscapeColon(t *testing.T) {
sql := "SELECT uuid, \"data\" #> '{tags}' AS tags FROM nodes WHERE \"data\" -> 'tags' ??| array['?'] AND enabled = ?"
s, _ := Colon.ReplacePlaceholders(sql)
assert.Equal(t, "SELECT uuid, \"data\" #> '{tags}' AS tags FROM nodes WHERE \"data\" -> 'tags' ?| array[':1'] AND enabled = :2", s)
}
func TestEscapeAtp(t *testing.T) {
sql := "SELECT uuid, \"data\" #> '{tags}' AS tags FROM nodes WHERE \"data\" -> 'tags' ??| array['?'] AND enabled = ?"
s, _ := AtP.ReplacePlaceholders(sql)
assert.Equal(t, "SELECT uuid, \"data\" #> '{tags}' AS tags FROM nodes WHERE \"data\" -> 'tags' ?| array['@p1'] AND enabled = @p2", s)
}
func BenchmarkPlaceholdersArray(b *testing.B) {
var count = b.N
placeholders := make([]string, count)
for i := 0; i < count; i++ {
placeholders[i] = "?"
}
var _ = strings.Join(placeholders, ",")
}
func BenchmarkPlaceholdersStrings(b *testing.B) {
Placeholders(b.N)
}
================================================
FILE: row.go
================================================
package squirrel
// RowScanner is the interface that wraps the Scan method.
//
// Scan behaves like database/sql.Row.Scan.
type RowScanner interface {
Scan(...interface{}) error
}
// Row wraps database/sql.Row to let squirrel return new errors on Scan.
type Row struct {
RowScanner
err error
}
// Scan returns Row.err or calls RowScanner.Scan.
func (r *Row) Scan(dest ...interface{}) error {
if r.err != nil {
return r.err
}
return r.RowScanner.Scan(dest...)
}
================================================
FILE: row_test.go
================================================
package squirrel
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
type RowStub struct {
Scanned bool
}
func (r *RowStub) Scan(_ ...interface{}) error {
r.Scanned = true
return nil
}
func TestRowScan(t *testing.T) {
stub := &RowStub{}
row := &Row{RowScanner: stub}
err := row.Scan()
assert.True(t, stub.Scanned, "row was not scanned")
assert.NoError(t, err)
}
func TestRowScanErr(t *testing.T) {
stub := &RowStub{}
rowErr := fmt.Errorf("scan err")
row := &Row{RowScanner: stub, err: rowErr}
err := row.Scan()
assert.False(t, stub.Scanned, "row was scanned")
assert.Equal(t, rowErr, err)
}
================================================
FILE: select.go
================================================
package squirrel
import (
"bytes"
"database/sql"
"fmt"
"strings"
"github.com/lann/builder"
)
type selectData struct {
PlaceholderFormat PlaceholderFormat
RunWith BaseRunner
Prefixes []Sqlizer
Options []string
Columns []Sqlizer
From Sqlizer
Joins []Sqlizer
WhereParts []Sqlizer
GroupBys []string
HavingParts []Sqlizer
OrderByParts []Sqlizer
Limit string
Offset string
Suffixes []Sqlizer
}
func (d *selectData) Exec() (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return ExecWith(d.RunWith, d)
}
func (d *selectData) Query() (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return QueryWith(d.RunWith, d)
}
func (d *selectData) QueryRow() RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRower)
if !ok {
return &Row{err: RunnerNotQueryRunner}
}
return QueryRowWith(queryRower, d)
}
func (d *selectData) ToSql() (sqlStr string, args []interface{}, err error) {
sqlStr, args, err = d.toSqlRaw()
if err != nil {
return
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
return
}
func (d *selectData) toSqlRaw() (sqlStr string, args []interface{}, err error) {
if len(d.Columns) == 0 {
err = fmt.Errorf("select statements must have at least one result column")
return
}
sql := &bytes.Buffer{}
if len(d.Prefixes) > 0 {
args, err = appendToSql(d.Prefixes, sql, " ", args)
if err != nil {
return
}
sql.WriteString(" ")
}
sql.WriteString("SELECT ")
if len(d.Options) > 0 {
sql.WriteString(strings.Join(d.Options, " "))
sql.WriteString(" ")
}
if len(d.Columns) > 0 {
args, err = appendToSql(d.Columns, sql, ", ", args)
if err != nil {
return
}
}
if d.From != nil {
sql.WriteString(" FROM ")
args, err = appendToSql([]Sqlizer{d.From}, sql, "", args)
if err != nil {
return
}
}
if len(d.Joins) > 0 {
sql.WriteString(" ")
args, err = appendToSql(d.Joins, sql, " ", args)
if err != nil {
return
}
}
if len(d.WhereParts) > 0 {
sql.WriteString(" WHERE ")
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
if err != nil {
return
}
}
if len(d.GroupBys) > 0 {
sql.WriteString(" GROUP BY ")
sql.WriteString(strings.Join(d.GroupBys, ", "))
}
if len(d.HavingParts) > 0 {
sql.WriteString(" HAVING ")
args, err = appendToSql(d.HavingParts, sql, " AND ", args)
if err != nil {
return
}
}
if len(d.OrderByParts) > 0 {
sql.WriteString(" ORDER BY ")
args, err = appendToSql(d.OrderByParts, sql, ", ", args)
if err != nil {
return
}
}
if len(d.Limit) > 0 {
sql.WriteString(" LIMIT ")
sql.WriteString(d.Limit)
}
if len(d.Offset) > 0 {
sql.WriteString(" OFFSET ")
sql.WriteString(d.Offset)
}
if len(d.Suffixes) > 0 {
sql.WriteString(" ")
args, err = appendToSql(d.Suffixes, sql, " ", args)
if err != nil {
return
}
}
sqlStr = sql.String()
return
}
// Builder
// SelectBuilder builds SQL SELECT statements.
type SelectBuilder builder.Builder
func init() {
builder.Register(SelectBuilder{}, selectData{})
}
// Format methods
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
// query.
func (b SelectBuilder) PlaceholderFormat(f PlaceholderFormat) SelectBuilder {
return builder.Set(b, "PlaceholderFormat", f).(SelectBuilder)
}
// Runner methods
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
// For most cases runner will be a database connection.
//
// Internally we use this to mock out the database connection for testing.
func (b SelectBuilder) RunWith(runner BaseRunner) SelectBuilder {
return setRunWith(b, runner).(SelectBuilder)
}
// Exec builds and Execs the query with the Runner set by RunWith.
func (b SelectBuilder) Exec() (sql.Result, error) {
data := builder.GetStruct(b).(selectData)
return data.Exec()
}
// Query builds and Querys the query with the Runner set by RunWith.
func (b SelectBuilder) Query() (*sql.Rows, error) {
data := builder.GetStruct(b).(selectData)
return data.Query()
}
// QueryRow builds and QueryRows the query with the Runner set by RunWith.
func (b SelectBuilder) QueryRow() RowScanner {
data := builder.GetStruct(b).(selectData)
return data.QueryRow()
}
// Scan is a shortcut for QueryRow().Scan.
func (b SelectBuilder) Scan(dest ...interface{}) error {
return b.QueryRow().Scan(dest...)
}
// SQL methods
// ToSql builds the query into a SQL string and bound args.
func (b SelectBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(selectData)
return data.ToSql()
}
func (b SelectBuilder) toSqlRaw() (string, []interface{}, error) {
data := builder.GetStruct(b).(selectData)
return data.toSqlRaw()
}
// MustSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b SelectBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
if err != nil {
panic(err)
}
return sql, args
}
// Prefix adds an expression to the beginning of the query
func (b SelectBuilder) Prefix(sql string, args ...interface{}) SelectBuilder {
return b.PrefixExpr(Expr(sql, args...))
}
// PrefixExpr adds an expression to the very beginning of the query
func (b SelectBuilder) PrefixExpr(expr Sqlizer) SelectBuilder {
return builder.Append(b, "Prefixes", expr).(SelectBuilder)
}
// Distinct adds a DISTINCT clause to the query.
func (b SelectBuilder) Distinct() SelectBuilder {
return b.Options("DISTINCT")
}
// Options adds select option to the query
func (b SelectBuilder) Options(options ...string) SelectBuilder {
return builder.Extend(b, "Options", options).(SelectBuilder)
}
// Columns adds result columns to the query.
func (b SelectBuilder) Columns(columns ...string) SelectBuilder {
parts := make([]interface{}, 0, len(columns))
for _, str := range columns {
parts = append(parts, newPart(str))
}
return builder.Extend(b, "Columns", parts).(SelectBuilder)
}
// RemoveColumns remove all columns from query.
// Must add a new column with Column or Columns methods, otherwise
// return a error.
func (b SelectBuilder) RemoveColumns() SelectBuilder {
return builder.Delete(b, "Columns").(SelectBuilder)
}
// Column adds a result column to the query.
// Unlike Columns, Column accepts args which will be bound to placeholders in
// the columns string, for example:
// Column("IF(col IN ("+squirrel.Placeholders(3)+"), 1, 0) as col", 1, 2, 3)
func (b SelectBuilder) Column(column interface{}, args ...interface{}) SelectBuilder {
return builder.Append(b, "Columns", newPart(column, args...)).(SelectBuilder)
}
// From sets the FROM clause of the query.
func (b SelectBuilder) From(from string) SelectBuilder {
return builder.Set(b, "From", newPart(from)).(SelectBuilder)
}
// FromSelect sets a subquery into the FROM clause of the query.
func (b SelectBuilder) FromSelect(from SelectBuilder, alias string) SelectBuilder {
// Prevent misnumbered parameters in nested selects (#183).
from = from.PlaceholderFormat(Question)
return builder.Set(b, "From", Alias(from, alias)).(SelectBuilder)
}
// JoinClause adds a join clause to the query.
func (b SelectBuilder) JoinClause(pred interface{}, args ...interface{}) SelectBuilder {
return builder.Append(b, "Joins", newPart(pred, args...)).(SelectBuilder)
}
// Join adds a JOIN clause to the query.
func (b SelectBuilder) Join(join string, rest ...interface{}) SelectBuilder {
return b.JoinClause("JOIN "+join, rest...)
}
// LeftJoin adds a LEFT JOIN clause to the query.
func (b SelectBuilder) LeftJoin(join string, rest ...interface{}) SelectBuilder {
return b.JoinClause("LEFT JOIN "+join, rest...)
}
// RightJoin adds a RIGHT JOIN clause to the query.
func (b SelectBuilder) RightJoin(join string, rest ...interface{}) SelectBuilder {
return b.JoinClause("RIGHT JOIN "+join, rest...)
}
// InnerJoin adds a INNER JOIN clause to the query.
func (b SelectBuilder) InnerJoin(join string, rest ...interface{}) SelectBuilder {
return b.JoinClause("INNER JOIN "+join, rest...)
}
// CrossJoin adds a CROSS JOIN clause to the query.
func (b SelectBuilder) CrossJoin(join string, rest ...interface{}) SelectBuilder {
return b.JoinClause("CROSS JOIN "+join, rest...)
}
// Where adds an expression to the WHERE clause of the query.
//
// Expressions are ANDed together in the generated SQL.
//
// Where accepts several types for its pred argument:
//
// nil OR "" - ignored.
//
// string - SQL expression.
// If the expression has SQL placeholders then a set of arguments must be passed
// as well, one for each placeholder.
//
// map[string]interface{} OR Eq - map of SQL expressions to values. Each key is
// transformed into an expression like "<key> = ?", with the corresponding value
// bound to the placeholder. If the value is nil, the expression will be "<key>
// IS NULL". If the value is an array or slice, the expression will be "<key> IN
// (?,?,...)", with one placeholder for each item in the value. These expressions
// are ANDed together.
//
// Where will panic if pred isn't any of the above types.
func (b SelectBuilder) Where(pred interface{}, args ...interface{}) SelectBuilder {
if pred == nil || pred == "" {
return b
}
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(SelectBuilder)
}
// GroupBy adds GROUP BY expressions to the query.
func (b SelectBuilder) GroupBy(groupBys ...string) SelectBuilder {
return builder.Extend(b, "GroupBys", groupBys).(SelectBuilder)
}
// Having adds an expression to the HAVING clause of the query.
//
// See Where.
func (b SelectBuilder) Having(pred interface{}, rest ...interface{}) SelectBuilder {
return builder.Append(b, "HavingParts", newWherePart(pred, rest...)).(SelectBuilder)
}
// OrderByClause adds ORDER BY clause to the query.
func (b SelectBuilder) OrderByClause(pred interface{}, args ...interface{}) SelectBuilder {
return builder.Append(b, "OrderByParts", newPart(pred, args...)).(SelectBuilder)
}
// OrderBy adds ORDER BY expressions to the query.
func (b SelectBuilder) OrderBy(orderBys ...string) SelectBuilder {
for _, orderBy := range orderBys {
b = b.OrderByClause(orderBy)
}
return b
}
// Limit sets a LIMIT clause on the query.
func (b SelectBuilder) Limit(limit uint64) SelectBuilder {
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(SelectBuilder)
}
// Limit ALL allows to access all records with limit
func (b SelectBuilder) RemoveLimit() SelectBuilder {
return builder.Delete(b, "Limit").(SelectBuilder)
}
// Offset sets a OFFSET clause on the query.
func (b SelectBuilder) Offset(offset uint64) SelectBuilder {
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(SelectBuilder)
}
// RemoveOffset removes OFFSET clause.
func (b SelectBuilder) RemoveOffset() SelectBuilder {
return builder.Delete(b, "Offset").(SelectBuilder)
}
// Suffix adds an expression to the end of the query
func (b SelectBuilder) Suffix(sql string, args ...interface{}) SelectBuilder {
return b.SuffixExpr(Expr(sql, args...))
}
// SuffixExpr adds an expression to the end of the query
func (b SelectBuilder) SuffixExpr(expr Sqlizer) SelectBuilder {
return builder.Append(b, "Suffixes", expr).(SelectBuilder)
}
================================================
FILE: select_ctx.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
"github.com/lann/builder"
)
func (d *selectData) ExecContext(ctx context.Context) (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(ExecerContext)
if !ok {
return nil, NoContextSupport
}
return ExecContextWith(ctx, ctxRunner, d)
}
func (d *selectData) QueryContext(ctx context.Context) (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(QueryerContext)
if !ok {
return nil, NoContextSupport
}
return QueryContextWith(ctx, ctxRunner, d)
}
func (d *selectData) QueryRowContext(ctx context.Context) RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRowerContext)
if !ok {
if _, ok := d.RunWith.(QueryerContext); !ok {
return &Row{err: RunnerNotQueryRunner}
}
return &Row{err: NoContextSupport}
}
return QueryRowContextWith(ctx, queryRower, d)
}
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
func (b SelectBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
data := builder.GetStruct(b).(selectData)
return data.ExecContext(ctx)
}
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
func (b SelectBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
data := builder.GetStruct(b).(selectData)
return data.QueryContext(ctx)
}
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
func (b SelectBuilder) QueryRowContext(ctx context.Context) RowScanner {
data := builder.GetStruct(b).(selectData)
return data.QueryRowContext(ctx)
}
// ScanContext is a shortcut for QueryRowContext().Scan.
func (b SelectBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
return b.QueryRowContext(ctx).Scan(dest...)
}
================================================
FILE: select_ctx_test.go
================================================
// +build go1.8
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSelectBuilderContextRunners(t *testing.T) {
db := &DBStub{}
b := Select("test").RunWith(db)
expectedSql := "SELECT test"
b.ExecContext(ctx)
assert.Equal(t, expectedSql, db.LastExecSql)
b.QueryContext(ctx)
assert.Equal(t, expectedSql, db.LastQuerySql)
b.QueryRowContext(ctx)
assert.Equal(t, expectedSql, db.LastQueryRowSql)
err := b.ScanContext(ctx)
assert.NoError(t, err)
}
func TestSelectBuilderContextNoRunner(t *testing.T) {
b := Select("test")
_, err := b.ExecContext(ctx)
assert.Equal(t, RunnerNotSet, err)
_, err = b.QueryContext(ctx)
assert.Equal(t, RunnerNotSet, err)
err = b.ScanContext(ctx)
assert.Equal(t, RunnerNotSet, err)
}
================================================
FILE: select_test.go
================================================
package squirrel
import (
"database/sql"
"fmt"
"log"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestSelectBuilderToSql(t *testing.T) {
subQ := Select("aa", "bb").From("dd")
b := Select("a", "b").
Prefix("WITH prefix AS ?", 0).
Distinct().
Columns("c").
Column("IF(d IN ("+Placeholders(3)+"), 1, 0) as stat_column", 1, 2, 3).
Column(Expr("a > ?", 100)).
Column(Alias(Eq{"b": []int{101, 102, 103}}, "b_alias")).
Column(Alias(subQ, "subq")).
From("e").
JoinClause("CROSS JOIN j1").
Join("j2").
LeftJoin("j3").
RightJoin("j4").
InnerJoin("j5").
CrossJoin("j6").
Where("f = ?", 4).
Where(Eq{"g": 5}).
Where(map[string]interface{}{"h": 6}).
Where(Eq{"i": []int{7, 8, 9}}).
Where(Or{Expr("j = ?", 10), And{Eq{"k": 11}, Expr("true")}}).
GroupBy("l").
Having("m = n").
OrderByClause("? DESC", 1).
OrderBy("o ASC", "p DESC").
Limit(12).
Offset(13).
Suffix("FETCH FIRST ? ROWS ONLY", 14)
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql :=
"WITH prefix AS ? " +
"SELECT DISTINCT a, b, c, IF(d IN (?,?,?), 1, 0) as stat_column, a > ?, " +
"(b IN (?,?,?)) AS b_alias, " +
"(SELECT aa, bb FROM dd) AS subq " +
"FROM e " +
"CROSS JOIN j1 JOIN j2 LEFT JOIN j3 RIGHT JOIN j4 INNER JOIN j5 CROSS JOIN j6 " +
"WHERE f = ? AND g = ? AND h = ? AND i IN (?,?,?) AND (j = ? OR (k = ? AND true)) " +
"GROUP BY l HAVING m = n ORDER BY ? DESC, o ASC, p DESC LIMIT 12 OFFSET 13 " +
"FETCH FIRST ? ROWS ONLY"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{0, 1, 2, 3, 100, 101, 102, 103, 4, 5, 6, 7, 8, 9, 10, 11, 1, 14}
assert.Equal(t, expectedArgs, args)
}
func TestSelectBuilderFromSelect(t *testing.T) {
subQ := Select("c").From("d").Where(Eq{"i": 0})
b := Select("a", "b").FromSelect(subQ, "subq")
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT a, b FROM (SELECT c FROM d WHERE i = ?) AS subq"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{0}
assert.Equal(t, expectedArgs, args)
}
func TestSelectBuilderFromSelectNestedDollarPlaceholders(t *testing.T) {
subQ := Select("c").
From("t").
Where(Gt{"c": 1}).
PlaceholderFormat(Dollar)
b := Select("c").
FromSelect(subQ, "subq").
Where(Lt{"c": 2}).
PlaceholderFormat(Dollar)
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql := "SELECT c FROM (SELECT c FROM t WHERE c > $1) AS subq WHERE c < $2"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, 2}
assert.Equal(t, expectedArgs, args)
}
func TestSelectBuilderToSqlErr(t *testing.T) {
_, _, err := Select().From("x").ToSql()
assert.Error(t, err)
}
func TestSelectBuilderPlaceholders(t *testing.T) {
b := Select("test").Where("x = ? AND y = ?")
sql, _, _ := b.PlaceholderFormat(Question).ToSql()
assert.Equal(t, "SELECT test WHERE x = ? AND y = ?", sql)
sql, _, _ = b.PlaceholderFormat(Dollar).ToSql()
assert.Equal(t, "SELECT test WHERE x = $1 AND y = $2", sql)
sql, _, _ = b.PlaceholderFormat(Colon).ToSql()
assert.Equal(t, "SELECT test WHERE x = :1 AND y = :2", sql)
sql, _, _ = b.PlaceholderFormat(AtP).ToSql()
assert.Equal(t, "SELECT test WHERE x = @p1 AND y = @p2", sql)
}
func TestSelectBuilderRunners(t *testing.T) {
db := &DBStub{}
b := Select("test").RunWith(db)
expectedSql := "SELECT test"
b.Exec()
assert.Equal(t, expectedSql, db.LastExecSql)
b.Query()
assert.Equal(t, expectedSql, db.LastQuerySql)
b.QueryRow()
assert.Equal(t, expectedSql, db.LastQueryRowSql)
err := b.Scan()
assert.NoError(t, err)
}
func TestSelectBuilderNoRunner(t *testing.T) {
b := Select("test")
_, err := b.Exec()
assert.Equal(t, RunnerNotSet, err)
_, err = b.Query()
assert.Equal(t, RunnerNotSet, err)
err = b.Scan()
assert.Equal(t, RunnerNotSet, err)
}
func TestSelectBuilderSimpleJoin(t *testing.T) {
expectedSql := "SELECT * FROM bar JOIN baz ON bar.foo = baz.foo"
expectedArgs := []interface{}(nil)
b := Select("*").From("bar").Join("baz ON bar.foo = baz.foo")
sql, args, err := b.ToSql()
assert.NoError(t, err)
assert.Equal(t, expectedSql, sql)
assert.Equal(t, args, expectedArgs)
}
func TestSelectBuilderParamJoin(t *testing.T) {
expectedSql := "SELECT * FROM bar JOIN baz ON bar.foo = baz.foo AND baz.foo = ?"
expectedArgs := []interface{}{42}
b := Select("*").From("bar").Join("baz ON bar.foo = baz.foo AND baz.foo = ?", 42)
sql, args, err := b.ToSql()
assert.NoError(t, err)
assert.Equal(t, expectedSql, sql)
assert.Equal(t, args, expectedArgs)
}
func TestSelectBuilderNestedSelectJoin(t *testing.T) {
expectedSql := "SELECT * FROM bar JOIN ( SELECT * FROM baz WHERE foo = ? ) r ON bar.foo = r.foo"
expectedArgs := []interface{}{42}
nestedSelect := Select("*").From("baz").Where("foo = ?", 42)
b := Select("*").From("bar").JoinClause(nestedSelect.Prefix("JOIN (").Suffix(") r ON bar.foo = r.foo"))
sql, args, err := b.ToSql()
assert.NoError(t, err)
assert.Equal(t, expectedSql, sql)
assert.Equal(t, args, expectedArgs)
}
func TestSelectWithOptions(t *testing.T) {
sql, _, err := Select("*").From("foo").Distinct().Options("SQL_NO_CACHE").ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT DISTINCT SQL_NO_CACHE * FROM foo", sql)
}
func TestSelectWithRemoveLimit(t *testing.T) {
sql, _, err := Select("*").From("foo").Limit(10).RemoveLimit().ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM foo", sql)
}
func TestSelectWithRemoveOffset(t *testing.T) {
sql, _, err := Select("*").From("foo").Offset(10).RemoveOffset().ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM foo", sql)
}
func TestSelectBuilderNestedSelectDollar(t *testing.T) {
nestedBuilder := StatementBuilder.PlaceholderFormat(Dollar).Select("*").Prefix("NOT EXISTS (").
From("bar").Where("y = ?", 42).Suffix(")")
outerSql, _, err := StatementBuilder.PlaceholderFormat(Dollar).Select("*").
From("foo").Where("x = ?").Where(nestedBuilder).ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM foo WHERE x = $1 AND NOT EXISTS ( SELECT * FROM bar WHERE y = $2 )", outerSql)
}
func TestSelectBuilderMustSql(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("TestSelectBuilderMustSql should have panicked!")
}
}()
// This function should cause a panic
Select().From("foo").MustSql()
}
func TestSelectWithoutWhereClause(t *testing.T) {
sql, _, err := Select("*").From("users").ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM users", sql)
}
func TestSelectWithNilWhereClause(t *testing.T) {
sql, _, err := Select("*").From("users").Where(nil).ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM users", sql)
}
func TestSelectWithEmptyStringWhereClause(t *testing.T) {
sql, _, err := Select("*").From("users").Where("").ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM users", sql)
}
func TestSelectSubqueryPlaceholderNumbering(t *testing.T) {
subquery := Select("a").Where("b = ?", 1).PlaceholderFormat(Dollar)
with := subquery.Prefix("WITH a AS (").Suffix(")")
sql, args, err := Select("*").
PrefixExpr(with).
FromSelect(subquery, "q").
Where("c = ?", 2).
PlaceholderFormat(Dollar).
ToSql()
assert.NoError(t, err)
expectedSql := "WITH a AS ( SELECT a WHERE b = $1 ) SELECT * FROM (SELECT a WHERE b = $2) AS q WHERE c = $3"
assert.Equal(t, expectedSql, sql)
assert.Equal(t, []interface{}{1, 1, 2}, args)
}
func TestSelectSubqueryInConjunctionPlaceholderNumbering(t *testing.T) {
subquery := Select("a").Where(Eq{"b": 1}).Prefix("EXISTS(").Suffix(")").PlaceholderFormat(Dollar)
sql, args, err := Select("*").
Where(Or{subquery}).
Where("c = ?", 2).
PlaceholderFormat(Dollar).
ToSql()
assert.NoError(t, err)
expectedSql := "SELECT * WHERE (EXISTS( SELECT a WHERE b = $1 )) AND c = $2"
assert.Equal(t, expectedSql, sql)
assert.Equal(t, []interface{}{1, 2}, args)
}
func TestSelectJoinClausePlaceholderNumbering(t *testing.T) {
subquery := Select("a").Where(Eq{"b": 2}).PlaceholderFormat(Dollar)
sql, args, err := Select("t1.a").
From("t1").
Where(Eq{"a": 1}).
JoinClause(subquery.Prefix("JOIN (").Suffix(") t2 ON (t1.a = t2.a)")).
PlaceholderFormat(Dollar).
ToSql()
assert.NoError(t, err)
expectedSql := "SELECT t1.a FROM t1 JOIN ( SELECT a WHERE b = $1 ) t2 ON (t1.a = t2.a) WHERE a = $2"
assert.Equal(t, expectedSql, sql)
assert.Equal(t, []interface{}{2, 1}, args)
}
func ExampleSelect() {
Select("id", "created", "first_name").From("users") // ... continue building up your query
// sql methods in select columns are ok
Select("first_name", "count(*)").From("users")
// column aliases are ok too
Select("first_name", "count(*) as n_users").From("users")
}
func ExampleSelectBuilder_From() {
Select("id", "created", "first_name").From("users") // ... continue building up your query
}
func ExampleSelectBuilder_Where() {
companyId := 20
Select("id", "created", "first_name").From("users").Where("company = ?", companyId)
}
func ExampleSelectBuilder_Where_helpers() {
companyId := 20
Select("id", "created", "first_name").From("users").Where(Eq{
"company": companyId,
})
Select("id", "created", "first_name").From("users").Where(GtOrEq{
"created": time.Now().AddDate(0, 0, -7),
})
Select("id", "created", "first_name").From("users").Where(And{
GtOrEq{
"created": time.Now().AddDate(0, 0, -7),
},
Eq{
"company": companyId,
},
})
}
func ExampleSelectBuilder_Where_multiple() {
companyId := 20
// multiple where's are ok
Select("id", "created", "first_name").
From("users").
Where("company = ?", companyId).
Where(GtOrEq{
"created": time.Now().AddDate(0, 0, -7),
})
}
func ExampleSelectBuilder_FromSelect() {
usersByCompany := Select("company", "count(*) as n_users").From("users").GroupBy("company")
query := Select("company.id", "company.name", "users_by_company.n_users").
FromSelect(usersByCompany, "users_by_company").
Join("company on company.id = users_by_company.company")
sql, _, _ := query.ToSql()
fmt.Println(sql)
// Output: SELECT company.id, company.name, users_by_company.n_users FROM (SELECT company, count(*) as n_users FROM users GROUP BY company) AS users_by_company JOIN company on company.id = users_by_company.company
}
func ExampleSelectBuilder_Columns() {
query := Select("id").Columns("created", "first_name").From("users")
sql, _, _ := query.ToSql()
fmt.Println(sql)
// Output: SELECT id, created, first_name FROM users
}
func ExampleSelectBuilder_Columns_order() {
// out of order is ok too
query := Select("id").Columns("created").From("users").Columns("first_name")
sql, _, _ := query.ToSql()
fmt.Println(sql)
// Output: SELECT id, created, first_name FROM users
}
func ExampleSelectBuilder_Scan() {
var db *sql.DB
query := Select("id", "created", "first_name").From("users")
query = query.RunWith(db)
var id int
var created time.Time
var firstName string
if err := query.Scan(&id, &created, &firstName); err != nil {
log.Println(err)
return
}
}
func ExampleSelectBuilder_ScanContext() {
var db *sql.DB
query := Select("id", "created", "first_name").From("users")
query = query.RunWith(db)
var id int
var created time.Time
var firstName string
if err := query.ScanContext(ctx, &id, &created, &firstName); err != nil {
log.Println(err)
return
}
}
func ExampleSelectBuilder_RunWith() {
var db *sql.DB
query := Select("id", "created", "first_name").From("users").RunWith(db)
var id int
var created time.Time
var firstName string
if err := query.Scan(&id, &created, &firstName); err != nil {
log.Println(err)
return
}
}
func ExampleSelectBuilder_ToSql() {
var db *sql.DB
query := Select("id", "created", "first_name").From("users")
sql, args, err := query.ToSql()
if err != nil {
log.Println(err)
return
}
rows, err := db.Query(sql, args...)
if err != nil {
log.Println(err)
return
}
defer rows.Close()
for rows.Next() {
// scan...
}
}
func TestRemoveColumns(t *testing.T) {
query := Select("id").
From("users").
RemoveColumns()
query = query.Columns("name")
sql, _, err := query.ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT name FROM users", sql)
}
================================================
FILE: squirrel.go
================================================
// Package squirrel provides a fluent SQL generator.
//
// See https://github.com/Masterminds/squirrel for examples.
package squirrel
import (
"bytes"
"database/sql"
"fmt"
"strings"
"github.com/lann/builder"
)
// Sqlizer is the interface that wraps the ToSql method.
//
// ToSql returns a SQL representation of the Sqlizer, along with a slice of args
// as passed to e.g. database/sql.Exec. It can also return an error.
type Sqlizer interface {
ToSql() (string, []interface{}, error)
}
// rawSqlizer is expected to do what Sqlizer does, but without finalizing placeholders.
// This is useful for nested queries.
type rawSqlizer interface {
toSqlRaw() (string, []interface{}, error)
}
// Execer is the interface that wraps the Exec method.
//
// Exec executes the given query as implemented by database/sql.Exec.
type Execer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
}
// Queryer is the interface that wraps the Query method.
//
// Query executes the given query as implemented by database/sql.Query.
type Queryer interface {
Query(query string, args ...interface{}) (*sql.Rows, error)
}
// QueryRower is the interface that wraps the QueryRow method.
//
// QueryRow executes the given query as implemented by database/sql.QueryRow.
type QueryRower interface {
QueryRow(query string, args ...interface{}) RowScanner
}
// BaseRunner groups the Execer and Queryer interfaces.
type BaseRunner interface {
Execer
Queryer
}
// Runner groups the Execer, Queryer, and QueryRower interfaces.
type Runner interface {
Execer
Queryer
QueryRower
}
// WrapStdSql wraps a type implementing the standard SQL interface with methods that
// squirrel expects.
func WrapStdSql(stdSql StdSql) Runner {
return &stdsqlRunner{stdSql}
}
// StdSql encompasses the standard methods of the *sql.DB type, and other types that
// wrap these methods.
type StdSql interface {
Query(string, ...interface{}) (*sql.Rows, error)
QueryRow(string, ...interface{}) *sql.Row
Exec(string, ...interface{}) (sql.Result, error)
}
type stdsqlRunner struct {
StdSql
}
func (r *stdsqlRunner) QueryRow(query string, args ...interface{}) RowScanner {
return r.StdSql.QueryRow(query, args...)
}
func setRunWith(b interface{}, runner BaseRunner) interface{} {
switch r := runner.(type) {
case StdSqlCtx:
runner = WrapStdSqlCtx(r)
case StdSql:
runner = WrapStdSql(r)
}
return builder.Set(b, "RunWith", runner)
}
// RunnerNotSet is returned by methods that need a Runner if it isn't set.
var RunnerNotSet = fmt.Errorf("cannot run; no Runner set (RunWith)")
// RunnerNotQueryRunner is returned by QueryRow if the RunWith value doesn't implement QueryRower.
var RunnerNotQueryRunner = fmt.Errorf("cannot QueryRow; Runner is not a QueryRower")
// ExecWith Execs the SQL returned by s with db.
func ExecWith(db Execer, s Sqlizer) (res sql.Result, err error) {
query, args, err := s.ToSql()
if err != nil {
return
}
return db.Exec(query, args...)
}
// QueryWith Querys the SQL returned by s with db.
func QueryWith(db Queryer, s Sqlizer) (rows *sql.Rows, err error) {
query, args, err := s.ToSql()
if err != nil {
return
}
return db.Query(query, args...)
}
// QueryRowWith QueryRows the SQL returned by s with db.
func QueryRowWith(db QueryRower, s Sqlizer) RowScanner {
query, args, err := s.ToSql()
return &Row{RowScanner: db.QueryRow(query, args...), err: err}
}
// DebugSqlizer calls ToSql on s and shows the approximate SQL to be executed
//
// If ToSql returns an error, the result of this method will look like:
// "[ToSql error: %s]" or "[DebugSqlizer error: %s]"
//
// IMPORTANT: As its name suggests, this function should only be used for
// debugging. While the string result *might* be valid SQL, this function does
// not try very hard to ensure it. Additionally, executing the output of this
// function with any untrusted user input is certainly insecure.
func DebugSqlizer(s Sqlizer) string {
sql, args, err := s.ToSql()
if err != nil {
return fmt.Sprintf("[ToSql error: %s]", err)
}
var placeholder string
downCast, ok := s.(placeholderDebugger)
if !ok {
placeholder = "?"
} else {
placeholder = downCast.debugPlaceholder()
}
// TODO: dedupe this with placeholder.go
buf := &bytes.Buffer{}
i := 0
for {
p := strings.Index(sql, placeholder)
if p == -1 {
break
}
if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
buf.WriteString(sql[:p])
buf.WriteString("?")
if len(sql[p:]) == 1 {
break
}
sql = sql[p+2:]
} else {
if i+1 > len(args) {
return fmt.Sprintf(
"[DebugSqlizer error: too many placeholders in %#v for %d args]",
sql, len(args))
}
buf.WriteString(sql[:p])
fmt.Fprintf(buf, "'%v'", args[i])
// advance our sql string "cursor" beyond the arg we placed
sql = sql[p+1:]
i++
}
}
if i < len(args) {
return fmt.Sprintf(
"[DebugSqlizer error: not enough placeholders in %#v for %d args]",
sql, len(args))
}
// "append" any remaning sql that won't need interpolating
buf.WriteString(sql)
return buf.String()
}
================================================
FILE: squirrel_ctx.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
"errors"
)
// NoContextSupport is returned if a db doesn't support Context.
var NoContextSupport = errors.New("DB does not support Context")
// ExecerContext is the interface that wraps the ExecContext method.
//
// Exec executes the given query as implemented by database/sql.ExecContext.
type ExecerContext interface {
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}
// QueryerContext is the interface that wraps the QueryContext method.
//
// QueryContext executes the given query as implemented by database/sql.QueryContext.
type QueryerContext interface {
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
}
// QueryRowerContext is the interface that wraps the QueryRowContext method.
//
// QueryRowContext executes the given query as implemented by database/sql.QueryRowContext.
type QueryRowerContext interface {
QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner
}
// RunnerContext groups the Runner interface, along with the Context versions of each of
// its methods
type RunnerContext interface {
Runner
QueryerContext
QueryRowerContext
ExecerContext
}
// WrapStdSqlCtx wraps a type implementing the standard SQL interface plus the context
// versions of the methods with methods that squirrel expects.
func WrapStdSqlCtx(stdSqlCtx StdSqlCtx) RunnerContext {
return &stdsqlCtxRunner{stdSqlCtx}
}
// StdSqlCtx encompasses the standard methods of the *sql.DB type, along with the Context
// versions of those methods, and other types that wrap these methods.
type StdSqlCtx interface {
StdSql
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
}
type stdsqlCtxRunner struct {
StdSqlCtx
}
func (r *stdsqlCtxRunner) QueryRow(query string, args ...interface{}) RowScanner {
return r.StdSqlCtx.QueryRow(query, args...)
}
func (r *stdsqlCtxRunner) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
return r.StdSqlCtx.QueryRowContext(ctx, query, args...)
}
// ExecContextWith ExecContexts the SQL returned by s with db.
func ExecContextWith(ctx context.Context, db ExecerContext, s Sqlizer) (res sql.Result, err error) {
query, args, err := s.ToSql()
if err != nil {
return
}
return db.ExecContext(ctx, query, args...)
}
// QueryContextWith QueryContexts the SQL returned by s with db.
func QueryContextWith(ctx context.Context, db QueryerContext, s Sqlizer) (rows *sql.Rows, err error) {
query, args, err := s.ToSql()
if err != nil {
return
}
return db.QueryContext(ctx, query, args...)
}
// QueryRowContextWith QueryRowContexts the SQL returned by s with db.
func QueryRowContextWith(ctx context.Context, db QueryRowerContext, s Sqlizer) RowScanner {
query, args, err := s.ToSql()
return &Row{RowScanner: db.QueryRowContext(ctx, query, args...), err: err}
}
================================================
FILE: squirrel_ctx_test.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
"testing"
"github.com/stretchr/testify/assert"
)
func (s *DBStub) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
s.LastPrepareSql = query
s.PrepareCount++
return nil, nil
}
func (s *DBStub) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
s.LastExecSql = query
s.LastExecArgs = args
return nil, nil
}
func (s *DBStub) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
s.LastQuerySql = query
s.LastQueryArgs = args
return nil, nil
}
func (s *DBStub) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
s.LastQueryRowSql = query
s.LastQueryRowArgs = args
return &Row{RowScanner: &RowStub{}}
}
var ctx = context.Background()
func TestExecContextWith(t *testing.T) {
db := &DBStub{}
ExecContextWith(ctx, db, sqlizer)
assert.Equal(t, sqlStr, db.LastExecSql)
}
func TestQueryContextWith(t *testing.T) {
db := &DBStub{}
QueryContextWith(ctx, db, sqlizer)
assert.Equal(t, sqlStr, db.LastQuerySql)
}
func TestQueryRowContextWith(t *testing.T) {
db := &DBStub{}
QueryRowContextWith(ctx, db, sqlizer)
assert.Equal(t, sqlStr, db.LastQueryRowSql)
}
================================================
FILE: squirrel_test.go
================================================
package squirrel
import (
"database/sql"
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
type DBStub struct {
err error
LastPrepareSql string
PrepareCount int
LastExecSql string
LastExecArgs []interface{}
LastQuerySql string
LastQueryArgs []interface{}
LastQueryRowSql string
LastQueryRowArgs []interface{}
}
var StubError = fmt.Errorf("this is a stub; this is only a stub")
func (s *DBStub) Prepare(query string) (*sql.Stmt, error) {
s.LastPrepareSql = query
s.PrepareCount++
return nil, nil
}
func (s *DBStub) Exec(query string, args ...interface{}) (sql.Result, error) {
s.LastExecSql = query
s.LastExecArgs = args
return nil, nil
}
func (s *DBStub) Query(query string, args ...interface{}) (*sql.Rows, error) {
s.LastQuerySql = query
s.LastQueryArgs = args
return nil, nil
}
func (s *DBStub) QueryRow(query string, args ...interface{}) RowScanner {
s.LastQueryRowSql = query
s.LastQueryRowArgs = args
return &Row{RowScanner: &RowStub{}}
}
var sqlizer = Select("test")
var sqlStr = "SELECT test"
func TestExecWith(t *testing.T) {
db := &DBStub{}
ExecWith(db, sqlizer)
assert.Equal(t, sqlStr, db.LastExecSql)
}
func TestQueryWith(t *testing.T) {
db := &DBStub{}
QueryWith(db, sqlizer)
assert.Equal(t, sqlStr, db.LastQuerySql)
}
func TestQueryRowWith(t *testing.T) {
db := &DBStub{}
QueryRowWith(db, sqlizer)
assert.Equal(t, sqlStr, db.LastQueryRowSql)
}
func TestWithToSqlErr(t *testing.T) {
db := &DBStub{}
sqlizer := Select()
_, err := ExecWith(db, sqlizer)
assert.Error(t, err)
_, err = QueryWith(db, sqlizer)
assert.Error(t, err)
err = QueryRowWith(db, sqlizer).Scan()
assert.Error(t, err)
}
var testDebugUpdateSQL = Update("table").SetMap(Eq{"x": 1, "y": "val"})
var expectedDebugUpateSQL = "UPDATE table SET x = '1', y = 'val'"
func TestDebugSqlizerUpdateColon(t *testing.T) {
testDebugUpdateSQL.PlaceholderFormat(Colon)
assert.Equal(t, expectedDebugUpateSQL, DebugSqlizer(testDebugUpdateSQL))
}
func TestDebugSqlizerUpdateAtp(t *testing.T) {
testDebugUpdateSQL.PlaceholderFormat(AtP)
assert.Equal(t, expectedDebugUpateSQL, DebugSqlizer(testDebugUpdateSQL))
}
func TestDebugSqlizerUpdateDollar(t *testing.T) {
testDebugUpdateSQL.PlaceholderFormat(Dollar)
assert.Equal(t, expectedDebugUpateSQL, DebugSqlizer(testDebugUpdateSQL))
}
func TestDebugSqlizerUpdateQuestion(t *testing.T) {
testDebugUpdateSQL.PlaceholderFormat(Question)
assert.Equal(t, expectedDebugUpateSQL, DebugSqlizer(testDebugUpdateSQL))
}
var testDebugDeleteSQL = Delete("table").Where(And{
Eq{"column": "val"},
Eq{"other": 1},
})
var expectedDebugDeleteSQL = "DELETE FROM table WHERE (column = 'val' AND other = '1')"
func TestDebugSqlizerDeleteColon(t *testing.T) {
testDebugDeleteSQL.PlaceholderFormat(Colon)
assert.Equal(t, expectedDebugDeleteSQL, DebugSqlizer(testDebugDeleteSQL))
}
func TestDebugSqlizerDeleteAtp(t *testing.T) {
testDebugDeleteSQL.PlaceholderFormat(AtP)
assert.Equal(t, expectedDebugDeleteSQL, DebugSqlizer(testDebugDeleteSQL))
}
func TestDebugSqlizerDeleteDollar(t *testing.T) {
testDebugDeleteSQL.PlaceholderFormat(Dollar)
assert.Equal(t, expectedDebugDeleteSQL, DebugSqlizer(testDebugDeleteSQL))
}
func TestDebugSqlizerDeleteQuestion(t *testing.T) {
testDebugDeleteSQL.PlaceholderFormat(Question)
assert.Equal(t, expectedDebugDeleteSQL, DebugSqlizer(testDebugDeleteSQL))
}
var testDebugInsertSQL = Insert("table").Values(1, "test")
var expectedDebugInsertSQL = "INSERT INTO table VALUES ('1','test')"
func TestDebugSqlizerInsertColon(t *testing.T) {
testDebugInsertSQL.PlaceholderFormat(Colon)
assert.Equal(t, expectedDebugInsertSQL, DebugSqlizer(testDebugInsertSQL))
}
func TestDebugSqlizerInsertAtp(t *testing.T) {
testDebugInsertSQL.PlaceholderFormat(AtP)
assert.Equal(t, expectedDebugInsertSQL, DebugSqlizer(testDebugInsertSQL))
}
func TestDebugSqlizerInsertDollar(t *testing.T) {
testDebugInsertSQL.PlaceholderFormat(Dollar)
assert.Equal(t, expectedDebugInsertSQL, DebugSqlizer(testDebugInsertSQL))
}
func TestDebugSqlizerInsertQuestion(t *testing.T) {
testDebugInsertSQL.PlaceholderFormat(Question)
assert.Equal(t, expectedDebugInsertSQL, DebugSqlizer(testDebugInsertSQL))
}
var testDebugSelectSQL = Select("*").From("table").Where(And{
Eq{"column": "val"},
Eq{"other": 1},
})
var expectedDebugSelectSQL = "SELECT * FROM table WHERE (column = 'val' AND other = '1')"
func TestDebugSqlizerSelectColon(t *testing.T) {
testDebugSelectSQL.PlaceholderFormat(Colon)
assert.Equal(t, expectedDebugSelectSQL, DebugSqlizer(testDebugSelectSQL))
}
func TestDebugSqlizerSelectAtp(t *testing.T) {
testDebugSelectSQL.PlaceholderFormat(AtP)
assert.Equal(t, expectedDebugSelectSQL, DebugSqlizer(testDebugSelectSQL))
}
func TestDebugSqlizerSelectDollar(t *testing.T) {
testDebugSelectSQL.PlaceholderFormat(Dollar)
assert.Equal(t, expectedDebugSelectSQL, DebugSqlizer(testDebugSelectSQL))
}
func TestDebugSqlizerSelectQuestion(t *testing.T) {
testDebugSelectSQL.PlaceholderFormat(Question)
assert.Equal(t, expectedDebugSelectSQL, DebugSqlizer(testDebugSelectSQL))
}
func TestDebugSqlizer(t *testing.T) {
sqlizer := Expr("x = ? AND y = ? AND z = '??'", 1, "text")
expectedDebug := "x = '1' AND y = 'text' AND z = '?'"
assert.Equal(t, expectedDebug, DebugSqlizer(sqlizer))
}
func TestDebugSqlizerErrors(t *testing.T) {
errorMsg := DebugSqlizer(Expr("x = ?", 1, 2)) // Not enough placeholders
assert.True(t, strings.HasPrefix(errorMsg, "[DebugSqlizer error: "))
errorMsg = DebugSqlizer(Expr("x = ? AND y = ?", 1)) // Too many placeholders
assert.True(t, strings.HasPrefix(errorMsg, "[DebugSqlizer error: "))
errorMsg = DebugSqlizer(Lt{"x": nil}) // Cannot use nil values with Lt
assert.True(t, strings.HasPrefix(errorMsg, "[ToSql error: "))
}
================================================
FILE: statement.go
================================================
package squirrel
import "github.com/lann/builder"
// StatementBuilderType is the type of StatementBuilder.
type StatementBuilderType builder.Builder
// Select returns a SelectBuilder for this StatementBuilderType.
func (b StatementBuilderType) Select(columns ...string) SelectBuilder {
return SelectBuilder(b).Columns(columns...)
}
// Insert returns a InsertBuilder for this StatementBuilderType.
func (b StatementBuilderType) Insert(into string) InsertBuilder {
return InsertBuilder(b).Into(into)
}
// Replace returns a InsertBuilder for this StatementBuilderType with the
// statement keyword set to "REPLACE".
func (b StatementBuilderType) Replace(into string) InsertBuilder {
return InsertBuilder(b).statementKeyword("REPLACE").Into(into)
}
// Update returns a UpdateBuilder for this StatementBuilderType.
func (b StatementBuilderType) Update(table string) UpdateBuilder {
return UpdateBuilder(b).Table(table)
}
// Delete returns a DeleteBuilder for this StatementBuilderType.
func (b StatementBuilderType) Delete(from string) DeleteBuilder {
return DeleteBuilder(b).From(from)
}
// PlaceholderFormat sets the PlaceholderFormat field for any child builders.
func (b StatementBuilderType) PlaceholderFormat(f PlaceholderFormat) StatementBuilderType {
return builder.Set(b, "PlaceholderFormat", f).(StatementBuilderType)
}
// RunWith sets the RunWith field for any child builders.
func (b StatementBuilderType) RunWith(runner BaseRunner) StatementBuilderType {
return setRunWith(b, runner).(StatementBuilderType)
}
// Where adds WHERE expressions to the query.
//
// See SelectBuilder.Where for more information.
func (b StatementBuilderType) Where(pred interface{}, args ...interface{}) StatementBuilderType {
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(StatementBuilderType)
}
// StatementBuilder is a parent builder for other builders, e.g. SelectBuilder.
var StatementBuilder = StatementBuilderType(builder.EmptyBuilder).PlaceholderFormat(Question)
// Select returns a new SelectBuilder, optionally setting some result columns.
//
// See SelectBuilder.Columns.
func Select(columns ...string) SelectBuilder {
return StatementBuilder.Select(columns...)
}
// Insert returns a new InsertBuilder with the given table name.
//
// See InsertBuilder.Into.
func Insert(into string) InsertBuilder {
return StatementBuilder.Insert(into)
}
// Replace returns a new InsertBuilder with the statement keyword set to
// "REPLACE" and with the given table name.
//
// See InsertBuilder.Into.
func Replace(into string) InsertBuilder {
return StatementBuilder.Replace(into)
}
// Update returns a new UpdateBuilder with the given table name.
//
// See UpdateBuilder.Table.
func Update(table string) UpdateBuilder {
return StatementBuilder.Update(table)
}
// Delete returns a new DeleteBuilder with the given table name.
//
// See DeleteBuilder.Table.
func Delete(from string) DeleteBuilder {
return StatementBuilder.Delete(from)
}
// Case returns a new CaseBuilder
// "what" represents case value
func Case(what ...interface{}) CaseBuilder {
b := CaseBuilder(builder.EmptyBuilder)
switch len(what) {
case 0:
case 1:
b = b.what(what[0])
default:
b = b.what(newPart(what[0], what[1:]...))
}
return b
}
================================================
FILE: statement_test.go
================================================
package squirrel
import (
"database/sql"
"testing"
"github.com/lann/builder"
"github.com/stretchr/testify/assert"
)
func TestStatementBuilder(t *testing.T) {
db := &DBStub{}
sb := StatementBuilder.RunWith(db)
sb.Select("test").Exec()
assert.Equal(t, "SELECT test", db.LastExecSql)
}
func TestStatementBuilderPlaceholderFormat(t *testing.T) {
db := &DBStub{}
sb := StatementBuilder.RunWith(db).PlaceholderFormat(Dollar)
sb.Select("test").Where("x = ?").Exec()
assert.Equal(t, "SELECT test WHERE x = $1", db.LastExecSql)
}
func TestRunWithDB(t *testing.T) {
db := &sql.DB{}
assert.NotPanics(t, func() {
builder.GetStruct(Select().RunWith(db))
builder.GetStruct(Insert("t").RunWith(db))
builder.GetStruct(Update("t").RunWith(db))
builder.GetStruct(Delete("t").RunWith(db))
}, "RunWith(*sql.DB) should not panic")
}
func TestRunWithTx(t *testing.T) {
tx := &sql.Tx{}
assert.NotPanics(t, func() {
builder.GetStruct(Select().RunWith(tx))
builder.GetStruct(Insert("t").RunWith(tx))
builder.GetStruct(Update("t").RunWith(tx))
builder.GetStruct(Delete("t").RunWith(tx))
}, "RunWith(*sql.Tx) should not panic")
}
type fakeBaseRunner struct{}
func (fakeBaseRunner) Exec(query string, args ...interface{}) (sql.Result, error) {
return nil, nil
}
func (fakeBaseRunner) Query(query string, args ...interface{}) (*sql.Rows, error) {
return nil, nil
}
func TestRunWithBaseRunner(t *testing.T) {
sb := StatementBuilder.RunWith(fakeBaseRunner{})
_, err := sb.Select("test").Exec()
assert.NoError(t, err)
}
func TestRunWithBaseRunnerQueryRowError(t *testing.T) {
sb := StatementBuilder.RunWith(fakeBaseRunner{})
assert.Error(t, RunnerNotQueryRunner, sb.Select("test").QueryRow().Scan(nil))
}
func TestStatementBuilderWhere(t *testing.T) {
sb := StatementBuilder.Where("x = ?", 1)
sql, args, err := sb.Select("test").Where("y = ?", 2).ToSql()
assert.NoError(t, err)
expectedSql := "SELECT test WHERE x = ? AND y = ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{1, 2}
assert.Equal(t, expectedArgs, args)
}
================================================
FILE: stmtcacher.go
================================================
package squirrel
import (
"database/sql"
"fmt"
"sync"
)
// Prepareer is the interface that wraps the Prepare method.
//
// Prepare executes the given query as implemented by database/sql.Prepare.
type Preparer interface {
Prepare(query string) (*sql.Stmt, error)
}
// DBProxy groups the Execer, Queryer, QueryRower, and Preparer interfaces.
type DBProxy interface {
Execer
Queryer
QueryRower
Preparer
}
// NOTE: NewStmtCache is defined in stmtcacher_ctx.go (Go >= 1.8) or stmtcacher_noctx.go (Go < 1.8).
// StmtCache wraps and delegates down to a Preparer type
//
// It also automatically prepares all statements sent to the underlying Preparer calls
// for Exec, Query and QueryRow and caches the returns *sql.Stmt using the provided
// query as the key. So that it can be automatically re-used.
type StmtCache struct {
prep Preparer
cache map[string]*sql.Stmt
mu sync.Mutex
}
// Prepare delegates down to the underlying Preparer and caches the result
// using the provided query as a key
func (sc *StmtCache) Prepare(query string) (*sql.Stmt, error) {
sc.mu.Lock()
defer sc.mu.Unlock()
stmt, ok := sc.cache[query]
if ok {
return stmt, nil
}
stmt, err := sc.prep.Prepare(query)
if err == nil {
sc.cache[query] = stmt
}
return stmt, err
}
// Exec delegates down to the underlying Preparer using a prepared statement
func (sc *StmtCache) Exec(query string, args ...interface{}) (res sql.Result, err error) {
stmt, err := sc.Prepare(query)
if err != nil {
return
}
return stmt.Exec(args...)
}
// Query delegates down to the underlying Preparer using a prepared statement
func (sc *StmtCache) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
stmt, err := sc.Prepare(query)
if err != nil {
return
}
return stmt.Query(args...)
}
// QueryRow delegates down to the underlying Preparer using a prepared statement
func (sc *StmtCache) QueryRow(query string, args ...interface{}) RowScanner {
stmt, err := sc.Prepare(query)
if err != nil {
return &Row{err: err}
}
return stmt.QueryRow(args...)
}
// Clear removes and closes all the currently cached prepared statements
func (sc *StmtCache) Clear() (err error) {
sc.mu.Lock()
defer sc.mu.Unlock()
for key, stmt := range sc.cache {
delete(sc.cache, key)
if stmt == nil {
continue
}
if cerr := stmt.Close(); cerr != nil {
err = cerr
}
}
if err != nil {
return fmt.Errorf("one or more Stmt.Close failed; last error: %v", err)
}
return
}
type DBProxyBeginner interface {
DBProxy
Begin() (*sql.Tx, error)
}
type stmtCacheProxy struct {
DBProxy
db *sql.DB
}
func NewStmtCacheProxy(db *sql.DB) DBProxyBeginner {
return &stmtCacheProxy{DBProxy: NewStmtCache(db), db: db}
}
func (sp *stmtCacheProxy) Begin() (*sql.Tx, error) {
return sp.db.Begin()
}
================================================
FILE: stmtcacher_ctx.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
)
// PrepareerContext is the interface that wraps the Prepare and PrepareContext methods.
//
// Prepare executes the given query as implemented by database/sql.Prepare.
// PrepareContext executes the given query as implemented by database/sql.PrepareContext.
type PreparerContext interface {
Preparer
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
}
// DBProxyContext groups the Execer, Queryer, QueryRower and PreparerContext interfaces.
type DBProxyContext interface {
Execer
Queryer
QueryRower
PreparerContext
}
// NewStmtCache returns a *StmtCache wrapping a PreparerContext that caches Prepared Stmts.
//
// Stmts are cached based on the string value of their queries.
func NewStmtCache(prep PreparerContext) *StmtCache {
return &StmtCache{prep: prep, cache: make(map[string]*sql.Stmt)}
}
// NewStmtCacher is deprecated
//
// Use NewStmtCache instead
func NewStmtCacher(prep PreparerContext) DBProxyContext {
return NewStmtCache(prep)
}
// PrepareContext delegates down to the underlying PreparerContext and caches the result
// using the provided query as a key
func (sc *StmtCache) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
ctxPrep, ok := sc.prep.(PreparerContext)
if !ok {
return nil, NoContextSupport
}
sc.mu.Lock()
defer sc.mu.Unlock()
stmt, ok := sc.cache[query]
if ok {
return stmt, nil
}
stmt, err := ctxPrep.PrepareContext(ctx, query)
if err == nil {
sc.cache[query] = stmt
}
return stmt, err
}
// ExecContext delegates down to the underlying PreparerContext using a prepared statement
func (sc *StmtCache) ExecContext(ctx context.Context, query string, args ...interface{}) (res sql.Result, err error) {
stmt, err := sc.PrepareContext(ctx, query)
if err != nil {
return
}
return stmt.ExecContext(ctx, args...)
}
// QueryContext delegates down to the underlying PreparerContext using a prepared statement
func (sc *StmtCache) QueryContext(ctx context.Context, query string, args ...interface{}) (rows *sql.Rows, err error) {
stmt, err := sc.PrepareContext(ctx, query)
if err != nil {
return
}
return stmt.QueryContext(ctx, args...)
}
// QueryRowContext delegates down to the underlying PreparerContext using a prepared statement
func (sc *StmtCache) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
stmt, err := sc.PrepareContext(ctx, query)
if err != nil {
return &Row{err: err}
}
return stmt.QueryRowContext(ctx, args...)
}
================================================
FILE: stmtcacher_ctx_test.go
================================================
// +build go1.8
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestStmtCacherPrepareContext(t *testing.T) {
db := &DBStub{}
sc := NewStmtCache(db)
query := "SELECT 1"
sc.PrepareContext(ctx, query)
assert.Equal(t, query, db.LastPrepareSql)
sc.PrepareContext(ctx, query)
assert.Equal(t, 1, db.PrepareCount, "expected 1 Prepare, got %d", db.PrepareCount)
}
================================================
FILE: stmtcacher_noctx.go
================================================
// +build !go1.8
package squirrel
import (
"database/sql"
)
// NewStmtCacher returns a DBProxy wrapping prep that caches Prepared Stmts.
//
// Stmts are cached based on the string value of their queries.
func NewStmtCache(prep Preparer) *StmtCache {
return &StmtCacher{prep: prep, cache: make(map[string]*sql.Stmt)}
}
// NewStmtCacher is deprecated
//
// Use NewStmtCache instead
func NewStmtCacher(prep Preparer) DBProxy {
return NewStmtCache(prep)
}
================================================
FILE: stmtcacher_test.go
================================================
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestStmtCachePrepare(t *testing.T) {
db := &DBStub{}
sc := NewStmtCache(db)
query := "SELECT 1"
sc.Prepare(query)
assert.Equal(t, query, db.LastPrepareSql)
sc.Prepare(query)
assert.Equal(t, 1, db.PrepareCount, "expected 1 Prepare, got %d", db.PrepareCount)
// clear statement cache
assert.Nil(t, sc.Clear())
// should prepare the query again
sc.Prepare(query)
assert.Equal(t, 2, db.PrepareCount, "expected 2 Prepare, got %d", db.PrepareCount)
}
================================================
FILE: update.go
================================================
package squirrel
import (
"bytes"
"database/sql"
"fmt"
"sort"
"strings"
"github.com/lann/builder"
)
type updateData struct {
PlaceholderFormat PlaceholderFormat
RunWith BaseRunner
Prefixes []Sqlizer
Table string
SetClauses []setClause
From Sqlizer
WhereParts []Sqlizer
OrderBys []string
Limit string
Offset string
Suffixes []Sqlizer
}
type setClause struct {
column string
value interface{}
}
func (d *updateData) Exec() (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return ExecWith(d.RunWith, d)
}
func (d *updateData) Query() (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
return QueryWith(d.RunWith, d)
}
func (d *updateData) QueryRow() RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRower)
if !ok {
return &Row{err: RunnerNotQueryRunner}
}
return QueryRowWith(queryRower, d)
}
func (d *updateData) ToSql() (sqlStr string, args []interface{}, err error) {
if len(d.Table) == 0 {
err = fmt.Errorf("update statements must specify a table")
return
}
if len(d.SetClauses) == 0 {
err = fmt.Errorf("update statements must have at least one Set clause")
return
}
sql := &bytes.Buffer{}
if len(d.Prefixes) > 0 {
args, err = appendToSql(d.Prefixes, sql, " ", args)
if err != nil {
return
}
sql.WriteString(" ")
}
sql.WriteString("UPDATE ")
sql.WriteString(d.Table)
sql.WriteString(" SET ")
setSqls := make([]string, len(d.SetClauses))
for i, setClause := range d.SetClauses {
var valSql string
if vs, ok := setClause.value.(Sqlizer); ok {
vsql, vargs, err := vs.ToSql()
if err != nil {
return "", nil, err
}
if _, ok := vs.(SelectBuilder); ok {
valSql = fmt.Sprintf("(%s)", vsql)
} else {
valSql = vsql
}
args = append(args, vargs...)
} else {
valSql = "?"
args = append(args, setClause.value)
}
setSqls[i] = fmt.Sprintf("%s = %s", setClause.column, valSql)
}
sql.WriteString(strings.Join(setSqls, ", "))
if d.From != nil {
sql.WriteString(" FROM ")
args, err = appendToSql([]Sqlizer{d.From}, sql, "", args)
if err != nil {
return
}
}
if len(d.WhereParts) > 0 {
sql.WriteString(" WHERE ")
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
if err != nil {
return
}
}
if len(d.OrderBys) > 0 {
sql.WriteString(" ORDER BY ")
sql.WriteString(strings.Join(d.OrderBys, ", "))
}
if len(d.Limit) > 0 {
sql.WriteString(" LIMIT ")
sql.WriteString(d.Limit)
}
if len(d.Offset) > 0 {
sql.WriteString(" OFFSET ")
sql.WriteString(d.Offset)
}
if len(d.Suffixes) > 0 {
sql.WriteString(" ")
args, err = appendToSql(d.Suffixes, sql, " ", args)
if err != nil {
return
}
}
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
return
}
// Builder
// UpdateBuilder builds SQL UPDATE statements.
type UpdateBuilder builder.Builder
func init() {
builder.Register(UpdateBuilder{}, updateData{})
}
// Format methods
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
// query.
func (b UpdateBuilder) PlaceholderFormat(f PlaceholderFormat) UpdateBuilder {
return builder.Set(b, "PlaceholderFormat", f).(UpdateBuilder)
}
// Runner methods
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
func (b UpdateBuilder) RunWith(runner BaseRunner) UpdateBuilder {
return setRunWith(b, runner).(UpdateBuilder)
}
// Exec builds and Execs the query with the Runner set by RunWith.
func (b UpdateBuilder) Exec() (sql.Result, error) {
data := builder.GetStruct(b).(updateData)
return data.Exec()
}
func (b UpdateBuilder) Query() (*sql.Rows, error) {
data := builder.GetStruct(b).(updateData)
return data.Query()
}
func (b UpdateBuilder) QueryRow() RowScanner {
data := builder.GetStruct(b).(updateData)
return data.QueryRow()
}
func (b UpdateBuilder) Scan(dest ...interface{}) error {
return b.QueryRow().Scan(dest...)
}
// SQL methods
// ToSql builds the query into a SQL string and bound args.
func (b UpdateBuilder) ToSql() (string, []interface{}, error) {
data := builder.GetStruct(b).(updateData)
return data.ToSql()
}
// MustSql builds the query into a SQL string and bound args.
// It panics if there are any errors.
func (b UpdateBuilder) MustSql() (string, []interface{}) {
sql, args, err := b.ToSql()
if err != nil {
panic(err)
}
return sql, args
}
// Prefix adds an expression to the beginning of the query
func (b UpdateBuilder) Prefix(sql string, args ...interface{}) UpdateBuilder {
return b.PrefixExpr(Expr(sql, args...))
}
// PrefixExpr adds an expression to the very beginning of the query
func (b UpdateBuilder) PrefixExpr(expr Sqlizer) UpdateBuilder {
return builder.Append(b, "Prefixes", expr).(UpdateBuilder)
}
// Table sets the table to be updated.
func (b UpdateBuilder) Table(table string) UpdateBuilder {
return builder.Set(b, "Table", table).(UpdateBuilder)
}
// Set adds SET clauses to the query.
func (b UpdateBuilder) Set(column string, value interface{}) UpdateBuilder {
return builder.Append(b, "SetClauses", setClause{column: column, value: value}).(UpdateBuilder)
}
// SetMap is a convenience method which calls .Set for each key/value pair in clauses.
func (b UpdateBuilder) SetMap(clauses map[string]interface{}) UpdateBuilder {
keys := make([]string, len(clauses))
i := 0
for key := range clauses {
keys[i] = key
i++
}
sort.Strings(keys)
for _, key := range keys {
val, _ := clauses[key]
b = b.Set(key, val)
}
return b
}
// From adds FROM clause to the query
// FROM is valid construct in postgresql only.
func (b UpdateBuilder) From(from string) UpdateBuilder {
return builder.Set(b, "From", newPart(from)).(UpdateBuilder)
}
// FromSelect sets a subquery into the FROM clause of the query.
func (b UpdateBuilder) FromSelect(from SelectBuilder, alias string) UpdateBuilder {
// Prevent misnumbered parameters in nested selects (#183).
from = from.PlaceholderFormat(Question)
return builder.Set(b, "From", Alias(from, alias)).(UpdateBuilder)
}
// Where adds WHERE expressions to the query.
//
// See SelectBuilder.Where for more information.
func (b UpdateBuilder) Where(pred interface{}, args ...interface{}) UpdateBuilder {
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(UpdateBuilder)
}
// OrderBy adds ORDER BY expressions to the query.
func (b UpdateBuilder) OrderBy(orderBys ...string) UpdateBuilder {
return builder.Extend(b, "OrderBys", orderBys).(UpdateBuilder)
}
// Limit sets a LIMIT clause on the query.
func (b UpdateBuilder) Limit(limit uint64) UpdateBuilder {
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(UpdateBuilder)
}
// Offset sets a OFFSET clause on the query.
func (b UpdateBuilder) Offset(offset uint64) UpdateBuilder {
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(UpdateBuilder)
}
// Suffix adds an expression to the end of the query
func (b UpdateBuilder) Suffix(sql string, args ...interface{}) UpdateBuilder {
return b.SuffixExpr(Expr(sql, args...))
}
// SuffixExpr adds an expression to the end of the query
func (b UpdateBuilder) SuffixExpr(expr Sqlizer) UpdateBuilder {
return builder.Append(b, "Suffixes", expr).(UpdateBuilder)
}
================================================
FILE: update_ctx.go
================================================
// +build go1.8
package squirrel
import (
"context"
"database/sql"
"github.com/lann/builder"
)
func (d *updateData) ExecContext(ctx context.Context) (sql.Result, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(ExecerContext)
if !ok {
return nil, NoContextSupport
}
return ExecContextWith(ctx, ctxRunner, d)
}
func (d *updateData) QueryContext(ctx context.Context) (*sql.Rows, error) {
if d.RunWith == nil {
return nil, RunnerNotSet
}
ctxRunner, ok := d.RunWith.(QueryerContext)
if !ok {
return nil, NoContextSupport
}
return QueryContextWith(ctx, ctxRunner, d)
}
func (d *updateData) QueryRowContext(ctx context.Context) RowScanner {
if d.RunWith == nil {
return &Row{err: RunnerNotSet}
}
queryRower, ok := d.RunWith.(QueryRowerContext)
if !ok {
if _, ok := d.RunWith.(QueryerContext); !ok {
return &Row{err: RunnerNotQueryRunner}
}
return &Row{err: NoContextSupport}
}
return QueryRowContextWith(ctx, queryRower, d)
}
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
func (b UpdateBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
data := builder.GetStruct(b).(updateData)
return data.ExecContext(ctx)
}
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
func (b UpdateBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
data := builder.GetStruct(b).(updateData)
return data.QueryContext(ctx)
}
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
func (b UpdateBuilder) QueryRowContext(ctx context.Context) RowScanner {
data := builder.GetStruct(b).(updateData)
return data.QueryRowContext(ctx)
}
// ScanContext is a shortcut for QueryRowContext().Scan.
func (b UpdateBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
return b.QueryRowContext(ctx).Scan(dest...)
}
================================================
FILE: update_ctx_test.go
================================================
// +build go1.8
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUpdateBuilderContextRunners(t *testing.T) {
db := &DBStub{}
b := Update("test").Set("x", 1).RunWith(db)
expectedSql := "UPDATE test SET x = ?"
b.ExecContext(ctx)
assert.Equal(t, expectedSql, db.LastExecSql)
b.QueryContext(ctx)
assert.Equal(t, expectedSql, db.LastQuerySql)
b.QueryRowContext(ctx)
assert.Equal(t, expectedSql, db.LastQueryRowSql)
err := b.ScanContext(ctx)
assert.NoError(t, err)
}
func TestUpdateBuilderContextNoRunner(t *testing.T) {
b := Update("test").Set("x", 1)
_, err := b.ExecContext(ctx)
assert.Equal(t, RunnerNotSet, err)
_, err = b.QueryContext(ctx)
assert.Equal(t, RunnerNotSet, err)
err = b.ScanContext(ctx)
assert.Equal(t, RunnerNotSet, err)
}
================================================
FILE: update_test.go
================================================
package squirrel
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUpdateBuilderToSql(t *testing.T) {
b := Update("").
Prefix("WITH prefix AS ?", 0).
Table("a").
Set("b", Expr("? + 1", 1)).
SetMap(Eq{"c": 2}).
Set("c1", Case("status").When("1", "2").When("2", "1")).
Set("c2", Case().When("a = 2", Expr("?", "foo")).When("a = 3", Expr("?", "bar"))).
Set("c3", Select("a").From("b")).
Where("d = ?", 3).
OrderBy("e").
Limit(4).
Offset(5).
Suffix("RETURNING ?", 6)
sql, args, err := b.ToSql()
assert.NoError(t, err)
expectedSql :=
"WITH prefix AS ? " +
"UPDATE a SET b = ? + 1, c = ?, " +
"c1 = CASE status WHEN 1 THEN 2 WHEN 2 THEN 1 END, " +
"c2 = CASE WHEN a = 2 THEN ? WHEN a = 3 THEN ? END, " +
"c3 = (SELECT a FROM b) " +
"WHERE d = ? " +
"ORDER BY e LIMIT 4 OFFSET 5 " +
"RETURNING ?"
assert.Equal(t, expectedSql, sql)
expectedArgs := []interface{}{0, 1, 2, "foo", "bar", 3, 6}
assert.Equal(t, expectedArgs, args)
}
func TestUpdateBuilderToSqlErr(t *testing.T) {
_, _, err := Update("").Set("x", 1).ToSql()
assert.Error(t, err)
_, _, err = Update("x").ToSql()
assert.Error(t, err)
}
func TestUpdateBuilderMustSql(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("TestUpdateBuilderMustSql should have panicked!")
}
}()
Update("").MustSql()
}
func TestUpdateBuilderPlaceholders(t *testing.T) {
b := Update("test").SetMap(Eq{"x": 1, "y": 2})
sql, _, _ := b.PlaceholderFormat(Question).ToSql()
assert.Equal(t, "UPDATE test SET x = ?, y = ?", sql)
sql, _, _ = b.PlaceholderFormat(Dollar).ToSql()
assert.Equal(t, "UPDATE test SET x = $1, y = $2", sql)
}
func TestUpdateBuilderRunners(t *testing.T) {
db := &DBStub{}
b := Update("test").Set("x", 1).RunWith(db)
expectedSql := "UPDATE test SET x = ?"
b.Exec()
assert.Equal(t, expectedSql, db.LastExecSql)
}
func TestUpdateBuilderNoRunner(t *testing.T) {
b := Update("test").Set("x", 1)
_, err := b.Exec()
assert.Equal(t, RunnerNotSet, err)
}
func TestUpdateBuilderFrom(t *testing.T) {
sql, _, err := Update("employees").Set("sales_count", 100).From("accounts").Where("accounts.name = ?", "ACME").ToSql()
assert.NoError(t, err)
assert.Equal(t, "UPDATE employees SET sales_count = ? FROM accounts WHERE accounts.name = ?", sql)
}
func TestUpdateBuilderFromSelect(t *testing.T) {
sql, _, err := Update("employees").
Set("sales_count", 100).
FromSelect(Select("id").
From("accounts").
Where("accounts.name = ?", "ACME"), "subquery").
Where("employees.account_id = subquery.id").ToSql()
assert.NoError(t, err)
expectedSql :=
"UPDATE employees " +
"SET sales_count = ? " +
"FROM (SELECT id FROM accounts WHERE accounts.name = ?) AS subquery " +
"WHERE employees.account_id = subquery.id"
assert.Equal(t, expectedSql, sql)
}
================================================
FILE: where.go
================================================
package squirrel
import (
"fmt"
)
type wherePart part
func newWherePart(pred interface{}, args ...interface{}) Sqlizer {
return &wherePart{pred: pred, args: args}
}
func (p wherePart) ToSql() (sql string, args []interface{}, err error) {
switch pred := p.pred.(type) {
case nil:
// no-op
case rawSqlizer:
return pred.toSqlRaw()
case Sqlizer:
return pred.ToSql()
case map[string]interface{}:
return Eq(pred).ToSql()
case string:
sql = pred
args = p.args
default:
err = fmt.Errorf("expected string-keyed map or string, not %T", pred)
}
return
}
================================================
FILE: where_test.go
================================================
package squirrel
import (
"testing"
"bytes"
"github.com/stretchr/testify/assert"
)
func TestWherePartsAppendToSql(t *testing.T) {
parts := []Sqlizer{
newWherePart("x = ?", 1),
newWherePart(nil),
newWherePart(Eq{"y": 2}),
}
sql := &bytes.Buffer{}
args, _ := appendToSql(parts, sql, " AND ", []interface{}{})
assert.Equal(t, "x = ? AND y = ?", sql.String())
assert.Equal(t, []interface{}{1, 2}, args)
}
func TestWherePartsAppendToSqlErr(t *testing.T) {
parts := []Sqlizer{newWherePart(1)}
_, err := appendToSql(parts, &bytes.Buffer{}, "", []interface{}{})
assert.Error(t, err)
}
func TestWherePartNil(t *testing.T) {
sql, _, _ := newWherePart(nil).ToSql()
assert.Equal(t, "", sql)
}
func TestWherePartErr(t *testing.T) {
_, _, err := newWherePart(1).ToSql()
assert.Error(t, err)
}
func TestWherePartString(t *testing.T) {
sql, args, _ := newWherePart("x = ?", 1).ToSql()
assert.Equal(t, "x = ?", sql)
assert.Equal(t, []interface{}{1}, args)
}
func TestWherePartMap(t *testing.T) {
test := func(pred interface{}) {
sql, _, _ := newWherePart(pred).ToSql()
expect := []string{"x = ? AND y = ?", "y = ? AND x = ?"}
if sql != expect[0] && sql != expect[1] {
t.Errorf("expected one of %#v, got %#v", expect, sql)
}
}
m := map[string]interface{}{"x": 1, "y": 2}
test(m)
test(Eq(m))
}
gitextract_422pidv7/ ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── case.go ├── case_test.go ├── delete.go ├── delete_ctx.go ├── delete_ctx_test.go ├── delete_test.go ├── expr.go ├── expr_test.go ├── go.mod ├── go.sum ├── insert.go ├── insert_ctx.go ├── insert_ctx_test.go ├── insert_test.go ├── integration/ │ ├── doc.go │ ├── go.mod │ ├── go.sum │ └── integration_test.go ├── part.go ├── placeholder.go ├── placeholder_test.go ├── row.go ├── row_test.go ├── select.go ├── select_ctx.go ├── select_ctx_test.go ├── select_test.go ├── squirrel.go ├── squirrel_ctx.go ├── squirrel_ctx_test.go ├── squirrel_test.go ├── statement.go ├── statement_test.go ├── stmtcacher.go ├── stmtcacher_ctx.go ├── stmtcacher_ctx_test.go ├── stmtcacher_noctx.go ├── stmtcacher_test.go ├── update.go ├── update_ctx.go ├── update_ctx_test.go ├── update_test.go ├── where.go └── where_test.go
SYMBOL INDEX (475 symbols across 39 files)
FILE: case.go
function init (line 10) | func init() {
type sqlizerBuffer (line 16) | type sqlizerBuffer struct
method WriteSql (line 23) | func (b *sqlizerBuffer) WriteSql(item Sqlizer) {
method ToSql (line 41) | func (b *sqlizerBuffer) ToSql() (string, []interface{}, error) {
type whenPart (line 46) | type whenPart struct
function newWhenPart (line 51) | func newWhenPart(when interface{}, then interface{}) whenPart {
type caseData (line 56) | type caseData struct
method ToSql (line 63) | func (d *caseData) ToSql() (sqlStr string, args []interface{}, err err...
type CaseBuilder (line 95) | type CaseBuilder
method ToSql (line 98) | func (b CaseBuilder) ToSql() (string, []interface{}, error) {
method MustSql (line 105) | func (b CaseBuilder) MustSql() (string, []interface{}) {
method what (line 114) | func (b CaseBuilder) what(expr interface{}) CaseBuilder {
method When (line 119) | func (b CaseBuilder) When(when interface{}, then interface{}) CaseBuil...
method Else (line 126) | func (b CaseBuilder) Else(expr interface{}) CaseBuilder {
FILE: case_test.go
function TestCaseWithVal (line 9) | func TestCaseWithVal(t *testing.T) {
function TestCaseWithComplexVal (line 34) | func TestCaseWithComplexVal(t *testing.T) {
function TestCaseWithNoVal (line 55) | func TestCaseWithNoVal(t *testing.T) {
function TestCaseWithExpr (line 77) | func TestCaseWithExpr(t *testing.T) {
function TestMultipleCase (line 99) | func TestMultipleCase(t *testing.T) {
function TestCaseWithNoWhenClause (line 130) | func TestCaseWithNoWhenClause(t *testing.T) {
function TestCaseBuilderMustSql (line 143) | func TestCaseBuilderMustSql(t *testing.T) {
FILE: delete.go
type deleteData (line 12) | type deleteData struct
method Exec (line 24) | func (d *deleteData) Exec() (sql.Result, error) {
method ToSql (line 31) | func (d *deleteData) ToSql() (sqlStr string, args []interface{}, err e...
method Query (line 186) | func (d *deleteData) Query() (*sql.Rows, error) {
type DeleteBuilder (line 89) | type DeleteBuilder
method PlaceholderFormat (line 99) | func (b DeleteBuilder) PlaceholderFormat(f PlaceholderFormat) DeleteBu...
method RunWith (line 106) | func (b DeleteBuilder) RunWith(runner BaseRunner) DeleteBuilder {
method Exec (line 111) | func (b DeleteBuilder) Exec() (sql.Result, error) {
method ToSql (line 119) | func (b DeleteBuilder) ToSql() (string, []interface{}, error) {
method MustSql (line 126) | func (b DeleteBuilder) MustSql() (string, []interface{}) {
method Prefix (line 135) | func (b DeleteBuilder) Prefix(sql string, args ...interface{}) DeleteB...
method PrefixExpr (line 140) | func (b DeleteBuilder) PrefixExpr(expr Sqlizer) DeleteBuilder {
method From (line 145) | func (b DeleteBuilder) From(from string) DeleteBuilder {
method Where (line 152) | func (b DeleteBuilder) Where(pred interface{}, args ...interface{}) De...
method OrderBy (line 157) | func (b DeleteBuilder) OrderBy(orderBys ...string) DeleteBuilder {
method Limit (line 162) | func (b DeleteBuilder) Limit(limit uint64) DeleteBuilder {
method Offset (line 167) | func (b DeleteBuilder) Offset(offset uint64) DeleteBuilder {
method Suffix (line 172) | func (b DeleteBuilder) Suffix(sql string, args ...interface{}) DeleteB...
method SuffixExpr (line 177) | func (b DeleteBuilder) SuffixExpr(expr Sqlizer) DeleteBuilder {
method Query (line 181) | func (b DeleteBuilder) Query() (*sql.Rows, error) {
function init (line 91) | func init() {
FILE: delete_ctx.go
method ExecContext (line 12) | func (d *deleteData) ExecContext(ctx context.Context) (sql.Result, error) {
method QueryContext (line 23) | func (d *deleteData) QueryContext(ctx context.Context) (*sql.Rows, error) {
method QueryRowContext (line 34) | func (d *deleteData) QueryRowContext(ctx context.Context) RowScanner {
method ExecContext (line 49) | func (b DeleteBuilder) ExecContext(ctx context.Context) (sql.Result, err...
method QueryContext (line 55) | func (b DeleteBuilder) QueryContext(ctx context.Context) (*sql.Rows, err...
method QueryRowContext (line 61) | func (b DeleteBuilder) QueryRowContext(ctx context.Context) RowScanner {
method ScanContext (line 67) | func (b DeleteBuilder) ScanContext(ctx context.Context, dest ...interfac...
FILE: delete_ctx_test.go
function TestDeleteBuilderContextRunners (line 11) | func TestDeleteBuilderContextRunners(t *testing.T) {
function TestDeleteBuilderContextNoRunner (line 30) | func TestDeleteBuilderContextNoRunner(t *testing.T) {
FILE: delete_test.go
function TestDeleteBuilderToSql (line 9) | func TestDeleteBuilderToSql(t *testing.T) {
function TestDeleteBuilderToSqlErr (line 32) | func TestDeleteBuilderToSqlErr(t *testing.T) {
function TestDeleteBuilderMustSql (line 37) | func TestDeleteBuilderMustSql(t *testing.T) {
function TestDeleteBuilderPlaceholders (line 46) | func TestDeleteBuilderPlaceholders(t *testing.T) {
function TestDeleteBuilderRunners (line 56) | func TestDeleteBuilderRunners(t *testing.T) {
function TestDeleteBuilderNoRunner (line 66) | func TestDeleteBuilderNoRunner(t *testing.T) {
function TestDeleteWithQuery (line 73) | func TestDeleteWithQuery(t *testing.T) {
FILE: expr.go
constant sqlTrue (line 14) | sqlTrue = "(1=1)"
constant sqlFalse (line 15) | sqlFalse = "(1=0)"
type expr (line 18) | type expr struct
method ToSql (line 31) | func (e expr) ToSql() (sql string, args []interface{}, err error) {
function Expr (line 27) | func Expr(sql string, args ...interface{}) Sqlizer {
type concatExpr (line 84) | type concatExpr
method ToSql (line 86) | func (ce concatExpr) ToSql() (sql string, args []interface{}, err erro...
function ConcatExpr (line 110) | func ConcatExpr(parts ...interface{}) concatExpr {
type aliasExpr (line 115) | type aliasExpr struct
method ToSql (line 128) | func (e aliasExpr) ToSql() (sql string, args []interface{}, err error) {
function Alias (line 124) | func Alias(expr Sqlizer, alias string) aliasExpr {
type Eq (line 137) | type Eq
method toSQL (line 139) | func (eq Eq) toSQL(useNotOpr bool) (sql string, args []interface{}, er...
method ToSql (line 209) | func (eq Eq) ToSql() (sql string, args []interface{}, err error) {
type NotEq (line 216) | type NotEq
method ToSql (line 218) | func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {
type Like (line 225) | type Like
method toSql (line 227) | func (lk Like) toSql(opr string) (sql string, args []interface{}, err ...
method ToSql (line 257) | func (lk Like) ToSql() (sql string, args []interface{}, err error) {
type NotLike (line 264) | type NotLike
method ToSql (line 266) | func (nlk NotLike) ToSql() (sql string, args []interface{}, err error) {
type ILike (line 273) | type ILike
method ToSql (line 275) | func (ilk ILike) ToSql() (sql string, args []interface{}, err error) {
type NotILike (line 282) | type NotILike
method ToSql (line 284) | func (nilk NotILike) ToSql() (sql string, args []interface{}, err erro...
type Lt (line 291) | type Lt
method toSql (line 293) | func (lt Lt) toSql(opposite, orEq bool) (sql string, args []interface{...
method ToSql (line 336) | func (lt Lt) ToSql() (sql string, args []interface{}, err error) {
type LtOrEq (line 343) | type LtOrEq
method ToSql (line 345) | func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err erro...
type Gt (line 352) | type Gt
method ToSql (line 354) | func (gt Gt) ToSql() (sql string, args []interface{}, err error) {
type GtOrEq (line 361) | type GtOrEq
method ToSql (line 363) | func (gtOrEq GtOrEq) ToSql() (sql string, args []interface{}, err erro...
type conj (line 367) | type conj
method join (line 369) | func (c conj) join(sep, defaultExpr string) (sql string, args []interf...
type And (line 391) | type And
method ToSql (line 393) | func (a And) ToSql() (string, []interface{}, error) {
type Or (line 398) | type Or
method ToSql (line 400) | func (o Or) ToSql() (string, []interface{}, error) {
function getSortedKeys (line 404) | func getSortedKeys(exp map[string]interface{}) []string {
function isListType (line 413) | func isListType(val interface{}) bool {
FILE: expr_test.go
function TestConcatExpr (line 10) | func TestConcatExpr(t *testing.T) {
function TestConcatExprBadType (line 22) | func TestConcatExprBadType(t *testing.T) {
function TestEqToSql (line 29) | func TestEqToSql(t *testing.T) {
function TestEqEmptyToSql (line 41) | func TestEqEmptyToSql(t *testing.T) {
function TestEqInToSql (line 50) | func TestEqInToSql(t *testing.T) {
function TestNotEqToSql (line 62) | func TestNotEqToSql(t *testing.T) {
function TestEqNotInToSql (line 74) | func TestEqNotInToSql(t *testing.T) {
function TestEqInEmptyToSql (line 86) | func TestEqInEmptyToSql(t *testing.T) {
function TestNotEqInEmptyToSql (line 98) | func TestNotEqInEmptyToSql(t *testing.T) {
function TestEqBytesToSql (line 110) | func TestEqBytesToSql(t *testing.T) {
function TestLtToSql (line 122) | func TestLtToSql(t *testing.T) {
function TestLtOrEqToSql (line 134) | func TestLtOrEqToSql(t *testing.T) {
function TestGtToSql (line 146) | func TestGtToSql(t *testing.T) {
function TestGtOrEqToSql (line 158) | func TestGtOrEqToSql(t *testing.T) {
function TestExprNilToSql (line 170) | func TestExprNilToSql(t *testing.T) {
function TestNullTypeString (line 189) | func TestNullTypeString(t *testing.T) {
function TestNullTypeInt64 (line 209) | func TestNullTypeInt64(t *testing.T) {
function TestNilPointer (line 228) | func TestNilPointer(t *testing.T) {
function TestNotNilPointer (line 272) | func TestNotNilPointer(t *testing.T) {
function TestEmptyAndToSql (line 318) | func TestEmptyAndToSql(t *testing.T) {
function TestEmptyOrToSql (line 329) | func TestEmptyOrToSql(t *testing.T) {
function TestLikeToSql (line 340) | func TestLikeToSql(t *testing.T) {
function TestNotLikeToSql (line 352) | func TestNotLikeToSql(t *testing.T) {
function TestILikeToSql (line 364) | func TestILikeToSql(t *testing.T) {
function TestNotILikeToSql (line 376) | func TestNotILikeToSql(t *testing.T) {
function TestSqlEqOrder (line 388) | func TestSqlEqOrder(t *testing.T) {
function TestSqlLtOrder (line 400) | func TestSqlLtOrder(t *testing.T) {
function TestExprEscaped (line 412) | func TestExprEscaped(t *testing.T) {
function TestExprRecursion (line 424) | func TestExprRecursion(t *testing.T) {
function ExampleEq (line 460) | func ExampleEq() {
FILE: insert.go
type insertData (line 15) | type insertData struct
method Exec (line 28) | func (d *insertData) Exec() (sql.Result, error) {
method Query (line 35) | func (d *insertData) Query() (*sql.Rows, error) {
method QueryRow (line 42) | func (d *insertData) QueryRow() RowScanner {
method ToSql (line 53) | func (d *insertData) ToSql() (sqlStr string, args []interface{}, err e...
method appendValuesToSQL (line 117) | func (d *insertData) appendValuesToSQL(w io.Writer, args []interface{}...
method appendSelectToSQL (line 148) | func (d *insertData) appendSelectToSQL(w io.Writer, args []interface{}...
type InsertBuilder (line 167) | type InsertBuilder
method PlaceholderFormat (line 177) | func (b InsertBuilder) PlaceholderFormat(f PlaceholderFormat) InsertBu...
method RunWith (line 184) | func (b InsertBuilder) RunWith(runner BaseRunner) InsertBuilder {
method Exec (line 189) | func (b InsertBuilder) Exec() (sql.Result, error) {
method Query (line 195) | func (b InsertBuilder) Query() (*sql.Rows, error) {
method QueryRow (line 201) | func (b InsertBuilder) QueryRow() RowScanner {
method Scan (line 207) | func (b InsertBuilder) Scan(dest ...interface{}) error {
method ToSql (line 214) | func (b InsertBuilder) ToSql() (string, []interface{}, error) {
method MustSql (line 221) | func (b InsertBuilder) MustSql() (string, []interface{}) {
method Prefix (line 230) | func (b InsertBuilder) Prefix(sql string, args ...interface{}) InsertB...
method PrefixExpr (line 235) | func (b InsertBuilder) PrefixExpr(expr Sqlizer) InsertBuilder {
method Options (line 240) | func (b InsertBuilder) Options(options ...string) InsertBuilder {
method Into (line 245) | func (b InsertBuilder) Into(into string) InsertBuilder {
method Columns (line 250) | func (b InsertBuilder) Columns(columns ...string) InsertBuilder {
method Values (line 255) | func (b InsertBuilder) Values(values ...interface{}) InsertBuilder {
method Suffix (line 260) | func (b InsertBuilder) Suffix(sql string, args ...interface{}) InsertB...
method SuffixExpr (line 265) | func (b InsertBuilder) SuffixExpr(expr Sqlizer) InsertBuilder {
method SetMap (line 271) | func (b InsertBuilder) SetMap(clauses map[string]interface{}) InsertBu...
method Select (line 292) | func (b InsertBuilder) Select(sb SelectBuilder) InsertBuilder {
method statementKeyword (line 296) | func (b InsertBuilder) statementKeyword(keyword string) InsertBuilder {
function init (line 169) | func init() {
FILE: insert_ctx.go
method ExecContext (line 12) | func (d *insertData) ExecContext(ctx context.Context) (sql.Result, error) {
method QueryContext (line 23) | func (d *insertData) QueryContext(ctx context.Context) (*sql.Rows, error) {
method QueryRowContext (line 34) | func (d *insertData) QueryRowContext(ctx context.Context) RowScanner {
method ExecContext (line 49) | func (b InsertBuilder) ExecContext(ctx context.Context) (sql.Result, err...
method QueryContext (line 55) | func (b InsertBuilder) QueryContext(ctx context.Context) (*sql.Rows, err...
method QueryRowContext (line 61) | func (b InsertBuilder) QueryRowContext(ctx context.Context) RowScanner {
method ScanContext (line 67) | func (b InsertBuilder) ScanContext(ctx context.Context, dest ...interfac...
FILE: insert_ctx_test.go
function TestInsertBuilderContextRunners (line 11) | func TestInsertBuilderContextRunners(t *testing.T) {
function TestInsertBuilderContextNoRunner (line 30) | func TestInsertBuilderContextNoRunner(t *testing.T) {
FILE: insert_test.go
function TestInsertBuilderToSql (line 9) | func TestInsertBuilderToSql(t *testing.T) {
function TestInsertBuilderToSqlErr (line 32) | func TestInsertBuilderToSqlErr(t *testing.T) {
function TestInsertBuilderMustSql (line 40) | func TestInsertBuilderMustSql(t *testing.T) {
function TestInsertBuilderPlaceholders (line 49) | func TestInsertBuilderPlaceholders(t *testing.T) {
function TestInsertBuilderRunners (line 59) | func TestInsertBuilderRunners(t *testing.T) {
function TestInsertBuilderNoRunner (line 69) | func TestInsertBuilderNoRunner(t *testing.T) {
function TestInsertBuilderSetMap (line 76) | func TestInsertBuilderSetMap(t *testing.T) {
function TestInsertBuilderSelect (line 89) | func TestInsertBuilderSelect(t *testing.T) {
function TestInsertBuilderReplace (line 103) | func TestInsertBuilderReplace(t *testing.T) {
FILE: integration/integration_test.go
constant testSchema (line 21) | testSchema = `
constant testData (line 23) | testData = `
function TestMain (line 36) | func TestMain(m *testing.M) {
function assertVals (line 82) | func assertVals(t *testing.T, s sqrl.SelectBuilder, expected ...string) {
function TestSimpleSelect (line 99) | func TestSimpleSelect(t *testing.T) {
function TestEq (line 106) | func TestEq(t *testing.T) {
function TestIneq (line 118) | func TestIneq(t *testing.T) {
function TestConj (line 124) | func TestConj(t *testing.T) {
function TestContext (line 130) | func TestContext(t *testing.T) {
FILE: part.go
type part (line 8) | type part struct
method ToSql (line 17) | func (p part) ToSql() (sql string, args []interface{}, err error) {
function newPart (line 13) | func newPart(pred interface{}, args ...interface{}) Sqlizer {
function nestedToSql (line 32) | func nestedToSql(s Sqlizer) (string, []interface{}, error) {
function appendToSql (line 40) | func appendToSql(parts []Sqlizer, w io.Writer, sep string, args []interf...
FILE: placeholder.go
type PlaceholderFormat (line 13) | type PlaceholderFormat interface
type placeholderDebugger (line 17) | type placeholderDebugger interface
type questionFormat (line 39) | type questionFormat struct
method ReplacePlaceholders (line 41) | func (questionFormat) ReplacePlaceholders(sql string) (string, error) {
method debugPlaceholder (line 45) | func (questionFormat) debugPlaceholder() string {
type dollarFormat (line 49) | type dollarFormat struct
method ReplacePlaceholders (line 51) | func (dollarFormat) ReplacePlaceholders(sql string) (string, error) {
method debugPlaceholder (line 55) | func (dollarFormat) debugPlaceholder() string {
type colonFormat (line 59) | type colonFormat struct
method ReplacePlaceholders (line 61) | func (colonFormat) ReplacePlaceholders(sql string) (string, error) {
method debugPlaceholder (line 65) | func (colonFormat) debugPlaceholder() string {
type atpFormat (line 69) | type atpFormat struct
method ReplacePlaceholders (line 71) | func (atpFormat) ReplacePlaceholders(sql string) (string, error) {
method debugPlaceholder (line 75) | func (atpFormat) debugPlaceholder() string {
function Placeholders (line 80) | func Placeholders(count int) string {
function replacePositionalPlaceholders (line 88) | func replacePositionalPlaceholders(sql, prefix string) (string, error) {
FILE: placeholder_test.go
function TestQuestion (line 10) | func TestQuestion(t *testing.T) {
function TestDollar (line 16) | func TestDollar(t *testing.T) {
function TestColon (line 22) | func TestColon(t *testing.T) {
function TestAtp (line 28) | func TestAtp(t *testing.T) {
function TestPlaceholders (line 34) | func TestPlaceholders(t *testing.T) {
function TestEscapeDollar (line 38) | func TestEscapeDollar(t *testing.T) {
function TestEscapeColon (line 44) | func TestEscapeColon(t *testing.T) {
function TestEscapeAtp (line 50) | func TestEscapeAtp(t *testing.T) {
function BenchmarkPlaceholdersArray (line 56) | func BenchmarkPlaceholdersArray(b *testing.B) {
function BenchmarkPlaceholdersStrings (line 65) | func BenchmarkPlaceholdersStrings(b *testing.B) {
FILE: row.go
type RowScanner (line 6) | type RowScanner interface
type Row (line 11) | type Row struct
method Scan (line 17) | func (r *Row) Scan(dest ...interface{}) error {
FILE: row_test.go
type RowStub (line 10) | type RowStub struct
method Scan (line 14) | func (r *RowStub) Scan(_ ...interface{}) error {
function TestRowScan (line 19) | func TestRowScan(t *testing.T) {
function TestRowScanErr (line 27) | func TestRowScanErr(t *testing.T) {
FILE: select.go
type selectData (line 12) | type selectData struct
method Exec (line 29) | func (d *selectData) Exec() (sql.Result, error) {
method Query (line 36) | func (d *selectData) Query() (*sql.Rows, error) {
method QueryRow (line 43) | func (d *selectData) QueryRow() RowScanner {
method ToSql (line 54) | func (d *selectData) ToSql() (sqlStr string, args []interface{}, err e...
method toSqlRaw (line 64) | func (d *selectData) toSqlRaw() (sqlStr string, args []interface{}, er...
type SelectBuilder (line 166) | type SelectBuilder
method PlaceholderFormat (line 176) | func (b SelectBuilder) PlaceholderFormat(f PlaceholderFormat) SelectBu...
method RunWith (line 186) | func (b SelectBuilder) RunWith(runner BaseRunner) SelectBuilder {
method Exec (line 191) | func (b SelectBuilder) Exec() (sql.Result, error) {
method Query (line 197) | func (b SelectBuilder) Query() (*sql.Rows, error) {
method QueryRow (line 203) | func (b SelectBuilder) QueryRow() RowScanner {
method Scan (line 209) | func (b SelectBuilder) Scan(dest ...interface{}) error {
method ToSql (line 216) | func (b SelectBuilder) ToSql() (string, []interface{}, error) {
method toSqlRaw (line 221) | func (b SelectBuilder) toSqlRaw() (string, []interface{}, error) {
method MustSql (line 228) | func (b SelectBuilder) MustSql() (string, []interface{}) {
method Prefix (line 237) | func (b SelectBuilder) Prefix(sql string, args ...interface{}) SelectB...
method PrefixExpr (line 242) | func (b SelectBuilder) PrefixExpr(expr Sqlizer) SelectBuilder {
method Distinct (line 247) | func (b SelectBuilder) Distinct() SelectBuilder {
method Options (line 252) | func (b SelectBuilder) Options(options ...string) SelectBuilder {
method Columns (line 257) | func (b SelectBuilder) Columns(columns ...string) SelectBuilder {
method RemoveColumns (line 268) | func (b SelectBuilder) RemoveColumns() SelectBuilder {
method Column (line 276) | func (b SelectBuilder) Column(column interface{}, args ...interface{})...
method From (line 281) | func (b SelectBuilder) From(from string) SelectBuilder {
method FromSelect (line 286) | func (b SelectBuilder) FromSelect(from SelectBuilder, alias string) Se...
method JoinClause (line 293) | func (b SelectBuilder) JoinClause(pred interface{}, args ...interface{...
method Join (line 298) | func (b SelectBuilder) Join(join string, rest ...interface{}) SelectBu...
method LeftJoin (line 303) | func (b SelectBuilder) LeftJoin(join string, rest ...interface{}) Sele...
method RightJoin (line 308) | func (b SelectBuilder) RightJoin(join string, rest ...interface{}) Sel...
method InnerJoin (line 313) | func (b SelectBuilder) InnerJoin(join string, rest ...interface{}) Sel...
method CrossJoin (line 318) | func (b SelectBuilder) CrossJoin(join string, rest ...interface{}) Sel...
method Where (line 342) | func (b SelectBuilder) Where(pred interface{}, args ...interface{}) Se...
method GroupBy (line 350) | func (b SelectBuilder) GroupBy(groupBys ...string) SelectBuilder {
method Having (line 357) | func (b SelectBuilder) Having(pred interface{}, rest ...interface{}) S...
method OrderByClause (line 362) | func (b SelectBuilder) OrderByClause(pred interface{}, args ...interfa...
method OrderBy (line 367) | func (b SelectBuilder) OrderBy(orderBys ...string) SelectBuilder {
method Limit (line 376) | func (b SelectBuilder) Limit(limit uint64) SelectBuilder {
method RemoveLimit (line 381) | func (b SelectBuilder) RemoveLimit() SelectBuilder {
method Offset (line 386) | func (b SelectBuilder) Offset(offset uint64) SelectBuilder {
method RemoveOffset (line 391) | func (b SelectBuilder) RemoveOffset() SelectBuilder {
method Suffix (line 396) | func (b SelectBuilder) Suffix(sql string, args ...interface{}) SelectB...
method SuffixExpr (line 401) | func (b SelectBuilder) SuffixExpr(expr Sqlizer) SelectBuilder {
function init (line 168) | func init() {
FILE: select_ctx.go
method ExecContext (line 12) | func (d *selectData) ExecContext(ctx context.Context) (sql.Result, error) {
method QueryContext (line 23) | func (d *selectData) QueryContext(ctx context.Context) (*sql.Rows, error) {
method QueryRowContext (line 34) | func (d *selectData) QueryRowContext(ctx context.Context) RowScanner {
method ExecContext (line 49) | func (b SelectBuilder) ExecContext(ctx context.Context) (sql.Result, err...
method QueryContext (line 55) | func (b SelectBuilder) QueryContext(ctx context.Context) (*sql.Rows, err...
method QueryRowContext (line 61) | func (b SelectBuilder) QueryRowContext(ctx context.Context) RowScanner {
method ScanContext (line 67) | func (b SelectBuilder) ScanContext(ctx context.Context, dest ...interfac...
FILE: select_ctx_test.go
function TestSelectBuilderContextRunners (line 11) | func TestSelectBuilderContextRunners(t *testing.T) {
function TestSelectBuilderContextNoRunner (line 30) | func TestSelectBuilderContextNoRunner(t *testing.T) {
FILE: select_test.go
function TestSelectBuilderToSql (line 13) | func TestSelectBuilderToSql(t *testing.T) {
function TestSelectBuilderFromSelect (line 62) | func TestSelectBuilderFromSelect(t *testing.T) {
function TestSelectBuilderFromSelectNestedDollarPlaceholders (line 75) | func TestSelectBuilderFromSelectNestedDollarPlaceholders(t *testing.T) {
function TestSelectBuilderToSqlErr (line 94) | func TestSelectBuilderToSqlErr(t *testing.T) {
function TestSelectBuilderPlaceholders (line 99) | func TestSelectBuilderPlaceholders(t *testing.T) {
function TestSelectBuilderRunners (line 115) | func TestSelectBuilderRunners(t *testing.T) {
function TestSelectBuilderNoRunner (line 134) | func TestSelectBuilderNoRunner(t *testing.T) {
function TestSelectBuilderSimpleJoin (line 147) | func TestSelectBuilderSimpleJoin(t *testing.T) {
function TestSelectBuilderParamJoin (line 161) | func TestSelectBuilderParamJoin(t *testing.T) {
function TestSelectBuilderNestedSelectJoin (line 175) | func TestSelectBuilderNestedSelectJoin(t *testing.T) {
function TestSelectWithOptions (line 191) | func TestSelectWithOptions(t *testing.T) {
function TestSelectWithRemoveLimit (line 198) | func TestSelectWithRemoveLimit(t *testing.T) {
function TestSelectWithRemoveOffset (line 205) | func TestSelectWithRemoveOffset(t *testing.T) {
function TestSelectBuilderNestedSelectDollar (line 212) | func TestSelectBuilderNestedSelectDollar(t *testing.T) {
function TestSelectBuilderMustSql (line 222) | func TestSelectBuilderMustSql(t *testing.T) {
function TestSelectWithoutWhereClause (line 232) | func TestSelectWithoutWhereClause(t *testing.T) {
function TestSelectWithNilWhereClause (line 238) | func TestSelectWithNilWhereClause(t *testing.T) {
function TestSelectWithEmptyStringWhereClause (line 244) | func TestSelectWithEmptyStringWhereClause(t *testing.T) {
function TestSelectSubqueryPlaceholderNumbering (line 250) | func TestSelectSubqueryPlaceholderNumbering(t *testing.T) {
function TestSelectSubqueryInConjunctionPlaceholderNumbering (line 267) | func TestSelectSubqueryInConjunctionPlaceholderNumbering(t *testing.T) {
function TestSelectJoinClausePlaceholderNumbering (line 282) | func TestSelectJoinClausePlaceholderNumbering(t *testing.T) {
function ExampleSelect (line 298) | func ExampleSelect() {
function ExampleSelectBuilder_From (line 308) | func ExampleSelectBuilder_From() {
function ExampleSelectBuilder_Where (line 312) | func ExampleSelectBuilder_Where() {
function ExampleSelectBuilder_Where_helpers (line 317) | func ExampleSelectBuilder_Where_helpers() {
function ExampleSelectBuilder_Where_multiple (line 338) | func ExampleSelectBuilder_Where_multiple() {
function ExampleSelectBuilder_FromSelect (line 351) | func ExampleSelectBuilder_FromSelect() {
function ExampleSelectBuilder_Columns (line 363) | func ExampleSelectBuilder_Columns() {
function ExampleSelectBuilder_Columns_order (line 371) | func ExampleSelectBuilder_Columns_order() {
function ExampleSelectBuilder_Scan (line 380) | func ExampleSelectBuilder_Scan() {
function ExampleSelectBuilder_ScanContext (line 397) | func ExampleSelectBuilder_ScanContext() {
function ExampleSelectBuilder_RunWith (line 414) | func ExampleSelectBuilder_RunWith() {
function ExampleSelectBuilder_ToSql (line 430) | func ExampleSelectBuilder_ToSql() {
function TestRemoveColumns (line 455) | func TestRemoveColumns(t *testing.T) {
FILE: squirrel.go
type Sqlizer (line 19) | type Sqlizer interface
type rawSqlizer (line 25) | type rawSqlizer interface
type Execer (line 32) | type Execer interface
type Queryer (line 39) | type Queryer interface
type QueryRower (line 46) | type QueryRower interface
type BaseRunner (line 51) | type BaseRunner interface
type Runner (line 57) | type Runner interface
function WrapStdSql (line 65) | func WrapStdSql(stdSql StdSql) Runner {
type StdSql (line 71) | type StdSql interface
type stdsqlRunner (line 77) | type stdsqlRunner struct
method QueryRow (line 81) | func (r *stdsqlRunner) QueryRow(query string, args ...interface{}) Row...
function setRunWith (line 85) | func setRunWith(b interface{}, runner BaseRunner) interface{} {
function ExecWith (line 102) | func ExecWith(db Execer, s Sqlizer) (res sql.Result, err error) {
function QueryWith (line 111) | func QueryWith(db Queryer, s Sqlizer) (rows *sql.Rows, err error) {
function QueryRowWith (line 120) | func QueryRowWith(db QueryRower, s Sqlizer) RowScanner {
function DebugSqlizer (line 134) | func DebugSqlizer(s Sqlizer) string {
FILE: squirrel_ctx.go
type ExecerContext (line 17) | type ExecerContext interface
type QueryerContext (line 24) | type QueryerContext interface
type QueryRowerContext (line 31) | type QueryRowerContext interface
type RunnerContext (line 37) | type RunnerContext interface
function WrapStdSqlCtx (line 46) | func WrapStdSqlCtx(stdSqlCtx StdSqlCtx) RunnerContext {
type StdSqlCtx (line 52) | type StdSqlCtx interface
type stdsqlCtxRunner (line 59) | type stdsqlCtxRunner struct
method QueryRow (line 63) | func (r *stdsqlCtxRunner) QueryRow(query string, args ...interface{}) ...
method QueryRowContext (line 67) | func (r *stdsqlCtxRunner) QueryRowContext(ctx context.Context, query s...
function ExecContextWith (line 72) | func ExecContextWith(ctx context.Context, db ExecerContext, s Sqlizer) (...
function QueryContextWith (line 81) | func QueryContextWith(ctx context.Context, db QueryerContext, s Sqlizer)...
function QueryRowContextWith (line 90) | func QueryRowContextWith(ctx context.Context, db QueryRowerContext, s Sq...
FILE: squirrel_ctx_test.go
method PrepareContext (line 13) | func (s *DBStub) PrepareContext(ctx context.Context, query string) (*sql...
method ExecContext (line 19) | func (s *DBStub) ExecContext(ctx context.Context, query string, args ......
method QueryContext (line 25) | func (s *DBStub) QueryContext(ctx context.Context, query string, args .....
method QueryRowContext (line 31) | func (s *DBStub) QueryRowContext(ctx context.Context, query string, args...
function TestExecContextWith (line 39) | func TestExecContextWith(t *testing.T) {
function TestQueryContextWith (line 45) | func TestQueryContextWith(t *testing.T) {
function TestQueryRowContextWith (line 51) | func TestQueryRowContextWith(t *testing.T) {
FILE: squirrel_test.go
type DBStub (line 12) | type DBStub struct
method Prepare (line 30) | func (s *DBStub) Prepare(query string) (*sql.Stmt, error) {
method Exec (line 36) | func (s *DBStub) Exec(query string, args ...interface{}) (sql.Result, ...
method Query (line 42) | func (s *DBStub) Query(query string, args ...interface{}) (*sql.Rows, ...
method QueryRow (line 48) | func (s *DBStub) QueryRow(query string, args ...interface{}) RowScanner {
function TestExecWith (line 57) | func TestExecWith(t *testing.T) {
function TestQueryWith (line 63) | func TestQueryWith(t *testing.T) {
function TestQueryRowWith (line 69) | func TestQueryRowWith(t *testing.T) {
function TestWithToSqlErr (line 75) | func TestWithToSqlErr(t *testing.T) {
function TestDebugSqlizerUpdateColon (line 92) | func TestDebugSqlizerUpdateColon(t *testing.T) {
function TestDebugSqlizerUpdateAtp (line 97) | func TestDebugSqlizerUpdateAtp(t *testing.T) {
function TestDebugSqlizerUpdateDollar (line 102) | func TestDebugSqlizerUpdateDollar(t *testing.T) {
function TestDebugSqlizerUpdateQuestion (line 107) | func TestDebugSqlizerUpdateQuestion(t *testing.T) {
function TestDebugSqlizerDeleteColon (line 118) | func TestDebugSqlizerDeleteColon(t *testing.T) {
function TestDebugSqlizerDeleteAtp (line 123) | func TestDebugSqlizerDeleteAtp(t *testing.T) {
function TestDebugSqlizerDeleteDollar (line 128) | func TestDebugSqlizerDeleteDollar(t *testing.T) {
function TestDebugSqlizerDeleteQuestion (line 133) | func TestDebugSqlizerDeleteQuestion(t *testing.T) {
function TestDebugSqlizerInsertColon (line 141) | func TestDebugSqlizerInsertColon(t *testing.T) {
function TestDebugSqlizerInsertAtp (line 146) | func TestDebugSqlizerInsertAtp(t *testing.T) {
function TestDebugSqlizerInsertDollar (line 151) | func TestDebugSqlizerInsertDollar(t *testing.T) {
function TestDebugSqlizerInsertQuestion (line 156) | func TestDebugSqlizerInsertQuestion(t *testing.T) {
function TestDebugSqlizerSelectColon (line 167) | func TestDebugSqlizerSelectColon(t *testing.T) {
function TestDebugSqlizerSelectAtp (line 172) | func TestDebugSqlizerSelectAtp(t *testing.T) {
function TestDebugSqlizerSelectDollar (line 177) | func TestDebugSqlizerSelectDollar(t *testing.T) {
function TestDebugSqlizerSelectQuestion (line 182) | func TestDebugSqlizerSelectQuestion(t *testing.T) {
function TestDebugSqlizer (line 187) | func TestDebugSqlizer(t *testing.T) {
function TestDebugSqlizerErrors (line 193) | func TestDebugSqlizerErrors(t *testing.T) {
FILE: statement.go
type StatementBuilderType (line 6) | type StatementBuilderType
method Select (line 9) | func (b StatementBuilderType) Select(columns ...string) SelectBuilder {
method Insert (line 14) | func (b StatementBuilderType) Insert(into string) InsertBuilder {
method Replace (line 20) | func (b StatementBuilderType) Replace(into string) InsertBuilder {
method Update (line 25) | func (b StatementBuilderType) Update(table string) UpdateBuilder {
method Delete (line 30) | func (b StatementBuilderType) Delete(from string) DeleteBuilder {
method PlaceholderFormat (line 35) | func (b StatementBuilderType) PlaceholderFormat(f PlaceholderFormat) S...
method RunWith (line 40) | func (b StatementBuilderType) RunWith(runner BaseRunner) StatementBuil...
method Where (line 47) | func (b StatementBuilderType) Where(pred interface{}, args ...interfac...
function Select (line 57) | func Select(columns ...string) SelectBuilder {
function Insert (line 64) | func Insert(into string) InsertBuilder {
function Replace (line 72) | func Replace(into string) InsertBuilder {
function Update (line 79) | func Update(table string) UpdateBuilder {
function Delete (line 86) | func Delete(from string) DeleteBuilder {
function Case (line 92) | func Case(what ...interface{}) CaseBuilder {
FILE: statement_test.go
function TestStatementBuilder (line 11) | func TestStatementBuilder(t *testing.T) {
function TestStatementBuilderPlaceholderFormat (line 19) | func TestStatementBuilderPlaceholderFormat(t *testing.T) {
function TestRunWithDB (line 27) | func TestRunWithDB(t *testing.T) {
function TestRunWithTx (line 38) | func TestRunWithTx(t *testing.T) {
type fakeBaseRunner (line 48) | type fakeBaseRunner struct
method Exec (line 50) | func (fakeBaseRunner) Exec(query string, args ...interface{}) (sql.Res...
method Query (line 54) | func (fakeBaseRunner) Query(query string, args ...interface{}) (*sql.R...
function TestRunWithBaseRunner (line 58) | func TestRunWithBaseRunner(t *testing.T) {
function TestRunWithBaseRunnerQueryRowError (line 64) | func TestRunWithBaseRunnerQueryRowError(t *testing.T) {
function TestStatementBuilderWhere (line 70) | func TestStatementBuilderWhere(t *testing.T) {
FILE: stmtcacher.go
type Preparer (line 12) | type Preparer interface
type DBProxy (line 17) | type DBProxy interface
type StmtCache (line 31) | type StmtCache struct
method Prepare (line 39) | func (sc *StmtCache) Prepare(query string) (*sql.Stmt, error) {
method Exec (line 55) | func (sc *StmtCache) Exec(query string, args ...interface{}) (res sql....
method Query (line 64) | func (sc *StmtCache) Query(query string, args ...interface{}) (rows *s...
method QueryRow (line 73) | func (sc *StmtCache) QueryRow(query string, args ...interface{}) RowSc...
method Clear (line 82) | func (sc *StmtCache) Clear() (err error) {
type DBProxyBeginner (line 105) | type DBProxyBeginner interface
type stmtCacheProxy (line 110) | type stmtCacheProxy struct
method Begin (line 119) | func (sp *stmtCacheProxy) Begin() (*sql.Tx, error) {
function NewStmtCacheProxy (line 115) | func NewStmtCacheProxy(db *sql.DB) DBProxyBeginner {
FILE: stmtcacher_ctx.go
type PreparerContext (line 14) | type PreparerContext interface
type DBProxyContext (line 20) | type DBProxyContext interface
function NewStmtCache (line 30) | func NewStmtCache(prep PreparerContext) *StmtCache {
function NewStmtCacher (line 37) | func NewStmtCacher(prep PreparerContext) DBProxyContext {
method PrepareContext (line 43) | func (sc *StmtCache) PrepareContext(ctx context.Context, query string) (...
method ExecContext (line 62) | func (sc *StmtCache) ExecContext(ctx context.Context, query string, args...
method QueryContext (line 71) | func (sc *StmtCache) QueryContext(ctx context.Context, query string, arg...
method QueryRowContext (line 80) | func (sc *StmtCache) QueryRowContext(ctx context.Context, query string, ...
FILE: stmtcacher_ctx_test.go
function TestStmtCacherPrepareContext (line 11) | func TestStmtCacherPrepareContext(t *testing.T) {
FILE: stmtcacher_noctx.go
function NewStmtCache (line 12) | func NewStmtCache(prep Preparer) *StmtCache {
function NewStmtCacher (line 19) | func NewStmtCacher(prep Preparer) DBProxy {
FILE: stmtcacher_test.go
function TestStmtCachePrepare (line 9) | func TestStmtCachePrepare(t *testing.T) {
FILE: update.go
type updateData (line 13) | type updateData struct
method Exec (line 32) | func (d *updateData) Exec() (sql.Result, error) {
method Query (line 39) | func (d *updateData) Query() (*sql.Rows, error) {
method QueryRow (line 46) | func (d *updateData) QueryRow() RowScanner {
method ToSql (line 57) | func (d *updateData) ToSql() (sqlStr string, args []interface{}, err e...
type setClause (line 27) | type setClause struct
type UpdateBuilder (line 150) | type UpdateBuilder
method PlaceholderFormat (line 160) | func (b UpdateBuilder) PlaceholderFormat(f PlaceholderFormat) UpdateBu...
method RunWith (line 167) | func (b UpdateBuilder) RunWith(runner BaseRunner) UpdateBuilder {
method Exec (line 172) | func (b UpdateBuilder) Exec() (sql.Result, error) {
method Query (line 177) | func (b UpdateBuilder) Query() (*sql.Rows, error) {
method QueryRow (line 182) | func (b UpdateBuilder) QueryRow() RowScanner {
method Scan (line 187) | func (b UpdateBuilder) Scan(dest ...interface{}) error {
method ToSql (line 194) | func (b UpdateBuilder) ToSql() (string, []interface{}, error) {
method MustSql (line 201) | func (b UpdateBuilder) MustSql() (string, []interface{}) {
method Prefix (line 210) | func (b UpdateBuilder) Prefix(sql string, args ...interface{}) UpdateB...
method PrefixExpr (line 215) | func (b UpdateBuilder) PrefixExpr(expr Sqlizer) UpdateBuilder {
method Table (line 220) | func (b UpdateBuilder) Table(table string) UpdateBuilder {
method Set (line 225) | func (b UpdateBuilder) Set(column string, value interface{}) UpdateBui...
method SetMap (line 230) | func (b UpdateBuilder) SetMap(clauses map[string]interface{}) UpdateBu...
method From (line 247) | func (b UpdateBuilder) From(from string) UpdateBuilder {
method FromSelect (line 252) | func (b UpdateBuilder) FromSelect(from SelectBuilder, alias string) Up...
method Where (line 261) | func (b UpdateBuilder) Where(pred interface{}, args ...interface{}) Up...
method OrderBy (line 266) | func (b UpdateBuilder) OrderBy(orderBys ...string) UpdateBuilder {
method Limit (line 271) | func (b UpdateBuilder) Limit(limit uint64) UpdateBuilder {
method Offset (line 276) | func (b UpdateBuilder) Offset(offset uint64) UpdateBuilder {
method Suffix (line 281) | func (b UpdateBuilder) Suffix(sql string, args ...interface{}) UpdateB...
method SuffixExpr (line 286) | func (b UpdateBuilder) SuffixExpr(expr Sqlizer) UpdateBuilder {
function init (line 152) | func init() {
FILE: update_ctx.go
method ExecContext (line 12) | func (d *updateData) ExecContext(ctx context.Context) (sql.Result, error) {
method QueryContext (line 23) | func (d *updateData) QueryContext(ctx context.Context) (*sql.Rows, error) {
method QueryRowContext (line 34) | func (d *updateData) QueryRowContext(ctx context.Context) RowScanner {
method ExecContext (line 49) | func (b UpdateBuilder) ExecContext(ctx context.Context) (sql.Result, err...
method QueryContext (line 55) | func (b UpdateBuilder) QueryContext(ctx context.Context) (*sql.Rows, err...
method QueryRowContext (line 61) | func (b UpdateBuilder) QueryRowContext(ctx context.Context) RowScanner {
method ScanContext (line 67) | func (b UpdateBuilder) ScanContext(ctx context.Context, dest ...interfac...
FILE: update_ctx_test.go
function TestUpdateBuilderContextRunners (line 11) | func TestUpdateBuilderContextRunners(t *testing.T) {
function TestUpdateBuilderContextNoRunner (line 30) | func TestUpdateBuilderContextNoRunner(t *testing.T) {
FILE: update_test.go
function TestUpdateBuilderToSql (line 9) | func TestUpdateBuilderToSql(t *testing.T) {
function TestUpdateBuilderToSqlErr (line 42) | func TestUpdateBuilderToSqlErr(t *testing.T) {
function TestUpdateBuilderMustSql (line 50) | func TestUpdateBuilderMustSql(t *testing.T) {
function TestUpdateBuilderPlaceholders (line 59) | func TestUpdateBuilderPlaceholders(t *testing.T) {
function TestUpdateBuilderRunners (line 69) | func TestUpdateBuilderRunners(t *testing.T) {
function TestUpdateBuilderNoRunner (line 79) | func TestUpdateBuilderNoRunner(t *testing.T) {
function TestUpdateBuilderFrom (line 86) | func TestUpdateBuilderFrom(t *testing.T) {
function TestUpdateBuilderFromSelect (line 92) | func TestUpdateBuilderFromSelect(t *testing.T) {
FILE: where.go
type wherePart (line 7) | type wherePart
method ToSql (line 13) | func (p wherePart) ToSql() (sql string, args []interface{}, err error) {
function newWherePart (line 9) | func newWherePart(pred interface{}, args ...interface{}) Sqlizer {
FILE: where_test.go
function TestWherePartsAppendToSql (line 11) | func TestWherePartsAppendToSql(t *testing.T) {
function TestWherePartsAppendToSqlErr (line 23) | func TestWherePartsAppendToSqlErr(t *testing.T) {
function TestWherePartNil (line 29) | func TestWherePartNil(t *testing.T) {
function TestWherePartErr (line 34) | func TestWherePartErr(t *testing.T) {
function TestWherePartString (line 39) | func TestWherePartString(t *testing.T) {
function TestWherePartMap (line 45) | func TestWherePartMap(t *testing.T) {
Condensed preview — 48 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (151K chars).
[
{
"path": ".gitignore",
"chars": 13,
"preview": "squirrel.test"
},
{
"path": ".travis.yml",
"chars": 768,
"preview": "language: go\n\ngo:\n - 1.11.x\n - 1.12.x\n - 1.13.x\n\nservices:\n - mysql\n - postgresql\n\n# Setting sudo access to false w"
},
{
"path": "LICENSE",
"chars": 1185,
"preview": "MIT License\n\nSquirrel: The Masterminds\nCopyright (c) 2014-2015, Lann Martin. Copyright (C) 2015-2016, Google. Copyright "
},
{
"path": "README.md",
"chars": 4363,
"preview": "[](https://masterminds.github.io/stabi"
},
{
"path": "case.go",
"chars": 3065,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\n\t\"github.com/lann/builder\"\n)\n\nfunc init() {\n\tbuilder.Register(CaseBuilder"
},
{
"path": "case_test.go",
"chars": 3296,
"preview": "package squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCaseWithVal(t *testing.T) {\n\tca"
},
{
"path": "delete.go",
"chars": 4806,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/lann/builder\"\n)\n\ntype deleteData str"
},
{
"path": "delete_ctx.go",
"chars": 1908,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/lann/builder\"\n)\n\nfunc (d *deleteDat"
},
{
"path": "delete_ctx_test.go",
"chars": 847,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDeleteBuilderC"
},
{
"path": "delete_test.go",
"chars": 1806,
"preview": "package squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDeleteBuilderToSql(t *testing.T"
},
{
"path": "expr.go",
"chars": 9216,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n)\n\nconst (\n\t// Portable "
},
{
"path": "expr_test.go",
"chars": 10245,
"preview": "package squirrel\n\nimport (\n\t\"database/sql\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestConcatExpr(t *t"
},
{
"path": "go.mod",
"chars": 321,
"preview": "module github.com/Masterminds/squirrel\n\ngo 1.14\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/la"
},
{
"path": "go.sum",
"chars": 953,
"preview": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.m"
},
{
"path": "insert.go",
"chars": 7710,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/lann/builder"
},
{
"path": "insert_ctx.go",
"chars": 1908,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/lann/builder\"\n)\n\nfunc (d *insertDat"
},
{
"path": "insert_ctx_test.go",
"chars": 807,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInsertBuilderC"
},
{
"path": "insert_test.go",
"chars": 2627,
"preview": "package squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInsertBuilderToSql(t *testing.T"
},
{
"path": "integration/doc.go",
"chars": 53,
"preview": "// This is a tests-only package.\npackage integration\n"
},
{
"path": "integration/go.mod",
"chars": 347,
"preview": "module github.com/Masterminds/squirrel/integration\n\ngo 1.12\n\nrequire (\n\tgithub.com/Masterminds/squirrel v1.1.0\n\tgithub.c"
},
{
"path": "integration/go.sum",
"chars": 3122,
"preview": "github.com/Masterminds/squirrel v1.1.0 h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs=\ngithub.com/Masterminds/squirrel v"
},
{
"path": "integration/integration_test.go",
"chars": 3162,
"preview": "package integration\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/"
},
{
"path": "part.go",
"chars": 1149,
"preview": "package squirrel\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\ntype part struct {\n\tpred interface{}\n\targs []interface{}\n}\n\nfunc newPart(pred"
},
{
"path": "placeholder.go",
"chars": 2558,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// PlaceholderFormat is the interface that wraps the ReplacePla"
},
{
"path": "placeholder_test.go",
"chars": 2005,
"preview": "package squirrel\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestQuestion(t *testing."
},
{
"path": "row.go",
"chars": 472,
"preview": "package squirrel\n\n// RowScanner is the interface that wraps the Scan method.\n//\n// Scan behaves like database/sql.Row.Sc"
},
{
"path": "row_test.go",
"chars": 626,
"preview": "package squirrel\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype RowStub struct {\n\tScanned bo"
},
{
"path": "select.go",
"chars": 11320,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/lann/builder\"\n)\n\ntype selectData str"
},
{
"path": "select_ctx.go",
"chars": 1908,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/lann/builder\"\n)\n\nfunc (d *selectDat"
},
{
"path": "select_ctx_test.go",
"chars": 771,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSelectBuilderC"
},
{
"path": "select_test.go",
"chars": 12209,
"preview": "package squirrel\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfu"
},
{
"path": "squirrel.go",
"chars": 5074,
"preview": "// Package squirrel provides a fluent SQL generator.\n//\n// See https://github.com/Masterminds/squirrel for examples.\npac"
},
{
"path": "squirrel_ctx.go",
"chars": 3085,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n)\n\n// NoContextSupport is returned if a"
},
{
"path": "squirrel_ctx_test.go",
"chars": 1277,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\""
},
{
"path": "squirrel_test.go",
"chars": 5780,
"preview": "package squirrel\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype D"
},
{
"path": "statement.go",
"chars": 3254,
"preview": "package squirrel\n\nimport \"github.com/lann/builder\"\n\n// StatementBuilderType is the type of StatementBuilder.\ntype Statem"
},
{
"path": "statement_test.go",
"chars": 2072,
"preview": "package squirrel\n\nimport (\n\t\"database/sql\"\n\t\"testing\"\n\n\t\"github.com/lann/builder\"\n\t\"github.com/stretchr/testify/assert\"\n"
},
{
"path": "stmtcacher.go",
"chars": 2799,
"preview": "package squirrel\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"sync\"\n)\n\n// Prepareer is the interface that wraps the Prepare method"
},
{
"path": "stmtcacher_ctx.go",
"chars": 2550,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\n// PrepareerContext is the interface that wrap"
},
{
"path": "stmtcacher_ctx_test.go",
"chars": 402,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStmtCacherPrep"
},
{
"path": "stmtcacher_noctx.go",
"chars": 459,
"preview": "// +build !go1.8\n\npackage squirrel\n\nimport (\n\t\"database/sql\"\n)\n\n// NewStmtCacher returns a DBProxy wrapping prep that ca"
},
{
"path": "stmtcacher_test.go",
"chars": 546,
"preview": "package squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStmtCachePrepare(t *testing.T) "
},
{
"path": "update.go",
"chars": 7349,
"preview": "package squirrel\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/lann/builder\"\n)\n\ntype update"
},
{
"path": "update_ctx.go",
"chars": 1908,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/lann/builder\"\n)\n\nfunc (d *updateDat"
},
{
"path": "update_ctx_test.go",
"chars": 805,
"preview": "// +build go1.8\n\npackage squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestUpdateBuilderC"
},
{
"path": "update_test.go",
"chars": 2836,
"preview": "package squirrel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestUpdateBuilderToSql(t *testing.T"
},
{
"path": "where.go",
"chars": 572,
"preview": "package squirrel\n\nimport (\n\t\"fmt\"\n)\n\ntype wherePart part\n\nfunc newWherePart(pred interface{}, args ...interface{}) Sqliz"
},
{
"path": "where_test.go",
"chars": 1325,
"preview": "package squirrel\n\nimport (\n\t\"testing\"\n\n\t\"bytes\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWherePartsAppendToSql"
}
]
About this extraction
This page contains the full source code of the Masterminds/squirrel GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 48 files (134.4 KB), approximately 39.8k tokens, and a symbol index with 475 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.