Skip to content

Commit

Permalink
fix: pagination and optimistic write creation (#22)
Browse files Browse the repository at this point in the history
fix: pagination and optimistic write creation
  • Loading branch information
Bobby authored Aug 10, 2021
2 parents 932959b + 30c3b43 commit b4f52d9
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 123 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redux-firestore",
"version": "1.1.1",
"version": "1.1.2",
"description": "Redux bindings for Firestore.",
"main": "lib/index.js",
"module": "es/index.js",
Expand Down
4 changes: 4 additions & 0 deletions src/actions/firestore.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,12 @@ export function runTransaction(firebase, dispatch, transactionPromise) {
* @returns {Promise} Resolves with results of update call
*/
export function mutate(firebase, dispatch, writes) {
const timestamp = `${+new Date()}`;

return wrapInDispatch(dispatch, {
ref: firebase,
method: 'mutate',
meta: { timestamp },
args: [writes],
types: [
{
Expand All @@ -428,6 +431,7 @@ export function mutate(firebase, dispatch, writes) {
actionTypes.MUTATE_SUCCESS,
{
type: actionTypes.MUTATE_FAILURE,
meta: { timestamp },
payload: { data: writes },
},
],
Expand Down
1 change: 0 additions & 1 deletion src/createFirestoreInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ export default function createFirestoreInstance(firebase, configs, dispatch) {
* dispatch({ type: 'SOME_ACTION' })
* })
* };
*
*/
export function getFirestore() {
/* istanbul ignore next: Firestore instance always exists during tests */
Expand Down
33 changes: 23 additions & 10 deletions src/reducers/cacheReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ const xfAllIds = ({ collection: path }) =>

/**
* @name xfWhere
* @param getDoc.where
* @param getDoc
* @param {Array.<Array.<string>>} where - Firestore where clauses
* @property {object.<FirestorePath, object<FirestoreDocumentId, Doc>>} db
* @property {object.<FirestorePath, object<FirestoreDocumentId, ParitalDoc>>} dbo
Expand Down Expand Up @@ -206,6 +208,8 @@ const xfWhere = ({ where }, getDoc) => {

/**
* @name xfOrder
* @param getDoc.orderBy
* @param getDoc
* @param {Array.<string>} order - Firestore order property
* @property {object.<FirestorePath, object<FirestoreDocumentId, Doc>>} db
* @property {object.<FirestorePath, object<FirestoreDocumentId, ParitalDoc>>} dbo
Expand Down Expand Up @@ -234,11 +238,9 @@ const xfOrder = ({ orderBy: order }, getDoc) => {
// TODO: refactor to manually lookup and compare
const docs = tuples.map(([path, id]) => getDoc(path, id));

const result = orderBy(docs, fields, direction).map(
return orderBy(docs, fields, direction).map(
({ id, path } = {}) => path && id && [path, id],
);

return result;
});
};

Expand All @@ -262,7 +264,8 @@ const xfLimit = ({ limit, endAt, endBefore }) => {
* @param {?CacheState.database} db -
* @param {?CacheState.databaseOverrides} dbo -
* @param {RRFQuery} query - Firestore query
* @param {Boolean} isOptimisticWrite - includes optimistic data
* @param getDoc
* @param {boolean} isOptimisticWrite - includes optimistic data
* @typedef {Function} xFormFilter - in optimistic reads and overrides
* the reducer needs to take all documents and make a best effort to
* filter down the document based on a cursor.
Expand All @@ -276,8 +279,9 @@ const xfPaginate = (query, getDoc) => {
const end = endAt || endBefore;
const isAfter = startAfter !== undefined;
const isBefore = endBefore !== undefined;
const needsPagination = start || end || false;

if (!order || !isOptimisticRead || !!start || !!end) return identity;
if (!needsPagination || !order || !isOptimisticRead) return identity;

const isFlat = typeof order[0] === 'string';
const orders = isFlat ? [order] : order;
Expand Down Expand Up @@ -329,6 +333,7 @@ const xfPaginate = (query, getDoc) => {
* @name processOptimistic
* Convert the query to a transducer for the query results
* @param {?CacheState.database} database -
* @param state
* @param {?CacheState.databaseOverrides} overrides -
* @param {RRFQuery} query - query used to get data from firestore
* @returns {Function} - Transducer will return a modifed array of documents
Expand All @@ -340,9 +345,9 @@ function processOptimistic(query, state) {
const dbo = databaseOverrides && databaseOverrides[collection];

const getDoc = (path, id) => {
if (path !== collection) console.log('-----', path, collection);
const data = db[id] || {};
const override = dbo?.[id];

return override ? { ...data, ...override } : data;
};

Expand Down Expand Up @@ -530,7 +535,7 @@ function translateMutationToOverrides({ payload }, db = {}, dbo = {}) {
const overrides = dbo[path] || {};
return {
...result,
[key]: { ...collection[id], ...(overrides[id] || {}) },
[key]: { id, path, ...collection[id], ...(overrides[id] || {}) },
};
}, {});
}
Expand Down Expand Up @@ -830,13 +835,21 @@ const mutation = (state, { action, key, path }) => {
try {
const result = produce(state, (draft) => {
const done = mark(`cache.MUTATE_START`, key);
const {
meta: { timestamp },
} = action;
if (action.payload && action.payload.data) {
const optimisiticUpdates =
translateMutationToOverrides(action, draft.database) || [];

optimisiticUpdates.forEach(({ path: _path, id, ...data }) => {
info('overriding', `${_path}/${id}`, data);
setWith(draft, ['databaseOverrides', _path, id], data, Object);
optimisiticUpdates.forEach((data) => {
info('overriding', `${data.path}/${data.id}`, data);
setWith(
draft,
['databaseOverrides', data.path, data.id],
data,
Object,
);
});

const updatePaths = [
Expand Down
8 changes: 2 additions & 6 deletions src/reducers/statusReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ import { actionTypes } from '../constants';
import { getSlashStrPath, combineReducers } from '../utils/reducers';
import { getQueryName } from '../utils/query';

const {
SET_LISTENER,
UNSET_LISTENER,
LISTENER_ERROR,
LISTENER_RESPONSE,
} = actionTypes;
const { SET_LISTENER, UNSET_LISTENER, LISTENER_ERROR, LISTENER_RESPONSE } =
actionTypes;

/**
* Reducer for requesting state.Changed by `START`, `NO_VALUE`, and `SET` actions.
Expand Down
Loading

0 comments on commit b4f52d9

Please sign in to comment.