UNPKG

redux-devshare

Version:

[![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Code Climate][climate-image]][climate-url] [![Code Coverage][coverage-i

198 lines (179 loc) 5.75 kB
import { actionTypes } from '../constants' import { promisesForPopulate } from '../utils/populate' import { forEach, size } from 'lodash' import { applyParamsToQuery, getWatcherCount, setWatcher, unsetWatcher, getQueryIdFromPath } from '../utils/query' const { START, SET, NO_VALUE, UNAUTHORIZED_ERROR, ERROR } = actionTypes /** * @description Watch a specific event type * @param {Object} firebase - Internal firebase object * @param {Function} dispatch - Action dispatch function * @param {Object} options - Event options object * @param {String} options.event - Type of event to watch for (defaults to value) * @param {String} options.path - Path to watch with watcher * @param {String} options.storeAs - Location within redux to store value */ export const watchEvent = (firebase, dispatch, { type, path, populates, queryParams, queryId, isQuery, storeAs }) => { const watchPath = !storeAs ? path : `${path}@${storeAs}` const counter = getWatcherCount(firebase, type, watchPath, queryId) queryId = queryId || getQueryIdFromPath(path) if (counter > 0) { if (queryId) { unsetWatcher(firebase, dispatch, type, path, queryId) } else { return } } setWatcher(firebase, type, watchPath, queryId) if (type === 'first_child') { return firebase.database() .ref() .child(path) .orderByKey() .limitToFirst(1) .once('value', snapshot => { if (snapshot.val() === null) { dispatch({ type: NO_VALUE, timestamp: Date.now(), requesting: false, requested: true, path: storeAs || path }) } return snapshot }, (err) => { // TODO: Handle catching unauthorized error // dispatch({ // type: UNAUTHORIZED_ERROR, // payload: err // }) dispatch({ type: ERROR, payload: err }) }) } let query = firebase.database().ref().child(path) if (isQuery) { query = applyParamsToQuery(queryParams, query) } const runQuery = (q, e, p, params) => { dispatch({ type: START, timestamp: Date.now(), requesting: true, requested: false, path: storeAs || path }) // Handle once queries if (e === 'once') { return q.once('value') .then(snapshot => { if (snapshot.val() !== null) { dispatch({ type: SET, path: storeAs || path, data: snapshot.val() }) } return snapshot }, (err) => { dispatch({ type: UNAUTHORIZED_ERROR, payload: err }) }) } // Handle all other queries /* istanbul ignore next: is run by tests but doesn't show in coverage */ q.on(e, snapshot => { let data = (e === 'child_removed') ? undefined : snapshot.val() const resultPath = storeAs || (e === 'value') ? p : `${p}/${snapshot.key}` // Dispatch standard event if no populates exists if (!populates) { const ordered = [] // preserve order of children under ordered if (e === 'child_added') { ordered.push({ key: snapshot.key, ...snapshot.val() }) } else { snapshot.forEach((child) => { ordered.push({ key: child.key, ...child.val() }) }) } return dispatch({ type: SET, path: storeAs || resultPath, ordered: size(ordered) ? ordered : undefined, data, timestamp: Date.now(), requesting: false, requested: true }) } // TODO: Allow setting of unpopulated data before starting population through config // TODO: Set ordered for populate queries // TODO: Allow config to toggle Combining into one SET action promisesForPopulate(firebase, data, populates) .then((results) => { dispatch({ type: SET, path: resultPath, data, timestamp: Date.now(), requesting: false, requested: true }) forEach(results, (result, path) => { dispatch({ type: SET, path, data: result, timestamp: Date.now(), requesting: false, requested: true }) }) }) }, (err) => { dispatch({ type: UNAUTHORIZED_ERROR, payload: err }) }) } return runQuery(query, type, path, queryParams) } /** * @description Remove watcher from an event * @param {Object} firebase - Internal firebase object * @param {String} event - Event for which to remove the watcher * @param {String} path - Path of watcher to remove */ export const unWatchEvent = (firebase, dispatch, event, path, queryId = undefined) => unsetWatcher(firebase, dispatch, event, path, queryId) /** * @description Add watchers to a list of events * @param {Object} firebase - Internal firebase object * @param {Function} dispatch - Action dispatch function * @param {Array} events - List of events for which to add watchers */ export const watchEvents = (firebase, dispatch, events) => events.forEach(event => watchEvent(firebase, dispatch, event) ) /** * @description Remove watchers from a list of events * @param {Object} firebase - Internal firebase object * @param {Array} events - List of events for which to remove watchers */ export const unWatchEvents = (firebase, dispatch, events) => events.forEach(event => unWatchEvent(firebase, dispatch, event.type, event.path) ) export default { watchEvents, unWatchEvents }