diff --git a/dist/index.cjs.js b/dist/index.cjs.js index abb9dad6..28c1f551 100644 --- a/dist/index.cjs.js +++ b/dist/index.cjs.js @@ -91,11 +91,12 @@ function pluginState () { * execute Error() based on an error id string * * @export - * @param {string} error the error id + * @param {string} errorId the error id + * @param {any} [error] an actual error from an async request or something * @returns {string} the error id */ -function error (error) { - return error; +function error (errorId, error) { + return errorId; } var Firebase = Firebase$2; @@ -308,7 +309,7 @@ function pluginMutations (userState) { ref = ref[patches.id]; } if (!ref) - return error('patchNoRef'); + return error('patch-no-ref'); return Object.keys(patches).forEach(function (key) { var newVal = patches[key]; // Merge if exists @@ -711,11 +712,8 @@ function pluginActions (Firebase) { userId = Firebase.auth().currentUser.uid; } commit('SET_USER_ID', userId); - if (getters.firestorePathComplete.includes('{userId}')) { - var error_1 = '[vuex-easy-firestore] error trying to set userId.\n Try doing \`dispatch(\'module/setUserId\', userId)\ before openDBChannel or fetchAndAdd.`'; - console.error(error_1); - throw error_1; - } + if (getters.firestorePathComplete.includes('{userId}')) + return error('user-auth'); }, clearUser: function (_a) { var commit = _a.commit; @@ -733,7 +731,7 @@ function pluginActions (Firebase) { switch (_c.label) { case 0: if (!getters.collectionMode) - return [2 /*return*/, console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.')]; + return [2 /*return*/, error('only-in-collection-mode')]; if (!id) return [2 /*return*/, {}]; doc = merge(getters.storeRef[id], { id: null }); @@ -751,7 +749,7 @@ function pluginActions (Firebase) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; if (ids === void 0) { ids = []; } if (!getters.collectionMode) - return console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.'); + return error('only-in-collection-mode'); if (!isWhat.isArray(ids) || !ids.length) return {}; var idsMap = ids.reduce(function (carry, id) { return __awaiter(_this, void 0, void 0, function () { @@ -775,7 +773,7 @@ function pluginActions (Firebase) { var _c = _b === void 0 ? { ids: [], doc: {} } : _b, _d = _c.id, id = _d === void 0 ? '' : _d, _e = _c.ids, ids = _e === void 0 ? [] : _e, doc = _c.doc; // 0. payload correction (only arrays) if (!isWhat.isArray(ids)) - return console.error("[vuex-easy-firestore] ids needs to be an array"); + return error("`ids` prop passed to 'patch' needs to be an array"); if (id) ids.push(id); // EXTRA: check if doc is being inserted if so @@ -893,12 +891,12 @@ function pluginActions (Firebase) { transaction.set(initialDocRef, initialDocPrepared); } }); - }).then(function () { + }).then(function (_) { if (state._conf.logging) { console.log('[vuex-easy-firestore] Initial doc succesfully inserted.'); } - }).catch(function (error) { - console.error('[vuex-easy-firestore] Initial doc succesfully insertion failed. Further `set` or `patch` actions will also fail. Requires an internet connection when the initial doc is inserted. Please connect to the internet and refresh the page.', error); + }).catch(function (error$1) { + return error('initial-doc-failed', error$1); }); }, handleSyncStackDebounce: function (_a) { @@ -929,11 +927,10 @@ function pluginActions (Firebase) { } dispatch('_stopPatching'); return resolve(); - }).catch(function (error) { + }).catch(function (error$1) { state._sync.patching = 'error'; state._sync.syncStack.debounceTimer = null; - console.error('Error during synchronisation ↓'); - return reject(error); + return reject(error$1); }); }); }, @@ -1000,7 +997,7 @@ function pluginActions (Firebase) { fRef = fRef.limit(limit); // Stop if all records already fetched if (fRequest.retrievedFetchRefs.includes(fRef)) { - console.error('[vuex-easy-firestore] Already retrieved this part.'); + console.log('[vuex-easy-firestore] Already retrieved this part.'); return resolve(); } // make fetch request @@ -1021,9 +1018,8 @@ function pluginActions (Firebase) { // set the reference for the next records. var next = fRef.startAfter(lastVisible); state._sync.fetched[identifier].nextFetchRef = next; - }).catch(function (error) { - console.error('[vuex-easy-firestore]', error); - return reject(error); + }).catch(function (error$1) { + return reject(error(error$1)); }); }); }, @@ -1065,9 +1061,8 @@ function pluginActions (Firebase) { return [2 /*return*/, doc]; } }); - }); }).catch(function (error) { - console.error('[vuex-easy-firestore]', error); - return error; + }); }).catch(function (error$1) { + return error(error$1); }); } // 'collection' mode: @@ -1085,6 +1080,38 @@ function pluginActions (Firebase) { return querySnapshot; }); }, + fetchById: function (_a, id) { + var dispatch = _a.dispatch, getters = _a.getters, state = _a.state; + return __awaiter(this, void 0, void 0, function () { + var ref, _doc, doc, e_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + _b.trys.push([0, 2, , 3]); + if (!id) + throw 'missing-id'; + if (!getters.collectionMode) + throw 'only-in-collection-mode'; + ref = getters.dbRef; + return [4 /*yield*/, ref.doc(id).get()]; + case 1: + _doc = _b.sent(); + if (!_doc.exists) { + if (state._conf.logging) { + throw "Doc with id \"" + id + "\" not found!"; + } + } + doc = getters.cleanUpRetrievedDoc(_doc.data(), id); + dispatch('applyHooksAndUpdateState', { change: 'added', id: id, doc: doc }); + return [2 /*return*/, doc]; + case 2: + e_1 = _b.sent(); + return [2 /*return*/, error(e_1)]; + case 3: return [2 /*return*/]; + } + }); + }); + }, applyHooksAndUpdateState: function (// this is only on server retrievals _a, _b) { var getters = _a.getters, state = _a.state, commit = _a.commit, dispatch = _a.dispatch; @@ -1230,9 +1257,9 @@ function pluginActions (Firebase) { return [2 /*return*/, resolve()]; } }); - }); }, function (error) { + }); }, function (error$1) { state._sync.patching = 'error'; - return reject(error); + return reject(error(error$1)); }); state._sync.unsubscribe[identifier] = unsubscribe; }); @@ -1334,7 +1361,7 @@ function pluginActions (Firebase) { var id = (getters.collectionMode) ? getId(doc) : getters.docModeId; var value = (getters.collectionMode) ? getValueFromPayloadPiece(doc) : doc; if (!id && getters.collectionMode) - return; + return error('patch-missing-id'); // check userId dispatch('setUserId'); // add id to value @@ -1393,12 +1420,12 @@ function pluginActions (Firebase) { if (pathDelete) { var path = _id; if (!path) - return error('actionsDeleteMissingPath'); + return error('delete-missing-path'); commit('DELETE_PROP', path); return dispatch('deleteProp', path); } if (!_id) - return error('actionsDeleteMissingId'); + return error('delete-missing-id'); commit('DELETE_DOC', _id); return dispatch('deleteDoc', _id); } @@ -1426,12 +1453,12 @@ function pluginActions (Firebase) { if (pathDelete) { var path = _id; if (!path) - return error('actionsDeleteMissingPath'); + return error('delete-missing-path'); commit('DELETE_PROP', path); return dispatch('deleteProp', path); } if (!_id) - return error('actionsDeleteMissingId'); + return error('delete-missing-id'); commit('DELETE_DOC', _id); return dispatch('deleteDoc', _id); }); @@ -1640,7 +1667,7 @@ function pluginGetters (Firebase) { return; } if (!Object.keys(state._sync.pathVariables).includes(key)) { - return error('missingPathVarKey'); + return error('missing-path-variables'); } var varVal = state._sync.pathVariables[key]; // if path is only a param we need to just assign to avoid stringification diff --git a/dist/index.esm.js b/dist/index.esm.js index 7764375c..1bdeea0c 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -85,11 +85,12 @@ function pluginState () { * execute Error() based on an error id string * * @export - * @param {string} error the error id + * @param {string} errorId the error id + * @param {any} [error] an actual error from an async request or something * @returns {string} the error id */ -function error (error) { - return error; +function error (errorId, error) { + return errorId; } var Firebase = Firebase$2; @@ -302,7 +303,7 @@ function pluginMutations (userState) { ref = ref[patches.id]; } if (!ref) - return error('patchNoRef'); + return error('patch-no-ref'); return Object.keys(patches).forEach(function (key) { var newVal = patches[key]; // Merge if exists @@ -705,11 +706,8 @@ function pluginActions (Firebase) { userId = Firebase.auth().currentUser.uid; } commit('SET_USER_ID', userId); - if (getters.firestorePathComplete.includes('{userId}')) { - var error_1 = '[vuex-easy-firestore] error trying to set userId.\n Try doing \`dispatch(\'module/setUserId\', userId)\ before openDBChannel or fetchAndAdd.`'; - console.error(error_1); - throw error_1; - } + if (getters.firestorePathComplete.includes('{userId}')) + return error('user-auth'); }, clearUser: function (_a) { var commit = _a.commit; @@ -727,7 +725,7 @@ function pluginActions (Firebase) { switch (_c.label) { case 0: if (!getters.collectionMode) - return [2 /*return*/, console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.')]; + return [2 /*return*/, error('only-in-collection-mode')]; if (!id) return [2 /*return*/, {}]; doc = merge(getters.storeRef[id], { id: null }); @@ -745,7 +743,7 @@ function pluginActions (Firebase) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; if (ids === void 0) { ids = []; } if (!getters.collectionMode) - return console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.'); + return error('only-in-collection-mode'); if (!isArray(ids) || !ids.length) return {}; var idsMap = ids.reduce(function (carry, id) { return __awaiter(_this, void 0, void 0, function () { @@ -769,7 +767,7 @@ function pluginActions (Firebase) { var _c = _b === void 0 ? { ids: [], doc: {} } : _b, _d = _c.id, id = _d === void 0 ? '' : _d, _e = _c.ids, ids = _e === void 0 ? [] : _e, doc = _c.doc; // 0. payload correction (only arrays) if (!isArray(ids)) - return console.error("[vuex-easy-firestore] ids needs to be an array"); + return error("`ids` prop passed to 'patch' needs to be an array"); if (id) ids.push(id); // EXTRA: check if doc is being inserted if so @@ -887,12 +885,12 @@ function pluginActions (Firebase) { transaction.set(initialDocRef, initialDocPrepared); } }); - }).then(function () { + }).then(function (_) { if (state._conf.logging) { console.log('[vuex-easy-firestore] Initial doc succesfully inserted.'); } - }).catch(function (error) { - console.error('[vuex-easy-firestore] Initial doc succesfully insertion failed. Further `set` or `patch` actions will also fail. Requires an internet connection when the initial doc is inserted. Please connect to the internet and refresh the page.', error); + }).catch(function (error$1) { + return error('initial-doc-failed', error$1); }); }, handleSyncStackDebounce: function (_a) { @@ -923,11 +921,10 @@ function pluginActions (Firebase) { } dispatch('_stopPatching'); return resolve(); - }).catch(function (error) { + }).catch(function (error$1) { state._sync.patching = 'error'; state._sync.syncStack.debounceTimer = null; - console.error('Error during synchronisation ↓'); - return reject(error); + return reject(error$1); }); }); }, @@ -994,7 +991,7 @@ function pluginActions (Firebase) { fRef = fRef.limit(limit); // Stop if all records already fetched if (fRequest.retrievedFetchRefs.includes(fRef)) { - console.error('[vuex-easy-firestore] Already retrieved this part.'); + console.log('[vuex-easy-firestore] Already retrieved this part.'); return resolve(); } // make fetch request @@ -1015,9 +1012,8 @@ function pluginActions (Firebase) { // set the reference for the next records. var next = fRef.startAfter(lastVisible); state._sync.fetched[identifier].nextFetchRef = next; - }).catch(function (error) { - console.error('[vuex-easy-firestore]', error); - return reject(error); + }).catch(function (error$1) { + return reject(error(error$1)); }); }); }, @@ -1059,9 +1055,8 @@ function pluginActions (Firebase) { return [2 /*return*/, doc]; } }); - }); }).catch(function (error) { - console.error('[vuex-easy-firestore]', error); - return error; + }); }).catch(function (error$1) { + return error(error$1); }); } // 'collection' mode: @@ -1079,6 +1074,38 @@ function pluginActions (Firebase) { return querySnapshot; }); }, + fetchById: function (_a, id) { + var dispatch = _a.dispatch, getters = _a.getters, state = _a.state; + return __awaiter(this, void 0, void 0, function () { + var ref, _doc, doc, e_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + _b.trys.push([0, 2, , 3]); + if (!id) + throw 'missing-id'; + if (!getters.collectionMode) + throw 'only-in-collection-mode'; + ref = getters.dbRef; + return [4 /*yield*/, ref.doc(id).get()]; + case 1: + _doc = _b.sent(); + if (!_doc.exists) { + if (state._conf.logging) { + throw "Doc with id \"" + id + "\" not found!"; + } + } + doc = getters.cleanUpRetrievedDoc(_doc.data(), id); + dispatch('applyHooksAndUpdateState', { change: 'added', id: id, doc: doc }); + return [2 /*return*/, doc]; + case 2: + e_1 = _b.sent(); + return [2 /*return*/, error(e_1)]; + case 3: return [2 /*return*/]; + } + }); + }); + }, applyHooksAndUpdateState: function (// this is only on server retrievals _a, _b) { var getters = _a.getters, state = _a.state, commit = _a.commit, dispatch = _a.dispatch; @@ -1224,9 +1251,9 @@ function pluginActions (Firebase) { return [2 /*return*/, resolve()]; } }); - }); }, function (error) { + }); }, function (error$1) { state._sync.patching = 'error'; - return reject(error); + return reject(error(error$1)); }); state._sync.unsubscribe[identifier] = unsubscribe; }); @@ -1328,7 +1355,7 @@ function pluginActions (Firebase) { var id = (getters.collectionMode) ? getId(doc) : getters.docModeId; var value = (getters.collectionMode) ? getValueFromPayloadPiece(doc) : doc; if (!id && getters.collectionMode) - return; + return error('patch-missing-id'); // check userId dispatch('setUserId'); // add id to value @@ -1387,12 +1414,12 @@ function pluginActions (Firebase) { if (pathDelete) { var path = _id; if (!path) - return error('actionsDeleteMissingPath'); + return error('delete-missing-path'); commit('DELETE_PROP', path); return dispatch('deleteProp', path); } if (!_id) - return error('actionsDeleteMissingId'); + return error('delete-missing-id'); commit('DELETE_DOC', _id); return dispatch('deleteDoc', _id); } @@ -1420,12 +1447,12 @@ function pluginActions (Firebase) { if (pathDelete) { var path = _id; if (!path) - return error('actionsDeleteMissingPath'); + return error('delete-missing-path'); commit('DELETE_PROP', path); return dispatch('deleteProp', path); } if (!_id) - return error('actionsDeleteMissingId'); + return error('delete-missing-id'); commit('DELETE_DOC', _id); return dispatch('deleteDoc', _id); }); @@ -1634,7 +1661,7 @@ function pluginGetters (Firebase) { return; } if (!Object.keys(state._sync.pathVariables).includes(key)) { - return error('missingPathVarKey'); + return error('missing-path-variables'); } var varVal = state._sync.pathVariables[key]; // if path is only a param we need to just assign to avoid stringification diff --git a/package.json b/package.json index e2f6850b..e95d4667 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vuex-easy-firestore", - "version": "1.32.1", + "version": "1.33.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 a5750b5c..4ec5421c 100644 --- a/src/module/actions.ts +++ b/src/module/actions.ts @@ -11,7 +11,7 @@ import { makeBatchFromSyncstack, createFetchIdentifier } from '../utils/apiHelpe import { getId, getValueFromPayloadPiece } from '../utils/payloadHelpers' import { isArrayHelper } from '../utils/arrayHelpers' import { isIncrementHelper } from '../utils/incrementHelper' -import error from './errors' +import logError from './errors' /** * A function returning the actions object @@ -29,11 +29,7 @@ export default function (Firebase: any): AnyObject { userId = Firebase.auth().currentUser.uid } commit('SET_USER_ID', userId) - if (getters.firestorePathComplete.includes('{userId}')) { - const error = '[vuex-easy-firestore] error trying to set userId.\n Try doing \`dispatch(\'module/setUserId\', userId)\ before openDBChannel or fetchAndAdd.`' - console.error(error) - throw error - } + if (getters.firestorePathComplete.includes('{userId}')) return logError('user-auth') }, clearUser: ({commit}) => { commit('CLEAR_USER') @@ -42,7 +38,7 @@ export default function (Firebase: any): AnyObject { commit('SET_PATHVARS', pathVars) }, duplicate: async ({state, getters, commit, dispatch}, id) => { - if (!getters.collectionMode) return console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.') + if (!getters.collectionMode) return logError('only-in-collection-mode') if (!id) return {} const doc = merge(getters.storeRef[id], {id: null}) const dId = await dispatch('insert', doc) @@ -50,7 +46,7 @@ export default function (Firebase: any): AnyObject { return idMap }, duplicateBatch ({state, getters, commit, dispatch}, ids = []) { - if (!getters.collectionMode) return console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.') + if (!getters.collectionMode) return logError('only-in-collection-mode') if (!isArray(ids) || !ids.length) return {} const idsMap = ids.reduce(async (carry, id) => { const idMap = await dispatch('duplicate', id) @@ -64,7 +60,7 @@ export default function (Firebase: any): AnyObject { {id = '', ids = [], doc}: {id?: string, ids?: string[], doc?: AnyObject} = {ids: [], doc: {}} ) { // 0. payload correction (only arrays) - if (!isArray(ids)) return console.error(`[vuex-easy-firestore] ids needs to be an array`) + if (!isArray(ids)) return logError(`\`ids\` prop passed to 'patch' needs to be an array`) if (id) ids.push(id) // EXTRA: check if doc is being inserted if so @@ -200,12 +196,12 @@ export default function (Firebase: any): AnyObject { transaction.set(initialDocRef, initialDocPrepared) } }) - }).then(function() { + }).then(_ => { if (state._conf.logging) { console.log('[vuex-easy-firestore] Initial doc succesfully inserted.') } - }).catch(function(error) { - console.error('[vuex-easy-firestore] Initial doc succesfully insertion failed. Further `set` or `patch` actions will also fail. Requires an internet connection when the initial doc is inserted. Please connect to the internet and refresh the page.', error) + }).catch(error => { + return logError('initial-doc-failed', error) }) }, handleSyncStackDebounce ({state, commit, dispatch, getters}) { @@ -234,8 +230,7 @@ export default function (Firebase: any): AnyObject { }).catch(error => { state._sync.patching = 'error' state._sync.syncStack.debounceTimer = null - console.error('Error during synchronisation ↓') - Error(error) + logError('sync-error', error) return reject(error) }) }) @@ -296,7 +291,7 @@ export default function (Firebase: any): AnyObject { if (limit > 0) fRef = fRef.limit(limit) // Stop if all records already fetched if (fRequest.retrievedFetchRefs.includes(fRef)) { - console.error('[vuex-easy-firestore] Already retrieved this part.') + console.log('[vuex-easy-firestore] Already retrieved this part.') return resolve() } // make fetch request @@ -318,8 +313,7 @@ export default function (Firebase: any): AnyObject { const next = fRef.startAfter(lastVisible) state._sync.fetched[identifier].nextFetchRef = next }).catch(error => { - console.error('[vuex-easy-firestore]', error) - return reject(error) + return reject(logError(error)) }) }) }, @@ -351,8 +345,7 @@ export default function (Firebase: any): AnyObject { dispatch('applyHooksAndUpdateState', {change: 'modified', id, doc}) return doc }).catch(error => { - console.error('[vuex-easy-firestore]', error) - return error + return logError(error) }) } // 'collection' mode: @@ -369,6 +362,24 @@ export default function (Firebase: any): AnyObject { return querySnapshot }) }, + async fetchById ({dispatch, getters, state}, id) { + try { + if (!id) throw 'missing-id' + if (!getters.collectionMode) throw 'only-in-collection-mode' + const ref = getters.dbRef + const _doc = await ref.doc(id).get() + if (!_doc.exists) { + if (state._conf.logging) { + throw `Doc with id "${id}" not found!` + } + } + const doc = getters.cleanUpRetrievedDoc(_doc.data(), id) + dispatch('applyHooksAndUpdateState', {change: 'added', id, doc}) + return doc + } catch (e) { + return logError(e) + } + }, applyHooksAndUpdateState ( // this is only on server retrievals {getters, state, commit, dispatch}, {change, id, doc = {}}: {change: 'added' | 'removed' | 'modified', id: string, doc: AnyObject} @@ -500,7 +511,7 @@ export default function (Firebase: any): AnyObject { return resolve() }, error => { state._sync.patching = 'error' - return reject(error) + return reject(logError(error)) }) state._sync.unsubscribe[identifier] = unsubscribe }) @@ -591,7 +602,7 @@ export default function (Firebase: any): AnyObject { if (!doc) return const id = (getters.collectionMode) ? getId(doc) : getters.docModeId const value = (getters.collectionMode) ? getValueFromPayloadPiece(doc) : doc - if (!id && getters.collectionMode) return + if (!id && getters.collectionMode) return logError('patch-missing-id') // check userId dispatch('setUserId') // add id to value @@ -645,11 +656,11 @@ export default function (Firebase: any): AnyObject { const pathDelete = (_id.includes('.') || !getters.collectionMode) if (pathDelete) { const path = _id - if (!path) return error('actionsDeleteMissingPath') + if (!path) return logError('delete-missing-path') commit('DELETE_PROP', path) return dispatch('deleteProp', path) } - if (!_id) return error('actionsDeleteMissingId') + if (!_id) return logError('delete-missing-id') commit('DELETE_DOC', _id) return dispatch('deleteDoc', _id) } @@ -677,11 +688,11 @@ export default function (Firebase: any): AnyObject { const pathDelete = (_id.includes('.') || !getters.collectionMode) if (pathDelete) { const path = _id - if (!path) return error('actionsDeleteMissingPath') + if (!path) return logError('delete-missing-path') commit('DELETE_PROP', path) return dispatch('deleteProp', path) } - if (!_id) return error('actionsDeleteMissingId') + if (!_id) return logError('delete-missing-id') commit('DELETE_DOC', _id) return dispatch('deleteDoc', _id) }) diff --git a/src/module/errors.ts b/src/module/errors.ts index 07fbabb2..8189e509 100644 --- a/src/module/errors.ts +++ b/src/module/errors.ts @@ -1,32 +1,42 @@ const errorMessages = { - actionsDeleteMissingId: ` - Missing Id of the Doc you want to delete! + 'user-auth': ` + Error trying to set userId. + Please double check if you have correctly authenticated the user with Firebase Auth before calling \`openDBChannel\` or \`fetchAndAdd\`. + + If you still get this error, try passing your firebase instance to the plugin as described in the documentation: + https://mesqueeb.github.io/vuex-easy-firestore/extra-features.html#pass-firebase-dependency + `, + 'delete-missing-id': ` + Missing id of the doc you want to delete! Correct usage: dispatch('delete', id) `, - actionsDeleteMissingPath: ` + 'delete-missing-path': ` Missing path to the prop you want to delete! Correct usage: dispatch('delete', 'path.to.prop') Use \`.\` for sub props! `, - missingId: ` - Missing an id! Correct usage: + 'missing-id': ` + This action requires an id to be passed! + `, + 'patch-missing-id': ` + Missing an id of the doc you want to patch! + Correct usage: - // \`id\` as prop of item: + // pass \`id\` as a prop: dispatch('module/set', {id: '123', name: 'best item name'}) - - // or object with only 1 prop, which is the \`id\` as key, and item as its value: - dispatch('module/set', {'123': {name: 'best item name'}}) + // or + dispatch('module/patch', {id: '123', name: 'best item name'}) `, - missingPathVarKey: ` + 'missing-path-variables': ` A path variable was passed without defining it! In VuexEasyFirestore you can create paths with variables: eg: \`groups/{groupId}/user/{userId}\` - \`userId\` is automatically replaces with the userId of the firebase user. + \`userId\` is automatically replaced with the userId of the firebase user. \`groupId\` or any other variable that needs to be set after authentication needs to be passed upon the \`openDBChannel\` action. // (in module config) Example path: @@ -38,21 +48,34 @@ const errorMessages = { // pass as argument into openDBChannel: dispatch('moduleName/openDBChannel', {groupId}) `, - patchNoRef: ` + 'patch-no-ref': ` Something went wrong during the PATCH mutation: The document it's trying to patch does not exist. `, + 'only-in-collection-mode': ` + The action you dispatched can only be used in 'collection' mode. + `, + 'initial-doc-failed': ` + Initial doc insertion failed. Further \`set\` or \`patch\` actions will also fail. Requires an internet connection when the initial doc is inserted. Please connect to the internet and refresh the page. + `, + 'sync-error': ` + Something went wrong while trying to synchronise data to Cloud Firestore. + The data is kept in queue, so that it will try to sync again upon the next 'set' or 'patch' action. + `, } /** * execute Error() based on an error id string * * @export - * @param {string} error the error id + * @param {string} errorId the error id + * @param {any} [error] an actual error from an async request or something * @returns {string} the error id */ -export default function (error: string): string { - const log = `[vuex-easy-firestore] Error! ${errorMessages[error]}` +export default function (errorId: string, error?: any): string { + const logData = errorMessages[errorId] || errorId + const log = `[vuex-easy-firestore] Error! ${logData}` Error(log) - return error + if (error) Error(error) + return errorId } diff --git a/src/module/getters.ts b/src/module/getters.ts index f1b7e295..98994eb9 100644 --- a/src/module/getters.ts +++ b/src/module/getters.ts @@ -188,7 +188,7 @@ export default function (Firebase: any): AnyObject { return } if (!Object.keys(state._sync.pathVariables).includes(key)) { - return error('missingPathVarKey') + return error('missing-path-variables') } const varVal = state._sync.pathVariables[key] // if path is only a param we need to just assign to avoid stringification diff --git a/src/module/mutations.ts b/src/module/mutations.ts index 7beb9eb4..c1982302 100644 --- a/src/module/mutations.ts +++ b/src/module/mutations.ts @@ -1,6 +1,6 @@ -import { isPlainObject, isArray, isFunction, isNumber } from 'is-what' +import { isArray, isFunction, isNumber } from 'is-what' import { getDeepRef } from 'vuex-easy-access' -import error from './errors' +import logError from './errors' import merge from 'merge-anything' import { AnyObject } from '../declarations' import { isArrayHelper } from '../utils/arrayHelpers' @@ -101,7 +101,7 @@ export default function (userState: object): AnyObject { if (state._conf.firestoreRefType.toLowerCase() === 'collection') { ref = ref[patches.id] } - if (!ref) return error('patchNoRef') + if (!ref) return logError('patch-no-ref') return Object.keys(patches).forEach(key => { let newVal = patches[key] // Merge if exists diff --git a/test/helpers/index.cjs.js b/test/helpers/index.cjs.js index 457cdcbb..b41ca92a 100644 --- a/test/helpers/index.cjs.js +++ b/test/helpers/index.cjs.js @@ -699,11 +699,12 @@ function pluginState () { * execute Error() based on an error id string * * @export - * @param {string} error the error id + * @param {string} errorId the error id + * @param {any} [error] an actual error from an async request or something * @returns {string} the error id */ -function error (error) { - return error; +function error (errorId, error) { + return errorId; } var Firebase = Firebase$1; @@ -882,7 +883,7 @@ function pluginMutations (userState) { ref = ref[patches.id]; } if (!ref) - return error('patchNoRef'); + return error('patch-no-ref'); return Object.keys(patches).forEach(function (key) { var newVal = patches[key]; // Merge if exists @@ -1222,11 +1223,8 @@ function pluginActions (Firebase) { userId = Firebase.auth().currentUser.uid; } commit('SET_USER_ID', userId); - if (getters.firestorePathComplete.includes('{userId}')) { - var error_1 = '[vuex-easy-firestore] error trying to set userId.\n Try doing \`dispatch(\'module/setUserId\', userId)\ before openDBChannel or fetchAndAdd.`'; - console.error(error_1); - throw error_1; - } + if (getters.firestorePathComplete.includes('{userId}')) + return error('user-auth'); }, clearUser: function (_a) { var commit = _a.commit; @@ -1244,7 +1242,7 @@ function pluginActions (Firebase) { switch (_c.label) { case 0: if (!getters.collectionMode) - return [2 /*return*/, console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.')]; + return [2 /*return*/, error('only-in-collection-mode')]; if (!id) return [2 /*return*/, {}]; doc = merge(getters.storeRef[id], { id: null }); @@ -1262,7 +1260,7 @@ function pluginActions (Firebase) { var state = _a.state, getters = _a.getters, commit = _a.commit, dispatch = _a.dispatch; if (ids === void 0) { ids = []; } if (!getters.collectionMode) - return console.error('[vuex-easy-firestore] You can only duplicate in \'collection\' mode.'); + return error('only-in-collection-mode'); if (!isWhat.isArray(ids) || !ids.length) return {}; var idsMap = ids.reduce(function (carry, id) { return __awaiter(_this, void 0, void 0, function () { @@ -1286,7 +1284,7 @@ function pluginActions (Firebase) { var _c = _b === void 0 ? { ids: [], doc: {} } : _b, _d = _c.id, id = _d === void 0 ? '' : _d, _e = _c.ids, ids = _e === void 0 ? [] : _e, doc = _c.doc; // 0. payload correction (only arrays) if (!isWhat.isArray(ids)) - return console.error("[vuex-easy-firestore] ids needs to be an array"); + return error("`ids` prop passed to 'patch' needs to be an array"); if (id) ids.push(id); // EXTRA: check if doc is being inserted if so @@ -1404,12 +1402,12 @@ function pluginActions (Firebase) { transaction.set(initialDocRef, initialDocPrepared); } }); - }).then(function () { + }).then(function (_) { if (state._conf.logging) { console.log('[vuex-easy-firestore] Initial doc succesfully inserted.'); } - }).catch(function (error) { - console.error('[vuex-easy-firestore] Initial doc succesfully insertion failed. Further `set` or `patch` actions will also fail. Requires an internet connection when the initial doc is inserted. Please connect to the internet and refresh the page.', error); + }).catch(function (error$1) { + return error('initial-doc-failed', error$1); }); }, handleSyncStackDebounce: function (_a) { @@ -1440,11 +1438,10 @@ function pluginActions (Firebase) { } dispatch('_stopPatching'); return resolve(); - }).catch(function (error) { + }).catch(function (error$1) { state._sync.patching = 'error'; state._sync.syncStack.debounceTimer = null; - console.error('Error during synchronisation ↓'); - return reject(error); + return reject(error$1); }); }); }, @@ -1511,7 +1508,7 @@ function pluginActions (Firebase) { fRef = fRef.limit(limit); // Stop if all records already fetched if (fRequest.retrievedFetchRefs.includes(fRef)) { - console.error('[vuex-easy-firestore] Already retrieved this part.'); + console.log('[vuex-easy-firestore] Already retrieved this part.'); return resolve(); } // make fetch request @@ -1532,9 +1529,8 @@ function pluginActions (Firebase) { // set the reference for the next records. var next = fRef.startAfter(lastVisible); state._sync.fetched[identifier].nextFetchRef = next; - }).catch(function (error) { - console.error('[vuex-easy-firestore]', error); - return reject(error); + }).catch(function (error$1) { + return reject(error(error$1)); }); }); }, @@ -1576,9 +1572,8 @@ function pluginActions (Firebase) { return [2 /*return*/, doc]; } }); - }); }).catch(function (error) { - console.error('[vuex-easy-firestore]', error); - return error; + }); }).catch(function (error$1) { + return error(error$1); }); } // 'collection' mode: @@ -1596,6 +1591,38 @@ function pluginActions (Firebase) { return querySnapshot; }); }, + fetchById: function (_a, id) { + var dispatch = _a.dispatch, getters = _a.getters, state = _a.state; + return __awaiter(this, void 0, void 0, function () { + var ref, _doc, doc, e_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + _b.trys.push([0, 2, , 3]); + if (!id) + throw 'missing-id'; + if (!getters.collectionMode) + throw 'only-in-collection-mode'; + ref = getters.dbRef; + return [4 /*yield*/, ref.doc(id).get()]; + case 1: + _doc = _b.sent(); + if (!_doc.exists) { + if (state._conf.logging) { + throw "Doc with id \"" + id + "\" not found!"; + } + } + doc = getters.cleanUpRetrievedDoc(_doc.data(), id); + dispatch('applyHooksAndUpdateState', { change: 'added', id: id, doc: doc }); + return [2 /*return*/, doc]; + case 2: + e_1 = _b.sent(); + return [2 /*return*/, error(e_1)]; + case 3: return [2 /*return*/]; + } + }); + }); + }, applyHooksAndUpdateState: function (// this is only on server retrievals _a, _b) { var getters = _a.getters, state = _a.state, commit = _a.commit, dispatch = _a.dispatch; @@ -1741,9 +1768,9 @@ function pluginActions (Firebase) { return [2 /*return*/, resolve()]; } }); - }); }, function (error) { + }); }, function (error$1) { state._sync.patching = 'error'; - return reject(error); + return reject(error(error$1)); }); state._sync.unsubscribe[identifier] = unsubscribe; }); @@ -1845,7 +1872,7 @@ function pluginActions (Firebase) { var id = (getters.collectionMode) ? getId(doc) : getters.docModeId; var value = (getters.collectionMode) ? getValueFromPayloadPiece(doc) : doc; if (!id && getters.collectionMode) - return; + return error('patch-missing-id'); // check userId dispatch('setUserId'); // add id to value @@ -1904,12 +1931,12 @@ function pluginActions (Firebase) { if (pathDelete) { var path = _id; if (!path) - return error('actionsDeleteMissingPath'); + return error('delete-missing-path'); commit('DELETE_PROP', path); return dispatch('deleteProp', path); } if (!_id) - return error('actionsDeleteMissingId'); + return error('delete-missing-id'); commit('DELETE_DOC', _id); return dispatch('deleteDoc', _id); } @@ -1937,12 +1964,12 @@ function pluginActions (Firebase) { if (pathDelete) { var path = _id; if (!path) - return error('actionsDeleteMissingPath'); + return error('delete-missing-path'); commit('DELETE_PROP', path); return dispatch('deleteProp', path); } if (!_id) - return error('actionsDeleteMissingId'); + return error('delete-missing-id'); commit('DELETE_DOC', _id); return dispatch('deleteDoc', _id); }); @@ -2151,7 +2178,7 @@ function pluginGetters (Firebase) { return; } if (!Object.keys(state._sync.pathVariables).includes(key)) { - return error('missingPathVarKey'); + return error('missing-path-variables'); } var varVal = state._sync.pathVariables[key]; // if path is only a param we need to just assign to avoid stringification diff --git a/types/module/errors.d.ts b/types/module/errors.d.ts index e0871c11..e846b9dc 100644 --- a/types/module/errors.d.ts +++ b/types/module/errors.d.ts @@ -2,7 +2,8 @@ * execute Error() based on an error id string * * @export - * @param {string} error the error id + * @param {string} errorId the error id + * @param {any} [error] an actual error from an async request or something * @returns {string} the error id */ -export default function (error: string): string; +export default function (errorId: string, error?: any): string; diff --git a/types/src/module/errors.d.ts b/types/src/module/errors.d.ts index e0871c11..e846b9dc 100644 --- a/types/src/module/errors.d.ts +++ b/types/src/module/errors.d.ts @@ -2,7 +2,8 @@ * execute Error() based on an error id string * * @export - * @param {string} error the error id + * @param {string} errorId the error id + * @param {any} [error] an actual error from an async request or something * @returns {string} the error id */ -export default function (error: string): string; +export default function (errorId: string, error?: any): string;