2019-03-31 09:17:28 +02:00
|
|
|
package sqlbuilder
|
|
|
|
|
|
2019-04-29 14:39:48 +02:00
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"errors"
|
|
|
|
|
"strconv"
|
|
|
|
|
)
|
2019-03-31 09:17:28 +02:00
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
type clause interface {
|
|
|
|
|
serialize(out *queryData) error
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type queryData struct {
|
2019-05-01 14:42:46 +02:00
|
|
|
buff bytes.Buffer
|
|
|
|
|
args []interface{}
|
2019-05-03 12:51:57 +02:00
|
|
|
|
|
|
|
|
statementType int
|
|
|
|
|
clauseType int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
select_statement = iota
|
|
|
|
|
insert_statement
|
|
|
|
|
update_statement
|
|
|
|
|
delete_statement
|
|
|
|
|
set_statement
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
projection_clause = iota
|
|
|
|
|
where_clause
|
|
|
|
|
order_by_clause
|
|
|
|
|
group_by_clause
|
|
|
|
|
having_clause
|
|
|
|
|
)
|
|
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
func (q *queryData) WriteProjection(projections []projection) error {
|
2019-05-03 12:51:57 +02:00
|
|
|
q.clauseType = projection_clause
|
|
|
|
|
return serializeProjectionList(projections, q)
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
func (q *queryData) WriteWhere(where expression) error {
|
2019-05-03 12:51:57 +02:00
|
|
|
q.clauseType = where_clause
|
|
|
|
|
q.WriteString(" WHERE ")
|
2019-05-07 19:06:21 +02:00
|
|
|
return where.serialize(q)
|
2019-05-03 12:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
func (q *queryData) WriteGroupBy(groupBy []groupByClause) error {
|
2019-05-03 12:51:57 +02:00
|
|
|
q.clauseType = group_by_clause
|
|
|
|
|
q.WriteString(" GROUP BY ")
|
|
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
return serializeGroupByClauseList(groupBy, q)
|
2019-05-03 12:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
func (q *queryData) WriteOrderBy(orderBy []orderByClause) error {
|
2019-05-03 12:51:57 +02:00
|
|
|
q.clauseType = order_by_clause
|
|
|
|
|
q.WriteString(" ORDER BY ")
|
|
|
|
|
return serializeOrderByClauseList(orderBy, q)
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-07 19:06:21 +02:00
|
|
|
func (q *queryData) WriteHaving(having expression) error {
|
2019-05-03 12:51:57 +02:00
|
|
|
q.clauseType = having_clause
|
|
|
|
|
q.WriteString(" HAVING ")
|
2019-05-07 19:06:21 +02:00
|
|
|
return having.serialize(q)
|
2019-05-03 12:51:57 +02:00
|
|
|
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (q *queryData) Write(data []byte) {
|
2019-05-01 14:42:46 +02:00
|
|
|
q.buff.Write(data)
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (q *queryData) WriteString(str string) {
|
2019-05-01 14:42:46 +02:00
|
|
|
q.buff.WriteString(str)
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (q *queryData) WriteByte(b byte) {
|
2019-05-01 14:42:46 +02:00
|
|
|
q.buff.WriteByte(b)
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (q *queryData) InsertArgument(arg interface{}) {
|
|
|
|
|
q.args = append(q.args, arg)
|
|
|
|
|
argPlaceholder := "$" + strconv.Itoa(len(q.args))
|
|
|
|
|
|
2019-05-01 14:42:46 +02:00
|
|
|
q.buff.WriteString(argPlaceholder)
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-01 17:25:10 +02:00
|
|
|
func (q *queryData) Reset() {
|
|
|
|
|
q.buff.Reset()
|
|
|
|
|
q.args = []interface{}{}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 14:39:48 +02:00
|
|
|
func argToString(value interface{}) (string, error) {
|
|
|
|
|
switch bindVal := value.(type) {
|
|
|
|
|
case bool:
|
|
|
|
|
if bindVal {
|
|
|
|
|
return "TRUE", nil
|
|
|
|
|
} else {
|
|
|
|
|
return "FALSE", nil
|
|
|
|
|
}
|
|
|
|
|
case int8:
|
|
|
|
|
return strconv.FormatInt(int64(bindVal), 10), nil
|
|
|
|
|
case int:
|
|
|
|
|
return strconv.FormatInt(int64(bindVal), 10), nil
|
|
|
|
|
case int16:
|
|
|
|
|
return strconv.FormatInt(int64(bindVal), 10), nil
|
|
|
|
|
case int32:
|
|
|
|
|
return strconv.FormatInt(int64(bindVal), 10), nil
|
|
|
|
|
case int64:
|
|
|
|
|
return strconv.FormatInt(int64(bindVal), 10), nil
|
|
|
|
|
|
|
|
|
|
case uint8:
|
|
|
|
|
return strconv.FormatUint(uint64(bindVal), 10), nil
|
|
|
|
|
case uint:
|
|
|
|
|
return strconv.FormatUint(uint64(bindVal), 10), nil
|
|
|
|
|
case uint16:
|
|
|
|
|
return strconv.FormatUint(uint64(bindVal), 10), nil
|
|
|
|
|
case uint32:
|
|
|
|
|
return strconv.FormatUint(uint64(bindVal), 10), nil
|
|
|
|
|
case uint64:
|
|
|
|
|
return strconv.FormatUint(uint64(bindVal), 10), nil
|
|
|
|
|
|
|
|
|
|
case float32:
|
|
|
|
|
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64), nil
|
|
|
|
|
case float64:
|
|
|
|
|
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64), nil
|
|
|
|
|
|
|
|
|
|
case string:
|
|
|
|
|
return bindVal, nil
|
|
|
|
|
case []byte:
|
|
|
|
|
return string(bindVal), nil
|
|
|
|
|
//TODO: implement
|
|
|
|
|
//case time.Time:
|
|
|
|
|
// return bindVal.String())
|
|
|
|
|
default:
|
|
|
|
|
return "", errors.New("Unsupported literal type. ")
|
|
|
|
|
}
|
2019-03-31 14:07:58 +02:00
|
|
|
}
|