From 8d73ba206e19fdead7f30db86e4d4b790913884f Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 01:41:46 +0900 Subject: [PATCH 1/9] =?UTF-8?q?filter-anything=20=E2=86=92=20external=20pk?= =?UTF-8?q?g=20=E2=9A=94=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/index.cjs.js | 64 +++--------------------------- dist/index.esm.js | 64 +++--------------------------- package.json | 3 +- src/module/getters.ts | 10 ++--- src/utils/checkFillables.ts | 61 ----------------------------- test/helpers/index.cjs.js | 64 +++--------------------------- test/utils/checkFillables.js | 76 ------------------------------------ yarn.lock | 7 ++++ 8 files changed, 29 insertions(+), 320 deletions(-) delete mode 100644 src/utils/checkFillables.ts delete mode 100644 test/utils/checkFillables.js diff --git a/dist/index.cjs.js b/dist/index.cjs.js index c5697767..77d88d3f 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -9,6 +9,7 @@ var Firebase = require('firebase/app'); var vuexEasyAccess = require('vuex-easy-access'); var merge = _interopDefault(require('merge-anything')); var findAndReplaceAnything = require('find-and-replace-anything'); +var filter = _interopDefault(require('filter-anything')); require('@firebase/firestore'); @@ -1241,61 +1242,6 @@ function flattenToPaths (object) { return retrievePaths(object, null, result); } -function recursiveCheck(obj, fillables, guard, pathUntilNow) { - if (pathUntilNow === void 0) { pathUntilNow = ''; } - if (!isWhat.isPlainObject(obj)) { - console.log('obj → ', obj); - return obj; - } - return Object.keys(obj).reduce(function (carry, key) { - var path = pathUntilNow; - if (path) - path += '.'; - path += key; - // check guard regardless - if (guard.includes(path)) { - return carry; - } - var value = obj[key]; - // check fillables up to this point - if (fillables.length) { - var passed_1 = false; - fillables.forEach(function (fillable) { - var pathDepth = path.split('.').length; - var fillableDepth = fillable.split('.').length; - var fillableUpToNow = fillable.split('.').slice(0, pathDepth).join('.'); - var pathUpToFillableDepth = path.split('.').slice(0, fillableDepth).join('.'); - if (fillableUpToNow === pathUpToFillableDepth) - passed_1 = true; - }); - // there's not one fillable that allows up to now - if (!passed_1) - return carry; - } - // no fillables or fillables up to now allow it - if (!isWhat.isPlainObject(value)) { - carry[key] = value; - return carry; - } - carry[key] = recursiveCheck(obj[key], fillables, guard, path); - return carry; - }, {}); -} -/** - * Checks all props of an object and deletes guarded and non-fillables. - * - * @export - * @param {object} obj the target object to check - * @param {string[]} [fillables=[]] an array of strings, with the props which should be allowed on returned object - * @param {string[]} [guard=[]] an array of strings, with the props which should NOT be allowed on returned object - * @returns {AnyObject} the cleaned object after deleting guard and non-fillables - */ -function checkFillables (obj, fillables, guard) { - if (fillables === void 0) { fillables = []; } - if (guard === void 0) { guard = []; } - return recursiveCheck(obj, fillables, guard); -} - /** * A function returning the getters object * @@ -1380,7 +1326,7 @@ function pluginGetters (Firebase$$1) { fillables = fillables.concat(['updated_at', 'updated_by']); var guard = state._conf.sync.guard.concat(['_conf', '_sync']); // clean up item - var cleanedPatchData = checkFillables(patchData, fillables, guard); + var cleanedPatchData = filter(patchData, fillables, guard); var itemToUpdate = flattenToPaths(cleanedPatchData); // add id (required to get ref later at apiHelpers.ts) itemToUpdate.id = id; @@ -1404,7 +1350,7 @@ function pluginGetters (Firebase$$1) { fillables = fillables.concat(['updated_at', 'updated_by']); var guard = state._conf.sync.guard.concat(['_conf', '_sync']); // clean up item - var cleanedPatchData = checkFillables(patchData, fillables, guard); + var cleanedPatchData = filter(patchData, fillables, guard); // add id (required to get ref later at apiHelpers.ts) var id, cleanedPath; if (collectionMode) { @@ -1433,7 +1379,7 @@ function pluginGetters (Firebase$$1) { item.created_at = Firebase$$1.firestore.FieldValue.serverTimestamp(); item.created_by = state._sync.userId; // clean up item - item = checkFillables(item, fillables, guard); + item = filter(item, fillables, guard); carry.push(item); return carry; }, []); @@ -1450,7 +1396,7 @@ function pluginGetters (Firebase$$1) { doc.created_at = Firebase$$1.firestore.FieldValue.serverTimestamp(); doc.created_by = state._sync.userId; // clean up item - doc = checkFillables(doc, fillables, guard); + doc = filter(doc, fillables, guard); return doc; }; }, diff --git a/dist/index.esm.js b/dist/index.esm.js index 4567b5fa..00910e87 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -4,6 +4,7 @@ import { firestore } from 'firebase/app'; import { getDeepRef, getKeysFromPath } from 'vuex-easy-access'; import merge from 'merge-anything'; import { findAndReplace, findAndReplaceIf } from 'find-and-replace-anything'; +import filter from 'filter-anything'; require('@firebase/firestore'); @@ -1236,61 +1237,6 @@ function flattenToPaths (object) { return retrievePaths(object, null, result); } -function recursiveCheck(obj, fillables, guard, pathUntilNow) { - if (pathUntilNow === void 0) { pathUntilNow = ''; } - if (!isPlainObject(obj)) { - console.log('obj → ', obj); - return obj; - } - return Object.keys(obj).reduce(function (carry, key) { - var path = pathUntilNow; - if (path) - path += '.'; - path += key; - // check guard regardless - if (guard.includes(path)) { - return carry; - } - var value = obj[key]; - // check fillables up to this point - if (fillables.length) { - var passed_1 = false; - fillables.forEach(function (fillable) { - var pathDepth = path.split('.').length; - var fillableDepth = fillable.split('.').length; - var fillableUpToNow = fillable.split('.').slice(0, pathDepth).join('.'); - var pathUpToFillableDepth = path.split('.').slice(0, fillableDepth).join('.'); - if (fillableUpToNow === pathUpToFillableDepth) - passed_1 = true; - }); - // there's not one fillable that allows up to now - if (!passed_1) - return carry; - } - // no fillables or fillables up to now allow it - if (!isPlainObject(value)) { - carry[key] = value; - return carry; - } - carry[key] = recursiveCheck(obj[key], fillables, guard, path); - return carry; - }, {}); -} -/** - * Checks all props of an object and deletes guarded and non-fillables. - * - * @export - * @param {object} obj the target object to check - * @param {string[]} [fillables=[]] an array of strings, with the props which should be allowed on returned object - * @param {string[]} [guard=[]] an array of strings, with the props which should NOT be allowed on returned object - * @returns {AnyObject} the cleaned object after deleting guard and non-fillables - */ -function checkFillables (obj, fillables, guard) { - if (fillables === void 0) { fillables = []; } - if (guard === void 0) { guard = []; } - return recursiveCheck(obj, fillables, guard); -} - /** * A function returning the getters object * @@ -1375,7 +1321,7 @@ function pluginGetters (Firebase$$1) { fillables = fillables.concat(['updated_at', 'updated_by']); var guard = state._conf.sync.guard.concat(['_conf', '_sync']); // clean up item - var cleanedPatchData = checkFillables(patchData, fillables, guard); + var cleanedPatchData = filter(patchData, fillables, guard); var itemToUpdate = flattenToPaths(cleanedPatchData); // add id (required to get ref later at apiHelpers.ts) itemToUpdate.id = id; @@ -1399,7 +1345,7 @@ function pluginGetters (Firebase$$1) { fillables = fillables.concat(['updated_at', 'updated_by']); var guard = state._conf.sync.guard.concat(['_conf', '_sync']); // clean up item - var cleanedPatchData = checkFillables(patchData, fillables, guard); + var cleanedPatchData = filter(patchData, fillables, guard); // add id (required to get ref later at apiHelpers.ts) var id, cleanedPath; if (collectionMode) { @@ -1428,7 +1374,7 @@ function pluginGetters (Firebase$$1) { item.created_at = Firebase$$1.firestore.FieldValue.serverTimestamp(); item.created_by = state._sync.userId; // clean up item - item = checkFillables(item, fillables, guard); + item = filter(item, fillables, guard); carry.push(item); return carry; }, []); @@ -1445,7 +1391,7 @@ function pluginGetters (Firebase$$1) { doc.created_at = Firebase$$1.firestore.FieldValue.serverTimestamp(); doc.created_by = state._sync.userId; // clean up item - doc = checkFillables(doc, fillables, guard); + doc = filter(doc, fillables, guard); return doc; }; }, diff --git a/package.json b/package.json index 388ab0a7..0a11344c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vuex-easy-firestore", - "version": "1.21.0", + "version": "1.21.1", "description": "Easy coupling of firestore and a vuex module. 2-way sync with 0 boilerplate!", "main": "dist/index.cjs.js", "module": "dist/index.esm.js", @@ -35,6 +35,7 @@ }, "homepage": "https://github.com/mesqueeb/vuex-easy-firestore#readme", "dependencies": { + "filter-anything": "^1.0.0", "find-and-replace-anything": "^2.0.0", "is-what": "^3.1.1", "merge-anything": "^2.2.0", diff --git a/src/module/getters.ts b/src/module/getters.ts index f9e2c0c1..d75bf467 100644 --- a/src/module/getters.ts +++ b/src/module/getters.ts @@ -1,8 +1,8 @@ import { isString, isPlainObject, isAnyObject } from 'is-what' import { getDeepRef } from 'vuex-easy-access' import { findAndReplaceIf } from 'find-and-replace-anything' +import filter from 'filter-anything' import flattenToPaths from '../utils/objectFlattenToPaths' -import checkFillables from '../utils/checkFillables' import { getPathVarMatches } from '../utils/apiHelpers' import { isArrayHelper } from '../utils/arrayHelpers' import { AnyObject } from '../declarations' @@ -95,7 +95,7 @@ export default function (Firebase: any): AnyObject { if (fillables.length) fillables = fillables.concat(['updated_at', 'updated_by']) const guard = state._conf.sync.guard.concat(['_conf', '_sync']) // clean up item - const cleanedPatchData = checkFillables(patchData, fillables, guard) + const cleanedPatchData = filter(patchData, fillables, guard) const itemToUpdate = flattenToPaths(cleanedPatchData) // add id (required to get ref later at apiHelpers.ts) itemToUpdate.id = id @@ -115,7 +115,7 @@ export default function (Firebase: any): AnyObject { if (fillables.length) fillables = fillables.concat(['updated_at', 'updated_by']) const guard = state._conf.sync.guard.concat(['_conf', '_sync']) // clean up item - const cleanedPatchData = checkFillables(patchData, fillables, guard) + const cleanedPatchData = filter(patchData, fillables, guard) // add id (required to get ref later at apiHelpers.ts) let id, cleanedPath if (collectionMode) { @@ -140,7 +140,7 @@ export default function (Firebase: any): AnyObject { item.created_at = Firebase.firestore.FieldValue.serverTimestamp() item.created_by = state._sync.userId // clean up item - item = checkFillables(item, fillables, guard) + item = filter(item, fillables, guard) carry.push(item) return carry }, []) @@ -155,7 +155,7 @@ export default function (Firebase: any): AnyObject { doc.created_at = Firebase.firestore.FieldValue.serverTimestamp() doc.created_by = state._sync.userId // clean up item - doc = checkFillables(doc, fillables, guard) + doc = filter(doc, fillables, guard) return doc }, whereFilters: (state, getters) => { diff --git a/src/utils/checkFillables.ts b/src/utils/checkFillables.ts deleted file mode 100644 index fe212513..00000000 --- a/src/utils/checkFillables.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { isPlainObject } from 'is-what' -import { AnyObject } from '../declarations' - -function recursiveCheck ( - obj: object, - fillables: string[], - guard: string[], - pathUntilNow: string = '' -): AnyObject { - if (!isPlainObject(obj)) { - console.log('obj → ', obj) - return obj - } - return Object.keys(obj).reduce((carry, key) => { - let path = pathUntilNow - if (path) path += '.' - path += key - // check guard regardless - if (guard.includes(path)) { - return carry - } - const value = obj[key] - // check fillables up to this point - if (fillables.length) { - let passed = false - fillables.forEach(fillable => { - const pathDepth = path.split('.').length - const fillableDepth = fillable.split('.').length - const fillableUpToNow = fillable.split('.').slice(0, pathDepth).join('.') - const pathUpToFillableDepth = path.split('.').slice(0, fillableDepth).join('.') - if (fillableUpToNow === pathUpToFillableDepth) passed = true - }) - // there's not one fillable that allows up to now - if (!passed) return carry - } - // no fillables or fillables up to now allow it - if (!isPlainObject(value)) { - carry[key] = value - return carry - } - carry[key] = recursiveCheck(obj[key], fillables, guard, path) - return carry - }, {}) -} - -/** - * Checks all props of an object and deletes guarded and non-fillables. - * - * @export - * @param {object} obj the target object to check - * @param {string[]} [fillables=[]] an array of strings, with the props which should be allowed on returned object - * @param {string[]} [guard=[]] an array of strings, with the props which should NOT be allowed on returned object - * @returns {AnyObject} the cleaned object after deleting guard and non-fillables - */ -export default function ( - obj: object, - fillables: string[] = [], - guard: string[] = [] -): AnyObject { - return recursiveCheck(obj, fillables, guard) -} diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index 7f005e10..ed8bd00e 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -8,6 +8,7 @@ var isWhat = require('is-what'); var Firebase = require('firebase/app'); var merge = _interopDefault(require('merge-anything')); var findAndReplaceAnything = require('find-and-replace-anything'); +var filter = _interopDefault(require('filter-anything')); var Vue = _interopDefault(require('vue')); var Vuex = _interopDefault(require('vuex')); @@ -1376,61 +1377,6 @@ function flattenToPaths (object) { return retrievePaths(object, null, result); } -function recursiveCheck(obj, fillables, guard, pathUntilNow) { - if (pathUntilNow === void 0) { pathUntilNow = ''; } - if (!isWhat.isPlainObject(obj)) { - console.log('obj → ', obj); - return obj; - } - return Object.keys(obj).reduce(function (carry, key) { - var path = pathUntilNow; - if (path) - path += '.'; - path += key; - // check guard regardless - if (guard.includes(path)) { - return carry; - } - var value = obj[key]; - // check fillables up to this point - if (fillables.length) { - var passed_1 = false; - fillables.forEach(function (fillable) { - var pathDepth = path.split('.').length; - var fillableDepth = fillable.split('.').length; - var fillableUpToNow = fillable.split('.').slice(0, pathDepth).join('.'); - var pathUpToFillableDepth = path.split('.').slice(0, fillableDepth).join('.'); - if (fillableUpToNow === pathUpToFillableDepth) - passed_1 = true; - }); - // there's not one fillable that allows up to now - if (!passed_1) - return carry; - } - // no fillables or fillables up to now allow it - if (!isWhat.isPlainObject(value)) { - carry[key] = value; - return carry; - } - carry[key] = recursiveCheck(obj[key], fillables, guard, path); - return carry; - }, {}); -} -/** - * Checks all props of an object and deletes guarded and non-fillables. - * - * @export - * @param {object} obj the target object to check - * @param {string[]} [fillables=[]] an array of strings, with the props which should be allowed on returned object - * @param {string[]} [guard=[]] an array of strings, with the props which should NOT be allowed on returned object - * @returns {AnyObject} the cleaned object after deleting guard and non-fillables - */ -function checkFillables (obj, fillables, guard) { - if (fillables === void 0) { fillables = []; } - if (guard === void 0) { guard = []; } - return recursiveCheck(obj, fillables, guard); -} - /** * A function returning the getters object * @@ -1515,7 +1461,7 @@ function pluginGetters (Firebase$$1) { fillables = fillables.concat(['updated_at', 'updated_by']); var guard = state._conf.sync.guard.concat(['_conf', '_sync']); // clean up item - var cleanedPatchData = checkFillables(patchData, fillables, guard); + var cleanedPatchData = filter(patchData, fillables, guard); var itemToUpdate = flattenToPaths(cleanedPatchData); // add id (required to get ref later at apiHelpers.ts) itemToUpdate.id = id; @@ -1539,7 +1485,7 @@ function pluginGetters (Firebase$$1) { fillables = fillables.concat(['updated_at', 'updated_by']); var guard = state._conf.sync.guard.concat(['_conf', '_sync']); // clean up item - var cleanedPatchData = checkFillables(patchData, fillables, guard); + var cleanedPatchData = filter(patchData, fillables, guard); // add id (required to get ref later at apiHelpers.ts) var id, cleanedPath; if (collectionMode) { @@ -1568,7 +1514,7 @@ function pluginGetters (Firebase$$1) { item.created_at = Firebase$$1.firestore.FieldValue.serverTimestamp(); item.created_by = state._sync.userId; // clean up item - item = checkFillables(item, fillables, guard); + item = filter(item, fillables, guard); carry.push(item); return carry; }, []); @@ -1585,7 +1531,7 @@ function pluginGetters (Firebase$$1) { doc.created_at = Firebase$$1.firestore.FieldValue.serverTimestamp(); doc.created_by = state._sync.userId; // clean up item - doc = checkFillables(doc, fillables, guard); + doc = filter(doc, fillables, guard); return doc; }; }, diff --git a/test/utils/checkFillables.js b/test/utils/checkFillables.js deleted file mode 100644 index d8b2c188..00000000 --- a/test/utils/checkFillables.js +++ /dev/null @@ -1,76 +0,0 @@ -import checkFillables from '../../src/utils/checkFillables' -import test from 'ava' - -test('check fillables FLAT', t => { - let res, doc, fillables, guard - doc = {name: 'n1', id: '1', filled: true, notfilled: false} - fillables = ['name', 'filled', 'id'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {name: 'n1', id: '1', filled: true}) -}) - -test('check guard FLAT', t => { - let res, doc, fillables, guard - doc = {name: 'n1', id: '1', filled: true, guarded: true} - fillables = [] - guard = ['guarded'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {name: 'n1', id: '1', filled: true}) -}) - -test('check fillables NESTED - single fillable', t => { - let res, doc, fillables, guard - doc = {nested: {fillables: {yes: 0, no: 0}}, secondProp: true} - fillables = ['nested.fillables.yes'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0}}}) - fillables = ['nested.fillables'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0, no: 0}}}) - fillables = ['nested'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0, no: 0}}}) -}) - -test('check fillables NESTED - multiple fillable', t => { - let res, doc, fillables, guard - doc = {nested: {fillables: {yes: 0, no: 0}}, secondProp: {yes: true, no: false}} - fillables = ['nested.fillables.yes', 'secondProp.yes'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0}}, secondProp: {yes: true}}) - fillables = ['nested.fillables', 'secondProp.yes'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0, no: 0}}, secondProp: {yes: true}}) - fillables = ['nested', 'secondProp.yes'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0, no: 0}}, secondProp: {yes: true}}) -}) - -test('check guard NESTED', t => { - let res, doc, fillables, guard - doc = {nested: {guard: {yes: 0, no: 0}}, secondProp: true} - guard = ['nested.guard.yes'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {guard: {no: 0}}, secondProp: true}) - guard = ['nested.guard'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {}, secondProp: true}) - guard = ['nested'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {secondProp: true}) -}) - -test('check fillables NESTED - multiple fillable & guard', t => { - let res, doc, fillables, guard - doc = {nested: {fillables: {yes: 0, no: 0}}, secondProp: {yes: true, no: false}, guardedTop: true, guardedDeep: {yes: true, no: true}} - fillables = ['nested.fillables.yes', 'secondProp.yes', 'guardedTop', 'guardedDeep'] - guard = ['guardedTop', 'guardedDeep.yes'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0}}, secondProp: {yes: true}, guardedDeep: {no: true}}) - fillables = ['nested.fillables', 'secondProp.yes', 'guardedTop', 'guardedDeep'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0, no: 0}}, secondProp: {yes: true}, guardedDeep: {no: true}}) - fillables = ['nested', 'secondProp.yes', 'guardedTop', 'guardedDeep'] - res = checkFillables(doc, fillables, guard) - t.deepEqual(res, {nested: {fillables: {yes: 0, no: 0}}, secondProp: {yes: true}, guardedDeep: {no: true}}) -}) diff --git a/yarn.lock b/yarn.lock index f8d11694..b48bbdca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4073,6 +4073,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +filter-anything@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/filter-anything/-/filter-anything-1.0.0.tgz#59d1be272d9e72d0eac42c09b4a667a298088e75" + integrity sha512-ScsNU4RAtNdKqKC47i7E08dwdDVGRtTm+tYZj2YZVprJSKaM9VZQGlOEBTjRuzGOJqKnzAnurh2Q5PD3mMgEPA== + dependencies: + is-what "^3.1.1" + find-and-replace-anything@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/find-and-replace-anything/-/find-and-replace-anything-1.2.0.tgz#d2f2b69718da4e7aee363441d42485274cf79a2d" From 3c3fd061c99205067d2c69cdd2b7d901fcef2bb4 Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 13:39:33 +0900 Subject: [PATCH 2/9] =?UTF-8?q?support=20fillable/guard=20wildcards=20?= =?UTF-8?q?=F0=9F=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0a11344c..02fda902 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/mesqueeb/vuex-easy-firestore#readme", "dependencies": { - "filter-anything": "^1.0.0", + "filter-anything": "^1.1.0", "find-and-replace-anything": "^2.0.0", "is-what": "^3.1.1", "merge-anything": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index b48bbdca..cba48156 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4073,10 +4073,10 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -filter-anything@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/filter-anything/-/filter-anything-1.0.0.tgz#59d1be272d9e72d0eac42c09b4a667a298088e75" - integrity sha512-ScsNU4RAtNdKqKC47i7E08dwdDVGRtTm+tYZj2YZVprJSKaM9VZQGlOEBTjRuzGOJqKnzAnurh2Q5PD3mMgEPA== +filter-anything@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-anything/-/filter-anything-1.1.0.tgz#9821649f17be540297f13ec4d5bdf340a72a7e01" + integrity sha512-c5+DdGvv1qJLXctPCPEfers1iz9TzjmYo4w9JQeh4sy8/au+lJH70mpJ4QEKcCHN8vy4QdlvhMSzYS1BGtBGfw== dependencies: is-what "^3.1.1" From 5cc716c5f05d4e95ec232270d8f5b91b14c2890b Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 13:39:45 +0900 Subject: [PATCH 3/9] =?UTF-8?q?greatly=20improve=20docs=20=F0=9F=92=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vuepress/config.js | 3 +- docs/README.md | 4 +- docs/extra-features.md | 261 +++++++++++++-------------------------- docs/guide.md | 105 ++++++++-------- docs/hooks.md | 147 ++++++++++++++++++++++ docs/ja/README.md | 58 --------- docs/setup.md | 2 +- 7 files changed, 288 insertions(+), 292 deletions(-) create mode 100644 docs/hooks.md delete mode 100644 docs/ja/README.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index d1519845..16783b7e 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -10,8 +10,9 @@ module.exports = { sidebar: [ ['/setup', 'Installation & setup'], '/guide', - '/extra-features', '/firestore-fields-and-functions', + '/hooks', + '/extra-features', '/config-example', '/feedback', ], diff --git a/docs/README.md b/docs/README.md index fc877517..4102a459 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,9 +37,9 @@ Now you just update and add docs with `dispatch('userData/set', newItem)` and fo - Automatic 2-way sync between your Vuex module & Firestore - [Timestamp conversion to Date()](extra-features.html#defaultvalues-set-after-server-retrieval) +- [Hooks](hooks.html#hooks) (before / after sync) - [Fillables / guard](extra-features.html#fillables-and-guard) (limit fields which will sync) -- [Hooks](extra-features.html#hooks-before-insert-patch-delete) (before / after sync) -- [Where / orderBy filters](extra-features.html#filters) +- [Where / orderBy filters](guide.html#query-data-filters) # Motivation diff --git a/docs/extra-features.md b/docs/extra-features.md index 64e9b655..85d60647 100644 --- a/docs/extra-features.md +++ b/docs/extra-features.md @@ -1,55 +1,5 @@ # Extra features -## Filters - -> Only for 'collection' mode. - -Just as in Firestore's [onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) listener, you can set `where` and `orderBy` filters to filter which docs are retrieved and synced. - -- *where:* arrays of `parameters` that get passed on to firestore's `.where(...parameters)` -- *orderBy:* a single `array` that gets passed on to firestore's `.orderBy(...array)` - -### Usage: - -```js -const where = [ // an array of arrays - ['certain_field', '==', false], - ['another_field', '==', true], -] -const orderBy = ['created_date'] // or more params - -// Add to openDBChannel: -store.dispatch('myModule/openDBChannel', {where, orderBy}) // like this - -// OR -// Add to your vuex-easy-fire module in the config -myModule = { - // your other vuex-easy-fire config... - sync: { - where, - orderBy - } -} -``` - -You can also use all kind of variables like `'{userId}'` like so: - -```js -store.dispatch('myModule/openDBChannel', { - where: [ - ['created_by', '==', '{userId}'], - ['some field', '==', '{pathVar}'] - ], - pathVar: 'value' -}) -``` - -What happens here above is: -- `{userId}` will be automatically replaced with the authenticated user -- `{pathVar}` is a custom variable that will be replaced with `'value'` - -For more information on custom variables, see the next chapter: - ## Variables for firestorePath or filters Besides `'{userId}'` in your `firestorePath` in the config or in where filters, you can also use **any variable** in the `firestorePath` or the `where` filter. @@ -99,7 +49,7 @@ You can prevent props on your docs in 'collection' mode (or on your single doc i } ``` -**Example fillables:** +### Example fillables ```js // settings: @@ -116,7 +66,7 @@ dispatch('user/set', newUser) {name: 'Ash', age: 10} ``` -**Example guard:** +### Example guard If you have only one prop you do not want to sync to firestore you can set `guard` instead of `fillables`. @@ -125,149 +75,81 @@ If you have only one prop you do not want to sync to firestore you can set `guar guard: ['email'] ``` -## Hooks before insert/patch/delete +### Nested fillables/guard + +In the example below we will prevent the nested field called `notAllowed` from being synced: + +```js +const docToPatch = {nested: {allowed: true, notAllowed: true}} + +// in your module config, either set the fillables like so: +fillables: ['nested.allowed'] + +// OR set your guard like so: +guard: ['nested.notAllowed'] +``` + +### Wildcard fillables/guard -A function where you can check something or even change the doc (the doc object) before the store mutation occurs. The `doc` passed in these hooks will also have an `id` field which is the id with which it will be added to the store and to Firestore. +You can also use wildcards! -Please make sure to check the overview of [execution timings of hooks](#execution-timings-of-hooks). +In this example you have a document with an object called `lists`. The lists each have an id as the key, and a nested property you want to prevent from being synced: ```js -{ - // your other vuex-easy-fire config... - sync: { - insertHook: function (updateStore, doc, store) { updateStore(doc) }, - patchHook: function (updateStore, doc, store) { updateStore(doc) }, - deleteHook: function (updateStore, id, store) { updateStore(id) }, - // Batches have separate hooks! - insertBatchHook: function (updateStore, doc, store) { updateStore(doc) }, - patchBatchHook: function (updateStore, doc, ids, store) { updateStore(doc, ids) }, - deleteBatchHook: function (updateStore, ids, store) { updateStore(ids) }, +const docToPatch = { + lists: { + 'list-id1': {allowed: true, notAllowed: true}, + 'list-id2': {allowed: true, notAllowed: true} } } + +// in your module config, either set the fillables like so: +fillables: ['lists.*.allowed'] + +// OR set your guard like so: +guard: ['lists.*.notAllowed'] +``` + +## Duplicating docs + +> Only for 'collection' mode. + +You can duplicate a document really simply by dispatching 'duplicate' and passing the id of the target document. + +```js +// let's duplicate Bulbasaur who has the id '001' +dispatch('pokemonBox/duplicate', '001') ``` -::: warning You must call `updateStore(doc)` to make the store mutation. -But you may choose not to call this to abort the mutation. If you do not call `updateStore(doc)` nothing will happen. -::: +This will create a copy of Bulbasaur (and all its props) with a random new ID. The duplicated doc will automatically be added to your vuex module and synced as well. -## Hooks after changes on the server +If you need to know which new ID was generated for the duplicate, you can retrieve it from the action: -Exactly the same as above, but for changes that have occured on the server. You also have some extra parameters to work with: +```js +const idMap = await dispatch('pokemonBox/duplicate', '001') +// mind the await! +// idMap will look like this: +{'001': dupeId} +// dupeId will be a string with the ID of the duplicate! +``` -- *id:* the doc id returned in `change.doc.id` (see firestore documentation for more info) -- *doc:* the doc returned in `change.doc.data()` (see firestore documentation for more info) +In the example above, if Bulbasaur ('001') was duplicated and the new document has random ID `'123abc'` the `idMap` will be `{'001': '123abc'}`. + +### Duplicate batch + +This is how you duplicate a batch of documents: ```js +const idMap = await dispatch('pokemonBox/duplicateBatch', ['001', '004', '007']) +// idMap will look like this: { - // your other vuex-easy-fire config... - serverChange: { - addedHook: function (updateStore, doc, id, store) { updateStore(doc) }, - modifiedHook: function (updateStore, doc, id, store) { updateStore(doc) }, - removedHook: function (updateStore, doc, id, store) { updateStore(doc) }, - } + '001': 'some-random-new-ID-1', + '004': 'some-random-new-ID-2', + '007': 'some-random-new-ID-3', } ``` -Please make sure to check the overview of execution timings of hooks, in the next chapter: - -## Execution timings of hooks - -Notice that the `created_at` and `updated_at` fields mentioned below is used by default, but can be disabled. To disable just add them to your [guard config](#fillables-and-guard). - -**Collection mode hooks** - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
change typelocalserver
insertion - without created_at -
    -
  1. sync.insertHook
  2. -
-
- with created_at -
    -
  1. sync.insertHook
  2. -
  3. serverChange.modifiedHook
  4. -
-
serverChange.addedHook
modification - without updated_at -
    -
  1. sync.patchHook
  2. -
-
- with updated_at -
    -
  1. sync.patchHook
  2. -
  3. serverChange.modifiedHook
  4. -
-
serverChange.modifiedHook
deletion -
    -
  1. sync.deleteHook
  2. -
  3. serverChange.removedHook
  4. -
-
serverChange.removedHook
after openDBChannelserverChange.addedHook is executed once for each doc
- -**Doc mode hooks** - - - - - - - - - - - - - - - - - -
change typelocalserver
modification - without updated_at -
    -
  1. sync.patchHook
  2. -
-
- with updated_at -
    -
  1. sync.patchHook
  2. -
  3. serverChange.modifiedHook
  4. -
-
serverChange.modifiedHook
after openDBChannelserverChange.modifiedHook is executed once
- -### Note about the serverChange hooks executing on local changes - -I have done my best to limit the hooks to only be executed on the proper events. The server hooks are executed during Firestore's [onSnapshot events](https://firebase.google.com/docs/firestore/query-data/listen). - -The reason for `updated_at` to trigger `serverChange.modifiedHook` even on just a local change, is because `updated_at` uses Firestore's `firebase.firestore.FieldValue.serverTimestamp()` which is replaced by a timestamp on the server and therefor there is a "server change". +This way you can use the result if you need to do extra things to your duplicated docs and you will know for each ID which new ID was used to make a duplication. ## defaultValues set after server retrieval @@ -318,6 +200,29 @@ const docToBeInserted = {date: null} To learn more about Firestore's Timestamp format see [here](https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp). +## Shortcut: set(path, doc) + +Inside Vue component templates there is a shortcut for `dispatch('module/set', newVal)`. If you enable support for my other library called 'vuex-easy-access' you will be able to just use `set('module', newVal)` instead! + +For this shortcut usage, import the npm module 'vuex-easy-access' when you initialise your store and add it as plugin. Pass the 'vuex-easy-firestore' plugin first and **the 'vuex-easy-access' plugin second** for it to work properly. + +Also add `{vuexEasyFirestore: true}` in the options when you initialise 'vuex-easy-access' like so: + +```js +import vuexEasyAccess from 'vuex-easy-access' +const easyAccess = vuexEasyAccess({vuexEasyFirestore: true}) + +const store = { + plugins: [easyFirestoreModules, easyAccess] +} +``` + +Please check the relevant documentation [on the vuex-easy-access repository](https://mesqueeb.github.io/vuex-easy-access/advanced.html#firestore-integration-for-google-firebase)! + +### About 'vuex-easy-access' + +Vuex easy access has a lot of different features to make working with your store extremely easy. The main purpose of that library is to be able to do any kind of mutation to your store directly from the templates without having to set up actions yourself. It is especially usefull when working with wildcards. Please see the [introduction on Vuex Easy Access here](https://mesqueeb.github.io/vuex-easy-access/). + ## Pass Firebase dependency Vuex Easy Firestore will automatically use Firebase as a peer dependency to access `Firebase.auth()` etc. If you want to pass a Firebase instance you have instantiated yourself you can do so like this: diff --git a/docs/guide.md b/docs/guide.md index cf58cc8f..1cdf14dc 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -106,7 +106,7 @@ dispatch('moduleName/insert', newDoc) As you can see in the example above, each vuex-easy-firestore module has a getter called `dbRef` with the reference of your `firestorePath`. So when you add `.doc().id` to that reference you will "create" a new ID, just how Firestore would do it. This way you can do whatever you want with the ID before / after the insert. -Please note you can also access the ID (even if you don't manually pass it) in the [hooks](extra-features.html#hooks-before-insert-patch-delete). +Please note you can also access the ID (even if you don't manually pass it) in the [hooks](hooks.html#hooks). ## 'doc' mode @@ -144,14 +144,6 @@ When working with a single doc, your document updates will automatically receive - `updated_at` uses: `Firebase.firestore.FieldValue.serverTimestamp()` - `updated_by` will automatically fill in the userId -## Shortcut: set(path, doc) - -Inside Vue component templates you can also access the `set` action through a shortcut: `$store.set(path, doc)`. Or with our path: `$store.set('userData', doc)`. - -For this shortcut usage, import the npm module 'vuex-easy-access' and just add `{vuexEasyFirestore: true}` in its options. Please also check the relevant documentation [on the vuex-easy-access repository](https://mesqueeb.github.io/vuex-easy-access/advanced.html#firestore-integration-for-google-firebase)! - -Please note that **it is important to pass the 'vuex-easy-firestore' plugin first**, and the 'vuex-easy-access' plugin second for it to work properly. - ## Multiple modules with 2-way sync Of course you can have multiple vuex modules, all in sync with different firestore paths. @@ -231,7 +223,7 @@ const settingsModule = { > Only for 'collection' mode. -In cases you don't want to loop through items you can also use the special batch actions below. The main difference is you will have separate hooks (see [hooks](extra-features.html#hooks-before-insert-patch-delete)), and batches are optimised to update the vuex store first for all changes and the syncs to firestore last. +In cases you don't want to loop through items you can also use the special batch actions below. The main difference is you will have separate hooks (see [hooks](hooks.html#hooks)), and batches are optimised to update the vuex store first for all changes and the syncs to firestore last. ```js dispatch('moduleName/insertBatch', docs) // an array of docs @@ -241,11 +233,61 @@ dispatch('moduleName/deleteBatch', ids) // an array of ids > All batch actions will return a promise resolving to an array of the edited / added ids. +## Query data (filters) + +> Only for 'collection' mode. + +Just as in Firestore's [onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) listener, you can set `where` and `orderBy` filters to filter which docs are retrieved and synced. + +- *where:* arrays of `parameters` that get passed on to firestore's `.where(...parameters)` +- *orderBy:* a single `array` that gets passed on to firestore's `.orderBy(...array)` + +### Usage: + +```js +const where = [ // an array of arrays + ['certain_field', '==', false], + ['another_field', '==', true], +] +const orderBy = ['created_date'] // or more params + +// Add to openDBChannel: +store.dispatch('myModule/openDBChannel', {where, orderBy}) // like this + +// OR +// Add to your vuex-easy-fire module in the config +myModule = { + // your other vuex-easy-fire config... + sync: { + where, + orderBy + } +} +``` + +You can also use all kind of variables like `'{userId}'` like so: + +```js +store.dispatch('myModule/openDBChannel', { + where: [ + ['created_by', '==', '{userId}'], + ['some field', '==', '{pathVar}'] + ], + pathVar: 'value' // the actual value to replace {pathVar} with above +}) +``` + +What happens here above is: +- `{userId}` will be automatically replaced with the authenticated user +- `{pathVar}` is a custom variable that will be replaced with `'value'` + +For more information on custom variables, see the chapter on [variables for firestorePath or filters](vuex-easy-firestore/extra-features.html#variables-for-firestorepath-or-filters). + ## Fetching docs (with different filters) > Only for 'collection' mode. -Say that you have a default filter set on the documents you are syncing when you `openDBChannel` (see [Filters](extra-features.html#filters)). And you want to fetch extra documents with other filters. (eg. archived posts) In this case you can use the fetch actions to retrieve documents from the same firestore path your module is synced to: +Say that you have a default filter set on the documents you are syncing when you `openDBChannel` (see [Query data](#query-data-filters) above). And you want to fetch extra documents with other filters. (eg. archived posts) In this case you can use the fetch actions to retrieve documents from the same firestore path your module is synced to: - `dispatch('fetch')` for manual handling the fetched docs - `dispatch('fetchAndAdd')` for fetching and automatically adding the docs to the module like your other docs @@ -321,44 +363,3 @@ You can change the default fetch limit like so: }, } ``` - -## Duplicating docs - -> Only for 'collection' mode. - -You can duplicate a document really simply by dispatching 'duplicate' and passing the id of the target document. - -```js -// let's duplicate Bulbasaur who has the id '001' -dispatch('pokemonBox/duplicate', '001') -``` - -This will create a copy of Bulbasaur (and all its props) with a random new ID. The duplicated doc will automatically be added to your vuex module and synced as well. - -If you need to know which new ID was generated for the duplicate, you can retrieve it from the action: - -```js -const idMap = await dispatch('pokemonBox/duplicate', '001') -// mind the await! -// idMap will look like this: -{'001': dupeId} -// dupeId will be a string with the ID of the duplicate! -``` - -In the example above, if Bulbasaur ('001') was duplicated and the new document has random ID `'123abc'` the `idMap` will be `{'001': '123abc'}`. - -### Duplicate batch - -This is how you duplicate a batch of documents: - -```js -const idMap = await dispatch('pokemonBox/duplicateBatch', ['001', '004', '007']) -// idMap will look like this: -{ - '001': 'some-random-new-ID-1', - '004': 'some-random-new-ID-2', - '007': 'some-random-new-ID-3', -} -``` - -This way you can use the result if you need to do extra things to your duplicated docs and you will know for each ID which new ID was used to make a duplication. diff --git a/docs/hooks.md b/docs/hooks.md new file mode 100644 index 00000000..f671e615 --- /dev/null +++ b/docs/hooks.md @@ -0,0 +1,147 @@ +# Hooks + +A hook is a function do anything the doc (the doc object) before the store mutation occurs. You can even modify the docs, or add fields based on conditional checks etc. + +## Hooks on local changes + +Hooks must be defined inside your vuex module under `sync`. Below are the examples of all possible hooks that will trigger on 'local' changes. Please also check the overview of [execution timings of hooks](#execution-timings-of-hooks) to understand the difference between 'local' and 'server' changes. + +```js +{ + // your other vuex-easy-fire config... + sync: { + insertHook: function (updateStore, doc, store) { updateStore(doc) }, + patchHook: function (updateStore, doc, store) { updateStore(doc) }, + deleteHook: function (updateStore, id, store) { updateStore(id) }, + // Batches have separate hooks! + insertBatchHook: function (updateStore, docs, store) { updateStore(doc) }, + patchBatchHook: function (updateStore, doc, ids, store) { updateStore(doc, ids) }, + deleteBatchHook: function (updateStore, ids, store) { updateStore(ids) }, + } +} +``` + +The `doc` passed in the `insert` and `patch` hooks will also have an `id` field which is either the new id or the id of the doc to be patched. + +::: warning You must call `updateStore(doc)` to make the store mutation. +But you may choose not to call this to abort the mutation. If you do not call `updateStore(doc)` nothing will happen. +::: + +## Hooks after server changes + +Exactly the same as above, but for changes that have occured on the server. You also have some extra parameters to work with: + +- *id:* the doc id returned in `change.doc.id` (see firestore documentation for more info) +- *doc:* the doc returned in `change.doc.data()` (see firestore documentation for more info) + +```js +{ + // your other vuex-easy-fire config... + serverChange: { + addedHook: function (updateStore, doc, id, store) { updateStore(doc) }, + modifiedHook: function (updateStore, doc, id, store) { updateStore(doc) }, + removedHook: function (updateStore, doc, id, store) { updateStore(doc) }, + } +} +``` + +Please make sure to check the overview of execution timings of hooks, in the next chapter: + +## Execution timings of hooks + +Notice that the `created_at` and `updated_at` fields mentioned below is used by default, but can be disabled. To disable just add them to your [guard config](extra-features.html#fillables-and-guard). + +**Hooks on 'collection' mode** + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
change typelocalserver
insertion + without created_at +
    +
  1. sync.insertHook
  2. +
+
+ with created_at +
    +
  1. sync.insertHook
  2. +
  3. serverChange.modifiedHook
  4. +
+
serverChange.addedHook
modification + without updated_at +
    +
  1. sync.patchHook
  2. +
+
+ with updated_at +
    +
  1. sync.patchHook
  2. +
  3. serverChange.modifiedHook
  4. +
+
serverChange.modifiedHook
deletion +
    +
  1. sync.deleteHook
  2. +
  3. serverChange.removedHook
  4. +
+
serverChange.removedHook
after openDBChannelserverChange.addedHook is executed once for each doc
+ +**Hooks on 'doc' mode** + + + + + + + + + + + + + + + + + +
change typelocalserver
modification + without updated_at +
    +
  1. sync.patchHook
  2. +
+
+ with updated_at +
    +
  1. sync.patchHook
  2. +
  3. serverChange.modifiedHook
  4. +
+
serverChange.modifiedHook
after openDBChannelserverChange.modifiedHook is executed once
+ +### Note about the serverChange hooks executing on local changes + +I have done my best to limit the hooks to only be executed on the proper events. The server hooks are executed during Firestore's [onSnapshot events](https://firebase.google.com/docs/firestore/query-data/listen). + +The reason for `updated_at` to trigger `serverChange.modifiedHook` even on just a local change, is because `updated_at` uses Firestore's `firebase.firestore.FieldValue.serverTimestamp()` which is replaced by a timestamp on the server and therefor there is a "server change". diff --git a/docs/ja/README.md b/docs/ja/README.md deleted file mode 100644 index 0e4965fd..00000000 --- a/docs/ja/README.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -home: true -# heroImage: /hero.png -actionText: 始めよう → -actionLink: /setup -features: -- title: 何よりシンプル - details: Minimal setup to get a vuex-module synced with Firestore automatically. -- title: パワフル - details: Easy to use features include filtering, hooks, automatic Firestore Timestamp conversion & much more. -- title: パフォーマンスが第一 - details: Automatic 2-way sync is fully optimised through api call batches. -footer: MIT Licensed | Copyright © 2018-present Luca Ban - Mesqueeb ---- - -# Overview - -たった4つの行のコードを追加するだけで、VuexモジュールがFirestoreと自動的に同期される状態にできる。 - -```js -const userModule = { - firestorePath: 'users/{userId}/data', - firestoreRefType: 'collection', // or 'doc' - moduleName: 'userData', - statePropName: 'docs', - // モジュールのその他 state, actions など -} -// vuex-easy-firestoreでこのuserModuleをvuex pluginとしてstoreに入れるだけ -``` - -and Alakazam! Now you have a vuex module called `userData` with `state: {docs: {}}`. -All firestore documents in your collection will be added with the doc's id as key inside `docs` in your state. - -Now you just update and add docs with `dispatch('userData/set', newItem)` and forget about the rest! - -# Features - -- Complete 2-way sync between your Vuex module & Firestore -- [Automatic Firestore Timestamp conversion](extra-features.html#defaultvalues-set-after-server-retrieval) -- [Fillables](extra-features.html#fillables-and-guard) (limit props able to sync) -- [Hooks](extra-features.html#hooks-before-insert-patch-delete) (before / after sync) -- [Where / orderBy filters](extra-features.html#filters) - -# Motivation - -I didn't like writing an entire an API wrapper from scratch for firestore every single project. If only a vuex module could be in perfect sync with firestore without having to code all the boilerplate yourself... - -And that's how Vuex Easy Firestore was born. - -
Installation and setup →
- -# Support - -If you like what I built, you can say thanks by buying me a coffee! :) - -Buy me a coffeeBuy me a coffee - -Thank you so much!! Every little bit helps. diff --git a/docs/setup.md b/docs/setup.md index c804212d..599911de 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -89,7 +89,7 @@ Firebase.auth().onAuthStateChanged(user => { Vuex-easy-firestore uses Firestore's [onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) to retrieve the doc(s) from the server and has added logic to save those doc(s) in a vuex module. If you do not want to open an `onSnapshot` listener you can also use [fetch](guide.html#fetching-docs-with-different-filters) instead. -Also note that just like Firestore you can use `where` and `orderBy` filters (see [Filters](extra-features.html#filters)). +Also note that just like Firestore you can use `where` and `orderBy` filters (see [Filters](guide.html#query-data-filters)). ### Close DB channel From 3af21bf0a5f6c0d1f18af047394f8eb0e3ed7bf4 Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 13:40:52 +0900 Subject: [PATCH 4/9] =?UTF-8?q?typo=20=F0=9F=92=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide.md b/docs/guide.md index 1cdf14dc..60c1653e 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -281,7 +281,7 @@ What happens here above is: - `{userId}` will be automatically replaced with the authenticated user - `{pathVar}` is a custom variable that will be replaced with `'value'` -For more information on custom variables, see the chapter on [variables for firestorePath or filters](vuex-easy-firestore/extra-features.html#variables-for-firestorepath-or-filters). +For more information on custom variables, see the chapter on [variables for firestorePath or filters](extra-features.html#variables-for-firestorepath-or-filters). ## Fetching docs (with different filters) From 3e9c7c6576bc5068a7a88a02e02a950d86eed1f9 Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 15:08:58 +0900 Subject: [PATCH 5/9] =?UTF-8?q?Allow=20patch=20<=201000ms=20after=20insert?= =?UTF-8?q?=20=F0=9F=96=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/index.cjs.js | 14 ++++++++++++++ dist/index.esm.js | 14 ++++++++++++++ src/module/actions.ts | 14 ++++++++++++++ test/actions.js | 22 +++++++++++++++++++++- test/helpers/index.cjs.js | 14 ++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/dist/index.cjs.js b/dist/index.cjs.js index 77d88d3f..294fb97a 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -708,6 +708,20 @@ function pluginActions (Firebase$$1) { return console.error('[vuex-easy-firestore] ids needs to be an array'); if (id) ids.push(id); + // EXTRA: check if doc is being inserted if so + state._sync.syncStack.inserts.forEach(function (newDoc, newDocIndex) { + // get the index of the id that is also in the insert stack + var indexIdInInsert = ids.indexOf(newDoc.id); + if (indexIdInInsert === -1) + return; + // the doc trying to be synced is also in insert + // prepare the doc as new doc: + var patchDoc = getters.prepareForInsert([doc])[0]; + // replace insert sync stack with merged item: + state._sync.syncStack.inserts[newDocIndex] = merge(newDoc, patchDoc); + // empty out the id that was to be patched: + ids.splice(indexIdInInsert, 1); + }); // 1. Prepare for patching var syncStackItems = getters.prepareForPatch(ids, doc); // 2. Push to syncStack diff --git a/dist/index.esm.js b/dist/index.esm.js index 00910e87..ee6a5f44 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -703,6 +703,20 @@ function pluginActions (Firebase$$1) { return console.error('[vuex-easy-firestore] ids needs to be an array'); if (id) ids.push(id); + // EXTRA: check if doc is being inserted if so + state._sync.syncStack.inserts.forEach(function (newDoc, newDocIndex) { + // get the index of the id that is also in the insert stack + var indexIdInInsert = ids.indexOf(newDoc.id); + if (indexIdInInsert === -1) + return; + // the doc trying to be synced is also in insert + // prepare the doc as new doc: + var patchDoc = getters.prepareForInsert([doc])[0]; + // replace insert sync stack with merged item: + state._sync.syncStack.inserts[newDocIndex] = merge(newDoc, patchDoc); + // empty out the id that was to be patched: + ids.splice(indexIdInInsert, 1); + }); // 1. Prepare for patching var syncStackItems = getters.prepareForPatch(ids, doc); // 2. Push to syncStack diff --git a/src/module/actions.ts b/src/module/actions.ts index dfd9b6c6..b63bdadd 100644 --- a/src/module/actions.ts +++ b/src/module/actions.ts @@ -42,6 +42,20 @@ export default function (Firebase: any): AnyObject { if (!isArray(ids)) return console.error('[vuex-easy-firestore] ids needs to be an array') if (id) ids.push(id) + // EXTRA: check if doc is being inserted if so + state._sync.syncStack.inserts.forEach((newDoc, newDocIndex) => { + // get the index of the id that is also in the insert stack + const indexIdInInsert = ids.indexOf(newDoc.id) + if (indexIdInInsert === -1) return + // the doc trying to be synced is also in insert + // prepare the doc as new doc: + const patchDoc = getters.prepareForInsert([doc])[0] + // replace insert sync stack with merged item: + state._sync.syncStack.inserts[newDocIndex] = merge(newDoc, patchDoc) + // empty out the id that was to be patched: + ids.splice(indexIdInInsert, 1) + }) + // 1. Prepare for patching const syncStackItems = getters.prepareForPatch(ids, doc) diff --git a/test/actions.js b/test/actions.js index c2626e5d..5d8ec891 100644 --- a/test/actions.js +++ b/test/actions.js @@ -23,7 +23,6 @@ test('[COLLECTION] set with no id', async t => { await wait(2) // insert set id = await store.dispatch('pokemonBox/insert', {name: 'Unown'}) - console.log('id set with no id → ', id) t.truthy(box.pokemon[id]) t.is(box.pokemon[id].name, 'Unown') await wait(2) @@ -56,6 +55,27 @@ test('[COLLECTION] set with no id', async t => { t.deepEqual(doc.name, {is: 'nested1'}) }) +test('[COLLECTION] insert and patch right after each other', async t => { + await wait(2) + // insert + const id = boxRef.doc().id + console.log('id → ', id) + store.dispatch('pokemonBox/insert', {id, name: 'Mew', type: {normal: true}}) + t.truthy(box.pokemon[id]) + t.is(box.pokemon[id].name, 'Mew') + t.deepEqual(box.pokemon[id].type, {normal: true}) + // patch + store.dispatch('pokemonBox/patch', {id, type: {psychic: true}}) + t.is(box.pokemon[id].name, 'Mew') + t.deepEqual(box.pokemon[id].type, {normal: true, psychic: true}) + // await server + await wait(2) + const docR = await boxRef.doc(id).get() + const doc = docR.data() + t.is(doc.name, 'Mew') + t.deepEqual(doc.type, {normal: true, psychic: true}) +}) + test('[COLLECTION] set & delete: top lvl', async t => { const id = boxRef.doc().id const id2 = boxRef.doc().id diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index ed8bd00e..76f88158 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -843,6 +843,20 @@ function pluginActions (Firebase$$1) { return console.error('[vuex-easy-firestore] ids needs to be an array'); if (id) ids.push(id); + // EXTRA: check if doc is being inserted if so + state._sync.syncStack.inserts.forEach(function (newDoc, newDocIndex) { + // get the index of the id that is also in the insert stack + var indexIdInInsert = ids.indexOf(newDoc.id); + if (indexIdInInsert === -1) + return; + // the doc trying to be synced is also in insert + // prepare the doc as new doc: + var patchDoc = getters.prepareForInsert([doc])[0]; + // replace insert sync stack with merged item: + state._sync.syncStack.inserts[newDocIndex] = merge(newDoc, patchDoc); + // empty out the id that was to be patched: + ids.splice(indexIdInInsert, 1); + }); // 1. Prepare for patching var syncStackItems = getters.prepareForPatch(ids, doc); // 2. Push to syncStack From b18a4c4450bf6fcbea1219bdc7683073426ba404 Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 15:21:46 +0900 Subject: [PATCH 6/9] =?UTF-8?q?replace=20doc=20id=20in=20doc-mode=20?= =?UTF-8?q?=F0=9F=A7=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/index.cjs.js | 9 ++++++--- dist/index.esm.js | 9 ++++++--- src/module/getters.ts | 7 +++++-- test/getters.js | 29 +++++++++++++++-------------- test/helpers/index.cjs.js | 9 ++++++--- 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/dist/index.cjs.js b/dist/index.cjs.js index 294fb97a..d1a8ef79 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -1002,7 +1002,7 @@ function pluginActions (Firebase$$1) { if (source === 'local') return resolve(); var doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues); - var id = getters.firestorePathComplete.split('/').pop(); + var id = getters.docModeId; doc.id = id; handleDoc('modified', id, doc); return resolve(); @@ -1303,6 +1303,9 @@ function pluginGetters (Firebase$$1) { collectionMode: function (state, getters, rootState) { return (state._conf.firestoreRefType.toLowerCase() === 'collection'); }, + docModeId: function (state, getters) { + return getters.firestorePathComplete.split('/').pop(); + }, prepareForPatch: function (state, getters, rootState, rootGetters) { return function (ids, doc) { if (ids === void 0) { ids = []; } @@ -1310,7 +1313,7 @@ function pluginGetters (Firebase$$1) { // get relevant data from the storeRef var collectionMode = getters.collectionMode; if (!collectionMode) - ids.push('singleDoc'); + ids.push(getters.docModeId); // returns {object} -> {id: data} return ids.reduce(function (carry, id) { var patchData = {}; @@ -1372,7 +1375,7 @@ function pluginGetters (Firebase$$1) { cleanedPath = path.substring(path.indexOf('.') + 1); } else { - id = 'singleDoc'; + id = getters.docModeId; cleanedPath = path; } cleanedPatchData[cleanedPath] = Firebase$$1.firestore.FieldValue.delete(); diff --git a/dist/index.esm.js b/dist/index.esm.js index ee6a5f44..93fde41f 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -997,7 +997,7 @@ function pluginActions (Firebase$$1) { if (source === 'local') return resolve(); var doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues); - var id = getters.firestorePathComplete.split('/').pop(); + var id = getters.docModeId; doc.id = id; handleDoc('modified', id, doc); return resolve(); @@ -1298,6 +1298,9 @@ function pluginGetters (Firebase$$1) { collectionMode: function (state, getters, rootState) { return (state._conf.firestoreRefType.toLowerCase() === 'collection'); }, + docModeId: function (state, getters) { + return getters.firestorePathComplete.split('/').pop(); + }, prepareForPatch: function (state, getters, rootState, rootGetters) { return function (ids, doc) { if (ids === void 0) { ids = []; } @@ -1305,7 +1308,7 @@ function pluginGetters (Firebase$$1) { // get relevant data from the storeRef var collectionMode = getters.collectionMode; if (!collectionMode) - ids.push('singleDoc'); + ids.push(getters.docModeId); // returns {object} -> {id: data} return ids.reduce(function (carry, id) { var patchData = {}; @@ -1367,7 +1370,7 @@ function pluginGetters (Firebase$$1) { cleanedPath = path.substring(path.indexOf('.') + 1); } else { - id = 'singleDoc'; + id = getters.docModeId; cleanedPath = path; } cleanedPatchData[cleanedPath] = Firebase$$1.firestore.FieldValue.delete(); diff --git a/src/module/getters.ts b/src/module/getters.ts index d75bf467..9bd6ad37 100644 --- a/src/module/getters.ts +++ b/src/module/getters.ts @@ -63,11 +63,14 @@ export default function (Firebase: any): AnyObject { collectionMode: (state, getters, rootState) => { return (state._conf.firestoreRefType.toLowerCase() === 'collection') }, + docModeId: (state, getters) => { + return getters.firestorePathComplete.split('/').pop() + }, prepareForPatch: (state, getters, rootState, rootGetters) => (ids = [], doc = {}) => { // get relevant data from the storeRef const collectionMode = getters.collectionMode - if (!collectionMode) ids.push('singleDoc') + if (!collectionMode) ids.push(getters.docModeId) // returns {object} -> {id: data} return ids.reduce((carry, id) => { let patchData: AnyObject = {} @@ -122,7 +125,7 @@ export default function (Firebase: any): AnyObject { id = path.substring(0, path.indexOf('.')) cleanedPath = path.substring(path.indexOf('.') + 1) } else { - id = 'singleDoc' + id = getters.docModeId cleanedPath = path } cleanedPatchData[cleanedPath] = Firebase.firestore.FieldValue.delete() diff --git a/test/getters.js b/test/getters.js index a71b9ade..261e89d0 100644 --- a/test/getters.js +++ b/test/getters.js @@ -52,26 +52,27 @@ test('[prepareForPatch] doc', async t => { char._conf.sync.fillables = ['body', 'del', 'pathdel'] char._conf.sync.guard = [] // prepareForPatch + const docModeId = store.getters['mainCharacter/docModeId'] res = store.getters['mainCharacter/prepareForPatch']([], {body: 'new', del: Firebase.firestore.FieldValue.delete()}) - t.deepEqual(Object.keys(res), ['singleDoc']) - t.is(res['singleDoc'].body, 'new') - t.is(res['singleDoc'].del._methodName, 'FieldValue.delete') - t.is(res['singleDoc'].id, 'singleDoc') - t.is(res['singleDoc'].updated_by, 'charlie') - t.is(res['singleDoc'].updated_at._methodName, 'FieldValue.serverTimestamp') + t.deepEqual(Object.keys(res), [docModeId]) + t.is(res[docModeId].body, 'new') + t.is(res[docModeId].del._methodName, 'FieldValue.delete') + t.is(res[docModeId].id, docModeId) + t.is(res[docModeId].updated_by, 'charlie') + t.is(res[docModeId].updated_at._methodName, 'FieldValue.serverTimestamp') // prepareForPropDeletion res = store.getters['mainCharacter/prepareForPropDeletion']('1.pathdel.a') - t.is(res['singleDoc'].id, 'singleDoc') - t.is(res['singleDoc']['1.pathdel.a']._methodName, 'FieldValue.delete') - t.is(res['singleDoc'].updated_by, 'charlie') - t.is(res['singleDoc'].updated_at._methodName, 'FieldValue.serverTimestamp') + t.is(res[docModeId].id, docModeId) + t.is(res[docModeId]['1.pathdel.a']._methodName, 'FieldValue.delete') + t.is(res[docModeId].updated_by, 'charlie') + t.is(res[docModeId].updated_at._methodName, 'FieldValue.serverTimestamp') // different fillables & guard char._conf.sync.guard = ['updated_at', 'updated_by', 'id'] res = store.getters['mainCharacter/prepareForPropDeletion']('1.pathdel.a') - t.is(res['singleDoc'].id, 'singleDoc') // id stays even if it's added to guard - t.is(res['singleDoc']['1.pathdel.a']._methodName, 'FieldValue.delete') - t.is(res['singleDoc'].updated_by, undefined) - t.is(res['singleDoc'].updated_at, undefined) + t.is(res[docModeId].id, docModeId) // id stays even if it's added to guard + t.is(res[docModeId]['1.pathdel.a']._methodName, 'FieldValue.delete') + t.is(res[docModeId].updated_by, undefined) + t.is(res[docModeId].updated_at, undefined) }) test('[whereFilters]', async t => { diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index 76f88158..65957e78 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -1137,7 +1137,7 @@ function pluginActions (Firebase$$1) { if (source === 'local') return resolve(); var doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues); - var id = getters.firestorePathComplete.split('/').pop(); + var id = getters.docModeId; doc.id = id; handleDoc('modified', id, doc); return resolve(); @@ -1438,6 +1438,9 @@ function pluginGetters (Firebase$$1) { collectionMode: function (state, getters, rootState) { return (state._conf.firestoreRefType.toLowerCase() === 'collection'); }, + docModeId: function (state, getters) { + return getters.firestorePathComplete.split('/').pop(); + }, prepareForPatch: function (state, getters, rootState, rootGetters) { return function (ids, doc) { if (ids === void 0) { ids = []; } @@ -1445,7 +1448,7 @@ function pluginGetters (Firebase$$1) { // get relevant data from the storeRef var collectionMode = getters.collectionMode; if (!collectionMode) - ids.push('singleDoc'); + ids.push(getters.docModeId); // returns {object} -> {id: data} return ids.reduce(function (carry, id) { var patchData = {}; @@ -1507,7 +1510,7 @@ function pluginGetters (Firebase$$1) { cleanedPath = path.substring(path.indexOf('.') + 1); } else { - id = 'singleDoc'; + id = getters.docModeId; cleanedPath = path; } cleanedPatchData[cleanedPath] = Firebase$$1.firestore.FieldValue.delete(); From de986cdd79e15a663fef5adc1408f88b5bbab75e Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 15:27:12 +0900 Subject: [PATCH 7/9] =?UTF-8?q?arg.=20'where'=20instead=20of=20'whereFilte?= =?UTF-8?q?rs'=20=F0=9F=96=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/index.cjs.js | 38 ++++++++++++++++++--------------- dist/index.esm.js | 38 ++++++++++++++++++--------------- docs/guide.md | 8 +++---- src/module/actions.ts | 20 +++++++++-------- src/module/getters.ts | 2 +- src/utils/apiHelpers.ts | 8 +++---- test/DBChannel.js | 6 +++--- test/getters.js | 8 +++---- test/helpers/index.cjs.js | 38 ++++++++++++++++++--------------- test/mutations.js | 4 ++-- test/utils/apiHelpers.js | 4 ++-- types/src/utils/apiHelpers.d.ts | 4 ++-- types/utils/apiHelpers.d.ts | 4 ++-- 13 files changed, 98 insertions(+), 84 deletions(-) diff --git a/dist/index.cjs.js b/dist/index.cjs.js index d1a8ef79..4513fc16 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -589,17 +589,17 @@ function stringifyParams(params) { }).join(); } /** - * Gets an object with {whereFilters, orderBy} filters and returns a unique identifier for that + * Gets an object with {where, orderBy} filters and returns a unique identifier for that * * @export - * @param {AnyObject} [whereOrderBy={}] whereOrderBy {whereFilters, orderBy} + * @param {AnyObject} [whereOrderBy={}] whereOrderBy {where, orderBy} * @returns {string} */ function createFetchIdentifier(whereOrderBy) { if (whereOrderBy === void 0) { whereOrderBy = {}; } var identifier = ''; - if ('whereFilters' in whereOrderBy) { - identifier += '[where]' + whereOrderBy.whereFilters.map(function (where) { return stringifyParams(where); }).join(); + if ('where' in whereOrderBy) { + identifier += '[where]' + whereOrderBy.where.map(function (where) { return stringifyParams(where); }).join(); } if ('orderBy' in whereOrderBy) { identifier += '[orderBy]' + stringifyParams(whereOrderBy.orderBy); @@ -825,26 +825,28 @@ function pluginActions (Firebase$$1) { }); }, fetch: function (_a, _b - // whereFilters: [['archived', '==', true]] + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; - var _c = _b === void 0 ? { whereFilters: [], orderBy: [] } : _b - // whereFilters: [['archived', '==', true]] + var _c = _b === void 0 ? { where: [], whereFilters: [], orderBy: [] } : _b + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] - , _d = _c.whereFilters, whereFilters = _d === void 0 ? [] : _d, _e = _c.orderBy, orderBy = _e === void 0 ? [] : _e; + , _d = _c.where, where = _d === void 0 ? [] : _d, _e = _c.whereFilters, whereFilters = _e === void 0 ? [] : _e, _f = _c.orderBy, orderBy = _f === void 0 ? [] : _f; + if (whereFilters.length) + where = whereFilters; return new Promise(function (resolve, reject) { if (state._conf.logging) console.log('[vuex-easy-firestore] Fetch starting'); if (!getters.signedIn) return resolve(); - var identifier = createFetchIdentifier({ whereFilters: whereFilters, orderBy: orderBy }); + var identifier = createFetchIdentifier({ where: where, orderBy: orderBy }); var fetched = state._sync.fetched[identifier]; // We've never fetched this before: if (!fetched) { var ref_1 = getters.dbRef; // apply where filters and orderBy - whereFilters.forEach(function (paramsArr) { + where.forEach(function (paramsArr) { ref_1 = ref_1.where.apply(ref_1, paramsArr); }); if (orderBy.length) { @@ -901,15 +903,17 @@ function pluginActions (Firebase$$1) { }); }, fetchAndAdd: function (_a, _b - // whereFilters: [['archived', '==', true]] + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; - var _c = _b === void 0 ? { whereFilters: [], orderBy: [] } : _b - // whereFilters: [['archived', '==', true]] + var _c = _b === void 0 ? { where: [], whereFilters: [], orderBy: [] } : _b + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] - , _d = _c.whereFilters, whereFilters = _d === void 0 ? [] : _d, _e = _c.orderBy, orderBy = _e === void 0 ? [] : _e; - return dispatch('fetch', { whereFilters: whereFilters, orderBy: orderBy }) + , _d = _c.where, where = _d === void 0 ? [] : _d, _e = _c.whereFilters, whereFilters = _e === void 0 ? [] : _e, _f = _c.orderBy, orderBy = _f === void 0 ? [] : _f; + if (whereFilters.length) + where = whereFilters; + return dispatch('fetch', { where: where, orderBy: orderBy }) .then(function (querySnapshot) { if (querySnapshot.done === true) return querySnapshot; @@ -961,7 +965,7 @@ function pluginActions (Firebase$$1) { var dbRef = getters.dbRef; // apply where filters and orderBy if (getters.collectionMode) { - getters.whereFilters.forEach(function (whereParams) { + getters.where.forEach(function (whereParams) { dbRef = dbRef.where.apply(dbRef, whereParams); }); if (state._conf.sync.orderBy.length) { @@ -1417,7 +1421,7 @@ function pluginGetters (Firebase$$1) { return doc; }; }, - whereFilters: function (state, getters) { + where: function (state, getters) { var whereArrays = state._conf.sync.where; return whereArrays.map(function (whereClause) { return whereClause.map(function (param) { diff --git a/dist/index.esm.js b/dist/index.esm.js index 93fde41f..80f6de01 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -584,17 +584,17 @@ function stringifyParams(params) { }).join(); } /** - * Gets an object with {whereFilters, orderBy} filters and returns a unique identifier for that + * Gets an object with {where, orderBy} filters and returns a unique identifier for that * * @export - * @param {AnyObject} [whereOrderBy={}] whereOrderBy {whereFilters, orderBy} + * @param {AnyObject} [whereOrderBy={}] whereOrderBy {where, orderBy} * @returns {string} */ function createFetchIdentifier(whereOrderBy) { if (whereOrderBy === void 0) { whereOrderBy = {}; } var identifier = ''; - if ('whereFilters' in whereOrderBy) { - identifier += '[where]' + whereOrderBy.whereFilters.map(function (where) { return stringifyParams(where); }).join(); + if ('where' in whereOrderBy) { + identifier += '[where]' + whereOrderBy.where.map(function (where) { return stringifyParams(where); }).join(); } if ('orderBy' in whereOrderBy) { identifier += '[orderBy]' + stringifyParams(whereOrderBy.orderBy); @@ -820,26 +820,28 @@ function pluginActions (Firebase$$1) { }); }, fetch: function (_a, _b - // whereFilters: [['archived', '==', true]] + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; - var _c = _b === void 0 ? { whereFilters: [], orderBy: [] } : _b - // whereFilters: [['archived', '==', true]] + var _c = _b === void 0 ? { where: [], whereFilters: [], orderBy: [] } : _b + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] - , _d = _c.whereFilters, whereFilters = _d === void 0 ? [] : _d, _e = _c.orderBy, orderBy = _e === void 0 ? [] : _e; + , _d = _c.where, where = _d === void 0 ? [] : _d, _e = _c.whereFilters, whereFilters = _e === void 0 ? [] : _e, _f = _c.orderBy, orderBy = _f === void 0 ? [] : _f; + if (whereFilters.length) + where = whereFilters; return new Promise(function (resolve, reject) { if (state._conf.logging) console.log('[vuex-easy-firestore] Fetch starting'); if (!getters.signedIn) return resolve(); - var identifier = createFetchIdentifier({ whereFilters: whereFilters, orderBy: orderBy }); + var identifier = createFetchIdentifier({ where: where, orderBy: orderBy }); var fetched = state._sync.fetched[identifier]; // We've never fetched this before: if (!fetched) { var ref_1 = getters.dbRef; // apply where filters and orderBy - whereFilters.forEach(function (paramsArr) { + where.forEach(function (paramsArr) { ref_1 = ref_1.where.apply(ref_1, paramsArr); }); if (orderBy.length) { @@ -896,15 +898,17 @@ function pluginActions (Firebase$$1) { }); }, fetchAndAdd: function (_a, _b - // whereFilters: [['archived', '==', true]] + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; - var _c = _b === void 0 ? { whereFilters: [], orderBy: [] } : _b - // whereFilters: [['archived', '==', true]] + var _c = _b === void 0 ? { where: [], whereFilters: [], orderBy: [] } : _b + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] - , _d = _c.whereFilters, whereFilters = _d === void 0 ? [] : _d, _e = _c.orderBy, orderBy = _e === void 0 ? [] : _e; - return dispatch('fetch', { whereFilters: whereFilters, orderBy: orderBy }) + , _d = _c.where, where = _d === void 0 ? [] : _d, _e = _c.whereFilters, whereFilters = _e === void 0 ? [] : _e, _f = _c.orderBy, orderBy = _f === void 0 ? [] : _f; + if (whereFilters.length) + where = whereFilters; + return dispatch('fetch', { where: where, orderBy: orderBy }) .then(function (querySnapshot) { if (querySnapshot.done === true) return querySnapshot; @@ -956,7 +960,7 @@ function pluginActions (Firebase$$1) { var dbRef = getters.dbRef; // apply where filters and orderBy if (getters.collectionMode) { - getters.whereFilters.forEach(function (whereParams) { + getters.where.forEach(function (whereParams) { dbRef = dbRef.where.apply(dbRef, whereParams); }); if (state._conf.sync.orderBy.length) { @@ -1412,7 +1416,7 @@ function pluginGetters (Firebase$$1) { return doc; }; }, - whereFilters: function (state, getters) { + where: function (state, getters) { var whereArrays = state._conf.sync.where; return whereArrays.map(function (whereClause) { return whereClause.map(function (param) { diff --git a/docs/guide.md b/docs/guide.md index 60c1653e..91b00c1c 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -294,13 +294,13 @@ Say that you have a default filter set on the documents you are syncing when you You can have two extra parameters: -- *whereFilters:* The same as firestore's `.where()`. An array of arrays with the filters you want. eg. `[['field', '==', false], ...]` +- *where:* The same as firestore's `.where()`. An array of arrays with the filters you want. eg. `[['field', '==', false], ...]` - *orderBy:* The same as firestore's `.orderBy()`. eg. `['created_date']` ### Usage example `fetchAndAdd`: ```js -dispatch('pokemonBox/fetchAndAdd', {whereFilters: [['freed', '==', true]], orderBy: ['freedDate']}) +dispatch('pokemonBox/fetchAndAdd', {where: [['freed', '==', true]], orderBy: ['freedDate']}) .then(querySnapshot => { if (querySnapshot.done === true) { // `{done: true}` is returned when everything is already fetched and there are 0 docs: @@ -317,7 +317,7 @@ Using the `fetchAndAdd` method means your documents will be added to your vuex-m ### Usage example `fetch`: ```js -dispatch('pokemonBox/fetch', {whereFilters: [['freed', '==', true]], orderBy: ['freedDate']}) +dispatch('pokemonBox/fetch', {where: [['freed', '==', true]], orderBy: ['freedDate']}) .then(querySnapshot => { if (querySnapshot.done === true) { // `{done: true}` is returned when everything is already fetched and there are 0 docs: @@ -343,7 +343,7 @@ The fetch limit defaults to 50 docs. If you watch to fetch *the next 50 docs* yo ```js function fetchFreedPokemon () { - dispatch('pokemonBox/fetchAndAdd', {whereFilters: [['freed', '==', true]], orderBy: ['freedDate']}) + dispatch('pokemonBox/fetchAndAdd', {where: [['freed', '==', true]], orderBy: ['freedDate']}) } // call once to fetch the first 50: fetchFreedPokemon() diff --git a/src/module/actions.ts b/src/module/actions.ts index b63bdadd..fd6f99b2 100644 --- a/src/module/actions.ts +++ b/src/module/actions.ts @@ -166,20 +166,21 @@ export default function (Firebase: any): AnyObject { }, fetch ( {state, getters, commit, dispatch}, - {whereFilters = [], orderBy = []} = {whereFilters: [], orderBy: []} - // whereFilters: [['archived', '==', true]] + {where = [], whereFilters = [], orderBy = []} = {where: [], whereFilters: [], orderBy: []} + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { + if (whereFilters.length) where = whereFilters return new Promise((resolve, reject) => { if (state._conf.logging) console.log('[vuex-easy-firestore] Fetch starting') if (!getters.signedIn) return resolve() - const identifier = createFetchIdentifier({whereFilters, orderBy}) + const identifier = createFetchIdentifier({where, orderBy}) const fetched = state._sync.fetched[identifier] // We've never fetched this before: if (!fetched) { let ref = getters.dbRef // apply where filters and orderBy - whereFilters.forEach(paramsArr => { + where.forEach(paramsArr => { ref = ref.where(...paramsArr) }) if (orderBy.length) { @@ -236,11 +237,12 @@ export default function (Firebase: any): AnyObject { }, fetchAndAdd ( {state, getters, commit, dispatch}, - {whereFilters = [], orderBy = []} = {whereFilters: [], orderBy: []} - // whereFilters: [['archived', '==', true]] + {where = [], whereFilters = [], orderBy = []} = {where: [], whereFilters: [], orderBy: []} + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { - return dispatch('fetch', {whereFilters, orderBy}) + if (whereFilters.length) where = whereFilters + return dispatch('fetch', {where, orderBy}) .then(querySnapshot => { if (querySnapshot.done === true) return querySnapshot if (isFunction(querySnapshot.forEach)) { @@ -291,7 +293,7 @@ export default function (Firebase: any): AnyObject { let dbRef = getters.dbRef // apply where filters and orderBy if (getters.collectionMode) { - getters.whereFilters.forEach(whereParams => { + getters.where.forEach(whereParams => { dbRef = dbRef.where(...whereParams) }) if (state._conf.sync.orderBy.length) { @@ -329,7 +331,7 @@ export default function (Firebase: any): AnyObject { } if (source === 'local') return resolve() const doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues) - const id = getters.firestorePathComplete.split('/').pop() + const id = getters.docModeId doc.id = id handleDoc('modified', id, doc) return resolve() diff --git a/src/module/getters.ts b/src/module/getters.ts index 9bd6ad37..ce63df7e 100644 --- a/src/module/getters.ts +++ b/src/module/getters.ts @@ -161,7 +161,7 @@ export default function (Firebase: any): AnyObject { doc = filter(doc, fillables, guard) return doc }, - whereFilters: (state, getters) => { + where: (state, getters) => { const whereArrays = state._conf.sync.where return whereArrays.map(whereClause => { return whereClause.map(param => { diff --git a/src/utils/apiHelpers.ts b/src/utils/apiHelpers.ts index 051ca6f8..525b70e2 100644 --- a/src/utils/apiHelpers.ts +++ b/src/utils/apiHelpers.ts @@ -161,16 +161,16 @@ function stringifyParams (params: any[]): string { } /** - * Gets an object with {whereFilters, orderBy} filters and returns a unique identifier for that + * Gets an object with {where, orderBy} filters and returns a unique identifier for that * * @export - * @param {AnyObject} [whereOrderBy={}] whereOrderBy {whereFilters, orderBy} + * @param {AnyObject} [whereOrderBy={}] whereOrderBy {where, orderBy} * @returns {string} */ export function createFetchIdentifier (whereOrderBy: AnyObject = {}): string { let identifier = '' - if ('whereFilters' in whereOrderBy) { - identifier += '[where]' + whereOrderBy.whereFilters.map(where => stringifyParams(where)).join() + if ('where' in whereOrderBy) { + identifier += '[where]' + whereOrderBy.where.map(where => stringifyParams(where)).join() } if ('orderBy' in whereOrderBy) { identifier += '[orderBy]' + stringifyParams(whereOrderBy.orderBy) diff --git a/test/DBChannel.js b/test/DBChannel.js index 4b6709b1..80f07eef 100644 --- a/test/DBChannel.js +++ b/test/DBChannel.js @@ -35,21 +35,21 @@ test('[openDBChannel] check where filter after openDBChannel', async t => { char._conf.sync.where = [['hi.{userId}.docs.{name}', '==', '{big}']] char._sync.userId = 'charlie' // 0. initial path - res = store.getters['mainCharacter/whereFilters'] + res = store.getters['mainCharacter/where'] t.deepEqual(char._sync.pathVariables, {}) t.deepEqual(char._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.{name}', '==', '{big}']]) // 1. open once store.dispatch('mainCharacter/openDBChannel', {name: 'Luca'}).catch(console.error) await wait(2) - res = store.getters['mainCharacter/whereFilters'] + res = store.getters['mainCharacter/where'] t.deepEqual(char._sync.pathVariables, {name: 'Luca'}) t.deepEqual(char._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.Luca', '==', '{big}']]) // 2. open again store.dispatch('mainCharacter/openDBChannel', {name: 'Mesqueeb'}).catch(console.error) await wait(2) - res = store.getters['mainCharacter/whereFilters'] + res = store.getters['mainCharacter/where'] t.deepEqual(char._sync.pathVariables, {name: 'Mesqueeb'}) t.deepEqual(res, [['hi.charlie.docs.Mesqueeb', '==', '{big}']]) }) diff --git a/test/getters.js b/test/getters.js index 261e89d0..2f46ece1 100644 --- a/test/getters.js +++ b/test/getters.js @@ -75,12 +75,12 @@ test('[prepareForPatch] doc', async t => { t.is(res[docModeId].updated_at, undefined) }) -test('[whereFilters]', async t => { +test('[where]', async t => { let res char._conf.sync.where = [['hi.{userId}.docs.{nr}', '==', '{big}'], ['{userId}', '==', '{userId}']] char._sync.userId = 'charlie' char._sync.pathVariables = {nr: '1', big: 'shot'} - res = store.getters['mainCharacter/whereFilters'] + res = store.getters['mainCharacter/where'] t.deepEqual(res, [['hi.charlie.docs.1', '==', 'shot'], ['charlie', '==', 'charlie']]) t.deepEqual(char._conf.sync.where, [['hi.{userId}.docs.{nr}', '==', '{big}'], ['{userId}', '==', '{userId}']]) // accept other values than strings @@ -88,12 +88,12 @@ test('[whereFilters]', async t => { char._sync.userId = '' const date = new Date() char._sync.pathVariables = {date, nulll: null, undef: undefined} - res = store.getters['mainCharacter/whereFilters'] + res = store.getters['mainCharacter/where'] t.deepEqual(res, [[1, '==', true], ['', '==', date, null, undefined]]) t.deepEqual(char._conf.sync.where, [[1, '==', true], ['{userId}', '==', '{date}', '{nulll}', '{undef}']]) char._conf.sync.where = [[1, true, undefined, '{a}', NaN]] char._sync.pathVariables = {a: {}} - res = store.getters['mainCharacter/whereFilters'] + res = store.getters['mainCharacter/where'] t.deepEqual(res, [[1, true, undefined, {}, NaN]]) t.deepEqual(char._conf.sync.where, [[1, true, undefined, '{a}', NaN]]) }) diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index 65957e78..21c31760 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -724,17 +724,17 @@ function stringifyParams(params) { }).join(); } /** - * Gets an object with {whereFilters, orderBy} filters and returns a unique identifier for that + * Gets an object with {where, orderBy} filters and returns a unique identifier for that * * @export - * @param {AnyObject} [whereOrderBy={}] whereOrderBy {whereFilters, orderBy} + * @param {AnyObject} [whereOrderBy={}] whereOrderBy {where, orderBy} * @returns {string} */ function createFetchIdentifier(whereOrderBy) { if (whereOrderBy === void 0) { whereOrderBy = {}; } var identifier = ''; - if ('whereFilters' in whereOrderBy) { - identifier += '[where]' + whereOrderBy.whereFilters.map(function (where) { return stringifyParams(where); }).join(); + if ('where' in whereOrderBy) { + identifier += '[where]' + whereOrderBy.where.map(function (where) { return stringifyParams(where); }).join(); } if ('orderBy' in whereOrderBy) { identifier += '[orderBy]' + stringifyParams(whereOrderBy.orderBy); @@ -960,26 +960,28 @@ function pluginActions (Firebase$$1) { }); }, fetch: function (_a, _b - // whereFilters: [['archived', '==', true]] + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; - var _c = _b === void 0 ? { whereFilters: [], orderBy: [] } : _b - // whereFilters: [['archived', '==', true]] + var _c = _b === void 0 ? { where: [], whereFilters: [], orderBy: [] } : _b + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] - , _d = _c.whereFilters, whereFilters = _d === void 0 ? [] : _d, _e = _c.orderBy, orderBy = _e === void 0 ? [] : _e; + , _d = _c.where, where = _d === void 0 ? [] : _d, _e = _c.whereFilters, whereFilters = _e === void 0 ? [] : _e, _f = _c.orderBy, orderBy = _f === void 0 ? [] : _f; + if (whereFilters.length) + where = whereFilters; return new Promise(function (resolve, reject) { if (state._conf.logging) console.log('[vuex-easy-firestore] Fetch starting'); if (!getters.signedIn) return resolve(); - var identifier = createFetchIdentifier({ whereFilters: whereFilters, orderBy: orderBy }); + var identifier = createFetchIdentifier({ where: where, orderBy: orderBy }); var fetched = state._sync.fetched[identifier]; // We've never fetched this before: if (!fetched) { var ref_1 = getters.dbRef; // apply where filters and orderBy - whereFilters.forEach(function (paramsArr) { + where.forEach(function (paramsArr) { ref_1 = ref_1.where.apply(ref_1, paramsArr); }); if (orderBy.length) { @@ -1036,15 +1038,17 @@ function pluginActions (Firebase$$1) { }); }, fetchAndAdd: function (_a, _b - // whereFilters: [['archived', '==', true]] + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] ) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; - var _c = _b === void 0 ? { whereFilters: [], orderBy: [] } : _b - // whereFilters: [['archived', '==', true]] + var _c = _b === void 0 ? { where: [], whereFilters: [], orderBy: [] } : _b + // where: [['archived', '==', true]] // orderBy: ['done_date', 'desc'] - , _d = _c.whereFilters, whereFilters = _d === void 0 ? [] : _d, _e = _c.orderBy, orderBy = _e === void 0 ? [] : _e; - return dispatch('fetch', { whereFilters: whereFilters, orderBy: orderBy }) + , _d = _c.where, where = _d === void 0 ? [] : _d, _e = _c.whereFilters, whereFilters = _e === void 0 ? [] : _e, _f = _c.orderBy, orderBy = _f === void 0 ? [] : _f; + if (whereFilters.length) + where = whereFilters; + return dispatch('fetch', { where: where, orderBy: orderBy }) .then(function (querySnapshot) { if (querySnapshot.done === true) return querySnapshot; @@ -1096,7 +1100,7 @@ function pluginActions (Firebase$$1) { var dbRef = getters.dbRef; // apply where filters and orderBy if (getters.collectionMode) { - getters.whereFilters.forEach(function (whereParams) { + getters.where.forEach(function (whereParams) { dbRef = dbRef.where.apply(dbRef, whereParams); }); if (state._conf.sync.orderBy.length) { @@ -1552,7 +1556,7 @@ function pluginGetters (Firebase$$1) { return doc; }; }, - whereFilters: function (state, getters) { + where: function (state, getters) { var whereArrays = state._conf.sync.where; return whereArrays.map(function (whereClause) { return whereClause.map(function (param) { diff --git a/test/mutations.js b/test/mutations.js index 702cc964..bf31d192 100644 --- a/test/mutations.js +++ b/test/mutations.js @@ -121,13 +121,13 @@ test('SET_PATHVARS & where getter', async t => { box._conf.sync.where = [['hi.{userId}.docs.{name}', '==', '{big}']] box._sync.userId = 'charlie' // pokemonBox._sync.userId = 'charlie' - res = store.getters['pokemonBox/whereFilters'] + res = store.getters['pokemonBox/where'] t.deepEqual(box._sync.pathVariables, {}) t.deepEqual(box._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.{name}', '==', '{big}']]) store.commit('pokemonBox/SET_PATHVARS', {name: 'Satoshi'}) - res = store.getters['pokemonBox/whereFilters'] + res = store.getters['pokemonBox/where'] t.deepEqual(box._sync.pathVariables, {name: 'Satoshi'}) t.deepEqual(box._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.Satoshi', '==', '{big}']]) diff --git a/test/utils/apiHelpers.js b/test/utils/apiHelpers.js index aa86f302..df67dae4 100644 --- a/test/utils/apiHelpers.js +++ b/test/utils/apiHelpers.js @@ -69,12 +69,12 @@ test('getPathVarMatches', t => { test('createFetchIdentifier', t => { let res res = createFetchIdentifier({ - whereFilters: [['hi.{userId}.docs.{nr}', '==', '{big}'], ['{userId}', '==', '{userId}']], + where: [['hi.{userId}.docs.{nr}', '==', '{big}'], ['{userId}', '==', '{userId}']], orderBy: ['date'] }) t.is(res, '[where]hi.{userId}.docs.{nr},==,{big},{userId},==,{userId}[orderBy]date') res = createFetchIdentifier({ - whereFilters: [['thatRef', '==', store.getters['mainCharacter/dbRef']]] + where: [['thatRef', '==', store.getters['mainCharacter/dbRef']]] }) t.is(res, `[where]thatRef,==,DocumentReferenceSatoshi`) }) diff --git a/types/src/utils/apiHelpers.d.ts b/types/src/utils/apiHelpers.d.ts index 88c4e00f..0e19ba93 100644 --- a/types/src/utils/apiHelpers.d.ts +++ b/types/src/utils/apiHelpers.d.ts @@ -37,10 +37,10 @@ export declare function getPathVarMatches(pathPiece: string): string[]; */ export declare function trimAccolades(pathPiece: string): string; /** - * Gets an object with {whereFilters, orderBy} filters and returns a unique identifier for that + * Gets an object with {where, orderBy} filters and returns a unique identifier for that * * @export - * @param {AnyObject} [whereOrderBy={}] whereOrderBy {whereFilters, orderBy} + * @param {AnyObject} [whereOrderBy={}] whereOrderBy {where, orderBy} * @returns {string} */ export declare function createFetchIdentifier(whereOrderBy?: AnyObject): string; diff --git a/types/utils/apiHelpers.d.ts b/types/utils/apiHelpers.d.ts index 88c4e00f..0e19ba93 100644 --- a/types/utils/apiHelpers.d.ts +++ b/types/utils/apiHelpers.d.ts @@ -37,10 +37,10 @@ export declare function getPathVarMatches(pathPiece: string): string[]; */ export declare function trimAccolades(pathPiece: string): string; /** - * Gets an object with {whereFilters, orderBy} filters and returns a unique identifier for that + * Gets an object with {where, orderBy} filters and returns a unique identifier for that * * @export - * @param {AnyObject} [whereOrderBy={}] whereOrderBy {whereFilters, orderBy} + * @param {AnyObject} [whereOrderBy={}] whereOrderBy {where, orderBy} * @returns {string} */ export declare function createFetchIdentifier(whereOrderBy?: AnyObject): string; From 4b868392c9931982852f6cda90a6c0044cb3e1b7 Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 16:00:24 +0900 Subject: [PATCH 8/9] =?UTF-8?q?improve=20fetch=20where=20filters=20?= =?UTF-8?q?=F0=9F=94=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/index.cjs.js | 22 ++++++++++------------ dist/index.esm.js | 22 ++++++++++------------ src/module/actions.ts | 13 +++---------- src/module/getters.ts | 10 +++++++--- src/module/mutations.ts | 4 ++-- test/DBChannel.js | 6 +++--- test/getters.js | 6 +++--- test/helpers/index.cjs.js | 22 ++++++++++------------ test/mutations.js | 4 ++-- 9 files changed, 50 insertions(+), 59 deletions(-) diff --git a/dist/index.cjs.js b/dist/index.cjs.js index 4513fc16..9f606138 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -846,7 +846,7 @@ function pluginActions (Firebase$$1) { if (!fetched) { var ref_1 = getters.dbRef; // apply where filters and orderBy - where.forEach(function (paramsArr) { + getters.getWhereArrays(where).forEach(function (paramsArr) { ref_1 = ref_1.where.apply(ref_1, paramsArr); }); if (orderBy.length) { @@ -954,18 +954,11 @@ function pluginActions (Firebase$$1) { delete pathVariables.orderBy; commit('SET_PATHVARS', pathVariables); } - // get userId - var userId = null; - if (Firebase$$1.auth().currentUser) { - state._sync.signedIn = true; - userId = Firebase$$1.auth().currentUser.uid; - state._sync.userId = userId; - } // getters.dbRef should already have pathVariables swapped out var dbRef = getters.dbRef; // apply where filters and orderBy if (getters.collectionMode) { - getters.where.forEach(function (whereParams) { + getters.getWhereArrays().forEach(function (whereParams) { dbRef = dbRef.where.apply(dbRef, whereParams); }); if (state._conf.sync.orderBy.length) { @@ -1421,8 +1414,13 @@ function pluginGetters (Firebase$$1) { return doc; }; }, - where: function (state, getters) { - var whereArrays = state._conf.sync.where; + getWhereArrays: function (state, getters) { return function (whereArrays) { + if (!isWhat.isArray(whereArrays)) + whereArrays = state._conf.sync.where; + if (Firebase$$1.auth().currentUser) { + state._sync.signedIn = true; + state._sync.userId = Firebase$$1.auth().currentUser.uid; + } return whereArrays.map(function (whereClause) { return whereClause.map(function (param) { if (!isWhat.isString(param)) @@ -1448,7 +1446,7 @@ function pluginGetters (Firebase$$1) { return cleanedParam; }); }); - }, + }; }, }; } diff --git a/dist/index.esm.js b/dist/index.esm.js index 80f6de01..5e9367a8 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -841,7 +841,7 @@ function pluginActions (Firebase$$1) { if (!fetched) { var ref_1 = getters.dbRef; // apply where filters and orderBy - where.forEach(function (paramsArr) { + getters.getWhereArrays(where).forEach(function (paramsArr) { ref_1 = ref_1.where.apply(ref_1, paramsArr); }); if (orderBy.length) { @@ -949,18 +949,11 @@ function pluginActions (Firebase$$1) { delete pathVariables.orderBy; commit('SET_PATHVARS', pathVariables); } - // get userId - var userId = null; - if (Firebase$$1.auth().currentUser) { - state._sync.signedIn = true; - userId = Firebase$$1.auth().currentUser.uid; - state._sync.userId = userId; - } // getters.dbRef should already have pathVariables swapped out var dbRef = getters.dbRef; // apply where filters and orderBy if (getters.collectionMode) { - getters.where.forEach(function (whereParams) { + getters.getWhereArrays().forEach(function (whereParams) { dbRef = dbRef.where.apply(dbRef, whereParams); }); if (state._conf.sync.orderBy.length) { @@ -1416,8 +1409,13 @@ function pluginGetters (Firebase$$1) { return doc; }; }, - where: function (state, getters) { - var whereArrays = state._conf.sync.where; + getWhereArrays: function (state, getters) { return function (whereArrays) { + if (!isArray(whereArrays)) + whereArrays = state._conf.sync.where; + if (Firebase$$1.auth().currentUser) { + state._sync.signedIn = true; + state._sync.userId = Firebase$$1.auth().currentUser.uid; + } return whereArrays.map(function (whereClause) { return whereClause.map(function (param) { if (!isString(param)) @@ -1443,7 +1441,7 @@ function pluginGetters (Firebase$$1) { return cleanedParam; }); }); - }, + }; }, }; } diff --git a/src/module/actions.ts b/src/module/actions.ts index fd6f99b2..c7ec77c6 100644 --- a/src/module/actions.ts +++ b/src/module/actions.ts @@ -1,4 +1,4 @@ -import { isArray, isPlainObject, isAnyObject, isFunction } from 'is-what' +import { isArray, isPlainObject, isFunction } from 'is-what' import merge from 'merge-anything' import { AnyObject, IPluginState } from '../declarations' import setDefaultValues from '../utils/setDefaultValues' @@ -180,7 +180,7 @@ export default function (Firebase: any): AnyObject { if (!fetched) { let ref = getters.dbRef // apply where filters and orderBy - where.forEach(paramsArr => { + getters.getWhereArrays(where).forEach(paramsArr => { ref = ref.where(...paramsArr) }) if (orderBy.length) { @@ -282,18 +282,11 @@ export default function (Firebase: any): AnyObject { delete pathVariables.orderBy commit('SET_PATHVARS', pathVariables) } - // get userId - let userId = null - if (Firebase.auth().currentUser) { - state._sync.signedIn = true - userId = Firebase.auth().currentUser.uid - state._sync.userId = userId - } // getters.dbRef should already have pathVariables swapped out let dbRef = getters.dbRef // apply where filters and orderBy if (getters.collectionMode) { - getters.where.forEach(whereParams => { + getters.getWhereArrays().forEach(whereParams => { dbRef = dbRef.where(...whereParams) }) if (state._conf.sync.orderBy.length) { diff --git a/src/module/getters.ts b/src/module/getters.ts index ce63df7e..febcb27f 100644 --- a/src/module/getters.ts +++ b/src/module/getters.ts @@ -1,4 +1,4 @@ -import { isString, isPlainObject, isAnyObject } from 'is-what' +import { isString, isArray } from 'is-what' import { getDeepRef } from 'vuex-easy-access' import { findAndReplaceIf } from 'find-and-replace-anything' import filter from 'filter-anything' @@ -161,8 +161,12 @@ export default function (Firebase: any): AnyObject { doc = filter(doc, fillables, guard) return doc }, - where: (state, getters) => { - const whereArrays = state._conf.sync.where + getWhereArrays: (state, getters) => (whereArrays) => { + if (!isArray(whereArrays)) whereArrays = state._conf.sync.where + if (Firebase.auth().currentUser) { + state._sync.signedIn = true + state._sync.userId = Firebase.auth().currentUser.uid + } return whereArrays.map(whereClause => { return whereClause.map(param => { if (!isString(param)) return param diff --git a/src/module/mutations.ts b/src/module/mutations.ts index 8debf6c0..67bbe2fb 100644 --- a/src/module/mutations.ts +++ b/src/module/mutations.ts @@ -1,9 +1,9 @@ -import { isPlainObject, isAnyObject, isArray } from 'is-what' +import { isPlainObject, isArray } from 'is-what' import { getDeepRef } from 'vuex-easy-access' import error from './errors' import merge from 'merge-anything' import { AnyObject } from '../declarations' -import { isArrayHelper, ArrayUnion } from '../utils/arrayHelpers' +import { isArrayHelper } from '../utils/arrayHelpers' /** * a function returning the mutations object diff --git a/test/DBChannel.js b/test/DBChannel.js index 80f07eef..60dd12c1 100644 --- a/test/DBChannel.js +++ b/test/DBChannel.js @@ -35,21 +35,21 @@ test('[openDBChannel] check where filter after openDBChannel', async t => { char._conf.sync.where = [['hi.{userId}.docs.{name}', '==', '{big}']] char._sync.userId = 'charlie' // 0. initial path - res = store.getters['mainCharacter/where'] + res = store.getters['mainCharacter/getWhereArrays']() t.deepEqual(char._sync.pathVariables, {}) t.deepEqual(char._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.{name}', '==', '{big}']]) // 1. open once store.dispatch('mainCharacter/openDBChannel', {name: 'Luca'}).catch(console.error) await wait(2) - res = store.getters['mainCharacter/where'] + res = store.getters['mainCharacter/getWhereArrays']() t.deepEqual(char._sync.pathVariables, {name: 'Luca'}) t.deepEqual(char._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.Luca', '==', '{big}']]) // 2. open again store.dispatch('mainCharacter/openDBChannel', {name: 'Mesqueeb'}).catch(console.error) await wait(2) - res = store.getters['mainCharacter/where'] + res = store.getters['mainCharacter/getWhereArrays']() t.deepEqual(char._sync.pathVariables, {name: 'Mesqueeb'}) t.deepEqual(res, [['hi.charlie.docs.Mesqueeb', '==', '{big}']]) }) diff --git a/test/getters.js b/test/getters.js index 2f46ece1..b39c36f6 100644 --- a/test/getters.js +++ b/test/getters.js @@ -80,7 +80,7 @@ test('[where]', async t => { char._conf.sync.where = [['hi.{userId}.docs.{nr}', '==', '{big}'], ['{userId}', '==', '{userId}']] char._sync.userId = 'charlie' char._sync.pathVariables = {nr: '1', big: 'shot'} - res = store.getters['mainCharacter/where'] + res = store.getters['mainCharacter/getWhereArrays']() t.deepEqual(res, [['hi.charlie.docs.1', '==', 'shot'], ['charlie', '==', 'charlie']]) t.deepEqual(char._conf.sync.where, [['hi.{userId}.docs.{nr}', '==', '{big}'], ['{userId}', '==', '{userId}']]) // accept other values than strings @@ -88,12 +88,12 @@ test('[where]', async t => { char._sync.userId = '' const date = new Date() char._sync.pathVariables = {date, nulll: null, undef: undefined} - res = store.getters['mainCharacter/where'] + res = store.getters['mainCharacter/getWhereArrays']() t.deepEqual(res, [[1, '==', true], ['', '==', date, null, undefined]]) t.deepEqual(char._conf.sync.where, [[1, '==', true], ['{userId}', '==', '{date}', '{nulll}', '{undef}']]) char._conf.sync.where = [[1, true, undefined, '{a}', NaN]] char._sync.pathVariables = {a: {}} - res = store.getters['mainCharacter/where'] + res = store.getters['mainCharacter/getWhereArrays']() t.deepEqual(res, [[1, true, undefined, {}, NaN]]) t.deepEqual(char._conf.sync.where, [[1, true, undefined, '{a}', NaN]]) }) diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index 21c31760..1c293982 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -981,7 +981,7 @@ function pluginActions (Firebase$$1) { if (!fetched) { var ref_1 = getters.dbRef; // apply where filters and orderBy - where.forEach(function (paramsArr) { + getters.getWhereArrays(where).forEach(function (paramsArr) { ref_1 = ref_1.where.apply(ref_1, paramsArr); }); if (orderBy.length) { @@ -1089,18 +1089,11 @@ function pluginActions (Firebase$$1) { delete pathVariables.orderBy; commit('SET_PATHVARS', pathVariables); } - // get userId - var userId = null; - if (Firebase$$1.auth().currentUser) { - state._sync.signedIn = true; - userId = Firebase$$1.auth().currentUser.uid; - state._sync.userId = userId; - } // getters.dbRef should already have pathVariables swapped out var dbRef = getters.dbRef; // apply where filters and orderBy if (getters.collectionMode) { - getters.where.forEach(function (whereParams) { + getters.getWhereArrays().forEach(function (whereParams) { dbRef = dbRef.where.apply(dbRef, whereParams); }); if (state._conf.sync.orderBy.length) { @@ -1556,8 +1549,13 @@ function pluginGetters (Firebase$$1) { return doc; }; }, - where: function (state, getters) { - var whereArrays = state._conf.sync.where; + getWhereArrays: function (state, getters) { return function (whereArrays) { + if (!isWhat.isArray(whereArrays)) + whereArrays = state._conf.sync.where; + if (Firebase$$1.auth().currentUser) { + state._sync.signedIn = true; + state._sync.userId = Firebase$$1.auth().currentUser.uid; + } return whereArrays.map(function (whereClause) { return whereClause.map(function (param) { if (!isWhat.isString(param)) @@ -1583,7 +1581,7 @@ function pluginGetters (Firebase$$1) { return cleanedParam; }); }); - }, + }; }, }; } diff --git a/test/mutations.js b/test/mutations.js index bf31d192..65b698a4 100644 --- a/test/mutations.js +++ b/test/mutations.js @@ -121,13 +121,13 @@ test('SET_PATHVARS & where getter', async t => { box._conf.sync.where = [['hi.{userId}.docs.{name}', '==', '{big}']] box._sync.userId = 'charlie' // pokemonBox._sync.userId = 'charlie' - res = store.getters['pokemonBox/where'] + res = store.getters['pokemonBox/getWhereArrays']() t.deepEqual(box._sync.pathVariables, {}) t.deepEqual(box._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.{name}', '==', '{big}']]) store.commit('pokemonBox/SET_PATHVARS', {name: 'Satoshi'}) - res = store.getters['pokemonBox/where'] + res = store.getters['pokemonBox/getWhereArrays']() t.deepEqual(box._sync.pathVariables, {name: 'Satoshi'}) t.deepEqual(box._conf.sync.where, [['hi.{userId}.docs.{name}', '==', '{big}']]) t.deepEqual(res, [['hi.charlie.docs.Satoshi', '==', '{big}']]) From 4559feb88793d9be90d02da1c0194ec853a5453e Mon Sep 17 00:00:00 2001 From: Luca Ban - Black Birdy Date: Sun, 16 Dec 2018 17:03:29 +0900 Subject: [PATCH 9/9] =?UTF-8?q?Default=20values=20for=20local=20changes=20?= =?UTF-8?q?=F0=9F=93=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/index.cjs.js | 34 ++++++++----- dist/index.esm.js | 34 ++++++++----- docs/README.md | 5 +- docs/config-example.md | 3 +- docs/extra-features.md | 64 ++++++++++++------------ package.json | 2 +- src/module/actions.ts | 32 +++++++++--- src/module/defaultConfig.ts | 14 ++++-- src/module/errorCheckConfig.ts | 4 +- test/helpers/index.cjs.js | 52 ++++++++++++++----- test/helpers/store/initialDoc.ts | 22 ++++++++ test/helpers/store/pokemonBox.ts | 18 ++++++- test/syncDefaultValues.js | 24 +++++++++ types/module/defaultConfig.d.ts | 12 +++-- types/src/module/defaultConfig.d.ts | 12 +++-- types/test/helpers/store/pokemonBox.d.ts | 3 ++ 16 files changed, 238 insertions(+), 97 deletions(-) create mode 100644 test/helpers/store/initialDoc.ts create mode 100644 test/syncDefaultValues.js diff --git a/dist/index.cjs.js b/dist/index.cjs.js index 9f606138..9ccac511 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -63,6 +63,7 @@ var defaultConfig = { orderBy: [], fillables: [], guard: [], + defaultValues: {}, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { return updateStore(doc); }, patchHook: function (updateStore, doc, store) { return updateStore(doc); }, @@ -75,10 +76,11 @@ var defaultConfig = { // When items on the server side are changed: serverChange: { defaultValues: {}, + convertTimestamps: {}, // HOOKS for changes on SERVER: - addedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, - modifiedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, - removedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, + addedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, + modifiedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, + removedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, }, // When items are fetched through `dispatch('module/fetch', filters)`. fetch: { @@ -920,7 +922,9 @@ function pluginActions (Firebase$$1) { if (isWhat.isFunction(querySnapshot.forEach)) { querySnapshot.forEach(function (_doc) { var id = _doc.id; - var doc = setDefaultValues(_doc.data(), state._conf.serverChange.defaultValues); + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); + var doc = setDefaultValues(_doc.data(), defaultValues); doc.id = id; commit('INSERT_DOC', doc); }); @@ -998,7 +1002,9 @@ function pluginActions (Firebase$$1) { } if (source === 'local') return resolve(); - var doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues); + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); + var doc = setDefaultValues(querySnapshot.data(), defaultValues); var id = getters.docModeId; doc.id = id; handleDoc('modified', id, doc); @@ -1010,8 +1016,10 @@ function pluginActions (Firebase$$1) { if (source === 'local') return resolve(); var id = change.doc.id; + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); var doc = (changeType === 'added') - ? setDefaultValues(change.doc.data(), state._conf.serverChange.defaultValues) + ? setDefaultValues(change.doc.data(), defaultValues) : change.doc.data(); handleDoc(changeType, id, doc); }); @@ -1057,6 +1065,8 @@ function pluginActions (Firebase$$1) { var newDoc = doc; if (!newDoc.id) newDoc.id = getters.dbRef.doc().id; + // apply default values + var newDocWithDefaults = setDefaultValues(newDoc, state._conf.sync.defaultValues); // define the store update function storeUpdateFn(_doc) { commit('INSERT_DOC', _doc); @@ -1064,11 +1074,11 @@ function pluginActions (Firebase$$1) { } // check for hooks if (state._conf.sync.insertHook) { - state._conf.sync.insertHook(storeUpdateFn, newDoc, store); - return newDoc.id; + state._conf.sync.insertHook(storeUpdateFn, newDocWithDefaults, store); + return newDocWithDefaults.id; } - storeUpdateFn(newDoc); - return newDoc.id; + storeUpdateFn(newDocWithDefaults); + return newDocWithDefaults.id; }, insertBatch: function (_a, docs) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; @@ -1471,7 +1481,7 @@ function errorCheck (config) { if (/\./.test(config.moduleName)) { errors.push("moduleName must only include letters from [a-z] and forward slashes '/'"); } - var syncProps = ['where', 'orderBy', 'fillables', 'guard', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook']; + var syncProps = ['where', 'orderBy', 'fillables', 'guard', 'defaultValues', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook']; syncProps.forEach(function (prop) { if (config[prop]) { errors.push("We found `" + prop + "` on your module, are you sure this shouldn't be inside a prop called `sync`?"); @@ -1506,7 +1516,7 @@ function errorCheck (config) { var objectProps = ['sync', 'serverChange', 'defaultValues', 'fetch']; objectProps.forEach(function (prop) { var _prop = (prop === 'defaultValues') - ? config.serverChange[prop] + ? config.sync[prop] : config[prop]; if (!isWhat.isPlainObject(_prop)) errors.push("`" + prop + "` should be an Object, but is not."); diff --git a/dist/index.esm.js b/dist/index.esm.js index 5e9367a8..318fc156 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -58,6 +58,7 @@ var defaultConfig = { orderBy: [], fillables: [], guard: [], + defaultValues: {}, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { return updateStore(doc); }, patchHook: function (updateStore, doc, store) { return updateStore(doc); }, @@ -70,10 +71,11 @@ var defaultConfig = { // When items on the server side are changed: serverChange: { defaultValues: {}, + convertTimestamps: {}, // HOOKS for changes on SERVER: - addedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, - modifiedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, - removedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, + addedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, + modifiedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, + removedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, }, // When items are fetched through `dispatch('module/fetch', filters)`. fetch: { @@ -915,7 +917,9 @@ function pluginActions (Firebase$$1) { if (isFunction(querySnapshot.forEach)) { querySnapshot.forEach(function (_doc) { var id = _doc.id; - var doc = setDefaultValues(_doc.data(), state._conf.serverChange.defaultValues); + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); + var doc = setDefaultValues(_doc.data(), defaultValues); doc.id = id; commit('INSERT_DOC', doc); }); @@ -993,7 +997,9 @@ function pluginActions (Firebase$$1) { } if (source === 'local') return resolve(); - var doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues); + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); + var doc = setDefaultValues(querySnapshot.data(), defaultValues); var id = getters.docModeId; doc.id = id; handleDoc('modified', id, doc); @@ -1005,8 +1011,10 @@ function pluginActions (Firebase$$1) { if (source === 'local') return resolve(); var id = change.doc.id; + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); var doc = (changeType === 'added') - ? setDefaultValues(change.doc.data(), state._conf.serverChange.defaultValues) + ? setDefaultValues(change.doc.data(), defaultValues) : change.doc.data(); handleDoc(changeType, id, doc); }); @@ -1052,6 +1060,8 @@ function pluginActions (Firebase$$1) { var newDoc = doc; if (!newDoc.id) newDoc.id = getters.dbRef.doc().id; + // apply default values + var newDocWithDefaults = setDefaultValues(newDoc, state._conf.sync.defaultValues); // define the store update function storeUpdateFn(_doc) { commit('INSERT_DOC', _doc); @@ -1059,11 +1069,11 @@ function pluginActions (Firebase$$1) { } // check for hooks if (state._conf.sync.insertHook) { - state._conf.sync.insertHook(storeUpdateFn, newDoc, store); - return newDoc.id; + state._conf.sync.insertHook(storeUpdateFn, newDocWithDefaults, store); + return newDocWithDefaults.id; } - storeUpdateFn(newDoc); - return newDoc.id; + storeUpdateFn(newDocWithDefaults); + return newDocWithDefaults.id; }, insertBatch: function (_a, docs) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; @@ -1466,7 +1476,7 @@ function errorCheck (config) { if (/\./.test(config.moduleName)) { errors.push("moduleName must only include letters from [a-z] and forward slashes '/'"); } - var syncProps = ['where', 'orderBy', 'fillables', 'guard', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook']; + var syncProps = ['where', 'orderBy', 'fillables', 'guard', 'defaultValues', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook']; syncProps.forEach(function (prop) { if (config[prop]) { errors.push("We found `" + prop + "` on your module, are you sure this shouldn't be inside a prop called `sync`?"); @@ -1501,7 +1511,7 @@ function errorCheck (config) { var objectProps = ['sync', 'serverChange', 'defaultValues', 'fetch']; objectProps.forEach(function (prop) { var _prop = (prop === 'defaultValues') - ? config.serverChange[prop] + ? config.sync[prop] : config[prop]; if (!isPlainObject(_prop)) errors.push("`" + prop + "` should be an Object, but is not."); diff --git a/docs/README.md b/docs/README.md index 4102a459..8b9e0071 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,7 +7,7 @@ features: - title: Simplicity First details: Minimal setup to get a vuex-module synced with Firestore automatically. - title: Powerful - details: Easy to use features include filtering, hooks, automatic Firestore Timestamp conversion & much more. + details: Easy to use features include filtering, hooks, default values, automatic Firestore Timestamp conversion & much more. - title: Performant details: Automatic 2-way sync is fully optimised through api call batches. footer: MIT Licensed | Copyright © 2018-present Luca Ban - Mesqueeb @@ -36,9 +36,10 @@ Now you just update and add docs with `dispatch('userData/set', newItem)` and fo # Features - Automatic 2-way sync between your Vuex module & Firestore -- [Timestamp conversion to Date()](extra-features.html#defaultvalues-set-after-server-retrieval) +- [Default values](extra-features.html#default-values) - [Hooks](hooks.html#hooks) (before / after sync) - [Fillables / guard](extra-features.html#fillables-and-guard) (limit fields which will sync) +- [Timestamp conversion to Date()](extra-features.html#firestore-timestamp-conversion) - [Where / orderBy filters](guide.html#query-data-filters) # Motivation diff --git a/docs/config-example.md b/docs/config-example.md index 389c5c65..65571580 100644 --- a/docs/config-example.md +++ b/docs/config-example.md @@ -19,6 +19,7 @@ const firestoreModule = { orderBy: [], fillables: [], guard: [], + defaultValues: {}, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { return updateStore(doc) }, patchHook: function (updateStore, doc, store) { return updateStore(doc) }, @@ -31,7 +32,7 @@ const firestoreModule = { // When docs on the server side are changed: serverChange: { - defaultValues: {}, + convertTimestamps: {}, // HOOKS for changes on SERVER: addedHook: function (updateStore, doc, id, store) { return updateStore(doc) }, modifiedHook: function (updateStore, doc, id, store) { return updateStore(doc) }, diff --git a/docs/extra-features.md b/docs/extra-features.md index 85d60647..ded7d143 100644 --- a/docs/extra-features.md +++ b/docs/extra-features.md @@ -31,7 +31,7 @@ store.dispatch('userData/openDBChannel') ## Fillables and guard -You can prevent props on your docs in 'collection' mode (or on your single doc in 'doc' mode) to be synced to the firestore server. For this you should use either `fillables` **or** `guard`: +You can prevent props on your docs to be synced to the firestore server. For this you should use either `fillables` **or** `guard`: - *Fillables:* Array of keys - the props which **may be synced** to the server. - 0 fillables = all props are synced @@ -151,54 +151,52 @@ const idMap = await dispatch('pokemonBox/duplicateBatch', ['001', '004', '007']) This way you can use the result if you need to do extra things to your duplicated docs and you will know for each ID which new ID was used to make a duplication. -## defaultValues set after server retrieval +## Default values -If you create a `defaultValues` object, then each document from the server will receive those default values! +You can set up default values for your docs that will be added to the object on each insert. -**Use case 1: Firestore Timestamp conversion**
-Automatically convert Firestore Timestamps into `new Date()` objects! Do this by setting `'%convertTimestamp%'` as the value of a `defaultValues` prop. (see example below). +**In 'doc' mode** this can just be done by adding those values to your module state. This is how's it's done regularly with Vuex. -**Use case 2: Reactivity**
-With VueJS, if you need a prop on an object to be fully reactive with your vue templates, it needs to exist from the start. If some docs in your user's firestore doesn't have all props (because you added new functionality to your app at later dates), the *retrieved docs will have reactivity problems!* +**In 'collection' mode** the library takes care of applying these default values to each doc that's inserted. Default values should be set in your modules `sync` config: -However, if you add these props to `defaultValues` with some value (or just `'null'`), vuex-easy-firestore will automatically add those props to the doc *before* inserting it into vuex! - -**Example:** ```js -const vuexModule = { +const pokemonBoxModule = { // your other vuex-easy-firestore config... - serverChange: { + sync: { defaultValues: { - defaultInt: 1, - propAddedLater: null, - date: '%convertTimestamp%', + freed: false, }, } } -// Now an example of what happens to the docs which are retrieved from the server: -const retrievedDoc = { - defaultInt: 2, - date: Timestamp // firestore Timestamp object -} +// Now, when you add a new pokemon, it will automatically have `freed` +dispatch('pokemonBox/insert', {name: 'Poliwag'}) +// This will appear in your module like so: +// {name: 'Poliwag', freed: false} +``` -// This doc will be inserted into vuex like so: -const docToBeInserted = { - defaultInt: 2, // stays 2 - propAddedLater: null, // receives propAddedLater prop with default val - date: Timestamp.toDate() // will execute firestore's Timestamp.toDate() -} +Also, to make sure there are no vue reactivity issues, these default values are also applied to any doc that doesn't have them that's retrieved from the server. + +## Firestore Timestamp conversion + +Firestore works with special "[timestamp](https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp)" fields rather than with `new Date()`. Vuex-easy-firestore also uses the timestamp fields for the auto-generated fields `created_at` and `updated_at` which are added to your docs. -// '%convertTimestamp%' works also with date strings: -const retrievedDoc = {date: '1990-06-22 17:35:00'} // date string -const docToBeInserted = {date: new Date('1990-06-22 17:35:00')} // converted to new Date +In your app, if you want to use these timestamps as a `new Date()` object you have to call `timestamp.toDate()` on each of these fields. **Luckily this can do this for you!** -// in case the retrieved val is not present `null` will be added -const retrievedDoc = {} -const docToBeInserted = {date: null} +You just have to specify the fields in a `convertTimestamps` object in your module config like so: + +```js +const vuexModule = { + // your other vuex-easy-firestore config... + serverChange: { + convertTimestamps: { + updated_at: '%convertTimestamp%' + }, + } +} ``` -To learn more about Firestore's Timestamp format see [here](https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp). +Now the Timestamp on `updated_at` will automatically trigger `Timestamp.toDate()` before being added to your vuex store! ## Shortcut: set(path, doc) diff --git a/package.json b/package.json index 02fda902..96447542 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vuex-easy-firestore", - "version": "1.21.1", + "version": "1.22.0", "description": "Easy coupling of firestore and a vuex module. 2-way sync with 0 boilerplate!", "main": "dist/index.cjs.js", "module": "dist/index.esm.js", diff --git a/src/module/actions.ts b/src/module/actions.ts index c7ec77c6..b71b297f 100644 --- a/src/module/actions.ts +++ b/src/module/actions.ts @@ -6,6 +6,7 @@ import startDebounce from '../utils/debounceHelper' import { makeBatchFromSyncstack, createFetchIdentifier } from '../utils/apiHelpers' import { getId, getValueFromPayloadPiece } from '../utils/payloadHelpers' import error from './errors' +import { createDiffieHellman } from 'crypto'; /** * A function returning the actions object @@ -248,7 +249,12 @@ export default function (Firebase: any): AnyObject { if (isFunction(querySnapshot.forEach)) { querySnapshot.forEach(_doc => { const id = _doc.id - const doc = setDefaultValues(_doc.data(), state._conf.serverChange.defaultValues) + const defaultValues = merge( + state._conf.sync.defaultValues, + state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps, + ) + const doc = setDefaultValues(_doc.data(), defaultValues) doc.id = id commit('INSERT_DOC', doc) }) @@ -323,7 +329,12 @@ export default function (Firebase: any): AnyObject { return resolve() } if (source === 'local') return resolve() - const doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues) + const defaultValues = merge( + state._conf.sync.defaultValues, + state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps, + ) + const doc = setDefaultValues(querySnapshot.data(), defaultValues) const id = getters.docModeId doc.id = id handleDoc('modified', id, doc) @@ -334,8 +345,13 @@ export default function (Firebase: any): AnyObject { // Don't do anything for local modifications & removals if (source === 'local') return resolve() const id = change.doc.id + const defaultValues = merge( + state._conf.sync.defaultValues, + state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps, + ) const doc = (changeType === 'added') - ? setDefaultValues(change.doc.data(), state._conf.serverChange.defaultValues) + ? setDefaultValues(change.doc.data(), defaultValues) : change.doc.data() handleDoc(changeType, id, doc) }) @@ -374,6 +390,8 @@ export default function (Firebase: any): AnyObject { if (!doc) return const newDoc = doc if (!newDoc.id) newDoc.id = getters.dbRef.doc().id + // apply default values + const newDocWithDefaults = setDefaultValues(newDoc, state._conf.sync.defaultValues) // define the store update function storeUpdateFn (_doc) { commit('INSERT_DOC', _doc) @@ -381,11 +399,11 @@ export default function (Firebase: any): AnyObject { } // check for hooks if (state._conf.sync.insertHook) { - state._conf.sync.insertHook(storeUpdateFn, newDoc, store) - return newDoc.id + state._conf.sync.insertHook(storeUpdateFn, newDocWithDefaults, store) + return newDocWithDefaults.id } - storeUpdateFn(newDoc) - return newDoc.id + storeUpdateFn(newDocWithDefaults) + return newDocWithDefaults.id }, insertBatch ({state, getters, commit, dispatch}, docs) { const store = this diff --git a/src/module/defaultConfig.ts b/src/module/defaultConfig.ts index 0230a08d..352424f1 100644 --- a/src/module/defaultConfig.ts +++ b/src/module/defaultConfig.ts @@ -11,7 +11,7 @@ export type SyncHookId = (updateStore: HandleId, id: string, store) => (void | H export type InsertBatchHook = (updateStore: HandleDocs, docs: any[], store) => (void | HandleDocs) export type PatchBatchHook = (updateStore: HandleDocIds, doc: any, ids: string[], store) => (void | HandleDocIds) export type DeleteBatchHook = (updateStore: HandleIds, ids: string[], store) => (void | HandleIds) -export type ServerChangeHook = (updateStore: HandleDoc, doc: any, id, store, source, change) => (void | HandleDoc) +export type ServerChangeHook = (updateStore: HandleDoc, doc: any, id, store) => (void | HandleDoc) export type IConfig = { firestorePath: string @@ -24,6 +24,7 @@ export type IConfig = { orderBy?: string[] fillables?: string[] guard?: string[] + defaultValues?: AnyObject insertHook?: SyncHookDoc patchHook?: SyncHookDoc deleteHook?: SyncHookId @@ -33,6 +34,7 @@ export type IConfig = { } serverChange?: { defaultValues?: AnyObject + convertTimestamps?: AnyObject addedHook?: ServerChangeHook modifiedHook?: ServerChangeHook removedHook?: ServerChangeHook @@ -62,6 +64,7 @@ export default { orderBy: [], fillables: [], guard: [], + defaultValues: {}, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { return updateStore(doc) }, patchHook: function (updateStore, doc, store) { return updateStore(doc) }, @@ -74,11 +77,12 @@ export default { // When items on the server side are changed: serverChange: { - defaultValues: {}, + defaultValues: {}, // depreciated + convertTimestamps: {}, // HOOKS for changes on SERVER: - addedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc) }, - modifiedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc) }, - removedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc) }, + addedHook: function (updateStore, doc, id, store) { return updateStore(doc) }, + modifiedHook: function (updateStore, doc, id, store) { return updateStore(doc) }, + removedHook: function (updateStore, doc, id, store) { return updateStore(doc) }, }, // When items are fetched through `dispatch('module/fetch', filters)`. diff --git a/src/module/errorCheckConfig.ts b/src/module/errorCheckConfig.ts index 06021fa8..61f10e85 100644 --- a/src/module/errorCheckConfig.ts +++ b/src/module/errorCheckConfig.ts @@ -22,7 +22,7 @@ export default function (config: IEasyFirestoreModule): boolean { if (/\./.test(config.moduleName)) { errors.push(`moduleName must only include letters from [a-z] and forward slashes '/'`) } - const syncProps = ['where', 'orderBy', 'fillables', 'guard', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook'] + const syncProps = ['where', 'orderBy', 'fillables', 'guard', 'defaultValues', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook'] syncProps.forEach(prop => { if (config[prop]) { errors.push(`We found \`${prop}\` on your module, are you sure this shouldn't be inside a prop called \`sync\`?`) @@ -55,7 +55,7 @@ export default function (config: IEasyFirestoreModule): boolean { const objectProps = ['sync', 'serverChange', 'defaultValues', 'fetch'] objectProps.forEach(prop => { const _prop = (prop === 'defaultValues') - ? config.serverChange[prop] + ? config.sync[prop] : config[prop] if (!isPlainObject(_prop)) errors.push(`\`${prop}\` should be an Object, but is not.`) }) diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index 1c293982..56f0aed6 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -32,8 +32,24 @@ var pokemonBox = { sync: { where: [['id', '==', '{pokeId}']], orderBy: [], - fillables: ['fillable', 'name', 'id', 'type', 'freed', 'nested', 'addedBeforeInsert', 'addedBeforePatch', 'arr1', 'arr2', 'guarded'], + fillables: [ + 'fillable', + 'name', + 'id', + 'type', + 'freed', + 'nested', + 'addedBeforeInsert', + 'addedBeforePatch', + 'arr1', + 'arr2', + 'guarded', + 'defaultVal' + ], guard: ['guarded'], + defaultValues: { + defaultVal: true + }, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { doc.addedBeforeInsert = true; @@ -237,6 +253,7 @@ var defaultConfig = { orderBy: [], fillables: [], guard: [], + defaultValues: {}, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { return updateStore(doc); }, patchHook: function (updateStore, doc, store) { return updateStore(doc); }, @@ -249,10 +266,11 @@ var defaultConfig = { // When items on the server side are changed: serverChange: { defaultValues: {}, + convertTimestamps: {}, // HOOKS for changes on SERVER: - addedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, - modifiedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, - removedHook: function (updateStore, doc, id, store, source, change) { return updateStore(doc); }, + addedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, + modifiedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, + removedHook: function (updateStore, doc, id, store) { return updateStore(doc); }, }, // When items are fetched through `dispatch('module/fetch', filters)`. fetch: { @@ -1055,7 +1073,9 @@ function pluginActions (Firebase$$1) { if (isWhat.isFunction(querySnapshot.forEach)) { querySnapshot.forEach(function (_doc) { var id = _doc.id; - var doc = setDefaultValues(_doc.data(), state._conf.serverChange.defaultValues); + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); + var doc = setDefaultValues(_doc.data(), defaultValues); doc.id = id; commit('INSERT_DOC', doc); }); @@ -1133,7 +1153,9 @@ function pluginActions (Firebase$$1) { } if (source === 'local') return resolve(); - var doc = setDefaultValues(querySnapshot.data(), state._conf.serverChange.defaultValues); + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); + var doc = setDefaultValues(querySnapshot.data(), defaultValues); var id = getters.docModeId; doc.id = id; handleDoc('modified', id, doc); @@ -1145,8 +1167,10 @@ function pluginActions (Firebase$$1) { if (source === 'local') return resolve(); var id = change.doc.id; + var defaultValues = merge(state._conf.sync.defaultValues, state._conf.serverChange.defaultValues, // depreciated + state._conf.serverChange.convertTimestamps); var doc = (changeType === 'added') - ? setDefaultValues(change.doc.data(), state._conf.serverChange.defaultValues) + ? setDefaultValues(change.doc.data(), defaultValues) : change.doc.data(); handleDoc(changeType, id, doc); }); @@ -1192,6 +1216,8 @@ function pluginActions (Firebase$$1) { var newDoc = doc; if (!newDoc.id) newDoc.id = getters.dbRef.doc().id; + // apply default values + var newDocWithDefaults = setDefaultValues(newDoc, state._conf.sync.defaultValues); // define the store update function storeUpdateFn(_doc) { commit('INSERT_DOC', _doc); @@ -1199,11 +1225,11 @@ function pluginActions (Firebase$$1) { } // check for hooks if (state._conf.sync.insertHook) { - state._conf.sync.insertHook(storeUpdateFn, newDoc, store); - return newDoc.id; + state._conf.sync.insertHook(storeUpdateFn, newDocWithDefaults, store); + return newDocWithDefaults.id; } - storeUpdateFn(newDoc); - return newDoc.id; + storeUpdateFn(newDocWithDefaults); + return newDocWithDefaults.id; }, insertBatch: function (_a, docs) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; @@ -1606,7 +1632,7 @@ function errorCheck (config) { if (/\./.test(config.moduleName)) { errors.push("moduleName must only include letters from [a-z] and forward slashes '/'"); } - var syncProps = ['where', 'orderBy', 'fillables', 'guard', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook']; + var syncProps = ['where', 'orderBy', 'fillables', 'guard', 'defaultValues', 'insertHook', 'patchHook', 'deleteHook', 'insertBatchHook', 'patchBatchHook', 'deleteBatchHook']; syncProps.forEach(function (prop) { if (config[prop]) { errors.push("We found `" + prop + "` on your module, are you sure this shouldn't be inside a prop called `sync`?"); @@ -1641,7 +1667,7 @@ function errorCheck (config) { var objectProps = ['sync', 'serverChange', 'defaultValues', 'fetch']; objectProps.forEach(function (prop) { var _prop = (prop === 'defaultValues') - ? config.serverChange[prop] + ? config.sync[prop] : config[prop]; if (!isWhat.isPlainObject(_prop)) errors.push("`" + prop + "` should be an Object, but is not."); diff --git a/test/helpers/store/initialDoc.ts b/test/helpers/store/initialDoc.ts new file mode 100644 index 00000000..cfc4728c --- /dev/null +++ b/test/helpers/store/initialDoc.ts @@ -0,0 +1,22 @@ +import { defaultMutations } from 'vuex-easy-access' + +function initialState () { + return { + name: 'Satoshi', + pokemonBelt: [], + items: [] + } +} + +export default { + // easy firestore config + firestorePath: 'docs/{randomId}', // this should be randomized each test + firestoreRefType: 'doc', + moduleName: 'initialDoc', + statePropName: '', + // module + state: initialState(), + mutations: defaultMutations(initialState()), + actions: {}, + getters: {}, +} diff --git a/test/helpers/store/pokemonBox.ts b/test/helpers/store/pokemonBox.ts index 18703b3f..cdb8cc28 100644 --- a/test/helpers/store/pokemonBox.ts +++ b/test/helpers/store/pokemonBox.ts @@ -21,8 +21,24 @@ export default { sync: { where: [['id', '==', '{pokeId}']], orderBy: [], - fillables: ['fillable', 'name', 'id', 'type', 'freed', 'nested', 'addedBeforeInsert', 'addedBeforePatch', 'arr1', 'arr2', 'guarded'], + fillables: [ + 'fillable', + 'name', + 'id', + 'type', + 'freed', + 'nested', + 'addedBeforeInsert', + 'addedBeforePatch', + 'arr1', + 'arr2', + 'guarded', + 'defaultVal' + ], guard: ['guarded'], + defaultValues: { + defaultVal: true + }, // HOOKS for local changes: insertHook: function (updateStore, doc, store) { doc.addedBeforeInsert = true diff --git a/test/syncDefaultValues.js b/test/syncDefaultValues.js new file mode 100644 index 00000000..605d6784 --- /dev/null +++ b/test/syncDefaultValues.js @@ -0,0 +1,24 @@ +import test from 'ava' +import wait from './helpers/wait' +import {storeSyncConfig as store} from './helpers/index.cjs.js' + +const box = store.state.pokemonBox +const boxRef = store.getters['pokemonBox/dbRef'] +// const char = store.state.mainCharacter +// const charRef = store.getters['mainCharacter/dbRef'] + +test('[COLLECTION] sync: defaultValues', async t => { + const id = boxRef.doc().id + store.dispatch('pokemonBox/insert', {id, name: 'Squirtle'}) + .catch(console.error) + t.truthy(box.pokemon[id]) + t.is(box.pokemon[id].name, 'Squirtle') + t.is(box.pokemon[id].defaultVal, true) + // fetch from server to check + await wait(2) + const docR = await boxRef.doc(id).get() + const doc = docR.data() + t.truthy(doc) + t.is(doc.name, 'Squirtle') + t.is(doc.defaultVal, true) +}) diff --git a/types/module/defaultConfig.d.ts b/types/module/defaultConfig.d.ts index ca14d26e..bd42cff7 100644 --- a/types/module/defaultConfig.d.ts +++ b/types/module/defaultConfig.d.ts @@ -9,7 +9,7 @@ export declare type SyncHookId = (updateStore: HandleId, id: string, store: any) export declare type InsertBatchHook = (updateStore: HandleDocs, docs: any[], store: any) => (void | HandleDocs); export declare type PatchBatchHook = (updateStore: HandleDocIds, doc: any, ids: string[], store: any) => (void | HandleDocIds); export declare type DeleteBatchHook = (updateStore: HandleIds, ids: string[], store: any) => (void | HandleIds); -export declare type ServerChangeHook = (updateStore: HandleDoc, doc: any, id: any, store: any, source: any, change: any) => (void | HandleDoc); +export declare type ServerChangeHook = (updateStore: HandleDoc, doc: any, id: any, store: any) => (void | HandleDoc); export declare type IConfig = { firestorePath: string; firestoreRefType: string; @@ -21,6 +21,7 @@ export declare type IConfig = { orderBy?: string[]; fillables?: string[]; guard?: string[]; + defaultValues?: AnyObject; insertHook?: SyncHookDoc; patchHook?: SyncHookDoc; deleteHook?: SyncHookId; @@ -30,6 +31,7 @@ export declare type IConfig = { }; serverChange?: { defaultValues?: AnyObject; + convertTimestamps?: AnyObject; addedHook?: ServerChangeHook; modifiedHook?: ServerChangeHook; removedHook?: ServerChangeHook; @@ -53,6 +55,7 @@ declare const _default: { orderBy: any[]; fillables: any[]; guard: any[]; + defaultValues: {}; insertHook: (updateStore: any, doc: any, store: any) => any; patchHook: (updateStore: any, doc: any, store: any) => any; deleteHook: (updateStore: any, id: any, store: any) => any; @@ -62,9 +65,10 @@ declare const _default: { }; serverChange: { defaultValues: {}; - addedHook: (updateStore: any, doc: any, id: any, store: any, source: any, change: any) => any; - modifiedHook: (updateStore: any, doc: any, id: any, store: any, source: any, change: any) => any; - removedHook: (updateStore: any, doc: any, id: any, store: any, source: any, change: any) => any; + convertTimestamps: {}; + addedHook: (updateStore: any, doc: any, id: any, store: any) => any; + modifiedHook: (updateStore: any, doc: any, id: any, store: any) => any; + removedHook: (updateStore: any, doc: any, id: any, store: any) => any; }; fetch: { docLimit: number; diff --git a/types/src/module/defaultConfig.d.ts b/types/src/module/defaultConfig.d.ts index ca14d26e..bd42cff7 100644 --- a/types/src/module/defaultConfig.d.ts +++ b/types/src/module/defaultConfig.d.ts @@ -9,7 +9,7 @@ export declare type SyncHookId = (updateStore: HandleId, id: string, store: any) export declare type InsertBatchHook = (updateStore: HandleDocs, docs: any[], store: any) => (void | HandleDocs); export declare type PatchBatchHook = (updateStore: HandleDocIds, doc: any, ids: string[], store: any) => (void | HandleDocIds); export declare type DeleteBatchHook = (updateStore: HandleIds, ids: string[], store: any) => (void | HandleIds); -export declare type ServerChangeHook = (updateStore: HandleDoc, doc: any, id: any, store: any, source: any, change: any) => (void | HandleDoc); +export declare type ServerChangeHook = (updateStore: HandleDoc, doc: any, id: any, store: any) => (void | HandleDoc); export declare type IConfig = { firestorePath: string; firestoreRefType: string; @@ -21,6 +21,7 @@ export declare type IConfig = { orderBy?: string[]; fillables?: string[]; guard?: string[]; + defaultValues?: AnyObject; insertHook?: SyncHookDoc; patchHook?: SyncHookDoc; deleteHook?: SyncHookId; @@ -30,6 +31,7 @@ export declare type IConfig = { }; serverChange?: { defaultValues?: AnyObject; + convertTimestamps?: AnyObject; addedHook?: ServerChangeHook; modifiedHook?: ServerChangeHook; removedHook?: ServerChangeHook; @@ -53,6 +55,7 @@ declare const _default: { orderBy: any[]; fillables: any[]; guard: any[]; + defaultValues: {}; insertHook: (updateStore: any, doc: any, store: any) => any; patchHook: (updateStore: any, doc: any, store: any) => any; deleteHook: (updateStore: any, id: any, store: any) => any; @@ -62,9 +65,10 @@ declare const _default: { }; serverChange: { defaultValues: {}; - addedHook: (updateStore: any, doc: any, id: any, store: any, source: any, change: any) => any; - modifiedHook: (updateStore: any, doc: any, id: any, store: any, source: any, change: any) => any; - removedHook: (updateStore: any, doc: any, id: any, store: any, source: any, change: any) => any; + convertTimestamps: {}; + addedHook: (updateStore: any, doc: any, id: any, store: any) => any; + modifiedHook: (updateStore: any, doc: any, id: any, store: any) => any; + removedHook: (updateStore: any, doc: any, id: any, store: any) => any; }; fetch: { docLimit: number; diff --git a/types/test/helpers/store/pokemonBox.d.ts b/types/test/helpers/store/pokemonBox.d.ts index 73b5b1ed..8ab09bb8 100644 --- a/types/test/helpers/store/pokemonBox.d.ts +++ b/types/test/helpers/store/pokemonBox.d.ts @@ -8,6 +8,9 @@ declare const _default: { orderBy: any[]; fillables: string[]; guard: string[]; + defaultValues: { + defaultVal: boolean; + }; insertHook: (updateStore: any, doc: any, store: any) => any; patchHook: (updateStore: any, doc: any, store: any) => any; deleteHook: (updateStore: any, id: any, store: any) => any;