mirror of https://github.com/lqs/sqlingo
273 lines
6.8 KiB
Go
273 lines
6.8 KiB
Go
package sqlingo
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Expression interface {
|
|
GetSQL() string
|
|
getOperatorPriority() int
|
|
|
|
NotEquals(other interface{}) BooleanExpression
|
|
Equals(other interface{}) BooleanExpression
|
|
LessThan(other interface{}) BooleanExpression
|
|
LessThanOrEquals(other interface{}) BooleanExpression
|
|
GreaterThan(other interface{}) BooleanExpression
|
|
GreaterThanOrEquals(other interface{}) BooleanExpression
|
|
|
|
IsNull() BooleanExpression
|
|
IsNotNull() BooleanExpression
|
|
In(values ...interface{}) BooleanExpression
|
|
Between(min interface{}, max interface{}) BooleanExpression
|
|
Desc() OrderBy
|
|
|
|
As(alias string) Alias
|
|
}
|
|
|
|
type BooleanExpression interface {
|
|
Expression
|
|
And(other interface{}) BooleanExpression
|
|
Or(other interface{}) BooleanExpression
|
|
Not() BooleanExpression
|
|
}
|
|
|
|
type NumberExpression interface {
|
|
Expression
|
|
Add(other interface{}) NumberExpression
|
|
Sub(other interface{}) NumberExpression
|
|
Mul(other interface{}) NumberExpression
|
|
Div(other interface{}) NumberExpression
|
|
IntDiv(other interface{}) NumberExpression
|
|
Mod(other interface{}) NumberExpression
|
|
|
|
Sum() NumberExpression
|
|
}
|
|
|
|
type StringExpression interface {
|
|
Expression
|
|
}
|
|
|
|
type UnknownExpression interface {
|
|
Expression
|
|
And(other interface{}) BooleanExpression
|
|
Or(other interface{}) BooleanExpression
|
|
Not() BooleanExpression
|
|
Add(other interface{}) NumberExpression
|
|
Sub(other interface{}) NumberExpression
|
|
Mul(other interface{}) NumberExpression
|
|
Div(other interface{}) NumberExpression
|
|
IntDiv(other interface{}) NumberExpression
|
|
Mod(other interface{}) NumberExpression
|
|
|
|
Sum() NumberExpression
|
|
}
|
|
|
|
type expression struct {
|
|
sql string
|
|
priority int
|
|
}
|
|
|
|
func (e *expression) As(name string) Alias {
|
|
return &alias{expression: e, name: name}
|
|
}
|
|
|
|
func (e *expression) GetSQL() string {
|
|
return e.sql
|
|
}
|
|
|
|
func getSQLFromWhatever(value interface{}) (sql string, priority int) {
|
|
switch value.(type) {
|
|
case Expression:
|
|
return value.(Expression).GetSQL(), value.(Expression).getOperatorPriority()
|
|
case Assignment:
|
|
return value.(Assignment).GetSQL(), 0
|
|
case int, int8, int16, int32, int64:
|
|
return strconv.FormatInt(reflect.ValueOf(value).Int(), 10), 0
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
return strconv.FormatUint(reflect.ValueOf(value).Uint(), 10), 0
|
|
case string:
|
|
return "\"" + strings.Replace(value.(string), "\"", "\\\"", -1) + "\"", 0
|
|
case []interface{}:
|
|
return "(" + commaValues(value.([]interface{})) + ")", 0
|
|
default:
|
|
if value == nil {
|
|
return "NULL", 0
|
|
}
|
|
v := reflect.ValueOf(value)
|
|
for v.Kind() == reflect.Ptr {
|
|
if v.IsNil() {
|
|
return "NULL", 0
|
|
}
|
|
return getSQLFromWhatever(reflect.Indirect(v).Interface())
|
|
}
|
|
switch v.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return getSQLFromWhatever(v.Int())
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return getSQLFromWhatever(v.Uint())
|
|
default:
|
|
return "[invalid type " + v.Kind().String() + "]", 99
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
1 INTERVAL
|
|
2 BINARY, COLLATE
|
|
3 !
|
|
4 - (unary minus), ~ (unary bit inversion)
|
|
5 ^
|
|
6 *, /, DIV, %, MOD
|
|
7 -, +
|
|
8 <<, >>
|
|
9 &
|
|
10 |
|
|
11 = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
|
12 BETWEEN, CASE, WHEN, THEN, ELSE
|
|
13 NOT
|
|
14 AND, &&
|
|
15 XOR
|
|
16 OR, ||
|
|
17 = (assignment), :=
|
|
*/
|
|
func (e *expression) NotEquals(other interface{}) BooleanExpression {
|
|
return e.binaryOperation("<>", other, 11)
|
|
}
|
|
|
|
func (e *expression) Equals(other interface{}) BooleanExpression {
|
|
return e.binaryOperation("=", other, 11)
|
|
}
|
|
|
|
func (e *expression) LessThan(other interface{}) BooleanExpression {
|
|
return e.binaryOperation("<", other, 11)
|
|
}
|
|
|
|
func (e *expression) LessThanOrEquals(other interface{}) BooleanExpression {
|
|
return e.binaryOperation("<=", other, 11)
|
|
}
|
|
|
|
func (e *expression) GreaterThan(other interface{}) BooleanExpression {
|
|
return e.binaryOperation(">", other, 11)
|
|
}
|
|
|
|
func (e *expression) GreaterThanOrEquals(other interface{}) BooleanExpression {
|
|
return e.binaryOperation(">=", other, 11)
|
|
}
|
|
|
|
func (e *expression) And(other interface{}) BooleanExpression {
|
|
return e.binaryOperation("AND", other, 14)
|
|
}
|
|
|
|
func (e *expression) Or(other interface{}) BooleanExpression {
|
|
return e.binaryOperation("OR", other, 16)
|
|
}
|
|
|
|
func (e *expression) Add(other interface{}) NumberExpression {
|
|
return e.binaryOperation("+", other, 7)
|
|
}
|
|
|
|
func (e *expression) Sub(other interface{}) NumberExpression {
|
|
return e.binaryOperation("-", other, 7)
|
|
}
|
|
|
|
func (e *expression) Mul(other interface{}) NumberExpression {
|
|
return e.binaryOperation("*", other, 6)
|
|
}
|
|
|
|
func (e *expression) Div(other interface{}) NumberExpression {
|
|
return e.binaryOperation("/", other, 6)
|
|
}
|
|
|
|
func (e *expression) IntDiv(other interface{}) NumberExpression {
|
|
return e.binaryOperation("DIV", other, 6)
|
|
}
|
|
|
|
func (e *expression) Mod(other interface{}) NumberExpression {
|
|
return e.binaryOperation("%", other, 6)
|
|
}
|
|
|
|
func (e *expression) Sum() NumberExpression {
|
|
return e.function("SUM")
|
|
}
|
|
|
|
func (e *expression) binaryOperation(operator string, value interface{}, priority int) *expression {
|
|
left := e.GetSQL()
|
|
leftLevel := e.priority
|
|
right, rightLevel := getSQLFromWhatever(value)
|
|
if leftLevel > priority {
|
|
left = "(" + left + ")"
|
|
}
|
|
if rightLevel >= priority {
|
|
right = "(" + right + ")"
|
|
}
|
|
return &expression{
|
|
sql: left + " " + operator + " " + right,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (e *expression) function(name string) *expression {
|
|
return &expression{sql: name + "(" + e.GetSQL() + ")", priority: 0}
|
|
}
|
|
|
|
func (e *expression) IsNull() BooleanExpression {
|
|
return &expression{sql: e.GetSQL() + " IS NULL", priority: 11}
|
|
}
|
|
|
|
func (e *expression) Not() BooleanExpression {
|
|
return &expression{sql: "NOT " + e.GetSQL(), priority: 13}
|
|
}
|
|
|
|
func (e *expression) IsNotNull() BooleanExpression {
|
|
return &expression{sql: e.GetSQL() + " IS NOT NULL", priority: 11}
|
|
}
|
|
|
|
func (e *expression) In(values ...interface{}) BooleanExpression {
|
|
if len(values) == 1 {
|
|
firstValue := values[0]
|
|
valueOfFirstValue := reflect.ValueOf(firstValue)
|
|
if valueOfFirstValue.Kind() == reflect.Slice {
|
|
length := valueOfFirstValue.Len()
|
|
values = make([]interface{}, length)
|
|
for i := 0; i < length; i++ {
|
|
value := valueOfFirstValue.Index(i)
|
|
values[i] = value.Interface()
|
|
}
|
|
}
|
|
}
|
|
if len(values) == 0 {
|
|
return &expression{sql: "FALSE", priority: 0}
|
|
}
|
|
|
|
sql := e.GetSQL() + " IN ("
|
|
for i, value := range values {
|
|
if i > 0 {
|
|
sql += ", "
|
|
}
|
|
valueSql, _ := getSQLFromWhatever(value)
|
|
sql += valueSql
|
|
}
|
|
sql += ")"
|
|
return &expression{sql: sql, priority: 11}
|
|
}
|
|
|
|
func (e *expression) Between(min interface{}, max interface{}) BooleanExpression {
|
|
minSql, _ := getSQLFromWhatever(min)
|
|
maxSql, _ := getSQLFromWhatever(max)
|
|
sql := e.GetSQL() + " BETWEEN " + minSql + " AND " + maxSql
|
|
return &expression{sql: sql, priority: 12}
|
|
}
|
|
|
|
func (e *expression) getOperatorPriority() int {
|
|
return e.priority
|
|
}
|
|
|
|
func (e *expression) Desc() OrderBy {
|
|
return &orderBy{by: e, desc: true}
|
|
}
|
|
|
|
func NewExpression(sql string, priority int) {
|
|
}
|