github.com/systematiccaos/gorm@v1.22.6/clause/where.go (about) 1 package clause 2 3 import ( 4 "strings" 5 ) 6 7 // Where where clause 8 type Where struct { 9 Exprs []Expression 10 } 11 12 // Name where clause name 13 func (where Where) Name() string { 14 return "WHERE" 15 } 16 17 // Build build where clause 18 func (where Where) Build(builder Builder) { 19 // Switch position if the first query expression is a single Or condition 20 for idx, expr := range where.Exprs { 21 if v, ok := expr.(OrConditions); !ok || len(v.Exprs) > 1 { 22 if idx != 0 { 23 where.Exprs[0], where.Exprs[idx] = where.Exprs[idx], where.Exprs[0] 24 } 25 break 26 } 27 } 28 29 buildExprs(where.Exprs, builder, " AND ") 30 } 31 32 func buildExprs(exprs []Expression, builder Builder, joinCond string) { 33 wrapInParentheses := false 34 35 for idx, expr := range exprs { 36 if idx > 0 { 37 if v, ok := expr.(OrConditions); ok && len(v.Exprs) == 1 { 38 builder.WriteString(" OR ") 39 } else { 40 builder.WriteString(joinCond) 41 } 42 } 43 44 if len(exprs) > 1 { 45 switch v := expr.(type) { 46 case OrConditions: 47 if len(v.Exprs) == 1 { 48 if e, ok := v.Exprs[0].(Expr); ok { 49 sql := strings.ToLower(e.SQL) 50 wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or") 51 } 52 } 53 case AndConditions: 54 if len(v.Exprs) == 1 { 55 if e, ok := v.Exprs[0].(Expr); ok { 56 sql := strings.ToLower(e.SQL) 57 wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or") 58 } 59 } 60 case Expr: 61 sql := strings.ToLower(v.SQL) 62 wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or") 63 case NamedExpr: 64 sql := strings.ToLower(v.SQL) 65 wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or") 66 } 67 } 68 69 if wrapInParentheses { 70 builder.WriteString(`(`) 71 expr.Build(builder) 72 builder.WriteString(`)`) 73 wrapInParentheses = false 74 } else { 75 expr.Build(builder) 76 } 77 } 78 } 79 80 // MergeClause merge where clauses 81 func (where Where) MergeClause(clause *Clause) { 82 if w, ok := clause.Expression.(Where); ok { 83 exprs := make([]Expression, len(w.Exprs)+len(where.Exprs)) 84 copy(exprs, w.Exprs) 85 copy(exprs[len(w.Exprs):], where.Exprs) 86 where.Exprs = exprs 87 } 88 89 clause.Expression = where 90 } 91 92 func And(exprs ...Expression) Expression { 93 if len(exprs) == 0 { 94 return nil 95 } else if len(exprs) == 1 { 96 return exprs[0] 97 } 98 return AndConditions{Exprs: exprs} 99 } 100 101 type AndConditions struct { 102 Exprs []Expression 103 } 104 105 func (and AndConditions) Build(builder Builder) { 106 if len(and.Exprs) > 1 { 107 builder.WriteByte('(') 108 buildExprs(and.Exprs, builder, " AND ") 109 builder.WriteByte(')') 110 } else { 111 buildExprs(and.Exprs, builder, " AND ") 112 } 113 } 114 115 func Or(exprs ...Expression) Expression { 116 if len(exprs) == 0 { 117 return nil 118 } 119 return OrConditions{Exprs: exprs} 120 } 121 122 type OrConditions struct { 123 Exprs []Expression 124 } 125 126 func (or OrConditions) Build(builder Builder) { 127 if len(or.Exprs) > 1 { 128 builder.WriteByte('(') 129 buildExprs(or.Exprs, builder, " OR ") 130 builder.WriteByte(')') 131 } else { 132 buildExprs(or.Exprs, builder, " OR ") 133 } 134 } 135 136 func Not(exprs ...Expression) Expression { 137 if len(exprs) == 0 { 138 return nil 139 } 140 return NotConditions{Exprs: exprs} 141 } 142 143 type NotConditions struct { 144 Exprs []Expression 145 } 146 147 func (not NotConditions) Build(builder Builder) { 148 if len(not.Exprs) > 1 { 149 builder.WriteByte('(') 150 } 151 152 for idx, c := range not.Exprs { 153 if idx > 0 { 154 builder.WriteString(" AND ") 155 } 156 157 if negationBuilder, ok := c.(NegationExpressionBuilder); ok { 158 negationBuilder.NegationBuild(builder) 159 } else { 160 builder.WriteString("NOT ") 161 e, wrapInParentheses := c.(Expr) 162 if wrapInParentheses { 163 sql := strings.ToLower(e.SQL) 164 if wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or"); wrapInParentheses { 165 builder.WriteByte('(') 166 } 167 } 168 169 c.Build(builder) 170 171 if wrapInParentheses { 172 builder.WriteByte(')') 173 } 174 } 175 } 176 177 if len(not.Exprs) > 1 { 178 builder.WriteByte(')') 179 } 180 }