132 lines
3.0 KiB
Go
132 lines
3.0 KiB
Go
// Package dotsql provides a way to separate your code from SQL queries.
|
|
//
|
|
// It is not an ORM, it is not a query builder.
|
|
// Dotsql is a library that helps you keep sql files in one place and use it with ease.
|
|
//
|
|
// For more usage examples see https://github.com/gchaincl/dotsql
|
|
package dotsql
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"database/sql"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
// Preparer is an interface used by Prepare.
|
|
type Preparer interface {
|
|
Prepare(query string) (*sql.Stmt, error)
|
|
}
|
|
|
|
// Queryer is an interface used by Query.
|
|
type Queryer interface {
|
|
Query(query string, args ...interface{}) (*sql.Rows, error)
|
|
}
|
|
|
|
// Execer is an interface used by Exec.
|
|
type Execer interface {
|
|
Exec(query string, args ...interface{}) (sql.Result, error)
|
|
}
|
|
|
|
// DotSql represents a dotSQL queries holder.
|
|
type DotSql struct {
|
|
queries map[string]string
|
|
}
|
|
|
|
func (d DotSql) lookupQuery(name string) (query string, err error) {
|
|
query, ok := d.queries[name]
|
|
if !ok {
|
|
err = fmt.Errorf("dotsql: '%s' could not be found", name)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Query is a wrapper for database/sql's Prepare(), using dotsql named query.
|
|
func (d DotSql) Prepare(db Preparer, name string) (*sql.Stmt, error) {
|
|
query, err := d.lookupQuery(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return db.Prepare(query)
|
|
}
|
|
|
|
// Query is a wrapper for database/sql's Query(), using dotsql named query.
|
|
func (d DotSql) Query(db Queryer, name string, args ...interface{}) (*sql.Rows, error) {
|
|
query, err := d.lookupQuery(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return db.Query(query, args...)
|
|
}
|
|
|
|
// Exec is a wrapper for database/sql's Exec(), using dotsql named query.
|
|
func (d DotSql) Exec(db Execer, name string, args ...interface{}) (sql.Result, error) {
|
|
query, err := d.lookupQuery(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return db.Exec(query, args...)
|
|
}
|
|
|
|
// Raw returns the query, everything after the --name tag
|
|
func (d DotSql) Raw(name string) (string, error) {
|
|
return d.lookupQuery(name)
|
|
}
|
|
|
|
// QueryMap returns a map[string]string of loaded queries
|
|
func (d DotSql) QueryMap() map[string]string {
|
|
return d.queries
|
|
}
|
|
|
|
// Load imports sql queries from any io.Reader.
|
|
func Load(r io.Reader) (*DotSql, error) {
|
|
scanner := &Scanner{}
|
|
queries := scanner.Run(bufio.NewScanner(r))
|
|
|
|
dotsql := &DotSql{
|
|
queries: queries,
|
|
}
|
|
|
|
return dotsql, nil
|
|
}
|
|
|
|
// LoadFromFile imports SQL queries from the file.
|
|
func LoadFromFile(sqlFile string) (*DotSql, error) {
|
|
f, err := os.Open(sqlFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
return Load(f)
|
|
}
|
|
|
|
// LoadFromString imports SQL queries from the string.
|
|
func LoadFromString(sql string) (*DotSql, error) {
|
|
buf := bytes.NewBufferString(sql)
|
|
return Load(buf)
|
|
}
|
|
|
|
// Merge takes one or more *DotSql and merge its queries
|
|
// It's in-order, so the last source will override queries with the same name
|
|
// in the previous arguments if any.
|
|
func Merge(dots ...*DotSql) *DotSql {
|
|
queries := make(map[string]string)
|
|
|
|
for _, dot := range dots {
|
|
for k, v := range dot.QueryMap() {
|
|
queries[k] = v
|
|
}
|
|
}
|
|
|
|
return &DotSql{
|
|
queries: queries,
|
|
}
|
|
}
|