# All files / src/components LocalStorageInterface.js

82.93% Statements 34/41
100% Branches 8/8
76.92% Functions 10/13
81.08% Lines 30/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144

    7x
    7x
    7x

    14x
    14x

    14x
    14x
    14x

    14x
    8x

    6x

    14x
    14x

    14x

    14x
    14x

    14x
    4x

    14x
    20x
    20x
    6x
    3x

    5x
    5x
    5x

    4x
    5x
    5x

    4x

     import filter from 'lodash/filter';
    import pickBy from 'lodash/pickBy';
    import merge from 'lodash/merge';
    import uniq from 'lodash/uniq';
    import keys from 'lodash/keys';
    import empty from 'lodash/isEmpty';

    /**
     * Creates an interface class to winodow.localStorage, that we can extend
     * This got necessary due to a constant overload and overall downspiraling performance
     *
     */
    export default class LocalStorageInterface {
        /**
         * Create the Interface object to create an archive of the registered
         */
        constructor() {
            this.stateNames = [];
            this.archive = {};
            this.refreshArchive();
        }

        /**
         * This is a different way to filter and control the stored localStorage keys
         * @TODO make this possible
         *
         * @param String name -> the name of the mapped state
         */
        registerStateName(name) {
            const tmpArray = merge([], this.stateNames);
            tmpArray.push(name);
            this.stateNames = uniq(tmpArray);
        }

        /**
         * Returns the saveState function used in VueXPersist
         * It will trigger a cleanup on the already stored keys
         *
         * @param String name  -> the name the Vuex-Persist is storing the state in localStorage
         *
         * @returns function The saveState function used in VueX-Persist
         */
        getSaveState(name) {
            this.archive[name] = {
                name: name,
                created: new Date().getTime()
            }

            this.refreshArchive();
            return this.createSaveState(name);
        }

        /**
         * Cleanup and refresh method.
         * Currently checking the keys for last usage.
         * A key last used more than an hour ago, will be deleted from localStorage
         */
        refreshArchive() {
            const currentTime = new Date().getTime();
            const ttl = currentTime - (1000*60*60); // 1 hour

            let currentStoredArchive = window.localStorage.getItem('LsPersistentStorageArchive');
            try {
                currentStoredArchive = JSON.parse(currentStoredArchive);
            } catch(e) {}

            if(empty(currentStoredArchive)) {
                currentStoredArchive = this.archive;
            } else {
                currentStoredArchive = merge(currentStoredArchive, this.archive);
            }

            const toBeRemoved = filter(currentStoredArchive, (entry) => (entry.created < ttl) );
            this.archive = pickBy(currentStoredArchive, (entry) => (entry.created >= ttl) );

            window.localStorage.setItem('LsPersistentStorageArchive', JSON.stringify(this.archive));

            this.purgeInvalidated(toBeRemoved);
            this.removeDeadReferences();
        }

        /**
         * Method to remove keys from localStorage
         *
         * @param Array toBeRemoved  keys that will be removed from the localStorage
         */
        purgeInvalidated(toBeRemoved) {
            toBeRemoved.forEach((toBeRemovedItem) => {
                window.localStorage.removeItem(toBeRemovedItem.name);
            })
        }

        /**
         * Filters the currently stored keys in localStorage
         * and removes them, if they are not stored in the archive map.
         */
        removeDeadReferences() {
            for (let i=0; i< localStorage.length; i++) {
                const key = localStorage.key( i );
                if(key === 'LsPersistentStorageArchive') { continue; }
                if(keys(this.archive).indexOf(key) < 0) {
                    window.localStorage.removeItem(key);
                }
            }
        }

        updateArchiveTimestamp(name) {
            this.archive[name] = this.archive[name] || {};
            this.archive[name].created = new Date().getTime();
            this.refreshArchive();
        }

        /**
         * SaveState method as used in VuexPersist
         * @see https://github.com/championswimmer/vuex-persist/blob/master/src/index.ts#L218
         *
         * @param String name The name of the state to be created
         *
         * @return λ-function with definition (key, state, storage)
         */
        createSaveState(name) {
            const saveState = function(key, state, storage) {
                LS.localStorageInterface.updateArchiveTimestamp(name);
                storage.setItem(
                    key,
                    JSON.stringify(state)
                );
            }

            return saveState;

        }

        /**
         * Returns the window localStorage
         * @TODO create alternatives
         */
        getLocalStorage() {
            return window.localStorage;
        }

    }