mongodb-livedata-server 0.1.2 → 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.
- package/dist/livedata_server.d.ts +4 -4
- package/dist/livedata_server.js +11 -11
- package/dist/meteor/binary-heap/max_heap.d.ts +31 -31
- package/dist/meteor/binary-heap/max_heap.js +186 -186
- package/dist/meteor/binary-heap/min_heap.d.ts +6 -6
- package/dist/meteor/binary-heap/min_heap.js +17 -17
- package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -11
- package/dist/meteor/binary-heap/min_max_heap.js +48 -48
- package/dist/meteor/callback-hook/hook.d.ts +11 -11
- package/dist/meteor/callback-hook/hook.js +78 -78
- package/dist/meteor/ddp/crossbar.d.ts +15 -15
- package/dist/meteor/ddp/crossbar.js +136 -136
- package/dist/meteor/ddp/heartbeat.d.ts +19 -19
- package/dist/meteor/ddp/heartbeat.js +77 -77
- package/dist/meteor/ddp/livedata_server.d.ts +141 -142
- package/dist/meteor/ddp/livedata_server.js +403 -403
- package/dist/meteor/ddp/method-invocation.d.ts +35 -35
- package/dist/meteor/ddp/method-invocation.js +72 -72
- package/dist/meteor/ddp/random-stream.d.ts +8 -8
- package/dist/meteor/ddp/random-stream.js +100 -100
- package/dist/meteor/ddp/session-collection-view.d.ts +20 -20
- package/dist/meteor/ddp/session-collection-view.js +106 -106
- package/dist/meteor/ddp/session-document-view.d.ts +8 -8
- package/dist/meteor/ddp/session-document-view.js +82 -82
- package/dist/meteor/ddp/session.d.ts +75 -74
- package/dist/meteor/ddp/session.js +590 -589
- package/dist/meteor/ddp/stream_server.d.ts +20 -21
- package/dist/meteor/ddp/stream_server.js +181 -181
- package/dist/meteor/ddp/subscription.d.ts +94 -94
- package/dist/meteor/ddp/subscription.js +370 -370
- package/dist/meteor/ddp/utils.d.ts +8 -8
- package/dist/meteor/ddp/utils.js +104 -104
- package/dist/meteor/ddp/writefence.d.ts +20 -20
- package/dist/meteor/ddp/writefence.js +111 -111
- package/dist/meteor/diff-sequence/diff.d.ts +17 -17
- package/dist/meteor/diff-sequence/diff.js +257 -257
- package/dist/meteor/ejson/ejson.d.ts +82 -82
- package/dist/meteor/ejson/ejson.js +568 -569
- package/dist/meteor/ejson/stringify.d.ts +2 -2
- package/dist/meteor/ejson/stringify.js +119 -119
- package/dist/meteor/ejson/utils.d.ts +12 -12
- package/dist/meteor/ejson/utils.js +42 -42
- package/dist/meteor/mongo/caching_change_observer.d.ts +16 -16
- package/dist/meteor/mongo/caching_change_observer.js +63 -63
- package/dist/meteor/mongo/doc_fetcher.d.ts +7 -7
- package/dist/meteor/mongo/doc_fetcher.js +53 -53
- package/dist/meteor/mongo/geojson_utils.d.ts +3 -3
- package/dist/meteor/mongo/geojson_utils.js +40 -41
- package/dist/meteor/mongo/live_connection.d.ts +28 -28
- package/dist/meteor/mongo/live_connection.js +264 -264
- package/dist/meteor/mongo/live_cursor.d.ts +25 -25
- package/dist/meteor/mongo/live_cursor.js +60 -60
- package/dist/meteor/mongo/minimongo_common.d.ts +84 -84
- package/dist/meteor/mongo/minimongo_common.js +1998 -2002
- package/dist/meteor/mongo/minimongo_matcher.d.ts +23 -23
- package/dist/meteor/mongo/minimongo_matcher.js +283 -283
- package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -16
- package/dist/meteor/mongo/minimongo_sorter.js +268 -268
- package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -9
- package/dist/meteor/mongo/observe_driver_utils.js +72 -73
- package/dist/meteor/mongo/observe_multiplexer.d.ts +46 -46
- package/dist/meteor/mongo/observe_multiplexer.js +203 -203
- package/dist/meteor/mongo/oplog-observe-driver.d.ts +68 -68
- package/dist/meteor/mongo/oplog-observe-driver.js +918 -918
- package/dist/meteor/mongo/oplog_tailing.d.ts +35 -35
- package/dist/meteor/mongo/oplog_tailing.js +352 -352
- package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -1
- package/dist/meteor/mongo/oplog_v2_converter.js +125 -126
- package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -30
- package/dist/meteor/mongo/polling_observe_driver.js +216 -221
- package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -17
- package/dist/meteor/mongo/synchronous-cursor.js +261 -261
- package/dist/meteor/mongo/synchronous-queue.d.ts +13 -13
- package/dist/meteor/mongo/synchronous-queue.js +110 -110
- package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -31
- package/dist/meteor/ordered-dict/ordered_dict.js +198 -198
- package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -42
- package/dist/meteor/random/AbstractRandomGenerator.js +92 -92
- package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -13
- package/dist/meteor/random/AleaRandomGenerator.js +90 -90
- package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -16
- package/dist/meteor/random/NodeRandomGenerator.js +42 -42
- package/dist/meteor/random/createAleaGenerator.d.ts +2 -2
- package/dist/meteor/random/createAleaGenerator.js +32 -32
- package/dist/meteor/random/createRandom.d.ts +1 -1
- package/dist/meteor/random/createRandom.js +22 -22
- package/dist/meteor/random/main.d.ts +1 -1
- package/dist/meteor/random/main.js +12 -12
- package/dist/meteor/types.d.ts +1 -1
- package/dist/meteor/types.js +2 -2
- package/package.json +6 -5
|
@@ -1,73 +1,72 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// to
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
var
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function _idsMatchedBySelector(selector) {
|
|
41
|
-
if (!selector) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
// Do we have an _id clause?
|
|
45
|
-
if (selector.hasOwnProperty('_id')) {
|
|
46
|
-
// Is the _id clause just an ID?
|
|
47
|
-
if (typeof selector._id === "string") {
|
|
48
|
-
return [selector._id];
|
|
49
|
-
}
|
|
50
|
-
// Is the _id clause {_id: {$in: ["x", "y", "z"]}}?
|
|
51
|
-
if (selector._id
|
|
52
|
-
&& "$in" in selector._id
|
|
53
|
-
&& Array.isArray(selector._id.$in)
|
|
54
|
-
&& selector._id.$in.length
|
|
55
|
-
&& selector._id.$in.every(id => typeof id === "string")) {
|
|
56
|
-
return selector._id.$in;
|
|
57
|
-
}
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
// If this is a top-level $and, and any of the clauses constrain their
|
|
61
|
-
// documents, then the whole selector is constrained by any one clause's
|
|
62
|
-
// constraint. (Well, by their intersection, but that seems unlikely.)
|
|
63
|
-
if ("$and" in selector && Array.isArray(selector.$and)) {
|
|
64
|
-
for (let i = 0; i < selector.$and.length; ++i) {
|
|
65
|
-
const subIds = _idsMatchedBySelector(selector.$and[i]);
|
|
66
|
-
if (subIds) {
|
|
67
|
-
return subIds;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
exports._idsMatchedBySelector = _idsMatchedBySelector;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listenAll = listenAll;
|
|
4
|
+
exports.forEachTrigger = forEachTrigger;
|
|
5
|
+
exports._idsMatchedBySelector = _idsMatchedBySelector;
|
|
6
|
+
const crossbar_1 = require("../ddp/crossbar");
|
|
7
|
+
// Listen for the invalidation messages that will trigger us to poll the
|
|
8
|
+
// database for changes. If this selector specifies specific IDs, specify them
|
|
9
|
+
// here, so that updates to different specific IDs don't cause us to poll.
|
|
10
|
+
// listenCallback is the same kind of (notification, complete) callback passed
|
|
11
|
+
// to InvalidationCrossbar.listen.
|
|
12
|
+
function listenAll(cursorDescription, listenCallback) {
|
|
13
|
+
var listeners = [];
|
|
14
|
+
forEachTrigger(cursorDescription, function (trigger) {
|
|
15
|
+
listeners.push(crossbar_1._InvalidationCrossbar.listen(trigger, listenCallback));
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
stop: function () {
|
|
19
|
+
for (const listener of listeners) {
|
|
20
|
+
listener.stop();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function forEachTrigger(cursorDescription, triggerCallback) {
|
|
26
|
+
var key = { collection: cursorDescription.collectionName };
|
|
27
|
+
var specificIds = _idsMatchedBySelector(cursorDescription.selector);
|
|
28
|
+
if (specificIds) {
|
|
29
|
+
for (const id of specificIds) {
|
|
30
|
+
triggerCallback(Object.assign({ id: id }, key));
|
|
31
|
+
}
|
|
32
|
+
triggerCallback(Object.assign({ dropCollection: true, id: null }, key));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
triggerCallback(key);
|
|
36
|
+
}
|
|
37
|
+
// Everyone cares about the database being dropped.
|
|
38
|
+
triggerCallback({ dropDatabase: true });
|
|
39
|
+
}
|
|
40
|
+
function _idsMatchedBySelector(selector) {
|
|
41
|
+
if (!selector) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
// Do we have an _id clause?
|
|
45
|
+
if (selector.hasOwnProperty('_id')) {
|
|
46
|
+
// Is the _id clause just an ID?
|
|
47
|
+
if (typeof selector._id === "string") {
|
|
48
|
+
return [selector._id];
|
|
49
|
+
}
|
|
50
|
+
// Is the _id clause {_id: {$in: ["x", "y", "z"]}}?
|
|
51
|
+
if (selector._id
|
|
52
|
+
&& "$in" in selector._id
|
|
53
|
+
&& Array.isArray(selector._id.$in)
|
|
54
|
+
&& selector._id.$in.length
|
|
55
|
+
&& selector._id.$in.every(id => typeof id === "string")) {
|
|
56
|
+
return selector._id.$in;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// If this is a top-level $and, and any of the clauses constrain their
|
|
61
|
+
// documents, then the whole selector is constrained by any one clause's
|
|
62
|
+
// constraint. (Well, by their intersection, but that seems unlikely.)
|
|
63
|
+
if ("$and" in selector && Array.isArray(selector.$and)) {
|
|
64
|
+
for (let i = 0; i < selector.$and.length; ++i) {
|
|
65
|
+
const subIds = _idsMatchedBySelector(selector.$and[i]);
|
|
66
|
+
if (subIds) {
|
|
67
|
+
return subIds;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { OrderedDict } from "../ordered-dict/ordered_dict";
|
|
2
|
-
export interface ObserveCallbacks {
|
|
3
|
-
added: (id: string, fields: Record<string, any>) => void;
|
|
4
|
-
changed: (id: string, fields: Record<string, any>) => void;
|
|
5
|
-
removed: (id: string) => void;
|
|
6
|
-
addedBefore?: (id: string, fields: Record<string, any>, before?: any) => void;
|
|
7
|
-
movedBefore?: (id: string, fields: Record<string, any>, before?: any) => void;
|
|
8
|
-
initialAdds: (docs: Map<string, any> | OrderedDict) => void;
|
|
9
|
-
_testOnlyPollCallback?: any;
|
|
10
|
-
}
|
|
11
|
-
export declare class ObserveMultiplexer {
|
|
12
|
-
private _ordered;
|
|
13
|
-
private _onStop;
|
|
14
|
-
private _queue;
|
|
15
|
-
private _handles;
|
|
16
|
-
private _readyFuture;
|
|
17
|
-
private _cache;
|
|
18
|
-
private _addHandleTasksScheduledButNotPerformed;
|
|
19
|
-
added: ObserveCallbacks["added"];
|
|
20
|
-
changed: ObserveCallbacks["changed"];
|
|
21
|
-
removed: ObserveCallbacks["removed"];
|
|
22
|
-
constructor(options: any);
|
|
23
|
-
addHandleAndSendInitialAdds(handle: ObserveHandle): Promise<void>;
|
|
24
|
-
removeHandle(id: number): void;
|
|
25
|
-
_stop(options?: any): void;
|
|
26
|
-
ready(): void;
|
|
27
|
-
queryError(err: Error): void;
|
|
28
|
-
onFlush(cb: any): void;
|
|
29
|
-
callbackNames(): string[];
|
|
30
|
-
_ready(): boolean;
|
|
31
|
-
_applyCallback(callbackName: string, args: any): Promise<void>;
|
|
32
|
-
}
|
|
33
|
-
export declare class ObserveHandle {
|
|
34
|
-
private _multiplexer;
|
|
35
|
-
nonMutatingCallbacks: boolean;
|
|
36
|
-
_id: number;
|
|
37
|
-
_initialAdds: ObserveCallbacks["initialAdds"];
|
|
38
|
-
_addedBefore: ObserveCallbacks["addedBefore"];
|
|
39
|
-
_movedBefore: ObserveCallbacks["movedBefore"];
|
|
40
|
-
_added: ObserveCallbacks["added"];
|
|
41
|
-
_changed: ObserveCallbacks["changed"];
|
|
42
|
-
_removed: ObserveCallbacks["removed"];
|
|
43
|
-
private _stopped;
|
|
44
|
-
constructor(_multiplexer: ObserveMultiplexer, callbacks: ObserveCallbacks, nonMutatingCallbacks?: boolean);
|
|
45
|
-
stop(): void;
|
|
46
|
-
}
|
|
1
|
+
import { OrderedDict } from "../ordered-dict/ordered_dict";
|
|
2
|
+
export interface ObserveCallbacks {
|
|
3
|
+
added: (id: string, fields: Record<string, any>) => void;
|
|
4
|
+
changed: (id: string, fields: Record<string, any>) => void;
|
|
5
|
+
removed: (id: string) => void;
|
|
6
|
+
addedBefore?: (id: string, fields: Record<string, any>, before?: any) => void;
|
|
7
|
+
movedBefore?: (id: string, fields: Record<string, any>, before?: any) => void;
|
|
8
|
+
initialAdds: (docs: Map<string, any> | OrderedDict) => void;
|
|
9
|
+
_testOnlyPollCallback?: any;
|
|
10
|
+
}
|
|
11
|
+
export declare class ObserveMultiplexer {
|
|
12
|
+
private _ordered;
|
|
13
|
+
private _onStop;
|
|
14
|
+
private _queue;
|
|
15
|
+
private _handles;
|
|
16
|
+
private _readyFuture;
|
|
17
|
+
private _cache;
|
|
18
|
+
private _addHandleTasksScheduledButNotPerformed;
|
|
19
|
+
added: ObserveCallbacks["added"];
|
|
20
|
+
changed: ObserveCallbacks["changed"];
|
|
21
|
+
removed: ObserveCallbacks["removed"];
|
|
22
|
+
constructor(options: any);
|
|
23
|
+
addHandleAndSendInitialAdds(handle: ObserveHandle): Promise<void>;
|
|
24
|
+
removeHandle(id: number): void;
|
|
25
|
+
_stop(options?: any): void;
|
|
26
|
+
ready(): void;
|
|
27
|
+
queryError(err: Error): void;
|
|
28
|
+
onFlush(cb: any): void;
|
|
29
|
+
callbackNames(): string[];
|
|
30
|
+
_ready(): boolean;
|
|
31
|
+
_applyCallback(callbackName: string, args: any): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export declare class ObserveHandle {
|
|
34
|
+
private _multiplexer;
|
|
35
|
+
nonMutatingCallbacks: boolean;
|
|
36
|
+
_id: number;
|
|
37
|
+
_initialAdds: ObserveCallbacks["initialAdds"];
|
|
38
|
+
_addedBefore: ObserveCallbacks["addedBefore"];
|
|
39
|
+
_movedBefore: ObserveCallbacks["movedBefore"];
|
|
40
|
+
_added: ObserveCallbacks["added"];
|
|
41
|
+
_changed: ObserveCallbacks["changed"];
|
|
42
|
+
_removed: ObserveCallbacks["removed"];
|
|
43
|
+
private _stopped;
|
|
44
|
+
constructor(_multiplexer: ObserveMultiplexer, callbacks: ObserveCallbacks, nonMutatingCallbacks?: boolean);
|
|
45
|
+
stop(): void;
|
|
46
|
+
}
|
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ObserveHandle = exports.ObserveMultiplexer = void 0;
|
|
4
|
-
const ejson_1 = require("../ejson/ejson");
|
|
5
|
-
const caching_change_observer_1 = require("./caching_change_observer");
|
|
6
|
-
const synchronous_queue_1 = require("./synchronous-queue");
|
|
7
|
-
class ObserveMultiplexer {
|
|
8
|
-
constructor(options) {
|
|
9
|
-
this._readyFuture = { isResolved: false };
|
|
10
|
-
var self = this;
|
|
11
|
-
if (!options || !options.hasOwnProperty('ordered'))
|
|
12
|
-
throw Error("must specify ordered");
|
|
13
|
-
self._ordered = options.ordered;
|
|
14
|
-
self._onStop = options.onStop || function () { };
|
|
15
|
-
self._queue = new synchronous_queue_1._SynchronousQueue();
|
|
16
|
-
self._handles = {};
|
|
17
|
-
self._readyFuture.promise = new Promise((resolve, reject) => {
|
|
18
|
-
self._readyFuture.resolve = resolve;
|
|
19
|
-
self._readyFuture.reject = reject;
|
|
20
|
-
});
|
|
21
|
-
self._cache = new caching_change_observer_1._CachingChangeObserver({ ordered: options.ordered });
|
|
22
|
-
// Number of addHandleAndSendInitialAdds tasks scheduled but not yet
|
|
23
|
-
// running. removeHandle uses this to know if it's time to call the onStop
|
|
24
|
-
// callback.
|
|
25
|
-
self._addHandleTasksScheduledButNotPerformed = 0;
|
|
26
|
-
for (const callbackName of self.callbackNames()) {
|
|
27
|
-
self[callbackName] = async function ( /* ... */) {
|
|
28
|
-
await self._applyCallback(callbackName, Array.from(arguments));
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async addHandleAndSendInitialAdds(handle) {
|
|
33
|
-
var self = this;
|
|
34
|
-
// Check this before calling runTask (even though runTask does the same
|
|
35
|
-
// check) so that we don't leak an ObserveMultiplexer on error by
|
|
36
|
-
// incrementing _addHandleTasksScheduledButNotPerformed and never
|
|
37
|
-
// decrementing it.
|
|
38
|
-
//if (!self._queue.safeToRunTask())
|
|
39
|
-
// throw new Error("Can't call observeChanges from an observe callback on the same query");
|
|
40
|
-
++self._addHandleTasksScheduledButNotPerformed;
|
|
41
|
-
await self._queue.runTask(async () => {
|
|
42
|
-
self._handles[handle._id] = handle;
|
|
43
|
-
if (this._ready() && this._cache.docs.size > 0)
|
|
44
|
-
handle._initialAdds(this._cache.docs);
|
|
45
|
-
--self._addHandleTasksScheduledButNotPerformed;
|
|
46
|
-
});
|
|
47
|
-
// *outside* the task, since otherwise we'd deadlock
|
|
48
|
-
await self._readyFuture.promise;
|
|
49
|
-
}
|
|
50
|
-
// Remove an observe handle. If it was the last observe handle, call the
|
|
51
|
-
// onStop callback; you cannot add any more observe handles after this.
|
|
52
|
-
//
|
|
53
|
-
// This is not synchronized with polls and handle additions: this means that
|
|
54
|
-
// you can safely call it from within an observe callback, but it also means
|
|
55
|
-
// that we have to be careful when we iterate over _handles.
|
|
56
|
-
removeHandle(id) {
|
|
57
|
-
var self = this;
|
|
58
|
-
// This should not be possible: you can only call removeHandle by having
|
|
59
|
-
// access to the ObserveHandle, which isn't returned to user code until the
|
|
60
|
-
// multiplex is ready.
|
|
61
|
-
if (!self._ready())
|
|
62
|
-
throw new Error("Can't remove handles until the multiplex is ready");
|
|
63
|
-
delete self._handles[id];
|
|
64
|
-
if (Object.keys(self._handles).length === 0 && self._addHandleTasksScheduledButNotPerformed === 0) {
|
|
65
|
-
self._stop();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
_stop(options) {
|
|
69
|
-
const self = this;
|
|
70
|
-
options = options || {};
|
|
71
|
-
// It shouldn't be possible for us to stop when all our handles still
|
|
72
|
-
// haven't been returned from observeChanges!
|
|
73
|
-
if (!self._ready() && !options.fromQueryError)
|
|
74
|
-
throw Error("surprising _stop: not ready");
|
|
75
|
-
// Call stop callback (which kills the underlying process which sends us
|
|
76
|
-
// callbacks and removes us from the connection's dictionary).
|
|
77
|
-
self._onStop();
|
|
78
|
-
// Cause future addHandleAndSendInitialAdds calls to throw (but the onStop
|
|
79
|
-
// callback should make our connection forget about us).
|
|
80
|
-
self._handles = null;
|
|
81
|
-
}
|
|
82
|
-
// Allows all addHandleAndSendInitialAdds calls to return, once all preceding
|
|
83
|
-
// adds have been processed. Does not block.
|
|
84
|
-
ready() {
|
|
85
|
-
this._queue.queueTask(async () => {
|
|
86
|
-
if (this._ready())
|
|
87
|
-
throw Error("can't make ObserveMultiplex ready twice!");
|
|
88
|
-
if (this._cache.docs.size > 0) {
|
|
89
|
-
for (const handleId of Object.keys(this._handles)) {
|
|
90
|
-
var handle = this._handles && this._handles[handleId];
|
|
91
|
-
if (handle)
|
|
92
|
-
handle._initialAdds(this._cache.docs);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
this._readyFuture.resolve();
|
|
96
|
-
this._readyFuture.isResolved = true;
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
// If trying to execute the query results in an error, call this. This is
|
|
100
|
-
// intended for permanent errors, not transient network errors that could be
|
|
101
|
-
// fixed. It should only be called before ready(), because if you called ready
|
|
102
|
-
// that meant that you managed to run the query once. It will stop this
|
|
103
|
-
// ObserveMultiplex and cause addHandleAndSendInitialAdds calls (and thus
|
|
104
|
-
// observeChanges calls) to throw the error.
|
|
105
|
-
queryError(err) {
|
|
106
|
-
var self = this;
|
|
107
|
-
self._queue.runTask(async () => {
|
|
108
|
-
if (self._ready())
|
|
109
|
-
throw Error("can't claim query has an error after it worked!");
|
|
110
|
-
self._stop({ fromQueryError: true });
|
|
111
|
-
self._readyFuture.reject(err);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
// Calls "cb" once the effects of all "ready", "addHandleAndSendInitialAdds"
|
|
115
|
-
// and observe callbacks which came before this call have been propagated to
|
|
116
|
-
// all handles. "ready" must have already been called on this multiplexer.
|
|
117
|
-
onFlush(cb) {
|
|
118
|
-
var self = this;
|
|
119
|
-
self._queue.queueTask(async () => {
|
|
120
|
-
if (!self._ready())
|
|
121
|
-
throw Error("only call onFlush on a multiplexer that will be ready");
|
|
122
|
-
cb();
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
callbackNames() {
|
|
126
|
-
var self = this;
|
|
127
|
-
if (self._ordered)
|
|
128
|
-
return ["initialAdds", "addedBefore", "changed", "movedBefore", "removed"];
|
|
129
|
-
else
|
|
130
|
-
return ["initialAdds", "added", "changed", "removed"];
|
|
131
|
-
}
|
|
132
|
-
_ready() {
|
|
133
|
-
return this._readyFuture.isResolved;
|
|
134
|
-
}
|
|
135
|
-
async _applyCallback(callbackName, args) {
|
|
136
|
-
var self = this;
|
|
137
|
-
self._queue.queueTask(async () => {
|
|
138
|
-
// If we stopped in the meantime, do nothing.
|
|
139
|
-
if (!self._handles)
|
|
140
|
-
return;
|
|
141
|
-
// First, apply the change to the cache.
|
|
142
|
-
self._cache.applyChange[callbackName].apply(null, args);
|
|
143
|
-
// If we haven't finished the initial adds, then we should only be getting
|
|
144
|
-
// adds.
|
|
145
|
-
if (!self._ready() &&
|
|
146
|
-
(callbackName !== 'added' && callbackName !== 'addedBefore')) {
|
|
147
|
-
throw new Error("Got " + callbackName + " during initial adds");
|
|
148
|
-
}
|
|
149
|
-
// don't actually send anything to the handles until initial adds are cached
|
|
150
|
-
if (!self._ready())
|
|
151
|
-
return;
|
|
152
|
-
// Now multiplex the callbacks out to all observe handles. It's OK if
|
|
153
|
-
// these calls yield; since we're inside a task, no other use of our queue
|
|
154
|
-
// can continue until these are done. (But we do have to be careful to not
|
|
155
|
-
// use a handle that got removed, because removeHandle does not use the
|
|
156
|
-
// queue; thus, we iterate over an array of keys that we control.)
|
|
157
|
-
for (const handleId of Object.keys(self._handles)) {
|
|
158
|
-
var handle = self._handles && self._handles[handleId];
|
|
159
|
-
if (!handle)
|
|
160
|
-
return;
|
|
161
|
-
var callback = handle['_' + callbackName];
|
|
162
|
-
// clone arguments so that callbacks can mutate their arguments
|
|
163
|
-
callback && callback.apply(null, handle.nonMutatingCallbacks ? args : (0, ejson_1.clone)(args));
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
exports.ObserveMultiplexer = ObserveMultiplexer;
|
|
169
|
-
let nextObserveHandleId = 1;
|
|
170
|
-
// When the callbacks do not mutate the arguments, we can skip a lot of data clones
|
|
171
|
-
class ObserveHandle {
|
|
172
|
-
constructor(_multiplexer, callbacks, nonMutatingCallbacks = false) {
|
|
173
|
-
this._multiplexer = _multiplexer;
|
|
174
|
-
this.nonMutatingCallbacks = nonMutatingCallbacks;
|
|
175
|
-
var self = this;
|
|
176
|
-
// The end user is only supposed to call stop(). The other fields are
|
|
177
|
-
// accessible to the multiplexer, though.
|
|
178
|
-
for (const name of _multiplexer.callbackNames()) {
|
|
179
|
-
if (callbacks[name]) {
|
|
180
|
-
self['_' + name] = callbacks[name];
|
|
181
|
-
}
|
|
182
|
-
else if (name === "addedBefore" && callbacks.added) {
|
|
183
|
-
// Special case: if you specify "added" and "movedBefore", you get an
|
|
184
|
-
// ordered observe where for some reason you don't get ordering data on
|
|
185
|
-
// the adds. I dunno, we wrote tests for it, there must have been a
|
|
186
|
-
// reason.
|
|
187
|
-
self._addedBefore = function (id, fields, before) {
|
|
188
|
-
callbacks.added(id, fields);
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
self._stopped = false;
|
|
193
|
-
self._id = nextObserveHandleId++;
|
|
194
|
-
}
|
|
195
|
-
stop() {
|
|
196
|
-
var self = this;
|
|
197
|
-
if (self._stopped)
|
|
198
|
-
return;
|
|
199
|
-
self._stopped = true;
|
|
200
|
-
self._multiplexer.removeHandle(self._id);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
exports.ObserveHandle = ObserveHandle;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ObserveHandle = exports.ObserveMultiplexer = void 0;
|
|
4
|
+
const ejson_1 = require("../ejson/ejson");
|
|
5
|
+
const caching_change_observer_1 = require("./caching_change_observer");
|
|
6
|
+
const synchronous_queue_1 = require("./synchronous-queue");
|
|
7
|
+
class ObserveMultiplexer {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this._readyFuture = { isResolved: false };
|
|
10
|
+
var self = this;
|
|
11
|
+
if (!options || !options.hasOwnProperty('ordered'))
|
|
12
|
+
throw Error("must specify ordered");
|
|
13
|
+
self._ordered = options.ordered;
|
|
14
|
+
self._onStop = options.onStop || function () { };
|
|
15
|
+
self._queue = new synchronous_queue_1._SynchronousQueue();
|
|
16
|
+
self._handles = {};
|
|
17
|
+
self._readyFuture.promise = new Promise((resolve, reject) => {
|
|
18
|
+
self._readyFuture.resolve = resolve;
|
|
19
|
+
self._readyFuture.reject = reject;
|
|
20
|
+
});
|
|
21
|
+
self._cache = new caching_change_observer_1._CachingChangeObserver({ ordered: options.ordered });
|
|
22
|
+
// Number of addHandleAndSendInitialAdds tasks scheduled but not yet
|
|
23
|
+
// running. removeHandle uses this to know if it's time to call the onStop
|
|
24
|
+
// callback.
|
|
25
|
+
self._addHandleTasksScheduledButNotPerformed = 0;
|
|
26
|
+
for (const callbackName of self.callbackNames()) {
|
|
27
|
+
self[callbackName] = async function ( /* ... */) {
|
|
28
|
+
await self._applyCallback(callbackName, Array.from(arguments));
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async addHandleAndSendInitialAdds(handle) {
|
|
33
|
+
var self = this;
|
|
34
|
+
// Check this before calling runTask (even though runTask does the same
|
|
35
|
+
// check) so that we don't leak an ObserveMultiplexer on error by
|
|
36
|
+
// incrementing _addHandleTasksScheduledButNotPerformed and never
|
|
37
|
+
// decrementing it.
|
|
38
|
+
//if (!self._queue.safeToRunTask())
|
|
39
|
+
// throw new Error("Can't call observeChanges from an observe callback on the same query");
|
|
40
|
+
++self._addHandleTasksScheduledButNotPerformed;
|
|
41
|
+
await self._queue.runTask(async () => {
|
|
42
|
+
self._handles[handle._id] = handle;
|
|
43
|
+
if (this._ready() && this._cache.docs.size > 0)
|
|
44
|
+
handle._initialAdds(this._cache.docs);
|
|
45
|
+
--self._addHandleTasksScheduledButNotPerformed;
|
|
46
|
+
});
|
|
47
|
+
// *outside* the task, since otherwise we'd deadlock
|
|
48
|
+
await self._readyFuture.promise;
|
|
49
|
+
}
|
|
50
|
+
// Remove an observe handle. If it was the last observe handle, call the
|
|
51
|
+
// onStop callback; you cannot add any more observe handles after this.
|
|
52
|
+
//
|
|
53
|
+
// This is not synchronized with polls and handle additions: this means that
|
|
54
|
+
// you can safely call it from within an observe callback, but it also means
|
|
55
|
+
// that we have to be careful when we iterate over _handles.
|
|
56
|
+
removeHandle(id) {
|
|
57
|
+
var self = this;
|
|
58
|
+
// This should not be possible: you can only call removeHandle by having
|
|
59
|
+
// access to the ObserveHandle, which isn't returned to user code until the
|
|
60
|
+
// multiplex is ready.
|
|
61
|
+
if (!self._ready())
|
|
62
|
+
throw new Error("Can't remove handles until the multiplex is ready");
|
|
63
|
+
delete self._handles[id];
|
|
64
|
+
if (Object.keys(self._handles).length === 0 && self._addHandleTasksScheduledButNotPerformed === 0) {
|
|
65
|
+
self._stop();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
_stop(options) {
|
|
69
|
+
const self = this;
|
|
70
|
+
options = options || {};
|
|
71
|
+
// It shouldn't be possible for us to stop when all our handles still
|
|
72
|
+
// haven't been returned from observeChanges!
|
|
73
|
+
if (!self._ready() && !options.fromQueryError)
|
|
74
|
+
throw Error("surprising _stop: not ready");
|
|
75
|
+
// Call stop callback (which kills the underlying process which sends us
|
|
76
|
+
// callbacks and removes us from the connection's dictionary).
|
|
77
|
+
self._onStop();
|
|
78
|
+
// Cause future addHandleAndSendInitialAdds calls to throw (but the onStop
|
|
79
|
+
// callback should make our connection forget about us).
|
|
80
|
+
self._handles = null;
|
|
81
|
+
}
|
|
82
|
+
// Allows all addHandleAndSendInitialAdds calls to return, once all preceding
|
|
83
|
+
// adds have been processed. Does not block.
|
|
84
|
+
ready() {
|
|
85
|
+
this._queue.queueTask(async () => {
|
|
86
|
+
if (this._ready())
|
|
87
|
+
throw Error("can't make ObserveMultiplex ready twice!");
|
|
88
|
+
if (this._cache.docs.size > 0) {
|
|
89
|
+
for (const handleId of Object.keys(this._handles)) {
|
|
90
|
+
var handle = this._handles && this._handles[handleId];
|
|
91
|
+
if (handle)
|
|
92
|
+
handle._initialAdds(this._cache.docs);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
this._readyFuture.resolve();
|
|
96
|
+
this._readyFuture.isResolved = true;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// If trying to execute the query results in an error, call this. This is
|
|
100
|
+
// intended for permanent errors, not transient network errors that could be
|
|
101
|
+
// fixed. It should only be called before ready(), because if you called ready
|
|
102
|
+
// that meant that you managed to run the query once. It will stop this
|
|
103
|
+
// ObserveMultiplex and cause addHandleAndSendInitialAdds calls (and thus
|
|
104
|
+
// observeChanges calls) to throw the error.
|
|
105
|
+
queryError(err) {
|
|
106
|
+
var self = this;
|
|
107
|
+
self._queue.runTask(async () => {
|
|
108
|
+
if (self._ready())
|
|
109
|
+
throw Error("can't claim query has an error after it worked!");
|
|
110
|
+
self._stop({ fromQueryError: true });
|
|
111
|
+
self._readyFuture.reject(err);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// Calls "cb" once the effects of all "ready", "addHandleAndSendInitialAdds"
|
|
115
|
+
// and observe callbacks which came before this call have been propagated to
|
|
116
|
+
// all handles. "ready" must have already been called on this multiplexer.
|
|
117
|
+
onFlush(cb) {
|
|
118
|
+
var self = this;
|
|
119
|
+
self._queue.queueTask(async () => {
|
|
120
|
+
if (!self._ready())
|
|
121
|
+
throw Error("only call onFlush on a multiplexer that will be ready");
|
|
122
|
+
cb();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
callbackNames() {
|
|
126
|
+
var self = this;
|
|
127
|
+
if (self._ordered)
|
|
128
|
+
return ["initialAdds", "addedBefore", "changed", "movedBefore", "removed"];
|
|
129
|
+
else
|
|
130
|
+
return ["initialAdds", "added", "changed", "removed"];
|
|
131
|
+
}
|
|
132
|
+
_ready() {
|
|
133
|
+
return this._readyFuture.isResolved;
|
|
134
|
+
}
|
|
135
|
+
async _applyCallback(callbackName, args) {
|
|
136
|
+
var self = this;
|
|
137
|
+
self._queue.queueTask(async () => {
|
|
138
|
+
// If we stopped in the meantime, do nothing.
|
|
139
|
+
if (!self._handles)
|
|
140
|
+
return;
|
|
141
|
+
// First, apply the change to the cache.
|
|
142
|
+
self._cache.applyChange[callbackName].apply(null, args);
|
|
143
|
+
// If we haven't finished the initial adds, then we should only be getting
|
|
144
|
+
// adds.
|
|
145
|
+
if (!self._ready() &&
|
|
146
|
+
(callbackName !== 'added' && callbackName !== 'addedBefore')) {
|
|
147
|
+
throw new Error("Got " + callbackName + " during initial adds");
|
|
148
|
+
}
|
|
149
|
+
// don't actually send anything to the handles until initial adds are cached
|
|
150
|
+
if (!self._ready())
|
|
151
|
+
return;
|
|
152
|
+
// Now multiplex the callbacks out to all observe handles. It's OK if
|
|
153
|
+
// these calls yield; since we're inside a task, no other use of our queue
|
|
154
|
+
// can continue until these are done. (But we do have to be careful to not
|
|
155
|
+
// use a handle that got removed, because removeHandle does not use the
|
|
156
|
+
// queue; thus, we iterate over an array of keys that we control.)
|
|
157
|
+
for (const handleId of Object.keys(self._handles)) {
|
|
158
|
+
var handle = self._handles && self._handles[handleId];
|
|
159
|
+
if (!handle)
|
|
160
|
+
return;
|
|
161
|
+
var callback = handle['_' + callbackName];
|
|
162
|
+
// clone arguments so that callbacks can mutate their arguments
|
|
163
|
+
callback && callback.apply(null, handle.nonMutatingCallbacks ? args : (0, ejson_1.clone)(args));
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.ObserveMultiplexer = ObserveMultiplexer;
|
|
169
|
+
let nextObserveHandleId = 1;
|
|
170
|
+
// When the callbacks do not mutate the arguments, we can skip a lot of data clones
|
|
171
|
+
class ObserveHandle {
|
|
172
|
+
constructor(_multiplexer, callbacks, nonMutatingCallbacks = false) {
|
|
173
|
+
this._multiplexer = _multiplexer;
|
|
174
|
+
this.nonMutatingCallbacks = nonMutatingCallbacks;
|
|
175
|
+
var self = this;
|
|
176
|
+
// The end user is only supposed to call stop(). The other fields are
|
|
177
|
+
// accessible to the multiplexer, though.
|
|
178
|
+
for (const name of _multiplexer.callbackNames()) {
|
|
179
|
+
if (callbacks[name]) {
|
|
180
|
+
self['_' + name] = callbacks[name];
|
|
181
|
+
}
|
|
182
|
+
else if (name === "addedBefore" && callbacks.added) {
|
|
183
|
+
// Special case: if you specify "added" and "movedBefore", you get an
|
|
184
|
+
// ordered observe where for some reason you don't get ordering data on
|
|
185
|
+
// the adds. I dunno, we wrote tests for it, there must have been a
|
|
186
|
+
// reason.
|
|
187
|
+
self._addedBefore = function (id, fields, before) {
|
|
188
|
+
callbacks.added(id, fields);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
self._stopped = false;
|
|
193
|
+
self._id = nextObserveHandleId++;
|
|
194
|
+
}
|
|
195
|
+
stop() {
|
|
196
|
+
var self = this;
|
|
197
|
+
if (self._stopped)
|
|
198
|
+
return;
|
|
199
|
+
self._stopped = true;
|
|
200
|
+
self._multiplexer.removeHandle(self._id);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.ObserveHandle = ObserveHandle;
|