diff --git a/packages/core/__e2e__/sync.test.js b/packages/core/__e2e__/sync.test.js index 79e8e96f6..67c0bdd6a 100644 --- a/packages/core/__e2e__/sync.test.js +++ b/packages/core/__e2e__/sync.test.js @@ -25,6 +25,8 @@ import { CHECK_IDS, EV, EVENTS } from "../src/common"; import { EventSource } from "event-source-polyfill"; import { test, expect, vitest } from "vitest"; import { login } from "./utils"; +import { SqliteDriver } from "kysely"; +import BetterSQLite3 from "better-sqlite3"; const TEST_TIMEOUT = 30 * 1000; @@ -73,10 +75,10 @@ test( await syncAndWait(deviceA, deviceB); - expect(deviceA.notes.note(note2Id)).toBeTruthy(); - expect(deviceB.notes.note(note1Id)).toBeTruthy(); - expect(deviceA.notes.note(note1Id)).toBeTruthy(); - expect(deviceB.notes.note(note2Id)).toBeTruthy(); + expect(await deviceA.notes.note(note2Id)).toBeTruthy(); + expect(await deviceB.notes.note(note1Id)).toBeTruthy(); + expect(await deviceA.notes.note(note1Id)).toBeTruthy(); + expect(await deviceB.notes.note(note2Id)).toBeTruthy(); console.log("Case 3 log out"); await cleanup(deviceA, deviceB); @@ -267,12 +269,12 @@ test( colorCode: "#ffff22" }); for (let noteId of noteIds) { - expect(deviceB.notes.note(noteId)).toBeTruthy(); + expect(await deviceB.notes.note(noteId)).toBeTruthy(); expect( - deviceB.relations + await deviceB.relations .from({ id: colorId, type: "color" }, "note") - .findIndex((a) => a.to.id === noteId) - ).toBe(-1); + .has(noteId) + ).toBe(false); await deviceA.relations.add( { id: colorId, type: "color" }, @@ -282,10 +284,10 @@ test( await syncAndWait(deviceA, deviceB); - expect(deviceB.colors.exists(colorId)).toBeTruthy(); - const purpleNotes = deviceB.relations + expect(await deviceB.colors.exists(colorId)).toBeTruthy(); + const purpleNotes = await deviceB.relations .from({ id: colorId, type: "color" }, "note") - .resolved(); + .resolve(); expect( noteIds.every((id) => purpleNotes.findIndex((p) => p.id === id) > -1) ).toBe(true); @@ -319,6 +321,7 @@ async function initializeDevice(id, capabilities = []) { const device = new Database(); device.setup({ storage: new NodeStorageInterface(), + sqlite: new SqliteDriver({ database: BetterSQLite3(":memory:") }), eventsource: EventSource, fs: FS, compressor: Compressor diff --git a/packages/core/src/api/sync/conflicts.ts b/packages/core/src/api/sync/conflicts.ts index 3a5ea6d9c..8fe8892de 100644 --- a/packages/core/src/api/sync/conflicts.ts +++ b/packages/core/src/api/sync/conflicts.ts @@ -22,14 +22,8 @@ import Database from ".."; class Conflicts { constructor(private readonly db: Database) {} - async recalculate() { - if (this.db.notes.conflicted.length <= 0) { - await this.db.storage().write("hasConflicts", false); - } - } - - check() { - return this.db.storage().read("hasConflicts"); + async check() { + return (await this.db.notes.conflicted.count()) > 0; } throw() { diff --git a/packages/core/src/api/sync/index.ts b/packages/core/src/api/sync/index.ts index 1dd72fddb..978daeba5 100644 --- a/packages/core/src/api/sync/index.ts +++ b/packages/core/src/api/sync/index.ts @@ -218,7 +218,6 @@ class Sync { async init(isForceSync?: boolean) { await this.checkConnection(); - await this.conflicts.recalculate(); if (await this.conflicts.check()) { this.conflicts.throw(); } diff --git a/packages/core/src/collections/attachments.ts b/packages/core/src/collections/attachments.ts index 46dc3edb9..987ee9347 100644 --- a/packages/core/src/collections/attachments.ts +++ b/packages/core/src/collections/attachments.ts @@ -33,6 +33,7 @@ import { Output } from "../interfaces"; import { Attachment } from "../types"; import Database from "../api"; import { SQLCollection } from "../database/sql-collection"; +import { isFalse } from "../database"; export class Attachments implements ICollection { name = "attachments"; @@ -283,16 +284,9 @@ export class Attachments implements ICollection { } async attachment(hashOrId: string): Promise { - return await this.db - .sql() - .selectFrom("attachments") - .selectAll() - .where((eb) => - eb.or([eb("id", "==", hashOrId), eb("hash", "==", hashOrId)]) - ) - .where("deleted", "is", null) - .$narrowType() - .executeTakeFirst(); + return this.all.find((eb) => + eb.or([eb("id", "==", hashOrId), eb("hash", "==", hashOrId)]) + ); } markAsUploaded(id: string) { @@ -372,9 +366,7 @@ export class Attachments implements ICollection { get pending() { return this.collection.createFilter((qb) => - qb.where((eb) => - eb.or([eb("dateUploaded", "is", null), eb("dateUploaded", "<=", 0)]) - ) + qb.where(isFalse("dateUploaded")) ); } @@ -419,9 +411,11 @@ export class Attachments implements ICollection { // ); // } - // get all() { - // return this.collection.items(); - // } + get all() { + return this.collection.createFilter((qb) => + qb.where(isFalse("deleted")) + ); + } private async encryptKey(key: SerializedKey) { const encryptionKey = await this._getEncryptionKey(); diff --git a/packages/core/src/collections/colors.ts b/packages/core/src/collections/colors.ts index df51019b5..596ece26b 100644 --- a/packages/core/src/collections/colors.ts +++ b/packages/core/src/collections/colors.ts @@ -23,6 +23,7 @@ import { Color } from "../types"; import Database from "../api"; import { Tags } from "./tags"; import { SQLCollection } from "../database/sql-collection"; +import { isFalse } from "../database"; export const DefaultColors: Record = { red: "#f44336", @@ -87,7 +88,7 @@ export class Colors implements ICollection { get all() { return this.collection.createFilter((qb) => - qb.where("deleted", "is", null) + qb.where(isFalse("deleted")) ); } diff --git a/packages/core/src/collections/notebooks.ts b/packages/core/src/collections/notebooks.ts index 96668c9d8..e464ac436 100644 --- a/packages/core/src/collections/notebooks.ts +++ b/packages/core/src/collections/notebooks.ts @@ -22,6 +22,7 @@ import Database from "../api"; import { Notebook, TrashOrItem, isTrashItem } from "../types"; import { ICollection } from "./collection"; import { SQLCollection } from "../database/sql-collection"; +import { isFalse } from "../database"; export class Notebooks implements ICollection { name = "notebooks"; @@ -79,15 +80,15 @@ export class Notebooks implements ICollection { get all() { return this.collection.createFilter((qb) => - qb.where("dateDeleted", "is", null).where("deleted", "is", null) + qb.where(isFalse("dateDeleted")).where(isFalse("deleted")) ); } get pinned() { return this.collection.createFilter((qb) => qb - .where("dateDeleted", "is", null) - .where("deleted", "is", null) + .where(isFalse("dateDeleted")) + .where(isFalse("deleted")) .where("pinned", "==", true) ); } diff --git a/packages/core/src/collections/notes.ts b/packages/core/src/collections/notes.ts index f318773c4..0048f7746 100644 --- a/packages/core/src/collections/notes.ts +++ b/packages/core/src/collections/notes.ts @@ -30,6 +30,7 @@ import Database from "../api"; import { ICollection } from "./collection"; import { NoteContent } from "./session-content"; import { SQLCollection } from "../database/sql-collection"; +import { isFalse } from "../database"; type ExportOptions = { format: "html" | "md" | "txt" | "md-frontmatter"; @@ -149,7 +150,7 @@ export class Notes implements ICollection { get all() { return this.collection.createFilter((qb) => - qb.where("dateDeleted", "is", null).where("deleted", "is", null) + qb.where(isFalse("dateDeleted")).where(isFalse("deleted")) ); } @@ -166,21 +167,26 @@ export class Notes implements ICollection { get pinned() { return this.collection.createFilter((qb) => qb - .where("dateDeleted", "is", null) - .where("deleted", "is", null) + .where(isFalse("dateDeleted")) + .where(isFalse("deleted")) .where("pinned", "==", true) ); } - // get conflicted() { - // return this.all.filter((item) => item.conflicted === true); - // } + get conflicted() { + return this.collection.createFilter((qb) => + qb + .where(isFalse("dateDeleted")) + .where(isFalse("deleted")) + .where("conflicted", "==", true) + ); + } get favorites() { return this.collection.createFilter((qb) => qb - .where("dateDeleted", "is", null) - .where("deleted", "is", null) + .where(isFalse("dateDeleted")) + .where(isFalse("deleted")) .where("favorite", "==", true) ); } @@ -188,8 +194,8 @@ export class Notes implements ICollection { get locked() { return this.collection.createFilter((qb) => qb - .where("dateDeleted", "is", null) - .where("deleted", "is", null) + .where(isFalse("dateDeleted")) + .where(isFalse("deleted")) .where("locked", "==", true) ); } diff --git a/packages/core/src/collections/relations.ts b/packages/core/src/collections/relations.ts index 6bce13b00..599680ef7 100644 --- a/packages/core/src/collections/relations.ts +++ b/packages/core/src/collections/relations.ts @@ -28,7 +28,7 @@ import { } from "../types"; import Database from "../api"; import { SQLCollection } from "../database/sql-collection"; -import { DatabaseAccessor, DatabaseSchema } from "../database"; +import { DatabaseAccessor, DatabaseSchema, isFalse } from "../database"; import { SelectQueryBuilder } from "kysely"; export class Relations implements ICollection { @@ -171,7 +171,7 @@ class RelationsArray { .$if(limit !== undefined && limit > 0, (b) => b.limit(limit!)) .selectAll() // TODO: check if we need to index deleted field. - .where("deleted", "is", null) + .where(isFalse("deleted")) .execute(); return items as unknown as ItemMap[TType][]; } diff --git a/packages/core/src/collections/shortcuts.ts b/packages/core/src/collections/shortcuts.ts index a99c22801..bd7c8e62b 100644 --- a/packages/core/src/collections/shortcuts.ts +++ b/packages/core/src/collections/shortcuts.ts @@ -18,6 +18,7 @@ along with this program. If not, see . */ import Database from "../api"; +import { isFalse } from "../database"; import { SQLCollection } from "../database/sql-collection"; import { Shortcut } from "../types"; import { ICollection } from "./collection"; @@ -82,7 +83,7 @@ export class Shortcuts implements ICollection { get all() { return this.collection.createFilter((qb) => - qb.where("deleted", "is", null) + qb.where(isFalse("deleted")) ); } diff --git a/packages/core/src/collections/tags.ts b/packages/core/src/collections/tags.ts index 804a2f906..f78bf48eb 100644 --- a/packages/core/src/collections/tags.ts +++ b/packages/core/src/collections/tags.ts @@ -22,6 +22,7 @@ import { Tag } from "../types"; import Database from "../api"; import { ICollection } from "./collection"; import { SQLCollection } from "../database/sql-collection"; +import { isFalse } from "../database"; export class Tags implements ICollection { name = "tags"; @@ -71,7 +72,7 @@ export class Tags implements ICollection { get all() { return this.collection.createFilter((qb) => - qb.where("deleted", "is", null) + qb.where(isFalse("deleted")) ); } diff --git a/packages/core/src/database/sql-collection.ts b/packages/core/src/database/sql-collection.ts index c6e804a27..48bd481c3 100644 --- a/packages/core/src/database/sql-collection.ts +++ b/packages/core/src/database/sql-collection.ts @@ -93,7 +93,7 @@ export class SQLCollection< .selectFrom(this.type) .select((a) => a.fn.count("id").as("count")) .where("id", "==", id) - .where("deleted", "is", null) + .where(isFalse("deleted")) .limit(1) .executeTakeFirst()) || {}; @@ -105,7 +105,7 @@ export class SQLCollection< (await this.db() .selectFrom(this.type) .select((a) => a.fn.count("id").as("count")) - .where("deleted", "is", null) + .where(isFalse("deleted")) .executeTakeFirst()) || {}; return count || 0; } @@ -132,6 +132,7 @@ export class SQLCollection< return array; }, [] as SQLiteItem[]); + if (entries.length <= 0) return; await this.db() .replaceInto(this.type) .values(entries) @@ -153,9 +154,9 @@ export class SQLCollection< const ids = await this.db() .selectFrom(this.type) .select("id") - .where("deleted", "is", null) + .where(isFalse("deleted")) .$if(this.type === "notes" || this.type === "notebooks", (eb) => - eb.where("dateDeleted", "is", null) + eb.where(isFalse("dateDeleted")) ) .orderBy(sortOptions.sortBy, sortOptions.sortDirection) .execute(); @@ -192,11 +193,7 @@ export class SQLCollection< .selectAll() .orderBy("dateModified", "asc") .$if(after > 0, (eb) => - eb - .where("dateModified", ">", after) - .where((eb) => - eb.or([eb("synced", "is", null), eb("synced", "==", false)]) - ) + eb.where("dateModified", ">", after).where(isFalse("synced")) ) .$if(this.type === "attachments", (eb) => eb.where("dateUploaded", ">", 0) @@ -217,7 +214,7 @@ export class SQLCollection< const rows = await this.db() .selectFrom(this.type) .where(isFalse("deleted")) - .orderBy("dateModified desc") + .orderBy("dateCreated desc") .selectAll() .offset(index) .limit(chunkSize) @@ -306,7 +303,7 @@ export class FilteredSelector { while (true) { const rows = await this.filter .selectAll() - .orderBy("dateModified asc") + .orderBy("dateCreated asc") .offset(index) .limit(this.batchSize) .execute();