mongodb-livedata-server 0.1.3 → 0.1.5

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.
Files changed (92) hide show
  1. package/README.md +2 -2
  2. package/dist/livedata_server.d.ts +4 -4
  3. package/dist/livedata_server.js +11 -11
  4. package/dist/meteor/binary-heap/max_heap.d.ts +31 -31
  5. package/dist/meteor/binary-heap/max_heap.js +186 -186
  6. package/dist/meteor/binary-heap/min_heap.d.ts +6 -6
  7. package/dist/meteor/binary-heap/min_heap.js +17 -17
  8. package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -11
  9. package/dist/meteor/binary-heap/min_max_heap.js +48 -48
  10. package/dist/meteor/callback-hook/hook.d.ts +11 -11
  11. package/dist/meteor/callback-hook/hook.js +78 -78
  12. package/dist/meteor/ddp/crossbar.d.ts +15 -15
  13. package/dist/meteor/ddp/crossbar.js +136 -136
  14. package/dist/meteor/ddp/heartbeat.d.ts +19 -19
  15. package/dist/meteor/ddp/heartbeat.js +77 -77
  16. package/dist/meteor/ddp/livedata_server.d.ts +141 -142
  17. package/dist/meteor/ddp/livedata_server.js +403 -403
  18. package/dist/meteor/ddp/method-invocation.d.ts +35 -35
  19. package/dist/meteor/ddp/method-invocation.js +72 -72
  20. package/dist/meteor/ddp/random-stream.d.ts +8 -8
  21. package/dist/meteor/ddp/random-stream.js +100 -100
  22. package/dist/meteor/ddp/session-collection-view.d.ts +20 -20
  23. package/dist/meteor/ddp/session-collection-view.js +106 -106
  24. package/dist/meteor/ddp/session-document-view.d.ts +8 -8
  25. package/dist/meteor/ddp/session-document-view.js +82 -82
  26. package/dist/meteor/ddp/session.d.ts +75 -75
  27. package/dist/meteor/ddp/session.js +590 -590
  28. package/dist/meteor/ddp/stream_server.d.ts +20 -21
  29. package/dist/meteor/ddp/stream_server.js +181 -181
  30. package/dist/meteor/ddp/subscription.d.ts +94 -94
  31. package/dist/meteor/ddp/subscription.js +370 -370
  32. package/dist/meteor/ddp/utils.d.ts +8 -8
  33. package/dist/meteor/ddp/utils.js +104 -104
  34. package/dist/meteor/ddp/writefence.d.ts +20 -20
  35. package/dist/meteor/ddp/writefence.js +111 -111
  36. package/dist/meteor/diff-sequence/diff.d.ts +17 -17
  37. package/dist/meteor/diff-sequence/diff.js +257 -257
  38. package/dist/meteor/ejson/ejson.d.ts +82 -82
  39. package/dist/meteor/ejson/ejson.js +568 -569
  40. package/dist/meteor/ejson/stringify.d.ts +2 -2
  41. package/dist/meteor/ejson/stringify.js +119 -119
  42. package/dist/meteor/ejson/utils.d.ts +12 -12
  43. package/dist/meteor/ejson/utils.js +42 -42
  44. package/dist/meteor/mongo/caching_change_observer.d.ts +16 -16
  45. package/dist/meteor/mongo/caching_change_observer.js +63 -63
  46. package/dist/meteor/mongo/doc_fetcher.d.ts +7 -7
  47. package/dist/meteor/mongo/doc_fetcher.js +53 -53
  48. package/dist/meteor/mongo/geojson_utils.d.ts +3 -3
  49. package/dist/meteor/mongo/geojson_utils.js +40 -41
  50. package/dist/meteor/mongo/live_connection.d.ts +28 -28
  51. package/dist/meteor/mongo/live_connection.js +264 -264
  52. package/dist/meteor/mongo/live_cursor.d.ts +25 -25
  53. package/dist/meteor/mongo/live_cursor.js +60 -60
  54. package/dist/meteor/mongo/minimongo_common.d.ts +84 -84
  55. package/dist/meteor/mongo/minimongo_common.js +1998 -1998
  56. package/dist/meteor/mongo/minimongo_matcher.d.ts +23 -23
  57. package/dist/meteor/mongo/minimongo_matcher.js +283 -283
  58. package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -16
  59. package/dist/meteor/mongo/minimongo_sorter.js +268 -268
  60. package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -9
  61. package/dist/meteor/mongo/observe_driver_utils.js +72 -73
  62. package/dist/meteor/mongo/observe_multiplexer.d.ts +46 -46
  63. package/dist/meteor/mongo/observe_multiplexer.js +203 -203
  64. package/dist/meteor/mongo/oplog-observe-driver.d.ts +68 -68
  65. package/dist/meteor/mongo/oplog-observe-driver.js +918 -918
  66. package/dist/meteor/mongo/oplog_tailing.d.ts +35 -35
  67. package/dist/meteor/mongo/oplog_tailing.js +352 -352
  68. package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -1
  69. package/dist/meteor/mongo/oplog_v2_converter.js +125 -126
  70. package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -30
  71. package/dist/meteor/mongo/polling_observe_driver.js +216 -221
  72. package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -17
  73. package/dist/meteor/mongo/synchronous-cursor.js +261 -261
  74. package/dist/meteor/mongo/synchronous-queue.d.ts +13 -13
  75. package/dist/meteor/mongo/synchronous-queue.js +110 -110
  76. package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -31
  77. package/dist/meteor/ordered-dict/ordered_dict.js +198 -198
  78. package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -42
  79. package/dist/meteor/random/AbstractRandomGenerator.js +92 -92
  80. package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -13
  81. package/dist/meteor/random/AleaRandomGenerator.js +90 -90
  82. package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -16
  83. package/dist/meteor/random/NodeRandomGenerator.js +42 -42
  84. package/dist/meteor/random/createAleaGenerator.d.ts +2 -2
  85. package/dist/meteor/random/createAleaGenerator.js +32 -32
  86. package/dist/meteor/random/createRandom.d.ts +1 -1
  87. package/dist/meteor/random/createRandom.js +22 -22
  88. package/dist/meteor/random/main.d.ts +1 -1
  89. package/dist/meteor/random/main.js +12 -12
  90. package/dist/meteor/types.d.ts +1 -1
  91. package/dist/meteor/types.js +2 -2
  92. package/package.json +5 -5
