diff options
author | Jenkins <jenkins@jenkins.ninjawedding.org> | 2018-03-25 15:17:21 +0000 |
---|---|---|
committer | Jenkins <jenkins@jenkins.ninjawedding.org> | 2018-03-25 15:17:21 +0000 |
commit | 837b3804bfed9db1cf92923c4f6202aa7117d408 (patch) | |
tree | c8b5a921754a6b40227364225002332b54d0d0dd /app/javascript/mastodon/db | |
parent | 995b59526b06e1f949cba59d76e5e2718a1674f6 (diff) | |
parent | 85a395fab6d7077a252bfe6f96673931ea3aa5ee (diff) |
Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master
Diffstat (limited to 'app/javascript/mastodon/db')
-rw-r--r-- | app/javascript/mastodon/db/async.js | 28 | ||||
-rw-r--r-- | app/javascript/mastodon/db/modifier.js | 93 |
2 files changed, 121 insertions, 0 deletions
diff --git a/app/javascript/mastodon/db/async.js b/app/javascript/mastodon/db/async.js new file mode 100644 index 000000000..e08fc3f3d --- /dev/null +++ b/app/javascript/mastodon/db/async.js @@ -0,0 +1,28 @@ +import { me } from '../initial_state'; + +export default new Promise((resolve, reject) => { + // Microsoft Edge 17 does not support getAll according to: + // Catalog of standard and vendor APIs across browsers - Microsoft Edge Development + // https://developer.microsoft.com/en-us/microsoft-edge/platform/catalog/?q=specName%3Aindexeddb + if (!me || !('getAll' in IDBObjectStore.prototype)) { + reject(); + return; + } + + const request = indexedDB.open('mastodon:' + me); + + request.onerror = reject; + request.onsuccess = ({ target }) => resolve(target.result); + + request.onupgradeneeded = ({ target }) => { + const accounts = target.result.createObjectStore('accounts', { autoIncrement: true }); + const statuses = target.result.createObjectStore('statuses', { autoIncrement: true }); + + accounts.createIndex('id', 'id', { unique: true }); + accounts.createIndex('moved', 'moved'); + + statuses.createIndex('id', 'id', { unique: true }); + statuses.createIndex('account', 'account'); + statuses.createIndex('reblog', 'reblog'); + }; +}); diff --git a/app/javascript/mastodon/db/modifier.js b/app/javascript/mastodon/db/modifier.js new file mode 100644 index 000000000..eb951905a --- /dev/null +++ b/app/javascript/mastodon/db/modifier.js @@ -0,0 +1,93 @@ +import asyncDB from './async'; + +const limit = 1024; + +function put(name, objects, callback) { + asyncDB.then(db => { + const putTransaction = db.transaction(name, 'readwrite'); + const putStore = putTransaction.objectStore(name); + const putIndex = putStore.index('id'); + + objects.forEach(object => { + function add() { + putStore.add(object); + } + + putIndex.getKey(object.id).onsuccess = retrieval => { + if (retrieval.target.result) { + putStore.delete(retrieval.target.result).onsuccess = add; + } else { + add(); + } + }; + }); + + putTransaction.oncomplete = () => { + const readTransaction = db.transaction(name, 'readonly'); + const readStore = readTransaction.objectStore(name); + + readStore.count().onsuccess = count => { + const excess = count.target.result - limit; + + if (excess > 0) { + readStore.getAll(null, excess).onsuccess = + retrieval => callback(retrieval.target.result.map(({ id }) => id)); + } + }; + }; + }); +} + +export function evictAccounts(ids) { + asyncDB.then(db => { + const transaction = db.transaction(['accounts', 'statuses'], 'readwrite'); + const accounts = transaction.objectStore('accounts'); + const accountsIdIndex = accounts.index('id'); + const accountsMovedIndex = accounts.index('moved'); + const statuses = transaction.objectStore('statuses'); + const statusesIndex = statuses.index('account'); + + function evict(toEvict) { + toEvict.forEach(id => { + accountsMovedIndex.getAllKeys(id).onsuccess = + ({ target }) => evict(target.result); + + statusesIndex.getAll(id).onsuccess = + ({ target }) => evictStatuses(target.result.map(({ id }) => id)); + + accountsIdIndex.getKey(id).onsuccess = + ({ target }) => target.result && accounts.delete(target.result); + }); + } + + evict(ids); + }); +} + +export function evictStatus(id) { + return evictStatuses([id]); +} + +export function evictStatuses(ids) { + asyncDB.then(db => { + const store = db.transaction('statuses', 'readwrite').objectStore('statuses'); + const idIndex = store.index('id'); + const reblogIndex = store.index('reblog'); + + ids.forEach(id => { + reblogIndex.getAllKeys(id).onsuccess = + ({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey)); + + idIndex.getKey(id).onsuccess = + ({ target }) => target.result && store.delete(target.result); + }); + }); +} + +export function putAccounts(records) { + put('accounts', records, evictAccounts); +} + +export function putStatuses(records) { + put('statuses', records, evictStatuses); +} |