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.SQLSelectItem;
17 
18 import hunt.sql.SQLUtils;
19 import hunt.sql.ast;
20 import hunt.sql.ast.expr.SQLAllColumnExpr;
21 import hunt.sql.ast.expr.SQLIdentifierExpr;
22 import hunt.sql.ast.expr.SQLPropertyExpr;
23 // import hunt.sql.dialect.oracle.ast.OracleSQLObject;
24 import hunt.sql.visitor.SQLASTVisitor;
25 import hunt.sql.util.FnvHash;
26 import hunt.sql.util.DBType;
27 import hunt.collection;
28 import hunt.sql.ast.statement.SQLTableSource;
29 import hunt.util.StringBuilder;
30 
31 public class SQLSelectItem : SQLObjectImpl , SQLReplaceable {
32 
33     protected SQLExpr expr;
34     protected string  _alias;
35 
36     protected bool connectByRoot = false;
37 
38     protected long aliasHashCode64;
39 
40     public this(){
41 
42     }
43 
44     public this(SQLExpr expr){
45         this(expr, null);
46     }
47 
48     public this(SQLExpr expr, string alias_p){
49         this.expr = expr;
50         this._alias = alias_p;
51 
52         if (expr !is null) {
53             expr.setParent(this);
54         }
55     }
56     
57     public this(SQLExpr expr, string alias_p, bool connectByRoot){
58         this.connectByRoot = connectByRoot;
59         this.expr = expr;
60         this._alias = alias_p;
61         
62         if (expr !is null) {
63             expr.setParent(this);
64         }
65     }
66 
67     public SQLExpr getExpr() {
68         return this.expr;
69     }
70 
71     public void setExpr(SQLExpr expr) {
72         if (expr !is null) {
73             expr.setParent(this);
74         }
75         this.expr = expr;
76     }
77 
78     public string computeAlias() {
79         string alias_p = this.getAlias();
80         if (alias_p is null) {
81             if (cast(SQLIdentifierExpr)(expr) !is null ) {
82                 alias_p = (cast(SQLIdentifierExpr) expr).getName();
83             } else if (cast(SQLPropertyExpr)(expr) !is null ) {
84                 alias_p = (cast(SQLPropertyExpr) expr).getName();
85             }
86         }
87 
88         return SQLUtils.normalize(alias_p);
89     }
90 
91     override public SQLDataType computeDataType() {
92         if (expr is null) {
93             return null;
94         }
95 
96         return expr.computeDataType();
97     }
98 
99     public string getAlias() {
100         return this._alias;
101     }
102 
103     public void setAlias(string alias_p) {
104         this._alias = alias_p;
105     }
106 
107     override public void output(StringBuilder buf) {
108         if(this.connectByRoot) {
109             buf.append(" CONNECT_BY_ROOT ");
110         }
111         this.expr.output(buf);
112         if ((this._alias !is null) && (this._alias.length != 0)) {
113             buf.append(" AS ");
114             buf.append(this._alias);
115         }
116     }
117 
118     override  protected void accept0(SQLASTVisitor visitor) {
119         if (visitor.visit(this)) {
120             acceptChild(visitor, this.expr);
121         }
122         visitor.endVisit(this);
123     }
124 
125     override
126     public size_t toHash() @trusted nothrow {
127          int prime = 31;
128         size_t result = 1;
129         result = prime * result + hashOf(_alias);
130         result = prime * result + ((expr is null) ? 0 : (cast(Object)expr).toHash());
131         return result;
132     }
133 
134     override
135     public bool opEquals(Object obj) {
136         if (this == obj) return true;
137         if (obj is null) return false;
138         if (typeid(this) != typeid(obj)) return false;
139         SQLSelectItem other = cast(SQLSelectItem) obj;
140         if (_alias is null) {
141             if (other._alias !is null) return false;
142         } else if (!(_alias == other._alias)) return false;
143         if (expr is null) {
144             if (other.expr !is null) return false;
145         } else if (!(cast(Object)(expr)).opEquals(cast(Object)(other.expr))) return false;
146         return true;
147     }
148 
149     public bool isConnectByRoot() {
150         return connectByRoot;
151     }
152 
153     public void setConnectByRoot(bool connectByRoot) {
154         this.connectByRoot = connectByRoot;
155     }
156 
157     override public SQLSelectItem clone() {
158         SQLSelectItem x = new SQLSelectItem();
159         x._alias = _alias;
160         if (expr !is null) {
161             x.setExpr(expr.clone());
162         }
163         x.connectByRoot = connectByRoot;
164         return x;
165     }
166 
167     override
168     public bool replace(SQLExpr expr, SQLExpr target) {
169         if (this.expr == expr) {
170             setExpr(target);
171             return true;
172         }
173 
174         return false;
175     }
176 
177     public bool match(string alias_p) {
178         if (alias_p is null) {
179             return false;
180         }
181 
182         long hash = FnvHash.hashCode64(alias_p);
183         return match(hash);
184     }
185 
186     public long alias_hash() {
187         if (this.aliasHashCode64 == 0) {
188             this.aliasHashCode64 = FnvHash.hashCode64(_alias);
189         }
190         return aliasHashCode64;
191     }
192 
193     public bool match(long _alias_hash) {
194         long hash = alias_hash();
195 
196         if (hash == _alias_hash) {
197             return true;
198         }
199 
200         if (cast(SQLAllColumnExpr)(expr) !is null ) {
201             SQLTableSource resolvedTableSource = (cast(SQLAllColumnExpr) expr).getResolvedTableSource();
202             if (resolvedTableSource !is null
203                     && resolvedTableSource.findColumn(_alias_hash) !is null) {
204                 return true;
205             }
206             return false;
207         }
208 
209         if (cast(SQLIdentifierExpr)(expr) !is null ) {
210             return (cast(SQLIdentifierExpr) expr).nameHashCode64() == _alias_hash;
211         }
212 
213         if (cast(SQLPropertyExpr)(expr) !is null ) {
214             string ident = (cast(SQLPropertyExpr) expr).getName();
215             if ("*" == (ident)) {
216                 SQLTableSource resolvedTableSource = (cast(SQLPropertyExpr) expr).getResolvedTableSource();
217                 if (resolvedTableSource !is null
218                         && resolvedTableSource.findColumn(_alias_hash) !is null) {
219                     return true;
220                 }
221                 return false;
222             }
223 
224             return (cast(SQLPropertyExpr) expr).nameHashCode64() == _alias_hash;
225         }
226 
227         return false;
228     }
229 
230     override public string toString() {
231         string dbType = null;
232         // if (cast(OracleSQLObject)(parent) !is null ) {
233         //     dbType = DBType.ORACLE;
234         // }
235         return SQLUtils.toSQLString(this, dbType);
236     }
237 }