prepare storage to work with alternative idb impl
This commit is contained in:
parent
8dfed73524
commit
edbac25613
16 changed files with 61 additions and 48 deletions
|
@ -21,8 +21,9 @@ import { reqAsPromise } from "./utils.js";
|
||||||
const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey";
|
const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey";
|
||||||
|
|
||||||
export class Storage {
|
export class Storage {
|
||||||
constructor(idbDatabase, hasWebkitEarlyCloseTxnBug) {
|
constructor(idbDatabase, IDBKeyRange, hasWebkitEarlyCloseTxnBug) {
|
||||||
this._db = idbDatabase;
|
this._db = idbDatabase;
|
||||||
|
this._IDBKeyRange = IDBKeyRange;
|
||||||
this._hasWebkitEarlyCloseTxnBug = hasWebkitEarlyCloseTxnBug;
|
this._hasWebkitEarlyCloseTxnBug = hasWebkitEarlyCloseTxnBug;
|
||||||
const nameMap = STORE_NAMES.reduce((nameMap, name) => {
|
const nameMap = STORE_NAMES.reduce((nameMap, name) => {
|
||||||
nameMap[name] = name;
|
nameMap[name] = name;
|
||||||
|
@ -47,7 +48,7 @@ export class Storage {
|
||||||
if (this._hasWebkitEarlyCloseTxnBug) {
|
if (this._hasWebkitEarlyCloseTxnBug) {
|
||||||
await reqAsPromise(txn.objectStore(storeNames[0]).get(WEBKITEARLYCLOSETXNBUG_BOGUS_KEY));
|
await reqAsPromise(txn.objectStore(storeNames[0]).get(WEBKITEARLYCLOSETXNBUG_BOGUS_KEY));
|
||||||
}
|
}
|
||||||
return new Transaction(txn, storeNames);
|
return new Transaction(txn, storeNames, this._IDBKeyRange);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
throw new StorageError("readTxn failed", err);
|
throw new StorageError("readTxn failed", err);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ export class Storage {
|
||||||
if (this._hasWebkitEarlyCloseTxnBug) {
|
if (this._hasWebkitEarlyCloseTxnBug) {
|
||||||
await reqAsPromise(txn.objectStore(storeNames[0]).get(WEBKITEARLYCLOSETXNBUG_BOGUS_KEY));
|
await reqAsPromise(txn.objectStore(storeNames[0]).get(WEBKITEARLYCLOSETXNBUG_BOGUS_KEY));
|
||||||
}
|
}
|
||||||
return new Transaction(txn, storeNames);
|
return new Transaction(txn, storeNames, this._IDBKeyRange);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
throw new StorageError("readWriteTxn failed", err);
|
throw new StorageError("readWriteTxn failed", err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,18 @@ import { schema } from "./schema.js";
|
||||||
import { detectWebkitEarlyCloseTxnBug } from "./quirks.js";
|
import { detectWebkitEarlyCloseTxnBug } from "./quirks.js";
|
||||||
|
|
||||||
const sessionName = sessionId => `hydrogen_session_${sessionId}`;
|
const sessionName = sessionId => `hydrogen_session_${sessionId}`;
|
||||||
const openDatabaseWithSessionId = sessionId => openDatabase(sessionName(sessionId), createStores, schema.length);
|
const openDatabaseWithSessionId = function(sessionId, idbFactory) {
|
||||||
|
return openDatabase(sessionName(sessionId), createStores, schema.length, idbFactory);
|
||||||
|
}
|
||||||
|
|
||||||
async function requestPersistedStorage() {
|
async function requestPersistedStorage() {
|
||||||
if (navigator?.storage?.persist) {
|
// don't assume browser so we can run in node with fake-idb
|
||||||
return await navigator.storage.persist();
|
const glob = this;
|
||||||
} else if (document.requestStorageAccess) {
|
if (glob?.navigator?.storage?.persist) {
|
||||||
|
return await glob.navigator.storage.persist();
|
||||||
|
} else if (glob?.document.requestStorageAccess) {
|
||||||
try {
|
try {
|
||||||
await document.requestStorageAccess();
|
await glob.document.requestStorageAccess();
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -39,8 +43,10 @@ async function requestPersistedStorage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StorageFactory {
|
export class StorageFactory {
|
||||||
constructor(serviceWorkerHandler) {
|
constructor(serviceWorkerHandler, idbFactory = window.indexedDB, IDBKeyRange = window.IDBKeyRange) {
|
||||||
this._serviceWorkerHandler = serviceWorkerHandler;
|
this._serviceWorkerHandler = serviceWorkerHandler;
|
||||||
|
this._idbFactory = idbFactory;
|
||||||
|
this._IDBKeyRange = IDBKeyRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(sessionId) {
|
async create(sessionId) {
|
||||||
|
@ -52,24 +58,24 @@ export class StorageFactory {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasWebkitEarlyCloseTxnBug = await detectWebkitEarlyCloseTxnBug();
|
const hasWebkitEarlyCloseTxnBug = await detectWebkitEarlyCloseTxnBug(this._idbFactory);
|
||||||
const db = await openDatabaseWithSessionId(sessionId);
|
const db = await openDatabaseWithSessionId(sessionId, this._idbFactory);
|
||||||
return new Storage(db, hasWebkitEarlyCloseTxnBug);
|
return new Storage(db, this._IDBKeyRange, hasWebkitEarlyCloseTxnBug);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(sessionId) {
|
delete(sessionId) {
|
||||||
const databaseName = sessionName(sessionId);
|
const databaseName = sessionName(sessionId);
|
||||||
const req = indexedDB.deleteDatabase(databaseName);
|
const req = this._idbFactory.deleteDatabase(databaseName);
|
||||||
return reqAsPromise(req);
|
return reqAsPromise(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
async export(sessionId) {
|
async export(sessionId) {
|
||||||
const db = await openDatabaseWithSessionId(sessionId);
|
const db = await openDatabaseWithSessionId(sessionId, this._idbFactory);
|
||||||
return await exportSession(db);
|
return await exportSession(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
async import(sessionId, data) {
|
async import(sessionId, data) {
|
||||||
const db = await openDatabaseWithSessionId(sessionId);
|
const db = await openDatabaseWithSessionId(sessionId, this._idbFactory);
|
||||||
return await importSession(db, data);
|
return await importSession(db, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,10 @@ export class Store extends QueryTarget {
|
||||||
this._transaction = transaction;
|
this._transaction = transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get IDBKeyRange() {
|
||||||
|
return this._transaction.IDBKeyRange;
|
||||||
|
}
|
||||||
|
|
||||||
get _idbStore() {
|
get _idbStore() {
|
||||||
return this._target;
|
return this._target;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,11 @@ import {OperationStore} from "./stores/OperationStore.js";
|
||||||
import {AccountDataStore} from "./stores/AccountDataStore.js";
|
import {AccountDataStore} from "./stores/AccountDataStore.js";
|
||||||
|
|
||||||
export class Transaction {
|
export class Transaction {
|
||||||
constructor(txn, allowedStoreNames) {
|
constructor(txn, allowedStoreNames, IDBKeyRange) {
|
||||||
this._txn = txn;
|
this._txn = txn;
|
||||||
this._allowedStoreNames = allowedStoreNames;
|
this._allowedStoreNames = allowedStoreNames;
|
||||||
this._stores = {};
|
this._stores = {};
|
||||||
|
this.IDBKeyRange = IDBKeyRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
_idbStore(name) {
|
_idbStore(name) {
|
||||||
|
@ -46,7 +47,7 @@ export class Transaction {
|
||||||
// more specific error? this is a bug, so maybe not ...
|
// more specific error? this is a bug, so maybe not ...
|
||||||
throw new StorageError(`Invalid store for transaction: ${name}, only ${this._allowedStoreNames.join(", ")} are allowed.`);
|
throw new StorageError(`Invalid store for transaction: ${name}, only ${this._allowedStoreNames.join(", ")} are allowed.`);
|
||||||
}
|
}
|
||||||
return new Store(this._txn.objectStore(name));
|
return new Store(this._txn.objectStore(name), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_store(name, mapStore) {
|
_store(name, mapStore) {
|
||||||
|
|
|
@ -18,12 +18,12 @@ limitations under the License.
|
||||||
import {openDatabase, txnAsPromise, reqAsPromise} from "./utils.js";
|
import {openDatabase, txnAsPromise, reqAsPromise} from "./utils.js";
|
||||||
|
|
||||||
// filed as https://bugs.webkit.org/show_bug.cgi?id=222746
|
// filed as https://bugs.webkit.org/show_bug.cgi?id=222746
|
||||||
export async function detectWebkitEarlyCloseTxnBug() {
|
export async function detectWebkitEarlyCloseTxnBug(idbFactory) {
|
||||||
const dbName = "hydrogen_webkit_test_inactive_txn_bug";
|
const dbName = "hydrogen_webkit_test_inactive_txn_bug";
|
||||||
try {
|
try {
|
||||||
const db = await openDatabase(dbName, db => {
|
const db = await openDatabase(dbName, db => {
|
||||||
db.createObjectStore("test", {keyPath: "key"});
|
db.createObjectStore("test", {keyPath: "key"});
|
||||||
}, 1);
|
}, 1, idbFactory);
|
||||||
const readTxn = db.transaction(["test"], "readonly");
|
const readTxn = db.transaction(["test"], "readonly");
|
||||||
await reqAsPromise(readTxn.objectStore("test").get("somekey"));
|
await reqAsPromise(readTxn.objectStore("test").get("somekey"));
|
||||||
// schedule a macro task in between the two txns
|
// schedule a macro task in between the two txns
|
||||||
|
|
|
@ -31,7 +31,7 @@ export class DeviceIdentityStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllForUserId(userId) {
|
getAllForUserId(userId) {
|
||||||
const range = IDBKeyRange.lowerBound(encodeKey(userId, ""));
|
const range = this._store.IDBKeyRange.lowerBound(encodeKey(userId, ""));
|
||||||
return this._store.selectWhile(range, device => {
|
return this._store.selectWhile(range, device => {
|
||||||
return device.userId === userId;
|
return device.userId === userId;
|
||||||
});
|
});
|
||||||
|
@ -39,7 +39,7 @@ export class DeviceIdentityStore {
|
||||||
|
|
||||||
async getAllDeviceIds(userId) {
|
async getAllDeviceIds(userId) {
|
||||||
const deviceIds = [];
|
const deviceIds = [];
|
||||||
const range = IDBKeyRange.lowerBound(encodeKey(userId, ""));
|
const range = this._store.IDBKeyRange.lowerBound(encodeKey(userId, ""));
|
||||||
await this._store.iterateKeys(range, key => {
|
await this._store.iterateKeys(range, key => {
|
||||||
const decodedKey = decodeKey(key);
|
const decodedKey = decodeKey(key);
|
||||||
// prevent running into the next room
|
// prevent running into the next room
|
||||||
|
@ -72,7 +72,7 @@ export class DeviceIdentityStore {
|
||||||
removeAllForUser(userId) {
|
removeAllForUser(userId) {
|
||||||
// exclude both keys as they are theoretical min and max,
|
// exclude both keys as they are theoretical min and max,
|
||||||
// but we should't have a match for just the room id, or room id with max
|
// but we should't have a match for just the room id, or room id with max
|
||||||
const range = IDBKeyRange.bound(encodeKey(userId, MIN_UNICODE), encodeKey(userId, MAX_UNICODE), true, true);
|
const range = this._store.IDBKeyRange.bound(encodeKey(userId, MIN_UNICODE), encodeKey(userId, MAX_UNICODE), true, true);
|
||||||
this._store.delete(range);
|
this._store.delete(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class GroupSessionDecryptionStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAllForRoom(roomId) {
|
removeAllForRoom(roomId) {
|
||||||
const range = IDBKeyRange.bound(
|
const range = this._store.IDBKeyRange.bound(
|
||||||
encodeKey(roomId, MIN_UNICODE, MIN_UNICODE),
|
encodeKey(roomId, MIN_UNICODE, MIN_UNICODE),
|
||||||
encodeKey(roomId, MAX_UNICODE, MAX_UNICODE)
|
encodeKey(roomId, MAX_UNICODE, MAX_UNICODE)
|
||||||
);
|
);
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class InboundGroupSessionStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAllForRoom(roomId) {
|
removeAllForRoom(roomId) {
|
||||||
const range = IDBKeyRange.bound(
|
const range = this._store.IDBKeyRange.bound(
|
||||||
encodeKey(roomId, MIN_UNICODE, MIN_UNICODE),
|
encodeKey(roomId, MIN_UNICODE, MIN_UNICODE),
|
||||||
encodeKey(roomId, MAX_UNICODE, MAX_UNICODE)
|
encodeKey(roomId, MAX_UNICODE, MAX_UNICODE)
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class OlmSessionStore {
|
||||||
|
|
||||||
async getSessionIds(senderKey) {
|
async getSessionIds(senderKey) {
|
||||||
const sessionIds = [];
|
const sessionIds = [];
|
||||||
const range = IDBKeyRange.lowerBound(encodeKey(senderKey, ""));
|
const range = this._store.IDBKeyRange.lowerBound(encodeKey(senderKey, ""));
|
||||||
await this._store.iterateKeys(range, key => {
|
await this._store.iterateKeys(range, key => {
|
||||||
const decodedKey = decodeKey(key);
|
const decodedKey = decodeKey(key);
|
||||||
// prevent running into the next room
|
// prevent running into the next room
|
||||||
|
@ -44,7 +44,7 @@ export class OlmSessionStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(senderKey) {
|
getAll(senderKey) {
|
||||||
const range = IDBKeyRange.lowerBound(encodeKey(senderKey, ""));
|
const range = this._store.IDBKeyRange.lowerBound(encodeKey(senderKey, ""));
|
||||||
return this._store.selectWhile(range, session => {
|
return this._store.selectWhile(range, session => {
|
||||||
return session.senderKey === senderKey;
|
return session.senderKey === senderKey;
|
||||||
});
|
});
|
||||||
|
|
|
@ -55,7 +55,7 @@ export class OperationStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeAllForScope(scope) {
|
async removeAllForScope(scope) {
|
||||||
const range = IDBKeyRange.bound(
|
const range = this._store.IDBKeyRange.bound(
|
||||||
encodeScopeTypeKey(scope, MIN_UNICODE),
|
encodeScopeTypeKey(scope, MIN_UNICODE),
|
||||||
encodeScopeTypeKey(scope, MAX_UNICODE)
|
encodeScopeTypeKey(scope, MAX_UNICODE)
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,7 +33,7 @@ export class PendingEventStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMaxQueueIndex(roomId) {
|
async getMaxQueueIndex(roomId) {
|
||||||
const range = IDBKeyRange.bound(
|
const range = this._eventStore.IDBKeyRange.bound(
|
||||||
encodeKey(roomId, KeyLimits.minStorageKey),
|
encodeKey(roomId, KeyLimits.minStorageKey),
|
||||||
encodeKey(roomId, KeyLimits.maxStorageKey),
|
encodeKey(roomId, KeyLimits.maxStorageKey),
|
||||||
false,
|
false,
|
||||||
|
@ -46,12 +46,12 @@ export class PendingEventStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(roomId, queueIndex) {
|
remove(roomId, queueIndex) {
|
||||||
const keyRange = IDBKeyRange.only(encodeKey(roomId, queueIndex));
|
const keyRange = this._eventStore.IDBKeyRange.only(encodeKey(roomId, queueIndex));
|
||||||
this._eventStore.delete(keyRange);
|
this._eventStore.delete(keyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
async exists(roomId, queueIndex) {
|
async exists(roomId, queueIndex) {
|
||||||
const keyRange = IDBKeyRange.only(encodeKey(roomId, queueIndex));
|
const keyRange = this._eventStore.IDBKeyRange.only(encodeKey(roomId, queueIndex));
|
||||||
const key = await this._eventStore.getKey(keyRange);
|
const key = await this._eventStore.getKey(keyRange);
|
||||||
return !!key;
|
return !!key;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ export class PendingEventStore {
|
||||||
removeAllForRoom(roomId) {
|
removeAllForRoom(roomId) {
|
||||||
const minKey = encodeKey(roomId, KeyLimits.minStorageKey);
|
const minKey = encodeKey(roomId, KeyLimits.minStorageKey);
|
||||||
const maxKey = encodeKey(roomId, KeyLimits.maxStorageKey);
|
const maxKey = encodeKey(roomId, KeyLimits.maxStorageKey);
|
||||||
const range = IDBKeyRange.bound(minKey, maxKey);
|
const range = this._eventStore.IDBKeyRange.bound(minKey, maxKey);
|
||||||
this._eventStore.delete(range);
|
this._eventStore.delete(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ export class RoomMemberStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(roomId) {
|
getAll(roomId) {
|
||||||
const range = IDBKeyRange.lowerBound(encodeKey(roomId, ""));
|
const range = this._roomMembersStore.IDBKeyRange.lowerBound(encodeKey(roomId, ""));
|
||||||
return this._roomMembersStore.selectWhile(range, member => {
|
return this._roomMembersStore.selectWhile(range, member => {
|
||||||
return member.roomId === roomId;
|
return member.roomId === roomId;
|
||||||
});
|
});
|
||||||
|
@ -50,7 +50,7 @@ export class RoomMemberStore {
|
||||||
|
|
||||||
async getAllUserIds(roomId) {
|
async getAllUserIds(roomId) {
|
||||||
const userIds = [];
|
const userIds = [];
|
||||||
const range = IDBKeyRange.lowerBound(encodeKey(roomId, ""));
|
const range = this._roomMembersStore.IDBKeyRange.lowerBound(encodeKey(roomId, ""));
|
||||||
await this._roomMembersStore.iterateKeys(range, key => {
|
await this._roomMembersStore.iterateKeys(range, key => {
|
||||||
const decodedKey = decodeKey(key);
|
const decodedKey = decodeKey(key);
|
||||||
// prevent running into the next room
|
// prevent running into the next room
|
||||||
|
@ -66,7 +66,7 @@ export class RoomMemberStore {
|
||||||
removeAllForRoom(roomId) {
|
removeAllForRoom(roomId) {
|
||||||
// exclude both keys as they are theoretical min and max,
|
// exclude both keys as they are theoretical min and max,
|
||||||
// but we should't have a match for just the room id, or room id with max
|
// but we should't have a match for just the room id, or room id with max
|
||||||
const range = IDBKeyRange.bound(roomId, `${roomId}|${MAX_UNICODE}`, true, true);
|
const range = this._roomMembersStore.IDBKeyRange.bound(roomId, `${roomId}|${MAX_UNICODE}`, true, true);
|
||||||
this._roomMembersStore.delete(range);
|
this._roomMembersStore.delete(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class RoomStateStore {
|
||||||
removeAllForRoom(roomId) {
|
removeAllForRoom(roomId) {
|
||||||
// exclude both keys as they are theoretical min and max,
|
// exclude both keys as they are theoretical min and max,
|
||||||
// but we should't have a match for just the room id, or room id with max
|
// but we should't have a match for just the room id, or room id with max
|
||||||
const range = IDBKeyRange.bound(roomId, `${roomId}|${MAX_UNICODE}`, true, true);
|
const range = this._roomStateStore.IDBKeyRange.bound(roomId, `${roomId}|${MAX_UNICODE}`, true, true);
|
||||||
this._roomStateStore.delete(range);
|
this._roomStateStore.delete(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@ function decodeEventIdKey(eventIdKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Range {
|
class Range {
|
||||||
constructor(only, lower, upper, lowerOpen, upperOpen) {
|
constructor(IDBKeyRange, only, lower, upper, lowerOpen, upperOpen) {
|
||||||
|
this._IDBKeyRange = IDBKeyRange;
|
||||||
this._only = only;
|
this._only = only;
|
||||||
this._lower = lower;
|
this._lower = lower;
|
||||||
this._upper = upper;
|
this._upper = upper;
|
||||||
|
@ -45,12 +46,12 @@ class Range {
|
||||||
try {
|
try {
|
||||||
// only
|
// only
|
||||||
if (this._only) {
|
if (this._only) {
|
||||||
return IDBKeyRange.only(encodeKey(roomId, this._only.fragmentId, this._only.eventIndex));
|
return this._IDBKeyRange.only(encodeKey(roomId, this._only.fragmentId, this._only.eventIndex));
|
||||||
}
|
}
|
||||||
// lowerBound
|
// lowerBound
|
||||||
// also bound as we don't want to move into another roomId
|
// also bound as we don't want to move into another roomId
|
||||||
if (this._lower && !this._upper) {
|
if (this._lower && !this._upper) {
|
||||||
return IDBKeyRange.bound(
|
return this._IDBKeyRange.bound(
|
||||||
encodeKey(roomId, this._lower.fragmentId, this._lower.eventIndex),
|
encodeKey(roomId, this._lower.fragmentId, this._lower.eventIndex),
|
||||||
encodeKey(roomId, this._lower.fragmentId, KeyLimits.maxStorageKey),
|
encodeKey(roomId, this._lower.fragmentId, KeyLimits.maxStorageKey),
|
||||||
this._lowerOpen,
|
this._lowerOpen,
|
||||||
|
@ -60,7 +61,7 @@ class Range {
|
||||||
// upperBound
|
// upperBound
|
||||||
// also bound as we don't want to move into another roomId
|
// also bound as we don't want to move into another roomId
|
||||||
if (!this._lower && this._upper) {
|
if (!this._lower && this._upper) {
|
||||||
return IDBKeyRange.bound(
|
return this._IDBKeyRange.bound(
|
||||||
encodeKey(roomId, this._upper.fragmentId, KeyLimits.minStorageKey),
|
encodeKey(roomId, this._upper.fragmentId, KeyLimits.minStorageKey),
|
||||||
encodeKey(roomId, this._upper.fragmentId, this._upper.eventIndex),
|
encodeKey(roomId, this._upper.fragmentId, this._upper.eventIndex),
|
||||||
false,
|
false,
|
||||||
|
@ -69,7 +70,7 @@ class Range {
|
||||||
}
|
}
|
||||||
// bound
|
// bound
|
||||||
if (this._lower && this._upper) {
|
if (this._lower && this._upper) {
|
||||||
return IDBKeyRange.bound(
|
return this._IDBKeyRange.bound(
|
||||||
encodeKey(roomId, this._lower.fragmentId, this._lower.eventIndex),
|
encodeKey(roomId, this._lower.fragmentId, this._lower.eventIndex),
|
||||||
encodeKey(roomId, this._upper.fragmentId, this._upper.eventIndex),
|
encodeKey(roomId, this._upper.fragmentId, this._upper.eventIndex),
|
||||||
this._lowerOpen,
|
this._lowerOpen,
|
||||||
|
@ -107,7 +108,7 @@ export class TimelineEventStore {
|
||||||
* @return {Range} the created range
|
* @return {Range} the created range
|
||||||
*/
|
*/
|
||||||
onlyRange(eventKey) {
|
onlyRange(eventKey) {
|
||||||
return new Range(eventKey);
|
return new Range(this._timelineStore.IDBKeyRange, eventKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a range that includes all keys before eventKey, and optionally also the key itself.
|
/** Creates a range that includes all keys before eventKey, and optionally also the key itself.
|
||||||
|
@ -116,7 +117,7 @@ export class TimelineEventStore {
|
||||||
* @return {Range} the created range
|
* @return {Range} the created range
|
||||||
*/
|
*/
|
||||||
upperBoundRange(eventKey, open=false) {
|
upperBoundRange(eventKey, open=false) {
|
||||||
return new Range(undefined, undefined, eventKey, undefined, open);
|
return new Range(this._timelineStore.IDBKeyRange, undefined, undefined, eventKey, undefined, open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a range that includes all keys after eventKey, and optionally also the key itself.
|
/** Creates a range that includes all keys after eventKey, and optionally also the key itself.
|
||||||
|
@ -125,7 +126,7 @@ export class TimelineEventStore {
|
||||||
* @return {Range} the created range
|
* @return {Range} the created range
|
||||||
*/
|
*/
|
||||||
lowerBoundRange(eventKey, open=false) {
|
lowerBoundRange(eventKey, open=false) {
|
||||||
return new Range(undefined, eventKey, undefined, open);
|
return new Range(this._timelineStore.IDBKeyRange, undefined, eventKey, undefined, open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a range that includes all keys between `lower` and `upper`, and optionally the given keys as well.
|
/** Creates a range that includes all keys between `lower` and `upper`, and optionally the given keys as well.
|
||||||
|
@ -136,7 +137,7 @@ export class TimelineEventStore {
|
||||||
* @return {Range} the created range
|
* @return {Range} the created range
|
||||||
*/
|
*/
|
||||||
boundRange(lower, upper, lowerOpen=false, upperOpen=false) {
|
boundRange(lower, upper, lowerOpen=false, upperOpen=false) {
|
||||||
return new Range(undefined, lower, upper, lowerOpen, upperOpen);
|
return new Range(this._timelineStore.IDBKeyRange, undefined, lower, upper, lowerOpen, upperOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Looks up the last `amount` entries in the timeline for `roomId`.
|
/** Looks up the last `amount` entries in the timeline for `roomId`.
|
||||||
|
@ -261,7 +262,7 @@ export class TimelineEventStore {
|
||||||
removeAllForRoom(roomId) {
|
removeAllForRoom(roomId) {
|
||||||
const minKey = encodeKey(roomId, KeyLimits.minStorageKey, KeyLimits.minStorageKey);
|
const minKey = encodeKey(roomId, KeyLimits.minStorageKey, KeyLimits.minStorageKey);
|
||||||
const maxKey = encodeKey(roomId, KeyLimits.maxStorageKey, KeyLimits.maxStorageKey);
|
const maxKey = encodeKey(roomId, KeyLimits.maxStorageKey, KeyLimits.maxStorageKey);
|
||||||
const range = IDBKeyRange.bound(minKey, maxKey);
|
const range = this._timelineStore.IDBKeyRange.bound(minKey, maxKey);
|
||||||
this._timelineStore.delete(range);
|
this._timelineStore.delete(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class TimelineFragmentStore {
|
||||||
|
|
||||||
_allRange(roomId) {
|
_allRange(roomId) {
|
||||||
try {
|
try {
|
||||||
return IDBKeyRange.bound(
|
return this._store.IDBKeyRange.bound(
|
||||||
encodeKey(roomId, KeyLimits.minStorageKey),
|
encodeKey(roomId, KeyLimits.minStorageKey),
|
||||||
encodeKey(roomId, KeyLimits.maxStorageKey)
|
encodeKey(roomId, KeyLimits.maxStorageKey)
|
||||||
);
|
);
|
||||||
|
|
|
@ -64,8 +64,8 @@ export function decodeUint32(str) {
|
||||||
return parseInt(str, 16);
|
return parseInt(str, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openDatabase(name, createObjectStore, version) {
|
export function openDatabase(name, createObjectStore, version, idbFactory = window.indexedDB) {
|
||||||
const req = indexedDB.open(name, version);
|
const req = idbFactory.open(name, version);
|
||||||
req.onupgradeneeded = (ev) => {
|
req.onupgradeneeded = (ev) => {
|
||||||
const db = ev.target.result;
|
const db = ev.target.result;
|
||||||
const txn = ev.target.transaction;
|
const txn = ev.target.transaction;
|
||||||
|
|
Reference in a new issue