forked from fongandrew/meteor-find-and-modify
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfind_and_modify.js
127 lines (105 loc) · 3.93 KB
/
find_and_modify.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
(function() {
'use strict';
// Code adapted from https://github.com/meteor/meteor/issues/1070
// Helper func to run shared validation code
function validate(collection, args) {
if(!collection._name)
throw new Meteor.Error(405,
"findAndModify: Must have collection name.");
if(!args)
throw new Meteor.Error(405, "findAndModify: Must have args.");
if(!args.query)
throw new Meteor.Error(405, "findAndModify: Must have query.");
if(!args.update && !args.remove)
throw new Meteor.Error(405,
"findAndModify: Must have update or remove.");
};
if (Meteor.isServer) {
Mongo.Collection.prototype.findAndModify = function(args){
validate(this, args);
var q = {};
q.query = args.query || {};
q.sort = args.sort || {};
if (args.update)
q.update = args.update;
q.options = {};
if (args.new !== undefined)
q.options.new = args.new;
if (args.remove !== undefined)
q.options.remove = args.remove;
if (args.upsert !== undefined)
q.options.upsert = args.upsert;
if (args.fields !== undefined)
q.options.fields = args.fields;
// If upsert, assign a string Id to $setOnInsert unless otherwise provided
if (q.options.upsert) {
q.update = q.update || {};
q.update.$setOnInsert = q.update.$setOnInsert || {};
q.update.$setOnInsert._id = q.update.$setOnInsert._id || Random.id(17);
}
// Use rawCollection object introduced in Meteor 1.0.4.
var collectionObj = this.rawCollection();
var wrappedFunc = Meteor.wrapAsync(collectionObj.findAndModify,
collectionObj);
return wrappedFunc(
q.query,
q.sort,
q.update,
q.options
);
};
}
if (Meteor.isClient) {
Mongo.Collection.prototype.findAndModify = function(args) {
validate(this, args);
var findOptions = {};
if (args.sort !== undefined)
findOptions.sort = args.sort;
if (args.fields !== undefined)
findOptions.fields = args.fields;
if (args.skip !== undefined)
findOptions.skip = args.skip;
var ret = this.findOne(args.query, findOptions);
if (args.remove) {
if (ret) this.remove({_id: ret._id});
}
else {
if (args.upsert && !ret) {
var writeResult = this.upsert(args.query, args.update);
if (writeResult.insertedId && args.new)
return this.findOne({_id: writeResult.insertedId}, findOptions);
else if (findOptions.sort)
return {};
return null;
}
else if (ret) {
// If we're in a simulation, it's safe to call update with normal
// selectors (which is needed, e.g., for modifiers with positional
// operators). Otherwise, we'll have to do an _id only update to
// get around the restriction that lets untrusted (e.g. client)
// code update collections by _id only.
var enclosing = DDP._CurrentInvocation.get();
var alreadyInSimulation = enclosing && enclosing.isSimulation;
if (alreadyInSimulation) {
// Add _id to query because Meteor's update doesn't include certain
// options that the full findAndModify does (like sort). Create
// shallow copy before update so as not to mess with user's
// original query object
var updatedQuery = {};
for (var prop in args.query) {
updatedQuery[prop] = args.query[prop];
}
updatedQuery._id = ret._id;
this.update(updatedQuery, args.update);
}
else {
this.update({_id: ret._id}, args.update);
}
if (args.new)
return this.findOne({_id: ret._id}, findOptions);
}
}
return ret;
};
}
})();