jet/sqlbuilder/clause.go

235 lines
4.7 KiB
Go
Raw Normal View History

2019-03-31 09:17:28 +02:00
package sqlbuilder
import (
"bytes"
2019-06-11 12:47:35 +02:00
"github.com/google/uuid"
"strconv"
2019-06-11 12:47:35 +02:00
"strings"
"time"
)
2019-03-31 09:17:28 +02:00
type serializeOption int
const (
NO_WRAP serializeOption = iota
)
2019-05-07 19:06:21 +02:00
type clause interface {
serialize(statement statementType, out *queryData, options ...serializeOption) error
}
func contains(options []serializeOption, option serializeOption) bool {
for _, opt := range options {
if opt == option {
return true
}
}
return false
}
type queryData struct {
2019-05-01 14:42:46 +02:00
buff bytes.Buffer
args []interface{}
2019-05-12 18:15:23 +02:00
lastChar byte
ident int
2019-05-03 12:51:57 +02:00
}
type statementType string
2019-05-03 12:51:57 +02:00
const (
select_statement statementType = "SELECT"
insert_statement statementType = "INSERT"
update_statement statementType = "UPDATE"
delete_statement statementType = "DELETE"
set_statement statementType = "SET"
lock_statement statementType = "LOCK"
2019-05-03 12:51:57 +02:00
)
2019-05-12 18:15:23 +02:00
const defaultIdent = 5
func (q *queryData) increaseIdent() {
q.ident += defaultIdent
}
func (q *queryData) decreaseIdent() {
if q.ident < defaultIdent {
q.ident = 0
}
q.ident -= defaultIdent
}
2019-06-09 11:06:08 +02:00
func (q *queryData) writeProjections(statement statementType, projections []projection) error {
2019-05-12 18:15:23 +02:00
q.increaseIdent()
err := serializeProjectionList(statement, projections, q)
q.decreaseIdent()
return err
}
2019-06-05 17:15:20 +02:00
func (q *queryData) writeFrom(statement statementType, table ReadableTable) error {
2019-05-12 18:15:23 +02:00
q.nextLine()
q.writeString("FROM")
q.increaseIdent()
err := table.serialize(statement, q)
q.decreaseIdent()
return err
2019-05-03 12:51:57 +02:00
}
2019-06-04 12:10:23 +02:00
func (q *queryData) writeWhere(statement statementType, where Expression) error {
2019-05-12 18:15:23 +02:00
q.nextLine()
q.writeString("WHERE")
q.increaseIdent()
err := where.serialize(statement, q, NO_WRAP)
2019-05-12 18:15:23 +02:00
q.decreaseIdent()
return err
2019-05-03 12:51:57 +02:00
}
func (q *queryData) writeGroupBy(statement statementType, groupBy []groupByClause) error {
2019-05-12 18:15:23 +02:00
q.nextLine()
q.writeString("GROUP BY")
2019-05-03 12:51:57 +02:00
2019-05-12 18:15:23 +02:00
q.increaseIdent()
err := serializeGroupByClauseList(statement, groupBy, q)
q.decreaseIdent()
return err
2019-05-03 12:51:57 +02:00
}
2019-06-04 12:10:23 +02:00
func (q *queryData) writeOrderBy(statement statementType, orderBy []OrderByClause) error {
2019-05-12 18:15:23 +02:00
q.nextLine()
q.writeString("ORDER BY")
q.increaseIdent()
err := serializeOrderByClauseList(statement, orderBy, q)
q.decreaseIdent()
return err
2019-05-03 12:51:57 +02:00
}
2019-06-04 12:10:23 +02:00
func (q *queryData) writeHaving(statement statementType, having Expression) error {
2019-05-12 18:15:23 +02:00
q.nextLine()
q.writeString("HAVING")
q.increaseIdent()
err := having.serialize(statement, q, NO_WRAP)
2019-05-12 18:15:23 +02:00
q.decreaseIdent()
return err
}
func (q *queryData) nextLine() {
q.write([]byte{'\n'})
q.write(bytes.Repeat([]byte{' '}, q.ident))
}
func (q *queryData) write(data []byte) {
2019-05-12 18:15:23 +02:00
if len(data) == 0 {
return
}
if !isPreSeparator(q.lastChar) && !isPostSeparator(data[0]) && q.buff.Len() > 0 {
q.buff.WriteByte(' ')
}
2019-05-01 14:42:46 +02:00
q.buff.Write(data)
2019-05-12 18:15:23 +02:00
q.lastChar = data[len(data)-1]
}
func isPreSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n' || b == ':'
2019-05-12 18:15:23 +02:00
}
func isPostSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n' || b == ':'
}
func (q *queryData) writeString(str string) {
2019-05-12 18:15:23 +02:00
q.write([]byte(str))
}
func (q *queryData) writeByte(b byte) {
2019-05-12 18:15:23 +02:00
q.write([]byte{b})
}
func (q *queryData) finalize() (string, []interface{}) {
return q.buff.String() + ";\n", q.args
}
2019-06-03 14:41:39 +02:00
func (q *queryData) insertConstantArgument(arg interface{}) {
q.writeString(ArgToString(arg))
}
func (q *queryData) insertPreparedArgument(arg interface{}) {
q.args = append(q.args, arg)
argPlaceholder := "$" + strconv.Itoa(len(q.args))
2019-05-12 18:15:23 +02:00
q.writeString(argPlaceholder)
}
func (q *queryData) reset() {
2019-05-01 17:25:10 +02:00
q.buff.Reset()
q.args = []interface{}{}
}
2019-05-12 18:15:23 +02:00
func ArgToString(value interface{}) string {
2019-06-11 12:47:35 +02:00
if isNil(value) {
return "NULL"
}
switch bindVal := value.(type) {
case bool:
if bindVal {
2019-05-12 18:15:23 +02:00
return "TRUE"
} else {
2019-05-12 18:15:23 +02:00
return "FALSE"
}
case int8:
2019-05-12 18:15:23 +02:00
return strconv.FormatInt(int64(bindVal), 10)
case int:
2019-05-12 18:15:23 +02:00
return strconv.FormatInt(int64(bindVal), 10)
case int16:
2019-05-12 18:15:23 +02:00
return strconv.FormatInt(int64(bindVal), 10)
case int32:
2019-05-12 18:15:23 +02:00
return strconv.FormatInt(int64(bindVal), 10)
case int64:
2019-05-12 18:15:23 +02:00
return strconv.FormatInt(int64(bindVal), 10)
case uint8:
2019-05-12 18:15:23 +02:00
return strconv.FormatUint(uint64(bindVal), 10)
case uint:
2019-05-12 18:15:23 +02:00
return strconv.FormatUint(uint64(bindVal), 10)
case uint16:
2019-05-12 18:15:23 +02:00
return strconv.FormatUint(uint64(bindVal), 10)
case uint32:
2019-05-12 18:15:23 +02:00
return strconv.FormatUint(uint64(bindVal), 10)
case uint64:
2019-05-12 18:15:23 +02:00
return strconv.FormatUint(uint64(bindVal), 10)
case float32:
2019-05-12 18:15:23 +02:00
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64)
case float64:
2019-05-12 18:15:23 +02:00
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64)
case string:
2019-06-11 12:47:35 +02:00
return stringQuote(bindVal)
case []byte:
2019-06-11 12:47:35 +02:00
return stringQuote(string(bindVal))
case uuid.UUID:
return stringQuote(bindVal.String())
case time.Time:
return stringQuote(bindVal.String())
default:
2019-05-12 18:15:23 +02:00
return "[Unknown type]"
}
2019-03-31 14:07:58 +02:00
}
2019-06-11 12:47:35 +02:00
func stringQuote(value string) string {
return `'` + strings.Replace(value, "'", "''", -1) + `'`
}