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