| // +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...) |
| } |