feat: recalculate conflicts on sync

This commit is contained in:
thecodrr
2020-04-04 13:29:33 +05:00
parent 10ee35a145
commit 4dc3d2fe44
4 changed files with 65 additions and 44 deletions

View File

@@ -0,0 +1,18 @@
import Database from "./index";
class Conflicts {
/**
*
* @param {Database} db
*/
constructor(db) {
this._db = db;
}
recalculate = async () => {
if (this._db.notes.conflicted.length < 0) {
await this._db.context.write("hasConflicts", false);
}
};
}
export default Conflicts;

View File

@@ -7,6 +7,7 @@ import Sync from "./sync";
import Vault from "./vault"; import Vault from "./vault";
import Lookup from "./lookup"; import Lookup from "./lookup";
import Content from "../collections/content"; import Content from "../collections/content";
import Conflict from "./conflicts";
class Database { class Database {
constructor(context) { constructor(context) {
@@ -37,6 +38,7 @@ class Database {
await this.trash.init(this.notes, this.notebooks, this.delta, this.text); await this.trash.init(this.notes, this.notebooks, this.delta, this.text);
this.syncer = new Sync(this); this.syncer = new Sync(this);
this.vault = new Vault(this, this.context); this.vault = new Vault(this, this.context);
this.conflicts = new Conflicts(this);
this.lookup = new Lookup(this); this.lookup = new Lookup(this);
} }

View File

@@ -45,7 +45,7 @@ export default class Sync {
let token = await this.db.user.token(); let token = await this.db.user.token();
if (!token) throw new Error("You are not logged in"); if (!token) throw new Error("You are not logged in");
let response = await fetch(`${HOST}sync?lst=${lastSyncedTimestamp}`, { let response = await fetch(`${HOST}sync?lst=${lastSyncedTimestamp}`, {
headers: { ...HEADERS, Authorization: `Bearer ${token}` } headers: { ...HEADERS, Authorization: `Bearer ${token}` },
}); });
//TODO decrypt the response. //TODO decrypt the response.
return await response.json(); return await response.json();
@@ -66,6 +66,7 @@ export default class Sync {
let user = await this.db.user.get(); let user = await this.db.user.get();
if (!user) throw new Error("You need to login to sync."); if (!user) throw new Error("You need to login to sync.");
await this.db.conflicts.recalculate();
await this.throwOnConflicts(); await this.throwOnConflicts();
let lastSyncedTimestamp = user.lastSynced || 0; let lastSyncedTimestamp = user.lastSynced || 0;
@@ -94,7 +95,7 @@ export default class Sync {
let response = await fetch(`${HOST}sync`, { let response = await fetch(`${HOST}sync`, {
method: "POST", method: "POST",
headers: { ...HEADERS, Authorization: `Bearer ${token}` }, headers: { ...HEADERS, Authorization: `Bearer ${token}` },
body: JSON.stringify(data) body: JSON.stringify(data),
}); });
return response.ok; return response.ok;
} }
@@ -120,7 +121,7 @@ class Merger {
async _mergeArray(array, get, set) { async _mergeArray(array, get, set) {
return Promise.all( return Promise.all(
array.map(async item => await this._mergeItem(item, get, set)) array.map(async (item) => await this._mergeItem(item, get, set))
); );
} }
@@ -137,7 +138,7 @@ class Merger {
async _mergeArrayWithConflicts(array, get, set, resolve) { async _mergeArrayWithConflicts(array, get, set, resolve) {
return Promise.all( return Promise.all(
array.map( array.map(
async item => async (item) =>
await this._mergeItemWithConflicts(item, get, set, resolve) await this._mergeItemWithConflicts(item, get, set, resolve)
) )
); );
@@ -152,26 +153,26 @@ class Merger {
text, text,
tags, tags,
colors, colors,
trash trash,
} = serverResponse; } = serverResponse;
if (synced || areAllEmpty(serverResponse)) return false; if (synced || areAllEmpty(serverResponse)) return false;
await this._mergeArray( await this._mergeArray(
notes, notes,
id => this._db.notes.note(id), (id) => this._db.notes.note(id),
item => this._db.notes.add(item) (item) => this._db.notes.add(item)
); );
await this._mergeArray( await this._mergeArray(
notebooks, notebooks,
id => this._db.notebooks.notebook(id), (id) => this._db.notebooks.notebook(id),
item => this._db.notebooks.add(item) (item) => this._db.notebooks.add(item)
); );
await this._mergeArrayWithConflicts( await this._mergeArrayWithConflicts(
delta, delta,
id => this._db.delta.raw(id), (id) => this._db.delta.raw(id),
item => this._db.delta.add(item), (item) => this._db.delta.add(item),
async (local, remote) => { async (local, remote) => {
await this._db.delta.add({ ...local, conflicted: remote }); await this._db.delta.add({ ...local, conflicted: remote });
await this._db.notes.add({ id: local.noteId, conflicted: true }); await this._db.notes.add({ id: local.noteId, conflicted: true });
@@ -181,26 +182,26 @@ class Merger {
await this._mergeArray( await this._mergeArray(
text, text,
id => this._db.text.raw(id), (id) => this._db.text.raw(id),
item => this._db.text.add(item) (item) => this._db.text.add(item)
); );
await this._mergeArray( await this._mergeArray(
tags, tags,
id => this._db.tags.tag(id), (id) => this._db.tags.tag(id),
item => this._db.tags.merge(item) (item) => this._db.tags.merge(item)
); );
await this._mergeArray( await this._mergeArray(
colors, colors,
id => this._db.colors.tag(id), (id) => this._db.colors.tag(id),
item => this._db.colors.merge(item) (item) => this._db.colors.merge(item)
); );
await this._mergeArray( await this._mergeArray(
trash, trash,
() => undefined, () => undefined,
item => this._db.trash.add(item) (item) => this._db.trash.add(item)
); );
return true; return true;
@@ -229,21 +230,21 @@ class Prepare {
tags: this._prepareForServer(this._db.tags.raw), tags: this._prepareForServer(this._db.tags.raw),
colors: this._prepareForServer(this._db.colors.raw), colors: this._prepareForServer(this._db.colors.raw),
trash: this._prepareForServer(this._db.trash.raw), trash: this._prepareForServer(this._db.trash.raw),
lastSynced: Date.now() lastSynced: Date.now(),
}; };
} }
_prepareForServer(array) { _prepareForServer(array) {
return tfun return tfun
.filter(item => item.dateEdited > this._lastSyncedTimestamp) .filter((item) => item.dateEdited > this._lastSyncedTimestamp)
.map(item => ({ .map((item) => ({
id: item.id, id: item.id,
data: JSON.stringify(item) data: JSON.stringify(item),
}))(array); }))(array);
} }
} }
function areAllEmpty(obj) { function areAllEmpty(obj) {
const arrays = Object.values(obj).filter(v => v.length !== undefined); const arrays = Object.values(obj).filter((v) => v.length !== undefined);
return arrays.every(array => array.length === 0); return arrays.every((array) => array.length === 0);
} }

View File

@@ -6,7 +6,7 @@ import {
getWeekGroupFromTimestamp, getWeekGroupFromTimestamp,
months, months,
getLastWeekTimestamp, getLastWeekTimestamp,
get7DayTimestamp get7DayTimestamp,
} from "../utils/date"; } from "../utils/date";
import Notebooks from "./notebooks"; import Notebooks from "./notebooks";
import Note from "../models/note"; import Note from "../models/note";
@@ -62,7 +62,7 @@ export default class Notes {
let note = { let note = {
...oldNote, ...oldNote,
...noteArg ...noteArg,
}; };
if (isNoteEmpty(note)) { if (isNoteEmpty(note)) {
@@ -79,7 +79,7 @@ export default class Notes {
deltaId = await this._deltaCollection.add({ deltaId = await this._deltaCollection.add({
noteId: id, noteId: id,
id: deltaId, id: deltaId,
data: delta data: delta,
}); });
} }
@@ -87,7 +87,7 @@ export default class Notes {
textId = await this._textCollection.add({ textId = await this._textCollection.add({
noteId: id, noteId: id,
id: textId, id: textId,
data: text data: text,
}); });
note.title = getNoteTitle(note); note.title = getNoteTitle(note);
note.headline = getNoteHeadline(note); note.headline = getNoteHeadline(note);
@@ -106,7 +106,7 @@ export default class Notes {
favorite: !!note.favorite, favorite: !!note.favorite,
headline: note.headline, headline: note.headline,
dateCreated: note.dateCreated, dateCreated: note.dateCreated,
conflicted: !!note.conflicted conflicted: !!note.conflicted,
}; };
if (!oldNote) { if (!oldNote) {
@@ -147,6 +147,10 @@ export default class Notes {
return tfun.filter(".pinned === true")(this.all); return tfun.filter(".pinned === true")(this.all);
} }
get conflicted() {
return tfun.filter(".conflicted === true")(this.all);
}
get favorites() { get favorites() {
return tfun.filter(".favorite === true")(this.all); return tfun.filter(".favorite === true")(this.all);
} }
@@ -154,49 +158,49 @@ export default class Notes {
tagged(tag) { tagged(tag) {
return this._tagsCollection return this._tagsCollection
.notes(tag) .notes(tag)
.map(id => this._collection.getItem(id)); .map((id) => this._collection.getItem(id));
} }
colored(color) { colored(color) {
return this._colorsCollection return this._colorsCollection
.notes(color) .notes(color)
.map(id => this._collection.getItem(id)); .map((id) => this._collection.getItem(id));
} }
group(by, special = false) { group(by, special = false) {
let notes = !special let notes = !special
? tfun.filter(".pinned === false")(this.all) ? tfun.filter(".pinned === false")(this.all)
: this.all; : this.all;
notes = sort(notes).desc(t => t.dateCreated); notes = sort(notes).desc((t) => t.dateCreated);
switch (by) { switch (by) {
case "abc": case "abc":
return groupBy(notes, note => note.title[0].toUpperCase(), special); return groupBy(notes, (note) => note.title[0].toUpperCase(), special);
case "month": case "month":
return groupBy( return groupBy(
notes, notes,
note => months[new Date(note.dateCreated).getMonth()], (note) => months[new Date(note.dateCreated).getMonth()],
special special
); );
case "week": case "week":
return groupBy( return groupBy(
notes, notes,
note => getWeekGroupFromTimestamp(note.dateCreated), (note) => getWeekGroupFromTimestamp(note.dateCreated),
special special
); );
case "year": case "year":
return groupBy( return groupBy(
notes, notes,
note => new Date(note.dateCreated).getFullYear().toString(), (note) => new Date(note.dateCreated).getFullYear().toString(),
special special
); );
default: default:
let timestamps = { let timestamps = {
recent: getLastWeekTimestamp(7), recent: getLastWeekTimestamp(7),
lastWeek: getLastWeekTimestamp(7) - get7DayTimestamp() //seven day timestamp value lastWeek: getLastWeekTimestamp(7) - get7DayTimestamp(), //seven day timestamp value
}; };
return groupBy( return groupBy(
notes, notes,
note => (note) =>
note.dateCreated >= timestamps.recent note.dateCreated >= timestamps.recent
? "Recent" ? "Recent"
: note.dateCreated >= timestamps.lastWeek : note.dateCreated >= timestamps.lastWeek
@@ -247,7 +251,7 @@ function isNoteEmpty(note) {
const { const {
title, title,
content: { delta, text }, content: { delta, text },
locked locked,
} = note; } = note;
const isTitleEmpty = !title || !title.trim().length; const isTitleEmpty = !title || !title.trim().length;
const isTextEmpty = !isHex(text) && (!text || !text.trim().length); const isTextEmpty = !isHex(text) && (!text || !text.trim().length);
@@ -265,9 +269,5 @@ function getNoteHeadline(note) {
function getNoteTitle(note) { function getNoteTitle(note) {
if (note.title && note.title.length > 0) return note.title.trim(); if (note.title && note.title.length > 0) return note.title.trim();
return note.content.text return note.content.text.split(" ").slice(0, 3).join(" ").trim();
.split(" ")
.slice(0, 3)
.join(" ")
.trim();
} }