| 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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 |
1x
1x
1x
144x
72x
72x
72x
72x
72x
72x
288x
72x
72x
72x
72x
72x
72x
65x
65x
65x
65x
61x
65x
65x
65x
65x
65x
65x
65x
65x
65x
65x
65x
65x
77x
77x
12x
12x
12x
12x
12x
12x
12x
12x
12x
77x
77x
77x
77x
77x
257x
77x
45x
77x
18x
12x
6x
4x
18x
59x
12x
47x
47x
47x
47x
67x
67x
67x
67x
1x
1x
1x
1x
1x
154x
77x
257x
45x
32x
|
import EventEmitter from 'component-emitter';
import makeDebug from 'debug';
const debug = makeDebug('base-engine');
export default class BaseEngine {
constructor (service, options = {}) {
debug('constructor entered');
this._service = service;
this._publication = options.publication;
this._subscriber = options.subscriber || (() => {});
this._sorter = options.sort;
this._eventEmitter = new EventEmitter();
this._listener = eventName => remoteRecord => this._mutateStore(
eventName, remoteRecord, 0
);
this._eventListeners = {
created: this._listener('created'),
updated: this._listener('updated'),
patched: this._listener('patched'),
removed: this._listener('removed')
};
this.useUuid = options.uuid;
this.emit = this._eventEmitter.emit;
this.on = this._eventEmitter.on;
this.listening = false;
this.store = {
last: { eventName: '', action: '', record: {} },
records: []
};
}
snapshot (records) {
debug('snapshot entered');
this.store.last = { action: 'snapshot' };
this.store.records = records;
if (this._sorter) {
records.sort(this._sorter);
}
this.emit('events', this.store.records, this.store.last);
this._subscriber(this.store.records, this.store.last);
}
addListeners () {
debug('addListeners entered');
const service = this._service;
const eventListeners = this._eventListeners;
service.on('created', eventListeners.created);
service.on('updated', eventListeners.updated);
service.on('patched', eventListeners.patched);
service.on('removed', eventListeners.removed);
this.listening = true;
this.emit('events', this.store.records, { action: 'add-listeners' });
this._subscriber(this.store.records, { action: 'add-listeners' });
}
removeListeners () {
debug('removeListeners entered');
if (this.listening) {
const service = this._service;
const eventListeners = this._eventListeners;
service.removeListener('created', eventListeners.created);
service.removeListener('updated', eventListeners.updated);
service.removeListener('patched', eventListeners.patched);
service.removeListener('removed', eventListeners.removed);
this.listening = false;
this.emit('events', this.store.records, { action: 'remove-listeners' });
this._subscriber(this.store.records, { action: 'remove-listeners' });
}
}
_mutateStore (eventName, remoteRecord, source) {
debug(`_mutateStore started: ${eventName}`);
const that = this;
const idName = this._useUuid ? 'uuid' : ('id' in remoteRecord ? 'id' : '_id');
const store = this.store;
const records = store.records;
const index = this._findIndex(records, record => record[idName] === remoteRecord[idName]);
if (index >= 0) {
records.splice(index, 1);
}
if (eventName === 'removed') {
if (index >= 0) {
broadcast('remove');
} else if (source === 0 && (!this._publication || this._publication(remoteRecord))) {
// Emit service event if it corresponds to a previous optimistic remove
broadcast('remove');
}
return; // index >= 0 ? broadcast('remove') : undefined;
}
if (this._publication && !this._publication(remoteRecord)) {
return index >= 0 ? broadcast('left-pub') : undefined;
}
records[records.length] = remoteRecord;
Eif (this._sorter) {
records.sort(this._sorter);
}
return broadcast('mutated');
function broadcast (action) {
debug(`emitted ${index} ${eventName} ${action}`);
store.last = { source, action, eventName, record: remoteRecord };
that.emit('events', records, store.last);
that._subscriber(records, store.last);
}
}
changeSort (sort) {
this._sorter = sort;
Eif (this._sorter) {
this.store.records.sort(this._sorter);
}
this.emit('events', this.store.records, { action: 'change-sort' });
this._subscriber(this.store.records, { action: 'change-sort' });
}
_findIndex (array, predicate = () => true, fromIndex = 0) {
for (let i = fromIndex, len = array.length; i < len; i++) {
if (predicate(array[i])) {
return i;
}
}
return -1;
}
}
|