mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 11:35:04 +01:00
work on memory store
This commit is contained in:
parent
1605170f9e
commit
6ba37e90a3
6
src/matrix/storage/common.js
Normal file
6
src/matrix/storage/common.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const STORE_NAMES = Object.freeze(["session", "roomState", "roomSummary", "roomTimeline"]);
|
||||||
|
|
||||||
|
export const STORE_MAP = Object.freeze(STORE_NAMES.reduce((nameMap, name) => {
|
||||||
|
nameMap[name] = name;
|
||||||
|
return nameMap;
|
||||||
|
}, {}));
|
37
src/matrix/storage/memory/Storage.js
Normal file
37
src/matrix/storage/memory/Storage.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import Transaction from "./transaction.js";
|
||||||
|
import { STORE_MAP, STORE_NAMES } from "../common.js";
|
||||||
|
|
||||||
|
export default class Storage {
|
||||||
|
constructor(initialStoreValues = {}) {
|
||||||
|
this._validateStoreNames(Object.keys(initialStoreValues));
|
||||||
|
this.storeNames = STORE_MAP;
|
||||||
|
this._storeValues = STORE_NAMES.reduce((values, name) => {
|
||||||
|
values[name] = initialStoreValues[name] || null;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
_validateStoreNames(storeNames) {
|
||||||
|
const idx = storeNames.findIndex(name => !STORE_MAP.hasOwnProperty(name));
|
||||||
|
if (idx !== -1) {
|
||||||
|
throw new Error(`Invalid store name ${storeNames[idx]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_createTxn(storeNames, writable) {
|
||||||
|
this._validateStoreNames(storeNames);
|
||||||
|
const storeValues = storeNames.reduce((values, name) => {
|
||||||
|
return values[name] = this._storeValues[name];
|
||||||
|
}, {});
|
||||||
|
return Promise.resolve(new Transaction(storeValues, writable));
|
||||||
|
}
|
||||||
|
|
||||||
|
readTxn(storeNames) {
|
||||||
|
// TODO: avoid concurrency
|
||||||
|
return this._createTxn(storeNames, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
readWriteTxn(storeNames) {
|
||||||
|
// TODO: avoid concurrency
|
||||||
|
return this._createTxn(storeNames, true);
|
||||||
|
}
|
||||||
|
}
|
57
src/matrix/storage/memory/Transaction.js
Normal file
57
src/matrix/storage/memory/Transaction.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import RoomTimelineStore from "./stores/RoomTimelineStore.js";
|
||||||
|
|
||||||
|
export default class Transaction {
|
||||||
|
constructor(storeValues, writable) {
|
||||||
|
this._storeValues = storeValues;
|
||||||
|
this._txnStoreValues = {};
|
||||||
|
this._writable = writable;
|
||||||
|
}
|
||||||
|
|
||||||
|
_store(name, mapper) {
|
||||||
|
if (!this._txnStoreValues.hasOwnProperty(name)) {
|
||||||
|
if (!this._storeValues.hasOwnProperty(name)) {
|
||||||
|
throw new Error(`Transaction wasn't opened for store ${name}`);
|
||||||
|
}
|
||||||
|
const store = mapper(this._storeValues[name]);
|
||||||
|
const clone = store.cloneStoreValue();
|
||||||
|
// extra prevention for writing
|
||||||
|
if (!this._writable) {
|
||||||
|
Object.freeze(clone);
|
||||||
|
}
|
||||||
|
this._txnStoreValues[name] = clone;
|
||||||
|
}
|
||||||
|
return mapper(this._txnStoreValues[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
get session() {
|
||||||
|
throw new Error("not yet implemented");
|
||||||
|
// return this._store("session", storeValue => new SessionStore(storeValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
get roomSummary() {
|
||||||
|
throw new Error("not yet implemented");
|
||||||
|
// return this._store("roomSummary", storeValue => new RoomSummaryStore(storeValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
get roomTimeline() {
|
||||||
|
return this._store("roomTimeline", storeValue => new RoomTimelineStore(storeValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
get roomState() {
|
||||||
|
throw new Error("not yet implemented");
|
||||||
|
// return this._store("roomState", storeValue => new RoomStateStore(storeValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
complete() {
|
||||||
|
for(let name of Object.keys(this._txnStoreValues)) {
|
||||||
|
this._storeValues[name] = this._txnStoreValues[name];
|
||||||
|
}
|
||||||
|
this._txnStoreValues = null;
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
this._txnStoreValues = null;
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import SortKey from "../sortkey.js";
|
import SortKey from "../sortkey.js";
|
||||||
import sortedIndex from "../../../utils/sortedIndex.js";
|
import sortedIndex from "../../../utils/sortedIndex.js";
|
||||||
|
import Store from "./Store";
|
||||||
|
|
||||||
function compareKeys(key, entry) {
|
function compareKeys(key, entry) {
|
||||||
if (key.roomId === entry.roomId) {
|
if (key.roomId === entry.roomId) {
|
||||||
@ -64,9 +65,13 @@ class Range {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class RoomTimelineStore {
|
export default class RoomTimelineStore extends Store {
|
||||||
constructor(initialTimeline = []) {
|
constructor(timeline, writable) {
|
||||||
this._timeline = initialTimeline;
|
super(timeline || [], writable);
|
||||||
|
}
|
||||||
|
|
||||||
|
get _timeline() {
|
||||||
|
return this._storeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a range that only includes the given key
|
/** Creates a range that only includes the given key
|
||||||
@ -176,6 +181,7 @@ export default class RoomTimelineStore {
|
|||||||
* @throws {StorageError} ...
|
* @throws {StorageError} ...
|
||||||
*/
|
*/
|
||||||
insert(entry) {
|
insert(entry) {
|
||||||
|
this.assertWritable();
|
||||||
const insertIndex = sortedIndex(this._timeline, entry, compareKeys);
|
const insertIndex = sortedIndex(this._timeline, entry, compareKeys);
|
||||||
if (insertIndex < this._timeline.length) {
|
if (insertIndex < this._timeline.length) {
|
||||||
const existingEntry = this._timeline[insertIndex];
|
const existingEntry = this._timeline[insertIndex];
|
||||||
@ -193,6 +199,7 @@ export default class RoomTimelineStore {
|
|||||||
* @return {Promise<>} a promise resolving to undefined if the operation was successful, or a StorageError if not.
|
* @return {Promise<>} a promise resolving to undefined if the operation was successful, or a StorageError if not.
|
||||||
*/
|
*/
|
||||||
update(entry) {
|
update(entry) {
|
||||||
|
this.assertWritable();
|
||||||
let update = false;
|
let update = false;
|
||||||
const updateIndex = sortedIndex(this._timeline, entry, compareKeys);
|
const updateIndex = sortedIndex(this._timeline, entry, compareKeys);
|
||||||
if (updateIndex < this._timeline.length) {
|
if (updateIndex < this._timeline.length) {
|
||||||
@ -213,6 +220,7 @@ export default class RoomTimelineStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeRange(roomId, range) {
|
removeRange(roomId, range) {
|
||||||
|
this.assertWritable();
|
||||||
const {startIndex, count} = range.project(roomId);
|
const {startIndex, count} = range.project(roomId);
|
||||||
const removedEntries = this._timeline.splice(startIndex, count);
|
const removedEntries = this._timeline.splice(startIndex, count);
|
||||||
return Promise.resolve(removedEntries);
|
return Promise.resolve(removedEntries);
|
||||||
|
27
src/matrix/storage/memory/stores/Store.js
Normal file
27
src/matrix/storage/memory/stores/Store.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
export default class Store {
|
||||||
|
constructor(storeValue, writable) {
|
||||||
|
this._storeValue = storeValue;
|
||||||
|
this._writable = writable;
|
||||||
|
}
|
||||||
|
|
||||||
|
// makes a copy deep enough that any modifications in the store
|
||||||
|
// won't affect the original
|
||||||
|
// used for transactions
|
||||||
|
cloneStoreValue() {
|
||||||
|
// assumes 1 level deep is enough, and that values will be replaced
|
||||||
|
// rather than updated.
|
||||||
|
if (Array.isArray(this._storeValue)) {
|
||||||
|
return this._storeValue.slice();
|
||||||
|
} else if (typeof this._storeValue === "object") {
|
||||||
|
return Object.assign({}, this._storeValue);
|
||||||
|
} else {
|
||||||
|
return this._storeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertWritable() {
|
||||||
|
if (!this._writable) {
|
||||||
|
throw new Error("Tried to write in read-only transaction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user