forked from mystiq/hydrogen-web
Migrate schema to TypeScript
This commit is contained in:
parent
eae820f91b
commit
34b173a057
2 changed files with 26 additions and 18 deletions
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import {Storage} from "./Storage";
|
import {Storage} from "./Storage";
|
||||||
import { openDatabase, reqAsPromise } from "./utils";
|
import { openDatabase, reqAsPromise } from "./utils";
|
||||||
import { exportSession, importSession } from "./export.js";
|
import { exportSession, importSession } from "./export.js";
|
||||||
import { schema } from "./schema.js";
|
import { schema } from "./schema";
|
||||||
import { detectWebkitEarlyCloseTxnBug } from "./quirks.js";
|
import { detectWebkitEarlyCloseTxnBug } from "./quirks.js";
|
||||||
|
|
||||||
const sessionName = sessionId => `hydrogen_session_${sessionId}`;
|
const sessionName = sessionId => `hydrogen_session_${sessionId}`;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {iterateCursor, reqAsPromise} from "./utils";
|
import {iterateCursor, NOT_DONE, reqAsPromise} from "./utils";
|
||||||
import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/RoomMember.js";
|
import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/RoomMember.js";
|
||||||
import {RoomMemberStore} from "./stores/RoomMemberStore";
|
import {RoomMemberStore} from "./stores/RoomMemberStore";
|
||||||
|
import {RoomStateEntry} from "./stores/RoomStateStore";
|
||||||
import {SessionStore} from "./stores/SessionStore";
|
import {SessionStore} from "./stores/SessionStore";
|
||||||
import {encodeScopeTypeKey} from "./stores/OperationStore";
|
import {encodeScopeTypeKey} from "./stores/OperationStore";
|
||||||
|
|
||||||
|
@ -20,10 +21,12 @@ export const schema = [
|
||||||
];
|
];
|
||||||
// TODO: how to deal with git merge conflicts of this array?
|
// TODO: how to deal with git merge conflicts of this array?
|
||||||
|
|
||||||
|
// TypeScript note: for now, do not bother introducing interfaces / alias
|
||||||
|
// for old schemas. Just take them as `any`.
|
||||||
|
|
||||||
// how do we deal with schema updates vs existing data migration in a way that
|
// how do we deal with schema updates vs existing data migration in a way that
|
||||||
//v1
|
//v1
|
||||||
function createInitialStores(db) {
|
function createInitialStores(db: IDBDatabase): void {
|
||||||
db.createObjectStore("session", {keyPath: "key"});
|
db.createObjectStore("session", {keyPath: "key"});
|
||||||
// any way to make keys unique here? (just use put?)
|
// any way to make keys unique here? (just use put?)
|
||||||
db.createObjectStore("roomSummary", {keyPath: "roomId"});
|
db.createObjectStore("roomSummary", {keyPath: "roomId"});
|
||||||
|
@ -40,11 +43,12 @@ function createInitialStores(db) {
|
||||||
db.createObjectStore("pendingEvents", {keyPath: "key"});
|
db.createObjectStore("pendingEvents", {keyPath: "key"});
|
||||||
}
|
}
|
||||||
//v2
|
//v2
|
||||||
async function createMemberStore(db, txn) {
|
async function createMemberStore(db: IDBDatabase, txn: IDBTransaction): Promise<void> {
|
||||||
const roomMembers = new RoomMemberStore(db.createObjectStore("roomMembers", {keyPath: "key"}));
|
// Cast ok here because only "set" is used
|
||||||
|
const roomMembers = new RoomMemberStore(db.createObjectStore("roomMembers", {keyPath: "key"}) as any);
|
||||||
// migrate existing member state events over
|
// migrate existing member state events over
|
||||||
const roomState = txn.objectStore("roomState");
|
const roomState = txn.objectStore("roomState");
|
||||||
await iterateCursor(roomState.openCursor(), entry => {
|
await iterateCursor<RoomStateEntry>(roomState.openCursor(), entry => {
|
||||||
if (entry.event.type === MEMBER_EVENT_TYPE) {
|
if (entry.event.type === MEMBER_EVENT_TYPE) {
|
||||||
roomState.delete(entry.key);
|
roomState.delete(entry.key);
|
||||||
const member = RoomMember.fromMemberEvent(entry.roomId, entry.event);
|
const member = RoomMember.fromMemberEvent(entry.roomId, entry.event);
|
||||||
|
@ -52,10 +56,11 @@ async function createMemberStore(db, txn) {
|
||||||
roomMembers.set(member.serialize());
|
roomMembers.set(member.serialize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return NOT_DONE;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//v3
|
//v3
|
||||||
async function migrateSession(db, txn) {
|
async function migrateSession(db: IDBDatabase, txn: IDBTransaction): Promise<void> {
|
||||||
const session = txn.objectStore("session");
|
const session = txn.objectStore("session");
|
||||||
try {
|
try {
|
||||||
const PRE_MIGRATION_KEY = 1;
|
const PRE_MIGRATION_KEY = 1;
|
||||||
|
@ -63,7 +68,8 @@ async function migrateSession(db, txn) {
|
||||||
if (entry) {
|
if (entry) {
|
||||||
session.delete(PRE_MIGRATION_KEY);
|
session.delete(PRE_MIGRATION_KEY);
|
||||||
const {syncToken, syncFilterId, serverVersions} = entry.value;
|
const {syncToken, syncFilterId, serverVersions} = entry.value;
|
||||||
const store = new SessionStore(session);
|
// Cast ok here because only "set" is used and we don't look into return
|
||||||
|
const store = new SessionStore(session as any);
|
||||||
store.set("sync", {token: syncToken, filterId: syncFilterId});
|
store.set("sync", {token: syncToken, filterId: syncFilterId});
|
||||||
store.set("serverVersions", serverVersions);
|
store.set("serverVersions", serverVersions);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +79,7 @@ async function migrateSession(db, txn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//v4
|
//v4
|
||||||
function createE2EEStores(db) {
|
function createE2EEStores(db: IDBDatabase): void {
|
||||||
db.createObjectStore("userIdentities", {keyPath: "userId"});
|
db.createObjectStore("userIdentities", {keyPath: "userId"});
|
||||||
const deviceIdentities = db.createObjectStore("deviceIdentities", {keyPath: "key"});
|
const deviceIdentities = db.createObjectStore("deviceIdentities", {keyPath: "key"});
|
||||||
deviceIdentities.createIndex("byCurve25519Key", "curve25519Key", {unique: true});
|
deviceIdentities.createIndex("byCurve25519Key", "curve25519Key", {unique: true});
|
||||||
|
@ -86,13 +92,14 @@ function createE2EEStores(db) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// v5
|
// v5
|
||||||
async function migrateEncryptionFlag(db, txn) {
|
async function migrateEncryptionFlag(db: IDBDatabase, txn: IDBTransaction): Promise<void> {
|
||||||
// migrate room summary isEncrypted -> encryption prop
|
// migrate room summary isEncrypted -> encryption prop
|
||||||
const roomSummary = txn.objectStore("roomSummary");
|
const roomSummary = txn.objectStore("roomSummary");
|
||||||
const roomState = txn.objectStore("roomState");
|
const roomState = txn.objectStore("roomState");
|
||||||
const summaries = [];
|
const summaries: any[] = [];
|
||||||
await iterateCursor(roomSummary.openCursor(), summary => {
|
await iterateCursor<any>(roomSummary.openCursor(), summary => {
|
||||||
summaries.push(summary);
|
summaries.push(summary);
|
||||||
|
return NOT_DONE;
|
||||||
});
|
});
|
||||||
for (const summary of summaries) {
|
for (const summary of summaries) {
|
||||||
const encryptionEntry = await reqAsPromise(roomState.get(`${summary.roomId}|m.room.encryption|`));
|
const encryptionEntry = await reqAsPromise(roomState.get(`${summary.roomId}|m.room.encryption|`));
|
||||||
|
@ -105,31 +112,32 @@ async function migrateEncryptionFlag(db, txn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// v6
|
// v6
|
||||||
function createAccountDataStore(db) {
|
function createAccountDataStore(db: IDBDatabase): void {
|
||||||
db.createObjectStore("accountData", {keyPath: "type"});
|
db.createObjectStore("accountData", {keyPath: "type"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// v7
|
// v7
|
||||||
function createInviteStore(db) {
|
function createInviteStore(db: IDBDatabase): void {
|
||||||
db.createObjectStore("invites", {keyPath: "roomId"});
|
db.createObjectStore("invites", {keyPath: "roomId"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// v8
|
// v8
|
||||||
function createArchivedRoomSummaryStore(db) {
|
function createArchivedRoomSummaryStore(db: IDBDatabase): void {
|
||||||
db.createObjectStore("archivedRoomSummary", {keyPath: "summary.roomId"});
|
db.createObjectStore("archivedRoomSummary", {keyPath: "summary.roomId"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// v9
|
// v9
|
||||||
async function migrateOperationScopeIndex(db, txn) {
|
async function migrateOperationScopeIndex(db: IDBDatabase, txn: IDBTransaction): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const operations = txn.objectStore("operations");
|
const operations = txn.objectStore("operations");
|
||||||
operations.deleteIndex("byTypeAndScope");
|
operations.deleteIndex("byTypeAndScope");
|
||||||
await iterateCursor(operations.openCursor(), (op, key, cur) => {
|
await iterateCursor<any>(operations.openCursor(), (op, key, cur) => {
|
||||||
const {typeScopeKey} = op;
|
const {typeScopeKey} = op;
|
||||||
delete op.typeScopeKey;
|
delete op.typeScopeKey;
|
||||||
const [type, scope] = typeScopeKey.split("|");
|
const [type, scope] = typeScopeKey.split("|");
|
||||||
op.scopeTypeKey = encodeScopeTypeKey(scope, type);
|
op.scopeTypeKey = encodeScopeTypeKey(scope, type);
|
||||||
cur.update(op);
|
cur.update(op);
|
||||||
|
return NOT_DONE;
|
||||||
});
|
});
|
||||||
operations.createIndex("byScopeAndType", "scopeTypeKey", {unique: false});
|
operations.createIndex("byScopeAndType", "scopeTypeKey", {unique: false});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -139,6 +147,6 @@ async function migrateOperationScopeIndex(db, txn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//v10
|
//v10
|
||||||
function createTimelineRelationsStore(db) {
|
function createTimelineRelationsStore(db: IDBDatabase) : void {
|
||||||
db.createObjectStore("timelineRelations", {keyPath: "key"});
|
db.createObjectStore("timelineRelations", {keyPath: "key"});
|
||||||
}
|
}
|
Loading…
Reference in a new issue