1 /*
2  * Copyright (C) 2019, HuntLabs
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  */
17 module hunt.database.base.impl.RowSetImpl;
18 
19 import hunt.database.base.impl.RowInternal;
20 import hunt.database.base.impl.SqlResultBase;
21 
22 import hunt.database.base.RowIterator;
23 import hunt.database.base.RowSet;
24 import hunt.database.base.Row;
25 
26 import hunt.Exceptions;
27 import hunt.Functions;
28 
29 import std.array;
30 import std.ascii : newline;
31 import std.variant;
32 
33 /**
34  * 
35  */
36 class RowSetImpl : SqlResultBase!(RowSet, RowSetImpl), RowSet {
37 
38     static void accumulator(RowSetImpl set, Row row) {
39         if (set.head is null) {
40             set.head = set.tail = cast(RowInternal) row;
41         } else {
42             set.tail.setNext(cast(RowInternal) row);
43             set.tail = set.tail.getNext();
44         }
45     }    
46 
47     static Function!(RowSet, RowSetImpl) FACTORY() {
48         return (rs) { return cast(RowSetImpl) rs; } ;
49     }
50 
51     private RowInternal head;
52     private RowInternal tail;
53 
54     override
55     RowSet value() {
56         return this;
57     }
58 
59     override
60     string[] columnsNames() {
61         return _columnNames;
62     }
63 
64     override
65     int rowCount() {
66         return _updated;
67     }
68     
69     void rowCount(int v) {
70         this._updated = v;
71     }
72 
73     override int size() {
74         return _size;
75     }
76 
77     
78     Row firstRow() {
79         return head;
80     }
81 
82     Row lastRow() {
83         return tail;
84     }
85 
86     Variant property(string key) {
87         if(key.empty) {
88             throw new IllegalArgumentException("Property can not be null");
89         }
90 
91         if(properties is null)
92             return Variant(null);
93         
94         return properties.get(key, Variant(null));
95     }
96 
97     override
98     RowSetImpl next() {
99         return _next;
100     }
101 
102     alias next = SqlResultBase!(RowSet, RowSetImpl).next;
103 
104     void append(Row row) {
105         if (this.head is null) {
106             this.head = this.tail = cast(RowInternal) row;
107         } else {
108             this.tail.setNext(cast(RowInternal) row);
109             this.tail = this.tail.getNext();
110         }        
111     }
112 
113     // override int size() {
114     //     return super.size();
115     // }
116     
117     // override int rowCount() {
118     //     return super.rowCount();
119     // }
120 
121     // override string[] columnsNames() {
122     //     return super.columnsNames();
123     // }
124 
125     override string toString() {
126         Appender!string sb;
127 
128         sb.put("|");
129         foreach(string name; _columnNames) {
130             sb.put(" ");
131             sb.put(name);
132             sb.put(" |");
133         }
134         sb.put(newline);
135         sb.put("-------------------------------------------------------");
136         sb.put(newline);
137 
138         foreach(Row row; this) {
139             sb.put("|");
140             for(int i=0; i<row.size(); i++) {
141                 sb.put(" ");
142                 sb.put(row[i].toString());
143                 sb.put(" |");
144             }
145             sb.put(newline);
146         }
147 
148         return sb.data;
149     }
150 
151     int opApply(scope int delegate(ref Row) dg) {
152 
153         int result = 0;
154         RowInternal cur = head;
155         while(cur !is null) {
156             Row r = cur;
157             result = dg(r);
158             cur = cur.getNext();
159         }
160         return result;        
161     }
162 
163     override
164     RowIterator iterator() {
165         return new IteratorImpl();
166     }
167 
168     private class IteratorImpl : RowIterator {
169         RowInternal current;
170 
171         this() {
172             current = head;
173         }
174 
175         bool empty() {
176             return current is null;
177         }
178 
179         Row front() {
180             if (current is null) {
181                 throw new NoSuchElementException("No such element!");
182             }
183 
184             return current;
185         }
186 
187         void popFront() {
188             if (current is null) {
189                 throw new NoSuchElementException();
190             }
191             current = current.getNext();
192         }
193 
194         Row moveFront() {
195             throw new NotImplementedException();
196         }
197 
198         int opApply(scope int delegate(Row) dg) {
199             int result = 0;
200             RowInternal cur = head;
201             while(cur !is null) {
202                 result = dg(cur);
203                 cur = cur.getNext();
204             }
205             return result;
206         }
207 
208         /// Ditto
209         int opApply(scope int delegate(size_t, Row) dg) {
210             int result = 0;
211             size_t index = 0;
212             RowInternal cur = head;
213             while(cur !is null) {
214                 result = dg(index++, cur);
215                 cur = cur.getNext();
216             }
217             return result;   
218         }
219 
220     }
221 }