2016-04-13 15:51:58 +02:00
|
|
|
package boil
|
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-04-13 15:51:58 +02:00
|
|
|
type where struct {
|
2016-06-02 23:07:51 +02:00
|
|
|
clause string
|
|
|
|
orSeperator bool
|
|
|
|
args []interface{}
|
2016-04-13 15:51:58 +02:00
|
|
|
}
|
|
|
|
|
2016-07-19 06:07:12 +02:00
|
|
|
type plainSQL struct {
|
|
|
|
sql string
|
|
|
|
args []interface{}
|
|
|
|
}
|
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
type join struct {
|
|
|
|
on string
|
|
|
|
args []interface{}
|
|
|
|
}
|
|
|
|
|
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-04-19 07:31:07 +02:00
|
|
|
executor Executor
|
2016-07-19 06:07:12 +02:00
|
|
|
plainSQL plainSQL
|
2016-04-19 07:31:07 +02:00
|
|
|
delete bool
|
|
|
|
update map[string]interface{}
|
|
|
|
selectCols []string
|
2016-05-10 12:20:29 +02:00
|
|
|
count bool
|
2016-07-19 06:07:12 +02:00
|
|
|
from string
|
2016-04-19 07:31:07 +02:00
|
|
|
innerJoins []join
|
|
|
|
outerJoins []join
|
|
|
|
leftOuterJoins []join
|
|
|
|
rightOuterJoins []join
|
|
|
|
where []where
|
|
|
|
groupBy []string
|
|
|
|
orderBy []string
|
|
|
|
having []string
|
|
|
|
limit int
|
2016-08-01 04:21:06 +02:00
|
|
|
offset int
|
2016-04-13 15:51:58 +02:00
|
|
|
}
|
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
func buildQuery(q *Query) (string, []interface{}) {
|
|
|
|
var buf *bytes.Buffer
|
|
|
|
var args []interface{}
|
|
|
|
|
|
|
|
switch {
|
2016-07-19 06:07:12 +02:00
|
|
|
case len(q.plainSQL.sql) != 0:
|
|
|
|
return q.plainSQL.sql, q.plainSQL.args
|
2016-04-19 07:31:07 +02:00
|
|
|
case q.delete:
|
|
|
|
buf, args = buildDeleteQuery(q)
|
|
|
|
case len(q.update) > 0:
|
|
|
|
buf, args = buildUpdateQuery(q)
|
|
|
|
default:
|
|
|
|
buf, args = buildSelectQuery(q)
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.String(), args
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
|
|
|
|
buf.WriteString("SELECT ")
|
|
|
|
|
2016-06-10 01:43:45 +02:00
|
|
|
if q.count {
|
|
|
|
buf.WriteString("COUNT(")
|
|
|
|
}
|
2016-04-19 07:31:07 +02:00
|
|
|
if len(q.selectCols) > 0 {
|
2016-07-19 06:07:12 +02:00
|
|
|
buf.WriteString(`"` + strings.Join(q.selectCols, `","`) + `"`)
|
2016-04-19 07:31:07 +02:00
|
|
|
} else {
|
|
|
|
buf.WriteByte('*')
|
|
|
|
}
|
2016-06-10 01:43:45 +02:00
|
|
|
// close sql COUNT function
|
|
|
|
if q.count {
|
|
|
|
buf.WriteString(")")
|
|
|
|
}
|
2016-04-19 07:31:07 +02:00
|
|
|
|
|
|
|
buf.WriteString(" FROM ")
|
2016-07-19 06:07:12 +02:00
|
|
|
fmt.Fprintf(buf, `"%s"`, q.from)
|
2016-04-19 07:31:07 +02:00
|
|
|
|
2016-06-12 13:14:25 +02:00
|
|
|
where, args := whereClause(q)
|
|
|
|
buf.WriteString(where)
|
2016-08-01 06:05:03 +02:00
|
|
|
|
|
|
|
if len(q.orderBy) != 0 {
|
|
|
|
buf.WriteString(" ORDER BY ")
|
|
|
|
buf.WriteString(strings.Join(q.orderBy, ","))
|
|
|
|
}
|
2016-06-12 13:14:25 +02:00
|
|
|
|
2016-08-01 04:21:06 +02:00
|
|
|
if q.limit != 0 {
|
|
|
|
fmt.Fprintf(buf, " LIMIT %d", q.limit)
|
|
|
|
}
|
|
|
|
if q.offset != 0 {
|
|
|
|
fmt.Fprintf(buf, " OFFSET %d", q.offset)
|
|
|
|
}
|
|
|
|
|
2016-06-02 23:07:51 +02:00
|
|
|
buf.WriteByte(';')
|
2016-06-12 13:14:25 +02:00
|
|
|
return buf, args
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
func buildDeleteQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
|
2016-06-02 23:07:51 +02:00
|
|
|
buf.WriteString("DELETE FROM ")
|
2016-07-19 06:07:12 +02:00
|
|
|
fmt.Fprintf(buf, `"%s"`, q.from)
|
2016-06-02 23:07:51 +02:00
|
|
|
|
2016-06-12 13:14:25 +02:00
|
|
|
where, args := whereClause(q)
|
|
|
|
buf.WriteString(where)
|
2016-06-02 23:07:51 +02:00
|
|
|
|
|
|
|
buf.WriteByte(';')
|
|
|
|
|
2016-06-10 07:20:26 +02:00
|
|
|
return buf, args
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-04-19 07:31:07 +02:00
|
|
|
func buildUpdateQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
|
|
|
buf := &bytes.Buffer{}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-06-02 23:07:51 +02:00
|
|
|
buf.WriteByte(';')
|
2016-04-19 07:31:07 +02:00
|
|
|
return buf, nil
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-04-20 15:03:33 +02:00
|
|
|
// ExecQuery executes a query that does not need a row returned
|
|
|
|
func ExecQuery(q *Query) (sql.Result, error) {
|
|
|
|
qs, args := buildQuery(q)
|
2016-06-02 23:07:51 +02:00
|
|
|
if DebugMode {
|
|
|
|
fmt.Fprintln(DebugWriter, qs)
|
|
|
|
}
|
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-04-20 15:03:33 +02:00
|
|
|
// ExecQueryOne executes the query for the One finisher and returns a row
|
|
|
|
func ExecQueryOne(q *Query) *sql.Row {
|
|
|
|
qs, args := buildQuery(q)
|
2016-06-02 23:07:51 +02:00
|
|
|
if DebugMode {
|
|
|
|
fmt.Fprintln(DebugWriter, qs)
|
|
|
|
}
|
2016-06-05 08:13:38 +02:00
|
|
|
return q.executor.QueryRow(qs, args...)
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-04-20 15:03:33 +02:00
|
|
|
// ExecQueryAll executes the query for the All finisher and returns multiple rows
|
2016-04-19 07:31:07 +02:00
|
|
|
func ExecQueryAll(q *Query) (*sql.Rows, error) {
|
2016-04-20 15:03:33 +02:00
|
|
|
qs, args := buildQuery(q)
|
2016-06-02 23:07:51 +02:00
|
|
|
if DebugMode {
|
|
|
|
fmt.Fprintln(DebugWriter, qs)
|
|
|
|
}
|
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-07-19 06:07:12 +02:00
|
|
|
// SetSQL on the query.
|
|
|
|
func SetSQL(q *Query, sql string, args ...interface{}) {
|
|
|
|
q.plainSQL = plainSQL{sql: sql, args: args}
|
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetCount on the query.
|
2016-05-10 12:20:29 +02:00
|
|
|
func SetCount(q *Query) {
|
|
|
|
q.count = true
|
|
|
|
}
|
|
|
|
|
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-07-16 13:22:57 +02:00
|
|
|
// SetUpdate on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetUpdate(q *Query, cols map[string]interface{}) {
|
|
|
|
q.update = cols
|
2016-04-13 15:51:58 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetExecutor on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetExecutor(q *Query, exec Executor) {
|
|
|
|
q.executor = exec
|
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetSelect on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetSelect(q *Query, columns ...string) {
|
|
|
|
q.selectCols = append(q.selectCols, columns...)
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// Select returns the select columns in the query.
|
2016-06-07 06:38:17 +02:00
|
|
|
func Select(q *Query) []string {
|
2016-06-05 08:13:38 +02:00
|
|
|
cols := make([]string, len(q.selectCols))
|
|
|
|
copy(cols, q.selectCols)
|
|
|
|
return cols
|
|
|
|
}
|
|
|
|
|
2016-07-19 06:07:12 +02:00
|
|
|
// SetFrom on the query.
|
|
|
|
func SetFrom(q *Query, from string) {
|
|
|
|
q.from = from
|
2016-04-19 07:31:07 +02:00
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetInnerJoin on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetInnerJoin(q *Query, on string, args ...interface{}) {
|
|
|
|
q.innerJoins = append(q.innerJoins, join{on: on, args: args})
|
2016-04-16 07:17:25 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetOuterJoin on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetOuterJoin(q *Query, on string, args ...interface{}) {
|
|
|
|
q.outerJoins = append(q.outerJoins, join{on: on, args: args})
|
|
|
|
}
|
2016-04-13 15:51:58 +02:00
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetLeftOuterJoin on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetLeftOuterJoin(q *Query, on string, args ...interface{}) {
|
|
|
|
q.leftOuterJoins = append(q.leftOuterJoins, join{on: on, args: args})
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetRightOuterJoin on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetRightOuterJoin(q *Query, on string, args ...interface{}) {
|
|
|
|
q.rightOuterJoins = append(q.rightOuterJoins, join{on: on, args: args})
|
|
|
|
}
|
2016-04-19 04:02:32 +02:00
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetWhere on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetWhere(q *Query, clause string, args ...interface{}) {
|
|
|
|
q.where = append(q.where, where{clause: clause, args: args})
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-07-19 06:07:12 +02:00
|
|
|
// SetLastWhereAsOr sets the or seperator for the last element in the where slice
|
|
|
|
func SetLastWhereAsOr(q *Query) {
|
|
|
|
q.where[len(q.where)-1].orSeperator = true
|
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetGroupBy on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetGroupBy(q *Query, clause string) {
|
|
|
|
q.groupBy = append(q.groupBy, clause)
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetOrderBy on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetOrderBy(q *Query, clause string) {
|
|
|
|
q.orderBy = append(q.orderBy, clause)
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetHaving on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetHaving(q *Query, clause string) {
|
|
|
|
q.having = append(q.having, clause)
|
2016-04-19 04:02:32 +02:00
|
|
|
}
|
|
|
|
|
2016-07-16 13:22:57 +02:00
|
|
|
// SetLimit on the query.
|
2016-04-19 07:31:07 +02:00
|
|
|
func SetLimit(q *Query, limit int) {
|
|
|
|
q.limit = limit
|
2016-04-13 15:51:58 +02:00
|
|
|
}
|
2016-06-12 13:14:25 +02:00
|
|
|
|
2016-08-01 04:21:06 +02:00
|
|
|
// SetOffset on the query.
|
|
|
|
func SetOffset(q *Query, offset int) {
|
|
|
|
q.offset = offset
|
|
|
|
}
|
|
|
|
|
2016-06-12 13:14:25 +02:00
|
|
|
func whereClause(q *Query) (string, []interface{}) {
|
2016-07-19 06:07:12 +02:00
|
|
|
if len(q.where) == 0 {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2016-06-12 13:14:25 +02:00
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
var args []interface{}
|
|
|
|
|
2016-07-19 06:07:12 +02:00
|
|
|
buf.WriteString(" WHERE ")
|
|
|
|
for i := 0; i < len(q.where); i++ {
|
|
|
|
buf.WriteString(fmt.Sprintf("%s", q.where[i].clause))
|
|
|
|
args = append(args, q.where[i].args...)
|
|
|
|
if i >= len(q.where)-1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if q.where[i].orSeperator {
|
|
|
|
buf.WriteString(" OR ")
|
|
|
|
} else {
|
|
|
|
buf.WriteString(" AND ")
|
2016-06-12 13:14:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.String(), args
|
|
|
|
}
|