mongodb-livedata-server 0.1.3 → 0.1.4

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 (91) hide show
  1. package/dist/livedata_server.d.ts +4 -4
  2. package/dist/livedata_server.js +11 -11
  3. package/dist/meteor/binary-heap/max_heap.d.ts +31 -31
  4. package/dist/meteor/binary-heap/max_heap.js +186 -186
  5. package/dist/meteor/binary-heap/min_heap.d.ts +6 -6
  6. package/dist/meteor/binary-heap/min_heap.js +17 -17
  7. package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -11
  8. package/dist/meteor/binary-heap/min_max_heap.js +48 -48
  9. package/dist/meteor/callback-hook/hook.d.ts +11 -11
  10. package/dist/meteor/callback-hook/hook.js +78 -78
  11. package/dist/meteor/ddp/crossbar.d.ts +15 -15
  12. package/dist/meteor/ddp/crossbar.js +136 -136
  13. package/dist/meteor/ddp/heartbeat.d.ts +19 -19
  14. package/dist/meteor/ddp/heartbeat.js +77 -77
  15. package/dist/meteor/ddp/livedata_server.d.ts +141 -142
  16. package/dist/meteor/ddp/livedata_server.js +403 -403
  17. package/dist/meteor/ddp/method-invocation.d.ts +35 -35
  18. package/dist/meteor/ddp/method-invocation.js +72 -72
  19. package/dist/meteor/ddp/random-stream.d.ts +8 -8
  20. package/dist/meteor/ddp/random-stream.js +100 -100
  21. package/dist/meteor/ddp/session-collection-view.d.ts +20 -20
  22. package/dist/meteor/ddp/session-collection-view.js +106 -106
  23. package/dist/meteor/ddp/session-document-view.d.ts +8 -8
  24. package/dist/meteor/ddp/session-document-view.js +82 -82
  25. package/dist/meteor/ddp/session.d.ts +75 -75
  26. package/dist/meteor/ddp/session.js +590 -590
  27. package/dist/meteor/ddp/stream_server.d.ts +20 -21
  28. package/dist/meteor/ddp/stream_server.js +181 -181
  29. package/dist/meteor/ddp/subscription.d.ts +94 -94
  30. package/dist/meteor/ddp/subscription.js +370 -370
  31. package/dist/meteor/ddp/utils.d.ts +8 -8
  32. package/dist/meteor/ddp/utils.js +104 -104
  33. package/dist/meteor/ddp/writefence.d.ts +20 -20
  34. package/dist/meteor/ddp/writefence.js +111 -111
  35. package/dist/meteor/diff-sequence/diff.d.ts +17 -17
  36. package/dist/meteor/diff-sequence/diff.js +257 -257
  37. package/dist/meteor/ejson/ejson.d.ts +82 -82
  38. package/dist/meteor/ejson/ejson.js +568 -569
  39. package/dist/meteor/ejson/stringify.d.ts +2 -2
  40. package/dist/meteor/ejson/stringify.js +119 -119
  41. package/dist/meteor/ejson/utils.d.ts +12 -12
  42. package/dist/meteor/ejson/utils.js +42 -42
  43. package/dist/meteor/mongo/caching_change_observer.d.ts +16 -16
  44. package/dist/meteor/mongo/caching_change_observer.js +63 -63
  45. package/dist/meteor/mongo/doc_fetcher.d.ts +7 -7
  46. package/dist/meteor/mongo/doc_fetcher.js +53 -53
  47. package/dist/meteor/mongo/geojson_utils.d.ts +3 -3
  48. package/dist/meteor/mongo/geojson_utils.js +40 -41
  49. package/dist/meteor/mongo/live_connection.d.ts +28 -28
  50. package/dist/meteor/mongo/live_connection.js +264 -264
  51. package/dist/meteor/mongo/live_cursor.d.ts +25 -25
  52. package/dist/meteor/mongo/live_cursor.js +60 -60
  53. package/dist/meteor/mongo/minimongo_common.d.ts +84 -84
  54. package/dist/meteor/mongo/minimongo_common.js +1998 -1998
  55. package/dist/meteor/mongo/minimongo_matcher.d.ts +23 -23
  56. package/dist/meteor/mongo/minimongo_matcher.js +283 -283
  57. package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -16
  58. package/dist/meteor/mongo/minimongo_sorter.js +268 -268
  59. package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -9
  60. package/dist/meteor/mongo/observe_driver_utils.js +72 -73
  61. package/dist/meteor/mongo/observe_multiplexer.d.ts +46 -46
  62. package/dist/meteor/mongo/observe_multiplexer.js +203 -203
  63. package/dist/meteor/mongo/oplog-observe-driver.d.ts +68 -68
  64. package/dist/meteor/mongo/oplog-observe-driver.js +918 -918
  65. package/dist/meteor/mongo/oplog_tailing.d.ts +35 -35
  66. package/dist/meteor/mongo/oplog_tailing.js +352 -352
  67. package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -1
  68. package/dist/meteor/mongo/oplog_v2_converter.js +125 -126
  69. package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -30
  70. package/dist/meteor/mongo/polling_observe_driver.js +216 -221
  71. package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -17
  72. package/dist/meteor/mongo/synchronous-cursor.js +261 -261
  73. package/dist/meteor/mongo/synchronous-queue.d.ts +13 -13
  74. package/dist/meteor/mongo/synchronous-queue.js +110 -110
  75. package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -31
  76. package/dist/meteor/ordered-dict/ordered_dict.js +198 -198
  77. package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -42
  78. package/dist/meteor/random/AbstractRandomGenerator.js +92 -92
  79. package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -13
  80. package/dist/meteor/random/AleaRandomGenerator.js +90 -90
  81. package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -16
  82. package/dist/meteor/random/NodeRandomGenerator.js +42 -42
  83. package/dist/meteor/random/createAleaGenerator.d.ts +2 -2
  84. package/dist/meteor/random/createAleaGenerator.js +32 -32
  85. package/dist/meteor/random/createRandom.d.ts +1 -1
  86. package/dist/meteor/random/createRandom.js +22 -22
  87. package/dist/meteor/random/main.d.ts +1 -1
  88. package/dist/meteor/random/main.js +12 -12
  89. package/dist/meteor/types.d.ts +1 -1
  90. package/dist/meteor/types.js +2 -2
  91. package/package.json +5 -5