@@ -1,23 +1,23 @@
1
- import { Filter } from 'mongodb';
2
- export declare class MinimongoMatcher {
3
- private _paths;
4
- private _hasGeoQuery;
5
- private _hasWhere;
6
- private _isSimple;
7
- private _matchingDocument;
8
- private _selector;
9
- private _docMatcher;
10
- private _isUpdate;
11
- constructor(selector: Filter<any>, isUpdate?: boolean);
12
- documentMatches(doc: any): any;
13
- hasGeoQuery(): boolean;
14
- hasWhere(): boolean;
15
- isSimple(): boolean;
16
- _compileSelector(selector: Filter<any>): any;
17
- affectedByModifier(modifier: any): boolean;
18
- canBecomeTrueByModifier(modifier: any): any;
19
- matchingDocument(): any;
20
- combineIntoProjection(projection: any): {};
21
- _getPaths(): string[];
22
- _recordPathUsed(path: any): void;
23
- }
1
+ import { Filter } from 'mongodb';
2
+ export declare class MinimongoMatcher {
3
+ private _paths;
4
+ private _hasGeoQuery;
5
+ private _hasWhere;
6
+ private _isSimple;
7
+ private _matchingDocument;
8
+ private _selector;
9
+ private _docMatcher;
10
+ private _isUpdate;
11
+ constructor(selector: Filter<any>, isUpdate?: boolean);
12
+ documentMatches(doc: any): any;
13
+ hasGeoQuery(): boolean;
14
+ hasWhere(): boolean;
15
+ isSimple(): boolean;
16
+ _compileSelector(selector: Filter<any>): any;
17
+ affectedByModifier(modifier: any): boolean;
18
+ canBecomeTrueByModifier(modifier: any): any;
19
+ matchingDocument(): any;
20
+ combineIntoProjection(projection: any): {};
21
+ _getPaths(): string[];
22
+ _recordPathUsed(path: any): void;
23
+ }
@@ -1,283 +1,283 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MinimongoMatcher = void 0;
4
- const minimongo_common_1 = require("./minimongo_common");
5
- const ejson_1 = require("../ejson/ejson");
6
- // The minimongo selector compiler!
7
- // Terminology:
8
- // - a 'selector' is the EJSON object representing a selector
9
- // - a 'matcher' is its compiled form (whether a full Minimongo.Matcher
10
- // object or one of the component lambdas that matches parts of it)
11
- // - a 'result object' is an object with a 'result' field and maybe
12
- // distance and arrayIndices.
13
- // - a 'branched value' is an object with a 'value' field and maybe
14
- // 'dontIterate' and 'arrayIndices'.
15
- // - a 'document' is a top-level object that can be stored in a collection.
16
- // - a 'lookup function' is a function that takes in a document and returns
17
- // an array of 'branched values'.
18
- // - a 'branched matcher' maps from an array of branched values to a result
19
- // object.
20
- // - an 'element matcher' maps from a single value to a bool.
21
- // Main entry point.
22
- // var matcher = new Minimongo.Matcher({a: {$gt: 5}});
23
- // if (matcher.documentMatches({a: 7})) ...
24
- class MinimongoMatcher {
25
- constructor(selector, isUpdate) {
26
- // A set (object mapping string -> *) of all of the document paths looked
27
- // at by the selector. Also includes the empty string if it may look at any
28
- // path (eg, $where).
29
- this._paths = {};
30
- // Set to true if compilation finds a $near.
31
- this._hasGeoQuery = false;
32
- // Set to true if compilation finds a $where.
33
- this._hasWhere = false;
34
- // Set to false if compilation finds anything other than a simple equality
35
- // or one or more of '$gt', '$gte', '$lt', '$lte', '$ne', '$in', '$nin' used
36
- // with scalars as operands.
37
- this._isSimple = true;
38
- // Set to a dummy document which always matches this Matcher. Or set to null
39
- // if such document is too hard to find.
40
- this._matchingDocument = undefined;
41
- // A clone of the original selector. It may just be a function if the user
42
- // passed in a function; otherwise is definitely an object (eg, IDs are
43
- // translated into {_id: ID} first. Used by canBecomeTrueByModifier and
44
- // Sorter._useWithMatcher.
45
- this._selector = null;
46
- this._docMatcher = this._compileSelector(selector);
47
- // Set to true if selection is done for an update operation
48
- // Default is false
49
- // Used for $near array update (issue #3599)
50
- this._isUpdate = isUpdate;
51
- }
52
- documentMatches(doc) {
53
- if (doc !== Object(doc)) {
54
- throw Error('documentMatches needs a document');
55
- }
56
- return this._docMatcher(doc);
57
- }
58
- hasGeoQuery() {
59
- return this._hasGeoQuery;
60
- }
61
- hasWhere() {
62
- return this._hasWhere;
63
- }
64
- isSimple() {
65
- return this._isSimple;
66
- }
67
- // Given a selector, return a function that takes one argument, a
68
- // document. It returns a result object.
69
- _compileSelector(selector) {
70
- // you can pass a literal function instead of a selector
71
- if (selector instanceof Function) {
72
- this._isSimple = false;
73
- this._selector = selector;
74
- this._recordPathUsed('');
75
- return doc => ({ result: !!selector.call(doc) });
76
- }
77
- // protect against dangerous selectors. falsey and {_id: falsey} are both
78
- // likely programmer error, and not what you want, particularly for
79
- // destructive operations.
80
- if (!selector || minimongo_common_1.hasOwn.call(selector, '_id') && !selector._id) {
81
- this._isSimple = false;
82
- return minimongo_common_1.nothingMatcher;
83
- }
84
- // Top level can't be an array or true or binary.
85
- if (Array.isArray(selector) ||
86
- (0, ejson_1.isBinary)(selector) ||
87
- typeof selector === 'boolean') {
88
- throw new Error(`Invalid selector: ${selector}`);
89
- }
90
- this._selector = (0, ejson_1.clone)(selector);
91
- return (0, minimongo_common_1.compileDocumentSelector)(selector, this, { isRoot: true });
92
- }
93
- affectedByModifier(modifier) {
94
- // safe check for $set/$unset being objects
95
- modifier = Object.assign({ $set: {}, $unset: {} }, modifier);
96
- const meaningfulPaths = this._getPaths();
97
- const modifiedPaths = [].concat(Object.keys(modifier.$set), Object.keys(modifier.$unset));
98
- return modifiedPaths.some(path => {
99
- const mod = path.split('.');
100
- return meaningfulPaths.some(meaningfulPath => {
101
- const sel = meaningfulPath.split('.');
102
- let i = 0, j = 0;
103
- while (i < sel.length && j < mod.length) {
104
- if ((0, minimongo_common_1.isNumericKey)(sel[i]) && (0, minimongo_common_1.isNumericKey)(mod[j])) {
105
- // foo.4.bar selector affected by foo.4 modifier
106
- // foo.3.bar selector unaffected by foo.4 modifier
107
- if (sel[i] === mod[j]) {
108
- i++;
109
- j++;
110
- }
111
- else {
112
- return false;
113
- }
114
- }
115
- else if ((0, minimongo_common_1.isNumericKey)(sel[i])) {
116
- // foo.4.bar selector unaffected by foo.bar modifier
117
- return false;
118
- }
119
- else if ((0, minimongo_common_1.isNumericKey)(mod[j])) {
120
- j++;
121
- }
122
- else if (sel[i] === mod[j]) {
123
- i++;
124
- j++;
125
- }
126
- else {
127
- return false;
128
- }
129
- }
130
- // One is a prefix of another, taking numeric fields into account
131
- return true;
132
- });
133
- });
134
- }
135
- canBecomeTrueByModifier(modifier) {
136
- if (!this.affectedByModifier(modifier)) {
137
- return false;
138
- }
139
- if (!this.isSimple()) {
140
- return true;
141
- }
142
- modifier = Object.assign({ $set: {}, $unset: {} }, modifier);
143
- const modifierPaths = [].concat(Object.keys(modifier.$set), Object.keys(modifier.$unset));
144
- if (this._getPaths().some(pathHasNumericKeys) ||
145
- modifierPaths.some(pathHasNumericKeys)) {
146
- return true;
147
- }
148
- // check if there is a $set or $unset that indicates something is an
149
- // object rather than a scalar in the actual object where we saw $-operator
150
- // NOTE: it is correct since we allow only scalars in $-operators
151
- // Example: for selector {'a.b': {$gt: 5}} the modifier {'a.b.c':7} would
152
- // definitely set the result to false as 'a.b' appears to be an object.
153
- const expectedScalarIsObject = Object.keys(this._selector).some(path => {
154
- if (!(0, minimongo_common_1.isOperatorObject)(this._selector[path])) {
155
- return false;
156
- }
157
- return modifierPaths.some(modifierPath => modifierPath.startsWith(`${path}.`));
158
- });
159
- if (expectedScalarIsObject) {
160
- return false;
161
- }
162
- // See if we can apply the modifier on the ideally matching object. If it
163
- // still matches the selector, then the modifier could have turned the real
164
- // object in the database into something matching.
165
- const matchingDocument = (0, ejson_1.clone)(this.matchingDocument());
166
- // The selector is too complex, anything can happen.
167
- if (matchingDocument === null) {
168
- return true;
169
- }
170
- try {
171
- (0, minimongo_common_1._modify)(matchingDocument, modifier);
172
- }
173
- catch (error) {
174
- // Couldn't set a property on a field which is a scalar or null in the
175
- // selector.
176
- // Example:
177
- // real document: { 'a.b': 3 }
178
- // selector: { 'a': 12 }
179
- // converted selector (ideal document): { 'a': 12 }
180
- // modifier: { $set: { 'a.b': 4 } }
181
- // We don't know what real document was like but from the error raised by
182
- // $set on a scalar field we can reason that the structure of real document
183
- // is completely different.
184
- if (error.name === 'MinimongoError' && error.setPropertyError) {
185
- return false;
186
- }
187
- throw error;
188
- }
189
- return this.documentMatches(matchingDocument).result;
190
- }
191
- matchingDocument() {
192
- // check if it was computed before
193
- if (this._matchingDocument !== undefined) {
194
- return this._matchingDocument;
195
- }
196
- // If the analysis of this selector is too hard for our implementation
197
- // fallback to "YES"
198
- let fallback = false;
199
- this._matchingDocument = (0, minimongo_common_1.pathsToTree)(this._getPaths(), path => {
200
- const valueSelector = this._selector[path];
201
- if ((0, minimongo_common_1.isOperatorObject)(valueSelector)) {
202
- // if there is a strict equality, there is a good
203
- // chance we can use one of those as "matching"
204
- // dummy value
205
- if (valueSelector.$eq) {
206
- return valueSelector.$eq;
207
- }
208
- if (valueSelector.$in) {
209
- const matcher = new MinimongoMatcher({ placeholder: valueSelector });
210
- // Return anything from $in that matches the whole selector for this
211
- // path. If nothing matches, returns `undefined` as nothing can make
212
- // this selector into `true`.
213
- return valueSelector.$in.find(placeholder => matcher.documentMatches({ placeholder }).result);
214
- }
215
- if (onlyContainsKeys(valueSelector, ['$gt', '$gte', '$lt', '$lte'])) {
216
- let lowerBound = -Infinity;
217
- let upperBound = Infinity;
218
- ['$lte', '$lt'].forEach(op => {
219
- if (minimongo_common_1.hasOwn.call(valueSelector, op) &&
220
- valueSelector[op] < upperBound) {
221
- upperBound = valueSelector[op];
222
- }
223
- });
224
- ['$gte', '$gt'].forEach(op => {
225
- if (minimongo_common_1.hasOwn.call(valueSelector, op) &&
226
- valueSelector[op] > lowerBound) {
227
- lowerBound = valueSelector[op];
228
- }
229
- });
230
- const middle = (lowerBound + upperBound) / 2;
231
- const matcher = new MinimongoMatcher({ placeholder: valueSelector });
232
- if (!matcher.documentMatches({ placeholder: middle }).result &&
233
- (middle === lowerBound || middle === upperBound)) {
234
- fallback = true;
235
- }
236
- return middle;
237
- }
238
- if (onlyContainsKeys(valueSelector, ['$nin', '$ne'])) {
239
- // Since this._isSimple makes sure $nin and $ne are not combined with
240
- // objects or arrays, we can confidently return an empty object as it
241
- // never matches any scalar.
242
- return {};
243
- }
244
- fallback = true;
245
- }
246
- return this._selector[path];
247
- }, x => x);
248
- if (fallback) {
249
- this._matchingDocument = null;
250
- }
251
- return this._matchingDocument;
252
- }
253
- ;
254
- // Knows how to combine a mongo selector and a fields projection to a new fields
255
- // projection taking into account active fields from the passed selector.
256
- // @returns Object - projection object (same as fields option of mongo cursor)
257
- combineIntoProjection(projection) {
258
- const selectorPaths = (0, minimongo_common_1._pathsElidingNumericKeys)(this._getPaths());
259
- // Special case for $where operator in the selector - projection should depend
260
- // on all fields of the document. getSelectorPaths returns a list of paths
261
- // selector depends on. If one of the paths is '' (empty string) representing
262
- // the root or the whole document, complete projection should be returned.
263
- if (selectorPaths.includes('')) {
264
- return {};
265
- }
266
- return (0, minimongo_common_1.combineImportantPathsIntoProjection)(selectorPaths, projection);
267
- }
268
- // Returns a list of key paths the given selector is looking for. It includes
269
- // the empty string if there is a $where.
270
- _getPaths() {
271
- return Object.keys(this._paths);
272
- }
273
- _recordPathUsed(path) {
274
- this._paths[path] = true;
275
- }
276
- }
277
- exports.MinimongoMatcher = MinimongoMatcher;
278
- function pathHasNumericKeys(path) {
279
- return path.split('.').some(minimongo_common_1.isNumericKey);
280
- }
281
- function onlyContainsKeys(obj, keys) {
282
- return Object.keys(obj).every(k => keys.includes(k));
283
- }
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MinimongoMatcher = void 0;
4
+ const minimongo_common_1 = require("./minimongo_common");
5
+ const ejson_1 = require("../ejson/ejson");
6
+ // The minimongo selector compiler!
7
+ // Terminology:
8
+ // - a 'selector' is the EJSON object representing a selector
9
+ // - a 'matcher' is its compiled form (whether a full Minimongo.Matcher
10
+ // object or one of the component lambdas that matches parts of it)
11
+ // - a 'result object' is an object with a 'result' field and maybe
12
+ // distance and arrayIndices.
13
+ // - a 'branched value' is an object with a 'value' field and maybe
14
+ // 'dontIterate' and 'arrayIndices'.
15
+ // - a 'document' is a top-level object that can be stored in a collection.
16
+ // - a 'lookup function' is a function that takes in a document and returns
17
+ // an array of 'branched values'.
18
+ // - a 'branched matcher' maps from an array of branched values to a result
19
+ // object.
20
+ // - an 'element matcher' maps from a single value to a bool.
21
+ // Main entry point.
22
+ // var matcher = new Minimongo.Matcher({a: {$gt: 5}});
23
+ // if (matcher.documentMatches({a: 7})) ...
24
+ class MinimongoMatcher {
25
+ constructor(selector, isUpdate) {
26
+ // A set (object mapping string -> *) of all of the document paths looked
27
+ // at by the selector. Also includes the empty string if it may look at any
28
+ // path (eg, $where).
29
+ this._paths = {};
30
+ // Set to true if compilation finds a $near.
31
+ this._hasGeoQuery = false;
32
+ // Set to true if compilation finds a $where.
33
+ this._hasWhere = false;
34
+ // Set to false if compilation finds anything other than a simple equality
35
+ // or one or more of '$gt', '$gte', '$lt', '$lte', '$ne', '$in', '$nin' used
36
+ // with scalars as operands.
37
+ this._isSimple = true;
38
+ // Set to a dummy document which always matches this Matcher. Or set to null
39
+ // if such document is too hard to find.
40
+ this._matchingDocument = undefined;
41
+ // A clone of the original selector. It may just be a function if the user
42
+ // passed in a function; otherwise is definitely an object (eg, IDs are
43
+ // translated into {_id: ID} first. Used by canBecomeTrueByModifier and
44
+ // Sorter._useWithMatcher.
45
+ this._selector = null;
46
+ this._docMatcher = this._compileSelector(selector);
47
+ // Set to true if selection is done for an update operation
48
+ // Default is false
49
+ // Used for $near array update (issue #3599)
50
+ this._isUpdate = isUpdate;
51
+ }
52
+ documentMatches(doc) {
53
+ if (doc !== Object(doc)) {
54
+ throw Error('documentMatches needs a document');
55
+ }
56
+ return this._docMatcher(doc);
57
+ }
58
+ hasGeoQuery() {
59
+ return this._hasGeoQuery;
60
+ }
61
+ hasWhere() {
62
+ return this._hasWhere;
63
+ }
64
+ isSimple() {
65
+ return this._isSimple;
66
+ }
67
+ // Given a selector, return a function that takes one argument, a
68
+ // document. It returns a result object.
69
+ _compileSelector(selector) {
70
+ // you can pass a literal function instead of a selector
71
+ if (selector instanceof Function) {
72
+ this._isSimple = false;
73
+ this._selector = selector;
74
+ this._recordPathUsed('');
75
+ return doc => ({ result: !!selector.call(doc) });
76
+ }
77
+ // protect against dangerous selectors. falsey and {_id: falsey} are both
78
+ // likely programmer error, and not what you want, particularly for
79
+ // destructive operations.
80
+ if (!selector || minimongo_common_1.hasOwn.call(selector, '_id') && !selector._id) {
81
+ this._isSimple = false;
82
+ return minimongo_common_1.nothingMatcher;
83
+ }
84
+ // Top level can't be an array or true or binary.
85
+ if (Array.isArray(selector) ||
86
+ (0, ejson_1.isBinary)(selector) ||
87
+ typeof selector === 'boolean') {
88
+ throw new Error(`Invalid selector: ${selector}`);
89
+ }
90
+ this._selector = (0, ejson_1.clone)(selector);
91
+ return (0, minimongo_common_1.compileDocumentSelector)(selector, this, { isRoot: true });
92
+ }
93
+ affectedByModifier(modifier) {
94
+ // safe check for $set/$unset being objects
95
+ modifier = Object.assign({ $set: {}, $unset: {} }, modifier);
96
+ const meaningfulPaths = this._getPaths();
97
+ const modifiedPaths = [].concat(Object.keys(modifier.$set), Object.keys(modifier.$unset));
98
+ return modifiedPaths.some(path => {
99
+ const mod = path.split('.');
100
+ return meaningfulPaths.some(meaningfulPath => {
101
+ const sel = meaningfulPath.split('.');
102
+ let i = 0, j = 0;
103
+ while (i < sel.length && j < mod.length) {
104
+ if ((0, minimongo_common_1.isNumericKey)(sel[i]) && (0, minimongo_common_1.isNumericKey)(mod[j])) {
105
+ // foo.4.bar selector affected by foo.4 modifier
106
+ // foo.3.bar selector unaffected by foo.4 modifier
107
+ if (sel[i] === mod[j]) {
108
+ i++;
109
+ j++;
110
+ }
111
+ else {
112
+ return false;
113
+ }
114
+ }
115
+ else if ((0, minimongo_common_1.isNumericKey)(sel[i])) {
116
+ // foo.4.bar selector unaffected by foo.bar modifier
117
+ return false;
118
+ }
119
+ else if ((0, minimongo_common_1.isNumericKey)(mod[j])) {
120
+ j++;
121
+ }
122
+ else if (sel[i] === mod[j]) {
123
+ i++;
124
+ j++;
125
+ }
126
+ else {
127
+ return false;
128
+ }
129
+ }
130
+ // One is a prefix of another, taking numeric fields into account
131
+ return true;
132
+ });
133
+ });
134
+ }
135
+ canBecomeTrueByModifier(modifier) {
136
+ if (!this.affectedByModifier(modifier)) {
137
+ return false;
138
+ }
139
+ if (!this.isSimple()) {
140
+ return true;
141
+ }
142
+ modifier = Object.assign({ $set: {}, $unset: {} }, modifier);
143
+ const modifierPaths = [].concat(Object.keys(modifier.$set), Object.keys(modifier.$unset));
144
+ if (this._getPaths().some(pathHasNumericKeys) ||
145
+ modifierPaths.some(pathHasNumericKeys)) {
146
+ return true;
147
+ }
148
+ // check if there is a $set or $unset that indicates something is an
149
+ // object rather than a scalar in the actual object where we saw $-operator
150
+ // NOTE: it is correct since we allow only scalars in $-operators
151
+ // Example: for selector {'a.b': {$gt: 5}} the modifier {'a.b.c':7} would
152
+ // definitely set the result to false as 'a.b' appears to be an object.
153
+ const expectedScalarIsObject = Object.keys(this._selector).some(path => {
154
+ if (!(0, minimongo_common_1.isOperatorObject)(this._selector[path])) {
155
+ return false;
156
+ }
157
+ return modifierPaths.some(modifierPath => modifierPath.startsWith(`${path}.`));
158
+ });
159
+ if (expectedScalarIsObject) {
160
+ return false;
161
+ }
162
+ // See if we can apply the modifier on the ideally matching object. If it
163
+ // still matches the selector, then the modifier could have turned the real
164
+ // object in the database into something matching.
165
+ const matchingDocument = (0, ejson_1.clone)(this.matchingDocument());
166
+ // The selector is too complex, anything can happen.
167
+ if (matchingDocument === null) {
168
+ return true;
169
+ }
170
+ try {
171
+ (0, minimongo_common_1._modify)(matchingDocument, modifier);
172
+ }
173
+ catch (error) {
174
+ // Couldn't set a property on a field which is a scalar or null in the
175
+ // selector.
176
+ // Example:
177
+ // real document: { 'a.b': 3 }
178
+ // selector: { 'a': 12 }
179
+ // converted selector (ideal document): { 'a': 12 }
180
+ // modifier: { $set: { 'a.b': 4 } }
181
+ // We don't know what real document was like but from the error raised by
182
+ // $set on a scalar field we can reason that the structure of real document
183
+ // is completely different.
184
+ if (error.name === 'MinimongoError' && error.setPropertyError) {
185
+ return false;
186
+ }
187
+ throw error;
188
+ }
189
+ return this.documentMatches(matchingDocument).result;
190
+ }
191
+ matchingDocument() {
192
+ // check if it was computed before
193
+ if (this._matchingDocument !== undefined) {
194
+ return this._matchingDocument;
195
+ }
196
+ // If the analysis of this selector is too hard for our implementation
197
+ // fallback to "YES"
198
+ let fallback = false;
199
+ this._matchingDocument = (0, minimongo_common_1.pathsToTree)(this._getPaths(), path => {
200
+ const valueSelector = this._selector[path];
201
+ if ((0, minimongo_common_1.isOperatorObject)(valueSelector)) {
202
+ // if there is a strict equality, there is a good
203
+ // chance we can use one of those as "matching"
204
+ // dummy value
205
+ if (valueSelector.$eq) {
206
+ return valueSelector.$eq;
207
+ }
208
+ if (valueSelector.$in) {
209
+ const matcher = new MinimongoMatcher({ placeholder: valueSelector });
210
+ // Return anything from $in that matches the whole selector for this
211
+ // path. If nothing matches, returns `undefined` as nothing can make
212
+ // this selector into `true`.
213
+ return valueSelector.$in.find(placeholder => matcher.documentMatches({ placeholder }).result);
214
+ }
215
+ if (onlyContainsKeys(valueSelector, ['$gt', '$gte', '$lt', '$lte'])) {
216
+ let lowerBound = -Infinity;
217
+ let upperBound = Infinity;
218
+ ['$lte', '$lt'].forEach(op => {
219
+ if (minimongo_common_1.hasOwn.call(valueSelector, op) &&
220
+ valueSelector[op] < upperBound) {
221
+ upperBound = valueSelector[op];
222
+ }
223
+ });
224
+ ['$gte', '$gt'].forEach(op => {
225
+ if (minimongo_common_1.hasOwn.call(valueSelector, op) &&
226
+ valueSelector[op] > lowerBound) {
227
+ lowerBound = valueSelector[op];
228
+ }
229
+ });
230
+ const middle = (lowerBound + upperBound) / 2;
231
+ const matcher = new MinimongoMatcher({ placeholder: valueSelector });
232
+ if (!matcher.documentMatches({ placeholder: middle }).result &&
233
+ (middle === lowerBound || middle === upperBound)) {
234
+ fallback = true;
235
+ }
236
+ return middle;
237
+ }
238
+ if (onlyContainsKeys(valueSelector, ['$nin', '$ne'])) {
239
+ // Since this._isSimple makes sure $nin and $ne are not combined with
240
+ // objects or arrays, we can confidently return an empty object as it
241
+ // never matches any scalar.
242
+ return {};
243
+ }
244
+ fallback = true;
245
+ }
246
+ return this._selector[path];
247
+ }, x => x);
248
+ if (fallback) {
249
+ this._matchingDocument = null;
250
+ }
251
+ return this._matchingDocument;
252
+ }
253
+ ;
254
+ // Knows how to combine a mongo selector and a fields projection to a new fields
255
+ // projection taking into account active fields from the passed selector.
256
+ // @returns Object - projection object (same as fields option of mongo cursor)
257
+ combineIntoProjection(projection) {
258
+ const selectorPaths = (0, minimongo_common_1._pathsElidingNumericKeys)(this._getPaths());
259
+ // Special case for $where operator in the selector - projection should depend
260
+ // on all fields of the document. getSelectorPaths returns a list of paths
261
+ // selector depends on. If one of the paths is '' (empty string) representing
262
+ // the root or the whole document, complete projection should be returned.
263
+ if (selectorPaths.includes('')) {
264
+ return {};
265
+ }
266
+ return (0, minimongo_common_1.combineImportantPathsIntoProjection)(selectorPaths, projection);
267
+ }
268
+ // Returns a list of key paths the given selector is looking for. It includes
269
+ // the empty string if there is a $where.
270
+ _getPaths() {
271
+ return Object.keys(this._paths);
272
+ }
273
+ _recordPathUsed(path) {
274
+ this._paths[path] = true;
275
+ }
276
+ }
277
+ exports.MinimongoMatcher = MinimongoMatcher;
278
+ function pathHasNumericKeys(path) {
279
+ return path.split('.').some(minimongo_common_1.isNumericKey);
280
+ }
281
+ function onlyContainsKeys(obj, keys) {
282
+ return Object.keys(obj).every(k => keys.includes(k));
283
+ }
@@ -1,16 +1,16 @@
1
- export default class MinimongoSorter {
2
- private _sortSpecParts;
3
- private _sortFunction;
4
- private _keyComparator;
5
- private _selectorForAffectedByModifier;
6
- constructor(spec: any);
7
- affectedByModifier(modifier: any): boolean;
8
- getComparator(options?: any): (a: any, b: any) => number;
9
- _compareKeys(key1: any, key2: any): number;
10
- _generateKeysFromDoc(doc: any, cb: any): void;
11
- _getBaseComparator(): (a: any, b: any) => number;
12
- _getMinKeyFromDoc(doc: any): any;
13
- _getPaths(): string[];
14
- _keyFieldComparator(i: number): (key1: any, key2: any) => any;
15
- combineIntoProjection: (projection: any) => {};
16
- }
1
+ export default class MinimongoSorter {
2
+ private _sortSpecParts;
3
+ private _sortFunction;
4
+ private _keyComparator;
5
+ private _selectorForAffectedByModifier;
6
+ constructor(spec: any);
7
+ affectedByModifier(modifier: any): boolean;
8
+ getComparator(options?: any): (a: any, b: any) => number;
9
+ _compareKeys(key1: any, key2: any): number;
10
+ _generateKeysFromDoc(doc: any, cb: any): void;
11
+ _getBaseComparator(): (a: any, b: any) => number | null;
12
+ _getMinKeyFromDoc(doc: any): any;
13
+ _getPaths(): string[];
14
+ _keyFieldComparator(i: number): (key1: any, key2: any) => any;
15
+ combineIntoProjection: (projection: any) => {};
16
+ }