-
Notifications
You must be signed in to change notification settings - Fork 48
/
SubscriptionManager.js
73 lines (67 loc) · 2.25 KB
/
SubscriptionManager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import {QueryState} from './QueryState';
// SubscriptionManager tracks active QueryStates, so that two components that
// have identical queries can share a QueryState rather than initiating
// redundant database queries.
//
// The constructor takes a runQuery function from the Session. The subscribe
// method registers a component with a new QueryRequest and an QueryResult
// to write the results into. It returns an object with an unsubscribe() method
// to be called when the component is no longer interested in that
// QueryRequest.
export class SubscriptionManager {
constructor(runQuery) {
this.runQuery = runQuery;
this.queryKeyToState = {};
this.doneLoadingCallbacks = [];
this.connected = false;
}
handleConnect() {
this.connected = true;
Object.keys(this.queryKeyToState).forEach(queryKey => {
const queryState = this.queryKeyToState[queryKey];
queryState.handleConnect();
});
}
handleDisconnect() {
this.connected = false;
}
subscribe(component, queryRequest, queryResult) {
const queryKey = queryRequest.toStringKey();
let queryState = this.queryKeyToState[queryKey];
if (!queryState) {
const onUpdate = () => this._checkDoneLoading();
const onCloseQueryState = () => {
delete this.queryKeyToState[queryKey];
};
queryState = new QueryState(queryRequest, this.runQuery,
onUpdate, onCloseQueryState);
if (this.connected) {
queryState.handleConnect();
}
this.queryKeyToState[queryKey] = queryState;
}
const subscription = queryState.subscribe(component, queryResult);
return {
unsubscribe: subscription.unsubscribe,
};
}
onceDoneLoading(callback) {
this.doneLoadingCallbacks.push(callback);
this._checkDoneLoading();
}
_checkDoneLoading() {
if (this.doneLoadingCallbacks.length) {
let anyLoading = false;
Object.keys(this.queryKeyToState).forEach(queryKey => {
const queryState = this.queryKeyToState[queryKey];
if (queryState.loading && !queryState.errors.length) {
anyLoading = true;
}
});
if (!anyLoading) {
this.doneLoadingCallbacks.forEach(cb => cb());
this.doneLoadingCallbacks = [];
}
}
}
}