diff --git a/packages/core/__e2e__/sync.test.js b/packages/core/__e2e__/sync.test.js index ca694acd5..4bec7bbd0 100644 --- a/packages/core/__e2e__/sync.test.js +++ b/packages/core/__e2e__/sync.test.js @@ -156,6 +156,34 @@ test( TEST_TIMEOUT * 10 ); +test( + "issue: syncing should not affect the items' dateModified", + async (t) => { + const [deviceA] = await Promise.all([initializeDevice("deviceA")]); + + t.onTestFinished(async (r) => { + console.log(`${t.task.name} log out`); + await cleanup(deviceA); + }); + + const noteId = await deviceA.notes.add({ + title: "Test note from device A", + content: { data: "
Hello
", type: "tiptap" } + }); + const noteDateBefore = (await deviceA.notes.note(noteId)).dateModified; + const contentDateBefore = (await deviceA.content.findByNoteId(noteId)) + .dateModified; + await deviceA.sync({ type: "full" }); + const noteDateAfter = (await deviceA.notes.note(noteId)).dateModified; + const contentDateAfter = (await deviceA.content.findByNoteId(noteId)) + .dateModified; + expect(noteDateBefore).toBe(noteDateAfter); + expect(contentDateBefore).toBe(contentDateAfter); + }, + TEST_TIMEOUT +); + + // test( // "case 4: Device A's sync is interrupted halfway and Device B makes some changes afterwards and syncs.", // async () => { diff --git a/packages/core/src/api/sync/collector.ts b/packages/core/src/api/sync/collector.ts index 8aee89c8a..396effbc4 100644 --- a/packages/core/src/api/sync/collector.ts +++ b/packages/core/src/api/sync/collector.ts @@ -57,37 +57,34 @@ class Collector { const collection = this.db[collectionKey].collection; let pushTimestamp = Date.now(); for await (const chunk of collection.unsynced(chunkSize, isForceSync)) { - const items = await this.prepareChunk(chunk, key); + const { ids, items: syncableItems } = filterSyncableItems(chunk); + if (!ids.length) continue; + const ciphers = await this.db + .storage() + .encryptMulti(key, syncableItems); + const items = toPushItem(ids, ciphers); if (!items) continue; yield { items, type: itemType }; - await collection.update( - chunk.map((i) => i.id), - { synced: true }, - { - sendEvent: false, - // EDGE CASE: - // Sometimes an item can get updated while it's being pushed. - // The result is that its `synced` property becomes true even - // though it's modification wasn't yet synced. - // In order to prevent that, we only set the `synced` property - // to true for items that haven't been modified since we last ran - // the push. Everything else will be collected again in the next - // push. - condition: (eb) => eb("dateModified", "<=", pushTimestamp) - } - ); + await this.db + .sql() + .updateTable(collection.type) + .where("id", "in", ids) + // EDGE CASE: + // Sometimes an item can get updated while it's being pushed. + // The result is that its `synced` property becomes true even + // though it's modification wasn't yet synced. + // In order to prevent that, we only set the `synced` property + // to true for items that haven't been modified since we last ran + // the push. Everything else will be collected again in the next + // push. + .where("dateModified", "<=", pushTimestamp) + .set({ synced: true }) + .execute(); pushTimestamp = Date.now(); } } } - - async prepareChunk(chunk: MaybeDeletedItem