fix: memories mobile sync for older clients (#32150)

Co-authored-by: Santo Shakil <[email protected]>
This commit is contained in:
Daniel Dietzler
2026-10-06 15:48:29 +02:00
committed by GitHub
co-authored by Santo Shakil
parent e49a5bb8c9
commit 8d377bfef5
13 changed files with 281 additions and 14 deletions
@@ -13,6 +13,7 @@ enum ServerCapability {
syncAssetFacesV3(SemVer(major: 3, minor: 3, patch: 0)),
syncAssetOcrV1(SemVer(major: 3, minor: 0, patch: 0)),
syncAuthUsersV2(SemVer(major: 3, minor: 3, patch: 0)),
syncMemoriesV2(SemVer(major: 3, minor: 3, patch: 0)),
// Migrations
assetPayloadChange20260128(SemVer(major: 2, minor: 5, patch: 0)),
@@ -296,10 +296,12 @@ class SyncStreamService {
case SyncEntityType.syncResetV1:
return _syncStreamRepository.reset();
case SyncEntityType.memoryV1:
return _syncStreamRepository.updateMemoriesV1(data.cast());
case SyncEntityType.memoryV2:
return _syncStreamRepository.updateMemoriesV2(data.cast());
case SyncEntityType.memoryDeleteV1:
return _syncStreamRepository.deleteMemoriesV1(data.cast());
case SyncEntityType.memoryToAssetV1:
case SyncEntityType.memoryToAssetV2:
return _syncStreamRepository.updateMemoryAssetsV1(data.cast());
case SyncEntityType.memoryToAssetDeleteV1:
return _syncStreamRepository.deleteMemoryAssetsV1(data.cast());
@@ -57,8 +57,8 @@ class SyncApiRepository {
serverVersion.supports(.syncV2) ? SyncRequestType.albumAssetsV2 : SyncRequestType.albumAssetsV1,
SyncRequestType.albumAssetExifsV1,
SyncRequestType.albumToAssetsV1,
SyncRequestType.memoriesV1,
SyncRequestType.memoryToAssetsV1,
serverVersion.supports(.syncMemoriesV2) ? SyncRequestType.memoriesV2 : SyncRequestType.memoriesV1,
serverVersion.supports(.syncMemoriesV2) ? SyncRequestType.memoryToAssetsV2 : SyncRequestType.memoryToAssetsV1,
SyncRequestType.stacksV1,
SyncRequestType.partnerStacksV1,
SyncRequestType.userMetadataV1,
@@ -184,9 +184,11 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
SyncEntityType.albumToAssetDeleteV1: SyncAlbumToAssetDeleteV1.fromJson,
SyncEntityType.syncAckV1: _SyncEmptyDto.fromJson,
SyncEntityType.syncResetV1: _SyncEmptyDto.fromJson,
SyncEntityType.memoryV1: SyncMemoryV1.fromJson,
SyncEntityType.memoryV1: SyncMemoryV2.fromJson,
SyncEntityType.memoryV2: SyncMemoryV2.fromJson,
SyncEntityType.memoryDeleteV1: SyncMemoryDeleteV1.fromJson,
SyncEntityType.memoryToAssetV1: SyncMemoryAssetV1.fromJson,
SyncEntityType.memoryToAssetV2: SyncMemoryAssetV1.fromJson,
SyncEntityType.memoryToAssetDeleteV1: SyncMemoryAssetDeleteV1.fromJson,
SyncEntityType.stackV1: SyncStackV1.fromJson,
SyncEntityType.stackDeleteV1: SyncStackDeleteV1.fromJson,
@@ -640,7 +640,7 @@ class SyncStreamRepository extends DatabaseAccessor<Drift> with $SyncStreamRepos
}
}
Future<void> updateMemoriesV1(Iterable<SyncMemoryV1> data) async {
Future<void> updateMemoriesV2(Iterable<SyncMemoryV2> data) async {
try {
await _db.batch((batch) {
for (final memory in data) {
@@ -665,7 +665,7 @@ class SyncStreamRepository extends DatabaseAccessor<Drift> with $SyncStreamRepos
}
});
} catch (error, stack) {
_logger.severe('Error: updateMemoriesV1', error, stack);
_logger.severe('Error: updateMemoriesV2', error, stack);
rethrow;
}
}
@@ -131,7 +131,7 @@ void main() {
when(
() => mockSyncStreamRepo.updateAssetsExifV1(any(), debugLabel: any(named: 'debugLabel')),
).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.updateMemoriesV1(any())).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.updateMemoriesV2(any())).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.deleteMemoriesV1(any())).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.updateMemoryAssetsV1(any())).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.deleteMemoryAssetsV1(any())).thenAnswer(successHandler);
@@ -320,7 +320,7 @@ void main() {
await simulateEvents(events);
verifyInOrder([
() => mockSyncStreamRepo.updateMemoriesV1(any()),
() => mockSyncStreamRepo.updateMemoriesV2(any()),
() => mockSyncApiRepo.ack(["5"]),
() => mockSyncStreamRepo.deleteMemoriesV1(any()),
() => mockSyncApiRepo.ack(["6"]),
@@ -349,14 +349,14 @@ void main() {
() => mockSyncApiRepo.ack(["1"]),
() => mockSyncStreamRepo.updateMemoryAssetsV1(any()),
() => mockSyncApiRepo.ack(["7"]),
() => mockSyncStreamRepo.updateMemoriesV1(any()),
() => mockSyncStreamRepo.updateMemoriesV2(any()),
() => mockSyncApiRepo.ack(["5"]),
]);
verifyNever(() => mockAbortCallbackWrapper());
});
test("handles memory sync failure gracefully", () async {
when(() => mockSyncStreamRepo.updateMemoriesV1(any())).thenThrow(Exception("Memory sync failed"));
when(() => mockSyncStreamRepo.updateMemoriesV2(any())).thenThrow(Exception("Memory sync failed"));
final events = [SyncStreamStub.memoryV1, SyncStreamStub.userV1Admin];
@@ -386,9 +386,22 @@ void main() {
await simulateEvents(events);
verify(() => mockSyncStreamRepo.updateMemoriesV1(any())).called(1);
verify(() => mockSyncStreamRepo.updateMemoriesV2(any())).called(1);
verify(() => mockSyncApiRepo.ack(["5"])).called(1);
});
test("processes memory v2 events", () async {
final events = [SyncStreamStub.memoryV2, SyncStreamStub.memoryToAssetV2];
await simulateEvents(events);
verifyInOrder([
() => mockSyncStreamRepo.updateMemoriesV2(any()),
() => mockSyncApiRepo.ack(["9"]),
() => mockSyncStreamRepo.updateMemoryAssetsV1(any()),
() => mockSyncApiRepo.ack(["10"]),
]);
});
});
group("SyncStreamService - remote trash & restore", () {
+26 -1
View File
@@ -47,7 +47,7 @@ abstract final class SyncStreamStub {
static final memoryV1 = SyncEvent(
type: SyncEntityType.memoryV1,
data: SyncMemoryV1(
data: SyncMemoryV2(
createdAt: DateTime(2023, 1, 1),
data: {"year": 2023, "title": "Test Memory"},
deletedAt: null,
@@ -64,6 +64,25 @@ abstract final class SyncStreamStub {
ack: "5",
);
static final memoryV2 = SyncEvent(
type: SyncEntityType.memoryV2,
data: SyncMemoryV2(
createdAt: DateTime(2023, 1, 1),
data: {"year": 2023},
deletedAt: null,
hideAt: null,
id: "memory-3",
isSaved: false,
memoryAt: DateTime(2023, 1, 1),
ownerId: "user-1",
seenAt: null,
showAt: DateTime(2023, 1, 1),
type: MemoryType.birthday,
updatedAt: DateTime(2023, 1, 1),
),
ack: "9",
);
static final memoryDeleteV1 = SyncEvent(
type: SyncEntityType.memoryDeleteV1,
data: SyncMemoryDeleteV1(memoryId: "memory-2"),
@@ -76,6 +95,12 @@ abstract final class SyncStreamStub {
ack: "7",
);
static final memoryToAssetV2 = SyncEvent(
type: SyncEntityType.memoryToAssetV2,
data: SyncMemoryAssetV1(assetId: "asset-1", memoryId: "memory-3"),
ack: "10",
);
static final memoryToAssetDeleteV1 = SyncEvent(
type: SyncEntityType.memoryToAssetDeleteV1,
data: SyncMemoryAssetDeleteV1(assetId: "asset-2", memoryId: "memory-1"),
+106
View File
@@ -23504,6 +23504,12 @@
],
"type": "string"
},
"MemoryTypeV1": {
"enum": [
"on_this_day"
],
"type": "string"
},
"MemoryUpdateDto": {
"properties": {
"isSaved": {
@@ -31400,8 +31406,10 @@
"AlbumToAssetDeleteV1",
"AlbumToAssetBackfillV1",
"MemoryV1",
"MemoryV2",
"MemoryDeleteV1",
"MemoryToAssetV1",
"MemoryToAssetV2",
"MemoryToAssetDeleteV1",
"StackV1",
"StackDeleteV1",
@@ -31476,6 +31484,102 @@
"type": "object"
},
"SyncMemoryV1": {
"properties": {
"createdAt": {
"description": "Created at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"data": {
"additionalProperties": {},
"description": "Data",
"type": "object"
},
"deletedAt": {
"description": "Deleted at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"nullable": true,
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"hideAt": {
"description": "Hide at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"nullable": true,
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"id": {
"description": "Memory ID",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
},
"isSaved": {
"description": "Is saved",
"type": "boolean"
},
"memoryAt": {
"description": "Memory at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"ownerId": {
"description": "Owner ID",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
},
"seenAt": {
"description": "Seen at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"nullable": true,
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"showAt": {
"description": "Show at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"nullable": true,
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"type": {
"$ref": "#/components/schemas/MemoryTypeV1"
},
"updatedAt": {
"description": "Updated at",
"example": "2024-01-01T00:00:00.000Z",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
}
},
"required": [
"createdAt",
"data",
"deletedAt",
"hideAt",
"id",
"isSaved",
"memoryAt",
"ownerId",
"seenAt",
"showAt",
"type",
"updatedAt"
],
"type": "object"
},
"SyncMemoryV2": {
"properties": {
"createdAt": {
"description": "Created at",
@@ -31724,7 +31828,9 @@
"AuthUsersV1",
"AuthUsersV2",
"MemoriesV1",
"MemoriesV2",
"MemoryToAssetsV1",
"MemoryToAssetsV2",
"PartnersV1",
"PartnerAssetsV1",
"PartnerAssetsV2",
+34
View File
@@ -3718,6 +3718,33 @@ export type SyncMemoryDeleteV1 = {
memoryId: string;
};
export type SyncMemoryV1 = {
/** Created at */
createdAt: string;
/** Data */
data: {
[key: string]: any;
};
/** Deleted at */
deletedAt: string | null;
/** Hide at */
hideAt: string | null;
/** Memory ID */
id: string;
/** Is saved */
isSaved: boolean;
/** Memory at */
memoryAt: string;
/** Owner ID */
ownerId: string;
/** Seen at */
seenAt: string | null;
/** Show at */
showAt: string | null;
"type": MemoryTypeV1;
/** Updated at */
updatedAt: string;
};
export type SyncMemoryV2 = {
/** Created at */
createdAt: string;
/** Data */
@@ -8532,8 +8559,10 @@ export enum SyncEntityType {
AlbumToAssetDeleteV1 = "AlbumToAssetDeleteV1",
AlbumToAssetBackfillV1 = "AlbumToAssetBackfillV1",
MemoryV1 = "MemoryV1",
MemoryV2 = "MemoryV2",
MemoryDeleteV1 = "MemoryDeleteV1",
MemoryToAssetV1 = "MemoryToAssetV1",
MemoryToAssetV2 = "MemoryToAssetV2",
MemoryToAssetDeleteV1 = "MemoryToAssetDeleteV1",
StackV1 = "StackV1",
StackDeleteV1 = "StackDeleteV1",
@@ -8566,7 +8595,9 @@ export enum SyncRequestType {
AuthUsersV1 = "AuthUsersV1",
AuthUsersV2 = "AuthUsersV2",
MemoriesV1 = "MemoriesV1",
MemoriesV2 = "MemoriesV2",
MemoryToAssetsV1 = "MemoryToAssetsV1",
MemoryToAssetsV2 = "MemoryToAssetsV2",
PartnersV1 = "PartnersV1",
PartnerAssetsV1 = "PartnerAssetsV1",
PartnerAssetsV2 = "PartnerAssetsV2",
@@ -8589,6 +8620,9 @@ export enum WorkflowResult {
Halted = "halted",
Error = "error"
}
export enum MemoryTypeV1 {
OnThisDay = "on_this_day"
}
export enum ReleaseType {
Major = "major",
Premajor = "premajor",
+9 -1
View File
@@ -295,7 +295,7 @@ const SyncMemoryV1Schema = z
updatedAt: isoDatetimeToDate.describe('Updated at'),
deletedAt: isoDatetimeToDate.nullable().describe('Deleted at'),
ownerId: z.uuidv4().describe('Owner ID'),
type: MemoryTypeSchema,
type: MemoryTypeSchema.extract(['OnThisDay']).meta({ id: 'MemoryTypeV1' }),
data: z.record(z.string(), z.unknown()).describe('Data'),
isSaved: z.boolean().describe('Is saved'),
memoryAt: isoDatetimeToDate.describe('Memory at'),
@@ -305,6 +305,10 @@ const SyncMemoryV1Schema = z
})
.meta({ id: 'SyncMemoryV1' });
const SyncMemoryV2Schema = SyncMemoryV1Schema.extend({
type: MemoryTypeSchema,
}).meta({ id: 'SyncMemoryV2' });
const SyncMemoryDeleteV1Schema = z
.object({ memoryId: z.uuidv4().describe('Memory ID') })
.meta({ id: 'SyncMemoryDeleteV1' });
@@ -403,6 +407,8 @@ const SyncCompleteV1Schema = z.object({}).meta({ id: 'SyncCompleteV1' });
@ExtraModel()
class SyncMemoryV1 extends createZodDto(SyncMemoryV1Schema) {}
@ExtraModel()
class SyncMemoryV2 extends createZodDto(SyncMemoryV2Schema) {}
@ExtraModel()
class SyncMemoryDeleteV1 extends createZodDto(SyncMemoryDeleteV1Schema) {}
@ExtraModel()
class SyncMemoryAssetV1 extends createZodDto(SyncMemoryAssetV1Schema) {}
@@ -505,8 +511,10 @@ export type SyncItem = {
[SyncEntityType.AlbumToAssetBackfillV1]: SyncAlbumToAssetV1;
[SyncEntityType.AlbumToAssetDeleteV1]: SyncAlbumToAssetDeleteV1;
[SyncEntityType.MemoryV1]: SyncMemoryV1;
[SyncEntityType.MemoryV2]: SyncMemoryV2;
[SyncEntityType.MemoryDeleteV1]: SyncMemoryDeleteV1;
[SyncEntityType.MemoryToAssetV1]: SyncMemoryAssetV1;
[SyncEntityType.MemoryToAssetV2]: SyncMemoryAssetV1;
[SyncEntityType.MemoryToAssetDeleteV1]: SyncMemoryAssetDeleteV1;
[SyncEntityType.StackV1]: SyncStackV1;
[SyncEntityType.StackDeleteV1]: SyncStackDeleteV1;
+4
View File
@@ -1055,7 +1055,9 @@ export enum SyncRequestType {
AuthUsersV1 = 'AuthUsersV1',
AuthUsersV2 = 'AuthUsersV2',
MemoriesV1 = 'MemoriesV1',
MemoriesV2 = 'MemoriesV2',
MemoryToAssetsV1 = 'MemoryToAssetsV1',
MemoryToAssetsV2 = 'MemoryToAssetsV2',
PartnersV1 = 'PartnersV1',
/** @deprecated */
PartnerAssetsV1 = 'PartnerAssetsV1',
@@ -1139,9 +1141,11 @@ export enum SyncEntityType {
AlbumToAssetBackfillV1 = 'AlbumToAssetBackfillV1',
MemoryV1 = 'MemoryV1',
MemoryV2 = 'MemoryV2',
MemoryDeleteV1 = 'MemoryDeleteV1',
MemoryToAssetV1 = 'MemoryToAssetV1',
MemoryToAssetV2 = 'MemoryToAssetV2',
MemoryToAssetDeleteV1 = 'MemoryToAssetDeleteV1',
StackV1 = 'StackV1',
+22
View File
@@ -768,6 +768,28 @@ where
order by
"memory_asset_audit"."id" asc
-- SyncRepository.memoryToAsset.getUpsertsV1
select
"memoriesId" as "memoryId",
"assetId" as "assetId",
"updateId"
from
"memory_asset" as "memory_asset"
where
"memory_asset"."updateId" < $1
and "memory_asset"."updateId" > $2
and "memoriesId" in (
select
"id"
from
"memory"
where
"ownerId" = $3
and "type" = 'on_this_day'
)
order by
"memory_asset"."updateId" asc
-- SyncRepository.memoryToAsset.getUpserts
select
"memoriesId" as "memoryId",
@@ -4,6 +4,7 @@ import { InjectKysely } from 'nestjs-kysely';
import type { SyncAck } from 'src/types.js';
import { columns } from 'src/database.js';
import { DummyValue, GenerateSql } from 'src/decorators.js';
import { MemoryType } from 'src/enum.js';
import { DB } from 'src/schema/index.js';
export type SyncBackfillOptions = {
@@ -596,6 +597,21 @@ class MemoryToAssetSync extends BaseSync {
return this.auditCleanup('memory_asset_audit', daysAgo);
}
@GenerateSql({ params: [dummyQueryOptions], stream: true })
getUpsertsV1(options: SyncQueryOptions) {
return this.upsertQuery('memory_asset', options)
.select(['memoriesId as memoryId', 'assetId as assetId'])
.select('updateId')
.where('memoriesId', 'in', (eb) =>
eb
.selectFrom('memory')
.select('id')
.where('ownerId', '=', options.userId)
.where('type', '=', sql.lit(MemoryType.OnThisDay)),
)
.stream();
}
@GenerateSql({ params: [dummyQueryOptions], stream: true })
getUpserts(options: SyncQueryOptions) {
return this.upsertQuery('memory_asset', options)
+35 -1
View File
@@ -13,7 +13,7 @@ import {
SyncStreamDto,
syncAlbumV2ToV1,
} from 'src/dtos/sync.dto.js';
import { JobName, QueueName, SyncEntityType, SyncRequestType } from 'src/enum.js';
import { JobName, MemoryType, QueueName, SyncEntityType, SyncRequestType } from 'src/enum.js';
import { SyncQueryOptions } from 'src/repositories/sync.repository.js';
import { SessionSyncCheckpointTable } from 'src/schema/tables/sync-checkpoint.table.js';
import { BaseService } from 'src/services/base.service.js';
@@ -83,7 +83,9 @@ export const SYNC_TYPES_ORDER = [
SyncRequestType.AssetOcrV1,
SyncRequestType.PartnerAssetExifsV1,
SyncRequestType.MemoriesV1,
SyncRequestType.MemoriesV2,
SyncRequestType.MemoryToAssetsV1,
SyncRequestType.MemoryToAssetsV2,
SyncRequestType.PeopleV1,
SyncRequestType.AssetFacesV1,
SyncRequestType.AssetFacesV2,
@@ -210,7 +212,9 @@ export class SyncService extends BaseService {
[SyncRequestType.AlbumAssetExifsV1]: () =>
this.syncAlbumAssetExifsV1(options, response, checkpointMap, session.id),
[SyncRequestType.MemoriesV1]: () => this.syncMemoriesV1(options, response, checkpointMap),
[SyncRequestType.MemoriesV2]: () => this.syncMemoriesV2(options, response, checkpointMap),
[SyncRequestType.MemoryToAssetsV1]: () => this.syncMemoryAssetsV1(options, response, checkpointMap),
[SyncRequestType.MemoryToAssetsV2]: () => this.syncMemoryAssetsV2(options, response, checkpointMap),
[SyncRequestType.StacksV1]: () => this.syncStackV1(options, response, checkpointMap),
[SyncRequestType.PartnerStacksV1]: () => this.syncPartnerStackV1(options, response, checkpointMap, session.id),
[SyncRequestType.PeopleV1]: () => this.syncPeopleV1(options, response, checkpointMap),
@@ -786,6 +790,22 @@ export class SyncService extends BaseService {
const upsertType = SyncEntityType.MemoryV1;
const upserts = this.syncRepository.memory.getUpserts({ ...options, ack: checkpointMap[upsertType] });
for await (const { updateId, ...data } of upserts) {
if (data.type === MemoryType.OnThisDay) {
await send(response, { type: upsertType, ids: [updateId], data: { ...data, type: data.type } });
}
}
}
private async syncMemoriesV2(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) {
const deleteType = SyncEntityType.MemoryDeleteV1;
const deletes = this.syncRepository.memory.getDeletes({ ...options, ack: checkpointMap[deleteType] });
for await (const { id, ...data } of deletes) {
await send(response, { type: deleteType, ids: [id], data });
}
const upsertType = SyncEntityType.MemoryV2;
const upserts = this.syncRepository.memory.getUpserts({ ...options, ack: checkpointMap[upsertType] });
for await (const { updateId, ...data } of upserts) {
await send(response, { type: upsertType, ids: [updateId], data });
}
@@ -799,6 +819,20 @@ export class SyncService extends BaseService {
}
const upsertType = SyncEntityType.MemoryToAssetV1;
const upserts = this.syncRepository.memoryToAsset.getUpsertsV1({ ...options, ack: checkpointMap[upsertType] });
for await (const { updateId, ...data } of upserts) {
await send(response, { type: upsertType, ids: [updateId], data });
}
}
private async syncMemoryAssetsV2(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) {
const deleteType = SyncEntityType.MemoryToAssetDeleteV1;
const deletes = this.syncRepository.memoryToAsset.getDeletes({ ...options, ack: checkpointMap[deleteType] });
for await (const { id, ...data } of deletes) {
await send(response, { type: deleteType, ids: [id], data });
}
const upsertType = SyncEntityType.MemoryToAssetV2;
const upserts = this.syncRepository.memoryToAsset.getUpserts({ ...options, ack: checkpointMap[upsertType] });
for await (const { updateId, ...data } of upserts) {
await send(response, { type: upsertType, ids: [updateId], data });