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.builder.impl.SQLUpdateBuilderImpl;
17 
18 import hunt.collection;
19 
20 import hunt.sql.SQLUtils;
21 import hunt.sql.ast.SQLExpr;
22 import hunt.sql.ast.SQLStatement;
23 import hunt.sql.ast.expr.SQLBinaryOperator;
24 import hunt.sql.ast.expr.SQLIdentifierExpr;
25 import hunt.sql.ast.statement.SQLExprTableSource;
26 import hunt.sql.ast.statement.SQLUpdateSetItem;
27 import hunt.sql.ast.statement.SQLUpdateStatement;
28 import hunt.sql.builder.SQLUpdateBuilder;
29 import hunt.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
30 // import hunt.sql.dialect.oracle.ast.stmt.OracleUpdateStatement;
31 import hunt.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
32 // import hunt.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement;
33 import hunt.sql.util.DBType;
34 import hunt.sql.builder.impl.SQLBuilderImpl;
35 import hunt.sql.builder.SQLBuilder;
36 import hunt.sql.ast.expr.SQLBlobExpr;
37 import hunt.sql.ast.expr.SQLBooleanExpr;
38 import hunt.sql.ast.expr.SQLCharExpr;
39 import hunt.sql.ast.expr.SQLIntegerExpr;
40 import hunt.sql.ast.expr.SQLNullExpr;
41 import hunt.sql.ast.expr.SQLNumberExpr;
42 
43 import hunt.Double;
44 import hunt.Exceptions;
45 import hunt.Float;
46 import hunt.Boolean;
47 import hunt.Integer;
48 import hunt.Long;
49 import hunt.Number;
50 import hunt.String;
51 import hunt.logging;
52 import hunt.Nullable;
53 
54 import std.variant;
55 
56 class SQLUpdateBuilderImpl :  SQLUpdateBuilder {
57 
58     private SQLUpdateStatement stmt;
59     private string             dbType;
60 
61     this(string dbType){
62         this.dbType = dbType;
63     }
64     
65     this(string sql, string dbType){
66         List!SQLStatement stmtList = SQLUtils.parseStatements(sql, dbType);
67 
68         if (stmtList.size() == 0) {
69             throw new Exception("not support empty-statement :" ~ sql);
70         }
71 
72         if (stmtList.size() > 1) {
73             throw new Exception("not support multi-statement :" ~ sql);
74         }
75 
76         SQLUpdateStatement stmt = cast(SQLUpdateStatement) stmtList.get(0);
77         this.stmt = stmt;
78         this.dbType = dbType;
79     }
80 
81     static SQLExpr toSQLExpr(Variant obj, string dbType) {
82         // logDebug("set : ",obj.toString);
83         if (!obj.hasValue() || obj == null) {
84             return new SQLNullExpr();
85         }
86 
87         TypeInfo typeInfo = obj.type;
88         
89         if (typeInfo == typeid(int)) {
90             return new SQLIntegerExpr(cast(long)obj.get!int());
91         }
92 
93         if (typeInfo == typeid(uint)) {
94             return new SQLIntegerExpr(cast(long)obj.get!uint());
95         }
96         
97         if (typeInfo == typeid(short)) {
98             return new SQLIntegerExpr(cast(long)obj.get!short());
99         }
100         
101         if (typeInfo == typeid(ushort)) {
102             return new SQLIntegerExpr(cast(long)obj.get!ushort());
103         }
104         
105         if (typeInfo == typeid(long)) {
106             return new SQLIntegerExpr(cast(long)obj.get!long());
107         }
108         
109         if (typeInfo == typeid(ulong)) {
110             return new SQLIntegerExpr(cast(long)obj.get!ulong());
111         }
112         
113         if (typeInfo == typeid(double)) {
114             Double db = new Double(obj.get!double());
115             return new SQLNumberExpr(db);
116         }
117         
118         if (typeInfo == typeid(float)) {
119             Float db = new Float(obj.get!float());
120             return new SQLNumberExpr(db);
121         }
122 
123         if (typeInfo == typeid(bool)) {
124             return new SQLBooleanExpr(obj.get!bool());
125         }
126 
127         if (typeInfo == typeid(string)) {
128             return new SQLCharExpr(obj.get!string());
129         }
130 
131         if(typeInfo == typeid(ubyte[])) {
132             ubyte[] data = obj.get!(ubyte[])();
133             return new SQLBlobExpr(data);
134         }
135 
136 
137         // if (cast(Integer)(obj) !is null) {
138         //     return new SQLIntegerExpr(cast(Integer) obj);
139         // }
140 
141         // if (cast(Long)(obj) !is null) {
142         //     return new SQLIntegerExpr(cast(int)(cast(Long) obj).longValue);
143         // }
144 
145         // if (cast(Float)(obj) !is null) {
146         //     return new SQLNumberExpr(cast(Float)obj);
147         // }
148 
149         // if (cast(Double)(obj) !is null) {
150         //     Number nm = cast(Number)obj;
151         //     return new SQLNumberExpr(nm);
152         // }
153         
154         // if (cast(Number)(obj) !is null) {
155         //     return new SQLNumberExpr(cast(Number) obj);
156         // }
157         
158         // if (cast(String)(obj) !is null) {
159         //     return new SQLCharExpr(cast(String) obj);
160         // }
161         
162         // if (cast(Boolean)(obj) !is null) {
163         //     return new SQLBooleanExpr((cast(Boolean) obj).booleanValue);
164         // }
165 
166         throw new IllegalArgumentException("unsupported : " ~ obj.type.toString());
167     }
168 
169     this(SQLUpdateStatement stmt, string dbType){
170         this.stmt = stmt;
171         this.dbType = dbType;
172     }
173 
174     override
175     SQLBuilder limit(int rowCount) {
176         throw new Exception("not implement");
177     }
178 
179     override
180     SQLBuilder limit(int rowCount, int offset) {
181         throw new Exception("not implement");
182     }
183 
184     override
185     SQLBuilder from(string table) {
186         return from(table, null);
187     }
188 
189     override
190     SQLBuilder from(string table, string _alias) {
191         SQLUpdateStatement update = getSQLUpdateStatement();
192         SQLExprTableSource from = new SQLExprTableSource(new SQLIdentifierExpr(table), _alias);
193         update.setTableSource(from);
194         return this;
195     }
196 
197     override
198     SQLBuilder where(string expr) {
199         SQLUpdateStatement update = getSQLUpdateStatement();
200 
201         SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType);
202         update.setWhere(exprObj);
203 
204         return this;
205     }
206 
207     override
208     SQLBuilder whereAnd(string expr) {
209         SQLUpdateStatement update = getSQLUpdateStatement();
210 
211         SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType);
212         SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanAnd, exprObj, false, update.getWhere());
213         update.setWhere(newCondition);
214 
215         return this;
216     }
217 
218     override
219     SQLBuilder whereOr(string expr) {
220         SQLUpdateStatement update = getSQLUpdateStatement();
221 
222         SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType);
223         SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanOr, exprObj, false, update.getWhere());
224         update.setWhere(newCondition);
225 
226         return this;
227     }
228 
229     override
230     SQLUpdateBuilder set(string[] items...) {
231         SQLUpdateStatement update = getSQLUpdateStatement();
232         foreach (string item ; items) {
233             SQLUpdateSetItem updateSetItem = SQLUtils.toUpdateSetItem(item, dbType);
234             update.addItem(updateSetItem);
235         }
236         
237         return this;
238     }
239     
240     SQLUpdateBuilderImpl setValue(Map!(string, Variant) values) {
241         foreach (string k, Variant v ; values) {
242             setValue(k, v);
243         }
244         
245         return this;
246     }
247     
248     SQLUpdateBuilderImpl setValue(string column, Variant value) {
249         SQLUpdateStatement update = getSQLUpdateStatement();
250         
251         SQLExpr columnExpr = SQLUtils.toSQLExpr(column, dbType);
252         SQLExpr valueExpr = toSQLExpr(value, dbType);
253         
254         SQLUpdateSetItem item = new SQLUpdateSetItem();
255         item.setColumn(columnExpr);
256         item.setValue(valueExpr);
257         update.addItem(item);
258         
259         return this;
260     }
261 
262     SQLUpdateStatement getSQLUpdateStatement() {
263         if (stmt is null) {
264             stmt = createSQLUpdateStatement();
265         }
266         return stmt;
267     }
268 
269     SQLUpdateStatement createSQLUpdateStatement() {
270         if (DBType.MYSQL.name == dbType) {
271             return new MySqlUpdateStatement();    
272         }
273         
274         // if (DBType.ORACLE.name == dbType) {
275         //     return new OracleUpdateStatement();    
276         // }
277         
278         if (DBType.POSTGRESQL.name == dbType) {
279             return new PGUpdateStatement();    
280         }
281         
282         // if (DBType.SQL_SERVER.name == dbType) {
283         //     return new SQLServerUpdateStatement();    
284         // }
285         
286         return new SQLUpdateStatement();
287     }
288     
289     override string toString() {
290         return SQLUtils.toSQLString(stmt, dbType);
291     }
292     
293     string toString(FormatOption option) {
294         return SQLUtils.toSQLString(stmt, dbType, option);
295     }
296 }