1 module hunt.sql.ast.expr.SQLAggregateExpr;
2 
3 import hunt.sql.ast;
4 import hunt.sql.visitor.SQLASTVisitor;
5 import hunt.sql.ast.expr.SQLAggregateOption;
6 import hunt.sql.util.FnvHash;
7 import hunt.sql.SQLUtils;
8 import hunt.sql.ast.expr.SQLIntegerExpr;
9 import hunt.sql.ast.expr.SQLCharExpr;
10 
11 import hunt.collection;
12 
13 
14 public class SQLAggregateExpr : SQLExprImpl , SQLReplaceable {
15 
16     protected string              methodName;
17     protected long                _methodNameHashCod64;
18 
19     protected SQLAggregateOption  option;
20     protected List!SQLExpr arguments;
21     protected SQLKeep             keep;
22     protected SQLExpr             filter;
23     protected SQLOver             over;
24     protected SQLName             overRef;
25     protected SQLOrderBy          withinGroup;
26     protected bool             ignoreNulls      = false;
27 
28     this()
29     {
30         arguments        = new ArrayList!SQLExpr();
31     }
32 
33     public this(string methodName){
34         this();
35         this.methodName = methodName;
36     }
37 
38     public this(string methodName, SQLAggregateOption option){
39         this();
40         this.methodName = methodName;
41         this.option = option;
42     }
43 
44     public string getMethodName() {
45         return this.methodName;
46     }
47 
48     public void setMethodName(string methodName) {
49         this.methodName = methodName;
50     }
51 
52     public long methodNameHashCod64() {
53         if (_methodNameHashCod64 == 0) {
54             _methodNameHashCod64 = FnvHash.hashCode64(methodName);
55         }
56         return _methodNameHashCod64;
57     }
58 
59     public SQLOrderBy getWithinGroup() {
60         return withinGroup;
61     }
62 
63     public void setWithinGroup(SQLOrderBy withinGroup) {
64         if (withinGroup !is null) {
65             withinGroup.setParent(this);
66         }
67 
68         this.withinGroup = withinGroup;
69     }
70 
71     public SQLAggregateOption getOption() {
72         return this.option;
73     }
74 
75     public void setOption(SQLAggregateOption option) {
76         this.option = option;
77     }
78 
79     public List!SQLExpr getArguments() {
80         return this.arguments;
81     }
82     
83     public void addArgument(SQLExpr argument) {
84         if (argument !is null) {
85             argument.setParent(this);
86         }
87         this.arguments.add(argument);
88     }
89 
90     public SQLOver getOver() {
91         return over;
92     }
93 
94     public void setOver(SQLOver over) {
95         if (over !is null) {
96             over.setParent(this);
97         }
98         this.over = over;
99     }
100 
101     public SQLName getOverRef() {
102         return overRef;
103     }
104 
105     public void setOverRef(SQLName x) {
106         if (x !is null) {
107             x.setParent(this);
108         }
109         this.overRef = x;
110     }
111     
112     public SQLKeep getKeep() {
113         return keep;
114     }
115 
116     public void setKeep(SQLKeep keep) {
117         if (keep !is null) {
118             keep.setParent(this);
119         }
120         this.keep = keep;
121     }
122     
123     public bool isIgnoreNulls() {
124         return /*this.ignoreNulls !is null && */this.ignoreNulls;
125     }
126 
127     public bool getIgnoreNulls() {
128         return this.ignoreNulls;
129     }
130 
131     public void setIgnoreNulls(bool ignoreNulls) {
132         this.ignoreNulls = ignoreNulls;
133     }
134 
135     public override string toString() {
136         return SQLUtils.toSQLString(this);
137     }
138 
139 
140     protected override void accept0(SQLASTVisitor visitor) {
141         if (visitor.visit(this)) {
142             acceptChild!SQLExpr(visitor, this.arguments);
143             acceptChild(visitor, this.keep);
144             acceptChild(visitor, this.over);
145             acceptChild(visitor, this.overRef);
146             acceptChild(visitor, this.withinGroup);
147         }
148 
149         visitor.endVisit(this);
150     }
151 
152     public override List!SQLObject getChildren() {
153         List!SQLObject children = new ArrayList!SQLObject();
154         children.addAll(cast(List!SQLObject)(this.arguments));
155         if (keep !is null) {
156             children.add(this.keep);
157         }
158         if (over !is null) {
159             children.add(over);
160         }
161         if (withinGroup !is null) {
162             children.add(withinGroup);
163         }
164         return children;
165     }
166 
167     public override bool opEquals(Object o) {
168         if (this == o) return true;
169         if (o is null || typeid(SQLAggregateExpr) != typeid(o)) return false;
170 
171         SQLAggregateExpr that = cast(SQLAggregateExpr) o;
172 
173         if (_methodNameHashCod64 != that._methodNameHashCod64) return false;
174         if (methodName !is null ? !(methodName == that.methodName) : that.methodName !is null) return false;
175         if (option != that.option) return false;
176         if (arguments !is null ? !(cast(Object)arguments).opEquals(cast(Object)(that.arguments)) : that.arguments !is null) return false;
177         if (keep !is null ? !(cast(Object)(keep)).opEquals(cast(Object)(that.keep)) : that.keep !is null) return false;
178         if (filter !is null ? !(cast(Object)filter).opEquals(cast(Object)(that.filter)) : that.filter !is null) return false;
179         if (over !is null ? !(cast(Object)(over)).opEquals(cast(Object)(that.over)) : that.over !is null) return false;
180         if (overRef !is null ? !(cast(Object)overRef).opEquals(cast(Object)(that.overRef)) : that.overRef !is null) return false;
181         if (withinGroup !is null ? !(cast(Object)(withinGroup)).opEquals(cast(Object)(that.withinGroup)) : that.withinGroup !is null) return false;
182         return ignoreNulls == that.ignoreNulls;
183     }
184 
185     public override size_t toHash() @trusted nothrow {
186         size_t result = methodName !is null ? hashOf(methodName) : 0;
187         result = 31 * result + cast(int) (_methodNameHashCod64 ^ (_methodNameHashCod64 >>> 32));
188         result = 31 * result + hashOf(option);
189         result = 31 * result + (arguments !is null ? (cast(Object)arguments).toHash() : 0);
190         result = 31 * result + (keep !is null ? (cast(Object)keep).toHash() : 0);
191         result = 31 * result + (filter !is null ? (cast(Object)filter).toHash() : 0);
192         result = 31 * result + (over !is null ? (cast(Object)over).toHash() : 0);
193         result = 31 * result + (overRef !is null ? (cast(Object)overRef).toHash() : 0);
194         result = 31 * result + (withinGroup !is null ? (cast(Object)withinGroup).toHash() : 0);
195         result = 31 * result + hashOf(ignoreNulls);
196         return result;
197     }
198 
199     public override SQLAggregateExpr clone() {
200         SQLAggregateExpr x = new SQLAggregateExpr(methodName);
201 
202         x.option = option;
203 
204         foreach (SQLExpr arg ; arguments) {
205             x.addArgument(arg.clone());
206         }
207 
208         if (keep !is null) {
209             x.setKeep(keep.clone());
210         }
211 
212         if (filter !is null) {
213             x.setFilter(filter.clone());
214         }
215 
216         if (over !is null) {
217             x.setOver(over.clone());
218         }
219 
220         if (overRef !is null) {
221             x.setOverRef(overRef.clone());
222         }
223 
224         if (withinGroup !is null) {
225             x.setWithinGroup(withinGroup.clone());
226         }
227 
228         x.ignoreNulls = ignoreNulls;
229 
230         return x;
231     }
232 
233     public SQLExpr getFilter() {
234         return filter;
235     }
236 
237     public void setFilter(SQLExpr x) {
238         if (x !is null) {
239             x.setParent(this);
240         }
241         this.filter = x;
242     }
243 
244     public override SQLDataType computeDataType() {
245         long hash = methodNameHashCod64();
246 
247         if (hash == FnvHash.Constants.COUNT
248                 || hash == FnvHash.Constants.ROW_NUMBER) {
249             return SQLIntegerExpr.DEFAULT_DATA_TYPE;
250         }
251 
252         if (arguments.size() > 0) {
253             SQLDataType dataType = arguments.get(0).computeDataType();
254             if (dataType !is null) {
255                 return dataType;
256             }
257         }
258 
259         if (hash == FnvHash.Constants.WM_CONCAT
260                 || hash == FnvHash.Constants.GROUP_CONCAT) {
261             return SQLCharExpr.DEFAULT_DATA_TYPE;
262         }
263 
264         return null;
265     }
266 
267     public bool replace(SQLExpr expr, SQLExpr target) {
268         if (target is null) {
269             return false;
270         }
271 
272         for (int i = 0; i < arguments.size(); ++i) {
273             if (arguments.get(i) == expr) {
274                 arguments.set(i, target);
275                 target.setParent(this);
276                 return true;
277             }
278         }
279 
280         if (overRef == expr) {
281             setOverRef(cast(SQLName) target);
282             return true;
283         }
284 
285         if (filter == expr) {
286             this.filter = target;
287             target.setParent(this);
288         }
289 
290         return false;
291     }
292 }