1 /*
2  * Copyright 2015-2018 HuntLabs.cn
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance _with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 module hunt.sql.ast.statement.SQLUpdateStatement;
17 
18 
19 import hunt.collection;
20 
21 import hunt.sql.SQLUtils;
22 import hunt.sql.ast;
23 import hunt.sql.ast.expr.SQLBinaryOpExpr;
24 import hunt.sql.ast.expr.SQLBinaryOpExprGroup;
25 import hunt.sql.ast.expr.SQLBinaryOperator;
26 import hunt.sql.visitor.SQLASTOutputVisitor;
27 import hunt.sql.visitor.SQLASTVisitor;
28 import hunt.sql.ast.statement.SQLExprTableSource;
29 import hunt.sql.ast.statement.SQLTableSource;
30 import hunt.sql.ast.statement.SQLWithSubqueryClause;
31 import hunt.sql.ast.statement.SQLUpdateSetItem;
32 import hunt.sql.ast.statement.SQLJoinTableSource;
33 import hunt.util.StringBuilder;
34 
35 public class SQLUpdateStatement : SQLStatementImpl , SQLReplaceable {
36     protected SQLWithSubqueryClause _with; // for pg
37 
38     protected  List!SQLUpdateSetItem items;
39     protected SQLExpr                      where;
40     protected SQLTableSource               from;
41 
42     protected SQLTableSource               tableSource;
43     protected List!SQLExpr                returning;
44 
45     protected List!SQLHint                hints;
46 
47     // for mysql
48     protected SQLOrderBy orderBy;
49 
50     public this(){
51         items = new ArrayList!SQLUpdateSetItem();
52     }
53 
54     public this(string dbType){
55         items = new ArrayList!SQLUpdateSetItem();
56         super (dbType);
57     }
58 
59     public SQLTableSource getTableSource() {
60         return tableSource;
61     }
62 
63     public void setTableSource(SQLExpr expr) {
64         this.setTableSource(new SQLExprTableSource(expr));
65     }
66 
67     public void setTableSource(SQLTableSource tableSource) {
68         if (tableSource !is null) {
69             tableSource.setParent(this);
70         }
71         this.tableSource = tableSource;
72     }
73 
74     public SQLName getTableName() {
75         if (cast(SQLExprTableSource)(tableSource) !is null ) {
76             return (cast(SQLExprTableSource) tableSource).getName();
77         }
78 
79         if (cast(SQLJoinTableSource)(tableSource) !is null ) {
80             SQLTableSource left = (cast(SQLJoinTableSource) tableSource).getLeft();
81             if (cast(SQLExprTableSource)(left) !is null ) {
82                 return (cast(SQLExprTableSource) left).getName();
83             }
84         }
85         return null;
86     }
87 
88     public SQLExpr getWhere() {
89         return where;
90     }
91 
92     public void setWhere(SQLExpr where) {
93         if (where !is null) {
94             where.setParent(this);
95         }
96         this.where = where;
97     }
98 
99     public List!SQLUpdateSetItem getItems() {
100         return items;
101     }
102 
103     public void addItem(SQLUpdateSetItem item) {
104         this.items.add(item);
105         item.setParent(this);
106     }
107 
108     public List!SQLExpr getReturning() {
109         if (returning is null) {
110             returning = new ArrayList!SQLExpr(2);
111         }
112 
113         return returning;
114     }
115 
116     public SQLTableSource getFrom() {
117         return from;
118     }
119 
120     public void setFrom(SQLTableSource from) {
121         if (from !is null) {
122             from.setParent(this);
123         }
124         this.from = from;
125     }
126 
127     public int getHintsSize() {
128         if (hints is null) {
129             return 0;
130         }
131 
132         return hints.size();
133     }
134 
135     public List!SQLHint getHints() {
136         if (hints is null) {
137             hints = new ArrayList!SQLHint(2);
138         }
139         return hints;
140     }
141 
142     public void setHints(List!SQLHint hints) {
143         this.hints = hints;
144     }
145 
146     override public void output(StringBuilder buf) {
147         SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(buf, dbType);
148         this.accept(visitor);
149     }
150 
151     
152     override  protected void accept0(SQLASTVisitor visitor) {
153         if (visitor.visit(this)) {
154             acceptChild(visitor, tableSource);
155             acceptChild(visitor, from);
156             acceptChild!SQLUpdateSetItem(visitor, items);
157             acceptChild(visitor, where);
158             acceptChild(visitor, orderBy);
159             acceptChild!SQLHint(visitor, hints);
160         }
161         visitor.endVisit(this);
162     }
163 
164     override public List!SQLObject getChildren() {
165         List!SQLObject children = new ArrayList!SQLObject();
166         if (tableSource !is null) {
167             children.add(tableSource);
168         }
169         if (from !is null) {
170             children.add(from);
171         }
172         children.addAll(cast(List!SQLObject)(this.items));
173         if (where !is null) {
174             children.add(where);
175         }
176         if (orderBy !is null) {
177             children.add(orderBy);
178         }
179         return children;
180     }
181 
182     override
183     public bool replace(SQLExpr expr, SQLExpr target) {
184         if (where == expr) {
185             setWhere(target);
186             return true;
187         }
188         return false;
189     }
190 
191 
192     public SQLOrderBy getOrderBy() {
193         return orderBy;
194     }
195 
196     public void setOrderBy(SQLOrderBy orderBy) {
197         if (orderBy !is null) {
198             orderBy.setParent(this);
199         }
200         this.orderBy = orderBy;
201     }
202 
203     public SQLWithSubqueryClause getWith() {
204         return _with;
205     }
206 
207     public void setWith(SQLWithSubqueryClause _with) {
208         if (_with !is null) {
209             _with.setParent(this);
210         }
211         this._with = _with;
212     }
213 
214     public void addCondition(string conditionSql) {
215         if (conditionSql is null || conditionSql.length == 0) {
216             return;
217         }
218 
219         SQLExpr condition = SQLUtils.toSQLExpr(conditionSql, dbType);
220         addCondition(condition);
221     }
222 
223     public void addCondition(SQLExpr expr) {
224         if (expr is null) {
225             return;
226         }
227 
228         this.setWhere(SQLBinaryOpExpr.and(where, expr));
229     }
230 
231     public bool removeCondition(string conditionSql) {
232         if (conditionSql is null || conditionSql.length == 0) {
233             return false;
234         }
235 
236         SQLExpr condition = SQLUtils.toSQLExpr(conditionSql, dbType);
237 
238         return removeCondition(condition);
239     }
240 
241     public bool removeCondition(SQLExpr condition) {
242         if (condition is null) {
243             return false;
244         }
245 
246         if (cast(SQLBinaryOpExprGroup)(where) !is null ) {
247             SQLBinaryOpExprGroup group = cast(SQLBinaryOpExprGroup) where;
248 
249             int removedCount = 0;
250             List!SQLExpr items = group.getItems();
251             for (int i = items.size() - 1; i >= 0; i--) {
252                 if ((cast(Object)(items.get(i))).opEquals(cast(Object)(condition))) {
253                     items.removeAt(i);
254                     removedCount++;
255                 }
256             }
257             if (items.size() == 0) {
258                 where = null;
259             }
260 
261             return removedCount > 0;
262         }
263 
264         if (cast(SQLBinaryOpExpr)(where) !is null ) {
265             SQLBinaryOpExpr binaryOpWhere = cast(SQLBinaryOpExpr) where;
266             SQLBinaryOperator operator = binaryOpWhere.getOperator();
267             if (operator == SQLBinaryOperator.BooleanAnd || operator == SQLBinaryOperator.BooleanOr) {
268                 List!SQLExpr items = SQLBinaryOpExpr.split(binaryOpWhere);
269 
270                 int removedCount = 0;
271                 for (int i = items.size() - 1; i >= 0; i--) {
272                     SQLExpr item = items.get(i);
273                     if ((cast(Object)(item)).opEquals(cast(Object)(condition))) {
274                         if (SQLUtils.replaceInParent(item, null)) {
275                             removedCount++;
276                         }
277                     }
278                 }
279 
280                 return removedCount > 0;
281             }
282         }
283 
284         if ((cast(Object)(condition)).opEquals(cast(Object)(where))) {
285             where = null;
286             return true;
287         }
288 
289         return false;
290     }
291 
292     override
293     public bool opEquals(Object o) {
294         if (this == o) return true;
295         if (o is null || typeid(this) != typeid(o)) return false;
296 
297         SQLUpdateStatement that = cast(SQLUpdateStatement) o;
298 
299         if (_with !is null ? !(cast(Object)(_with)).opEquals(cast(Object)(that._with)) : that._with !is null) return false;
300         if (items !is null ? !(cast(Object)(items)).opEquals(cast(Object)(that.items)) : that.items !is null) return false;
301         if (where !is null ? !(cast(Object)(where)).opEquals(cast(Object)(that.where)) : that.where !is null) return false;
302         if (from !is null ? !(cast(Object)(from)).opEquals(cast(Object)(that.from)) : that.from !is null) return false;
303         if (hints !is null ? !(cast(Object)(hints)).opEquals(cast(Object)(that.hints)) : that.hints !is null) return false;
304         if (tableSource !is null ? !(cast(Object)(tableSource)).opEquals(cast(Object)(that.tableSource)) : that.tableSource !is null) return false;
305         if (returning !is null ? !(cast(Object)(returning)).opEquals(cast(Object)(that.returning)) : that.returning !is null) return false;
306         return orderBy !is null ? (cast(Object)(orderBy)).opEquals(cast(Object)(that.orderBy)) : that.orderBy is null;
307     }
308 
309     override
310     public size_t toHash() @trusted nothrow {
311         size_t result = _with !is null ? (cast(Object)_with).toHash() : 0;
312         result = 31 * result + (items !is null ? (cast(Object)items).toHash() : 0);
313         result = 31 * result + (where !is null ? (cast(Object)where).toHash() : 0);
314         result = 31 * result + (from !is null ? (cast(Object)from).toHash() : 0);
315         result = 31 * result + (tableSource !is null ? (cast(Object)tableSource).toHash() : 0);
316         result = 31 * result + (returning !is null ? (cast(Object)returning).toHash() : 0);
317         result = 31 * result + (orderBy !is null ? (cast(Object)orderBy).toHash() : 0);
318         result = 31 * result + (hints !is null ? (cast(Object)hints).toHash() : 0);
319         return result;
320     }
321 
322     public bool addWhere(SQLExpr where) {
323         if (where is null) {
324             return false;
325         }
326 
327         this.addCondition(where);
328         return true;
329     }
330 }