123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- package clause
- import (
- "database/sql"
- "database/sql/driver"
- "go/ast"
- "reflect"
- )
- // Expression expression interface
- type Expression interface {
- Build(builder Builder)
- }
- // NegationExpressionBuilder negation expression builder
- type NegationExpressionBuilder interface {
- NegationBuild(builder Builder)
- }
- // Expr raw expression
- type Expr struct {
- SQL string
- Vars []interface{}
- WithoutParentheses bool
- }
- // Build build raw expression
- func (expr Expr) Build(builder Builder) {
- var (
- afterParenthesis bool
- idx int
- )
- for _, v := range []byte(expr.SQL) {
- if v == '?' && len(expr.Vars) > idx {
- if afterParenthesis || expr.WithoutParentheses {
- if _, ok := expr.Vars[idx].(driver.Valuer); ok {
- builder.AddVar(builder, expr.Vars[idx])
- } else {
- switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() {
- case reflect.Slice, reflect.Array:
- if rv.Len() == 0 {
- builder.AddVar(builder, nil)
- } else {
- for i := 0; i < rv.Len(); i++ {
- if i > 0 {
- builder.WriteByte(',')
- }
- builder.AddVar(builder, rv.Index(i).Interface())
- }
- }
- default:
- builder.AddVar(builder, expr.Vars[idx])
- }
- }
- } else {
- builder.AddVar(builder, expr.Vars[idx])
- }
- idx++
- } else {
- if v == '(' {
- afterParenthesis = true
- } else {
- afterParenthesis = false
- }
- builder.WriteByte(v)
- }
- }
- }
- // NamedExpr raw expression for named expr
- type NamedExpr struct {
- SQL string
- Vars []interface{}
- }
- // Build build raw expression
- func (expr NamedExpr) Build(builder Builder) {
- var (
- idx int
- inName bool
- namedMap = make(map[string]interface{}, len(expr.Vars))
- )
- for _, v := range expr.Vars {
- switch value := v.(type) {
- case sql.NamedArg:
- namedMap[value.Name] = value.Value
- case map[string]interface{}:
- for k, v := range value {
- namedMap[k] = v
- }
- default:
- var appendFieldsToMap func(reflect.Value)
- appendFieldsToMap = func(reflectValue reflect.Value) {
- reflectValue = reflect.Indirect(reflectValue)
- switch reflectValue.Kind() {
- case reflect.Struct:
- modelType := reflectValue.Type()
- for i := 0; i < modelType.NumField(); i++ {
- if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) {
- namedMap[fieldStruct.Name] = reflectValue.Field(i).Interface()
- if fieldStruct.Anonymous {
- appendFieldsToMap(reflectValue.Field(i))
- }
- }
- }
- }
- }
- appendFieldsToMap(reflect.ValueOf(value))
- }
- }
- name := make([]byte, 0, 10)
- for _, v := range []byte(expr.SQL) {
- if v == '@' && !inName {
- inName = true
- name = []byte{}
- } else if v == ' ' || v == ',' || v == ')' || v == '"' || v == '\'' || v == '`' || v == '\n' {
- if inName {
- if nv, ok := namedMap[string(name)]; ok {
- builder.AddVar(builder, nv)
- } else {
- builder.WriteByte('@')
- builder.WriteString(string(name))
- }
- inName = false
- }
- builder.WriteByte(v)
- } else if v == '?' && len(expr.Vars) > idx {
- builder.AddVar(builder, expr.Vars[idx])
- idx++
- } else if inName {
- name = append(name, v)
- } else {
- builder.WriteByte(v)
- }
- }
- if inName {
- builder.AddVar(builder, namedMap[string(name)])
- }
- }
- // IN Whether a value is within a set of values
- type IN struct {
- Column interface{}
- Values []interface{}
- }
- func (in IN) Build(builder Builder) {
- builder.WriteQuoted(in.Column)
- switch len(in.Values) {
- case 0:
- builder.WriteString(" IN (NULL)")
- case 1:
- if _, ok := in.Values[0].([]interface{}); !ok {
- builder.WriteString(" = ")
- builder.AddVar(builder, in.Values[0])
- break
- }
- fallthrough
- default:
- builder.WriteString(" IN (")
- builder.AddVar(builder, in.Values...)
- builder.WriteByte(')')
- }
- }
- func (in IN) NegationBuild(builder Builder) {
- switch len(in.Values) {
- case 0:
- case 1:
- if _, ok := in.Values[0].([]interface{}); !ok {
- builder.WriteQuoted(in.Column)
- builder.WriteString(" <> ")
- builder.AddVar(builder, in.Values[0])
- break
- }
- fallthrough
- default:
- builder.WriteQuoted(in.Column)
- builder.WriteString(" NOT IN (")
- builder.AddVar(builder, in.Values...)
- builder.WriteByte(')')
- }
- }
- // Eq equal to for where
- type Eq struct {
- Column interface{}
- Value interface{}
- }
- func (eq Eq) Build(builder Builder) {
- builder.WriteQuoted(eq.Column)
- if eqNil(eq.Value) {
- builder.WriteString(" IS NULL")
- } else {
- builder.WriteString(" = ")
- builder.AddVar(builder, eq.Value)
- }
- }
- func (eq Eq) NegationBuild(builder Builder) {
- Neq(eq).Build(builder)
- }
- // Neq not equal to for where
- type Neq Eq
- func (neq Neq) Build(builder Builder) {
- builder.WriteQuoted(neq.Column)
- if eqNil(neq.Value) {
- builder.WriteString(" IS NOT NULL")
- } else {
- builder.WriteString(" <> ")
- builder.AddVar(builder, neq.Value)
- }
- }
- func (neq Neq) NegationBuild(builder Builder) {
- Eq(neq).Build(builder)
- }
- // Gt greater than for where
- type Gt Eq
- func (gt Gt) Build(builder Builder) {
- builder.WriteQuoted(gt.Column)
- builder.WriteString(" > ")
- builder.AddVar(builder, gt.Value)
- }
- func (gt Gt) NegationBuild(builder Builder) {
- Lte(gt).Build(builder)
- }
- // Gte greater than or equal to for where
- type Gte Eq
- func (gte Gte) Build(builder Builder) {
- builder.WriteQuoted(gte.Column)
- builder.WriteString(" >= ")
- builder.AddVar(builder, gte.Value)
- }
- func (gte Gte) NegationBuild(builder Builder) {
- Lt(gte).Build(builder)
- }
- // Lt less than for where
- type Lt Eq
- func (lt Lt) Build(builder Builder) {
- builder.WriteQuoted(lt.Column)
- builder.WriteString(" < ")
- builder.AddVar(builder, lt.Value)
- }
- func (lt Lt) NegationBuild(builder Builder) {
- Gte(lt).Build(builder)
- }
- // Lte less than or equal to for where
- type Lte Eq
- func (lte Lte) Build(builder Builder) {
- builder.WriteQuoted(lte.Column)
- builder.WriteString(" <= ")
- builder.AddVar(builder, lte.Value)
- }
- func (lte Lte) NegationBuild(builder Builder) {
- Gt(lte).Build(builder)
- }
- // Like whether string matches regular expression
- type Like Eq
- func (like Like) Build(builder Builder) {
- builder.WriteQuoted(like.Column)
- builder.WriteString(" LIKE ")
- builder.AddVar(builder, like.Value)
- }
- func (like Like) NegationBuild(builder Builder) {
- builder.WriteQuoted(like.Column)
- builder.WriteString(" NOT LIKE ")
- builder.AddVar(builder, like.Value)
- }
- func eqNil(value interface{}) bool {
- if valuer, ok := value.(driver.Valuer); ok {
- value, _ = valuer.Value()
- }
- return value == nil || eqNilReflect(value)
- }
- func eqNilReflect(value interface{}) bool {
- reflectValue := reflect.ValueOf(value)
- return reflectValue.Kind() == reflect.Ptr && reflectValue.IsNil()
- }
|