2022-01-07 09:17:27 +05:00
|
|
|
import { makeSessionContentId } from "../utils/id";
|
2021-12-21 13:41:08 +05:00
|
|
|
import Collection from "./collection";
|
2021-12-22 09:57:12 +05:00
|
|
|
import SessionContent from "./session-content";
|
2021-12-21 13:41:08 +05:00
|
|
|
/**
|
|
|
|
|
* @typedef Session
|
|
|
|
|
* @property {string} id
|
|
|
|
|
* @property {string} noteId
|
|
|
|
|
* @property {string} sessionContentId
|
2021-12-22 12:07:07 +05:00
|
|
|
* @property {string} dateModified
|
2021-12-21 13:41:08 +05:00
|
|
|
* @property {string} dateCreated
|
|
|
|
|
* @property {boolean} locked
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @typedef Content
|
|
|
|
|
* @property {string} data
|
|
|
|
|
* @property {string} type
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
export default class NoteHistory extends Collection {
|
|
|
|
|
constructor(db, name, cached) {
|
|
|
|
|
super(db, name, cached);
|
|
|
|
|
this.versionsLimit = 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async init() {
|
2021-12-22 10:03:55 +05:00
|
|
|
await super.init();
|
2021-12-21 13:41:08 +05:00
|
|
|
|
|
|
|
|
/**
|
2021-12-22 09:57:12 +05:00
|
|
|
* @type {SessionContent}
|
2021-12-21 13:41:08 +05:00
|
|
|
*/
|
2021-12-22 09:57:12 +05:00
|
|
|
this.sessionContent = await SessionContent.new(
|
2021-12-21 13:41:08 +05:00
|
|
|
this._db,
|
2021-12-22 09:57:12 +05:00
|
|
|
"sessioncontent",
|
2021-12-21 13:41:08 +05:00
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get complete session history of a note.
|
|
|
|
|
* @param noteId id of the note
|
|
|
|
|
* @returns {Promise<Session[]>} An array of session ids of a note
|
|
|
|
|
*/
|
|
|
|
|
async get(noteId) {
|
|
|
|
|
if (!noteId) return [];
|
|
|
|
|
|
2021-12-22 10:00:30 +05:00
|
|
|
let indices = this._collection.indexer.getIndices();
|
|
|
|
|
let sessionIds = indices.filter((id) => id.startsWith(noteId));
|
2021-12-21 13:41:08 +05:00
|
|
|
if (sessionIds.length === 0) return [];
|
2021-12-22 10:00:30 +05:00
|
|
|
let history = (await this._getSessions(sessionIds)) || [];
|
2021-12-21 13:41:08 +05:00
|
|
|
|
2021-12-22 09:59:19 +05:00
|
|
|
return history.sort(function (a, b) {
|
|
|
|
|
return b.dateModified - a.dateModified;
|
|
|
|
|
});
|
2021-12-21 13:41:08 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add and update a session content
|
|
|
|
|
* @param {string} noteId id of the note
|
|
|
|
|
* @param {string} dateEdited edited date of the note
|
|
|
|
|
* @param {Content} content
|
|
|
|
|
*
|
|
|
|
|
* @returns {Promise<Session>}
|
|
|
|
|
*/
|
|
|
|
|
async add(noteId, dateEdited, content) {
|
|
|
|
|
if (!noteId || !dateEdited || !content) return;
|
|
|
|
|
let sessionId = `${noteId}_${dateEdited}`;
|
2021-12-22 10:01:15 +05:00
|
|
|
let oldSession = await this._collection.getItem(sessionId);
|
2021-12-21 13:41:08 +05:00
|
|
|
let locked = this._db.notes.note(noteId)?.data?.locked;
|
|
|
|
|
|
|
|
|
|
let session = {
|
|
|
|
|
id: sessionId,
|
|
|
|
|
sessionContentId: makeSessionContentId(sessionId),
|
|
|
|
|
noteId,
|
2021-12-22 10:01:15 +05:00
|
|
|
dateCreated: oldSession ? oldSession.dateCreated : Date.now(),
|
2021-12-21 13:41:08 +05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (locked) {
|
|
|
|
|
session.locked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await this._collection.addItem(session);
|
2021-12-22 09:57:12 +05:00
|
|
|
await this.sessionContent.add(sessionId, content, session.locked);
|
2021-12-21 13:41:08 +05:00
|
|
|
await this._cleanup(noteId);
|
|
|
|
|
|
|
|
|
|
return session;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _cleanup(noteId, limit = this.versionsLimit) {
|
|
|
|
|
let history = await this.get(noteId);
|
|
|
|
|
if (history.length === 0 || history.length < limit) return;
|
|
|
|
|
history.sort(function (a, b) {
|
2021-12-22 10:00:47 +05:00
|
|
|
return a.dateModified - b.dateModified;
|
2021-12-21 13:41:08 +05:00
|
|
|
});
|
|
|
|
|
let deleteCount = history.length - limit;
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < deleteCount; i++) {
|
|
|
|
|
let session = history[i];
|
|
|
|
|
await this._remove(session);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get content of a session
|
|
|
|
|
* @param {string} sessionId session id
|
|
|
|
|
*
|
|
|
|
|
* @returns {Promise<Content>}
|
|
|
|
|
*/
|
2021-12-22 12:07:07 +05:00
|
|
|
async content(sessionId) {
|
2021-12-21 13:41:08 +05:00
|
|
|
if (!sessionId) return;
|
2021-12-22 12:07:07 +05:00
|
|
|
/**
|
|
|
|
|
* @type {Session}
|
|
|
|
|
*/
|
|
|
|
|
let session = await this._collection.getItem(sessionId);
|
|
|
|
|
return await this.sessionContent.get(session.sessionContentId);
|
2021-12-21 13:41:08 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove a session from storage
|
|
|
|
|
* @param {string} sessionId
|
|
|
|
|
*/
|
2021-12-22 12:07:07 +05:00
|
|
|
async remove(sessionId) {
|
2021-12-21 13:41:08 +05:00
|
|
|
if (!sessionId) return;
|
|
|
|
|
/**
|
|
|
|
|
* @type {Session}
|
|
|
|
|
*/
|
2021-12-22 09:57:12 +05:00
|
|
|
let session = await this._collection.getItem(sessionId);
|
2021-12-21 13:41:08 +05:00
|
|
|
await this._remove(session);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove all sessions of a note from storage
|
|
|
|
|
* @param {string} noteId
|
|
|
|
|
*/
|
|
|
|
|
async clearSessions(noteId) {
|
|
|
|
|
if (!noteId) return;
|
|
|
|
|
let history = await this.get(noteId);
|
|
|
|
|
for (let item of history) {
|
|
|
|
|
await this._remove(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param {Session} session
|
|
|
|
|
*/
|
|
|
|
|
async _remove(session) {
|
|
|
|
|
await this._collection.deleteItem(session.id);
|
2021-12-22 09:57:12 +05:00
|
|
|
await this.sessionContent.remove(session.sessionContentId);
|
2021-12-21 13:41:08 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param {string} sessionId
|
|
|
|
|
*/
|
|
|
|
|
async restore(sessionId) {
|
|
|
|
|
/**
|
|
|
|
|
* @type {Session}
|
|
|
|
|
*/
|
|
|
|
|
let session = await this._collection.getItem(sessionId);
|
2021-12-22 09:57:12 +05:00
|
|
|
let content = await this.sessionContent.get(session.sessionContentId);
|
2021-12-21 13:41:08 +05:00
|
|
|
let note = this._db.notes.note(session.noteId).data;
|
|
|
|
|
if (session.locked) {
|
|
|
|
|
await this._db.content.add({
|
|
|
|
|
id: note.contentId,
|
|
|
|
|
data: content.data,
|
|
|
|
|
type: content.type,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
await this._db.notes.add({
|
|
|
|
|
id: session.noteId,
|
|
|
|
|
content: {
|
|
|
|
|
data: content.data,
|
|
|
|
|
type: content.type,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @returns A json string containing all sessions with content
|
|
|
|
|
*/
|
|
|
|
|
async serialize() {
|
|
|
|
|
return JSON.stringify({
|
|
|
|
|
sessions: await this.all(),
|
2021-12-22 09:57:12 +05:00
|
|
|
sessionContents: await this.sessionContent.all(),
|
2021-12-21 13:41:08 +05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async all() {
|
2021-12-22 10:00:30 +05:00
|
|
|
return this._getSessions(this._collection.indexer.getIndices());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _getSessions(sessionIds) {
|
|
|
|
|
let items = await this._collection.getItems(sessionIds);
|
2021-12-21 13:41:08 +05:00
|
|
|
return Object.values(items);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Restore session history from a serialized json string.
|
|
|
|
|
* @param {string} data
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
async deserialize(data) {
|
|
|
|
|
if (!data) return;
|
|
|
|
|
let deserialized = JSON.parse(data);
|
|
|
|
|
if (!deserialized.sessions || !deserialized.sessionContents) return;
|
|
|
|
|
|
|
|
|
|
for (let session of deserialized.sessions) {
|
|
|
|
|
let sessionContent = deserialized.sessionContents.find((v) =>
|
|
|
|
|
v.id.includes(session.id)
|
|
|
|
|
);
|
2021-12-22 12:07:07 +05:00
|
|
|
|
2021-12-21 13:41:08 +05:00
|
|
|
if (sessionContent) {
|
|
|
|
|
await this._collection.addItem(session);
|
2021-12-22 09:57:12 +05:00
|
|
|
await this.sessionContent._collection.addItem(sessionContent);
|
2021-12-21 13:41:08 +05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|