feat: memories sync (#19644)

* feat: memories sync

* Update mobile/lib/infrastructure/repositories/sync_stream.repository.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update mobile/lib/infrastructure/repositories/sync_stream.repository.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* show sync information

* tests and pr feedback

* pr feedback

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Alex 2025-07-02 14:18:37 -05:00 committed by GitHub
parent 7855974a29
commit 445f9174ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 3491 additions and 33 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,202 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
enum MemoryTypeEnum {
// do not change this order!
onThisDay,
}
class MemoryData {
final int year;
const MemoryData({
required this.year,
});
MemoryData copyWith({
int? year,
}) {
return MemoryData(
year: year ?? this.year,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'year': year,
};
}
factory MemoryData.fromMap(Map<String, dynamic> map) {
return MemoryData(
year: map['year'] as int,
);
}
String toJson() => json.encode(toMap());
factory MemoryData.fromJson(String source) =>
MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'MemoryData(year: $year)';
@override
bool operator ==(covariant MemoryData other) {
if (identical(this, other)) return true;
return other.year == year;
}
@override
int get hashCode => year.hashCode;
}
// Model for a memory stored in the server
class Memory {
final String id;
final DateTime createdAt;
final DateTime updatedAt;
final DateTime? deletedAt;
final String ownerId;
// enum
final MemoryTypeEnum type;
final MemoryData data;
final bool isSaved;
final DateTime memoryAt;
final DateTime? seenAt;
final DateTime? showAt;
final DateTime? hideAt;
const Memory({
required this.id,
required this.createdAt,
required this.updatedAt,
this.deletedAt,
required this.ownerId,
required this.type,
required this.data,
required this.isSaved,
required this.memoryAt,
this.seenAt,
this.showAt,
this.hideAt,
});
Memory copyWith({
String? id,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? deletedAt,
String? ownerId,
MemoryTypeEnum? type,
MemoryData? data,
bool? isSaved,
DateTime? memoryAt,
DateTime? seenAt,
DateTime? showAt,
DateTime? hideAt,
}) {
return Memory(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
ownerId: ownerId ?? this.ownerId,
type: type ?? this.type,
data: data ?? this.data,
isSaved: isSaved ?? this.isSaved,
memoryAt: memoryAt ?? this.memoryAt,
seenAt: seenAt ?? this.seenAt,
showAt: showAt ?? this.showAt,
hideAt: hideAt ?? this.hideAt,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'createdAt': createdAt.millisecondsSinceEpoch,
'updatedAt': updatedAt.millisecondsSinceEpoch,
'deletedAt': deletedAt?.millisecondsSinceEpoch,
'ownerId': ownerId,
'type': type.index,
'data': data.toMap(),
'isSaved': isSaved,
'memoryAt': memoryAt.millisecondsSinceEpoch,
'seenAt': seenAt?.millisecondsSinceEpoch,
'showAt': showAt?.millisecondsSinceEpoch,
'hideAt': hideAt?.millisecondsSinceEpoch,
};
}
factory Memory.fromMap(Map<String, dynamic> map) {
return Memory(
id: map['id'] as String,
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int),
deletedAt: map['deletedAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['deletedAt'] as int)
: null,
ownerId: map['ownerId'] as String,
type: MemoryTypeEnum.values[map['type'] as int],
data: MemoryData.fromMap(map['data'] as Map<String, dynamic>),
isSaved: map['isSaved'] as bool,
memoryAt: DateTime.fromMillisecondsSinceEpoch(map['memoryAt'] as int),
seenAt: map['seenAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['seenAt'] as int)
: null,
showAt: map['showAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['showAt'] as int)
: null,
hideAt: map['hideAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['hideAt'] as int)
: null,
);
}
String toJson() => json.encode(toMap());
factory Memory.fromJson(String source) =>
Memory.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() {
return 'Memory(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, ownerId: $ownerId, type: $type, data: $data, isSaved: $isSaved, memoryAt: $memoryAt, seenAt: $seenAt, showAt: $showAt, hideAt: $hideAt)';
}
@override
bool operator ==(covariant Memory other) {
if (identical(this, other)) return true;
return other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.deletedAt == deletedAt &&
other.ownerId == ownerId &&
other.type == type &&
other.data == data &&
other.isSaved == isSaved &&
other.memoryAt == memoryAt &&
other.seenAt == seenAt &&
other.showAt == showAt &&
other.hideAt == hideAt;
}
@override
int get hashCode {
return id.hashCode ^
createdAt.hashCode ^
updatedAt.hashCode ^
deletedAt.hashCode ^
ownerId.hashCode ^
type.hashCode ^
data.hashCode ^
isSaved.hashCode ^
memoryAt.hashCode ^
seenAt.hashCode ^
showAt.hashCode ^
hideAt.hashCode;
}
}

View File

@ -146,6 +146,14 @@ class SyncStreamService {
// to acknowledge that the client has processed all the backfill events // to acknowledge that the client has processed all the backfill events
case SyncEntityType.syncAckV1: case SyncEntityType.syncAckV1:
return; return;
case SyncEntityType.memoryV1:
return _syncStreamRepository.updateMemoriesV1(data.cast());
case SyncEntityType.memoryDeleteV1:
return _syncStreamRepository.deleteMemoriesV1(data.cast());
case SyncEntityType.memoryToAssetV1:
return _syncStreamRepository.updateMemoryAssetsV1(data.cast());
case SyncEntityType.memoryToAssetDeleteV1:
return _syncStreamRepository.deleteMemoryAssetsV1(data.cast());
default: default:
_logger.warning("Unknown sync data type: $type"); _logger.warning("Unknown sync data type: $type");
} }

View File

@ -0,0 +1,36 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/memory.model.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class MemoryEntity extends Table with DriftDefaultsMixin {
const MemoryEntity();
TextColumn get id => text()();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
DateTimeColumn get deletedAt => dateTime().nullable()();
TextColumn get ownerId =>
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
IntColumn get type => intEnum<MemoryTypeEnum>()();
TextColumn get data => text()();
BoolColumn get isSaved => boolean().withDefault(const Constant(false))();
DateTimeColumn get memoryAt => dateTime()();
DateTimeColumn get seenAt => dateTime().nullable()();
DateTimeColumn get showAt => dateTime().nullable()();
DateTimeColumn get hideAt => dateTime().nullable()();
@override
Set<Column> get primaryKey => {id};
}

View File

@ -0,0 +1,970 @@
// dart format width=80
// ignore_for_file: type=lint
import 'package:drift/drift.dart' as i0;
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
as i1;
import 'package:immich_mobile/domain/models/memory.model.dart' as i2;
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart' as i3;
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
as i5;
import 'package:drift/internal/modular.dart' as i6;
typedef $$MemoryEntityTableCreateCompanionBuilder = i1.MemoryEntityCompanion
Function({
required String id,
i0.Value<DateTime> createdAt,
i0.Value<DateTime> updatedAt,
i0.Value<DateTime?> deletedAt,
required String ownerId,
required i2.MemoryTypeEnum type,
required String data,
i0.Value<bool> isSaved,
required DateTime memoryAt,
i0.Value<DateTime?> seenAt,
i0.Value<DateTime?> showAt,
i0.Value<DateTime?> hideAt,
});
typedef $$MemoryEntityTableUpdateCompanionBuilder = i1.MemoryEntityCompanion
Function({
i0.Value<String> id,
i0.Value<DateTime> createdAt,
i0.Value<DateTime> updatedAt,
i0.Value<DateTime?> deletedAt,
i0.Value<String> ownerId,
i0.Value<i2.MemoryTypeEnum> type,
i0.Value<String> data,
i0.Value<bool> isSaved,
i0.Value<DateTime> memoryAt,
i0.Value<DateTime?> seenAt,
i0.Value<DateTime?> showAt,
i0.Value<DateTime?> hideAt,
});
final class $$MemoryEntityTableReferences extends i0.BaseReferences<
i0.GeneratedDatabase, i1.$MemoryEntityTable, i1.MemoryEntityData> {
$$MemoryEntityTableReferences(super.$_db, super.$_table, super.$_typedResult);
static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
i6.ReadDatabaseContainer(db)
.resultSet<i5.$UserEntityTable>('user_entity')
.createAlias(i0.$_aliasNameGenerator(
i6.ReadDatabaseContainer(db)
.resultSet<i1.$MemoryEntityTable>('memory_entity')
.ownerId,
i6.ReadDatabaseContainer(db)
.resultSet<i5.$UserEntityTable>('user_entity')
.id));
i5.$$UserEntityTableProcessedTableManager get ownerId {
final $_column = $_itemColumn<String>('owner_id')!;
final manager = i5
.$$UserEntityTableTableManager(
$_db,
i6.ReadDatabaseContainer($_db)
.resultSet<i5.$UserEntityTable>('user_entity'))
.filter((f) => f.id.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_ownerIdTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
}
class $$MemoryEntityTableFilterComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$MemoryEntityTable> {
$$MemoryEntityTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.ColumnFilters<String> get id => $composableBuilder(
column: $table.id, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get deletedAt => $composableBuilder(
column: $table.deletedAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnWithTypeConverterFilters<i2.MemoryTypeEnum, i2.MemoryTypeEnum, int>
get type => $composableBuilder(
column: $table.type,
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
i0.ColumnFilters<String> get data => $composableBuilder(
column: $table.data, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<bool> get isSaved => $composableBuilder(
column: $table.isSaved, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get memoryAt => $composableBuilder(
column: $table.memoryAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get seenAt => $composableBuilder(
column: $table.seenAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get showAt => $composableBuilder(
column: $table.showAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get hideAt => $composableBuilder(
column: $table.hideAt, builder: (column) => i0.ColumnFilters(column));
i5.$$UserEntityTableFilterComposer get ownerId {
final i5.$$UserEntityTableFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.ownerId,
referencedTable: i6.ReadDatabaseContainer($db)
.resultSet<i5.$UserEntityTable>('user_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i5.$$UserEntityTableFilterComposer(
$db: $db,
$table: i6.ReadDatabaseContainer($db)
.resultSet<i5.$UserEntityTable>('user_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$MemoryEntityTableOrderingComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$MemoryEntityTable> {
$$MemoryEntityTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.ColumnOrderings<String> get id => $composableBuilder(
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder(
column: $table.updatedAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get deletedAt => $composableBuilder(
column: $table.deletedAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<int> get type => $composableBuilder(
column: $table.type, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get data => $composableBuilder(
column: $table.data, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<bool> get isSaved => $composableBuilder(
column: $table.isSaved, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get memoryAt => $composableBuilder(
column: $table.memoryAt, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get seenAt => $composableBuilder(
column: $table.seenAt, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get showAt => $composableBuilder(
column: $table.showAt, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get hideAt => $composableBuilder(
column: $table.hideAt, builder: (column) => i0.ColumnOrderings(column));
i5.$$UserEntityTableOrderingComposer get ownerId {
final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.ownerId,
referencedTable: i6.ReadDatabaseContainer($db)
.resultSet<i5.$UserEntityTable>('user_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i5.$$UserEntityTableOrderingComposer(
$db: $db,
$table: i6.ReadDatabaseContainer($db)
.resultSet<i5.$UserEntityTable>('user_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$MemoryEntityTableAnnotationComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$MemoryEntityTable> {
$$MemoryEntityTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.GeneratedColumn<String> get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
i0.GeneratedColumn<DateTime> get createdAt =>
$composableBuilder(column: $table.createdAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get updatedAt =>
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get deletedAt =>
$composableBuilder(column: $table.deletedAt, builder: (column) => column);
i0.GeneratedColumnWithTypeConverter<i2.MemoryTypeEnum, int> get type =>
$composableBuilder(column: $table.type, builder: (column) => column);
i0.GeneratedColumn<String> get data =>
$composableBuilder(column: $table.data, builder: (column) => column);
i0.GeneratedColumn<bool> get isSaved =>
$composableBuilder(column: $table.isSaved, builder: (column) => column);
i0.GeneratedColumn<DateTime> get memoryAt =>
$composableBuilder(column: $table.memoryAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get seenAt =>
$composableBuilder(column: $table.seenAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get showAt =>
$composableBuilder(column: $table.showAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get hideAt =>
$composableBuilder(column: $table.hideAt, builder: (column) => column);
i5.$$UserEntityTableAnnotationComposer get ownerId {
final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.ownerId,
referencedTable: i6.ReadDatabaseContainer($db)
.resultSet<i5.$UserEntityTable>('user_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i5.$$UserEntityTableAnnotationComposer(
$db: $db,
$table: i6.ReadDatabaseContainer($db)
.resultSet<i5.$UserEntityTable>('user_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$MemoryEntityTableTableManager extends i0.RootTableManager<
i0.GeneratedDatabase,
i1.$MemoryEntityTable,
i1.MemoryEntityData,
i1.$$MemoryEntityTableFilterComposer,
i1.$$MemoryEntityTableOrderingComposer,
i1.$$MemoryEntityTableAnnotationComposer,
$$MemoryEntityTableCreateCompanionBuilder,
$$MemoryEntityTableUpdateCompanionBuilder,
(i1.MemoryEntityData, i1.$$MemoryEntityTableReferences),
i1.MemoryEntityData,
i0.PrefetchHooks Function({bool ownerId})> {
$$MemoryEntityTableTableManager(
i0.GeneratedDatabase db, i1.$MemoryEntityTable table)
: super(i0.TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
i1.$$MemoryEntityTableFilterComposer($db: db, $table: table),
createOrderingComposer: () =>
i1.$$MemoryEntityTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () =>
i1.$$MemoryEntityTableAnnotationComposer($db: db, $table: table),
updateCompanionCallback: ({
i0.Value<String> id = const i0.Value.absent(),
i0.Value<DateTime> createdAt = const i0.Value.absent(),
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<String> ownerId = const i0.Value.absent(),
i0.Value<i2.MemoryTypeEnum> type = const i0.Value.absent(),
i0.Value<String> data = const i0.Value.absent(),
i0.Value<bool> isSaved = const i0.Value.absent(),
i0.Value<DateTime> memoryAt = const i0.Value.absent(),
i0.Value<DateTime?> seenAt = const i0.Value.absent(),
i0.Value<DateTime?> showAt = const i0.Value.absent(),
i0.Value<DateTime?> hideAt = const i0.Value.absent(),
}) =>
i1.MemoryEntityCompanion(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
ownerId: ownerId,
type: type,
data: data,
isSaved: isSaved,
memoryAt: memoryAt,
seenAt: seenAt,
showAt: showAt,
hideAt: hideAt,
),
createCompanionCallback: ({
required String id,
i0.Value<DateTime> createdAt = const i0.Value.absent(),
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
required String ownerId,
required i2.MemoryTypeEnum type,
required String data,
i0.Value<bool> isSaved = const i0.Value.absent(),
required DateTime memoryAt,
i0.Value<DateTime?> seenAt = const i0.Value.absent(),
i0.Value<DateTime?> showAt = const i0.Value.absent(),
i0.Value<DateTime?> hideAt = const i0.Value.absent(),
}) =>
i1.MemoryEntityCompanion.insert(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
ownerId: ownerId,
type: type,
data: data,
isSaved: isSaved,
memoryAt: memoryAt,
seenAt: seenAt,
showAt: showAt,
hideAt: hideAt,
),
withReferenceMapper: (p0) => p0
.map((e) => (
e.readTable(table),
i1.$$MemoryEntityTableReferences(db, table, e)
))
.toList(),
prefetchHooksCallback: ({ownerId = false}) {
return i0.PrefetchHooks(
db: db,
explicitlyWatchedTables: [],
addJoins: <
T extends i0.TableManagerState<
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic>>(state) {
if (ownerId) {
state = state.withJoin(
currentTable: table,
currentColumn: table.ownerId,
referencedTable:
i1.$$MemoryEntityTableReferences._ownerIdTable(db),
referencedColumn:
i1.$$MemoryEntityTableReferences._ownerIdTable(db).id,
) as T;
}
return state;
},
getPrefetchedDataCallback: (items) async {
return [];
},
);
},
));
}
typedef $$MemoryEntityTableProcessedTableManager = i0.ProcessedTableManager<
i0.GeneratedDatabase,
i1.$MemoryEntityTable,
i1.MemoryEntityData,
i1.$$MemoryEntityTableFilterComposer,
i1.$$MemoryEntityTableOrderingComposer,
i1.$$MemoryEntityTableAnnotationComposer,
$$MemoryEntityTableCreateCompanionBuilder,
$$MemoryEntityTableUpdateCompanionBuilder,
(i1.MemoryEntityData, i1.$$MemoryEntityTableReferences),
i1.MemoryEntityData,
i0.PrefetchHooks Function({bool ownerId})>;
class $MemoryEntityTable extends i3.MemoryEntity
with i0.TableInfo<$MemoryEntityTable, i1.MemoryEntityData> {
@override
final i0.GeneratedDatabase attachedDatabase;
final String? _alias;
$MemoryEntityTable(this.attachedDatabase, [this._alias]);
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
@override
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
'id', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _createdAtMeta =
const i0.VerificationMeta('createdAt');
@override
late final i0.GeneratedColumn<DateTime> createdAt =
i0.GeneratedColumn<DateTime>('created_at', aliasedName, false,
type: i0.DriftSqlType.dateTime,
requiredDuringInsert: false,
defaultValue: i4.currentDateAndTime);
static const i0.VerificationMeta _updatedAtMeta =
const i0.VerificationMeta('updatedAt');
@override
late final i0.GeneratedColumn<DateTime> updatedAt =
i0.GeneratedColumn<DateTime>('updated_at', aliasedName, false,
type: i0.DriftSqlType.dateTime,
requiredDuringInsert: false,
defaultValue: i4.currentDateAndTime);
static const i0.VerificationMeta _deletedAtMeta =
const i0.VerificationMeta('deletedAt');
@override
late final i0.GeneratedColumn<DateTime> deletedAt =
i0.GeneratedColumn<DateTime>('deleted_at', aliasedName, true,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
static const i0.VerificationMeta _ownerIdMeta =
const i0.VerificationMeta('ownerId');
@override
late final i0.GeneratedColumn<String> ownerId = i0.GeneratedColumn<String>(
'owner_id', aliasedName, false,
type: i0.DriftSqlType.string,
requiredDuringInsert: true,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'REFERENCES user_entity (id) ON DELETE CASCADE'));
@override
late final i0.GeneratedColumnWithTypeConverter<i2.MemoryTypeEnum, int> type =
i0.GeneratedColumn<int>('type', aliasedName, false,
type: i0.DriftSqlType.int, requiredDuringInsert: true)
.withConverter<i2.MemoryTypeEnum>(
i1.$MemoryEntityTable.$convertertype);
static const i0.VerificationMeta _dataMeta =
const i0.VerificationMeta('data');
@override
late final i0.GeneratedColumn<String> data = i0.GeneratedColumn<String>(
'data', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _isSavedMeta =
const i0.VerificationMeta('isSaved');
@override
late final i0.GeneratedColumn<bool> isSaved = i0.GeneratedColumn<bool>(
'is_saved', aliasedName, false,
type: i0.DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints:
i0.GeneratedColumn.constraintIsAlways('CHECK ("is_saved" IN (0, 1))'),
defaultValue: const i4.Constant(false));
static const i0.VerificationMeta _memoryAtMeta =
const i0.VerificationMeta('memoryAt');
@override
late final i0.GeneratedColumn<DateTime> memoryAt =
i0.GeneratedColumn<DateTime>('memory_at', aliasedName, false,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: true);
static const i0.VerificationMeta _seenAtMeta =
const i0.VerificationMeta('seenAt');
@override
late final i0.GeneratedColumn<DateTime> seenAt = i0.GeneratedColumn<DateTime>(
'seen_at', aliasedName, true,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
static const i0.VerificationMeta _showAtMeta =
const i0.VerificationMeta('showAt');
@override
late final i0.GeneratedColumn<DateTime> showAt = i0.GeneratedColumn<DateTime>(
'show_at', aliasedName, true,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
static const i0.VerificationMeta _hideAtMeta =
const i0.VerificationMeta('hideAt');
@override
late final i0.GeneratedColumn<DateTime> hideAt = i0.GeneratedColumn<DateTime>(
'hide_at', aliasedName, true,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
@override
List<i0.GeneratedColumn> get $columns => [
id,
createdAt,
updatedAt,
deletedAt,
ownerId,
type,
data,
isSaved,
memoryAt,
seenAt,
showAt,
hideAt
];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'memory_entity';
@override
i0.VerificationContext validateIntegrity(
i0.Insertable<i1.MemoryEntityData> instance,
{bool isInserting = false}) {
final context = i0.VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
} else if (isInserting) {
context.missing(_idMeta);
}
if (data.containsKey('created_at')) {
context.handle(_createdAtMeta,
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
}
if (data.containsKey('updated_at')) {
context.handle(_updatedAtMeta,
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
}
if (data.containsKey('deleted_at')) {
context.handle(_deletedAtMeta,
deletedAt.isAcceptableOrUnknown(data['deleted_at']!, _deletedAtMeta));
}
if (data.containsKey('owner_id')) {
context.handle(_ownerIdMeta,
ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta));
} else if (isInserting) {
context.missing(_ownerIdMeta);
}
if (data.containsKey('data')) {
context.handle(
_dataMeta, this.data.isAcceptableOrUnknown(data['data']!, _dataMeta));
} else if (isInserting) {
context.missing(_dataMeta);
}
if (data.containsKey('is_saved')) {
context.handle(_isSavedMeta,
isSaved.isAcceptableOrUnknown(data['is_saved']!, _isSavedMeta));
}
if (data.containsKey('memory_at')) {
context.handle(_memoryAtMeta,
memoryAt.isAcceptableOrUnknown(data['memory_at']!, _memoryAtMeta));
} else if (isInserting) {
context.missing(_memoryAtMeta);
}
if (data.containsKey('seen_at')) {
context.handle(_seenAtMeta,
seenAt.isAcceptableOrUnknown(data['seen_at']!, _seenAtMeta));
}
if (data.containsKey('show_at')) {
context.handle(_showAtMeta,
showAt.isAcceptableOrUnknown(data['show_at']!, _showAtMeta));
}
if (data.containsKey('hide_at')) {
context.handle(_hideAtMeta,
hideAt.isAcceptableOrUnknown(data['hide_at']!, _hideAtMeta));
}
return context;
}
@override
Set<i0.GeneratedColumn> get $primaryKey => {id};
@override
i1.MemoryEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return i1.MemoryEntityData(
id: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
createdAt: attachedDatabase.typeMapping.read(
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
updatedAt: attachedDatabase.typeMapping.read(
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
deletedAt: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']),
ownerId: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!,
type: i1.$MemoryEntityTable.$convertertype.fromSql(attachedDatabase
.typeMapping
.read(i0.DriftSqlType.int, data['${effectivePrefix}type'])!),
data: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}data'])!,
isSaved: attachedDatabase.typeMapping
.read(i0.DriftSqlType.bool, data['${effectivePrefix}is_saved'])!,
memoryAt: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}memory_at'])!,
seenAt: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}seen_at']),
showAt: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}show_at']),
hideAt: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}hide_at']),
);
}
@override
$MemoryEntityTable createAlias(String alias) {
return $MemoryEntityTable(attachedDatabase, alias);
}
static i0.JsonTypeConverter2<i2.MemoryTypeEnum, int, int> $convertertype =
const i0.EnumIndexConverter<i2.MemoryTypeEnum>(i2.MemoryTypeEnum.values);
@override
bool get withoutRowId => true;
@override
bool get isStrict => true;
}
class MemoryEntityData extends i0.DataClass
implements i0.Insertable<i1.MemoryEntityData> {
final String id;
final DateTime createdAt;
final DateTime updatedAt;
final DateTime? deletedAt;
final String ownerId;
final i2.MemoryTypeEnum type;
final String data;
final bool isSaved;
final DateTime memoryAt;
final DateTime? seenAt;
final DateTime? showAt;
final DateTime? hideAt;
const MemoryEntityData(
{required this.id,
required this.createdAt,
required this.updatedAt,
this.deletedAt,
required this.ownerId,
required this.type,
required this.data,
required this.isSaved,
required this.memoryAt,
this.seenAt,
this.showAt,
this.hideAt});
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
map['id'] = i0.Variable<String>(id);
map['created_at'] = i0.Variable<DateTime>(createdAt);
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
if (!nullToAbsent || deletedAt != null) {
map['deleted_at'] = i0.Variable<DateTime>(deletedAt);
}
map['owner_id'] = i0.Variable<String>(ownerId);
{
map['type'] =
i0.Variable<int>(i1.$MemoryEntityTable.$convertertype.toSql(type));
}
map['data'] = i0.Variable<String>(data);
map['is_saved'] = i0.Variable<bool>(isSaved);
map['memory_at'] = i0.Variable<DateTime>(memoryAt);
if (!nullToAbsent || seenAt != null) {
map['seen_at'] = i0.Variable<DateTime>(seenAt);
}
if (!nullToAbsent || showAt != null) {
map['show_at'] = i0.Variable<DateTime>(showAt);
}
if (!nullToAbsent || hideAt != null) {
map['hide_at'] = i0.Variable<DateTime>(hideAt);
}
return map;
}
factory MemoryEntityData.fromJson(Map<String, dynamic> json,
{i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return MemoryEntityData(
id: serializer.fromJson<String>(json['id']),
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
deletedAt: serializer.fromJson<DateTime?>(json['deletedAt']),
ownerId: serializer.fromJson<String>(json['ownerId']),
type: i1.$MemoryEntityTable.$convertertype
.fromJson(serializer.fromJson<int>(json['type'])),
data: serializer.fromJson<String>(json['data']),
isSaved: serializer.fromJson<bool>(json['isSaved']),
memoryAt: serializer.fromJson<DateTime>(json['memoryAt']),
seenAt: serializer.fromJson<DateTime?>(json['seenAt']),
showAt: serializer.fromJson<DateTime?>(json['showAt']),
hideAt: serializer.fromJson<DateTime?>(json['hideAt']),
);
}
@override
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<String>(id),
'createdAt': serializer.toJson<DateTime>(createdAt),
'updatedAt': serializer.toJson<DateTime>(updatedAt),
'deletedAt': serializer.toJson<DateTime?>(deletedAt),
'ownerId': serializer.toJson<String>(ownerId),
'type': serializer
.toJson<int>(i1.$MemoryEntityTable.$convertertype.toJson(type)),
'data': serializer.toJson<String>(data),
'isSaved': serializer.toJson<bool>(isSaved),
'memoryAt': serializer.toJson<DateTime>(memoryAt),
'seenAt': serializer.toJson<DateTime?>(seenAt),
'showAt': serializer.toJson<DateTime?>(showAt),
'hideAt': serializer.toJson<DateTime?>(hideAt),
};
}
i1.MemoryEntityData copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
String? ownerId,
i2.MemoryTypeEnum? type,
String? data,
bool? isSaved,
DateTime? memoryAt,
i0.Value<DateTime?> seenAt = const i0.Value.absent(),
i0.Value<DateTime?> showAt = const i0.Value.absent(),
i0.Value<DateTime?> hideAt = const i0.Value.absent()}) =>
i1.MemoryEntityData(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt,
ownerId: ownerId ?? this.ownerId,
type: type ?? this.type,
data: data ?? this.data,
isSaved: isSaved ?? this.isSaved,
memoryAt: memoryAt ?? this.memoryAt,
seenAt: seenAt.present ? seenAt.value : this.seenAt,
showAt: showAt.present ? showAt.value : this.showAt,
hideAt: hideAt.present ? hideAt.value : this.hideAt,
);
MemoryEntityData copyWithCompanion(i1.MemoryEntityCompanion data) {
return MemoryEntityData(
id: data.id.present ? data.id.value : this.id,
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt,
ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId,
type: data.type.present ? data.type.value : this.type,
data: data.data.present ? data.data.value : this.data,
isSaved: data.isSaved.present ? data.isSaved.value : this.isSaved,
memoryAt: data.memoryAt.present ? data.memoryAt.value : this.memoryAt,
seenAt: data.seenAt.present ? data.seenAt.value : this.seenAt,
showAt: data.showAt.present ? data.showAt.value : this.showAt,
hideAt: data.hideAt.present ? data.hideAt.value : this.hideAt,
);
}
@override
String toString() {
return (StringBuffer('MemoryEntityData(')
..write('id: $id, ')
..write('createdAt: $createdAt, ')
..write('updatedAt: $updatedAt, ')
..write('deletedAt: $deletedAt, ')
..write('ownerId: $ownerId, ')
..write('type: $type, ')
..write('data: $data, ')
..write('isSaved: $isSaved, ')
..write('memoryAt: $memoryAt, ')
..write('seenAt: $seenAt, ')
..write('showAt: $showAt, ')
..write('hideAt: $hideAt')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(id, createdAt, updatedAt, deletedAt, ownerId,
type, data, isSaved, memoryAt, seenAt, showAt, hideAt);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is i1.MemoryEntityData &&
other.id == this.id &&
other.createdAt == this.createdAt &&
other.updatedAt == this.updatedAt &&
other.deletedAt == this.deletedAt &&
other.ownerId == this.ownerId &&
other.type == this.type &&
other.data == this.data &&
other.isSaved == this.isSaved &&
other.memoryAt == this.memoryAt &&
other.seenAt == this.seenAt &&
other.showAt == this.showAt &&
other.hideAt == this.hideAt);
}
class MemoryEntityCompanion extends i0.UpdateCompanion<i1.MemoryEntityData> {
final i0.Value<String> id;
final i0.Value<DateTime> createdAt;
final i0.Value<DateTime> updatedAt;
final i0.Value<DateTime?> deletedAt;
final i0.Value<String> ownerId;
final i0.Value<i2.MemoryTypeEnum> type;
final i0.Value<String> data;
final i0.Value<bool> isSaved;
final i0.Value<DateTime> memoryAt;
final i0.Value<DateTime?> seenAt;
final i0.Value<DateTime?> showAt;
final i0.Value<DateTime?> hideAt;
const MemoryEntityCompanion({
this.id = const i0.Value.absent(),
this.createdAt = const i0.Value.absent(),
this.updatedAt = const i0.Value.absent(),
this.deletedAt = const i0.Value.absent(),
this.ownerId = const i0.Value.absent(),
this.type = const i0.Value.absent(),
this.data = const i0.Value.absent(),
this.isSaved = const i0.Value.absent(),
this.memoryAt = const i0.Value.absent(),
this.seenAt = const i0.Value.absent(),
this.showAt = const i0.Value.absent(),
this.hideAt = const i0.Value.absent(),
});
MemoryEntityCompanion.insert({
required String id,
this.createdAt = const i0.Value.absent(),
this.updatedAt = const i0.Value.absent(),
this.deletedAt = const i0.Value.absent(),
required String ownerId,
required i2.MemoryTypeEnum type,
required String data,
this.isSaved = const i0.Value.absent(),
required DateTime memoryAt,
this.seenAt = const i0.Value.absent(),
this.showAt = const i0.Value.absent(),
this.hideAt = const i0.Value.absent(),
}) : id = i0.Value(id),
ownerId = i0.Value(ownerId),
type = i0.Value(type),
data = i0.Value(data),
memoryAt = i0.Value(memoryAt);
static i0.Insertable<i1.MemoryEntityData> custom({
i0.Expression<String>? id,
i0.Expression<DateTime>? createdAt,
i0.Expression<DateTime>? updatedAt,
i0.Expression<DateTime>? deletedAt,
i0.Expression<String>? ownerId,
i0.Expression<int>? type,
i0.Expression<String>? data,
i0.Expression<bool>? isSaved,
i0.Expression<DateTime>? memoryAt,
i0.Expression<DateTime>? seenAt,
i0.Expression<DateTime>? showAt,
i0.Expression<DateTime>? hideAt,
}) {
return i0.RawValuesInsertable({
if (id != null) 'id': id,
if (createdAt != null) 'created_at': createdAt,
if (updatedAt != null) 'updated_at': updatedAt,
if (deletedAt != null) 'deleted_at': deletedAt,
if (ownerId != null) 'owner_id': ownerId,
if (type != null) 'type': type,
if (data != null) 'data': data,
if (isSaved != null) 'is_saved': isSaved,
if (memoryAt != null) 'memory_at': memoryAt,
if (seenAt != null) 'seen_at': seenAt,
if (showAt != null) 'show_at': showAt,
if (hideAt != null) 'hide_at': hideAt,
});
}
i1.MemoryEntityCompanion copyWith(
{i0.Value<String>? id,
i0.Value<DateTime>? createdAt,
i0.Value<DateTime>? updatedAt,
i0.Value<DateTime?>? deletedAt,
i0.Value<String>? ownerId,
i0.Value<i2.MemoryTypeEnum>? type,
i0.Value<String>? data,
i0.Value<bool>? isSaved,
i0.Value<DateTime>? memoryAt,
i0.Value<DateTime?>? seenAt,
i0.Value<DateTime?>? showAt,
i0.Value<DateTime?>? hideAt}) {
return i1.MemoryEntityCompanion(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
ownerId: ownerId ?? this.ownerId,
type: type ?? this.type,
data: data ?? this.data,
isSaved: isSaved ?? this.isSaved,
memoryAt: memoryAt ?? this.memoryAt,
seenAt: seenAt ?? this.seenAt,
showAt: showAt ?? this.showAt,
hideAt: hideAt ?? this.hideAt,
);
}
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
if (id.present) {
map['id'] = i0.Variable<String>(id.value);
}
if (createdAt.present) {
map['created_at'] = i0.Variable<DateTime>(createdAt.value);
}
if (updatedAt.present) {
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
}
if (deletedAt.present) {
map['deleted_at'] = i0.Variable<DateTime>(deletedAt.value);
}
if (ownerId.present) {
map['owner_id'] = i0.Variable<String>(ownerId.value);
}
if (type.present) {
map['type'] = i0.Variable<int>(
i1.$MemoryEntityTable.$convertertype.toSql(type.value));
}
if (data.present) {
map['data'] = i0.Variable<String>(data.value);
}
if (isSaved.present) {
map['is_saved'] = i0.Variable<bool>(isSaved.value);
}
if (memoryAt.present) {
map['memory_at'] = i0.Variable<DateTime>(memoryAt.value);
}
if (seenAt.present) {
map['seen_at'] = i0.Variable<DateTime>(seenAt.value);
}
if (showAt.present) {
map['show_at'] = i0.Variable<DateTime>(showAt.value);
}
if (hideAt.present) {
map['hide_at'] = i0.Variable<DateTime>(hideAt.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('MemoryEntityCompanion(')
..write('id: $id, ')
..write('createdAt: $createdAt, ')
..write('updatedAt: $updatedAt, ')
..write('deletedAt: $deletedAt, ')
..write('ownerId: $ownerId, ')
..write('type: $type, ')
..write('data: $data, ')
..write('isSaved: $isSaved, ')
..write('memoryAt: $memoryAt, ')
..write('seenAt: $seenAt, ')
..write('showAt: $showAt, ')
..write('hideAt: $hideAt')
..write(')'))
.toString();
}
}

View File

@ -0,0 +1,17 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class MemoryAssetEntity extends Table with DriftDefaultsMixin {
const MemoryAssetEntity();
TextColumn get assetId =>
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get memoryId =>
text().references(MemoryEntity, #id, onDelete: KeyAction.cascade)();
@override
Set<Column> get primaryKey => {assetId, memoryId};
}

View File

@ -0,0 +1,550 @@
// dart format width=80
// ignore_for_file: type=lint
import 'package:drift/drift.dart' as i0;
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
as i1;
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart'
as i2;
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
as i3;
import 'package:drift/internal/modular.dart' as i4;
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
as i5;
typedef $$MemoryAssetEntityTableCreateCompanionBuilder
= i1.MemoryAssetEntityCompanion Function({
required String assetId,
required String memoryId,
});
typedef $$MemoryAssetEntityTableUpdateCompanionBuilder
= i1.MemoryAssetEntityCompanion Function({
i0.Value<String> assetId,
i0.Value<String> memoryId,
});
final class $$MemoryAssetEntityTableReferences extends i0.BaseReferences<
i0.GeneratedDatabase,
i1.$MemoryAssetEntityTable,
i1.MemoryAssetEntityData> {
$$MemoryAssetEntityTableReferences(
super.$_db, super.$_table, super.$_typedResult);
static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
i4.ReadDatabaseContainer(db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
.createAlias(i0.$_aliasNameGenerator(
i4.ReadDatabaseContainer(db)
.resultSet<i1.$MemoryAssetEntityTable>('memory_asset_entity')
.assetId,
i4.ReadDatabaseContainer(db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
.id));
i3.$$RemoteAssetEntityTableProcessedTableManager get assetId {
final $_column = $_itemColumn<String>('asset_id')!;
final manager = i3
.$$RemoteAssetEntityTableTableManager(
$_db,
i4.ReadDatabaseContainer($_db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'))
.filter((f) => f.id.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_assetIdTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
static i5.$MemoryEntityTable _memoryIdTable(i0.GeneratedDatabase db) =>
i4.ReadDatabaseContainer(db)
.resultSet<i5.$MemoryEntityTable>('memory_entity')
.createAlias(i0.$_aliasNameGenerator(
i4.ReadDatabaseContainer(db)
.resultSet<i1.$MemoryAssetEntityTable>('memory_asset_entity')
.memoryId,
i4.ReadDatabaseContainer(db)
.resultSet<i5.$MemoryEntityTable>('memory_entity')
.id));
i5.$$MemoryEntityTableProcessedTableManager get memoryId {
final $_column = $_itemColumn<String>('memory_id')!;
final manager = i5
.$$MemoryEntityTableTableManager(
$_db,
i4.ReadDatabaseContainer($_db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'))
.filter((f) => f.id.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_memoryIdTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
}
class $$MemoryAssetEntityTableFilterComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$MemoryAssetEntityTable> {
$$MemoryAssetEntityTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i3.$$RemoteAssetEntityTableFilterComposer get assetId {
final i3.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.assetId,
referencedTable: i4.ReadDatabaseContainer($db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i3.$$RemoteAssetEntityTableFilterComposer(
$db: $db,
$table: i4.ReadDatabaseContainer($db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
i5.$$MemoryEntityTableFilterComposer get memoryId {
final i5.$$MemoryEntityTableFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.memoryId,
referencedTable: i4.ReadDatabaseContainer($db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i5.$$MemoryEntityTableFilterComposer(
$db: $db,
$table: i4.ReadDatabaseContainer($db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$MemoryAssetEntityTableOrderingComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$MemoryAssetEntityTable> {
$$MemoryAssetEntityTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i3.$$RemoteAssetEntityTableOrderingComposer get assetId {
final i3.$$RemoteAssetEntityTableOrderingComposer composer =
$composerBuilder(
composer: this,
getCurrentColumn: (t) => t.assetId,
referencedTable: i4.ReadDatabaseContainer($db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i3.$$RemoteAssetEntityTableOrderingComposer(
$db: $db,
$table: i4.ReadDatabaseContainer($db)
.resultSet<i3.$RemoteAssetEntityTable>(
'remote_asset_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
i5.$$MemoryEntityTableOrderingComposer get memoryId {
final i5.$$MemoryEntityTableOrderingComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.memoryId,
referencedTable: i4.ReadDatabaseContainer($db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i5.$$MemoryEntityTableOrderingComposer(
$db: $db,
$table: i4.ReadDatabaseContainer($db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$MemoryAssetEntityTableAnnotationComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$MemoryAssetEntityTable> {
$$MemoryAssetEntityTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i3.$$RemoteAssetEntityTableAnnotationComposer get assetId {
final i3.$$RemoteAssetEntityTableAnnotationComposer composer =
$composerBuilder(
composer: this,
getCurrentColumn: (t) => t.assetId,
referencedTable: i4.ReadDatabaseContainer($db)
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i3.$$RemoteAssetEntityTableAnnotationComposer(
$db: $db,
$table: i4.ReadDatabaseContainer($db)
.resultSet<i3.$RemoteAssetEntityTable>(
'remote_asset_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
i5.$$MemoryEntityTableAnnotationComposer get memoryId {
final i5.$$MemoryEntityTableAnnotationComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.memoryId,
referencedTable: i4.ReadDatabaseContainer($db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i5.$$MemoryEntityTableAnnotationComposer(
$db: $db,
$table: i4.ReadDatabaseContainer($db)
.resultSet<i5.$MemoryEntityTable>('memory_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$MemoryAssetEntityTableTableManager extends i0.RootTableManager<
i0.GeneratedDatabase,
i1.$MemoryAssetEntityTable,
i1.MemoryAssetEntityData,
i1.$$MemoryAssetEntityTableFilterComposer,
i1.$$MemoryAssetEntityTableOrderingComposer,
i1.$$MemoryAssetEntityTableAnnotationComposer,
$$MemoryAssetEntityTableCreateCompanionBuilder,
$$MemoryAssetEntityTableUpdateCompanionBuilder,
(i1.MemoryAssetEntityData, i1.$$MemoryAssetEntityTableReferences),
i1.MemoryAssetEntityData,
i0.PrefetchHooks Function({bool assetId, bool memoryId})> {
$$MemoryAssetEntityTableTableManager(
i0.GeneratedDatabase db, i1.$MemoryAssetEntityTable table)
: super(i0.TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
i1.$$MemoryAssetEntityTableFilterComposer($db: db, $table: table),
createOrderingComposer: () => i1
.$$MemoryAssetEntityTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () =>
i1.$$MemoryAssetEntityTableAnnotationComposer(
$db: db, $table: table),
updateCompanionCallback: ({
i0.Value<String> assetId = const i0.Value.absent(),
i0.Value<String> memoryId = const i0.Value.absent(),
}) =>
i1.MemoryAssetEntityCompanion(
assetId: assetId,
memoryId: memoryId,
),
createCompanionCallback: ({
required String assetId,
required String memoryId,
}) =>
i1.MemoryAssetEntityCompanion.insert(
assetId: assetId,
memoryId: memoryId,
),
withReferenceMapper: (p0) => p0
.map((e) => (
e.readTable(table),
i1.$$MemoryAssetEntityTableReferences(db, table, e)
))
.toList(),
prefetchHooksCallback: ({assetId = false, memoryId = false}) {
return i0.PrefetchHooks(
db: db,
explicitlyWatchedTables: [],
addJoins: <
T extends i0.TableManagerState<
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic>>(state) {
if (assetId) {
state = state.withJoin(
currentTable: table,
currentColumn: table.assetId,
referencedTable:
i1.$$MemoryAssetEntityTableReferences._assetIdTable(db),
referencedColumn: i1.$$MemoryAssetEntityTableReferences
._assetIdTable(db)
.id,
) as T;
}
if (memoryId) {
state = state.withJoin(
currentTable: table,
currentColumn: table.memoryId,
referencedTable: i1.$$MemoryAssetEntityTableReferences
._memoryIdTable(db),
referencedColumn: i1.$$MemoryAssetEntityTableReferences
._memoryIdTable(db)
.id,
) as T;
}
return state;
},
getPrefetchedDataCallback: (items) async {
return [];
},
);
},
));
}
typedef $$MemoryAssetEntityTableProcessedTableManager
= i0.ProcessedTableManager<
i0.GeneratedDatabase,
i1.$MemoryAssetEntityTable,
i1.MemoryAssetEntityData,
i1.$$MemoryAssetEntityTableFilterComposer,
i1.$$MemoryAssetEntityTableOrderingComposer,
i1.$$MemoryAssetEntityTableAnnotationComposer,
$$MemoryAssetEntityTableCreateCompanionBuilder,
$$MemoryAssetEntityTableUpdateCompanionBuilder,
(i1.MemoryAssetEntityData, i1.$$MemoryAssetEntityTableReferences),
i1.MemoryAssetEntityData,
i0.PrefetchHooks Function({bool assetId, bool memoryId})>;
class $MemoryAssetEntityTable extends i2.MemoryAssetEntity
with i0.TableInfo<$MemoryAssetEntityTable, i1.MemoryAssetEntityData> {
@override
final i0.GeneratedDatabase attachedDatabase;
final String? _alias;
$MemoryAssetEntityTable(this.attachedDatabase, [this._alias]);
static const i0.VerificationMeta _assetIdMeta =
const i0.VerificationMeta('assetId');
@override
late final i0.GeneratedColumn<String> assetId = i0.GeneratedColumn<String>(
'asset_id', aliasedName, false,
type: i0.DriftSqlType.string,
requiredDuringInsert: true,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'REFERENCES remote_asset_entity (id) ON DELETE CASCADE'));
static const i0.VerificationMeta _memoryIdMeta =
const i0.VerificationMeta('memoryId');
@override
late final i0.GeneratedColumn<String> memoryId = i0.GeneratedColumn<String>(
'memory_id', aliasedName, false,
type: i0.DriftSqlType.string,
requiredDuringInsert: true,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'REFERENCES memory_entity (id) ON DELETE CASCADE'));
@override
List<i0.GeneratedColumn> get $columns => [assetId, memoryId];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'memory_asset_entity';
@override
i0.VerificationContext validateIntegrity(
i0.Insertable<i1.MemoryAssetEntityData> instance,
{bool isInserting = false}) {
final context = i0.VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('asset_id')) {
context.handle(_assetIdMeta,
assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta));
} else if (isInserting) {
context.missing(_assetIdMeta);
}
if (data.containsKey('memory_id')) {
context.handle(_memoryIdMeta,
memoryId.isAcceptableOrUnknown(data['memory_id']!, _memoryIdMeta));
} else if (isInserting) {
context.missing(_memoryIdMeta);
}
return context;
}
@override
Set<i0.GeneratedColumn> get $primaryKey => {assetId, memoryId};
@override
i1.MemoryAssetEntityData map(Map<String, dynamic> data,
{String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return i1.MemoryAssetEntityData(
assetId: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!,
memoryId: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}memory_id'])!,
);
}
@override
$MemoryAssetEntityTable createAlias(String alias) {
return $MemoryAssetEntityTable(attachedDatabase, alias);
}
@override
bool get withoutRowId => true;
@override
bool get isStrict => true;
}
class MemoryAssetEntityData extends i0.DataClass
implements i0.Insertable<i1.MemoryAssetEntityData> {
final String assetId;
final String memoryId;
const MemoryAssetEntityData({required this.assetId, required this.memoryId});
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
map['asset_id'] = i0.Variable<String>(assetId);
map['memory_id'] = i0.Variable<String>(memoryId);
return map;
}
factory MemoryAssetEntityData.fromJson(Map<String, dynamic> json,
{i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return MemoryAssetEntityData(
assetId: serializer.fromJson<String>(json['assetId']),
memoryId: serializer.fromJson<String>(json['memoryId']),
);
}
@override
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'assetId': serializer.toJson<String>(assetId),
'memoryId': serializer.toJson<String>(memoryId),
};
}
i1.MemoryAssetEntityData copyWith({String? assetId, String? memoryId}) =>
i1.MemoryAssetEntityData(
assetId: assetId ?? this.assetId,
memoryId: memoryId ?? this.memoryId,
);
MemoryAssetEntityData copyWithCompanion(i1.MemoryAssetEntityCompanion data) {
return MemoryAssetEntityData(
assetId: data.assetId.present ? data.assetId.value : this.assetId,
memoryId: data.memoryId.present ? data.memoryId.value : this.memoryId,
);
}
@override
String toString() {
return (StringBuffer('MemoryAssetEntityData(')
..write('assetId: $assetId, ')
..write('memoryId: $memoryId')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(assetId, memoryId);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is i1.MemoryAssetEntityData &&
other.assetId == this.assetId &&
other.memoryId == this.memoryId);
}
class MemoryAssetEntityCompanion
extends i0.UpdateCompanion<i1.MemoryAssetEntityData> {
final i0.Value<String> assetId;
final i0.Value<String> memoryId;
const MemoryAssetEntityCompanion({
this.assetId = const i0.Value.absent(),
this.memoryId = const i0.Value.absent(),
});
MemoryAssetEntityCompanion.insert({
required String assetId,
required String memoryId,
}) : assetId = i0.Value(assetId),
memoryId = i0.Value(memoryId);
static i0.Insertable<i1.MemoryAssetEntityData> custom({
i0.Expression<String>? assetId,
i0.Expression<String>? memoryId,
}) {
return i0.RawValuesInsertable({
if (assetId != null) 'asset_id': assetId,
if (memoryId != null) 'memory_id': memoryId,
});
}
i1.MemoryAssetEntityCompanion copyWith(
{i0.Value<String>? assetId, i0.Value<String>? memoryId}) {
return i1.MemoryAssetEntityCompanion(
assetId: assetId ?? this.assetId,
memoryId: memoryId ?? this.memoryId,
);
}
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
if (assetId.present) {
map['asset_id'] = i0.Variable<String>(assetId.value);
}
if (memoryId.present) {
map['memory_id'] = i0.Variable<String>(memoryId.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('MemoryAssetEntityCompanion(')
..write('assetId: $assetId, ')
..write('memoryId: $memoryId')
..write(')'))
.toString();
}
}

View File

@ -7,6 +7,8 @@ import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart'; import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart';
@ -46,6 +48,8 @@ class IsarDatabaseRepository implements IDatabaseRepository {
RemoteAlbumEntity, RemoteAlbumEntity,
RemoteAlbumAssetEntity, RemoteAlbumAssetEntity,
RemoteAlbumUserEntity, RemoteAlbumUserEntity,
MemoryEntity,
MemoryAssetEntity,
], ],
include: { include: {
'package:immich_mobile/infrastructure/entities/merged_asset.drift', 'package:immich_mobile/infrastructure/entities/merged_asset.drift',

View File

@ -23,9 +23,13 @@ import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.
as i10; as i10;
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart' import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'
as i11; as i11;
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart' import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
as i12; as i12;
import 'package:drift/internal/modular.dart' as i13; import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
as i13;
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
as i14;
import 'package:drift/internal/modular.dart' as i15;
abstract class $Drift extends i0.GeneratedDatabase { abstract class $Drift extends i0.GeneratedDatabase {
$Drift(i0.QueryExecutor e) : super(e); $Drift(i0.QueryExecutor e) : super(e);
@ -51,8 +55,11 @@ abstract class $Drift extends i0.GeneratedDatabase {
i10.$RemoteAlbumAssetEntityTable(this); i10.$RemoteAlbumAssetEntityTable(this);
late final i11.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = late final i11.$RemoteAlbumUserEntityTable remoteAlbumUserEntity =
i11.$RemoteAlbumUserEntityTable(this); i11.$RemoteAlbumUserEntityTable(this);
i12.MergedAssetDrift get mergedAssetDrift => i13.ReadDatabaseContainer(this) late final i12.$MemoryEntityTable memoryEntity = i12.$MemoryEntityTable(this);
.accessor<i12.MergedAssetDrift>(i12.MergedAssetDrift.new); late final i13.$MemoryAssetEntityTable memoryAssetEntity =
i13.$MemoryAssetEntityTable(this);
i14.MergedAssetDrift get mergedAssetDrift => i15.ReadDatabaseContainer(this)
.accessor<i14.MergedAssetDrift>(i14.MergedAssetDrift.new);
@override @override
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables => Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>(); allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
@ -71,7 +78,9 @@ abstract class $Drift extends i0.GeneratedDatabase {
remoteExifEntity, remoteExifEntity,
remoteAlbumEntity, remoteAlbumEntity,
remoteAlbumAssetEntity, remoteAlbumAssetEntity,
remoteAlbumUserEntity remoteAlbumUserEntity,
memoryEntity,
memoryAssetEntity
]; ];
@override @override
i0.StreamQueryUpdateRules get streamUpdateRules => i0.StreamQueryUpdateRules get streamUpdateRules =>
@ -175,6 +184,27 @@ abstract class $Drift extends i0.GeneratedDatabase {
kind: i0.UpdateKind.delete), kind: i0.UpdateKind.delete),
], ],
), ),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('user_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('memory_entity', kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('memory_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete),
],
),
], ],
); );
@override @override
@ -208,4 +238,8 @@ class $DriftManager {
_db, _db.remoteAlbumAssetEntity); _db, _db.remoteAlbumAssetEntity);
i11.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i11 i11.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i11
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity); .$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
i12.$$MemoryEntityTableTableManager get memoryEntity =>
i12.$$MemoryEntityTableTableManager(_db, _db.memoryEntity);
i13.$$MemoryAssetEntityTableTableManager get memoryAssetEntity =>
i13.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
} }

View File

@ -0,0 +1,37 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/memory.model.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
class DriftMemoryRepository extends DriftDatabaseRepository {
final Drift _db;
const DriftMemoryRepository(this._db) : super(_db);
Future<List<Memory>> getAll(String userId) {
final query = _db.memoryEntity.select()
..where((e) => e.ownerId.equals(userId));
return query.map((memory) {
return memory.toDto();
}).get();
}
}
extension on MemoryEntityData {
Memory toDto() {
return Memory(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
ownerId: ownerId,
type: type,
data: MemoryData.fromJson(data),
isSaved: isSaved,
memoryAt: memoryAt,
seenAt: seenAt,
showAt: showAt,
hideAt: hideAt,
);
}
}

View File

@ -52,6 +52,8 @@ class SyncApiRepository {
SyncRequestType.albumAssetsV1, SyncRequestType.albumAssetsV1,
SyncRequestType.albumAssetExifsV1, SyncRequestType.albumAssetExifsV1,
SyncRequestType.albumToAssetsV1, SyncRequestType.albumToAssetsV1,
SyncRequestType.memoriesV1,
SyncRequestType.memoryToAssetsV1,
], ],
).toJson(), ).toJson(),
); );
@ -157,6 +159,10 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
SyncEntityType.albumToAssetBackfillV1: SyncAlbumToAssetV1.fromJson, SyncEntityType.albumToAssetBackfillV1: SyncAlbumToAssetV1.fromJson,
SyncEntityType.albumToAssetDeleteV1: SyncAlbumToAssetDeleteV1.fromJson, SyncEntityType.albumToAssetDeleteV1: SyncAlbumToAssetDeleteV1.fromJson,
SyncEntityType.syncAckV1: _SyncAckV1.fromJson, SyncEntityType.syncAckV1: _SyncAckV1.fromJson,
SyncEntityType.memoryV1: SyncMemoryV1.fromJson,
SyncEntityType.memoryDeleteV1: SyncMemoryDeleteV1.fromJson,
SyncEntityType.memoryToAssetV1: SyncMemoryAssetV1.fromJson,
SyncEntityType.memoryToAssetDeleteV1: SyncMemoryAssetDeleteV1.fromJson,
}; };
class _SyncAckV1 { class _SyncAckV1 {

View File

@ -1,12 +1,17 @@
import 'dart:convert';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart'; import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/memory.model.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
@ -64,8 +69,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: SyncPartnerDeleteV1', e, s); _logger.severe('Error: SyncPartnerDeleteV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -87,8 +92,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: SyncPartnerV1', e, s); _logger.severe('Error: SyncPartnerV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -98,10 +103,11 @@ class SyncStreamRepository extends DriftDatabaseRepository {
String debugLabel = 'user', String debugLabel = 'user',
}) async { }) async {
try { try {
await _db.remoteAssetEntity await _db.remoteAssetEntity.deleteWhere(
.deleteWhere((row) => row.id.isIn(data.map((e) => e.assetId))); (row) => row.id.isIn(data.map((error) => error.assetId)),
} catch (e, s) { );
_logger.severe('Error: deleteAssetsV1 - $debugLabel', e, s); } catch (error, stackTrace) {
_logger.severe('Error: deleteAssetsV1 - $debugLabel', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -136,8 +142,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: updateAssetsV1 - $debugLabel', e, s); _logger.severe('Error: updateAssetsV1 - $debugLabel', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -180,18 +186,23 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: updateAssetsExifV1 - $debugLabel', e, s); _logger.severe(
'Error: updateAssetsExifV1 - $debugLabel',
error,
stackTrace,
);
rethrow; rethrow;
} }
} }
Future<void> deleteAlbumsV1(Iterable<SyncAlbumDeleteV1> data) async { Future<void> deleteAlbumsV1(Iterable<SyncAlbumDeleteV1> data) async {
try { try {
await _db.remoteAlbumEntity await _db.remoteAlbumEntity.deleteWhere(
.deleteWhere((row) => row.id.isIn(data.map((e) => e.albumId))); (row) => row.id.isIn(data.map((e) => e.albumId)),
} catch (e, s) { );
_logger.severe('Error: deleteAlbumsV1', e, s); } catch (error, stackTrace) {
_logger.severe('Error: deleteAlbumsV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -218,8 +229,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: updateAlbumsV1', e, s); _logger.severe('Error: updateAlbumsV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -237,8 +248,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: deleteAlbumUsersV1', e, s); _logger.severe('Error: deleteAlbumUsersV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -264,8 +275,12 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: updateAlbumUsersV1 - $debugLabel', e, s); _logger.severe(
'Error: updateAlbumUsersV1 - $debugLabel',
error,
stackTrace,
);
rethrow; rethrow;
} }
} }
@ -285,8 +300,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: deleteAlbumToAssetsV1', e, s); _logger.severe('Error: deleteAlbumToAssetsV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -310,8 +325,96 @@ class SyncStreamRepository extends DriftDatabaseRepository {
); );
} }
}); });
} catch (e, s) { } catch (error, stackTrace) {
_logger.severe('Error: updateAlbumToAssetsV1 - $debugLabel', e, s); _logger.severe(
'Error: updateAlbumToAssetsV1 - $debugLabel',
error,
stackTrace,
);
rethrow;
}
}
Future<void> updateMemoriesV1(Iterable<SyncMemoryV1> data) async {
try {
await _db.batch((batch) {
for (final memory in data) {
final companion = MemoryEntityCompanion(
createdAt: Value(memory.createdAt),
deletedAt: Value(memory.deletedAt),
ownerId: Value(memory.ownerId),
type: Value(memory.type.toMemoryType()),
data: Value(jsonEncode(memory.data)),
isSaved: Value(memory.isSaved),
memoryAt: Value(memory.memoryAt),
seenAt: Value.absentIfNull(memory.seenAt),
showAt: Value.absentIfNull(memory.showAt),
hideAt: Value.absentIfNull(memory.hideAt),
);
batch.insert(
_db.memoryEntity,
companion.copyWith(id: Value(memory.id)),
onConflict: DoUpdate((_) => companion),
);
}
});
} catch (error, stackTrace) {
_logger.severe('Error: updateMemoriesV1', error, stackTrace);
rethrow;
}
}
Future<void> deleteMemoriesV1(Iterable<SyncMemoryDeleteV1> data) async {
try {
await _db.memoryEntity.deleteWhere(
(row) => row.id.isIn(data.map((e) => e.memoryId)),
);
} catch (error, stackTrace) {
_logger.severe('Error: deleteMemoriesV1', error, stackTrace);
rethrow;
}
}
Future<void> updateMemoryAssetsV1(Iterable<SyncMemoryAssetV1> data) async {
try {
await _db.batch((batch) {
for (final asset in data) {
final companion = MemoryAssetEntityCompanion(
memoryId: Value(asset.memoryId),
assetId: Value(asset.assetId),
);
batch.insert(
_db.memoryAssetEntity,
companion,
onConflict: DoNothing(),
);
}
});
} catch (error, stackTrace) {
_logger.severe('Error: updateMemoryAssetsV1', error, stackTrace);
rethrow;
}
}
Future<void> deleteMemoryAssetsV1(
Iterable<SyncMemoryAssetDeleteV1> data,
) async {
try {
await _db.batch((batch) {
for (final asset in data) {
batch.delete(
_db.memoryAssetEntity,
MemoryAssetEntityCompanion(
memoryId: Value(asset.memoryId),
assetId: Value(asset.assetId),
),
);
}
});
} catch (error, stackTrace) {
_logger.severe('Error: deleteMemoryAssetsV1', error, stackTrace);
rethrow; rethrow;
} }
} }
@ -335,6 +438,13 @@ extension on AssetOrder {
}; };
} }
extension on MemoryType {
MemoryTypeEnum toMemoryType() => switch (this) {
MemoryType.onThisDay => MemoryTypeEnum.onThisDay,
_ => throw Exception('Unknown MemoryType value: $this'),
};
}
extension on api.AlbumUserRole { extension on api.AlbumUserRole {
AlbumUserRole toAlbumUserRole() => switch (this) { AlbumUserRole toAlbumUserRole() => switch (this) {
api.AlbumUserRole.editor => AlbumUserRole.editor, api.AlbumUserRole.editor => AlbumUserRole.editor,
@ -357,7 +467,7 @@ extension on String {
Duration? toDuration() { Duration? toDuration() {
try { try {
final parts = split(':') final parts = split(':')
.map((e) => double.parse(e).toInt()) .map((error) => double.parse(error).toInt())
.toList(growable: false); .toList(growable: false);
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]); return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);

View File

@ -154,6 +154,14 @@ final _remoteStats = [
name: 'Remote Albums', name: 'Remote Albums',
load: (db) => db.managers.remoteAlbumEntity.count(), load: (db) => db.managers.remoteAlbumEntity.count(),
), ),
_Stat(
name: 'Memories',
load: (db) => db.managers.memoryEntity.count(),
),
_Stat(
name: 'Memories Assets',
load: (db) => db.managers.memoryAssetEntity.count(),
),
]; ];
@RoutePage() @RoutePage()

View File

@ -1,5 +1,7 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/infrastructure/repositories/memory.repository.dart';
import 'package:immich_mobile/models/memories/memory.model.dart'; import 'package:immich_mobile/models/memories/memory.model.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/services/memory.service.dart'; import 'package:immich_mobile/services/memory.service.dart';
final memoryFutureProvider = final memoryFutureProvider =
@ -8,3 +10,7 @@ final memoryFutureProvider =
return await service.getMemoryLane(); return await service.getMemoryLane();
}); });
final driftMemoryProvider = Provider<DriftMemoryRepository>(
(ref) => DriftMemoryRepository(ref.watch(driftProvider)),
);

View File

@ -81,6 +81,14 @@ void main() {
debugLabel: any(named: 'debugLabel'), debugLabel: any(named: 'debugLabel'),
), ),
).thenAnswer(successHandler); ).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.updateMemoriesV1(any()))
.thenAnswer(successHandler);
when(() => mockSyncStreamRepo.deleteMemoriesV1(any()))
.thenAnswer(successHandler);
when(() => mockSyncStreamRepo.updateMemoryAssetsV1(any()))
.thenAnswer(successHandler);
when(() => mockSyncStreamRepo.deleteMemoryAssetsV1(any()))
.thenAnswer(successHandler);
sut = SyncStreamService( sut = SyncStreamService(
syncApiRepository: mockSyncApiRepo, syncApiRepository: mockSyncApiRepo,
@ -227,5 +235,94 @@ void main() {
verify(() => mockSyncApiRepo.ack(["2"])).called(1); verify(() => mockSyncApiRepo.ack(["2"])).called(1);
}, },
); );
test("processes memory sync events successfully", () async {
final events = [
SyncStreamStub.memoryV1,
SyncStreamStub.memoryDeleteV1,
SyncStreamStub.memoryToAssetV1,
SyncStreamStub.memoryToAssetDeleteV1,
];
await simulateEvents(events);
verifyInOrder([
() => mockSyncStreamRepo.updateMemoriesV1(any()),
() => mockSyncApiRepo.ack(["5"]),
() => mockSyncStreamRepo.deleteMemoriesV1(any()),
() => mockSyncApiRepo.ack(["6"]),
() => mockSyncStreamRepo.updateMemoryAssetsV1(any()),
() => mockSyncApiRepo.ack(["7"]),
() => mockSyncStreamRepo.deleteMemoryAssetsV1(any()),
() => mockSyncApiRepo.ack(["8"]),
]);
verifyNever(() => mockAbortCallbackWrapper());
});
test("processes mixed memory and user events in correct order", () async {
final events = [
SyncStreamStub.memoryDeleteV1,
SyncStreamStub.userV1Admin,
SyncStreamStub.memoryToAssetV1,
SyncStreamStub.memoryV1,
];
await simulateEvents(events);
verifyInOrder([
() => mockSyncStreamRepo.deleteMemoriesV1(any()),
() => mockSyncApiRepo.ack(["6"]),
() => mockSyncStreamRepo.updateUsersV1(any()),
() => mockSyncApiRepo.ack(["1"]),
() => mockSyncStreamRepo.updateMemoryAssetsV1(any()),
() => mockSyncApiRepo.ack(["7"]),
() => mockSyncStreamRepo.updateMemoriesV1(any()),
() => mockSyncApiRepo.ack(["5"]),
]);
verifyNever(() => mockAbortCallbackWrapper());
});
test("handles memory sync failure gracefully", () async {
when(() => mockSyncStreamRepo.updateMemoriesV1(any()))
.thenThrow(Exception("Memory sync failed"));
final events = [
SyncStreamStub.memoryV1,
SyncStreamStub.userV1Admin,
];
expect(
() async => await simulateEvents(events),
throwsA(isA<Exception>()),
);
});
test("processes memory asset events with correct data types", () async {
final events = [SyncStreamStub.memoryToAssetV1];
await simulateEvents(events);
verify(() => mockSyncStreamRepo.updateMemoryAssetsV1(any())).called(1);
verify(() => mockSyncApiRepo.ack(["7"])).called(1);
});
test("processes memory delete events with correct data types", () async {
final events = [SyncStreamStub.memoryDeleteV1];
await simulateEvents(events);
verify(() => mockSyncStreamRepo.deleteMemoriesV1(any())).called(1);
verify(() => mockSyncApiRepo.ack(["6"])).called(1);
});
test("processes memory create/update events with correct data types",
() async {
final events = [SyncStreamStub.memoryV1];
await simulateEvents(events);
verify(() => mockSyncStreamRepo.updateMemoriesV1(any())).called(1);
verify(() => mockSyncApiRepo.ack(["5"])).called(1);
});
}); });
} }

View File

@ -42,4 +42,47 @@ abstract final class SyncStreamStub {
data: SyncPartnerDeleteV1(sharedById: "3", sharedWithId: "4"), data: SyncPartnerDeleteV1(sharedById: "3", sharedWithId: "4"),
ack: "4", ack: "4",
); );
static final memoryV1 = SyncEvent(
type: SyncEntityType.memoryV1,
data: SyncMemoryV1(
createdAt: DateTime(2023, 1, 1),
data: {"year": 2023, "title": "Test Memory"},
deletedAt: null,
hideAt: null,
id: "memory-1",
isSaved: false,
memoryAt: DateTime(2023, 1, 1),
ownerId: "user-1",
seenAt: null,
showAt: DateTime(2023, 1, 1),
type: MemoryType.onThisDay,
updatedAt: DateTime(2023, 1, 1),
),
ack: "5",
);
static final memoryDeleteV1 = SyncEvent(
type: SyncEntityType.memoryDeleteV1,
data: SyncMemoryDeleteV1(memoryId: "memory-2"),
ack: "6",
);
static final memoryToAssetV1 = SyncEvent(
type: SyncEntityType.memoryToAssetV1,
data: SyncMemoryAssetV1(
assetId: "asset-1",
memoryId: "memory-1",
),
ack: "7",
);
static final memoryToAssetDeleteV1 = SyncEvent(
type: SyncEntityType.memoryToAssetDeleteV1,
data: SyncMemoryAssetDeleteV1(
assetId: "asset-2",
memoryId: "memory-1",
),
ack: "8",
);
} }