From 522105a858650c148a83f561db976b0122d76fba Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 26 Jan 2017 16:57:59 +0000 Subject: [PATCH] First cut --- src/store/indexeddb.js | 120 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 110 insertions(+), 10 deletions(-) diff --git a/src/store/indexeddb.js b/src/store/indexeddb.js index 111fd378e..b0c92e745 100644 --- a/src/store/indexeddb.js +++ b/src/store/indexeddb.js @@ -1,5 +1,5 @@ /* -Copyright 2015, 2016 OpenMarket Ltd +Copyright 2017 OpenMarket Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ limitations under the License. */ "use strict"; +import q from "q"; + /** * This is an internal module. See {@link IndexedDBStore} for the public class. * @module store/indexeddb @@ -41,7 +43,7 @@ module.exports.IndexedDBStore.prototype = { */ connect: function() { if (this.db) { - return Promise.resolve(); + return q(); } const req = this.indexedDB.open("matrix-js-sdk", VERSION); req.onupgradeneeded = (ev) => { @@ -51,19 +53,117 @@ module.exports.IndexedDBStore.prototype = { createDatabase(db); } // Expand as needed. - } - return promiseify(req).then((ev) => { + }; + return promiseifyRequest(req).then((ev) => { this.db = ev.target.result; }); - } -} + }, + + /** + * Clear the entire database. This should be used when logging out of a client + * to prevent mixing data between accounts. + * @return {Promise} Resolved when the database is cleared. + */ + clearDatabase: function() { + return promiseifyRequest(this.indexedDB.deleteDatabase("matrix-js-sdk")); + }, + + /** + * Persist a list of Room objects. + * @param {Room[]} rooms An array of rooms + * @return {Promise} Resolves if the rooms were persisted. + */ + persistRooms: function(rooms) { + return q.try(() => { + const txn = this.db.transaction(["rooms"], "readwrite"); + const store = txn.objectStore("rooms"); + for (let i =0; i < rooms.length; i++) { + store.put(rooms[i]); // put == UPSERT + } + return promiseifyTxn(txn); + }); + }, + + /** + * Persist a sync token. + * @param {string} syncToken The token to persist. + * @return {Promise} Resolves if the token was persisted. + */ + persistSyncToken: function(syncToken) { + const obj = { + clobber: "-", // constant key so will always clobber + syncToken: syncToken, + }; + return q.try(() => { + const txn = this.db.transaction(["config"], "readwrite"); + const store = txn.objectStore("config"); + store.put(obj); // put == UPSERT + return promiseifyTxn(txn); + }); + }, + + /** + * Persist a list of account data events. + * @param {MatrixEvent[]} accountData An array of user-scoped account data events + * @return {Promise} Resolves if the events were persisted. + */ + persistAccountData: function(accountData) { + return q.try(() => { + const txn = this.db.transaction(["accountData"], "readwrite"); + const store = txn.objectStore("accountData"); + for (let i =0; i < accountData.length; i++) { + store.put(accountData[i]); // put == UPSERT + } + return promiseifyTxn(txn); + }); + }, + + /** + * Persist a list of User objects. + * @param {User[]} users An array of users + * @return {Promise} Resolves if the users were persisted. + */ + persistUsers: function(users) { + return q.try(() => { + const txn = this.db.transaction(["users"], "readwrite"); + const store = txn.objectStore("users"); + for (let i =0; i < users.length; i++) { + store.put(users[i]); // put == UPSERT + } + return promiseifyTxn(txn); + }); + }, + +}; function createDatabase(db) { - // TODO: Make object stores and indexes. + // Make room store, clobber based on room ID. (roomId property of Room objects) + db.createObjectStore("rooms", { keyPath: ["roomId"] }); + + // Make user store, clobber based on user ID. (userId property of User objects) + db.createObjectStore("users", { keyPath: ["userId"] }); + + // Make account data store, clobber based on event type. + // (event.type property of MatrixEvent objects) + db.createObjectStore("accountData", { keyPath: ["event.type"] }); + + // Make configuration store (sync tokens, etc), always clobber (const key). + db.createObjectStore("config", { keyPath: ["clobber"] }); } -function promiseify(req) { - return new Promise((resolve, reject) => { +function promiseifyTxn(txn) { + return new q.Promise((resolve, reject) => { + txn.oncomplete = function(event) { + resolve(event); + }; + txn.onerror = function(event) { + reject(event); + }; + }); +} + +function promiseifyRequest(req) { + return new q.Promise((resolve, reject) => { req.onsuccess = function(event) { resolve(event); }; @@ -71,4 +171,4 @@ function promiseify(req) { reject(event); }; }); -} \ No newline at end of file +}