Migrate schema to TypeScript

This commit is contained in:
Danila Fedorin 2021-08-12 13:28:36 -07:00
parent eae820f91b
commit 34b173a057
2 changed files with 26 additions and 18 deletions

View file

@ -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}`;

View file

@ -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"});
} }