@@ -1,264 +1,264 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.LiveMongoConnection = void 0;
7
- const hook_1 = require("../callback-hook/hook");
8
- const mongodb_1 = require("mongodb");
9
- const live_cursor_1 = require("./live_cursor");
10
- const ejson_1 = require("../ejson/ejson");
11
- const synchronous_cursor_1 = require("./synchronous-cursor");
12
- const oplog_tailing_1 = require("./oplog_tailing");
13
- const doc_fetcher_1 = require("./doc_fetcher");
14
- const observe_multiplexer_1 = require("./observe_multiplexer");
15
- const polling_observe_driver_1 = require("./polling_observe_driver");
16
- const oplog_observe_driver_1 = require("./oplog-observe-driver");
17
- const minimongo_matcher_1 = require("./minimongo_matcher");
18
- const minimongo_sorter_1 = __importDefault(require("./minimongo_sorter"));
19
- class LiveMongoConnection {
20
- constructor(url, options) {
21
- this._oplogHandle = null;
22
- this._docFetcher = null;
23
- this._observeMultiplexers = {};
24
- this._onFailoverHook = new hook_1.Hook();
25
- options = options || {};
26
- var mongoOptions = {
27
- ignoreUndefined: true,
28
- maxPoolSize: undefined
29
- };
30
- // Internally the oplog connections specify their own maxPoolSize
31
- // which we don't want to overwrite with any user defined value
32
- if (options.hasOwnProperty("maxPoolSize")) {
33
- // If we just set this for "server", replSet will override it. If we just
34
- // set it for replSet, it will be ignored if we're not using a replSet.
35
- mongoOptions.maxPoolSize = options.maxPoolSize;
36
- }
37
- this.client = new mongodb_1.MongoClient(url, mongoOptions);
38
- this.db = this.client.db();
39
- this.client.on('serverDescriptionChanged', event => {
40
- // When the connection is no longer against the primary node, execute all
41
- // failover hooks. This is important for the driver as it has to re-pool the
42
- // query when it happens.
43
- if (event.previousDescription.type !== 'RSPrimary' &&
44
- event.newDescription.type === 'RSPrimary') {
45
- this._onFailoverHook.each(callback => {
46
- callback();
47
- return true;
48
- });
49
- }
50
- });
51
- if (options.oplogUrl) {
52
- this._oplogHandle = new oplog_tailing_1.OplogHandle(options.oplogUrl, this.db.databaseName);
53
- this._docFetcher = new doc_fetcher_1.DocFetcher(this.db);
54
- }
55
- }
56
- close() {
57
- var self = this;
58
- if (!self.db)
59
- throw Error("close called before Connection created?");
60
- // XXX probably untested
61
- var oplogHandle = self._oplogHandle;
62
- self._oplogHandle = null;
63
- if (oplogHandle)
64
- oplogHandle.stop();
65
- // Use Future.wrap so that errors get thrown. This happens to
66
- // work even outside a fiber since the 'close' method is not
67
- // actually asynchronous.
68
- self.client.close(true);
69
- }
70
- // Tails the cursor described by cursorDescription, most likely on the
71
- // oplog. Calls docCallback with each document found. Ignores errors and just
72
- // restarts the tail on error.
73
- //
74
- // If timeoutMS is set, then if we don't get a new document every timeoutMS,
75
- // kill and restart the cursor. This is primarily a workaround for #8598.
76
- tail(cursorDescription, docCallback, timeoutMS) {
77
- if (!cursorDescription.options.tailable)
78
- throw new Error("Can only tail a tailable cursor");
79
- var cursor = (0, synchronous_cursor_1._createSynchronousCursor)(this.db, cursorDescription);
80
- var stopped = false;
81
- var lastTS;
82
- const loop = async () => {
83
- var doc = null;
84
- while (true) {
85
- if (stopped)
86
- return;
87
- try {
88
- doc = await cursor._nextObjectPromiseWithTimeout(timeoutMS);
89
- }
90
- catch (err) {
91
- // There's no good way to figure out if this was actually an error from
92
- // Mongo, or just client-side (including our own timeout error). Ah
93
- // well. But either way, we need to retry the cursor (unless the failure
94
- // was because the observe got stopped).
95
- doc = null;
96
- }
97
- // Since we awaited a promise above, we need to check again to see if
98
- // we've been stopped before calling the callback.
99
- if (stopped)
100
- return;
101
- if (doc) {
102
- // If a tailable cursor contains a "ts" field, use it to recreate the
103
- // cursor on error. ("ts" is a standard that Mongo uses internally for
104
- // the oplog, and there's a special flag that lets you do binary search
105
- // on it instead of needing to use an index.)
106
- lastTS = doc.ts;
107
- docCallback(doc);
108
- }
109
- else {
110
- const newSelector = Object.assign({}, cursorDescription.selector);
111
- if (lastTS) {
112
- newSelector.ts = { $gt: lastTS };
113
- }
114
- const newDescription = new live_cursor_1.CursorDescription(cursorDescription.collectionName, newSelector, cursorDescription.options);
115
- cursor = (0, synchronous_cursor_1._createSynchronousCursor)(this.db, newDescription);
116
- // Mongo failover takes many seconds. Retry in a bit. (Without this
117
- // setTimeout, we peg the CPU at 100% and never notice the actual
118
- // failover.
119
- setTimeout(loop, 100);
120
- break;
121
- }
122
- }
123
- };
124
- setImmediate(loop);
125
- return {
126
- stop: function () {
127
- stopped = true;
128
- cursor.close();
129
- }
130
- };
131
- }
132
- async _observeChanges(cursorDescription, ordered, callbacks, nonMutatingCallbacks) {
133
- var self = this;
134
- if (cursorDescription.options.tailable) {
135
- return self._observeChangesTailable(cursorDescription, ordered, callbacks);
136
- }
137
- // You may not filter out _id when observing changes, because the id is a core
138
- // part of the observeChanges API.
139
- const fieldsOptions = cursorDescription.options.projection;
140
- if (fieldsOptions && (fieldsOptions._id === 0 || fieldsOptions._id === false))
141
- throw Error("You may not observe a cursor with {fields: {_id: 0}}");
142
- var observeKey = (0, ejson_1.stringify)(Object.assign({ ordered: ordered }, cursorDescription));
143
- var multiplexer, observeDriver;
144
- var firstHandle = false;
145
- // Find a matching ObserveMultiplexer, or create a new one. This next block is
146
- // guaranteed to not yield (and it doesn't call anything that can observe a
147
- // new query), so no other calls to this function can interleave with it.
148
- //Meteor._noYieldsAllowed(function () {
149
- if (self._observeMultiplexers.hasOwnProperty(observeKey)) {
150
- multiplexer = self._observeMultiplexers[observeKey];
151
- }
152
- else {
153
- firstHandle = true;
154
- // Create a new ObserveMultiplexer.
155
- multiplexer = new observe_multiplexer_1.ObserveMultiplexer({
156
- ordered: ordered,
157
- onStop: function () {
158
- delete self._observeMultiplexers[observeKey];
159
- observeDriver.stop();
160
- }
161
- });
162
- self._observeMultiplexers[observeKey] = multiplexer;
163
- }
164
- //});
165
- var observeHandle = new observe_multiplexer_1.ObserveHandle(multiplexer, callbacks, nonMutatingCallbacks);
166
- if (firstHandle) {
167
- let matcher;
168
- let sorter;
169
- // At a bare minimum, using the oplog requires us to have an oplog, to
170
- // want unordered callbacks, and to not want a callback on the polls
171
- // that won't happen.
172
- const basicPrerequisites = self._oplogHandle && !ordered && !callbacks._testOnlyPollCallback;
173
- let selectorIsCompilable = false;
174
- // We need to be able to compile the selector. Fall back to polling for
175
- // some newfangled $selector that minimongo doesn't support yet.
176
- try {
177
- matcher = new minimongo_matcher_1.MinimongoMatcher(cursorDescription.selector);
178
- selectorIsCompilable = true;
179
- }
180
- catch (e) {
181
- }
182
- const supportedByOplog = oplog_observe_driver_1.OplogObserveDriver.cursorSupported(cursorDescription, matcher);
183
- let cursorIsSortable = false;
184
- // And we need to be able to compile the sort, if any. eg, can't be
185
- // {$natural: 1}.
186
- if (!cursorDescription.options.sort)
187
- cursorIsSortable = true;
188
- try {
189
- sorter = new minimongo_sorter_1.default(cursorDescription.options.sort);
190
- cursorIsSortable = true;
191
- }
192
- catch (e) {
193
- }
194
- const canUseOplog = basicPrerequisites && selectorIsCompilable && cursorIsSortable && supportedByOplog;
195
- var driverClass = canUseOplog ? oplog_observe_driver_1.OplogObserveDriver : polling_observe_driver_1.PollingObserveDriver;
196
- observeDriver = new driverClass({
197
- cursorDescription: cursorDescription,
198
- mongoHandle: self,
199
- multiplexer: multiplexer,
200
- ordered: ordered,
201
- matcher,
202
- sorter // ignored by polling
203
- });
204
- }
205
- // Blocks until the initial adds have been sent.
206
- await multiplexer.addHandleAndSendInitialAdds(observeHandle);
207
- return observeHandle;
208
- }
209
- // observeChanges for tailable cursors on capped collections.
210
- //
211
- // Some differences from normal cursors:
212
- // - Will never produce anything other than 'added' or 'addedBefore'. If you
213
- // do update a document that has already been produced, this will not notice
214
- // it.
215
- // - If you disconnect and reconnect from Mongo, it will essentially restart
216
- // the query, which will lead to duplicate results. This is pretty bad,
217
- // but if you include a field called 'ts' which is inserted as
218
- // new MongoInternals.MongoTimestamp(0, 0) (which is initialized to the
219
- // current Mongo-style timestamp), we'll be able to find the place to
220
- // restart properly. (This field is specifically understood by Mongo with an
221
- // optimization which allows it to find the right place to start without
222
- // an index on ts. It's how the oplog works.)
223
- // - No callbacks are triggered synchronously with the call (there's no
224
- // differentiation between "initial data" and "later changes"; everything
225
- // that matches the query gets sent asynchronously).
226
- // - De-duplication is not implemented.
227
- // - Does not yet interact with the write fence. Probably, this should work by
228
- // ignoring removes (which don't work on capped collections) and updates
229
- // (which don't affect tailable cursors), and just keeping track of the ID
230
- // of the inserted object, and closing the write fence once you get to that
231
- // ID (or timestamp?). This doesn't work well if the document doesn't match
232
- // the query, though. On the other hand, the write fence can close
233
- // immediately if it does not match the query. So if we trust minimongo
234
- // enough to accurately evaluate the query against the write fence, we
235
- // should be able to do this... Of course, minimongo doesn't even support
236
- // Mongo Timestamps yet.
237
- _observeChangesTailable(cursorDescription, ordered, callbacks) {
238
- var self = this;
239
- // Tailable cursors only ever call added/addedBefore callbacks, so it's an
240
- // error if you didn't provide them.
241
- if ((ordered && !callbacks.addedBefore) ||
242
- (!ordered && !callbacks.added)) {
243
- throw new Error("Can't observe an " + (ordered ? "ordered" : "unordered")
244
- + " tailable cursor without a "
245
- + (ordered ? "addedBefore" : "added") + " callback");
246
- }
247
- return self.tail(cursorDescription, function (doc) {
248
- var id = doc._id;
249
- delete doc._id;
250
- // The ts is an implementation detail. Hide it.
251
- delete doc.ts;
252
- if (ordered) {
253
- callbacks.addedBefore(id, doc, null);
254
- }
255
- else {
256
- callbacks.added(id, doc);
257
- }
258
- });
259
- }
260
- _onFailover(callback) {
261
- return this._onFailoverHook.register(callback);
262
- }
263
- }
264
- exports.LiveMongoConnection = LiveMongoConnection;
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LiveMongoConnection = void 0;
7
+ const hook_1 = require("../callback-hook/hook");
8
+ const mongodb_1 = require("mongodb");
9
+ const live_cursor_1 = require("./live_cursor");
10
+ const ejson_1 = require("../ejson/ejson");
11
+ const synchronous_cursor_1 = require("./synchronous-cursor");
12
+ const oplog_tailing_1 = require("./oplog_tailing");
13
+ const doc_fetcher_1 = require("./doc_fetcher");
14
+ const observe_multiplexer_1 = require("./observe_multiplexer");
15
+ const polling_observe_driver_1 = require("./polling_observe_driver");
16
+ const oplog_observe_driver_1 = require("./oplog-observe-driver");
17
+ const minimongo_matcher_1 = require("./minimongo_matcher");
18
+ const minimongo_sorter_1 = __importDefault(require("./minimongo_sorter"));
19
+ class LiveMongoConnection {
20
+ constructor(url, options) {
21
+ this._oplogHandle = null;
22
+ this._docFetcher = null;
23
+ this._observeMultiplexers = {};
24
+ this._onFailoverHook = new hook_1.Hook();
25
+ options = options || {};
26
+ var mongoOptions = {
27
+ ignoreUndefined: true,
28
+ maxPoolSize: undefined
29
+ };
30
+ // Internally the oplog connections specify their own maxPoolSize
31
+ // which we don't want to overwrite with any user defined value
32
+ if (options.hasOwnProperty("maxPoolSize")) {
33
+ // If we just set this for "server", replSet will override it. If we just
34
+ // set it for replSet, it will be ignored if we're not using a replSet.
35
+ mongoOptions.maxPoolSize = options.maxPoolSize;
36
+ }
37
+ this.client = new mongodb_1.MongoClient(url, mongoOptions);
38
+ this.db = this.client.db();
39
+ this.client.on('serverDescriptionChanged', event => {
40
+ // When the connection is no longer against the primary node, execute all
41
+ // failover hooks. This is important for the driver as it has to re-pool the
42
+ // query when it happens.
43
+ if (event.previousDescription.type !== 'RSPrimary' &&
44
+ event.newDescription.type === 'RSPrimary') {
45
+ this._onFailoverHook.each(callback => {
46
+ callback();
47
+ return true;
48
+ });
49
+ }
50
+ });
51
+ if (options.oplogUrl) {
52
+ this._oplogHandle = new oplog_tailing_1.OplogHandle(options.oplogUrl, this.db.databaseName);
53
+ this._docFetcher = new doc_fetcher_1.DocFetcher(this.db);
54
+ }
55
+ }
56
+ close() {
57
+ var self = this;
58
+ if (!self.db)
59
+ throw Error("close called before Connection created?");
60
+ // XXX probably untested
61
+ var oplogHandle = self._oplogHandle;
62
+ self._oplogHandle = null;
63
+ if (oplogHandle)
64
+ oplogHandle.stop();
65
+ // Use Future.wrap so that errors get thrown. This happens to
66
+ // work even outside a fiber since the 'close' method is not
67
+ // actually asynchronous.
68
+ self.client.close(true);
69
+ }
70
+ // Tails the cursor described by cursorDescription, most likely on the
71
+ // oplog. Calls docCallback with each document found. Ignores errors and just
72
+ // restarts the tail on error.
73
+ //
74
+ // If timeoutMS is set, then if we don't get a new document every timeoutMS,
75
+ // kill and restart the cursor. This is primarily a workaround for #8598.
76
+ tail(cursorDescription, docCallback, timeoutMS) {
77
+ if (!cursorDescription.options.tailable)
78
+ throw new Error("Can only tail a tailable cursor");
79
+ var cursor = (0, synchronous_cursor_1._createSynchronousCursor)(this.db, cursorDescription);
80
+ var stopped = false;
81
+ var lastTS;
82
+ const loop = async () => {
83
+ var doc = null;
84
+ while (true) {
85
+ if (stopped)
86
+ return;
87
+ try {
88
+ doc = await cursor._nextObjectPromiseWithTimeout(timeoutMS);
89
+ }
90
+ catch (err) {
91
+ // There's no good way to figure out if this was actually an error from
92
+ // Mongo, or just client-side (including our own timeout error). Ah
93
+ // well. But either way, we need to retry the cursor (unless the failure
94
+ // was because the observe got stopped).
95
+ doc = null;
96
+ }
97
+ // Since we awaited a promise above, we need to check again to see if
98
+ // we've been stopped before calling the callback.
99
+ if (stopped)
100
+ return;
101
+ if (doc) {
102
+ // If a tailable cursor contains a "ts" field, use it to recreate the
103
+ // cursor on error. ("ts" is a standard that Mongo uses internally for
104
+ // the oplog, and there's a special flag that lets you do binary search
105
+ // on it instead of needing to use an index.)
106
+ lastTS = doc.ts;
107
+ docCallback(doc);
108
+ }
109
+ else {
110
+ const newSelector = Object.assign({}, cursorDescription.selector);
111
+ if (lastTS) {
112
+ newSelector.ts = { $gt: lastTS };
113
+ }
114
+ const newDescription = new live_cursor_1.CursorDescription(cursorDescription.collectionName, newSelector, cursorDescription.options);
115
+ cursor = (0, synchronous_cursor_1._createSynchronousCursor)(this.db, newDescription);
116
+ // Mongo failover takes many seconds. Retry in a bit. (Without this
117
+ // setTimeout, we peg the CPU at 100% and never notice the actual
118
+ // failover.
119
+ setTimeout(loop, 100);
120
+ break;
121
+ }
122
+ }
123
+ };
124
+ setImmediate(loop);
125
+ return {
126
+ stop: function () {
127
+ stopped = true;
128
+ cursor.close();
129
+ }
130
+ };
131
+ }
132
+ async _observeChanges(cursorDescription, ordered, callbacks, nonMutatingCallbacks) {
133
+ var self = this;
134
+ if (cursorDescription.options.tailable) {
135
+ return self._observeChangesTailable(cursorDescription, ordered, callbacks);
136
+ }
137
+ // You may not filter out _id when observing changes, because the id is a core
138
+ // part of the observeChanges API.
139
+ const fieldsOptions = cursorDescription.options.projection;
140
+ if (fieldsOptions && (fieldsOptions._id === 0 || fieldsOptions._id === false))
141
+ throw Error("You may not observe a cursor with {fields: {_id: 0}}");
142
+ var observeKey = (0, ejson_1.stringify)(Object.assign({ ordered: ordered }, cursorDescription));
143
+ var multiplexer, observeDriver;
144
+ var firstHandle = false;
145
+ // Find a matching ObserveMultiplexer, or create a new one. This next block is
146
+ // guaranteed to not yield (and it doesn't call anything that can observe a
147
+ // new query), so no other calls to this function can interleave with it.
148
+ //Meteor._noYieldsAllowed(function () {
149
+ if (self._observeMultiplexers.hasOwnProperty(observeKey)) {
150
+ multiplexer = self._observeMultiplexers[observeKey];
151
+ }
152
+ else {
153
+ firstHandle = true;
154
+ // Create a new ObserveMultiplexer.
155
+ multiplexer = new observe_multiplexer_1.ObserveMultiplexer({
156
+ ordered: ordered,
157
+ onStop: function () {
158
+ delete self._observeMultiplexers[observeKey];
159
+ observeDriver.stop();
160
+ }
161
+ });
162
+ self._observeMultiplexers[observeKey] = multiplexer;
163
+ }
164
+ //});
165
+ var observeHandle = new observe_multiplexer_1.ObserveHandle(multiplexer, callbacks, nonMutatingCallbacks);
166
+ if (firstHandle) {
167
+ let matcher;
168
+ let sorter;
169
+ // At a bare minimum, using the oplog requires us to have an oplog, to
170
+ // want unordered callbacks, and to not want a callback on the polls
171
+ // that won't happen.
172
+ const basicPrerequisites = self._oplogHandle && !ordered && !callbacks._testOnlyPollCallback;
173
+ let selectorIsCompilable = false;
174
+ // We need to be able to compile the selector. Fall back to polling for
175
+ // some newfangled $selector that minimongo doesn't support yet.
176
+ try {
177
+ matcher = new minimongo_matcher_1.MinimongoMatcher(cursorDescription.selector);
178
+ selectorIsCompilable = true;
179
+ }
180
+ catch (e) {
181
+ }
182
+ const supportedByOplog = oplog_observe_driver_1.OplogObserveDriver.cursorSupported(cursorDescription, matcher);
183
+ let cursorIsSortable = false;
184
+ // And we need to be able to compile the sort, if any. eg, can't be
185
+ // {$natural: 1}.
186
+ if (!cursorDescription.options.sort)
187
+ cursorIsSortable = true;
188
+ try {
189
+ sorter = new minimongo_sorter_1.default(cursorDescription.options.sort);
190
+ cursorIsSortable = true;
191
+ }
192
+ catch (e) {
193
+ }
194
+ const canUseOplog = basicPrerequisites && selectorIsCompilable && cursorIsSortable && supportedByOplog;
195
+ var driverClass = canUseOplog ? oplog_observe_driver_1.OplogObserveDriver : polling_observe_driver_1.PollingObserveDriver;
196
+ observeDriver = new driverClass({
197
+ cursorDescription: cursorDescription,
198
+ mongoHandle: self,
199
+ multiplexer: multiplexer,
200
+ ordered: ordered,
201
+ matcher, // ignored by polling
202
+ sorter // ignored by polling
203
+ });
204
+ }
205
+ // Blocks until the initial adds have been sent.
206
+ await multiplexer.addHandleAndSendInitialAdds(observeHandle);
207
+ return observeHandle;
208
+ }
209
+ // observeChanges for tailable cursors on capped collections.
210
+ //
211
+ // Some differences from normal cursors:
212
+ // - Will never produce anything other than 'added' or 'addedBefore'. If you
213
+ // do update a document that has already been produced, this will not notice
214
+ // it.
215
+ // - If you disconnect and reconnect from Mongo, it will essentially restart
216
+ // the query, which will lead to duplicate results. This is pretty bad,
217
+ // but if you include a field called 'ts' which is inserted as
218
+ // new MongoInternals.MongoTimestamp(0, 0) (which is initialized to the
219
+ // current Mongo-style timestamp), we'll be able to find the place to
220
+ // restart properly. (This field is specifically understood by Mongo with an
221
+ // optimization which allows it to find the right place to start without
222
+ // an index on ts. It's how the oplog works.)
223
+ // - No callbacks are triggered synchronously with the call (there's no
224
+ // differentiation between "initial data" and "later changes"; everything
225
+ // that matches the query gets sent asynchronously).
226
+ // - De-duplication is not implemented.
227
+ // - Does not yet interact with the write fence. Probably, this should work by
228
+ // ignoring removes (which don't work on capped collections) and updates
229
+ // (which don't affect tailable cursors), and just keeping track of the ID
230
+ // of the inserted object, and closing the write fence once you get to that
231
+ // ID (or timestamp?). This doesn't work well if the document doesn't match
232
+ // the query, though. On the other hand, the write fence can close
233
+ // immediately if it does not match the query. So if we trust minimongo
234
+ // enough to accurately evaluate the query against the write fence, we
235
+ // should be able to do this... Of course, minimongo doesn't even support
236
+ // Mongo Timestamps yet.
237
+ _observeChangesTailable(cursorDescription, ordered, callbacks) {
238
+ var self = this;
239
+ // Tailable cursors only ever call added/addedBefore callbacks, so it's an
240
+ // error if you didn't provide them.
241
+ if ((ordered && !callbacks.addedBefore) ||
242
+ (!ordered && !callbacks.added)) {
243
+ throw new Error("Can't observe an " + (ordered ? "ordered" : "unordered")
244
+ + " tailable cursor without a "
245
+ + (ordered ? "addedBefore" : "added") + " callback");
246
+ }
247
+ return self.tail(cursorDescription, function (doc) {
248
+ var id = doc._id;
249
+ delete doc._id;
250
+ // The ts is an implementation detail. Hide it.
251
+ delete doc.ts;
252
+ if (ordered) {
253
+ callbacks.addedBefore(id, doc, null);
254
+ }
255
+ else {
256
+ callbacks.added(id, doc);
257
+ }
258
+ });
259
+ }
260
+ _onFailover(callback) {
261
+ return this._onFailoverHook.register(callback);
262
+ }
263
+ }
264
+ exports.LiveMongoConnection = LiveMongoConnection;
@@ -1,25 +1,25 @@
1
- import { Subscription } from "../ddp/subscription";
2
- import * as MongoDB from "mongodb";
3
- import { LiveMongoConnection } from "./live_connection";
4
- interface CustomFindOptions<T> extends MongoDB.FindOptions<MongoDB.WithId<T>> {
5
- pollingThrottleMs?: number;
6
- pollingIntervalMs?: number;
7
- transform?: (doc: T) => T;
8
- maxTimeMs?: number;
9
- disableOplog?: boolean;
10
- }
11
- export declare class CursorDescription<T> {
12
- collectionName: string;
13
- selector: MongoDB.Filter<MongoDB.WithId<T>>;
14
- options: CustomFindOptions<MongoDB.WithId<T>>;
15
- constructor(collectionName: string, selector: MongoDB.Filter<MongoDB.WithId<T>>, options?: CustomFindOptions<MongoDB.WithId<T>>);
16
- }
17
- export declare class LiveCursor<T> {
18
- mongo: LiveMongoConnection;
19
- cursorDescription: CursorDescription<T>;
20
- constructor(mongo: LiveMongoConnection, collectionName: string, selector: MongoDB.Filter<MongoDB.WithId<T>>, options: CustomFindOptions<MongoDB.WithId<T>>);
21
- _publishCursor(sub: Subscription): Promise<{
22
- stop: () => void;
23
- }>;
24
- }
25
- export {};
1
+ import { Subscription } from "../ddp/subscription";
2
+ import * as MongoDB from "mongodb";
3
+ import { LiveMongoConnection } from "./live_connection";
4
+ interface CustomFindOptions<T> extends MongoDB.FindOptions<MongoDB.WithId<T>> {
5
+ pollingThrottleMs?: number;
6
+ pollingIntervalMs?: number;
7
+ transform?: (doc: T) => T;
8
+ maxTimeMs?: number;
9
+ disableOplog?: boolean;
10
+ }
11
+ export declare class CursorDescription<T> {
12
+ collectionName: string;
13
+ selector: MongoDB.Filter<MongoDB.WithId<T>>;
14
+ options: CustomFindOptions<MongoDB.WithId<T>>;
15
+ constructor(collectionName: string, selector: MongoDB.Filter<MongoDB.WithId<T>>, options?: CustomFindOptions<MongoDB.WithId<T>>);
16
+ }
17
+ export declare class LiveCursor<T> {
18
+ mongo: LiveMongoConnection;
19
+ cursorDescription: CursorDescription<T>;
20
+ constructor(mongo: LiveMongoConnection, collectionName: string, selector: MongoDB.Filter<MongoDB.WithId<T>>, options: CustomFindOptions<MongoDB.WithId<T>>);
21
+ _publishCursor(sub: Subscription): Promise<{
22
+ stop: () => void;
23
+ }>;
24
+ }
25
+ export {};