mongoose 4.11.8 → 4.11.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/History.md +38 -0
- package/lib/browser.js +4 -1
- package/lib/connection.js +8 -1
- package/lib/document.js +9 -171
- package/lib/document_provider.js +10 -1
- package/lib/error/browserMissingSchema.js +5 -1
- package/lib/error/divergentArray.js +5 -1
- package/lib/error/missingSchema.js +5 -1
- package/lib/error/overwriteModel.js +5 -1
- package/lib/index.js +0 -10
- package/lib/model.js +32 -19
- package/lib/query.js +10 -5
- package/lib/queryhelpers.js +9 -5
- package/lib/schema/embedded.js +7 -1
- package/lib/schema/objectid.js +7 -3
- package/lib/schema.js +100 -45
- package/lib/services/document/cleanModifiedSubpaths.js +18 -0
- package/lib/services/document/compile.js +165 -0
- package/lib/services/model/discriminator.js +8 -0
- package/lib/services/query/castUpdate.js +1 -1
- package/lib/types/array.js +33 -3
- package/lib/types/buffer.js +13 -0
- package/lib/types/subdocument.js +1 -1
- package/package.json +2 -1
package/History.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
4.11.12 / 2017-09-18
|
|
2
|
+
====================
|
|
3
|
+
* docs(model): asterisk should not render as markdown bullet #5644 [timkinnane](https://github.com/timkinnane)
|
|
4
|
+
* docs: use useMongoClient in connection example #5627 [GabrielNicolasAvellaneda](https://github.com/GabrielNicolasAvellaneda)
|
|
5
|
+
* fix(connection): call callback when initial connection failed #5626
|
|
6
|
+
* fix(query): apply select correctly if a given nested schema is used for 2 different paths #5603
|
|
7
|
+
* fix(document): add graceful fallback for setting a doc array value and `pull()`-ing a doc #3511
|
|
8
|
+
|
|
9
|
+
4.11.11 / 2017-09-10
|
|
10
|
+
====================
|
|
11
|
+
* fix(connection): properly set readyState in response to driver 'close' and 'reconnect' events #5604
|
|
12
|
+
* fix(document): ensure single embedded doc setters only get called once, with correct value #5601
|
|
13
|
+
* fix(timestamps): allow enabling updatedAt without createdAt #5598
|
|
14
|
+
* test: improve unique validator test by making create run before ensureIndex #5595 #5562
|
|
15
|
+
* fix(query): ensure find callback only gets called once when post init hook throws error #5592
|
|
16
|
+
|
|
17
|
+
4.11.10 / 2017-09-03
|
|
18
|
+
====================
|
|
19
|
+
* docs: add KeenIO tracking #5612
|
|
20
|
+
* fix(schema): ensure validators declared with `.validate()` get copied with clone() #5607
|
|
21
|
+
* fix: remove unnecessary jest warning #5480
|
|
22
|
+
* fix(discriminator): prevent implicit discriminator schema id from clobbering base schema custom id #5591
|
|
23
|
+
* fix(schema): hide schema objectid warning for non-hex strings of length 24 #5587
|
|
24
|
+
* docs(populate): use story schema defined key author instead of creator #5578 [dmric](https://github.com/dmric)
|
|
25
|
+
* docs(document): describe usage of `.set()` #5576
|
|
26
|
+
* fix(document): ensure correct scope in single nested validators #5569
|
|
27
|
+
* fix(populate): don't mark path as populated until populate() is done #5564
|
|
28
|
+
* fix(document): make push()-ing a doc onto an empty array act as manual population #5504
|
|
29
|
+
* fix(connection): emit timeout event on socket timeout #4513
|
|
30
|
+
|
|
31
|
+
4.11.9 / 2017-08-27
|
|
32
|
+
===================
|
|
33
|
+
* fix(error): avoid using arguments.callee because that breaks strict mode #5572
|
|
34
|
+
* docs(schematypes): fix spacing #5567
|
|
35
|
+
* fix(query): enforce binary subtype always propagates to mongodb #5551
|
|
36
|
+
* fix(query): only skip castForQuery for mongoose arrays #5536
|
|
37
|
+
* fix(browser): rely on browser entrypoint to decide whether to use BrowserDocument or NodeDocument #5480
|
|
38
|
+
|
|
1
39
|
4.11.8 / 2017-08-23
|
|
2
40
|
===================
|
|
3
41
|
* feat: add warning about using schema ObjectId as type ObjectId #5571 [efkan](https://github.com/efkan)
|
package/lib/browser.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/* eslint-env browser */
|
|
2
2
|
|
|
3
|
+
var DocumentProvider = require('./document_provider.js');
|
|
3
4
|
var PromiseProvider = require('./promise_provider');
|
|
4
5
|
|
|
6
|
+
DocumentProvider.setBrowser(true);
|
|
7
|
+
|
|
5
8
|
/**
|
|
6
9
|
* The Mongoose [Promise](#promise_Promise) constructor.
|
|
7
10
|
*
|
|
@@ -114,7 +117,7 @@ exports.utils = require('./utils.js');
|
|
|
114
117
|
* @method Document
|
|
115
118
|
* @api public
|
|
116
119
|
*/
|
|
117
|
-
exports.Document =
|
|
120
|
+
exports.Document = DocumentProvider();
|
|
118
121
|
|
|
119
122
|
/*!
|
|
120
123
|
* Module exports.
|
package/lib/connection.js
CHANGED
|
@@ -66,6 +66,7 @@ function Connection(base) {
|
|
|
66
66
|
this.name = null;
|
|
67
67
|
this.options = null;
|
|
68
68
|
this.otherDbs = [];
|
|
69
|
+
this.states = STATES;
|
|
69
70
|
this._readyState = STATES.disconnected;
|
|
70
71
|
this._closeCalled = false;
|
|
71
72
|
this._hasOpened = false;
|
|
@@ -760,14 +761,20 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
760
761
|
if (_this.listeners('error').length) {
|
|
761
762
|
_this.emit('error', error);
|
|
762
763
|
}
|
|
764
|
+
callback && callback(error);
|
|
763
765
|
return reject(error);
|
|
764
766
|
}
|
|
765
767
|
// Backwards compat for mongoose 4.x
|
|
766
768
|
db.on('reconnect', function() {
|
|
769
|
+
_this.readyState = STATES.connected;
|
|
767
770
|
_this.emit('reconnected');
|
|
768
771
|
});
|
|
769
772
|
db.s.topology.on('close', function() {
|
|
770
|
-
|
|
773
|
+
// Implicitly emits 'disconnected'
|
|
774
|
+
_this.readyState = STATES.disconnected;
|
|
775
|
+
});
|
|
776
|
+
db.on('timeout', function() {
|
|
777
|
+
_this.emit('timeout');
|
|
771
778
|
});
|
|
772
779
|
|
|
773
780
|
_this.db = db;
|
package/lib/document.js
CHANGED
|
@@ -16,7 +16,10 @@ var isMongooseObject = utils.isMongooseObject;
|
|
|
16
16
|
var inspect = require('util').inspect;
|
|
17
17
|
var ValidationError = MongooseError.ValidationError;
|
|
18
18
|
var InternalCache = require('./internal');
|
|
19
|
+
var cleanModifiedSubpaths = require('./services/document/cleanModifiedSubpaths');
|
|
20
|
+
var compile = require('./services/document/compile').compile;
|
|
19
21
|
var deepEqual = utils.deepEqual;
|
|
22
|
+
var defineKey = require('./services/document/compile').defineKey;
|
|
20
23
|
var hooks = require('hooks-fixed');
|
|
21
24
|
var PromiseProvider = require('./promise_provider');
|
|
22
25
|
var DocumentArray;
|
|
@@ -498,12 +501,13 @@ Document.prototype.set = function(path, val, type, options) {
|
|
|
498
501
|
type = undefined;
|
|
499
502
|
}
|
|
500
503
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
504
|
+
options = options || {};
|
|
505
|
+
var merge = options.merge;
|
|
506
|
+
var adhoc = type && type !== true;
|
|
507
|
+
var constructing = type === true;
|
|
508
|
+
var adhocs;
|
|
505
509
|
|
|
506
|
-
var strict =
|
|
510
|
+
var strict = 'strict' in options
|
|
507
511
|
? options.strict
|
|
508
512
|
: this.$__.strictMode;
|
|
509
513
|
|
|
@@ -774,20 +778,6 @@ Document.prototype.set = function(path, val, type, options) {
|
|
|
774
778
|
return this;
|
|
775
779
|
};
|
|
776
780
|
|
|
777
|
-
/*!
|
|
778
|
-
* ignore
|
|
779
|
-
*/
|
|
780
|
-
|
|
781
|
-
function cleanModifiedSubpaths(doc, path) {
|
|
782
|
-
var _modifiedPaths = Object.keys(doc.$__.activePaths.states.modify);
|
|
783
|
-
var _numModifiedPaths = _modifiedPaths.length;
|
|
784
|
-
for (var j = 0; j < _numModifiedPaths; ++j) {
|
|
785
|
-
if (_modifiedPaths[j].indexOf(path + '.') === 0) {
|
|
786
|
-
delete doc.$__.activePaths.states.modify[_modifiedPaths[j]];
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
781
|
/**
|
|
792
782
|
* Determine if we should mark this change as modified.
|
|
793
783
|
*
|
|
@@ -1833,158 +1823,6 @@ Document.prototype.$__dirty = function() {
|
|
|
1833
1823
|
return minimal;
|
|
1834
1824
|
};
|
|
1835
1825
|
|
|
1836
|
-
/*!
|
|
1837
|
-
* Compiles schemas.
|
|
1838
|
-
*/
|
|
1839
|
-
|
|
1840
|
-
function compile(tree, proto, prefix, options) {
|
|
1841
|
-
var keys = Object.keys(tree);
|
|
1842
|
-
var i = keys.length;
|
|
1843
|
-
var len = keys.length;
|
|
1844
|
-
var limb;
|
|
1845
|
-
var key;
|
|
1846
|
-
|
|
1847
|
-
if (options.retainKeyOrder) {
|
|
1848
|
-
for (i = 0; i < len; ++i) {
|
|
1849
|
-
key = keys[i];
|
|
1850
|
-
limb = tree[key];
|
|
1851
|
-
|
|
1852
|
-
defineKey(key,
|
|
1853
|
-
((utils.getFunctionName(limb.constructor) === 'Object'
|
|
1854
|
-
&& Object.keys(limb).length)
|
|
1855
|
-
&& (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type))
|
|
1856
|
-
? limb
|
|
1857
|
-
: null)
|
|
1858
|
-
, proto
|
|
1859
|
-
, prefix
|
|
1860
|
-
, keys
|
|
1861
|
-
, options);
|
|
1862
|
-
}
|
|
1863
|
-
} else {
|
|
1864
|
-
while (i--) {
|
|
1865
|
-
key = keys[i];
|
|
1866
|
-
limb = tree[key];
|
|
1867
|
-
|
|
1868
|
-
defineKey(key,
|
|
1869
|
-
((utils.getFunctionName(limb.constructor) === 'Object'
|
|
1870
|
-
&& Object.keys(limb).length)
|
|
1871
|
-
&& (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type))
|
|
1872
|
-
? limb
|
|
1873
|
-
: null)
|
|
1874
|
-
, proto
|
|
1875
|
-
, prefix
|
|
1876
|
-
, keys
|
|
1877
|
-
, options);
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
// gets descriptors for all properties of `object`
|
|
1883
|
-
// makes all properties non-enumerable to match previous behavior to #2211
|
|
1884
|
-
function getOwnPropertyDescriptors(object) {
|
|
1885
|
-
var result = {};
|
|
1886
|
-
|
|
1887
|
-
Object.getOwnPropertyNames(object).forEach(function(key) {
|
|
1888
|
-
result[key] = Object.getOwnPropertyDescriptor(object, key);
|
|
1889
|
-
result[key].enumerable = ['isNew', '$__', 'errors', '_doc'].indexOf(key) === -1;
|
|
1890
|
-
});
|
|
1891
|
-
|
|
1892
|
-
return result;
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
/*!
|
|
1896
|
-
* Defines the accessor named prop on the incoming prototype.
|
|
1897
|
-
*/
|
|
1898
|
-
|
|
1899
|
-
function defineKey(prop, subprops, prototype, prefix, keys, options) {
|
|
1900
|
-
var path = (prefix ? prefix + '.' : '') + prop;
|
|
1901
|
-
prefix = prefix || '';
|
|
1902
|
-
|
|
1903
|
-
if (subprops) {
|
|
1904
|
-
Object.defineProperty(prototype, prop, {
|
|
1905
|
-
enumerable: true,
|
|
1906
|
-
configurable: true,
|
|
1907
|
-
get: function() {
|
|
1908
|
-
var _this = this;
|
|
1909
|
-
if (!this.$__.getters) {
|
|
1910
|
-
this.$__.getters = {};
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
if (!this.$__.getters[path]) {
|
|
1914
|
-
var nested = Object.create(Object.getPrototypeOf(this), getOwnPropertyDescriptors(this));
|
|
1915
|
-
|
|
1916
|
-
// save scope for nested getters/setters
|
|
1917
|
-
if (!prefix) {
|
|
1918
|
-
nested.$__.scope = this;
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
// shadow inherited getters from sub-objects so
|
|
1922
|
-
// thing.nested.nested.nested... doesn't occur (gh-366)
|
|
1923
|
-
var i = 0,
|
|
1924
|
-
len = keys.length;
|
|
1925
|
-
|
|
1926
|
-
for (; i < len; ++i) {
|
|
1927
|
-
// over-write the parents getter without triggering it
|
|
1928
|
-
Object.defineProperty(nested, keys[i], {
|
|
1929
|
-
enumerable: false, // It doesn't show up.
|
|
1930
|
-
writable: true, // We can set it later.
|
|
1931
|
-
configurable: true, // We can Object.defineProperty again.
|
|
1932
|
-
value: undefined // It shadows its parent.
|
|
1933
|
-
});
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
Object.defineProperty(nested, 'toObject', {
|
|
1937
|
-
enumerable: false,
|
|
1938
|
-
configurable: true,
|
|
1939
|
-
writable: false,
|
|
1940
|
-
value: function() {
|
|
1941
|
-
return clone(_this.get(path), { retainKeyOrder: true });
|
|
1942
|
-
}
|
|
1943
|
-
});
|
|
1944
|
-
|
|
1945
|
-
Object.defineProperty(nested, 'toJSON', {
|
|
1946
|
-
enumerable: false,
|
|
1947
|
-
configurable: true,
|
|
1948
|
-
writable: false,
|
|
1949
|
-
value: function() {
|
|
1950
|
-
return _this.get(path);
|
|
1951
|
-
}
|
|
1952
|
-
});
|
|
1953
|
-
|
|
1954
|
-
Object.defineProperty(nested, '$__isNested', {
|
|
1955
|
-
enumerable: false,
|
|
1956
|
-
configurable: true,
|
|
1957
|
-
writable: false,
|
|
1958
|
-
value: true
|
|
1959
|
-
});
|
|
1960
|
-
|
|
1961
|
-
compile(subprops, nested, path, options);
|
|
1962
|
-
this.$__.getters[path] = nested;
|
|
1963
|
-
}
|
|
1964
|
-
|
|
1965
|
-
return this.$__.getters[path];
|
|
1966
|
-
},
|
|
1967
|
-
set: function(v) {
|
|
1968
|
-
if (v instanceof Document) {
|
|
1969
|
-
v = v.toObject({ transform: false });
|
|
1970
|
-
}
|
|
1971
|
-
return (this.$__.scope || this).set(path, v);
|
|
1972
|
-
}
|
|
1973
|
-
});
|
|
1974
|
-
} else {
|
|
1975
|
-
Object.defineProperty(prototype, prop, {
|
|
1976
|
-
enumerable: true,
|
|
1977
|
-
configurable: true,
|
|
1978
|
-
get: function() {
|
|
1979
|
-
return this.get.call(this.$__.scope || this, path);
|
|
1980
|
-
},
|
|
1981
|
-
set: function(v) {
|
|
1982
|
-
return this.set.call(this.$__.scope || this, path, v);
|
|
1983
|
-
}
|
|
1984
|
-
});
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
1826
|
/**
|
|
1989
1827
|
* Assigns/compiles `schema` into this documents prototype.
|
|
1990
1828
|
*
|
package/lib/document_provider.js
CHANGED
|
@@ -8,14 +8,23 @@
|
|
|
8
8
|
var Document = require('./document.js');
|
|
9
9
|
var BrowserDocument = require('./browserDocument.js');
|
|
10
10
|
|
|
11
|
+
var isBrowser = false;
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Returns the Document constructor for the current context
|
|
13
15
|
*
|
|
14
16
|
* @api private
|
|
15
17
|
*/
|
|
16
18
|
module.exports = function() {
|
|
17
|
-
if (
|
|
19
|
+
if (isBrowser) {
|
|
18
20
|
return BrowserDocument;
|
|
19
21
|
}
|
|
20
22
|
return Document;
|
|
21
23
|
};
|
|
24
|
+
|
|
25
|
+
/*!
|
|
26
|
+
* ignore
|
|
27
|
+
*/
|
|
28
|
+
module.exports.setBrowser = function(flag) {
|
|
29
|
+
isBrowser = flag;
|
|
30
|
+
};
|
|
@@ -15,7 +15,11 @@ function MissingSchemaError() {
|
|
|
15
15
|
+ 'Use mongoose.Document(name, schema)';
|
|
16
16
|
MongooseError.call(this, msg);
|
|
17
17
|
this.name = 'MissingSchemaError';
|
|
18
|
-
|
|
18
|
+
if (Error.captureStackTrace) {
|
|
19
|
+
Error.captureStackTrace(this);
|
|
20
|
+
} else {
|
|
21
|
+
this.stack = new Error().stack;
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
/*!
|
|
@@ -24,7 +24,11 @@ function DivergentArrayError(paths) {
|
|
|
24
24
|
|
|
25
25
|
MongooseError.call(this, msg);
|
|
26
26
|
this.name = 'DivergentArrayError';
|
|
27
|
-
|
|
27
|
+
if (Error.captureStackTrace) {
|
|
28
|
+
Error.captureStackTrace(this);
|
|
29
|
+
} else {
|
|
30
|
+
this.stack = new Error().stack;
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/*!
|
|
@@ -16,7 +16,11 @@ function MissingSchemaError(name) {
|
|
|
16
16
|
+ 'Use mongoose.model(name, schema)';
|
|
17
17
|
MongooseError.call(this, msg);
|
|
18
18
|
this.name = 'MissingSchemaError';
|
|
19
|
-
|
|
19
|
+
if (Error.captureStackTrace) {
|
|
20
|
+
Error.captureStackTrace(this);
|
|
21
|
+
} else {
|
|
22
|
+
this.stack = new Error().stack;
|
|
23
|
+
}
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
/*!
|
|
@@ -14,7 +14,11 @@ var MongooseError = require('../error.js');
|
|
|
14
14
|
function OverwriteModelError(name) {
|
|
15
15
|
MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
|
|
16
16
|
this.name = 'OverwriteModelError';
|
|
17
|
-
|
|
17
|
+
if (Error.captureStackTrace) {
|
|
18
|
+
Error.captureStackTrace(this);
|
|
19
|
+
} else {
|
|
20
|
+
this.stack = new Error().stack;
|
|
21
|
+
}
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
/*!
|
package/lib/index.js
CHANGED
|
@@ -858,13 +858,3 @@ MongooseThenable.prototype.catch = function(onRejected) {
|
|
|
858
858
|
*/
|
|
859
859
|
|
|
860
860
|
var mongoose = module.exports = exports = new Mongoose;
|
|
861
|
-
|
|
862
|
-
/*!
|
|
863
|
-
* ignore
|
|
864
|
-
*/
|
|
865
|
-
|
|
866
|
-
if (typeof jest !== 'undefined' && typeof window !== 'undefined') {
|
|
867
|
-
console.warn('You are running mongoose with jest in the jsdom environment. ' +
|
|
868
|
-
'You probably do not want to do this. Switch to the node environment: ' +
|
|
869
|
-
'https://facebook.github.io/jest/docs/configuration.html#testenvironment-string');
|
|
870
|
-
}
|
package/lib/model.js
CHANGED
|
@@ -865,7 +865,10 @@ for (var i in EventEmitter.prototype) {
|
|
|
865
865
|
Model.init = function init() {
|
|
866
866
|
if ((this.schema.options.autoIndex) ||
|
|
867
867
|
(this.schema.options.autoIndex == null && this.db.config.autoIndex)) {
|
|
868
|
-
|
|
868
|
+
var _this = this;
|
|
869
|
+
setImmediate(function() {
|
|
870
|
+
_this.ensureIndexes({ __noPromise: true, _automatic: true });
|
|
871
|
+
});
|
|
869
872
|
}
|
|
870
873
|
|
|
871
874
|
this.schema.emit('init', this);
|
|
@@ -1283,7 +1286,7 @@ Model.find = function find(conditions, projection, options, callback) {
|
|
|
1283
1286
|
*
|
|
1284
1287
|
* Note: `findById()` triggers `findOne` hooks.
|
|
1285
1288
|
*
|
|
1286
|
-
*
|
|
1289
|
+
* \* Except for how it treats `undefined`. If you use `findOne()`, you'll see
|
|
1287
1290
|
* that `findOne(undefined)` and `findOne({ _id: undefined })` are equivalent
|
|
1288
1291
|
* to `findOne({})` and return arbitrary documents. However, mongoose
|
|
1289
1292
|
* translates `findById(undefined)` into `findOne({ _id: null })`.
|
|
@@ -1562,12 +1565,12 @@ Model.$where = function $where() {
|
|
|
1562
1565
|
* ####Example:
|
|
1563
1566
|
*
|
|
1564
1567
|
* var query = { name: 'borne' };
|
|
1565
|
-
* Model.findOneAndUpdate(query, { name: 'jason
|
|
1568
|
+
* Model.findOneAndUpdate(query, { name: 'jason bourne' }, options, callback)
|
|
1566
1569
|
*
|
|
1567
1570
|
* // is sent as
|
|
1568
|
-
* Model.findOneAndUpdate(query, { $set: { name: 'jason
|
|
1571
|
+
* Model.findOneAndUpdate(query, { $set: { name: 'jason bourne' }}, options, callback)
|
|
1569
1572
|
*
|
|
1570
|
-
* This helps prevent accidentally overwriting your document with `{ name: 'jason
|
|
1573
|
+
* This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`.
|
|
1571
1574
|
*
|
|
1572
1575
|
* ####Note:
|
|
1573
1576
|
*
|
|
@@ -1586,7 +1589,7 @@ Model.$where = function $where() {
|
|
|
1586
1589
|
*
|
|
1587
1590
|
* Model.findById(id, function (err, doc) {
|
|
1588
1591
|
* if (err) ..
|
|
1589
|
-
* doc.name = 'jason
|
|
1592
|
+
* doc.name = 'jason bourne';
|
|
1590
1593
|
* doc.save(callback);
|
|
1591
1594
|
* });
|
|
1592
1595
|
*
|
|
@@ -1676,12 +1679,12 @@ Model.findOneAndUpdate = function(conditions, update, options, callback) {
|
|
|
1676
1679
|
*
|
|
1677
1680
|
* ####Example:
|
|
1678
1681
|
*
|
|
1679
|
-
* Model.findByIdAndUpdate(id, { name: 'jason
|
|
1682
|
+
* Model.findByIdAndUpdate(id, { name: 'jason bourne' }, options, callback)
|
|
1680
1683
|
*
|
|
1681
1684
|
* // is sent as
|
|
1682
|
-
* Model.findByIdAndUpdate(id, { $set: { name: 'jason
|
|
1685
|
+
* Model.findByIdAndUpdate(id, { $set: { name: 'jason bourne' }}, options, callback)
|
|
1683
1686
|
*
|
|
1684
|
-
* This helps prevent accidentally overwriting your document with `{ name: 'jason
|
|
1687
|
+
* This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`.
|
|
1685
1688
|
*
|
|
1686
1689
|
* ####Note:
|
|
1687
1690
|
*
|
|
@@ -1700,7 +1703,7 @@ Model.findOneAndUpdate = function(conditions, update, options, callback) {
|
|
|
1700
1703
|
*
|
|
1701
1704
|
* Model.findById(id, function (err, doc) {
|
|
1702
1705
|
* if (err) ..
|
|
1703
|
-
* doc.name = 'jason
|
|
1706
|
+
* doc.name = 'jason bourne';
|
|
1704
1707
|
* doc.save(callback);
|
|
1705
1708
|
* });
|
|
1706
1709
|
*
|
|
@@ -1775,7 +1778,7 @@ Model.findByIdAndUpdate = function(id, update, options, callback) {
|
|
|
1775
1778
|
*
|
|
1776
1779
|
* Model.findById(id, function (err, doc) {
|
|
1777
1780
|
* if (err) ..
|
|
1778
|
-
* doc.name = 'jason
|
|
1781
|
+
* doc.name = 'jason bourne';
|
|
1779
1782
|
* doc.save(callback);
|
|
1780
1783
|
* });
|
|
1781
1784
|
*
|
|
@@ -2325,13 +2328,13 @@ Model.hydrate = function(obj) {
|
|
|
2325
2328
|
* ####Example:
|
|
2326
2329
|
*
|
|
2327
2330
|
* var query = { name: 'borne' };
|
|
2328
|
-
* Model.update(query, { name: 'jason
|
|
2331
|
+
* Model.update(query, { name: 'jason bourne' }, options, callback)
|
|
2329
2332
|
*
|
|
2330
2333
|
* // is sent as
|
|
2331
|
-
* Model.update(query, { $set: { name: 'jason
|
|
2334
|
+
* Model.update(query, { $set: { name: 'jason bourne' }}, options, callback)
|
|
2332
2335
|
* // if overwrite option is false. If overwrite is true, sent without the $set wrapper.
|
|
2333
2336
|
*
|
|
2334
|
-
* This helps prevent accidentally overwriting all documents in your collection with `{ name: 'jason
|
|
2337
|
+
* This helps prevent accidentally overwriting all documents in your collection with `{ name: 'jason bourne' }`.
|
|
2335
2338
|
*
|
|
2336
2339
|
* ####Note:
|
|
2337
2340
|
*
|
|
@@ -2356,7 +2359,7 @@ Model.hydrate = function(obj) {
|
|
|
2356
2359
|
*
|
|
2357
2360
|
* Model.findOne({ name: 'borne' }, function (err, doc) {
|
|
2358
2361
|
* if (err) ..
|
|
2359
|
-
* doc.name = 'jason
|
|
2362
|
+
* doc.name = 'jason bourne';
|
|
2360
2363
|
* doc.save(callback);
|
|
2361
2364
|
* })
|
|
2362
2365
|
*
|
|
@@ -3136,6 +3139,14 @@ function populate(model, docs, options, callback) {
|
|
|
3136
3139
|
var key;
|
|
3137
3140
|
var val;
|
|
3138
3141
|
|
|
3142
|
+
// Clone because `assignRawDocsToIdStructure` will mutate the array
|
|
3143
|
+
var allIds = [].concat(mod.allIds.map(function(v) {
|
|
3144
|
+
if (Array.isArray(v)) {
|
|
3145
|
+
return [].concat(v);
|
|
3146
|
+
}
|
|
3147
|
+
return v;
|
|
3148
|
+
}));
|
|
3149
|
+
|
|
3139
3150
|
// optimization:
|
|
3140
3151
|
// record the document positions as returned by
|
|
3141
3152
|
// the query result.
|
|
@@ -3197,6 +3208,7 @@ function populate(model, docs, options, callback) {
|
|
|
3197
3208
|
assignVals({
|
|
3198
3209
|
originalModel: model,
|
|
3199
3210
|
rawIds: mod.allIds,
|
|
3211
|
+
allIds: allIds,
|
|
3200
3212
|
localField: mod.localField,
|
|
3201
3213
|
foreignField: mod.foreignField,
|
|
3202
3214
|
rawDocs: rawDocs,
|
|
@@ -3205,7 +3217,8 @@ function populate(model, docs, options, callback) {
|
|
|
3205
3217
|
path: options.path,
|
|
3206
3218
|
options: assignmentOpts,
|
|
3207
3219
|
justOne: mod.justOne,
|
|
3208
|
-
isVirtual: mod.isVirtual
|
|
3220
|
+
isVirtual: mod.isVirtual,
|
|
3221
|
+
allOptions: mod
|
|
3209
3222
|
});
|
|
3210
3223
|
}
|
|
3211
3224
|
}
|
|
@@ -3259,6 +3272,9 @@ function assignVals(o) {
|
|
|
3259
3272
|
}
|
|
3260
3273
|
cur = cur[parts[j]];
|
|
3261
3274
|
}
|
|
3275
|
+
if (docs[i].$__) {
|
|
3276
|
+
docs[i].populated(o.path, o.allIds[i], o.allOptions);
|
|
3277
|
+
}
|
|
3262
3278
|
utils.setValue(o.path, rawIds[i], docs[i], setValue);
|
|
3263
3279
|
}
|
|
3264
3280
|
}
|
|
@@ -3454,9 +3470,6 @@ function getModelsMapForPopulate(model, docs, options) {
|
|
|
3454
3470
|
var ret = convertTo_id(utils.getValue(localField, doc));
|
|
3455
3471
|
var id = String(utils.getValue(foreignField, doc));
|
|
3456
3472
|
options._docs[id] = Array.isArray(ret) ? ret.slice() : ret;
|
|
3457
|
-
if (doc.$__) {
|
|
3458
|
-
doc.populated(options.path, options._docs[id], options);
|
|
3459
|
-
}
|
|
3460
3473
|
|
|
3461
3474
|
var k = modelNames.length;
|
|
3462
3475
|
while (k--) {
|
package/lib/query.js
CHANGED
|
@@ -1305,11 +1305,16 @@ function completeMany(model, docs, fields, userProvidedFields, pop, callback) {
|
|
|
1305
1305
|
var arr = [];
|
|
1306
1306
|
var count = docs.length;
|
|
1307
1307
|
var len = count;
|
|
1308
|
-
var opts = pop ?
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1308
|
+
var opts = pop ? { populated: pop } : undefined;
|
|
1309
|
+
var error = null;
|
|
1310
|
+
function init(_error) {
|
|
1311
|
+
if (error != null) {
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
if (_error != null) {
|
|
1315
|
+
error = _error;
|
|
1316
|
+
return callback(error);
|
|
1317
|
+
}
|
|
1313
1318
|
--count || callback(null, arr);
|
|
1314
1319
|
}
|
|
1315
1320
|
for (var i = 0; i < len; ++i) {
|
package/lib/queryhelpers.js
CHANGED
|
@@ -101,9 +101,9 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
101
101
|
// if selecting, apply default schematype select:true fields
|
|
102
102
|
// if excluding, apply schematype select:false fields
|
|
103
103
|
|
|
104
|
-
var selected = []
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
var selected = [];
|
|
105
|
+
var excluded = [];
|
|
106
|
+
var stack = [];
|
|
107
107
|
|
|
108
108
|
var analyzePath = function(path, type) {
|
|
109
109
|
if (typeof type.selected !== 'boolean') return;
|
|
@@ -133,8 +133,10 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
133
133
|
prefix || (prefix = '');
|
|
134
134
|
|
|
135
135
|
// avoid recursion
|
|
136
|
-
if (
|
|
137
|
-
|
|
136
|
+
if (stack.indexOf(schema) !== -1) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
stack.push(schema);
|
|
138
140
|
|
|
139
141
|
schema.eachPath(function(path, type) {
|
|
140
142
|
if (prefix) path = prefix + '.' + path;
|
|
@@ -146,6 +148,8 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
146
148
|
analyzeSchema(type.schema, path);
|
|
147
149
|
}
|
|
148
150
|
});
|
|
151
|
+
|
|
152
|
+
stack.pop();
|
|
149
153
|
};
|
|
150
154
|
|
|
151
155
|
analyzeSchema(schema);
|
package/lib/schema/embedded.js
CHANGED
|
@@ -133,7 +133,13 @@ Embedded.prototype.cast = function(val, doc, init, priorVal) {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
if (priorVal && priorVal.$isSingleNested) {
|
|
136
|
-
|
|
136
|
+
var _priorVal = priorVal.toObject({
|
|
137
|
+
minimize: true,
|
|
138
|
+
transform: false,
|
|
139
|
+
virtuals: false,
|
|
140
|
+
getters: false
|
|
141
|
+
});
|
|
142
|
+
subdoc = new this.caster(_priorVal, doc ? doc.$__.selected : void 0, doc);
|
|
137
143
|
} else {
|
|
138
144
|
subdoc = new this.caster(void 0, doc ? doc.$__.selected : void 0, doc);
|
|
139
145
|
}
|
package/lib/schema/objectid.js
CHANGED
|
@@ -20,10 +20,14 @@ var SchemaType = require('../schematype'),
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
function ObjectId(key, options) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
var isKeyHexStr = typeof key === 'string' && /^a-f0-9$/i.test(key);
|
|
24
|
+
var suppressWarning = options && options.suppressWarning;
|
|
25
|
+
if ((isKeyHexStr || typeof key === 'undefined') && !suppressWarning) {
|
|
26
|
+
console.warn('mongoose: To create a new ObjectId please try ' +
|
|
25
27
|
'`Mongoose.Types.ObjectId` instead of using ' +
|
|
26
|
-
'`Mongoose.Schema.ObjectId`.'
|
|
28
|
+
'`Mongoose.Schema.ObjectId`. Set the `suppressWarning` option if ' +
|
|
29
|
+
'you\'re trying to create a hex char path in your schema.');
|
|
30
|
+
console.trace();
|
|
27
31
|
}
|
|
28
32
|
SchemaType.call(this, key, options, 'ObjectID');
|
|
29
33
|
}
|
package/lib/schema.js
CHANGED
|
@@ -277,7 +277,7 @@ Schema.prototype.tree;
|
|
|
277
277
|
*/
|
|
278
278
|
|
|
279
279
|
Schema.prototype.clone = function() {
|
|
280
|
-
var s = new Schema(this.
|
|
280
|
+
var s = new Schema(this.paths, this.options);
|
|
281
281
|
// Clone the call queue
|
|
282
282
|
s.callQueue = this.callQueue.map(function(f) { return f; });
|
|
283
283
|
s.methods = utils.clone(this.methods);
|
|
@@ -531,6 +531,10 @@ Schema.prototype.path = function(path, obj) {
|
|
|
531
531
|
*/
|
|
532
532
|
|
|
533
533
|
Schema.interpretAsType = function(path, obj, options) {
|
|
534
|
+
if (obj instanceof SchemaType) {
|
|
535
|
+
return obj;
|
|
536
|
+
}
|
|
537
|
+
|
|
534
538
|
if (obj.constructor) {
|
|
535
539
|
var constructorName = utils.getFunctionName(obj.constructor);
|
|
536
540
|
if (constructorName !== 'Object') {
|
|
@@ -775,28 +779,35 @@ Schema.prototype.hasMixedParent = function(path) {
|
|
|
775
779
|
*/
|
|
776
780
|
Schema.prototype.setupTimestamp = function(timestamps) {
|
|
777
781
|
if (timestamps) {
|
|
778
|
-
var createdAt = timestamps
|
|
779
|
-
var updatedAt = timestamps
|
|
782
|
+
var createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
783
|
+
var updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
780
784
|
var schemaAdditions = {};
|
|
781
785
|
|
|
782
|
-
var parts
|
|
786
|
+
var parts;
|
|
783
787
|
var i;
|
|
784
|
-
var cur
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
788
|
+
var cur;
|
|
789
|
+
|
|
790
|
+
if (createdAt != null) {
|
|
791
|
+
cur = schemaAdditions;
|
|
792
|
+
parts = createdAt.split('.');
|
|
793
|
+
if (this.pathType(createdAt) === 'adhocOrUndefined') {
|
|
794
|
+
for (i = 0; i < parts.length; ++i) {
|
|
795
|
+
cur[parts[i]] = (i < parts.length - 1 ?
|
|
796
|
+
cur[parts[i]] || {} :
|
|
797
|
+
Date);
|
|
798
|
+
}
|
|
790
799
|
}
|
|
791
800
|
}
|
|
792
801
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
cur[parts[i]]
|
|
799
|
-
|
|
802
|
+
if (updatedAt != null) {
|
|
803
|
+
parts = updatedAt.split('.');
|
|
804
|
+
cur = schemaAdditions;
|
|
805
|
+
if (this.pathType(createdAt) === 'adhocOrUndefined') {
|
|
806
|
+
for (i = 0; i < parts.length; ++i) {
|
|
807
|
+
cur[parts[i]] = (i < parts.length - 1 ?
|
|
808
|
+
cur[parts[i]] || {} :
|
|
809
|
+
Date);
|
|
810
|
+
}
|
|
800
811
|
}
|
|
801
812
|
}
|
|
802
813
|
|
|
@@ -806,12 +817,20 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
|
|
806
817
|
var defaultTimestamp = new Date();
|
|
807
818
|
var auto_id = this._id && this._id.auto;
|
|
808
819
|
|
|
809
|
-
if (!this.get(createdAt) && this.isSelected(createdAt)) {
|
|
820
|
+
if (createdAt != null && !this.get(createdAt) && this.isSelected(createdAt)) {
|
|
810
821
|
this.set(createdAt, auto_id ? this._id.getTimestamp() : defaultTimestamp);
|
|
811
822
|
}
|
|
812
823
|
|
|
813
|
-
if (this.isNew || this.isModified()) {
|
|
814
|
-
|
|
824
|
+
if (updatedAt != null && (this.isNew || this.isModified())) {
|
|
825
|
+
var ts = defaultTimestamp;
|
|
826
|
+
if (this.isNew) {
|
|
827
|
+
if (createdAt != null) {
|
|
828
|
+
ts = this.get(createdAt);
|
|
829
|
+
} else if (auto_id) {
|
|
830
|
+
ts = this._id.getTimestamp();
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
this.set(updatedAt, ts);
|
|
815
834
|
}
|
|
816
835
|
|
|
817
836
|
next();
|
|
@@ -827,10 +846,10 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
|
|
827
846
|
updates.$set = {};
|
|
828
847
|
_updates = updates.$set;
|
|
829
848
|
}
|
|
830
|
-
if (!currentUpdate[updatedAt]) {
|
|
849
|
+
if (updatedAt != null && !currentUpdate[updatedAt]) {
|
|
831
850
|
_updates[updatedAt] = now;
|
|
832
851
|
}
|
|
833
|
-
if (!currentUpdate[createdAt]) {
|
|
852
|
+
if (createdAt != null && !currentUpdate[createdAt]) {
|
|
834
853
|
_updates[createdAt] = now;
|
|
835
854
|
}
|
|
836
855
|
return updates;
|
|
@@ -838,19 +857,22 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
|
|
838
857
|
updates = { $set: {} };
|
|
839
858
|
currentUpdate = currentUpdate || {};
|
|
840
859
|
|
|
841
|
-
if (
|
|
860
|
+
if (updatedAt != null &&
|
|
861
|
+
(!currentUpdate.$currentDate || !currentUpdate.$currentDate[updatedAt])) {
|
|
842
862
|
updates.$set[updatedAt] = now;
|
|
843
863
|
}
|
|
844
864
|
|
|
845
|
-
if (
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
865
|
+
if (createdAt != null) {
|
|
866
|
+
if (currentUpdate[createdAt]) {
|
|
867
|
+
delete currentUpdate[createdAt];
|
|
868
|
+
}
|
|
869
|
+
if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
|
|
870
|
+
delete currentUpdate.$set[createdAt];
|
|
871
|
+
}
|
|
851
872
|
|
|
852
|
-
|
|
853
|
-
|
|
873
|
+
updates.$setOnInsert = {};
|
|
874
|
+
updates.$setOnInsert[createdAt] = now;
|
|
875
|
+
}
|
|
854
876
|
|
|
855
877
|
return updates;
|
|
856
878
|
};
|
|
@@ -885,6 +907,23 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
|
|
885
907
|
}
|
|
886
908
|
};
|
|
887
909
|
|
|
910
|
+
/*!
|
|
911
|
+
* ignore
|
|
912
|
+
*/
|
|
913
|
+
|
|
914
|
+
function handleTimestampOption(arg, prop) {
|
|
915
|
+
if (typeof arg === 'boolean') {
|
|
916
|
+
return prop;
|
|
917
|
+
}
|
|
918
|
+
if (typeof arg[prop] === 'boolean') {
|
|
919
|
+
return arg[prop] ? prop : null;
|
|
920
|
+
}
|
|
921
|
+
if (!(prop in arg)) {
|
|
922
|
+
return prop;
|
|
923
|
+
}
|
|
924
|
+
return arg[prop];
|
|
925
|
+
}
|
|
926
|
+
|
|
888
927
|
/*!
|
|
889
928
|
* ignore
|
|
890
929
|
*/
|
|
@@ -912,16 +951,24 @@ function applyTimestampsToChildren(query) {
|
|
|
912
951
|
$path.$isMongooseDocumentArray &&
|
|
913
952
|
$path.schema.options.timestamps) {
|
|
914
953
|
timestamps = $path.schema.options.timestamps;
|
|
915
|
-
createdAt = timestamps
|
|
916
|
-
updatedAt = timestamps
|
|
954
|
+
createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
955
|
+
updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
917
956
|
if (update.$push[key].$each) {
|
|
918
957
|
update.$push[key].$each.forEach(function(subdoc) {
|
|
919
|
-
|
|
920
|
-
|
|
958
|
+
if (updatedAt != null) {
|
|
959
|
+
subdoc[updatedAt] = now;
|
|
960
|
+
}
|
|
961
|
+
if (createdAt != null) {
|
|
962
|
+
subdoc[createdAt] = now;
|
|
963
|
+
}
|
|
921
964
|
});
|
|
922
965
|
} else {
|
|
923
|
-
|
|
924
|
-
|
|
966
|
+
if (updatedAt != null) {
|
|
967
|
+
update.$push[key][updatedAt] = now;
|
|
968
|
+
}
|
|
969
|
+
if (createdAt != null) {
|
|
970
|
+
update.$push[key][createdAt] = now;
|
|
971
|
+
}
|
|
925
972
|
}
|
|
926
973
|
}
|
|
927
974
|
}
|
|
@@ -936,20 +983,28 @@ function applyTimestampsToChildren(query) {
|
|
|
936
983
|
len = update.$set[key].length;
|
|
937
984
|
timestamps = schema.path(key).schema.options.timestamps;
|
|
938
985
|
if (timestamps) {
|
|
939
|
-
createdAt = timestamps
|
|
940
|
-
updatedAt = timestamps
|
|
986
|
+
createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
987
|
+
updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
941
988
|
for (var i = 0; i < len; ++i) {
|
|
942
|
-
|
|
943
|
-
|
|
989
|
+
if (updatedAt != null) {
|
|
990
|
+
update.$set[key][i][updatedAt] = now;
|
|
991
|
+
}
|
|
992
|
+
if (createdAt != null) {
|
|
993
|
+
update.$set[key][i][createdAt] = now;
|
|
994
|
+
}
|
|
944
995
|
}
|
|
945
996
|
}
|
|
946
997
|
} else if (update.$set[key] && path.$isSingleNested) {
|
|
947
998
|
timestamps = schema.path(key).schema.options.timestamps;
|
|
948
999
|
if (timestamps) {
|
|
949
|
-
createdAt = timestamps
|
|
950
|
-
updatedAt = timestamps
|
|
951
|
-
|
|
952
|
-
|
|
1000
|
+
createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
1001
|
+
updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
1002
|
+
if (updatedAt != null) {
|
|
1003
|
+
update.$set[key][updatedAt] = now;
|
|
1004
|
+
}
|
|
1005
|
+
if (createdAt != null) {
|
|
1006
|
+
update.$set[key][createdAt] = now;
|
|
1007
|
+
}
|
|
953
1008
|
}
|
|
954
1009
|
}
|
|
955
1010
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* ignore
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports = function cleanModifiedSubpaths(doc, path) {
|
|
8
|
+
var _modifiedPaths = Object.keys(doc.$__.activePaths.states.modify);
|
|
9
|
+
var _numModifiedPaths = _modifiedPaths.length;
|
|
10
|
+
var deleted = 0;
|
|
11
|
+
for (var j = 0; j < _numModifiedPaths; ++j) {
|
|
12
|
+
if (_modifiedPaths[j].indexOf(path + '.') === 0) {
|
|
13
|
+
delete doc.$__.activePaths.states.modify[_modifiedPaths[j]];
|
|
14
|
+
++deleted;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return deleted;
|
|
18
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Document;
|
|
4
|
+
var utils = require('../../utils');
|
|
5
|
+
|
|
6
|
+
/*!
|
|
7
|
+
* exports
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
exports.compile = compile;
|
|
11
|
+
exports.defineKey = defineKey;
|
|
12
|
+
|
|
13
|
+
/*!
|
|
14
|
+
* Compiles schemas.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function compile(tree, proto, prefix, options) {
|
|
18
|
+
Document = Document || require('../../document');
|
|
19
|
+
var keys = Object.keys(tree);
|
|
20
|
+
var i = keys.length;
|
|
21
|
+
var len = keys.length;
|
|
22
|
+
var limb;
|
|
23
|
+
var key;
|
|
24
|
+
|
|
25
|
+
if (options.retainKeyOrder) {
|
|
26
|
+
for (i = 0; i < len; ++i) {
|
|
27
|
+
key = keys[i];
|
|
28
|
+
limb = tree[key];
|
|
29
|
+
|
|
30
|
+
defineKey(key,
|
|
31
|
+
((utils.getFunctionName(limb.constructor) === 'Object'
|
|
32
|
+
&& Object.keys(limb).length)
|
|
33
|
+
&& (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type))
|
|
34
|
+
? limb
|
|
35
|
+
: null)
|
|
36
|
+
, proto
|
|
37
|
+
, prefix
|
|
38
|
+
, keys
|
|
39
|
+
, options);
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
while (i--) {
|
|
43
|
+
key = keys[i];
|
|
44
|
+
limb = tree[key];
|
|
45
|
+
|
|
46
|
+
defineKey(key,
|
|
47
|
+
((utils.getFunctionName(limb.constructor) === 'Object'
|
|
48
|
+
&& Object.keys(limb).length)
|
|
49
|
+
&& (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type))
|
|
50
|
+
? limb
|
|
51
|
+
: null)
|
|
52
|
+
, proto
|
|
53
|
+
, prefix
|
|
54
|
+
, keys
|
|
55
|
+
, options);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/*!
|
|
61
|
+
* Defines the accessor named prop on the incoming prototype.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
function defineKey(prop, subprops, prototype, prefix, keys, options) {
|
|
65
|
+
Document = Document || require('../../document');
|
|
66
|
+
var path = (prefix ? prefix + '.' : '') + prop;
|
|
67
|
+
prefix = prefix || '';
|
|
68
|
+
|
|
69
|
+
if (subprops) {
|
|
70
|
+
Object.defineProperty(prototype, prop, {
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true,
|
|
73
|
+
get: function() {
|
|
74
|
+
var _this = this;
|
|
75
|
+
if (!this.$__.getters) {
|
|
76
|
+
this.$__.getters = {};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!this.$__.getters[path]) {
|
|
80
|
+
var nested = Object.create(Object.getPrototypeOf(this), getOwnPropertyDescriptors(this));
|
|
81
|
+
|
|
82
|
+
// save scope for nested getters/setters
|
|
83
|
+
if (!prefix) {
|
|
84
|
+
nested.$__.scope = this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// shadow inherited getters from sub-objects so
|
|
88
|
+
// thing.nested.nested.nested... doesn't occur (gh-366)
|
|
89
|
+
var i = 0,
|
|
90
|
+
len = keys.length;
|
|
91
|
+
|
|
92
|
+
for (; i < len; ++i) {
|
|
93
|
+
// over-write the parents getter without triggering it
|
|
94
|
+
Object.defineProperty(nested, keys[i], {
|
|
95
|
+
enumerable: false, // It doesn't show up.
|
|
96
|
+
writable: true, // We can set it later.
|
|
97
|
+
configurable: true, // We can Object.defineProperty again.
|
|
98
|
+
value: undefined // It shadows its parent.
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Object.defineProperty(nested, 'toObject', {
|
|
103
|
+
enumerable: false,
|
|
104
|
+
configurable: true,
|
|
105
|
+
writable: false,
|
|
106
|
+
value: function() {
|
|
107
|
+
return utils.clone(_this.get(path), { retainKeyOrder: true });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
Object.defineProperty(nested, 'toJSON', {
|
|
112
|
+
enumerable: false,
|
|
113
|
+
configurable: true,
|
|
114
|
+
writable: false,
|
|
115
|
+
value: function() {
|
|
116
|
+
return _this.get(path);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
Object.defineProperty(nested, '$__isNested', {
|
|
121
|
+
enumerable: false,
|
|
122
|
+
configurable: true,
|
|
123
|
+
writable: false,
|
|
124
|
+
value: true
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
compile(subprops, nested, path, options);
|
|
128
|
+
this.$__.getters[path] = nested;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return this.$__.getters[path];
|
|
132
|
+
},
|
|
133
|
+
set: function(v) {
|
|
134
|
+
if (v instanceof Document) {
|
|
135
|
+
v = v.toObject({ transform: false });
|
|
136
|
+
}
|
|
137
|
+
return (this.$__.scope || this).set(path, v);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
} else {
|
|
141
|
+
Object.defineProperty(prototype, prop, {
|
|
142
|
+
enumerable: true,
|
|
143
|
+
configurable: true,
|
|
144
|
+
get: function() {
|
|
145
|
+
return this.get.call(this.$__.scope || this, path);
|
|
146
|
+
},
|
|
147
|
+
set: function(v) {
|
|
148
|
+
return this.set.call(this.$__.scope || this, path, v);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// gets descriptors for all properties of `object`
|
|
155
|
+
// makes all properties non-enumerable to match previous behavior to #2211
|
|
156
|
+
function getOwnPropertyDescriptors(object) {
|
|
157
|
+
var result = {};
|
|
158
|
+
|
|
159
|
+
Object.getOwnPropertyNames(object).forEach(function(key) {
|
|
160
|
+
result[key] = Object.getOwnPropertyDescriptor(object, key);
|
|
161
|
+
result[key].enumerable = ['isNew', '$__', 'errors', '_doc'].indexOf(key) === -1;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
@@ -35,6 +35,14 @@ module.exports = function discriminator(model, name, schema) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function merge(schema, baseSchema) {
|
|
38
|
+
if (baseSchema.paths._id &&
|
|
39
|
+
baseSchema.paths._id.options &&
|
|
40
|
+
!baseSchema.paths._id.options.auto) {
|
|
41
|
+
var originalSchema = schema;
|
|
42
|
+
utils.merge(schema, originalSchema, { retainKeyOrder: true });
|
|
43
|
+
delete schema.paths._id;
|
|
44
|
+
delete schema.tree._id;
|
|
45
|
+
}
|
|
38
46
|
utils.merge(schema, baseSchema, { retainKeyOrder: true });
|
|
39
47
|
|
|
40
48
|
var obj = {};
|
|
@@ -308,7 +308,7 @@ function castUpdateVal(schema, val, op, $conditional, context) {
|
|
|
308
308
|
return schema.castForQueryWrapper({
|
|
309
309
|
val: val,
|
|
310
310
|
context: context,
|
|
311
|
-
$skipQueryCastForUpdate: val != null
|
|
311
|
+
$skipQueryCastForUpdate: val != null && schema.$isMongooseArray
|
|
312
312
|
});
|
|
313
313
|
}
|
|
314
314
|
|
package/lib/types/array.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
var EmbeddedDocument = require('./embedded');
|
|
6
6
|
var Document = require('../document');
|
|
7
7
|
var ObjectId = require('./objectid');
|
|
8
|
+
var cleanModifiedSubpaths = require('../services/document/cleanModifiedSubpaths');
|
|
8
9
|
var utils = require('../utils');
|
|
10
|
+
|
|
9
11
|
var isMongooseObject = utils.isMongooseObject;
|
|
10
12
|
|
|
11
13
|
/**
|
|
@@ -103,7 +105,7 @@ MongooseArray.mixin = {
|
|
|
103
105
|
|
|
104
106
|
if (populated && value !== null && value !== undefined) {
|
|
105
107
|
// cast to the populated Models schema
|
|
106
|
-
Model = populated.options.model;
|
|
108
|
+
Model = populated.options.model || populated.options.Model;
|
|
107
109
|
|
|
108
110
|
// only objects are permitted so we can safely assume that
|
|
109
111
|
// non-objects are to be interpreted as _id
|
|
@@ -154,7 +156,7 @@ MongooseArray.mixin = {
|
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
|
|
157
|
-
parent.markModified(dirtyPath, elem);
|
|
159
|
+
parent.markModified(dirtyPath, arguments.length > 0 ? elem : parent);
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
return this;
|
|
@@ -306,9 +308,28 @@ MongooseArray.mixin = {
|
|
|
306
308
|
*/
|
|
307
309
|
|
|
308
310
|
push: function() {
|
|
311
|
+
var ref = this._schema.caster.options && this._schema.caster.options.ref;
|
|
312
|
+
if (this.length === 0 &&
|
|
313
|
+
arguments.length) {
|
|
314
|
+
var allSubdocs = true;
|
|
315
|
+
for (var i = 0; i < arguments.length; ++i) {
|
|
316
|
+
var arg = arguments[i];
|
|
317
|
+
var model = arg.constructor;
|
|
318
|
+
allSubdocs = arg instanceof Document &&
|
|
319
|
+
ref &&
|
|
320
|
+
(model.modelName === ref || model.baseModelName === ref);
|
|
321
|
+
if (!allSubdocs) {
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (allSubdocs) {
|
|
327
|
+
this._parent.populated(this._path, [], { model: arguments[0].constructor });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
309
330
|
var values = [].map.call(arguments, this._mapCast, this);
|
|
310
331
|
values = this._schema.applySetters(values, this._parent, undefined,
|
|
311
|
-
undefined, {skipDocumentArrayCast: true});
|
|
332
|
+
undefined, { skipDocumentArrayCast: true });
|
|
312
333
|
var ret = [].push.apply(this, values);
|
|
313
334
|
|
|
314
335
|
// $pushAll might be fibbed (could be $push). But it makes it easier to
|
|
@@ -539,6 +560,15 @@ MongooseArray.mixin = {
|
|
|
539
560
|
}
|
|
540
561
|
|
|
541
562
|
this._markModified();
|
|
563
|
+
|
|
564
|
+
// Might have modified child paths and then pulled, like
|
|
565
|
+
// `doc.children[1].name = 'test';` followed by
|
|
566
|
+
// `doc.children.remove(doc.children[0]);`. In this case we fall back
|
|
567
|
+
// to a `$set` on the whole array. See #3511
|
|
568
|
+
if (cleanModifiedSubpaths(this._parent, this._path) > 0) {
|
|
569
|
+
this._registerAtomic('$set', this);
|
|
570
|
+
}
|
|
571
|
+
|
|
542
572
|
return this;
|
|
543
573
|
},
|
|
544
574
|
|
package/lib/types/buffer.js
CHANGED
|
@@ -203,6 +203,19 @@ MongooseBuffer.mixin.toObject = function(options) {
|
|
|
203
203
|
return new Binary(this, subtype);
|
|
204
204
|
};
|
|
205
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Converts this buffer for storage in MongoDB, including subtype
|
|
208
|
+
*
|
|
209
|
+
* @return {Binary}
|
|
210
|
+
* @api public
|
|
211
|
+
* @method toBSON
|
|
212
|
+
* @receiver MongooseBuffer
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
MongooseBuffer.mixin.toBSON = function() {
|
|
216
|
+
return new Binary(this, this._subtype || 0);
|
|
217
|
+
};
|
|
218
|
+
|
|
206
219
|
/**
|
|
207
220
|
* Determines if this buffer is equals to `other` buffer
|
|
208
221
|
*
|
package/lib/types/subdocument.js
CHANGED
|
@@ -60,7 +60,7 @@ Subdocument.prototype.markModified = function(path) {
|
|
|
60
60
|
if (this.$parent.isDirectModified(this.$basePath)) {
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
this.$parent.markModified([this.$basePath, path].join('.'));
|
|
63
|
+
this.$parent.markModified([this.$basePath, path].join('.'), this);
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "4.11.
|
|
4
|
+
"version": "4.11.12",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"tbd": "0.6.4",
|
|
56
56
|
"uglify-js": "2.7.0",
|
|
57
57
|
"uuid": "2.0.3",
|
|
58
|
+
"uuid-parse": "1.0.0",
|
|
58
59
|
"validator": "5.4.0"
|
|
59
60
|
},
|
|
60
61
|
"browserDependencies": {
|