mirror of
https://github.com/immich-app/immich.git
synced 2026-10-12 02:16:40 +00:00
fix: memories mobile sync for older clients (#32150)
Co-authored-by: Santo Shakil <[email protected]>
This commit is contained in:
co-authored by
Santo Shakil
parent
e49a5bb8c9
commit
8d377bfef5
@@ -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
@@ -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"),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 });
|
||||
|
||||
Reference in New Issue
Block a user