1 module hunt.sql.ast.expr.SQLPropertyExpr;
2 import hunt.sql.ast.SQLExprImpl;
3 import hunt.sql.ast.SQLName;
4 import hunt.sql.ast.SQLExpr;
5 import hunt.sql.ast.SQLObject;
6 import hunt.sql.ast.statement.SQLColumnDefinition;
7 import hunt.collection;
8 import hunt.sql.visitor.SQLASTVisitor;
9 import hunt.sql.ast.statement.SQLTableSource;
10 import hunt.sql.ast.statement.SQLCreateProcedureStatement;
11 import hunt.sql.ast.SQLDataType;
12 import hunt.sql.ast.statement.SQLSelectItem;
13 import hunt.sql.ast.statement.SQLSelect;
14 import hunt.sql.ast.statement.SQLSelectQueryBlock;
15 import hunt.sql.ast.expr.SQLIdentifierExpr;
16 import hunt.sql.util.FnvHash;
17 import hunt.String;
18 import hunt.sql.SQLUtils;
19 import hunt.sql.ast.statement.SQLSubqueryTableSource;
20 import hunt.text;
21 
22 public  class SQLPropertyExpr : SQLExprImpl , SQLName {
23     private   SQLExpr             owner;
24     private   string              name;
25 
26     protected long                nameHashCod64;
27     protected long                _hashCode64;
28 
29     protected SQLColumnDefinition resolvedColumn;
30     protected SQLObject           resolvedOwnerObject;
31 
32     public this(string owner, string name){
33         this(new SQLIdentifierExpr(owner), name);
34     }
35 
36     public this(SQLExpr owner, string name){
37         setOwner(owner);
38         this.name = name;
39     }
40 
41     public this(SQLExpr owner, string name, long nameHashCod64){
42         setOwner(owner);
43         this.name = name;
44         this.nameHashCod64 = nameHashCod64;
45     }
46 
47     public this(){
48 
49     }
50 
51     public string getSimpleName() {
52         return name;
53     }
54 
55     public SQLExpr getOwner() {
56         return this.owner;
57     }
58 
59     public string getOwnernName() {
60         if ( cast(SQLName)owner !is null) {
61             return (cast(Object) owner).toString();
62         }
63 
64         return null;
65     }
66 
67     public void setOwner(SQLExpr owner) {
68         if (owner !is null) {
69             owner.setParent(this);
70         }
71 
72         if ( cast(SQLPropertyExpr)parent !is null) {
73             SQLPropertyExpr propertyExpr = cast(SQLPropertyExpr) parent;
74             propertyExpr.computeHashCode64();
75         }
76 
77         this.owner = owner;
78         this._hashCode64 = 0;
79     }
80 
81     public  void computeHashCode64() {
82         long hash;
83         if ( cast(SQLName)owner !is null) {
84             hash = (cast(SQLName) owner).hashCode64();
85 
86             hash ^= '.';
87             hash *= FnvHash.PRIME;
88         } else if (owner is null){
89             hash = FnvHash.BASIC;
90         } else {
91             hash = FnvHash.fnv1a_64_lower((cast(Object)owner).toString());
92 
93             hash ^= '.';
94             hash *= FnvHash.PRIME;
95         }
96         hash = FnvHash.hashCode64(hash, name);
97         _hashCode64 = hash;
98     }
99 
100     public void setOwner(string owner) {
101         this.setOwner(new SQLIdentifierExpr(owner));
102     }
103 
104     public string getName() {
105         return this.name;
106     }
107 
108     public void setName(string name) {
109         this.name = name;
110         this._hashCode64 = 0;
111         this.nameHashCod64 = 0;
112 
113         SQLPropertyExpr propertyExpr = cast(SQLPropertyExpr) parent;
114         if (propertyExpr !is null) {
115             propertyExpr.computeHashCode64();
116         }
117     }
118 
119     override public void output(StringBuilder buf) {
120         import hunt.logging;
121         SQLIdentifierExpr qe = cast(SQLIdentifierExpr)this.owner;
122         this.owner.output(buf);
123         buf.append(".");
124         buf.append(this.name);
125     }
126 
127     override  protected void accept0(SQLASTVisitor visitor) {
128         if (visitor.visit(this)) {
129             acceptChild(visitor, this.owner);
130         }
131 
132         visitor.endVisit(this);
133     }
134 
135    override
136     public List!SQLObject getChildren() {
137         return Collections.singletonList!SQLObject(this.owner);
138     }
139 
140    override
141     public size_t toHash() @trusted nothrow {
142         long hash;
143         try{
144               hash= hashCode64();
145         }catch(Exception){}
146        
147         return cast(size_t)(hash ^ (hash >>> 32));
148     }
149 
150     public long hashCode64() {
151         if (_hashCode64 == 0) {
152             computeHashCode64();
153         }
154 
155         return _hashCode64;
156     }
157 
158    override
159     public bool opEquals(Object obj) {
160         if (this is obj) {
161             return true;
162         }
163         if (obj is null) {
164             return false;
165         }
166         // if (!(cast(SQLPropertyExpr)(obj) !is null)) {
167         //     return false;
168         // }
169         SQLPropertyExpr other = cast(SQLPropertyExpr) obj;
170         if(other is null)
171             return false;
172 
173         if (name is null) {
174             if (other.name !is null) {
175                 return false;
176             }
177         } else if (name != (other.name)) {
178             return false;
179         }
180         if (owner is null) {
181             if (other.owner !is null) {
182                 return false;
183             }
184         } else if (owner != (other.owner)) {
185             return false;
186         }
187         return true;
188     }
189     
190     //  override bool opEquals(Object o) {
191     //     if (o is this)
192     //         return true;
193             
194     //     return opEquals(o);
195     // }
196 
197     // override size_t toHash() @trusted nothrow {
198     //     return hashCode();
199     // }
200 
201     override public SQLPropertyExpr clone() {
202         SQLExpr owner_x = null;
203         if (owner !is null) {
204             owner_x = owner.clone();
205         }
206 
207         SQLPropertyExpr x = new SQLPropertyExpr(owner_x, name, nameHashCod64);
208 
209         x._hashCode64 = _hashCode64;
210         x.resolvedColumn = resolvedColumn;
211         x.resolvedOwnerObject = resolvedOwnerObject;
212 
213         return x;
214     }
215 
216     public bool matchOwner(string alias_p) {
217         auto obj = cast(SQLIdentifierExpr) owner;
218         if (obj !is null) {
219             return equalsIgnoreCase(obj.getName(),alias_p);
220         }
221 
222         return false;
223     }
224 
225     public long nameHashCode64() {
226         if (nameHashCod64 == 0
227                 && name !is null) {
228             nameHashCod64 = FnvHash.hashCode64(name);
229         }
230         return nameHashCod64;
231     }
232 
233     public string normalizedName() {
234 
235         string ownerName;
236         if ( cast(SQLIdentifierExpr)owner !is null) {
237             ownerName = (cast(SQLIdentifierExpr) owner).normalizedName();
238         } else if ( cast(SQLPropertyExpr)owner !is null) {
239             ownerName = (cast(SQLPropertyExpr) owner).normalizedName();
240         } else {
241             ownerName = (cast(Object)owner).toString();
242         }
243 
244         return ownerName ~ '.' ~ SQLUtils.normalize(name);
245     }
246 
247     public SQLColumnDefinition getResolvedColumn() {
248         return resolvedColumn;
249     }
250 
251     public void setResolvedColumn(SQLColumnDefinition resolvedColumn) {
252         this.resolvedColumn = resolvedColumn;
253     }
254 
255     public SQLTableSource getResolvedTableSource() {
256         if ( cast(SQLTableSource)resolvedOwnerObject !is null) {
257             return cast(SQLTableSource) resolvedOwnerObject;
258         }
259 
260         return null;
261     }
262 
263     public void setResolvedTableSource(SQLTableSource resolvedTableSource) {
264         this.resolvedOwnerObject = resolvedTableSource;
265     }
266 
267     public void setResolvedProcedure(SQLCreateProcedureStatement stmt) {
268         this.resolvedOwnerObject = stmt;
269     }
270 
271     public void setResolvedOwnerObject(SQLObject resolvedOwnerObject) {
272         this.resolvedOwnerObject = resolvedOwnerObject;
273     }
274 
275     public SQLCreateProcedureStatement getResolvedProcudure() {
276         // if (cast(SQLCreateProcedureStatement)(this.resolvedOwnerObject) !is null) {
277         //     return (SQLCreateProcedureStatement) this.resolvedOwnerObject;
278         // }
279 
280         return cast(SQLCreateProcedureStatement) this.resolvedOwnerObject;
281     }
282 
283     public SQLObject getResolvedOwnerObject() {
284         return resolvedOwnerObject;
285     }
286 
287     override public SQLDataType computeDataType() {
288         if (resolvedColumn !is null) {
289             return resolvedColumn.getDataType();
290         }
291 
292         if (resolvedOwnerObject !is null
293                 &&  cast(SQLSubqueryTableSource)resolvedOwnerObject !is null) {
294             SQLSelect select = (cast(SQLSubqueryTableSource) resolvedOwnerObject).getSelect();
295             SQLSelectQueryBlock queryBlock = select.getFirstQueryBlock();
296             if (queryBlock is null) {
297                 return null;
298             }
299             SQLSelectItem selectItem = queryBlock.findSelectItem(nameHashCode64());
300             if (selectItem !is null) {
301                 return selectItem.computeDataType();
302             }
303         }
304 
305         return null;
306     }
307 
308     public bool nameEquals(string name) {
309         return SQLUtils.nameEquals(this.name, name);
310     }
311 
312     public SQLPropertyExpr simplify() {
313         string normalizedName = SQLUtils.normalize(name);
314         SQLExpr normalizedOwner = this.owner;
315         if ( cast(SQLIdentifierExpr)normalizedOwner !is null) {
316             normalizedOwner = (cast(SQLIdentifierExpr) normalizedOwner).simplify();
317         }
318 
319         if (normalizedName != name || normalizedOwner != owner) {
320             return new SQLPropertyExpr(normalizedOwner, normalizedName, _hashCode64);
321         }
322 
323         return this;
324     }
325 
326     override public string toString() {
327         if (owner is null) {
328             return this.name;
329         }
330 
331         return (cast(Object)owner).toString() ~ '.' ~ name;
332     }
333 }