@urql/exchange-graphcache
Version:
A normalized and configurable cache exchange for urql
159 lines (154 loc) • 5.28 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
var getRequestPromise = request => {
return new Promise((resolve, reject) => {
request.onerror = () => {
reject(request.error);
};
request.onsuccess = () => {
resolve(request.result);
};
});
};
var getTransactionPromise = transaction => {
return new Promise((resolve, reject) => {
transaction.onerror = () => {
reject(transaction.error);
};
transaction.oncomplete = resolve;
});
};
/** Sample storage adapter persisting to IndexedDB. */
/** Creates a default {@link StorageAdapter} which uses IndexedDB for storage.
*
* @param opts - A {@link StorageOptions} configuration object.
* @returns the created {@link StorageAdapter}.
*
* @remarks
* The default storage uses IndexedDB to persist the normalized cache for
* offline use. It demonstrates that the cache can be chunked by timestamps.
*
* Note: We have no data on stability of this storage and our Offline Support
* for large APIs or longterm use. Proceed with caution.
*/
var makeDefaultStorage = opts => {
if (!opts) opts = {};
var callback;
var DB_NAME = opts.idbName || 'graphcache-v4';
var ENTRIES_STORE_NAME = 'entries';
var METADATA_STORE_NAME = 'metadata';
var batch = Object.create(null);
var timestamp = Math.floor(new Date().valueOf() / (1000 * 60 * 60 * 24));
var maxAge = timestamp - (opts.maxAge || 7);
var req = indexedDB.open(DB_NAME, 1);
var database$ = getRequestPromise(req);
req.onupgradeneeded = () => {
req.result.createObjectStore(ENTRIES_STORE_NAME);
req.result.createObjectStore(METADATA_STORE_NAME);
};
var serializeEntry = entry => entry.replace(/:/g, '%3a');
var deserializeEntry = entry => entry.replace(/%3a/g, ':');
var serializeBatch = () => {
var data = '';
for (var key in batch) {
var value = batch[key];
data += serializeEntry(key);
data += ':';
if (value) data += serializeEntry(value);
data += ':';
}
return data;
};
var deserializeBatch = input => {
var data = {};
var char = '';
var key = '';
var entry = '';
var mode = 0;
var index = 0;
while (index < input.length) {
entry = '';
while ((char = input[index++]) !== ':' && char) {
entry += char;
}
if (mode) {
data[key] = deserializeEntry(entry) || undefined;
mode = 0;
} else {
key = deserializeEntry(entry);
mode = 1;
}
}
return data;
};
return {
clear() {
return database$.then(database => {
var transaction = database.transaction([METADATA_STORE_NAME, ENTRIES_STORE_NAME], 'readwrite');
transaction.objectStore(METADATA_STORE_NAME).clear();
transaction.objectStore(ENTRIES_STORE_NAME).clear();
batch = Object.create(null);
return getTransactionPromise(transaction);
});
},
readMetadata() {
return database$.then(database => {
return getRequestPromise(database.transaction(METADATA_STORE_NAME, 'readonly').objectStore(METADATA_STORE_NAME).get(METADATA_STORE_NAME));
}, () => null);
},
writeMetadata(metadata) {
database$.then(database => {
return getRequestPromise(database.transaction(METADATA_STORE_NAME, 'readwrite').objectStore(METADATA_STORE_NAME).put(metadata, METADATA_STORE_NAME));
}, () => {
/* noop */
});
},
writeData(entries) {
Object.assign(batch, entries);
var toUndefined = () => undefined;
return database$.then(database => {
return getRequestPromise(database.transaction(ENTRIES_STORE_NAME, 'readwrite').objectStore(ENTRIES_STORE_NAME).put(serializeBatch(), timestamp));
}).then(toUndefined, toUndefined);
},
readData() {
var chunks = [];
return database$.then(database => {
var transaction = database.transaction(ENTRIES_STORE_NAME, 'readwrite');
var store = transaction.objectStore(ENTRIES_STORE_NAME);
var request = (store.openKeyCursor || store.openCursor).call(store);
request.onsuccess = function () {
if (this.result) {
var {
key
} = this.result;
if (typeof key !== 'number' || key < maxAge) {
store.delete(key);
} else {
var _request = store.get(key);
var index = chunks.length;
chunks.push('');
_request.onsuccess = () => {
var result = '' + _request.result;
if (key === timestamp) Object.assign(batch, deserializeBatch(result));
chunks[index] = result;
};
}
this.result.continue();
}
};
return getTransactionPromise(transaction);
}).then(() => deserializeBatch(chunks.join('')), () => batch);
},
onCacheHydrated: opts.onCacheHydrated,
onOnline(cb) {
if (callback) {
window.removeEventListener('online', callback);
callback = undefined;
}
window.addEventListener('online', callback = () => {
cb();
});
}
};
};
exports.makeDefaultStorage = makeDefaultStorage;
//# sourceMappingURL=urql-exchange-graphcache-default-storage.js.map