core: do not update dateModified when setting synced=true

This commit is contained in:
Abdullah Atta
2024-05-14 15:17:49 +05:00
parent e722866d62
commit 198fa33fc0
5 changed files with 52 additions and 26 deletions

View File

@@ -156,6 +156,34 @@ test(
TEST_TIMEOUT * 10 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: "<p>Hello</p>", 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( // test(
// "case 4: Device A's sync is interrupted halfway and Device B makes some changes afterwards and syncs.", // "case 4: Device A's sync is interrupted halfway and Device B makes some changes afterwards and syncs.",
// async () => { // async () => {

View File

@@ -57,15 +57,19 @@ class Collector {
const collection = this.db[collectionKey].collection; const collection = this.db[collectionKey].collection;
let pushTimestamp = Date.now(); let pushTimestamp = Date.now();
for await (const chunk of collection.unsynced(chunkSize, isForceSync)) { 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; if (!items) continue;
yield { items, type: itemType }; yield { items, type: itemType };
await collection.update( await this.db
chunk.map((i) => i.id), .sql()
{ synced: true }, .updateTable(collection.type)
{ .where("id", "in", ids)
sendEvent: false,
// EDGE CASE: // EDGE CASE:
// Sometimes an item can get updated while it's being pushed. // Sometimes an item can get updated while it's being pushed.
// The result is that its `synced` property becomes true even // The result is that its `synced` property becomes true even
@@ -74,20 +78,13 @@ class Collector {
// to true for items that haven't been modified since we last ran // to true for items that haven't been modified since we last ran
// the push. Everything else will be collected again in the next // the push. Everything else will be collected again in the next
// push. // push.
condition: (eb) => eb("dateModified", "<=", pushTimestamp) .where("dateModified", "<=", pushTimestamp)
} .set({ synced: true })
); .execute();
pushTimestamp = Date.now(); pushTimestamp = Date.now();
} }
} }
} }
async prepareChunk(chunk: MaybeDeletedItem<Item>[], key: SerializedKey) {
const { ids, items } = filterSyncableItems(chunk);
if (!ids.length) return;
const ciphers = await this.db.storage().encryptMulti(key, items);
return toPushItem(ids, ciphers);
}
} }
export default Collector; export default Collector;

View File

@@ -160,6 +160,7 @@ type AsyncOrSyncResult<Async extends boolean, Response> = Async extends true
: Response; : Response;
export interface DatabaseCollection<T, IsAsync extends boolean> { export interface DatabaseCollection<T, IsAsync extends boolean> {
type: keyof DatabaseSchema;
clear(): Promise<void>; clear(): Promise<void>;
init(): Promise<void>; init(): Promise<void>;
upsert(item: T): Promise<void>; upsert(item: T): Promise<void>;

View File

@@ -38,7 +38,7 @@ export class SQLCachedCollection<
startTransaction: ( startTransaction: (
executor: (tr: Kysely<DatabaseSchema>) => Promise<void> executor: (tr: Kysely<DatabaseSchema>) => Promise<void>
) => Promise<void>, ) => Promise<void>,
type: TCollectionType, public type: TCollectionType,
eventManager: EventManager, eventManager: EventManager,
sanitizer: Sanitizer sanitizer: Sanitizer
) { ) {

View File

@@ -75,7 +75,7 @@ export class SQLCollection<
_startTransaction: ( _startTransaction: (
executor: (tr: Kysely<DatabaseSchema>) => Promise<void> executor: (tr: Kysely<DatabaseSchema>) => Promise<void>
) => Promise<void>, ) => Promise<void>,
private readonly type: TCollectionType, public readonly type: TCollectionType,
private readonly eventManager: EventManager, private readonly eventManager: EventManager,
private readonly sanitizer: Sanitizer private readonly sanitizer: Sanitizer
) {} ) {}