|
|
|
@ -1,9 +1,11 @@ |
|
|
|
|
/** |
|
|
|
|
* Manage access to data, be it to find, update or remove it |
|
|
|
|
*/ |
|
|
|
|
var model = require('./model'); |
|
|
|
|
var model = require('./model') |
|
|
|
|
, _ = require('underscore') |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Create a new cursor for this collection |
|
|
|
@ -38,7 +40,7 @@ Cursor.prototype.skip = function(skip) { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sort results of the query |
|
|
|
|
* @Param {SortQuery} sortQuery - SortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending |
|
|
|
|
* @param {SortQuery} sortQuery - SortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending |
|
|
|
|
*/ |
|
|
|
|
Cursor.prototype.sort = function(sortQuery) { |
|
|
|
|
this._sort = sortQuery; |
|
|
|
@ -46,6 +48,50 @@ Cursor.prototype.sort = function(sortQuery) { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Add the use of a projection |
|
|
|
|
* @param {Object} projection - MongoDB-style projection. {} means take all fields. Then it's {key1:1, key2:1} to take only key1 and key2 |
|
|
|
|
* {key1: 0, key2: 0} to omit only key1 and key2. Except _id, you can't mix takes and omits |
|
|
|
|
*/ |
|
|
|
|
Cursor.prototype.projection = function(projection) { |
|
|
|
|
this._projection = projection; |
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Apply the projection |
|
|
|
|
*/ |
|
|
|
|
Cursor.prototype.project = function (candidates) { |
|
|
|
|
var res = [], self = this |
|
|
|
|
, keepId, action, keys |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
if (this._projection === undefined || Object.keys(this._projection).length === 0) { |
|
|
|
|
return candidates; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
keepId = this._projection._id === 0 ? false : true; |
|
|
|
|
this._projection = _.omit(this._projection, '_id'); |
|
|
|
|
|
|
|
|
|
// Check for consistency
|
|
|
|
|
keys = Object.keys(this._projection); |
|
|
|
|
keys.forEach(function (k) { |
|
|
|
|
if (action !== undefined && self._projection[k] !== action) { throw "Can't both keep and omit fields except for _id"; } |
|
|
|
|
action = self._projection[k]; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Do the actual projection
|
|
|
|
|
candidates.forEach(function (candidate) { |
|
|
|
|
var toPush = action === 1 ? _.pick(candidate, keys) : _.omit(candidate, keys); |
|
|
|
|
if (keepId) { toPush._id = candidate._id; } |
|
|
|
|
res.push(candidate); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get all matching elements |
|
|
|
|
* Will return pointers to matched elements (shallow copies), returning full copies is the role of find or findOne |
|
|
|
@ -56,6 +102,7 @@ Cursor.prototype.sort = function(sortQuery) { |
|
|
|
|
Cursor.prototype._exec = function(callback) { |
|
|
|
|
var candidates = this.db.getCandidates(this.query) |
|
|
|
|
, res = [], added = 0, skipped = 0, self = this |
|
|
|
|
, error = null |
|
|
|
|
, i, keys, key |
|
|
|
|
; |
|
|
|
|
|
|
|
|
@ -109,10 +156,18 @@ Cursor.prototype._exec = function(callback) { |
|
|
|
|
res = res.slice(skip, skip + limit); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Apply projection
|
|
|
|
|
try { |
|
|
|
|
res = this.project(res); |
|
|
|
|
} catch (e) { |
|
|
|
|
error = e; |
|
|
|
|
res = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this.execFn) { |
|
|
|
|
return this.execFn(null, res, callback); |
|
|
|
|
return this.execFn(error, res, callback); |
|
|
|
|
} else { |
|
|
|
|
return callback(null, res); |
|
|
|
|
return callback(error, res); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|