1 module uim.mongo.filter;
2 
3 import uim.mongo;
4 
5 class DBsonFilter {
6     this() {
7         _bson = Bson.emptyObject;
8     }
9     this(T)(string field, T value) {
10         this();
11         _bson[field] = Bson(value);
12     }
13     this(T)(T[string] values) {
14         this();
15         _bson = value.toBson;
16     }
17 
18     private Bson _bson;
19 
20     /*
21     all() - creates an all filter for an array field. 
22     */
23     @safe O All(this O, T)(string field, T[] values) {
24         if (_bson[field].type != Bson.Type.null_) {
25             auto condition = _bson[field];
26             condition["$all"] = values.toBson;
27             _bson[field] = condition; 
28         }
29         else {
30             auto condition = Bson.emptyObject;
31             condition["$all"] = values.toBson;
32             _bson[field] = condition; 
33         }
34         return cast(O)this;    }
35     unittest{
36         writeln(BsonFilter.All("fruits", ["apple", "melone"]));
37     }
38 
39     /*
40     And() - creates an and field. 
41     */
42     @safe O And(this O, T)(string field, T value) {
43         _bson[field] = value;
44         return cast(O)this;
45     }
46     @safe O And(this O, T)(T[string] values) {
47         _bson = values.toBson;
48         return cast(O)this;
49     }
50     unittest{
51         assert(BsonFilter.And(["a":"b"]) == `{"a":"b"}`);
52         assert(BsonFilter.And(["a":"b", "c": "d"]) == `{"c":"d","a":"b"}`);
53     }
54 
55     /*
56     anyEq() - Creates an equality filter for an array field. 
57     */
58     @safe O anyEq(this O)() {
59         // TODO
60         return cast(O)this;
61     }
62     unittest{
63 
64     }
65 
66     /*
67     anyGt() - Creates an greater than filter for an array field. 
68     */
69     @safe O Gt(this O, T)(string field, T value) {
70         if (_bson[field].type != Bson.Type.null_) {
71             auto condition = _bson[field];
72             condition["$gt"] = Bson(value);
73             _bson[field] = condition; 
74         }
75         else {
76             auto condition = Bson.emptyObject;
77             condition["$gt"] = Bson(value);
78             _bson[field] = condition; 
79         }
80         return cast(O)this;
81     }
82     unittest{
83         writeln(BsonFilter.Gt("age", 20));
84         assert(BsonFilter.Gt("age", 20) == `{"age":{"$gt":20}}`);
85         assert(BsonFilter.Gt("age", 20).Gt("age", 40) == `{"age":{"$gt":40}}`);
86     }
87 
88     /*
89     anyGe() - Creates an greater than or equal filter for an array field. 
90     */
91     @safe O anyGe(this O, T)(string field, string value) {
92         // TODO
93         return cast(O)this;
94     }
95     unittest{
96 
97     }
98 
99     // $bitsAllClear 
100     @safe O BitsAllClear(this O)(string field, BsonBinData data) {
101         auto condition = Bson.emptyObject;
102         condition["$bitsAllClear"] = data;
103         _bson[field] = condition; 
104         return cast(O)this;
105     }
106     @safe O BitsAllClear(this O)(string field, int[] positions) {
107         auto condition = Bson.emptyObject;
108         condition["$bitsAllClear"] = positions.toBson;
109         _bson[field] = condition; 
110         return cast(O)this;
111     }
112     @safe O BitsAllClear(this O)(string field, int mask) {
113         auto condition = Bson.emptyObject;
114         condition["$bitsAllClear"] = mask;
115         _bson[field] = condition; 
116         return cast(O)this;
117     }
118     unittest{
119         assert(BsonFilter.BitsAllClear("a", [1, 5]) == `{"a":{"$bitsAllClear":[1,5]}}`);
120         assert(BsonFilter.BitsAllClear("a", 35) == `{"a":{"$bitsAllClear":35}}`);
121     }
122 
123     // $bitsAllSet  
124    @safe  O BitsAllSet(this O)(string field, BsonBinData data) {
125         auto condition = Bson.emptyObject;
126         condition["$bitsAllSet"] = data;
127         _bson[field] = condition; 
128         return cast(O)this;
129     }
130     @safe O BitsAllSet(this O)(string field, int[] positions) {
131         auto condition = Bson.emptyObject;
132         condition["$bitsAllSet"] = positions.toBson;
133         _bson[field] = condition; 
134         return cast(O)this;
135     }
136     @safe O BitsAllSet(this O)(string field, int mask) {
137         auto condition = Bson.emptyObject;
138         condition["$bitsAllSet"] = mask;
139         _bson[field] = condition; 
140         return cast(O)this;
141     }
142     unittest{
143         assert(BsonFilter.BitsAllSet("a", [1, 5]) == `{"a":{"$bitsAllSet":[1,5]}}`);
144         assert(BsonFilter.BitsAllSet("a", 35) == `{"a":{"$bitsAllSet":35}}`);
145     }
146 
147     // $bitsAnyClear 
148     @safe O BitsAnyClear(this O)(string field, BsonBinData data) {
149         auto condition = Bson.emptyObject;
150         condition["$bitsAnyClear"] = data;
151         _bson[field] = condition; 
152         return cast(O)this;
153     }
154     @safe O BitsAnyClear(this O)(string field, int[] positions) {
155         auto condition = Bson.emptyObject;
156         condition["$bitsAnyClear"] = positions.toBson;
157         _bson[field] = condition; 
158         return cast(O)this;
159     }
160     @safe O BitsAnyClear(this O)(string field, int mask) {
161         auto condition = Bson.emptyObject;
162         condition["$bitsAnyClear"] = mask;
163         _bson[field] = condition; 
164         return cast(O)this;
165     }
166     unittest{
167         assert(BsonFilter.BitsAnyClear("a", [1, 5]) == `{"a":{"$bitsAnyClear":[1,5]}}`);
168         assert(BsonFilter.BitsAnyClear("a", 35) == `{"a":{"$bitsAnyClear":35}}`);
169     }
170 
171     // $bitsAnySet  
172     @safe O BitsAnySet(this O)(string field, BsonBinData data) {
173         auto condition = Bson.emptyObject;
174         condition["$bitsAnySet"] = data;
175         _bson[field] = condition; 
176         return cast(O)this;
177     }
178     @safe O BitsAnySet(this O)(string field, int[] positions) {
179         auto condition = Bson.emptyObject;
180         condition["$bitsAnySet"] = positions.toBson;
181         _bson[field] = condition; 
182         return cast(O)this;
183     }
184     @safe O BitsAnySet(this O)(string field, int mask) {
185         auto condition = Bson.emptyObject;
186         condition["$bitsAnySet"] = mask;
187         _bson[field] = condition; 
188         return cast(O)this;
189     }
190     unittest{
191         assert(BsonFilter.BitsAnySet("a", [1, 5]) == `{"a":{"$bitsAnySet":[1,5]}}`);
192         assert(BsonFilter.BitsAnySet("a", 35) == `{"a":{"$bitsAnySet":35}}`);
193     }
194 
195     @safe O Comment(this O)(string text) {
196         _bson["$comment"] = text; 
197         return cast(O)this;
198     }
199     unittest{
200         assert(BsonFilter.BitsAnySet("a", [1, 5]) == `{"a":{"$bitsAnySet":[1,5]}}`);
201         assert(BsonFilter.BitsAnySet("a", 35) == `{"a":{"$bitsAnySet":35}}`);
202     }
203 
204     @safe O ElemMatch(this O)(string field, Bson condition) {
205         auto match = Bson.emptyObject;
206         match["$elemMatch"] = condition;
207         _bson[field] = match;
208         return cast(O)this;
209     }
210     unittest{
211         // students: { $elemMatch: { school: 102 } }
212     }
213 
214     @safe O Meta(this O)(string field, string txt) {
215         auto meta = Bson.emptyObject;
216         meta["$meta"] = Bson(text);
217         _bson[field] = meta;
218         return cast(O)this;
219     }
220     unittest{
221         // students: { $elemMatch: { school: 102 } }
222     }
223 
224     @safe O Slice(this O)(string field, int amount) {
225         auto slice = Bson.emptyObject;
226         slice["$slice"] = Bson(amount);
227         _bson[field] = slice;
228         return cast(O)this;
229     }
230     @safe O Slice(this O)(string field, size_t skip, size_t limit) {
231         auto slice = Bson.emptyObject;
232         slice["$slice"] = [skip, limit].toBson;
233         _bson[field] = slice;
234         return cast(O)this;
235     }
236     unittest{
237         // students: { $elemMatch: { school: 102 } }
238     }
239 
240     /*
241         In(this O, T)(string field, T[] values)
242         Adds an "in" filter for an array field 
243     */
244     @safe O In(this O, T)(string field, T[] values) {
245         auto condition = Bson.emptyObject;
246         condition["$in"] = values.toBson;
247         _bson[field] = condition;
248 
249         return cast(O)this;
250     }
251     unittest{
252         // In SQL: SELECT * FROM inventory WHERE status in ("A", "D")
253         assert(BsonFilter.In("status", ["A","D"]) == `{"status":{"$in":["A","D"]}}`);
254     }
255 
256     /*
257         Lt(this O)(string field, string value)
258         Adds an "less than" filter for field
259     */
260     @safe O Lt(this O, T)(string field, T value) {
261         if (_bson[field].type != Bson.Type.null_) {
262             auto condition = _bson[field];
263             condition["$lt"] = Bson(value);
264             _bson[field] = condition; 
265         }
266         else {
267             auto condition = Bson.emptyObject;
268             condition["$lt"] = Bson(value);
269             _bson[field] = condition; 
270         }
271         return cast(O)this;
272     }
273     unittest{
274         assert(BsonFilter.Lt("age", 20) == `{"age":{"$lt":20}}`);
275         assert(BsonFilter.Lt("age", 20).Gt("age", 40).Lt("name", "Tomb").Gt("name", "Raider") == `{"age":{"$lt":20,"$gt":40},"name":{"$lt":"Tomb","$gt":"Raider"}}`);
276     }
277 
278     /*
279     anyLe() - Creates an less than or equal filter for an array field. 
280     */
281     @safe O Le(this O, T)(string field, string value) {
282         // TODO
283         return cast(O)this;
284     }
285     unittest{
286 
287     }
288 
289     /*
290     anyNe() - Creates a not equal filter for an array field. 
291     */
292     @safe O Ne(this O, T)(string field, string value) {
293         // TODO
294         return cast(O)this;
295     }
296     unittest{
297 
298     }
299 
300     /*
301     or() - creates an or field. 
302     */
303     @safe O Or(this O)(DBsonFilter[] conditions) {
304         Bson[] bsons; bsons.length = conditions.length;
305         foreach(i, condition; conditions) bsons[i] = condition.toBson;
306         return this.Or(bsons);
307     }    
308     @safe O Or(this O)(Bson[] conditions) {
309         return this.Or(Bson(conditions));
310     }
311     @safe O Or(this O)(Bson conditions) {
312         _bson["$or"] = conditions;
313         return cast(O)this;
314     }
315     unittest{
316         // { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] }
317         assert(BsonFilter.Or([BsonFilter("status", "A"), BsonFilter.Lt("qty", 30)]) == `{"$or":[{"status":"A"},{"qty":{"$lt":30}}]}`);
318     }
319 
320     /*
321         Size to return documents in the collection where the array size of field is value
322     */
323     @safe O Size(this O, T)(string field, T value) if (isIntegral!T) {
324         if (_bson[field].type != Bson.Type.null_) {
325             auto condition = _bson[field];
326             condition["$size"] = Bson(value);
327             _bson[field] = condition; 
328         }
329         else {
330             auto condition = Bson.emptyObject;
331             condition["$size"] = Bson(value);
332             _bson[field] = condition; 
333         }
334         return cast(O)this;
335     }
336     unittest{
337         writeln(BsonFilter.Size("personen", 20));
338         assert(BsonFilter.Size("personen", 20) == `{"personen":{"$size":20}}`);
339     }
340 
341     bool opEquals(string txt) { return (toString == txt); }
342     @safe Bson toBson() {
343         return _bson;
344     }
345     override string toString() {
346         return _bson.toString;
347     }
348 }
349 auto BsonFilter() { return new DBsonFilter(); }
350 auto BsonFilter(T)(string field, T value) { return new DBsonFilter(field, value); }
351 auto BsonFilter(T)(T[string] values) { return new DBsonFilter(values); }
352 
353 unittest{
354 /*    writeln(
355         BsonFilter
356         .and(["field1":"b", "field2":"d"])
357         .or(["x":"y"]));*/
358 }