about summary refs log tree commit diff
path: root/app/javascript/mastodon/db
diff options
context:
space:
mode:
authorJenkins <jenkins@jenkins.ninjawedding.org>2018-03-25 15:17:21 +0000
committerJenkins <jenkins@jenkins.ninjawedding.org>2018-03-25 15:17:21 +0000
commit837b3804bfed9db1cf92923c4f6202aa7117d408 (patch)
treec8b5a921754a6b40227364225002332b54d0d0dd /app/javascript/mastodon/db
parent995b59526b06e1f949cba59d76e5e2718a1674f6 (diff)
parent85a395fab6d7077a252bfe6f96673931ea3aa5ee (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.js28
-rw-r--r--app/javascript/mastodon/db/modifier.js93
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);
+}