1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.firestoreRef = firestoreRef;
|
7 | exports.getQueryName = getQueryName;
|
8 | exports.getBaseQueryName = getBaseQueryName;
|
9 | exports.listenerExists = listenerExists;
|
10 | exports.attachListener = attachListener;
|
11 | exports.detachListener = detachListener;
|
12 | exports.queryStrToObj = queryStrToObj;
|
13 | exports.getQueryConfig = getQueryConfig;
|
14 | exports.getQueryConfigs = getQueryConfigs;
|
15 | exports.orderedFromSnap = orderedFromSnap;
|
16 | exports.dataByIdSnapshot = dataByIdSnapshot;
|
17 | exports.getPopulateChild = getPopulateChild;
|
18 | exports.populateList = populateList;
|
19 | exports.promisesForPopulate = promisesForPopulate;
|
20 | exports.dispatchListenerResponse = dispatchListenerResponse;
|
21 | exports.getPopulateActions = getPopulateActions;
|
22 |
|
23 | var _some2 = _interopRequireDefault(require("lodash/some"));
|
24 |
|
25 | var _set2 = _interopRequireDefault(require("lodash/set"));
|
26 |
|
27 | var _get2 = _interopRequireDefault(require("lodash/get"));
|
28 |
|
29 | var _map2 = _interopRequireDefault(require("lodash/map"));
|
30 |
|
31 | var _has2 = _interopRequireDefault(require("lodash/has"));
|
32 |
|
33 | var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
|
34 |
|
35 | var _trim2 = _interopRequireDefault(require("lodash/trim"));
|
36 |
|
37 | var _size2 = _interopRequireDefault(require("lodash/size"));
|
38 |
|
39 | var _isObject2 = _interopRequireDefault(require("lodash/isObject"));
|
40 |
|
41 | var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
|
42 |
|
43 | var _isArray2 = _interopRequireDefault(require("lodash/isArray"));
|
44 |
|
45 | var _isString2 = _interopRequireDefault(require("lodash/isString"));
|
46 |
|
47 | var _constants = require("../constants");
|
48 |
|
49 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
50 |
|
51 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
|
52 |
|
53 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
54 |
|
55 | function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest(); }
|
56 |
|
57 | function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
|
58 |
|
59 | function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
60 |
|
61 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
|
62 |
|
63 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
|
64 |
|
65 | function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
|
66 |
|
67 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
|
68 |
|
69 | function addWhereToRef(ref, where) {
|
70 | if (!(0, _isArray2.default)(where)) {
|
71 | throw new Error('where parameter must be an array.');
|
72 | }
|
73 |
|
74 | if ((0, _isString2.default)(where[0])) {
|
75 | return where.length > 1 ? ref.where.apply(ref, _toConsumableArray(where)) : ref.where(where[0]);
|
76 | }
|
77 |
|
78 | return where.reduce(function (acc, whereArgs) {
|
79 | return addWhereToRef(acc, whereArgs);
|
80 | }, ref);
|
81 | }
|
82 |
|
83 | function addOrderByToRef(ref, orderBy) {
|
84 | if (!(0, _isArray2.default)(orderBy) && !(0, _isString2.default)(orderBy)) {
|
85 | throw new Error('orderBy parameter must be an array or string.');
|
86 | }
|
87 |
|
88 | if ((0, _isString2.default)(orderBy)) {
|
89 | return ref.orderBy(orderBy);
|
90 | }
|
91 |
|
92 | if ((0, _isString2.default)(orderBy[0])) {
|
93 | return ref.orderBy.apply(ref, _toConsumableArray(orderBy));
|
94 | }
|
95 |
|
96 | return orderBy.reduce(function (acc, orderByArgs) {
|
97 | return addOrderByToRef(acc, orderByArgs);
|
98 | }, ref);
|
99 | }
|
100 |
|
101 | function handleSubcollections(ref, subcollectionList) {
|
102 | if (subcollectionList) {
|
103 | (0, _forEach2.default)(subcollectionList, function (subcollection) {
|
104 | if (subcollection.collection) {
|
105 | if (!(0, _isFunction2.default)(ref.collection)) {
|
106 | throw new Error("Collection can only be run on a document. Check that query config for subcollection: \"".concat(subcollection.collection, "\" contains a doc parameter."));
|
107 | }
|
108 |
|
109 | ref = ref.collection(subcollection.collection);
|
110 | }
|
111 |
|
112 | if (subcollection.doc) ref = ref.doc(subcollection.doc);
|
113 | if (subcollection.where) ref = addWhereToRef(ref, subcollection.where);
|
114 |
|
115 | if (subcollection.orderBy) {
|
116 | ref = addOrderByToRef(ref, subcollection.orderBy);
|
117 | }
|
118 |
|
119 | if (subcollection.limit) ref = ref.limit(subcollection.limit);
|
120 | if (subcollection.startAt) ref = ref.startAt(subcollection.startAt);
|
121 |
|
122 | if (subcollection.startAfter) {
|
123 | ref = ref.startAfter(subcollection.startAfter);
|
124 | }
|
125 |
|
126 | if (subcollection.endAt) ref = ref.endAt(subcollection.endAt);
|
127 | if (subcollection.endBefore) ref = ref.endBefore(subcollection.endBefore);
|
128 | ref = handleSubcollections(ref, subcollection.subcollections);
|
129 | });
|
130 | }
|
131 |
|
132 | return ref;
|
133 | }
|
134 |
|
135 | function firestoreRef(firebase, meta) {
|
136 | if (!firebase.firestore) {
|
137 | throw new Error('Firestore must be required and initalized.');
|
138 | }
|
139 |
|
140 | var collection = meta.collection,
|
141 | doc = meta.doc,
|
142 | subcollections = meta.subcollections,
|
143 | where = meta.where,
|
144 | orderBy = meta.orderBy,
|
145 | limit = meta.limit,
|
146 | startAt = meta.startAt,
|
147 | startAfter = meta.startAfter,
|
148 | endAt = meta.endAt,
|
149 | endBefore = meta.endBefore;
|
150 | var ref = firebase.firestore().collection(collection);
|
151 | if (doc) ref = ref.doc(doc);
|
152 | ref = handleSubcollections(ref, subcollections);
|
153 | if (where) ref = addWhereToRef(ref, where);
|
154 | if (orderBy) ref = addOrderByToRef(ref, orderBy);
|
155 | if (limit) ref = ref.limit(limit);
|
156 | if (startAt) ref = ref.startAt(startAt);
|
157 | if (startAfter) ref = ref.startAfter(startAfter);
|
158 | if (endAt) ref = ref.endAt(endAt);
|
159 | if (endBefore) ref = ref.endBefore(endBefore);
|
160 | return ref;
|
161 | }
|
162 |
|
163 | function whereToStr(where) {
|
164 | return (0, _isString2.default)(where[0]) ? "where=".concat(where.join(':')) : where.map(whereToStr);
|
165 | }
|
166 |
|
167 | function getQueryName(meta) {
|
168 | if ((0, _isString2.default)(meta)) {
|
169 | return meta;
|
170 | }
|
171 |
|
172 | var collection = meta.collection,
|
173 | doc = meta.doc,
|
174 | subcollections = meta.subcollections,
|
175 | where = meta.where,
|
176 | limit = meta.limit;
|
177 |
|
178 | if (!collection) {
|
179 | throw new Error('Collection is required to build query name');
|
180 | }
|
181 |
|
182 | var basePath = collection;
|
183 |
|
184 | if (doc) {
|
185 | basePath = basePath.concat("/".concat(doc));
|
186 | }
|
187 |
|
188 | if (subcollections) {
|
189 | var mappedCollections = subcollections.map(function (subcollection) {
|
190 | return getQueryName(subcollection);
|
191 | });
|
192 | basePath = "".concat(basePath, "/").concat(mappedCollections.join('/'));
|
193 | }
|
194 |
|
195 | if (where) {
|
196 | if (!(0, _isArray2.default)(where)) {
|
197 | throw new Error('where parameter must be an array.');
|
198 | }
|
199 |
|
200 | basePath = basePath.concat("?".concat(whereToStr(where)));
|
201 | }
|
202 |
|
203 | if (typeof limit !== 'undefined') {
|
204 | var limitStr = "limit=".concat(limit);
|
205 | basePath = basePath.concat("".concat(where ? '&' : '?').concat(limitStr));
|
206 | }
|
207 |
|
208 | return basePath;
|
209 | }
|
210 |
|
211 | function getBaseQueryName(meta) {
|
212 | if ((0, _isString2.default)(meta)) {
|
213 | return meta;
|
214 | }
|
215 |
|
216 | var collection = meta.collection,
|
217 | subcollections = meta.subcollections,
|
218 | where = meta.where,
|
219 | limit = meta.limit;
|
220 |
|
221 | if (!collection) {
|
222 | throw new Error('Collection is required to build query name');
|
223 | }
|
224 |
|
225 | var basePath = collection;
|
226 |
|
227 | if (subcollections) {
|
228 | var mappedCollections = subcollections.map(function (subcollection) {
|
229 | return getQueryName(subcollection);
|
230 | });
|
231 | basePath = "".concat(basePath, "/").concat(mappedCollections.join('/'));
|
232 | }
|
233 |
|
234 | if (where) {
|
235 | if (!(0, _isArray2.default)(where)) {
|
236 | throw new Error('where parameter must be an array.');
|
237 | }
|
238 |
|
239 | basePath = basePath.concat("?".concat(whereToStr(where)));
|
240 | }
|
241 |
|
242 | if (typeof limit !== 'undefined') {
|
243 | var limitStr = "limit=".concat(limit);
|
244 | basePath = basePath.concat("".concat(where ? '&' : '?').concat(limitStr));
|
245 | }
|
246 |
|
247 | return basePath;
|
248 | }
|
249 |
|
250 | function confirmMetaAndConfig(firebase, meta) {
|
251 | if (!meta) {
|
252 | throw new Error('Meta data is required to attach listener.');
|
253 | }
|
254 |
|
255 | if (!(0, _has2.default)(firebase, '_.listeners')) {
|
256 | throw new Error('Internal Firebase object required to attach listener. Confirm that reduxFirestore enhancer was added when you were creating your store');
|
257 | }
|
258 | }
|
259 |
|
260 | function listenerExists(firebase, meta) {
|
261 | confirmMetaAndConfig(firebase, meta);
|
262 | var name = getQueryName(meta);
|
263 | return !!firebase._.listeners[name];
|
264 | }
|
265 |
|
266 | function attachListener(firebase, dispatch, meta, unsubscribe) {
|
267 | confirmMetaAndConfig(firebase, meta);
|
268 | var name = getQueryName(meta);
|
269 |
|
270 | if (!firebase._.listeners[name]) {
|
271 | firebase._.listeners[name] = unsubscribe;
|
272 | }
|
273 |
|
274 | dispatch({
|
275 | type: _constants.actionTypes.SET_LISTENER,
|
276 | meta: meta,
|
277 | payload: {
|
278 | name: name
|
279 | }
|
280 | });
|
281 | return firebase._.listeners;
|
282 | }
|
283 |
|
284 | function detachListener(firebase, dispatch, meta) {
|
285 | var name = getQueryName(meta);
|
286 |
|
287 | if (firebase._.listeners[name]) {
|
288 | firebase._.listeners[name]();
|
289 |
|
290 | delete firebase._.listeners[name];
|
291 | }
|
292 |
|
293 | dispatch({
|
294 | type: _constants.actionTypes.UNSET_LISTENER,
|
295 | meta: meta,
|
296 | payload: {
|
297 | name: name
|
298 | }
|
299 | });
|
300 | }
|
301 |
|
302 | function queryStrToObj(queryPathStr, parsedPath) {
|
303 | var pathArr = parsedPath || (0, _trim2.default)(queryPathStr, ['/']).split('/');
|
304 |
|
305 | var _pathArr = _toArray(pathArr),
|
306 | collection = _pathArr[0],
|
307 | doc = _pathArr[1],
|
308 | subcollections = _pathArr.slice(2);
|
309 |
|
310 | var queryObj = {};
|
311 | if (collection) queryObj.collection = collection;
|
312 | if (doc) queryObj.doc = doc;
|
313 |
|
314 | if (subcollections.length) {
|
315 | queryObj.subcollections = [queryStrToObj('', subcollections)];
|
316 | }
|
317 |
|
318 | return queryObj;
|
319 | }
|
320 |
|
321 | function getQueryConfig(query) {
|
322 | if ((0, _isString2.default)(query)) {
|
323 | return queryStrToObj(query);
|
324 | }
|
325 |
|
326 | if ((0, _isObject2.default)(query)) {
|
327 | if (!query.collection && !query.doc) {
|
328 | throw new Error('Collection and/or Doc are required parameters within query definition object.');
|
329 | }
|
330 |
|
331 | return query;
|
332 | }
|
333 |
|
334 | throw new Error('Invalid Path Definition: Only Strings and Objects are accepted.');
|
335 | }
|
336 |
|
337 | function getQueryConfigs(queries) {
|
338 | if ((0, _isArray2.default)(queries)) {
|
339 | return queries.map(getQueryConfig);
|
340 | }
|
341 |
|
342 | if ((0, _isString2.default)(queries)) {
|
343 | return queryStrToObj(queries);
|
344 | }
|
345 |
|
346 | if ((0, _isObject2.default)(queries)) {
|
347 | return [getQueryConfig(queries)];
|
348 | }
|
349 |
|
350 | throw new Error('Querie(s) must be an Array or a string.');
|
351 | }
|
352 |
|
353 | function orderedFromSnap(snap) {
|
354 | var ordered = [];
|
355 |
|
356 | if (snap.data && snap.exists) {
|
357 | var obj = (0, _isObject2.default)(snap.data()) ? _objectSpread({
|
358 | id: snap.id
|
359 | }, snap.data() || snap.data) : {
|
360 | id: snap.id,
|
361 | data: snap.data()
|
362 | };
|
363 | ordered.push(obj);
|
364 | } else if (snap.forEach) {
|
365 | snap.forEach(function (doc) {
|
366 | var obj = (0, _isObject2.default)(doc.data()) ? _objectSpread({
|
367 | id: doc.id
|
368 | }, doc.data() || doc.data) : {
|
369 | id: doc.id,
|
370 | data: doc.data()
|
371 | };
|
372 | ordered.push(obj);
|
373 | });
|
374 | }
|
375 |
|
376 | return ordered;
|
377 | }
|
378 |
|
379 | function dataByIdSnapshot(snap) {
|
380 | var data = {};
|
381 |
|
382 | if (snap.data && snap.exists) {
|
383 | data[snap.id] = snap.data();
|
384 | } else if (snap.forEach) {
|
385 | snap.forEach(function (doc) {
|
386 | data[doc.id] = doc.data() || doc;
|
387 | });
|
388 | }
|
389 |
|
390 | return (0, _size2.default)(data) ? data : null;
|
391 | }
|
392 |
|
393 | function getPopulateChild(firebase, populate, id) {
|
394 | return firestoreRef(firebase, {
|
395 | collection: populate.root,
|
396 | doc: id
|
397 | }).get().then(function (snap) {
|
398 | return snap.data();
|
399 | });
|
400 | }
|
401 |
|
402 | function populateList(firebase, list, p, results) {
|
403 | if (!results[p.root]) {
|
404 | (0, _set2.default)(results, p.root, {});
|
405 | }
|
406 |
|
407 | return Promise.all((0, _map2.default)(list, function (id, childKey) {
|
408 | var populateKey = id === true || p.populateByKey ? childKey : id;
|
409 | return getPopulateChild(firebase, p, populateKey).then(function (pc) {
|
410 | if (pc) {
|
411 | return (0, _set2.default)(results, "".concat(p.root, ".").concat(populateKey), pc);
|
412 | }
|
413 |
|
414 | return results;
|
415 | });
|
416 | }));
|
417 | }
|
418 |
|
419 | function getPopulateObj(str) {
|
420 | if (!(0, _isString2.default)(str)) {
|
421 | return str;
|
422 | }
|
423 |
|
424 | var strArray = str.split(':');
|
425 | return {
|
426 | child: strArray[0],
|
427 | root: strArray[1]
|
428 | };
|
429 | }
|
430 |
|
431 | function getPopulateObjs(arr) {
|
432 | if (!(0, _isArray2.default)(arr)) {
|
433 | return arr;
|
434 | }
|
435 |
|
436 | return arr.map(function (o) {
|
437 | return (0, _isObject2.default)(o) ? o : getPopulateObj(o);
|
438 | });
|
439 | }
|
440 |
|
441 | function promisesForPopulate(firebase, dataKey, originalData, populatesIn) {
|
442 | var promisesArray = [];
|
443 | var results = {};
|
444 | var populatesForData = getPopulateObjs((0, _isFunction2.default)(populatesIn) ? populatesIn(dataKey, originalData) : populatesIn);
|
445 | var dataHasPopulateChilds = (0, _some2.default)(populatesForData, function (populate) {
|
446 | return (0, _has2.default)(originalData, populate.child);
|
447 | });
|
448 |
|
449 | if (dataHasPopulateChilds) {
|
450 | (0, _forEach2.default)(populatesForData, function (p) {
|
451 | if ((0, _isString2.default)((0, _get2.default)(originalData, p.child))) {
|
452 | return promisesArray.push(getPopulateChild(firebase, p, (0, _get2.default)(originalData, p.child)).then(function (v) {
|
453 | if (v) {
|
454 | (0, _set2.default)(results, "".concat(p.root, ".").concat((0, _get2.default)(originalData, p.child)), v);
|
455 | }
|
456 | }));
|
457 | }
|
458 |
|
459 | return promisesArray.push(populateList(firebase, (0, _get2.default)(originalData, p.child), p, results));
|
460 | });
|
461 | } else {
|
462 | (0, _forEach2.default)(originalData, function (d, key) {
|
463 | var populatesForDataItem = getPopulateObj((0, _isFunction2.default)(populatesIn) ? populatesIn(key, d) : populatesIn);
|
464 | (0, _forEach2.default)(populatesForDataItem, function (p) {
|
465 | var idOrList = (0, _get2.default)(d, p.child);
|
466 |
|
467 | if (!idOrList) {
|
468 | return;
|
469 | }
|
470 |
|
471 | if ((0, _isString2.default)(idOrList)) {
|
472 | return promisesArray.push(getPopulateChild(firebase, p, idOrList).then(function (v) {
|
473 | if (v) {
|
474 | (0, _set2.default)(results, "".concat(p.root, ".").concat(idOrList), v);
|
475 | }
|
476 |
|
477 | return results;
|
478 | }));
|
479 | }
|
480 |
|
481 | if ((0, _isArray2.default)(idOrList) || (0, _isObject2.default)(idOrList)) {
|
482 | return promisesArray.push(populateList(firebase, idOrList, p, results));
|
483 | }
|
484 | });
|
485 | });
|
486 | }
|
487 |
|
488 | return Promise.all(promisesArray).then(function () {
|
489 | return results;
|
490 | });
|
491 | }
|
492 |
|
493 | var changeTypeToEventType = {
|
494 | added: _constants.actionTypes.DOCUMENT_ADDED,
|
495 | removed: _constants.actionTypes.DOCUMENT_REMOVED,
|
496 | modified: _constants.actionTypes.DOCUMENT_MODIFIED
|
497 | };
|
498 |
|
499 | function docChangeEvent(change) {
|
500 | var originalMeta = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
501 |
|
502 | var meta = _objectSpread({}, originalMeta, {
|
503 | path: change.doc.ref.path
|
504 | });
|
505 |
|
506 | if (originalMeta.subcollections && !originalMeta.storeAs) {
|
507 | meta.subcollections[0] = _objectSpread({}, meta.subcollections[0], {
|
508 | doc: change.doc.id
|
509 | });
|
510 | } else {
|
511 | meta.doc = change.doc.id;
|
512 | }
|
513 |
|
514 | return {
|
515 | type: changeTypeToEventType[change.type] || _constants.actionTypes.DOCUMENT_MODIFIED,
|
516 | meta: meta,
|
517 | payload: {
|
518 | data: change.doc.data(),
|
519 | ordered: {
|
520 | oldIndex: change.oldIndex,
|
521 | newIndex: change.newIndex
|
522 | }
|
523 | }
|
524 | };
|
525 | }
|
526 |
|
527 | function dispatchListenerResponse(_ref) {
|
528 | var dispatch = _ref.dispatch,
|
529 | docData = _ref.docData,
|
530 | meta = _ref.meta,
|
531 | firebase = _ref.firebase;
|
532 |
|
533 | var _ref2 = firebase._.config || {},
|
534 | mergeOrdered = _ref2.mergeOrdered,
|
535 | mergeOrderedDocUpdates = _ref2.mergeOrderedDocUpdates,
|
536 | mergeOrderedCollectionUpdates = _ref2.mergeOrderedCollectionUpdates;
|
537 |
|
538 | var docChanges = typeof docData.docChanges === 'function' ? docData.docChanges() : docData.docChanges;
|
539 |
|
540 | if (docChanges && docChanges.length < docData.size) {
|
541 | docChanges.forEach(function (change) {
|
542 | dispatch(docChangeEvent(change, meta));
|
543 | });
|
544 | } else {
|
545 | dispatch({
|
546 | type: _constants.actionTypes.LISTENER_RESPONSE,
|
547 | meta: meta,
|
548 | payload: {
|
549 | data: dataByIdSnapshot(docData),
|
550 | ordered: orderedFromSnap(docData)
|
551 | },
|
552 | merge: {
|
553 | docs: mergeOrdered && mergeOrderedDocUpdates,
|
554 | collections: mergeOrdered && mergeOrderedCollectionUpdates
|
555 | }
|
556 | });
|
557 | }
|
558 | }
|
559 |
|
560 | function getPopulateActions(_ref3) {
|
561 | var firebase = _ref3.firebase,
|
562 | docData = _ref3.docData,
|
563 | meta = _ref3.meta;
|
564 | return promisesForPopulate(firebase, docData.id, dataByIdSnapshot(docData), meta.populates).then(function (populateResults) {
|
565 | return Object.keys(populateResults).map(function (resultKey) {
|
566 | return {
|
567 | meta: {
|
568 | collection: resultKey
|
569 | },
|
570 | payload: {
|
571 | data: populateResults[resultKey]
|
572 | },
|
573 | requesting: false,
|
574 | requested: true
|
575 | };
|
576 | });
|
577 | }).catch(function (populateErr) {
|
578 | console.error('Error with populate:', populateErr, meta);
|
579 | return Promise.reject(populateErr);
|
580 | });
|
581 | } |
\ | No newline at end of file |