mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
core: do not update dateModified when setting synced=true
This commit is contained in:
@@ -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 () => {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -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
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
Reference in New Issue
Block a user