2016-09-15 05:45:09 +02:00
|
|
|
package queries
|
2016-04-13 15:51:58 +02:00
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
2017-07-06 21:15:00 +02:00
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2016-09-15 05:45:09 +02:00
|
|
|
|
2017-07-06 21:15:00 +02:00
|
|
|
"github.com/lbryio/null.go"
|
2017-05-08 19:25:15 +02:00
|
|
|
"github.com/lbryio/sqlboiler/boil"
|
2017-07-06 21:15:00 +02:00
|
|
|
|
|
|
|
"github.com/go-errors/errors"
|
2016-04-19 07:31:07 +02:00
|
|
|
)
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-08-07 22:37:51 +02:00
|
|
|
// joinKind is the type of join
|
|
|
|
type joinKind int
|
|
|
|
|
|
|
|
// Join type constants
|
|
|
|
const (
|
|
|
|
JoinInner joinKind = iota
|
|
|
|
JoinOuterLeft
|
|
|
|
JoinOuterRight
|
|
|
|
JoinNatural
|
|
|
|
)
|
|
|
|
|
2016-07-19 06:07:12 +02:00
|
|
|
// Query holds the state for the built up query
|
2016-04-13 15:51:58 +02:00
|
|
|
type Query struct {
|
2016-09-15 05:45:09 +02:00
|
|
|
executor boil.Executor
|
2016-09-09 19:14:18 +02:00
|
|
|
dialect *Dialect
|
2016-09-15 05:57:07 +02:00
|
|
|
rawSQL rawSQL
|
2016-08-26 14:08:27 +02:00
|
|
|
load []string
|
|
|
|
delete bool
|
|
|
|
update map[string]interface{}
|
|
|
|
selectCols []string
|
|
|
|
count bool
|
|
|
|
from []string
|
|
|
|
joins []join
|
|
|
|
where []where
|
|
|
|
in []in
|
|
|
|
groupBy []string
|
|
|
|
orderBy []string
|
|
|
|
having []having
|
|
|
|
limit int
|
|
|
|
offset int
|
2016-08-30 05:13:00 +02:00
|
|
|
forlock string
|
2016-04-13 15:51:58 +02:00
|
|
|
}
|
|
|
|
|
2016-09-09 19:14:18 +02:00
|
|
|
// Dialect holds values that direct the query builder
|
|
|
|
// how to build compatible queries for each database.
|
|
|
|
// Each database driver needs to implement functions
|
|
|
|
// that provide these values.
|
|
|
|
type Dialect struct {
|
|
|
|
// The left quote character for SQL identifiers
|
2016-09-09 19:30:46 +02:00
|
|
|
LQ byte
|
2016-09-09 19:14:18 +02:00
|
|
|
// The right quote character for SQL identifiers
|
2016-09-09 19:30:46 +02:00
|
|
|
RQ byte
|
2016-09-09 19:14:18 +02:00
|
|
|
// Bool flag indicating whether indexed
|
|
|
|
// placeholders ($1) are used, or ? placeholders.
|
|
|
|
IndexPlaceholders bool
|
2017-03-14 09:13:56 +01:00
|
|
|
// Bool flag indicating whether "TOP" or "LIMIT" clause
|
|
|
|
// must be used for rows limitation
|
|
|
|
UseTopClause bool
|
2016-09-09 19:14:18 +02:00
|
|
|
}
|
|
|
|
|
2016-08-06 23:42:22 +02:00
|
|
|
type where struct {
|
2016-08-11 08:44:15 +02:00
|
|
|
clause string
|
|
|
|
orSeparator bool
|
|
|
|
args []interface{}
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
type in struct {
|
|
|
|
clause string
|
|
|
|
orSeparator bool
|
|
|
|
args []interface{}
|
|
|
|
}
|
|
|
|
|
2016-08-12 19:08:09 +02:00
|
|
|
type having struct {
|
|
|
|
clause string
|
|
|
|
args []interface{}
|
|
|
|
}
|
|
|
|
|
2016-09-15 05:57:07 +02:00
|
|
|
type rawSQL struct {
|
2016-08-06 23:42:22 +02:00
|
|
|
sql string
|
|
|
|
args []interface{}
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-08-06 23:42:22 +02:00
|
|
|
type join struct {
|
2016-08-07 22:37:51 +02:00
|
|
|
kind joinKind
|
|
|
|
clause string
|
|
|
|
args []interface{}
|
2016-08-04 06:29:18 +02:00
|
|
|
}
|
|
|
|
|
2016-09-15 05:57:07 +02:00
|
|
|
// Raw makes a raw query, usually for use with bind
|
|
|
|
func Raw(exec boil.Executor, query string, args ...interface{}) *Query {
|
2016-08-08 08:36:11 +02:00
|
|
|
return &Query{
|
2016-08-28 06:51:03 +02:00
|
|
|
executor: exec,
|
2016-09-15 05:57:07 +02:00
|
|
|
rawSQL: rawSQL{
|
2016-08-08 08:36:11 +02:00
|
|
|
sql: query,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-15 05:57:07 +02:00
|
|
|
// RawG makes a raw query using the global boil.Executor, usually for use with bind
|
|
|
|
func RawG(query string, args ...interface{}) *Query {
|
|
|
|
return Raw(boil.GetDB(), query, args...)
|
2016-08-28 06:51:03 +02:00
|
|
|
}
|
|
|
|
|
2016-09-14 18:14:30 +02:00
|
|
|
// Exec executes a query that does not need a row returned
|
|
|
|
func (q *Query) Exec() (sql.Result, error) {
|
2016-04-20 15:03:33 +02:00
|
|
|
qs, args := buildQuery(q)
|
2016-09-15 05:45:09 +02:00
|
|
|
if boil.DebugMode {
|
2017-07-06 21:15:00 +02:00
|
|
|
qStr, err := interpolateParams(qs, args...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fmt.Fprintln(boil.DebugWriter, qStr)
|
2016-06-02 23:07:51 +02:00
|
|
|
}
|
2016-04-20 15:03:33 +02:00
|
|
|
return q.executor.Exec(qs, args...)
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-09-14 18:14:30 +02:00
|
|
|
// QueryRow executes the query for the One finisher and returns a row
|
|
|
|
func (q *Query) QueryRow() *sql.Row {
|
2016-08-08 02:11:45 +02:00
|
|
|
qs, args := buildQuery(q)
|
2016-09-15 05:45:09 +02:00
|
|
|
if boil.DebugMode {
|
2017-07-06 21:15:00 +02:00
|
|
|
qStr, err := interpolateParams(qs, args...)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fmt.Fprintln(boil.DebugWriter, qStr)
|
2016-08-08 02:11:45 +02:00
|
|
|
}
|
|
|
|
return q.executor.QueryRow(qs, args...)
|
|
|
|
}
|
|
|
|
|
2016-09-14 18:14:30 +02:00
|
|
|
// Query executes the query for the All finisher and returns multiple rows
|
|
|
|
func (q *Query) Query() (*sql.Rows, error) {
|
2016-04-20 15:03:33 +02:00
|
|
|
qs, args := buildQuery(q)
|
2016-09-15 05:45:09 +02:00
|
|
|
if boil.DebugMode {
|
2017-07-06 21:15:00 +02:00
|
|
|
qStr, err := interpolateParams(qs, args...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fmt.Fprintln(boil.DebugWriter, qStr)
|
2016-06-02 23:07:51 +02:00
|
|
|
}
|
2016-06-05 08:13:38 +02:00
|
|
|
return q.executor.Query(qs, args...)
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-09-14 18:14:30 +02:00
|
|
|
// ExecP executes a query that does not need a row returned
|
2016-09-14 11:42:07 +02:00
|
|
|
// It will panic on error
|
2016-09-14 18:14:30 +02:00
|
|
|
func (q *Query) ExecP() sql.Result {
|
|
|
|
res, err := q.Exec()
|
2016-09-14 11:42:07 +02:00
|
|
|
if err != nil {
|
2016-09-15 05:45:09 +02:00
|
|
|
panic(boil.WrapErr(err))
|
2016-09-14 11:42:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2016-09-14 18:14:30 +02:00
|
|
|
// QueryP executes the query for the All finisher and returns multiple rows
|
2016-09-14 11:42:07 +02:00
|
|
|
// It will panic on error
|
2016-09-14 18:14:30 +02:00
|
|
|
func (q *Query) QueryP() *sql.Rows {
|
|
|
|
rows, err := q.Query()
|
2016-09-14 11:42:07 +02:00
|
|
|
if err != nil {
|
2016-09-15 05:45:09 +02:00
|
|
|
panic(boil.WrapErr(err))
|
2016-09-14 11:42:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return rows
|
|
|
|
}
|
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// SetExecutor on the query.
|
2016-09-15 05:45:09 +02:00
|
|
|
func SetExecutor(q *Query, exec boil.Executor) {
|
2016-08-17 07:19:23 +02:00
|
|
|
q.executor = exec
|
|
|
|
}
|
|
|
|
|
2016-08-29 14:38:19 +02:00
|
|
|
// GetExecutor on the query.
|
2016-09-15 05:45:09 +02:00
|
|
|
func GetExecutor(q *Query) boil.Executor {
|
2016-08-29 14:38:19 +02:00
|
|
|
return q.executor
|
|
|
|
}
|
|
|
|
|
2016-09-09 19:14:18 +02:00
|
|
|
// SetDialect on the query.
|
|
|
|
func SetDialect(q *Query, dialect *Dialect) {
|
|
|
|
q.dialect = dialect
|
|
|
|
}
|
|
|
|
|
2016-07-19 06:07:12 +02:00
|
|
|
// SetSQL on the query.
|
|
|
|
func SetSQL(q *Query, sql string, args ...interface{}) {
|
2016-09-15 05:57:07 +02:00
|
|
|
q.rawSQL = rawSQL{sql: sql, args: args}
|
2016-07-19 06:07:12 +02:00
|
|
|
}
|
|
|
|
|
2016-08-17 19:56:00 +02:00
|
|
|
// SetLoad on the query.
|
|
|
|
func SetLoad(q *Query, relationships ...string) {
|
|
|
|
q.load = append([]string(nil), relationships...)
|
|
|
|
}
|
|
|
|
|
2016-10-01 08:24:42 +02:00
|
|
|
// AppendLoad on the query.
|
|
|
|
func AppendLoad(q *Query, relationships ...string) {
|
|
|
|
q.load = append(q.load, relationships...)
|
|
|
|
}
|
|
|
|
|
2016-09-13 09:48:14 +02:00
|
|
|
// SetSelect on the query.
|
|
|
|
func SetSelect(q *Query, sel []string) {
|
|
|
|
q.selectCols = sel
|
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetCount on the query.
|
2016-05-10 12:20:29 +02:00
|
|
|
func SetCount(q *Query) {
|
2016-08-26 14:08:27 +02:00
|
|
|
q.count = true
|
2016-05-10 12:20:29 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetDelete on the query.
|
2016-04-20 14:51:04 +02:00
|
|
|
func SetDelete(q *Query) {
|
|
|
|
q.delete = true
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// SetLimit on the query.
|
|
|
|
func SetLimit(q *Query, limit int) {
|
|
|
|
q.limit = limit
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetOffset on the query.
|
|
|
|
func SetOffset(q *Query, offset int) {
|
|
|
|
q.offset = offset
|
|
|
|
}
|
|
|
|
|
2016-08-30 05:13:00 +02:00
|
|
|
// SetFor on the query.
|
|
|
|
func SetFor(q *Query, clause string) {
|
|
|
|
q.forlock = clause
|
|
|
|
}
|
|
|
|
|
2016-08-04 06:29:18 +02:00
|
|
|
// SetUpdate on the query.
|
|
|
|
func SetUpdate(q *Query, cols map[string]interface{}) {
|
|
|
|
q.update = cols
|
|
|
|
}
|
|
|
|
|
2016-08-04 07:22:17 +02:00
|
|
|
// AppendSelect on the query.
|
|
|
|
func AppendSelect(q *Query, columns ...string) {
|
|
|
|
q.selectCols = append(q.selectCols, columns...)
|
|
|
|
}
|
2016-08-02 05:25:02 +02:00
|
|
|
|
2016-08-04 07:22:17 +02:00
|
|
|
// AppendFrom on the query.
|
|
|
|
func AppendFrom(q *Query, from ...string) {
|
2016-08-04 06:50:26 +02:00
|
|
|
q.from = append(q.from, from...)
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-08-04 07:22:17 +02:00
|
|
|
// SetFrom replaces the current from statements.
|
|
|
|
func SetFrom(q *Query, from ...string) {
|
|
|
|
q.from = append([]string(nil), from...)
|
2016-04-16 07:17:25 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 07:22:17 +02:00
|
|
|
// AppendInnerJoin on the query.
|
2016-08-07 22:37:51 +02:00
|
|
|
func AppendInnerJoin(q *Query, clause string, args ...interface{}) {
|
|
|
|
q.joins = append(q.joins, join{clause: clause, kind: JoinInner, args: args})
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-13 15:51:58 +02:00
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// AppendHaving on the query.
|
|
|
|
func AppendHaving(q *Query, clause string, args ...interface{}) {
|
|
|
|
q.having = append(q.having, having{clause: clause, args: args})
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 07:22:17 +02:00
|
|
|
// AppendWhere on the query.
|
|
|
|
func AppendWhere(q *Query, clause string, args ...interface{}) {
|
|
|
|
q.where = append(q.where, where{clause: clause, args: args})
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// AppendIn on the query.
|
|
|
|
func AppendIn(q *Query, clause string, args ...interface{}) {
|
|
|
|
q.in = append(q.in, in{clause: clause, args: args})
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// SetLastWhereAsOr sets the or separator for the tail "WHERE" in the slice
|
2016-08-11 08:44:15 +02:00
|
|
|
func SetLastWhereAsOr(q *Query) {
|
|
|
|
if len(q.where) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
q.where[len(q.where)-1].orSeparator = true
|
|
|
|
}
|
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// SetLastInAsOr sets the or separator for the tail "IN" in the slice
|
|
|
|
func SetLastInAsOr(q *Query) {
|
|
|
|
if len(q.in) == 0 {
|
|
|
|
return
|
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
q.in[len(q.in)-1].orSeparator = true
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// AppendGroupBy on the query.
|
|
|
|
func AppendGroupBy(q *Query, clause string) {
|
|
|
|
q.groupBy = append(q.groupBy, clause)
|
2016-04-13 15:51:58 +02:00
|
|
|
}
|
2016-06-12 13:14:25 +02:00
|
|
|
|
2016-08-17 07:19:23 +02:00
|
|
|
// AppendOrderBy on the query.
|
|
|
|
func AppendOrderBy(q *Query, clause string) {
|
|
|
|
q.orderBy = append(q.orderBy, clause)
|
2016-08-01 04:21:06 +02:00
|
|
|
}
|
2017-07-06 21:15:00 +02:00
|
|
|
|
|
|
|
// duplicated in boil_queries.tpl
|
|
|
|
func interpolateParams(query string, args ...interface{}) (string, error) {
|
|
|
|
for i := 0; i < len(args); i++ {
|
|
|
|
field := reflect.ValueOf(args[i])
|
|
|
|
|
|
|
|
if value, ok := field.Interface().(time.Time); ok {
|
|
|
|
query = strings.Replace(query, "?", `"`+value.Format("2006-01-02 15:04:05")+`"`, 1)
|
|
|
|
} else if nullable, ok := field.Interface().(null.Nullable); ok {
|
|
|
|
if nullable.IsNull() {
|
|
|
|
query = strings.Replace(query, "?", "NULL", 1)
|
|
|
|
} else {
|
|
|
|
switch field.Type() {
|
|
|
|
case reflect.TypeOf(null.Time{}):
|
|
|
|
query = strings.Replace(query, "?", `"`+field.Interface().(null.Time).Time.Format("2006-01-02 15:04:05")+`"`, 1)
|
|
|
|
case reflect.TypeOf(null.Int{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int).Int), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Int8{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int8).Int8), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Int16{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int16).Int16), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Int32{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int32).Int32), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Int64{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatInt(field.Interface().(null.Int64).Int64, 10), 1)
|
|
|
|
case reflect.TypeOf(null.Uint{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint).Uint), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Uint8{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint8).Uint8), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Uint16{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint16).Uint16), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Uint32{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint32).Uint32), 10), 1)
|
|
|
|
case reflect.TypeOf(null.Uint64{}):
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatUint(field.Interface().(null.Uint64).Uint64, 10), 1)
|
|
|
|
case reflect.TypeOf(null.String{}):
|
|
|
|
query = strings.Replace(query, "?", `"`+field.Interface().(null.String).String+`"`, 1)
|
|
|
|
case reflect.TypeOf(null.Bool{}):
|
|
|
|
if field.Interface().(null.Bool).Bool {
|
|
|
|
query = strings.Replace(query, "?", "1", 1)
|
|
|
|
} else {
|
|
|
|
query = strings.Replace(query, "?", "0", 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch field.Kind() {
|
|
|
|
case reflect.Bool:
|
|
|
|
boolString := "0"
|
|
|
|
if field.Bool() {
|
|
|
|
boolString = "1"
|
|
|
|
}
|
|
|
|
query = strings.Replace(query, "?", boolString, 1)
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatInt(field.Int(), 10), 1)
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
query = strings.Replace(query, "?", strconv.FormatUint(field.Uint(), 10), 1)
|
|
|
|
case reflect.String:
|
|
|
|
query = strings.Replace(query, "?", `"`+field.String()+`"`, 1)
|
|
|
|
default:
|
|
|
|
return "", errors.New("Dont know how to interpolate type " + field.Type().String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return query, nil
|
|
|
|
}
|