1 // query.js
  2 
  3 if ( typeof DBQuery == "undefined" ){
  4     DBQuery = function( mongo , db , collection , ns , query , fields , limit , skip ){
  5         
  6         this._mongo = mongo; // 0
  7         this._db = db; // 1
  8         this._collection = collection; // 2
  9         this._ns = ns; // 3
 10         
 11         this._query = query || {}; // 4
 12         this._fields = fields; // 5
 13         this._limit = limit || 0; // 6
 14         this._skip = skip || 0; // 7
 15         
 16         this._cursor = null;
 17         this._numReturned = 0;
 18         this._special = false;
 19     }
 20     print( "DBQuery probably won't have array access " );
 21 }
 22 
 23 DBQuery.prototype.help = function(){
 24     print( "DBQuery help" );
 25     print( "\t.sort( {...} )" )
 26     print( "\t.limit( n )" )
 27     print( "\t.skip( n )" )
 28     print( "\t.count()" )
 29     print( "\t.explain()" )
 30     print( "\t.forEach( func )" )
 31     print( "\t.map( func )" )
 32 
 33 }
 34 
 35 DBQuery.prototype.clone = function(){
 36     var q =  new DBQuery( this._mongo , this._db , this._collection , this._ns , 
 37         this._query , this._fields , 
 38         this._limit , this._skip );
 39     q._special = this._special;
 40     return q;
 41 }
 42 
 43 DBQuery.prototype._ensureSpecial = function(){
 44     if ( this._special )
 45         return;
 46     
 47     var n = { query : this._query };
 48     this._query = n;
 49     this._special = true;
 50 }
 51 
 52 DBQuery.prototype._checkModify = function(){
 53     if ( this._cursor )
 54         throw "query already executed";
 55 }
 56 
 57 DBQuery.prototype._exec = function(){
 58     if ( ! this._cursor ){
 59         assert.eq( 0 , this._numReturned );
 60         this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip );
 61         this._cursorSeen = 0;
 62     }
 63     return this._cursor;
 64 }
 65 
 66 DBQuery.prototype.limit = function( limit ){
 67     this._checkModify();
 68     this._limit = limit;
 69     return this;
 70 }
 71 
 72 DBQuery.prototype.skip = function( skip ){
 73     this._checkModify();
 74     this._skip = skip;
 75     return this;
 76 }
 77 
 78 DBQuery.prototype.hasNext = function(){
 79     this._exec();
 80 
 81     if ( this._limit > 0 && this._cursorSeen >= this._limit )
 82         return false;
 83     var o = this._cursor.hasNext();
 84     return o;
 85 }
 86 
 87 DBQuery.prototype.next = function(){
 88     this._exec();
 89     
 90     var o = this._cursor.hasNext();
 91     if ( o )
 92         this._cursorSeen++;
 93     else
 94         throw "error hasNext: " + o;
 95     
 96     var ret = this._cursor.next();
 97     if ( ret.$err && this._numReturned == 0 && ! this.hasNext() )
 98         throw "error: " + tojson( ret );
 99 
100     this._numReturned++;
101     return ret;
102 }
103 
104 DBQuery.prototype.toArray = function(){
105     if ( this._arr )
106         return this._arr;
107     
108     var a = [];
109     while ( this.hasNext() )
110         a.push( this.next() );
111     this._arr = a;
112     return a;
113 }
114 
115 DBQuery.prototype.count = function(){
116     var cmd = { count: this._collection.getName() };
117     if ( this._query ){
118         if ( this._special )
119             cmd.query = this._query.query;
120         else 
121             cmd.query = this._query;
122     }
123     cmd.fields = this._fields || {};
124     
125     var res = this._db.runCommand( cmd );
126     if( res && res.n != null ) return res.n;
127     throw "count failed: " + tojson( res );
128 }
129 
130 DBQuery.prototype.countReturn = function(){
131     var c = this.count();
132 
133     if ( this._skip )
134         c = c - this._skip;
135 
136     if ( this._limit > 0 && this._limit < c )
137         return this._limit;
138     
139     return c;
140 }
141 
142 /**
143 * iterative count - only for testing
144 */
145 DBQuery.prototype.itcount = function(){
146     var num = 0;
147     while ( this.hasNext() ){
148         num++;
149         this.next();
150     }
151     return num;
152 }
153 
154 DBQuery.prototype.length = function(){
155     return this.toArray().length;
156 }
157 
158 DBQuery.prototype.sort = function( sortBy ){
159     this._ensureSpecial();
160     this._query.orderby = sortBy;
161     return this;
162 }
163 
164 DBQuery.prototype.hint = function( hint ){
165     this._ensureSpecial();
166     this._query["$hint"] = hint;
167     return this;
168 }
169 
170 DBQuery.prototype.min = function( min ) {
171     this._ensureSpecial();
172     this._query["$min"] = min;
173     return this;
174 }
175 
176 DBQuery.prototype.max = function( max ) {
177     this._ensureSpecial();
178     this._query["$max"] = max;
179     return this;
180 }
181 
182 DBQuery.prototype.forEach = function( func ){
183     while ( this.hasNext() )
184         func( this.next() );
185 }
186 
187 DBQuery.prototype.map = function( func ){
188     var a = [];
189     while ( this.hasNext() )
190         a.push( func( this.next() ) );
191     return a;
192 }
193 
194 DBQuery.prototype.arrayAccess = function( idx ){
195     return this.toArray()[idx];
196 }
197 
198 DBQuery.prototype.explain = function(){
199     var n = this.clone();
200     n._ensureSpecial();
201     n._query.$explain = true;
202     n._limit = n._limit * -1;
203     return n.next();
204 }
205 
206 DBQuery.prototype.snapshot = function(){
207     this._ensureSpecial();
208     this._query.$snapshot = true;
209     return this;
210  }
211 
212 DBQuery.prototype.shellPrint = function(){
213     try {
214         var n = 0;
215         while ( this.hasNext() && n < 20 ){
216             var s = tojson( this.next() , "" , true );
217             print( s );
218             n++;
219         }
220         if ( this.hasNext() ){
221             print( "has more" );
222             ___it___  = this;
223         }
224         else {
225             ___it___  = null;
226         }
227     }
228     catch ( e ){
229         print( e );
230     }
231     
232 }
233 
234 DBQuery.prototype.toString = function(){
235     return "DBQuery: " + this._ns + " -> " + tojson( this.query );
236 }
237