UNPKG

14.9 kBJavaScriptView Raw
1'use strict';
2
3var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
4
5var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
6
7var _inherits2 = require('babel-runtime/helpers/inherits');
8
9var _inherits3 = _interopRequireDefault(_inherits2);
10
11var _typeof2 = require('babel-runtime/helpers/typeof');
12
13var _typeof3 = _interopRequireDefault(_typeof2);
14
15var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
16
17var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
18
19var _Observable = require('rxjs/Observable');
20
21var _empty = require('rxjs/observable/empty');
22
23var _publishReplay = require('rxjs/operator/publishReplay');
24
25var _scan = require('rxjs/operator/scan');
26
27var _filter = require('rxjs/operator/filter');
28
29var _map = require('rxjs/operator/map');
30
31var _snakeCase = require('snake-case');
32
33var _snakeCase2 = _interopRequireDefault(_snakeCase);
34
35var _checkArgs = require('./util/check-args');
36
37var _checkArgs2 = _interopRequireDefault(_checkArgs);
38
39var _validIndexValue = require('./util/valid-index-value.js');
40
41var _validIndexValue2 = _interopRequireDefault(_validIndexValue);
42
43var _serialization = require('./serialization.js');
44
45function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
46
47/**
48 @this TermBase
49
50 Validation check to throw an exception if a method is chained onto a
51 query that already has it. It belongs to TermBase, but we don't want
52 to pollute the objects with it (since it isn't useful to api users),
53 so it's dynamically bound with :: inside methods that use it.
54*/
55function checkIfLegalToChain(key) {
56 if (this._legalMethods.indexOf(key) === -1) {
57 throw new Error(key + ' cannot be called on the current query');
58 }
59 if ((0, _snakeCase2.default)(key) in this._query) {
60 throw new Error(key + ' has already been called on this query');
61 }
62}
63
64// Abstract base class for terms
65
66var TermBase = function () {
67 function TermBase(sendRequest, query, legalMethods) {
68 (0, _classCallCheck3.default)(this, TermBase);
69
70 this._sendRequest = sendRequest;
71 this._query = query;
72 this._legalMethods = legalMethods;
73 }
74 // Returns a sequence of the result set. Every time it changes the
75 // updated sequence will be emitted. If raw change objects are
76 // needed, pass the option 'rawChanges: true'. An observable is
77 // returned which will lazily emit the query when it is subscribed
78 // to
79
80
81 TermBase.prototype.watch = function watch() {
82 var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
83
84 var _ref$rawChanges = _ref.rawChanges;
85 var rawChanges = _ref$rawChanges === undefined ? false : _ref$rawChanges;
86
87 var raw = this._sendRequest('subscribe', this._query);
88 if (rawChanges) {
89 return raw;
90 } else {
91 return makePresentable(raw, this._query);
92 }
93 };
94 // Grab a snapshot of the current query (non-changefeed). Emits an
95 // array with all results. An observable is returned which will
96 // lazily emit the query when subscribed to
97
98
99 TermBase.prototype.fetch = function fetch() {
100 return this._sendRequest('query', this._query);
101 };
102
103 TermBase.prototype.findAll = function findAll() {
104 for (var _len = arguments.length, fieldValues = Array(_len), _key = 0; _key < _len; _key++) {
105 fieldValues[_key] = arguments[_key];
106 }
107
108 checkIfLegalToChain.call(this, 'findAll');
109 (0, _checkArgs2.default)('findAll', arguments, { maxArgs: 100 });
110 return new FindAll(this._sendRequest, this._query, fieldValues);
111 };
112
113 TermBase.prototype.find = function find(idOrObject) {
114 checkIfLegalToChain.call(this, 'find');
115 (0, _checkArgs2.default)('find', arguments);
116 return new Find(this._sendRequest, this._query, idOrObject);
117 };
118
119 TermBase.prototype.order = function order(fields) {
120 var direction = arguments.length <= 1 || arguments[1] === undefined ? 'ascending' : arguments[1];
121
122 checkIfLegalToChain.call(this, 'order');
123 (0, _checkArgs2.default)('order', arguments, { minArgs: 1, maxArgs: 2 });
124 return new Order(this._sendRequest, this._query, fields, direction);
125 };
126
127 TermBase.prototype.above = function above(aboveSpec) {
128 var bound = arguments.length <= 1 || arguments[1] === undefined ? 'closed' : arguments[1];
129
130 checkIfLegalToChain.call(this, 'above');
131 (0, _checkArgs2.default)('above', arguments, { minArgs: 1, maxArgs: 2 });
132 return new Above(this._sendRequest, this._query, aboveSpec, bound);
133 };
134
135 TermBase.prototype.below = function below(belowSpec) {
136 var bound = arguments.length <= 1 || arguments[1] === undefined ? 'open' : arguments[1];
137
138 checkIfLegalToChain.call(this, 'below');
139 (0, _checkArgs2.default)('below', arguments, { minArgs: 1, maxArgs: 2 });
140 return new Below(this._sendRequest, this._query, belowSpec, bound);
141 };
142
143 TermBase.prototype.limit = function limit(size) {
144 checkIfLegalToChain.call(this, 'limit');
145 (0, _checkArgs2.default)('limit', arguments);
146 return new Limit(this._sendRequest, this._query, size);
147 };
148
149 return TermBase;
150}();
151
152// Turn a raw observable of server responses into user-presentable events
153//
154// `observable` is the base observable with full responses coming from
155// the HorizonSocket
156// `query` is the value of `options` in the request
157
158
159function makePresentable(observable, query) {
160 // Whether the entire data structure is in each change
161 var pointQuery = Boolean(query.find);
162
163 if (pointQuery) {
164 var _ret = function () {
165 var _context;
166
167 var hasEmitted = false;
168 var seedVal = null;
169 // Simplest case: just pass through new_val
170 return {
171 v: (_context = _filter.filter.call(observable, function (change) {
172 return !hasEmitted || change.type !== 'state';
173 }), _scan.scan).call(_context, function (previous, change) {
174 hasEmitted = true;
175 if (change.state === 'synced') {
176 return previous;
177 } else {
178 return change.new_val;
179 }
180 }, seedVal)
181 };
182 }();
183
184 if ((typeof _ret === 'undefined' ? 'undefined' : (0, _typeof3.default)(_ret)) === "object") return _ret.v;
185 } else {
186 var _context2;
187
188 var _seedVal = { emitted: false, val: [] };
189 return (_context2 = (_context2 = _scan.scan.call(observable, function (state, change) {
190 if (change.state === 'synced') {
191 state.emitted = true;
192 }
193 state.val = applyChange(state.val.slice(), change);
194 return state;
195 }, _seedVal), _filter.filter).call(_context2, function (state) {
196 return state.emitted;
197 }), _map.map).call(_context2, function (x) {
198 return x.val;
199 });
200 }
201}
202
203function applyChange(arr, change) {
204 switch (change.type) {
205 case 'remove':
206 case 'uninitial':
207 {
208 // Remove old values from the array
209 if (change.old_offset != null) {
210 arr.splice(change.old_offset, 1);
211 } else {
212 var index = arr.findIndex(function (x) {
213 return x.id === change.old_val.id;
214 });
215 arr.splice(index, 1);
216 }
217 break;
218 }
219 case 'add':
220 case 'initial':
221 {
222 // Add new values to the array
223 if (change.new_offset != null) {
224 // If we have an offset, put it in the correct location
225 arr.splice(change.new_offset, 0, change.new_val);
226 } else {
227 // otherwise for unordered results, push it on the end
228 arr.push(change.new_val);
229 }
230 break;
231 }
232 case 'change':
233 {
234 // Modify in place if a change is happening
235 if (change.old_offset != null) {
236 // Remove the old document from the results
237 arr.splice(change.old_offset, 1);
238 }
239 if (change.new_offset != null) {
240 // Splice in the new val if we have an offset
241 arr.splice(change.new_offset, 0, change.new_val);
242 } else {
243 // If we don't have an offset, find the old val and
244 // replace it with the new val
245 var _index = arr.findIndex(function (x) {
246 return x.id === change.old_val.id;
247 });
248 arr[_index] = change.new_val;
249 }
250 break;
251 }
252 case 'state':
253 {
254 // This gets hit if we have not emitted yet, and should
255 // result in an empty array being output.
256 break;
257 }
258 default:
259 throw new Error('unrecognized \'type\' field from server ' + JSON.stringify(change));
260 }
261 return arr;
262}
263
264/** @this Collection
265 Implements writeOps for the Collection class
266*/
267function writeOp(name, args, documents) {
268 (0, _checkArgs2.default)(name, args);
269 var wrappedDocs = documents;
270 if (!Array.isArray(documents)) {
271 // Wrap in an array if we need to
272 wrappedDocs = [documents];
273 } else if (documents.length === 0) {
274 // Don't bother sending no-ops to the server
275 return _empty.empty.call(_Observable.Observable);
276 }
277 var options = Object.assign({}, this._query, { data: (0, _serialization.serialize)(wrappedDocs) });
278 var observable = this._sendRequest(name, options);
279 if (!this._lazyWrites) {
280 var _context3;
281
282 // Need to buffer response since this becomes a hot observable and
283 // when we subscribe matters
284 observable = (_context3 = observable, _publishReplay.publishReplay).call(_context3).refCount();
285 observable.subscribe();
286 }
287 return observable;
288}
289
290var Collection = function (_TermBase) {
291 (0, _inherits3.default)(Collection, _TermBase);
292
293 function Collection(sendRequest, collectionName, lazyWrites) {
294 (0, _classCallCheck3.default)(this, Collection);
295
296 var query = { collection: collectionName };
297 var legalMethods = ['find', 'findAll', 'justInitial', 'order', 'above', 'below', 'limit'];
298
299 var _this = (0, _possibleConstructorReturn3.default)(this, _TermBase.call(this, sendRequest, query, legalMethods));
300
301 _this._lazyWrites = lazyWrites;
302 return _this;
303 }
304
305 Collection.prototype.store = function store(documents) {
306 return writeOp.call(this, 'store', arguments, documents);
307 };
308
309 Collection.prototype.upsert = function upsert(documents) {
310 return writeOp.call(this, 'upsert', arguments, documents);
311 };
312
313 Collection.prototype.insert = function insert(documents) {
314 return writeOp.call(this, 'insert', arguments, documents);
315 };
316
317 Collection.prototype.replace = function replace(documents) {
318 return writeOp.call(this, 'replace', arguments, documents);
319 };
320
321 Collection.prototype.update = function update(documents) {
322 return writeOp.call(this, 'update', arguments, documents);
323 };
324
325 Collection.prototype.remove = function remove(documentOrId) {
326 var wrapped = (0, _validIndexValue2.default)(documentOrId) ? { id: documentOrId } : documentOrId;
327 return writeOp.call(this, 'remove', arguments, wrapped);
328 };
329
330 Collection.prototype.removeAll = function removeAll(documentsOrIds) {
331 if (!Array.isArray(documentsOrIds)) {
332 throw new Error('removeAll takes an array as an argument');
333 }
334 var wrapped = documentsOrIds.map(function (item) {
335 if ((0, _validIndexValue2.default)(item)) {
336 return { id: item };
337 } else {
338 return item;
339 }
340 });
341 return writeOp.call(this, 'removeAll', arguments, wrapped);
342 };
343
344 return Collection;
345}(TermBase);
346
347var Find = function (_TermBase2) {
348 (0, _inherits3.default)(Find, _TermBase2);
349
350 function Find(sendRequest, previousQuery, idOrObject) {
351 (0, _classCallCheck3.default)(this, Find);
352
353 var findObject = (0, _validIndexValue2.default)(idOrObject) ? { id: idOrObject } : idOrObject;
354 var query = Object.assign({}, previousQuery, { find: findObject });
355 return (0, _possibleConstructorReturn3.default)(this, _TermBase2.call(this, sendRequest, query, []));
356 }
357
358 return Find;
359}(TermBase);
360
361var FindAll = function (_TermBase3) {
362 (0, _inherits3.default)(FindAll, _TermBase3);
363
364 function FindAll(sendRequest, previousQuery, fieldValues) {
365 (0, _classCallCheck3.default)(this, FindAll);
366
367 var wrappedFields = fieldValues.map(function (item) {
368 return (0, _validIndexValue2.default)(item) ? { id: item } : item;
369 });
370 var options = { find_all: wrappedFields };
371 var findAllQuery = Object.assign({}, previousQuery, options);
372 var legalMethods = void 0;
373 if (wrappedFields.length === 1) {
374 legalMethods = ['order', 'above', 'below', 'limit'];
375 } else {
376 // The vararg version of findAll cannot have anything chained to it
377 legalMethods = [];
378 }
379 return (0, _possibleConstructorReturn3.default)(this, _TermBase3.call(this, sendRequest, findAllQuery, legalMethods));
380 }
381
382 return FindAll;
383}(TermBase);
384
385var Above = function (_TermBase4) {
386 (0, _inherits3.default)(Above, _TermBase4);
387
388 function Above(sendRequest, previousQuery, aboveSpec, bound) {
389 (0, _classCallCheck3.default)(this, Above);
390
391 var option = { above: [aboveSpec, bound] };
392 var query = Object.assign({}, previousQuery, option);
393 var legalMethods = ['findAll', 'order', 'below', 'limit'];
394 return (0, _possibleConstructorReturn3.default)(this, _TermBase4.call(this, sendRequest, query, legalMethods));
395 }
396
397 return Above;
398}(TermBase);
399
400var Below = function (_TermBase5) {
401 (0, _inherits3.default)(Below, _TermBase5);
402
403 function Below(sendRequest, previousQuery, belowSpec, bound) {
404 (0, _classCallCheck3.default)(this, Below);
405
406 var options = { below: [belowSpec, bound] };
407 var query = Object.assign({}, previousQuery, options);
408 var legalMethods = ['findAll', 'order', 'above', 'limit'];
409 return (0, _possibleConstructorReturn3.default)(this, _TermBase5.call(this, sendRequest, query, legalMethods));
410 }
411
412 return Below;
413}(TermBase);
414
415var Order = function (_TermBase6) {
416 (0, _inherits3.default)(Order, _TermBase6);
417
418 function Order(sendRequest, previousQuery, fields, direction) {
419 (0, _classCallCheck3.default)(this, Order);
420
421 var wrappedFields = Array.isArray(fields) ? fields : [fields];
422 var options = { order: [wrappedFields, direction] };
423 var query = Object.assign({}, previousQuery, options);
424 var legalMethods = ['findAll', 'above', 'below', 'limit'];
425 return (0, _possibleConstructorReturn3.default)(this, _TermBase6.call(this, sendRequest, query, legalMethods));
426 }
427
428 return Order;
429}(TermBase);
430
431var Limit = function (_TermBase7) {
432 (0, _inherits3.default)(Limit, _TermBase7);
433
434 function Limit(sendRequest, previousQuery, size) {
435 (0, _classCallCheck3.default)(this, Limit);
436
437 var query = Object.assign({}, previousQuery, { limit: size });
438 // Nothing is legal to chain after .limit
439 return (0, _possibleConstructorReturn3.default)(this, _TermBase7.call(this, sendRequest, query, []));
440 }
441
442 return Limit;
443}(TermBase);
444
445module.exports = {
446 TermBase: TermBase,
447 Collection: Collection,
448 FindAll: FindAll,
449 Find: Find,
450 Above: Above,
451 Below: Below,
452 Order: Order,
453 Limit: Limit
454};
455//# sourceMappingURL=ast.js.map
\No newline at end of file