From 111efe6130acdf6316ac2a3637bdcf46f89ce425 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Wed, 4 Nov 2020 21:21:57 +1300 Subject: [PATCH] Splitting out library utils, fixing spread of null, should fix #629 --- src/js/services/core/middleware.js | 121 ++-------------------- src/js/util/library.js | 161 +++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 114 deletions(-) create mode 100644 src/js/util/library.js diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index cc6c1366..d797da84 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -4,7 +4,13 @@ import localForage from 'localforage'; import { compact } from 'lodash'; import { arrayOf } from '../../util/arrays'; import URILink from '../../components/URILink'; -import { uriSource, upgradeSpotifyPlaylistUris, uriType, titleCase } from '../../util/helpers'; +import { + uriSource, + upgradeSpotifyPlaylistUris, + uriType, + titleCase, +} from '../../util/helpers'; +import { ensureLoaded } from '../../util/library'; import { formatTracks, formatTrack, @@ -18,114 +24,6 @@ const mopidyActions = require('../mopidy/actions.js'); const googleActions = require('../google/actions.js'); const spotifyActions = require('../spotify/actions.js'); -/** - * Ensure we have an item in our index - * If it's not there, attempt to fetch it from our cold storage - * If it's not their either, call the provided fetch() - * - * @param {*} Object { store, action, fetch, dependents} - */ -const ensureLoaded = ({ - store, - containerName = 'items', - action, - fetch, - dependents = [], - fullDependents = [], -}) => { - const { - uri, - options: { - forceRefetch, - full, - }, - } = action; - const { - core: { - [containerName]: { - [uri]: item, - } = {}, - } = {}, - } = store.getState(); - - const getMissingDependents = (parent) => { - const allDependents = [...dependents, ...fullDependents]; - if (!parent) return allDependents; - if (full) { - return allDependents.filter((dep) => parent[dep] === undefined || parent[dep] === null); - } - return dependents.filter((dep) => parent[dep] === undefined || parent[dep] === null); - }; - - const getDependentUris = (parent) => { - if (!parent) return []; - - return [...dependents, ...fullDependents].reduce( - (acc, dependent) => { - return [ - ...acc, - ...(dependent.match(new RegExp('(.*)_uri(.*)')) ? parent[dependent] : []), - ]; - }, - [], - ); - }; - - // Forced refetch bypasses everything - if (forceRefetch) { - console.info(`Force-refetching "${uri}"`); - fetch(); - return; - } - - // Item already in our index? - if (item) { - if (getMissingDependents(item).length === 0) { - store.dispatch(uiActions.stopLoading(uri)); - console.info(`"${uri}" already in index`); - - const dependentUris = getDependentUris(item); - if (dependentUris.length) { - console.log(`Loading ${dependentUris.length} dependents`); - store.dispatch(coreActions.loadItems(dependentUris)); - } - return; - } - } - - // What about in the coldstore? - localForage.getItem(uri).then((restoredItem) => { - if (!restoredItem || getMissingDependents(restoredItem).length > 0) { - fetch(); - return; - } - - console.info(`Restoring "${uri}" from database`); - store.dispatch(coreActions.restoreItemsFromColdStore([restoredItem])); - - // We already have the dependents of our restored item, so restore them. - // We assume that because THIS item is in the coldstore, its dependents - // are as well. - const dependentUris = getDependentUris(restoredItem); - if (dependentUris.length > 0) { - console.info(`Restoring ${dependentUris.length} dependents from database`); - - const restoreAllDependents = dependentUris.map( - (dependentUri) => localForage.getItem(dependentUri), - ); - Promise.all(restoreAllDependents).then( - (dependentItems) => { - store.dispatch( - coreActions.restoreItemsFromColdStore( - compact(dependentItems), // Squash nulls (ie items not found in coldstore) - ), - ); - }, - ); - } - }); -}; - const CoreMiddleware = (function () { return (store) => (next) => (action = {}) => { const { @@ -352,10 +250,6 @@ const CoreMiddleware = (function () { break; } - case 'RESTART': - location.reload(); - break; - case 'PLAYLIST_TRACKS_ADDED': { const { key, @@ -378,7 +272,6 @@ const CoreMiddleware = (function () { switch (uriSource(key)) { case 'spotify': - console.log("GETTING", key) store.dispatch(spotifyActions.getPlaylist(key)); break; case 'm3u': diff --git a/src/js/util/library.js b/src/js/util/library.js new file mode 100644 index 00000000..9cbc8236 --- /dev/null +++ b/src/js/util/library.js @@ -0,0 +1,161 @@ +import { compact } from 'lodash'; +import localForage from 'localforage'; + +const coreActions = require('../services/core/actions.js'); +const uiActions = require('../services/ui/actions.js'); + +/** + * Inspect object to check for missing dependent properties + * + * @param {Object} = item, dependents, fullDependents, full + */ +const getMissingDependents = ({ + item, + dependents = [], + fullDependents = [], + full, +}) => { + const allDependents = [ + ...dependents, + ...fullDependents, + ]; + if (!item) return allDependents; + if (full) { + return allDependents.filter((dep) => item[dep] === undefined || item[dep] === null); + } + return dependents.filter((dep) => item[dep] === undefined || item[dep] === null); +}; + +/** + * Pluck all the URIs out of our dependent properties. + * + * @param {Object} = item, dependents, fullDependents + */ +const getDependentUris = ({ + item, + dependents = [], + fullDependents = [], +}) => { + if (!item) return []; + + return [...dependents, ...fullDependents].reduce( + (acc, dep) => [ + ...acc, + ...(dep.match(new RegExp('(.*)_uri(.*)')) ? item[dep] : []), + ], + [], + ); +}; + +/** + * Ensure we have an item in our index + * If it's not there, attempt to fetch it from our cold storage + * If it's not their either, call the provided fetch() + * + * @param {*} Object { store, action, fetch, dependents} + */ +const ensureLoaded = ({ + store, + containerName = 'items', + action, + fetch, + dependents = [], + fullDependents = [], +}) => { + const { + uri, + options: { + forceRefetch, + full, + }, + } = action; + const { + core: { + [containerName]: { + [uri]: item, + } = {}, + } = {}, + } = store.getState(); + + // Forced refetch bypasses everything + if (forceRefetch) { + console.info(`Force-refetching "${uri}"`); + fetch(); + return; + } + + const missingDependents = (itemToCheck) => getMissingDependents({ + item: itemToCheck, + dependents, + fullDependents, + full, + }); + + const dependentUris = (itemToCheck) => getDependentUris({ + item: itemToCheck, + dependents, + fullDependents, + }); + + // Item already in our index? + if (item) { + if (missingDependents(item).length === 0) { + store.dispatch(uiActions.stopLoading(uri)); + console.info(`"${uri}" already in index`); + + const uris = dependentUris(item); + if (uris.length) { + console.log(`Loading ${uris.length} dependents`); + store.dispatch(coreActions.loadItems(uris)); + } + return; + } + } + + // What about in the coldstore? + localForage.getItem(uri).then((restoredItem) => { + if ( + !restoredItem || + missingDependents(restoredItem).length > 0 + ) { + fetch(); + return; + } + + console.info(`Restoring "${uri}" from database`); + store.dispatch(coreActions.restoreItemsFromColdStore([restoredItem])); + + // We already have the dependents of our restored item, so restore them. + // We assume that because THIS item is in the coldstore, its dependents + // are as well. + const uris = dependentUris(restoredItem); + if (uris.length > 0) { + console.info(`Restoring ${uris.length} dependents from database`); + + const restoreAllDependents = uris.map( + (dependentUri) => localForage.getItem(dependentUri), + ); + Promise.all(restoreAllDependents).then( + (dependentItems) => { + store.dispatch( + coreActions.restoreItemsFromColdStore( + compact(dependentItems), // Squash nulls (ie items not found in coldstore) + ), + ); + }, + ); + } + }); +}; + +export { + getMissingDependents, + getDependentUris, + ensureLoaded, +}; + +export default { + getMissingDependents, + getDependentUris, + ensureLoaded, +};