| // 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() |
| } |