mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 06:59:31 +01:00
refactor: use a single migration backend
This commit is contained in:
@@ -76,8 +76,8 @@ class Database {
|
||||
|
||||
await this.settings.init();
|
||||
await this.user.sync();
|
||||
await this.migrations.init();
|
||||
|
||||
await this.migrations.init();
|
||||
await this.migrations.migrate();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CURRENT_DATABASE_VERSION } from "../common";
|
||||
import { migrations } from "../migrations";
|
||||
import { CURRENT_DATABASE_VERSION, EV } from "../common";
|
||||
import Migrator from "../database/migrator";
|
||||
|
||||
class Migrations {
|
||||
/**
|
||||
@@ -8,58 +8,65 @@ class Migrations {
|
||||
*/
|
||||
constructor(db) {
|
||||
this._db = db;
|
||||
this.dbVersion = CURRENT_DATABASE_VERSION;
|
||||
this._migrator = new Migrator();
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.dbVersion = (await this._db.context.read("v")) || 2;
|
||||
}
|
||||
|
||||
get _shouldMigrate() {
|
||||
return this.dbVersion < CURRENT_DATABASE_VERSION;
|
||||
}
|
||||
|
||||
_migrationFunction(collectionId) {
|
||||
let migrationFunction = migrations[this.dbVersion][collectionId];
|
||||
if (!migrationFunction)
|
||||
migrationFunction = migrations[CURRENT_DATABASE_VERSION][collectionId];
|
||||
return migrationFunction;
|
||||
}
|
||||
|
||||
async migrate() {
|
||||
if (!this._shouldMigrate) return;
|
||||
if (this.dbVersion > CURRENT_DATABASE_VERSION) return;
|
||||
|
||||
await this._db.notes.init();
|
||||
const content = await this._db.content.all();
|
||||
|
||||
const collections = [
|
||||
"notes",
|
||||
"notebooks",
|
||||
"tags",
|
||||
"colors",
|
||||
"trash",
|
||||
"delta",
|
||||
"text",
|
||||
"content",
|
||||
"settings",
|
||||
{
|
||||
id: "notes",
|
||||
index: this._db.notes.raw,
|
||||
dbCollection: this._db.notes,
|
||||
},
|
||||
{
|
||||
id: "notebooks",
|
||||
index: this._db.notebooks.raw,
|
||||
dbCollection: this._db.notebooks,
|
||||
},
|
||||
{
|
||||
id: "tags",
|
||||
index: this._db.tags.raw,
|
||||
dbCollection: this._db.tags,
|
||||
},
|
||||
{
|
||||
id: "colors",
|
||||
index: this._db.colors.raw,
|
||||
dbCollection: this._db.colors,
|
||||
},
|
||||
{
|
||||
id: "trash",
|
||||
index: this._db.trash.raw,
|
||||
dbCollection: this._db.trash,
|
||||
},
|
||||
{
|
||||
id: "content",
|
||||
index: content,
|
||||
dbCollection: this._db.content,
|
||||
},
|
||||
{
|
||||
id: "settings",
|
||||
index: [this._db.settings.raw],
|
||||
dbCollection: this._db.settings,
|
||||
},
|
||||
];
|
||||
|
||||
await Promise.all(
|
||||
collections.map(async (collectionId) => {
|
||||
const collection = this._db[collectionId];
|
||||
if (!collection) return;
|
||||
|
||||
const items =
|
||||
collectionId === "content" || collectionId === "delta"
|
||||
? await collection.all()
|
||||
: collectionId === "settings"
|
||||
? [collection.raw]
|
||||
: collection.raw;
|
||||
|
||||
await Promise.all(
|
||||
items.map(async (item) => {
|
||||
await this._migrationFunction(collectionId)(this._db, item);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
await this._migrator.migrate(collections, (item) => item, this.dbVersion);
|
||||
await this._db.context.write("v", CURRENT_DATABASE_VERSION);
|
||||
|
||||
EV.publish("db:onMigrationDone", {
|
||||
prev: this.dbVersion,
|
||||
current: CURRENT_DATABASE_VERSION,
|
||||
});
|
||||
|
||||
this.dbVersion = CURRENT_DATABASE_VERSION;
|
||||
}
|
||||
}
|
||||
export default Migrations;
|
||||
|
||||
@@ -8,6 +8,7 @@ class Settings {
|
||||
constructor(db) {
|
||||
this._db = db;
|
||||
this._settings = {
|
||||
type: "settings",
|
||||
id: id(),
|
||||
pins: [],
|
||||
dateEdited: 0,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CURRENT_DATABASE_VERSION } from "../../common";
|
||||
import Database from "../index";
|
||||
var tfun = require("transfun/transfun.js").tfun;
|
||||
if (!tfun) {
|
||||
@@ -43,6 +44,7 @@ class Collector {
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
v: CURRENT_DATABASE_VERSION,
|
||||
...(await this._serialize(item)),
|
||||
};
|
||||
})(array)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Hashes from "jshashes";
|
||||
import Migrator from "./migrator.js";
|
||||
import {
|
||||
CHECK_IDS,
|
||||
sendCheckUserStatusEvent,
|
||||
CURRENT_DATABASE_VERSION,
|
||||
} from "../common.js";
|
||||
import { migrations } from "../migrations.js";
|
||||
const md5 = new Hashes.MD5();
|
||||
|
||||
const invalidKeys = ["user", "t", "lastBackupTime"];
|
||||
@@ -16,6 +16,7 @@ export default class Backup {
|
||||
*/
|
||||
constructor(db) {
|
||||
this._db = db;
|
||||
this._migrator = new Migrator();
|
||||
}
|
||||
|
||||
lastBackupTime() {
|
||||
@@ -117,45 +118,56 @@ export default class Backup {
|
||||
|
||||
async _migrateData(backup) {
|
||||
const { data, version = 0 } = backup;
|
||||
|
||||
if (version > CURRENT_DATABASE_VERSION)
|
||||
throw new Error(
|
||||
"This backup was made from a newer version of Notesnook. Cannot migrate."
|
||||
);
|
||||
|
||||
const collections = [
|
||||
"notes",
|
||||
"notebooks",
|
||||
"tags",
|
||||
"colors",
|
||||
"trash",
|
||||
"delta",
|
||||
"text",
|
||||
"content",
|
||||
"settings",
|
||||
{
|
||||
id: "notes",
|
||||
index: data["notes"],
|
||||
dbCollection: this._db.notes,
|
||||
},
|
||||
{
|
||||
id: "notebooks",
|
||||
index: data["notebooks"],
|
||||
dbCollection: this._db.notebooks,
|
||||
},
|
||||
{
|
||||
id: "tags",
|
||||
index: data["tags"],
|
||||
dbCollection: this._db.tags,
|
||||
},
|
||||
{
|
||||
id: "colors",
|
||||
index: data["colors"],
|
||||
dbCollection: this._db.colors,
|
||||
},
|
||||
{
|
||||
id: "trash",
|
||||
index: data["trash"],
|
||||
dbCollection: this._db.trash,
|
||||
},
|
||||
{
|
||||
id: "delta",
|
||||
index: data["delta"],
|
||||
dbCollection: this._db.content,
|
||||
},
|
||||
{
|
||||
id: "content",
|
||||
index: data["content"],
|
||||
dbCollection: this._db.content,
|
||||
},
|
||||
{
|
||||
id: "settings",
|
||||
index: ["settings"],
|
||||
dbCollection: this._db.settings,
|
||||
},
|
||||
];
|
||||
|
||||
await Promise.all(
|
||||
collections.map(async (collectionId) => {
|
||||
let collection = data[collectionId];
|
||||
if (!collection) return;
|
||||
|
||||
if (!Array.isArray(collection)) {
|
||||
collection = [collectionId];
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
collection.map(async (id) => {
|
||||
const item = data[id];
|
||||
if (!item) return;
|
||||
let migrationFunction = migrations[version][collectionId];
|
||||
if (!migrationFunction)
|
||||
migrationFunction =
|
||||
migrations[CURRENT_DATABASE_VERSION][collectionId];
|
||||
await migrationFunction(this._db, item);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
await this._migrator.migrate(collections, (id) => data[id], version);
|
||||
}
|
||||
|
||||
_validate(backup) {
|
||||
|
||||
31
packages/core/database/migrator.js
Normal file
31
packages/core/database/migrator.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { CURRENT_DATABASE_VERSION } from "../common";
|
||||
import { migrations } from "../migrations";
|
||||
|
||||
class Migrator {
|
||||
async migrate(collections, get, version) {
|
||||
await Promise.all(
|
||||
collections.map(async (collection) => {
|
||||
if (!collection.index || !collection.dbCollection) return;
|
||||
|
||||
await Promise.all(
|
||||
collection.index.map(async (id) => {
|
||||
let item = get(id);
|
||||
if (!item) return;
|
||||
if (item.deleted)
|
||||
return await collection.dbCollection._collection.addItem(item);
|
||||
|
||||
const migrate = migrations[version][item.type || collection.id];
|
||||
if (migrate) item = migrate(item);
|
||||
if (!!collection.dbCollection.merge) {
|
||||
await collection.dbCollection.merge(item);
|
||||
} else {
|
||||
await collection.dbCollection.add(item);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export default Migrator;
|
||||
@@ -1,15 +1,6 @@
|
||||
export const migrations = {
|
||||
handleDeleted: async function (db, collection, item) {
|
||||
if (item.deleted) {
|
||||
await db[collection]._collection.addItem(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
0: {
|
||||
notes: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "notes", item)) return;
|
||||
|
||||
note: function (item) {
|
||||
const contentId = item.content.delta;
|
||||
const notebook = item.notebook;
|
||||
delete item.content;
|
||||
@@ -17,69 +8,43 @@ export const migrations = {
|
||||
item.contentId = contentId;
|
||||
item.remote = true;
|
||||
if (notebook) item.notebooks = [notebook];
|
||||
await db.notes.add(item);
|
||||
return item;
|
||||
},
|
||||
delta: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "content", item)) return;
|
||||
|
||||
delta: function (item) {
|
||||
item.data = item.data.ops;
|
||||
item.type = "delta";
|
||||
await db.content.add(item);
|
||||
return item;
|
||||
},
|
||||
trash: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "trash", item)) return;
|
||||
|
||||
trash: function (item) {
|
||||
item.itemType = item.type;
|
||||
item.type = "trash";
|
||||
if (item.itemType === "note") {
|
||||
item.contentId = item.content.delta;
|
||||
delete item.content;
|
||||
}
|
||||
await db.trash.add(item);
|
||||
return item;
|
||||
},
|
||||
text: function () {},
|
||||
},
|
||||
2: {
|
||||
notes: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "notes", item)) return;
|
||||
|
||||
note: function (item) {
|
||||
// notebook -> notebooks
|
||||
const notebook = item.notebook;
|
||||
delete item.notebook;
|
||||
item.remote = true;
|
||||
if (notebook) item.notebooks = [notebook];
|
||||
|
||||
await db.notes.add({ ...item, remote: true });
|
||||
return item;
|
||||
},
|
||||
},
|
||||
3: {
|
||||
notes: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "notes", item)) return;
|
||||
await db.notes.add({ ...item, remote: true });
|
||||
},
|
||||
notebooks: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "notebooks", item)) return;
|
||||
note: false,
|
||||
notebooks: function (item) {
|
||||
if (item.favorite !== undefined) delete item.favorite;
|
||||
await db.notebooks.add(item);
|
||||
},
|
||||
tags: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "tags", item)) return;
|
||||
await db.tags.merge(item);
|
||||
},
|
||||
colors: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "colors", item)) return;
|
||||
await db.colors.merge(item);
|
||||
},
|
||||
trash: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "trash", item)) return;
|
||||
await db.trash.add(item);
|
||||
},
|
||||
content: async function (db, item) {
|
||||
if (await migrations.handleDeleted(db, "content", item)) return;
|
||||
await db.content.add(item);
|
||||
},
|
||||
settings: async function (db, item) {
|
||||
db.settings.merge(item);
|
||||
return item;
|
||||
},
|
||||
tag: false,
|
||||
trash: false,
|
||||
content: false,
|
||||
settings: false,
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user