mirror of
https://github.com/immich-app/immich.git
synced 2025-06-04 06:04:21 -04:00
wip: sqlite - device album sync
This commit is contained in:
parent
13ef491aa8
commit
f405a67f29
@ -55,6 +55,9 @@ custom_lint:
|
|||||||
restrict: package:photo_manager
|
restrict: package:photo_manager
|
||||||
allowed:
|
allowed:
|
||||||
# required / wanted
|
# required / wanted
|
||||||
|
- 'lib/domain/interfaces/album_media.interface.dart'
|
||||||
|
- 'lib/infrastructure/repositories/album_media.repository.dart'
|
||||||
|
- 'lib/domain/services/sync.service.dart'
|
||||||
- 'lib/repositories/{album,asset,file}_media.repository.dart'
|
- 'lib/repositories/{album,asset,file}_media.repository.dart'
|
||||||
# acceptable exceptions for the time being
|
# acceptable exceptions for the time being
|
||||||
- lib/entities/asset.entity.dart # to provide local AssetEntity for now
|
- lib/entities/asset.entity.dart # to provide local AssetEntity for now
|
||||||
|
File diff suppressed because one or more lines are too long
@ -11,3 +11,6 @@ const int kSyncEventBatchSize = 5000;
|
|||||||
// Hash batch limits
|
// Hash batch limits
|
||||||
const int kBatchHashFileLimit = 128;
|
const int kBatchHashFileLimit = 128;
|
||||||
const int kBatchHashSizeLimit = 1024 * 1024 * 1024; // 1GB
|
const int kBatchHashSizeLimit = 1024 * 1024 * 1024; // 1GB
|
||||||
|
|
||||||
|
// Sync related
|
||||||
|
const int kFetchLocalAssetsBatchSize = 40000;
|
||||||
|
10
mobile/lib/domain/interfaces/album_media.interface.dart
Normal file
10
mobile/lib/domain/interfaces/album_media.interface.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumMediaRepository {
|
||||||
|
Future<List<AssetPathEntity>> getAll({PMFilter? filter});
|
||||||
|
|
||||||
|
Future<List<LocalAsset>> getAssetsForAlbum(AssetPathEntity album);
|
||||||
|
|
||||||
|
Future<AssetPathEntity> refresh(String albumId, {PMFilter? filter});
|
||||||
|
}
|
17
mobile/lib/domain/interfaces/local_album.interface.dart
Normal file
17
mobile/lib/domain/interfaces/local_album.interface.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILocalAlbumRepository implements IDatabaseRepository {
|
||||||
|
Future<void> upsert(LocalAlbum localAlbum);
|
||||||
|
|
||||||
|
Future<List<LocalAlbum>> getAll({SortLocalAlbumsBy? sortBy});
|
||||||
|
|
||||||
|
/// Get all asset ids that are only in the album and not in other albums.
|
||||||
|
/// This is used to determine which assets are unique to the album.
|
||||||
|
/// This is useful in cases where the album is a smart album or a user-created album, especially in iOS
|
||||||
|
Future<List<String>> getAssetIdsOnlyInAlbum(String albumId);
|
||||||
|
|
||||||
|
Future<void> delete(String albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortLocalAlbumsBy { id }
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILocalAlbumAssetRepository
|
||||||
|
implements IDatabaseRepository {
|
||||||
|
Future<List<LocalAsset>> getAssetsForAlbum(String albumId);
|
||||||
|
|
||||||
|
Future<void> linkAssetsToAlbum(String albumId, Iterable<String> assetIds);
|
||||||
|
|
||||||
|
Future<void> unlinkAssetsFromAlbum(String albumId, Iterable<String> assetIds);
|
||||||
|
}
|
10
mobile/lib/domain/interfaces/local_asset.interface.dart
Normal file
10
mobile/lib/domain/interfaces/local_asset.interface.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILocalAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<LocalAsset> get(String assetId);
|
||||||
|
|
||||||
|
Future<void> upsertAll(Iterable<LocalAsset> localAssets);
|
||||||
|
|
||||||
|
Future<void> deleteIds(Iterable<String> ids);
|
||||||
|
}
|
72
mobile/lib/domain/models/asset/asset.model.dart
Normal file
72
mobile/lib/domain/models/asset/asset.model.dart
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
part 'local_asset.model.dart';
|
||||||
|
part 'merged_asset.model.dart';
|
||||||
|
part 'remote_asset.model.dart';
|
||||||
|
|
||||||
|
enum AssetType {
|
||||||
|
// do not change this order!
|
||||||
|
other,
|
||||||
|
image,
|
||||||
|
video,
|
||||||
|
audio,
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Asset {
|
||||||
|
final String name;
|
||||||
|
final String? checksum;
|
||||||
|
final AssetType type;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final int? width;
|
||||||
|
final int? height;
|
||||||
|
final int? durationInSeconds;
|
||||||
|
|
||||||
|
const Asset({
|
||||||
|
required this.name,
|
||||||
|
required this.checksum,
|
||||||
|
required this.type,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.durationInSeconds,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''Asset {
|
||||||
|
name: $name,
|
||||||
|
type: $type,
|
||||||
|
createdAt: $createdAt,
|
||||||
|
updatedAt: $updatedAt,
|
||||||
|
width: ${width ?? "<NA>"},
|
||||||
|
height: ${height ?? "<NA>"},
|
||||||
|
durationInSeconds: ${durationInSeconds ?? "<NA>"}
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
if (other is Asset) {
|
||||||
|
return name == other.name &&
|
||||||
|
type == other.type &&
|
||||||
|
createdAt == other.createdAt &&
|
||||||
|
updatedAt == other.updatedAt &&
|
||||||
|
width == other.width &&
|
||||||
|
height == other.height &&
|
||||||
|
durationInSeconds == other.durationInSeconds;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return name.hashCode ^
|
||||||
|
type.hashCode ^
|
||||||
|
createdAt.hashCode ^
|
||||||
|
updatedAt.hashCode ^
|
||||||
|
width.hashCode ^
|
||||||
|
height.hashCode ^
|
||||||
|
durationInSeconds.hashCode;
|
||||||
|
}
|
||||||
|
}
|
66
mobile/lib/domain/models/asset/local_asset.model.dart
Normal file
66
mobile/lib/domain/models/asset/local_asset.model.dart
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
part of 'asset.model.dart';
|
||||||
|
|
||||||
|
class LocalAsset extends Asset {
|
||||||
|
final String localId;
|
||||||
|
|
||||||
|
const LocalAsset({
|
||||||
|
required this.localId,
|
||||||
|
required super.name,
|
||||||
|
super.checksum,
|
||||||
|
required super.type,
|
||||||
|
required super.createdAt,
|
||||||
|
required super.updatedAt,
|
||||||
|
super.width,
|
||||||
|
super.height,
|
||||||
|
super.durationInSeconds,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''LocalAsset {
|
||||||
|
localId: $localId,
|
||||||
|
name: $name,
|
||||||
|
type: $type,
|
||||||
|
createdAt: $createdAt,
|
||||||
|
updatedAt: $updatedAt,
|
||||||
|
width: ${width ?? "<NA>"},
|
||||||
|
height: ${height ?? "<NA>"},
|
||||||
|
durationInSeconds: ${durationInSeconds ?? "<NA>"}
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant LocalAsset other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return super == other && localId == other.localId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return super.hashCode ^ localId.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalAsset copyWith({
|
||||||
|
String? localId,
|
||||||
|
String? name,
|
||||||
|
String? checksum,
|
||||||
|
AssetType? type,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
int? width,
|
||||||
|
int? height,
|
||||||
|
int? durationInSeconds,
|
||||||
|
}) {
|
||||||
|
return LocalAsset(
|
||||||
|
localId: localId ?? this.localId,
|
||||||
|
name: name ?? this.name,
|
||||||
|
checksum: checksum ?? this.checksum,
|
||||||
|
type: type ?? this.type,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
width: width ?? this.width,
|
||||||
|
height: height ?? this.height,
|
||||||
|
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
47
mobile/lib/domain/models/asset/merged_asset.model.dart
Normal file
47
mobile/lib/domain/models/asset/merged_asset.model.dart
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
part of 'asset.model.dart';
|
||||||
|
|
||||||
|
class MergedAsset extends Asset {
|
||||||
|
final String remoteId;
|
||||||
|
final String localId;
|
||||||
|
|
||||||
|
const MergedAsset({
|
||||||
|
required this.remoteId,
|
||||||
|
required this.localId,
|
||||||
|
required super.name,
|
||||||
|
required super.checksum,
|
||||||
|
required super.type,
|
||||||
|
required super.createdAt,
|
||||||
|
required super.updatedAt,
|
||||||
|
super.width,
|
||||||
|
super.height,
|
||||||
|
super.durationInSeconds,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''MergedAsset {
|
||||||
|
remoteId: $remoteId,
|
||||||
|
localId: $localId,
|
||||||
|
name: $name,
|
||||||
|
type: $type,
|
||||||
|
createdAt: $createdAt,
|
||||||
|
updatedAt: $updatedAt,
|
||||||
|
width: ${width ?? "<NA>"},
|
||||||
|
height: ${height ?? "<NA>"},
|
||||||
|
durationInSeconds: ${durationInSeconds ?? "<NA>"}
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant MergedAsset other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return super == other &&
|
||||||
|
remoteId == other.remoteId &&
|
||||||
|
localId == other.localId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return super.hashCode ^ remoteId.hashCode ^ localId.hashCode;
|
||||||
|
}
|
||||||
|
}
|
42
mobile/lib/domain/models/asset/remote_asset.model.dart
Normal file
42
mobile/lib/domain/models/asset/remote_asset.model.dart
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
part of 'asset.model.dart';
|
||||||
|
|
||||||
|
class RemoteAsset extends Asset {
|
||||||
|
final String remoteId;
|
||||||
|
|
||||||
|
const RemoteAsset({
|
||||||
|
required this.remoteId,
|
||||||
|
required super.name,
|
||||||
|
required super.checksum,
|
||||||
|
required super.type,
|
||||||
|
required super.createdAt,
|
||||||
|
required super.updatedAt,
|
||||||
|
super.width,
|
||||||
|
super.height,
|
||||||
|
super.durationInSeconds,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''RemoteAsset {
|
||||||
|
remoteId: $remoteId,
|
||||||
|
name: $name,
|
||||||
|
type: $type,
|
||||||
|
createdAt: $createdAt,
|
||||||
|
updatedAt: $updatedAt,
|
||||||
|
width: ${width ?? "<NA>"},
|
||||||
|
height: ${height ?? "<NA>"},
|
||||||
|
durationInSeconds: ${durationInSeconds ?? "<NA>"}
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant RemoteAsset other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return super == other && remoteId == other.remoteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return super.hashCode ^ remoteId.hashCode;
|
||||||
|
}
|
||||||
|
}
|
84
mobile/lib/domain/models/local_album.model.dart
Normal file
84
mobile/lib/domain/models/local_album.model.dart
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
enum BackupSelection {
|
||||||
|
none,
|
||||||
|
selected,
|
||||||
|
excluded,
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAlbum {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
|
||||||
|
/// Whether the album contains all photos (i.e, the virtual "Recent" album)
|
||||||
|
final bool isAll;
|
||||||
|
final int assetCount;
|
||||||
|
final String? thumbnailId;
|
||||||
|
final BackupSelection backupSelection;
|
||||||
|
|
||||||
|
const LocalAlbum({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.updatedAt,
|
||||||
|
this.assetCount = 0,
|
||||||
|
this.thumbnailId,
|
||||||
|
this.backupSelection = BackupSelection.none,
|
||||||
|
this.isAll = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
LocalAlbum copyWith({
|
||||||
|
String? id,
|
||||||
|
String? name,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
int? assetCount,
|
||||||
|
String? thumbnailId,
|
||||||
|
BackupSelection? backupSelection,
|
||||||
|
bool? isAll,
|
||||||
|
}) {
|
||||||
|
return LocalAlbum(
|
||||||
|
id: id ?? this.id,
|
||||||
|
name: name ?? this.name,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
assetCount: assetCount ?? this.assetCount,
|
||||||
|
thumbnailId: thumbnailId ?? this.thumbnailId,
|
||||||
|
backupSelection: backupSelection ?? this.backupSelection,
|
||||||
|
isAll: isAll ?? this.isAll,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant LocalAlbum other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other.id == id &&
|
||||||
|
other.name == name &&
|
||||||
|
other.updatedAt == updatedAt &&
|
||||||
|
other.assetCount == assetCount &&
|
||||||
|
other.isAll == isAll &&
|
||||||
|
other.thumbnailId == thumbnailId &&
|
||||||
|
other.backupSelection == backupSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return id.hashCode ^
|
||||||
|
name.hashCode ^
|
||||||
|
updatedAt.hashCode ^
|
||||||
|
assetCount.hashCode ^
|
||||||
|
isAll.hashCode ^
|
||||||
|
thumbnailId.hashCode ^
|
||||||
|
backupSelection.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '''LocalAlbum: {
|
||||||
|
id: $id,
|
||||||
|
name: $name,
|
||||||
|
updatedAt: $updatedAt,
|
||||||
|
assetCount: $assetCount,
|
||||||
|
thumbnailId: ${thumbnailId ?? '<NA>'},
|
||||||
|
backupSelection: $backupSelection,
|
||||||
|
isAll: $isAll
|
||||||
|
}''';
|
||||||
|
}
|
||||||
|
}
|
357
mobile/lib/domain/services/sync.service.dart
Normal file
357
mobile/lib/domain/services/sync.service.dart
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
import 'package:immich_mobile/utils/diff.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
|
class SyncService {
|
||||||
|
final IAlbumMediaRepository _albumMediaRepository;
|
||||||
|
final ILocalAlbumRepository _localAlbumRepository;
|
||||||
|
final ILocalAssetRepository _localAssetRepository;
|
||||||
|
final ILocalAlbumAssetRepository _localAlbumAssetRepository;
|
||||||
|
final Logger _log = Logger("SyncService");
|
||||||
|
|
||||||
|
SyncService({
|
||||||
|
required IAlbumMediaRepository albumMediaRepository,
|
||||||
|
required ILocalAlbumRepository localAlbumRepository,
|
||||||
|
required ILocalAssetRepository localAssetRepository,
|
||||||
|
required ILocalAlbumAssetRepository localAlbumAssetRepository,
|
||||||
|
}) : _albumMediaRepository = albumMediaRepository,
|
||||||
|
_localAlbumRepository = localAlbumRepository,
|
||||||
|
_localAssetRepository = localAssetRepository,
|
||||||
|
_localAlbumAssetRepository = localAlbumAssetRepository;
|
||||||
|
|
||||||
|
late final albumFilter = FilterOptionGroup(
|
||||||
|
imageOption: const FilterOption(
|
||||||
|
// needTitle is expected to be slow on iOS but is required to fetch the asset title
|
||||||
|
needTitle: true,
|
||||||
|
sizeConstraint: SizeConstraint(ignoreSize: true),
|
||||||
|
),
|
||||||
|
videoOption: const FilterOption(
|
||||||
|
needTitle: true,
|
||||||
|
sizeConstraint: SizeConstraint(ignoreSize: true),
|
||||||
|
durationConstraint: DurationConstraint(allowNullable: true),
|
||||||
|
),
|
||||||
|
// This is needed to get the modified time of the album
|
||||||
|
containsPathModified: true,
|
||||||
|
createTimeCond: DateTimeCond.def().copyWith(ignore: true),
|
||||||
|
updateTimeCond: DateTimeCond.def().copyWith(ignore: true),
|
||||||
|
orders: const [
|
||||||
|
// Always sort the result by createdDate.des to update the thumbnail
|
||||||
|
OrderOption(type: OrderOptionType.createDate, asc: false),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<bool> syncLocalAlbums() async {
|
||||||
|
try {
|
||||||
|
final Stopwatch stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
// Use an AdvancedCustomFilter to get all albums faster
|
||||||
|
final filter = AdvancedCustomFilter(
|
||||||
|
orderBy: [OrderByItem.asc(CustomColumns.base.id)],
|
||||||
|
);
|
||||||
|
final deviceAlbums = await _albumMediaRepository.getAll(filter: filter);
|
||||||
|
final dbAlbums =
|
||||||
|
await _localAlbumRepository.getAll(sortBy: SortLocalAlbumsBy.id);
|
||||||
|
|
||||||
|
final hasChange = await diffSortedLists(
|
||||||
|
dbAlbums,
|
||||||
|
await Future.wait(
|
||||||
|
deviceAlbums.map((a) => a.toDto(withAssetCount: false)),
|
||||||
|
),
|
||||||
|
compare: (a, b) => a.id.compareTo(b.id),
|
||||||
|
both: diffLocalAlbums,
|
||||||
|
onlyFirst: removeLocalAlbum,
|
||||||
|
onlySecond: addLocalAlbum,
|
||||||
|
);
|
||||||
|
|
||||||
|
stopwatch.stop();
|
||||||
|
_log.info("Full device sync took - ${stopwatch.elapsedMilliseconds}ms");
|
||||||
|
return hasChange;
|
||||||
|
} catch (e, s) {
|
||||||
|
_log.severe("Error performing full device sync", e, s);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addLocalAlbum(LocalAlbum newAlbum) async {
|
||||||
|
try {
|
||||||
|
_log.info("Adding device album ${newAlbum.name}");
|
||||||
|
final deviceAlbum =
|
||||||
|
await _albumMediaRepository.refresh(newAlbum.id, filter: albumFilter);
|
||||||
|
|
||||||
|
final assets = newAlbum.assetCount > 0
|
||||||
|
? (await _albumMediaRepository.getAssetsForAlbum(deviceAlbum))
|
||||||
|
: <LocalAsset>[];
|
||||||
|
final album = (await deviceAlbum.toDto()).copyWith(
|
||||||
|
// The below assumes the list is already sorted by createdDate from the filter
|
||||||
|
thumbnailId: assets.firstOrNull?.localId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await _localAlbumRepository.transaction(() async {
|
||||||
|
if (newAlbum.assetCount > 0) {
|
||||||
|
await _localAssetRepository.upsertAll(assets);
|
||||||
|
}
|
||||||
|
// Needs to be after asset upsert to link the thumbnail
|
||||||
|
await _localAlbumRepository.upsert(album);
|
||||||
|
|
||||||
|
if (newAlbum.assetCount > 0) {
|
||||||
|
await _localAlbumAssetRepository.linkAssetsToAlbum(
|
||||||
|
album.id,
|
||||||
|
assets.map((a) => a.localId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e, s) {
|
||||||
|
_log.warning("Error while adding device album", e, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeLocalAlbum(LocalAlbum album) async {
|
||||||
|
_log.info("Removing device album ${album.name}");
|
||||||
|
try {
|
||||||
|
// Remove all assets that are only in this particular album
|
||||||
|
// We cannot remove all assets in the album because they might be in other albums in iOS
|
||||||
|
final assetsToDelete =
|
||||||
|
await _localAlbumRepository.getAssetIdsOnlyInAlbum(album.id);
|
||||||
|
await _localAlbumRepository.transaction(() async {
|
||||||
|
if (assetsToDelete.isNotEmpty) {
|
||||||
|
await _localAssetRepository.deleteIds(assetsToDelete);
|
||||||
|
}
|
||||||
|
await _localAlbumRepository.delete(album.id);
|
||||||
|
});
|
||||||
|
} catch (e, s) {
|
||||||
|
_log.warning("Error while removing device album", e, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
// The deviceAlbum is ignored since we are going to refresh it anyways
|
||||||
|
FutureOr<bool> diffLocalAlbums(LocalAlbum dbAlbum, LocalAlbum _) async {
|
||||||
|
try {
|
||||||
|
_log.info("Syncing device album ${dbAlbum.name}");
|
||||||
|
|
||||||
|
final albumEntity =
|
||||||
|
await _albumMediaRepository.refresh(dbAlbum.id, filter: albumFilter);
|
||||||
|
final deviceAlbum = await albumEntity.toDto();
|
||||||
|
|
||||||
|
// Early return if album hasn't changed
|
||||||
|
if (deviceAlbum.updatedAt.isAtSameMomentAs(dbAlbum.updatedAt) &&
|
||||||
|
deviceAlbum.assetCount == dbAlbum.assetCount) {
|
||||||
|
_log.info(
|
||||||
|
"Device album ${dbAlbum.name} has not changed. Skipping sync.",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip empty albums that don't need syncing
|
||||||
|
if (deviceAlbum.assetCount == 0 && dbAlbum.assetCount == 0) {
|
||||||
|
await _localAlbumRepository.upsert(
|
||||||
|
deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection),
|
||||||
|
);
|
||||||
|
_log.info("Album ${dbAlbum.name} is empty. Only metadata updated.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.info("Device album ${dbAlbum.name} has changed. Syncing...");
|
||||||
|
|
||||||
|
// Handle the case where assets are only added - fast path
|
||||||
|
if (await handleOnlyAssetsAdded(dbAlbum, deviceAlbum)) {
|
||||||
|
_log.info("Fast synced device album ${dbAlbum.name}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slower path - full sync
|
||||||
|
return await handleAssetUpdate(dbAlbum, deviceAlbum, albumEntity);
|
||||||
|
} catch (e, s) {
|
||||||
|
_log.warning("Error while diff device album", e, s);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
Future<bool> handleOnlyAssetsAdded(
|
||||||
|
LocalAlbum dbAlbum,
|
||||||
|
LocalAlbum deviceAlbum,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
_log.info("Fast syncing device album ${dbAlbum.name}");
|
||||||
|
if (!deviceAlbum.updatedAt.isAfter(dbAlbum.updatedAt)) {
|
||||||
|
_log.info(
|
||||||
|
"Local album ${deviceAlbum.name} has modifications. Proceeding to full sync",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assets has been modified
|
||||||
|
if (deviceAlbum.assetCount <= dbAlbum.assetCount) {
|
||||||
|
_log.info("Local album has modifications. Proceeding to full sync");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all assets that are modified after the last known modifiedTime
|
||||||
|
final filter = albumFilter.copyWith(
|
||||||
|
updateTimeCond: DateTimeCond(
|
||||||
|
min: dbAlbum.updatedAt.add(const Duration(seconds: 1)),
|
||||||
|
max: deviceAlbum.updatedAt,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final modifiedAlbum =
|
||||||
|
await _albumMediaRepository.refresh(deviceAlbum.id, filter: filter);
|
||||||
|
final newAssets =
|
||||||
|
await _albumMediaRepository.getAssetsForAlbum(modifiedAlbum);
|
||||||
|
|
||||||
|
// Early return if no new assets were found
|
||||||
|
if (newAssets.isEmpty) {
|
||||||
|
_log.info(
|
||||||
|
"No new assets found despite album changes. Proceeding to full sync for ${dbAlbum.name}",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether there is only addition or if there has been deletions
|
||||||
|
if (deviceAlbum.assetCount != dbAlbum.assetCount + newAssets.length) {
|
||||||
|
_log.info("Local album has modifications. Proceeding to full sync");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? thumbnailId = dbAlbum.thumbnailId;
|
||||||
|
if (thumbnailId == null || newAssets.isNotEmpty) {
|
||||||
|
if (thumbnailId == null) {
|
||||||
|
thumbnailId = newAssets.firstOrNull?.localId;
|
||||||
|
} else if (newAssets.isNotEmpty) {
|
||||||
|
// The below assumes the list is already sorted by createdDate from the filter
|
||||||
|
final oldThumbAsset = await _localAssetRepository.get(thumbnailId);
|
||||||
|
if (oldThumbAsset.createdAt
|
||||||
|
.isBefore(newAssets.firstOrNull!.createdAt)) {
|
||||||
|
thumbnailId = newAssets.firstOrNull?.localId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _localAlbumRepository.transaction(() async {
|
||||||
|
await _localAssetRepository.upsertAll(newAssets);
|
||||||
|
await _localAlbumAssetRepository.linkAssetsToAlbum(
|
||||||
|
deviceAlbum.id,
|
||||||
|
newAssets.map(((a) => a.localId)),
|
||||||
|
);
|
||||||
|
await _localAlbumRepository.upsert(
|
||||||
|
deviceAlbum.copyWith(
|
||||||
|
thumbnailId: thumbnailId,
|
||||||
|
backupSelection: dbAlbum.backupSelection,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e, s) {
|
||||||
|
_log.warning("Error on fast syncing local album: ${dbAlbum.name}", e, s);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
Future<bool> handleAssetUpdate(
|
||||||
|
LocalAlbum dbAlbum,
|
||||||
|
LocalAlbum deviceAlbum,
|
||||||
|
AssetPathEntity deviceAlbumEntity,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
final assetsInDevice = deviceAlbum.assetCount > 0
|
||||||
|
? await _albumMediaRepository.getAssetsForAlbum(deviceAlbumEntity)
|
||||||
|
: <LocalAsset>[];
|
||||||
|
|
||||||
|
final assetsInDb = dbAlbum.assetCount > 0
|
||||||
|
? await _localAlbumAssetRepository.getAssetsForAlbum(dbAlbum.id)
|
||||||
|
: <LocalAsset>[];
|
||||||
|
|
||||||
|
// The below assumes the list is already sorted by createdDate from the filter
|
||||||
|
String? thumbnailId =
|
||||||
|
assetsInDevice.firstOrNull?.localId ?? dbAlbum.thumbnailId;
|
||||||
|
|
||||||
|
final assetsToAdd = <LocalAsset>{},
|
||||||
|
assetsToUpsert = <LocalAsset>{},
|
||||||
|
assetsToDelete = <String>{};
|
||||||
|
if (deviceAlbum.assetCount == 0) {
|
||||||
|
assetsToDelete.addAll(assetsInDb.map((asset) => asset.localId));
|
||||||
|
thumbnailId = null;
|
||||||
|
} else if (dbAlbum.assetCount == 0) {
|
||||||
|
assetsToAdd.addAll(assetsInDevice);
|
||||||
|
} else {
|
||||||
|
assetsInDb.sort((a, b) => a.localId.compareTo(b.localId));
|
||||||
|
assetsInDevice.sort((a, b) => a.localId.compareTo(b.localId));
|
||||||
|
diffSortedListsSync(
|
||||||
|
assetsInDb,
|
||||||
|
assetsInDevice,
|
||||||
|
compare: (a, b) => a.localId.compareTo(b.localId),
|
||||||
|
both: (dbAsset, deviceAsset) {
|
||||||
|
if (dbAsset == deviceAsset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assetsToUpsert.add(deviceAsset);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
onlyFirst: (dbAsset) => assetsToDelete.add(dbAsset.localId),
|
||||||
|
onlySecond: (deviceAsset) => assetsToAdd.add(deviceAsset),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_log.info(
|
||||||
|
"Syncing ${deviceAlbum.name}. ${assetsToAdd.length} assets to add, ${assetsToUpsert.length} assets to update and ${assetsToDelete.length} assets to delete",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Populate the album meta
|
||||||
|
final updatedAlbum = deviceAlbum.copyWith(
|
||||||
|
thumbnailId: thumbnailId,
|
||||||
|
backupSelection: dbAlbum.backupSelection,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Only query for assets unique to album if we have assets to delete
|
||||||
|
final assetsOnlyInAlbum = assetsToDelete.isEmpty
|
||||||
|
? <String>{}
|
||||||
|
: (await _localAlbumRepository.getAssetIdsOnlyInAlbum(deviceAlbum.id))
|
||||||
|
.toSet();
|
||||||
|
|
||||||
|
await _localAlbumRepository.transaction(() async {
|
||||||
|
await _localAssetRepository
|
||||||
|
.upsertAll(assetsToAdd.followedBy(assetsToUpsert));
|
||||||
|
await _localAlbumAssetRepository.linkAssetsToAlbum(
|
||||||
|
dbAlbum.id,
|
||||||
|
assetsToAdd.map((a) => a.localId),
|
||||||
|
);
|
||||||
|
await _localAlbumRepository.upsert(updatedAlbum);
|
||||||
|
// Remove all assets that are only in this particular album
|
||||||
|
// We cannot remove all assets in the album because they might be in other albums in iOS
|
||||||
|
await _localAssetRepository.deleteIds(
|
||||||
|
assetsToDelete.intersection(assetsOnlyInAlbum),
|
||||||
|
);
|
||||||
|
// Unlink the others
|
||||||
|
await _localAlbumAssetRepository.unlinkAssetsFromAlbum(
|
||||||
|
dbAlbum.id,
|
||||||
|
assetsToDelete.difference(assetsOnlyInAlbum),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (e, s) {
|
||||||
|
_log.warning("Error on full syncing local album: ${dbAlbum.name}", e, s);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AssetPathEntitySyncX on AssetPathEntity {
|
||||||
|
Future<LocalAlbum> toDto({bool withAssetCount = true}) async => LocalAlbum(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
updatedAt: lastModified ?? DateTime.now(),
|
||||||
|
// the assetCountAsync call is expensive for larger albums with several thousand assets
|
||||||
|
assetCount: withAssetCount ? await assetCountAsync : 0,
|
||||||
|
backupSelection: BackupSelection.none,
|
||||||
|
isAll: isAll,
|
||||||
|
);
|
||||||
|
}
|
35
mobile/lib/infrastructure/entities/local_album.entity.dart
Normal file
35
mobile/lib/infrastructure/entities/local_album.entity.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
||||||
|
class LocalAlbumEntity extends Table with DriftDefaultsMixin {
|
||||||
|
const LocalAlbumEntity();
|
||||||
|
|
||||||
|
TextColumn get id => text()();
|
||||||
|
TextColumn get name => text()();
|
||||||
|
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
IntColumn get assetCount => integer().withDefault(const Constant(0))();
|
||||||
|
TextColumn get thumbnailId => text()
|
||||||
|
.nullable()
|
||||||
|
.references(LocalAssetEntity, #localId, onDelete: KeyAction.setNull)();
|
||||||
|
IntColumn get backupSelection => intEnum<BackupSelection>()();
|
||||||
|
BoolColumn get isAll => boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {id};
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LocalAlbumEntityX on LocalAlbumEntityData {
|
||||||
|
LocalAlbum toDto() {
|
||||||
|
return LocalAlbum(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
thumbnailId: thumbnailId,
|
||||||
|
backupSelection: backupSelection,
|
||||||
|
isAll: isAll,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
732
mobile/lib/infrastructure/entities/local_album.entity.drift.dart
generated
Normal file
732
mobile/lib/infrastructure/entities/local_album.entity.drift.dart
generated
Normal file
@ -0,0 +1,732 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
|
||||||
|
as i1;
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart' as i2;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart'
|
||||||
|
as i3;
|
||||||
|
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
|
||||||
|
as i5;
|
||||||
|
import 'package:drift/internal/modular.dart' as i6;
|
||||||
|
|
||||||
|
typedef $$LocalAlbumEntityTableCreateCompanionBuilder
|
||||||
|
= i1.LocalAlbumEntityCompanion Function({
|
||||||
|
required String id,
|
||||||
|
required String name,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
i0.Value<int> assetCount,
|
||||||
|
i0.Value<String?> thumbnailId,
|
||||||
|
required i2.BackupSelection backupSelection,
|
||||||
|
i0.Value<bool> isAll,
|
||||||
|
});
|
||||||
|
typedef $$LocalAlbumEntityTableUpdateCompanionBuilder
|
||||||
|
= i1.LocalAlbumEntityCompanion Function({
|
||||||
|
i0.Value<String> id,
|
||||||
|
i0.Value<String> name,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
i0.Value<int> assetCount,
|
||||||
|
i0.Value<String?> thumbnailId,
|
||||||
|
i0.Value<i2.BackupSelection> backupSelection,
|
||||||
|
i0.Value<bool> isAll,
|
||||||
|
});
|
||||||
|
|
||||||
|
final class $$LocalAlbumEntityTableReferences extends i0.BaseReferences<
|
||||||
|
i0.GeneratedDatabase, i1.$LocalAlbumEntityTable, i1.LocalAlbumEntityData> {
|
||||||
|
$$LocalAlbumEntityTableReferences(
|
||||||
|
super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
|
static i5.$LocalAssetEntityTable _thumbnailIdTable(i0.GeneratedDatabase db) =>
|
||||||
|
i6.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity')
|
||||||
|
.createAlias(i0.$_aliasNameGenerator(
|
||||||
|
i6.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i1.$LocalAlbumEntityTable>('local_album_entity')
|
||||||
|
.thumbnailId,
|
||||||
|
i6.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity')
|
||||||
|
.localId));
|
||||||
|
|
||||||
|
i5.$$LocalAssetEntityTableProcessedTableManager? get thumbnailId {
|
||||||
|
final $_column = $_itemColumn<String>('thumbnail_id');
|
||||||
|
if ($_column == null) return null;
|
||||||
|
final manager = i5
|
||||||
|
.$$LocalAssetEntityTableTableManager(
|
||||||
|
$_db,
|
||||||
|
i6.ReadDatabaseContainer($_db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity'))
|
||||||
|
.filter((f) => f.localId.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_thumbnailIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return i0.ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumEntityTableFilterComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAlbumEntityTable> {
|
||||||
|
$$LocalAlbumEntityTableFilterComposer({
|
||||||
|
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<String> get name => $composableBuilder(
|
||||||
|
column: $table.name, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
|
||||||
|
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<int> get assetCount => $composableBuilder(
|
||||||
|
column: $table.assetCount, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnWithTypeConverterFilters<i2.BackupSelection, i2.BackupSelection, int>
|
||||||
|
get backupSelection => $composableBuilder(
|
||||||
|
column: $table.backupSelection,
|
||||||
|
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<bool> get isAll => $composableBuilder(
|
||||||
|
column: $table.isAll, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i5.$$LocalAssetEntityTableFilterComposer get thumbnailId {
|
||||||
|
final i5.$$LocalAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.thumbnailId,
|
||||||
|
referencedTable: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.localId,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$LocalAssetEntityTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumEntityTableOrderingComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAlbumEntityTable> {
|
||||||
|
$$LocalAlbumEntityTableOrderingComposer({
|
||||||
|
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<String> get name => $composableBuilder(
|
||||||
|
column: $table.name, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder(
|
||||||
|
column: $table.updatedAt,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<int> get assetCount => $composableBuilder(
|
||||||
|
column: $table.assetCount,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<int> get backupSelection => $composableBuilder(
|
||||||
|
column: $table.backupSelection,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<bool> get isAll => $composableBuilder(
|
||||||
|
column: $table.isAll, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i5.$$LocalAssetEntityTableOrderingComposer get thumbnailId {
|
||||||
|
final i5.$$LocalAssetEntityTableOrderingComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.thumbnailId,
|
||||||
|
referencedTable: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.localId,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$LocalAssetEntityTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>(
|
||||||
|
'local_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumEntityTableAnnotationComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAlbumEntityTable> {
|
||||||
|
$$LocalAlbumEntityTableAnnotationComposer({
|
||||||
|
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<String> get name =>
|
||||||
|
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<DateTime> get updatedAt =>
|
||||||
|
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<int> get assetCount => $composableBuilder(
|
||||||
|
column: $table.assetCount, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumnWithTypeConverter<i2.BackupSelection, int>
|
||||||
|
get backupSelection => $composableBuilder(
|
||||||
|
column: $table.backupSelection, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<bool> get isAll =>
|
||||||
|
$composableBuilder(column: $table.isAll, builder: (column) => column);
|
||||||
|
|
||||||
|
i5.$$LocalAssetEntityTableAnnotationComposer get thumbnailId {
|
||||||
|
final i5.$$LocalAssetEntityTableAnnotationComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.thumbnailId,
|
||||||
|
referencedTable: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.localId,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$LocalAssetEntityTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAssetEntityTable>(
|
||||||
|
'local_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumEntityTableTableManager extends i0.RootTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAlbumEntityTable,
|
||||||
|
i1.LocalAlbumEntityData,
|
||||||
|
i1.$$LocalAlbumEntityTableFilterComposer,
|
||||||
|
i1.$$LocalAlbumEntityTableOrderingComposer,
|
||||||
|
i1.$$LocalAlbumEntityTableAnnotationComposer,
|
||||||
|
$$LocalAlbumEntityTableCreateCompanionBuilder,
|
||||||
|
$$LocalAlbumEntityTableUpdateCompanionBuilder,
|
||||||
|
(i1.LocalAlbumEntityData, i1.$$LocalAlbumEntityTableReferences),
|
||||||
|
i1.LocalAlbumEntityData,
|
||||||
|
i0.PrefetchHooks Function({bool thumbnailId})> {
|
||||||
|
$$LocalAlbumEntityTableTableManager(
|
||||||
|
i0.GeneratedDatabase db, i1.$LocalAlbumEntityTable table)
|
||||||
|
: super(i0.TableManagerState(
|
||||||
|
db: db,
|
||||||
|
table: table,
|
||||||
|
createFilteringComposer: () =>
|
||||||
|
i1.$$LocalAlbumEntityTableFilterComposer($db: db, $table: table),
|
||||||
|
createOrderingComposer: () => i1
|
||||||
|
.$$LocalAlbumEntityTableOrderingComposer($db: db, $table: table),
|
||||||
|
createComputedFieldComposer: () =>
|
||||||
|
i1.$$LocalAlbumEntityTableAnnotationComposer(
|
||||||
|
$db: db, $table: table),
|
||||||
|
updateCompanionCallback: ({
|
||||||
|
i0.Value<String> id = const i0.Value.absent(),
|
||||||
|
i0.Value<String> name = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
i0.Value<int> assetCount = const i0.Value.absent(),
|
||||||
|
i0.Value<String?> thumbnailId = const i0.Value.absent(),
|
||||||
|
i0.Value<i2.BackupSelection> backupSelection =
|
||||||
|
const i0.Value.absent(),
|
||||||
|
i0.Value<bool> isAll = const i0.Value.absent(),
|
||||||
|
}) =>
|
||||||
|
i1.LocalAlbumEntityCompanion(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
assetCount: assetCount,
|
||||||
|
thumbnailId: thumbnailId,
|
||||||
|
backupSelection: backupSelection,
|
||||||
|
isAll: isAll,
|
||||||
|
),
|
||||||
|
createCompanionCallback: ({
|
||||||
|
required String id,
|
||||||
|
required String name,
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
i0.Value<int> assetCount = const i0.Value.absent(),
|
||||||
|
i0.Value<String?> thumbnailId = const i0.Value.absent(),
|
||||||
|
required i2.BackupSelection backupSelection,
|
||||||
|
i0.Value<bool> isAll = const i0.Value.absent(),
|
||||||
|
}) =>
|
||||||
|
i1.LocalAlbumEntityCompanion.insert(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
assetCount: assetCount,
|
||||||
|
thumbnailId: thumbnailId,
|
||||||
|
backupSelection: backupSelection,
|
||||||
|
isAll: isAll,
|
||||||
|
),
|
||||||
|
withReferenceMapper: (p0) => p0
|
||||||
|
.map((e) => (
|
||||||
|
e.readTable(table),
|
||||||
|
i1.$$LocalAlbumEntityTableReferences(db, table, e)
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
prefetchHooksCallback: ({thumbnailId = 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 (thumbnailId) {
|
||||||
|
state = state.withJoin(
|
||||||
|
currentTable: table,
|
||||||
|
currentColumn: table.thumbnailId,
|
||||||
|
referencedTable: i1.$$LocalAlbumEntityTableReferences
|
||||||
|
._thumbnailIdTable(db),
|
||||||
|
referencedColumn: i1.$$LocalAlbumEntityTableReferences
|
||||||
|
._thumbnailIdTable(db)
|
||||||
|
.localId,
|
||||||
|
) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
getPrefetchedDataCallback: (items) async {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef $$LocalAlbumEntityTableProcessedTableManager = i0.ProcessedTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAlbumEntityTable,
|
||||||
|
i1.LocalAlbumEntityData,
|
||||||
|
i1.$$LocalAlbumEntityTableFilterComposer,
|
||||||
|
i1.$$LocalAlbumEntityTableOrderingComposer,
|
||||||
|
i1.$$LocalAlbumEntityTableAnnotationComposer,
|
||||||
|
$$LocalAlbumEntityTableCreateCompanionBuilder,
|
||||||
|
$$LocalAlbumEntityTableUpdateCompanionBuilder,
|
||||||
|
(i1.LocalAlbumEntityData, i1.$$LocalAlbumEntityTableReferences),
|
||||||
|
i1.LocalAlbumEntityData,
|
||||||
|
i0.PrefetchHooks Function({bool thumbnailId})>;
|
||||||
|
|
||||||
|
class $LocalAlbumEntityTable extends i3.LocalAlbumEntity
|
||||||
|
with i0.TableInfo<$LocalAlbumEntityTable, i1.LocalAlbumEntityData> {
|
||||||
|
@override
|
||||||
|
final i0.GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$LocalAlbumEntityTable(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 _nameMeta =
|
||||||
|
const i0.VerificationMeta('name');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>(
|
||||||
|
'name', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
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 _assetCountMeta =
|
||||||
|
const i0.VerificationMeta('assetCount');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<int> assetCount = i0.GeneratedColumn<int>(
|
||||||
|
'asset_count', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.int,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: const i4.Constant(0));
|
||||||
|
static const i0.VerificationMeta _thumbnailIdMeta =
|
||||||
|
const i0.VerificationMeta('thumbnailId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> thumbnailId =
|
||||||
|
i0.GeneratedColumn<String>('thumbnail_id', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||||
|
'REFERENCES local_asset_entity (local_id) ON DELETE SET NULL'));
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumnWithTypeConverter<i2.BackupSelection, int>
|
||||||
|
backupSelection = i0.GeneratedColumn<int>(
|
||||||
|
'backup_selection', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.int, requiredDuringInsert: true)
|
||||||
|
.withConverter<i2.BackupSelection>(
|
||||||
|
i1.$LocalAlbumEntityTable.$converterbackupSelection);
|
||||||
|
static const i0.VerificationMeta _isAllMeta =
|
||||||
|
const i0.VerificationMeta('isAll');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<bool> isAll = i0.GeneratedColumn<bool>(
|
||||||
|
'is_all', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.bool,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints:
|
||||||
|
i0.GeneratedColumn.constraintIsAlways('CHECK ("is_all" IN (0, 1))'),
|
||||||
|
defaultValue: const i4.Constant(false));
|
||||||
|
@override
|
||||||
|
List<i0.GeneratedColumn> get $columns =>
|
||||||
|
[id, name, updatedAt, assetCount, thumbnailId, backupSelection, isAll];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
|
@override
|
||||||
|
String get actualTableName => $name;
|
||||||
|
static const String $name = 'local_album_entity';
|
||||||
|
@override
|
||||||
|
i0.VerificationContext validateIntegrity(
|
||||||
|
i0.Insertable<i1.LocalAlbumEntityData> 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('name')) {
|
||||||
|
context.handle(
|
||||||
|
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_nameMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('updated_at')) {
|
||||||
|
context.handle(_updatedAtMeta,
|
||||||
|
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('asset_count')) {
|
||||||
|
context.handle(
|
||||||
|
_assetCountMeta,
|
||||||
|
assetCount.isAcceptableOrUnknown(
|
||||||
|
data['asset_count']!, _assetCountMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('thumbnail_id')) {
|
||||||
|
context.handle(
|
||||||
|
_thumbnailIdMeta,
|
||||||
|
thumbnailId.isAcceptableOrUnknown(
|
||||||
|
data['thumbnail_id']!, _thumbnailIdMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('is_all')) {
|
||||||
|
context.handle(
|
||||||
|
_isAllMeta, isAll.isAcceptableOrUnknown(data['is_all']!, _isAllMeta));
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||||
|
@override
|
||||||
|
i1.LocalAlbumEntityData map(Map<String, dynamic> data,
|
||||||
|
{String? tablePrefix}) {
|
||||||
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
|
return i1.LocalAlbumEntityData(
|
||||||
|
id: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||||
|
name: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
|
||||||
|
updatedAt: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
|
||||||
|
assetCount: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.int, data['${effectivePrefix}asset_count'])!,
|
||||||
|
thumbnailId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}thumbnail_id']),
|
||||||
|
backupSelection: i1.$LocalAlbumEntityTable.$converterbackupSelection
|
||||||
|
.fromSql(attachedDatabase.typeMapping.read(i0.DriftSqlType.int,
|
||||||
|
data['${effectivePrefix}backup_selection'])!),
|
||||||
|
isAll: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.bool, data['${effectivePrefix}is_all'])!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$LocalAlbumEntityTable createAlias(String alias) {
|
||||||
|
return $LocalAlbumEntityTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
static i0.JsonTypeConverter2<i2.BackupSelection, int, int>
|
||||||
|
$converterbackupSelection =
|
||||||
|
const i0.EnumIndexConverter<i2.BackupSelection>(
|
||||||
|
i2.BackupSelection.values);
|
||||||
|
@override
|
||||||
|
bool get withoutRowId => true;
|
||||||
|
@override
|
||||||
|
bool get isStrict => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAlbumEntityData extends i0.DataClass
|
||||||
|
implements i0.Insertable<i1.LocalAlbumEntityData> {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final int assetCount;
|
||||||
|
final String? thumbnailId;
|
||||||
|
final i2.BackupSelection backupSelection;
|
||||||
|
final bool isAll;
|
||||||
|
const LocalAlbumEntityData(
|
||||||
|
{required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.assetCount,
|
||||||
|
this.thumbnailId,
|
||||||
|
required this.backupSelection,
|
||||||
|
required this.isAll});
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
map['id'] = i0.Variable<String>(id);
|
||||||
|
map['name'] = i0.Variable<String>(name);
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||||
|
map['asset_count'] = i0.Variable<int>(assetCount);
|
||||||
|
if (!nullToAbsent || thumbnailId != null) {
|
||||||
|
map['thumbnail_id'] = i0.Variable<String>(thumbnailId);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map['backup_selection'] = i0.Variable<int>(i1
|
||||||
|
.$LocalAlbumEntityTable.$converterbackupSelection
|
||||||
|
.toSql(backupSelection));
|
||||||
|
}
|
||||||
|
map['is_all'] = i0.Variable<bool>(isAll);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory LocalAlbumEntityData.fromJson(Map<String, dynamic> json,
|
||||||
|
{i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return LocalAlbumEntityData(
|
||||||
|
id: serializer.fromJson<String>(json['id']),
|
||||||
|
name: serializer.fromJson<String>(json['name']),
|
||||||
|
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||||
|
assetCount: serializer.fromJson<int>(json['assetCount']),
|
||||||
|
thumbnailId: serializer.fromJson<String?>(json['thumbnailId']),
|
||||||
|
backupSelection: i1.$LocalAlbumEntityTable.$converterbackupSelection
|
||||||
|
.fromJson(serializer.fromJson<int>(json['backupSelection'])),
|
||||||
|
isAll: serializer.fromJson<bool>(json['isAll']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'id': serializer.toJson<String>(id),
|
||||||
|
'name': serializer.toJson<String>(name),
|
||||||
|
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||||
|
'assetCount': serializer.toJson<int>(assetCount),
|
||||||
|
'thumbnailId': serializer.toJson<String?>(thumbnailId),
|
||||||
|
'backupSelection': serializer.toJson<int>(i1
|
||||||
|
.$LocalAlbumEntityTable.$converterbackupSelection
|
||||||
|
.toJson(backupSelection)),
|
||||||
|
'isAll': serializer.toJson<bool>(isAll),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.LocalAlbumEntityData copyWith(
|
||||||
|
{String? id,
|
||||||
|
String? name,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
int? assetCount,
|
||||||
|
i0.Value<String?> thumbnailId = const i0.Value.absent(),
|
||||||
|
i2.BackupSelection? backupSelection,
|
||||||
|
bool? isAll}) =>
|
||||||
|
i1.LocalAlbumEntityData(
|
||||||
|
id: id ?? this.id,
|
||||||
|
name: name ?? this.name,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
assetCount: assetCount ?? this.assetCount,
|
||||||
|
thumbnailId: thumbnailId.present ? thumbnailId.value : this.thumbnailId,
|
||||||
|
backupSelection: backupSelection ?? this.backupSelection,
|
||||||
|
isAll: isAll ?? this.isAll,
|
||||||
|
);
|
||||||
|
LocalAlbumEntityData copyWithCompanion(i1.LocalAlbumEntityCompanion data) {
|
||||||
|
return LocalAlbumEntityData(
|
||||||
|
id: data.id.present ? data.id.value : this.id,
|
||||||
|
name: data.name.present ? data.name.value : this.name,
|
||||||
|
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
|
||||||
|
assetCount:
|
||||||
|
data.assetCount.present ? data.assetCount.value : this.assetCount,
|
||||||
|
thumbnailId:
|
||||||
|
data.thumbnailId.present ? data.thumbnailId.value : this.thumbnailId,
|
||||||
|
backupSelection: data.backupSelection.present
|
||||||
|
? data.backupSelection.value
|
||||||
|
: this.backupSelection,
|
||||||
|
isAll: data.isAll.present ? data.isAll.value : this.isAll,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('LocalAlbumEntityData(')
|
||||||
|
..write('id: $id, ')
|
||||||
|
..write('name: $name, ')
|
||||||
|
..write('updatedAt: $updatedAt, ')
|
||||||
|
..write('assetCount: $assetCount, ')
|
||||||
|
..write('thumbnailId: $thumbnailId, ')
|
||||||
|
..write('backupSelection: $backupSelection, ')
|
||||||
|
..write('isAll: $isAll')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
id, name, updatedAt, assetCount, thumbnailId, backupSelection, isAll);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is i1.LocalAlbumEntityData &&
|
||||||
|
other.id == this.id &&
|
||||||
|
other.name == this.name &&
|
||||||
|
other.updatedAt == this.updatedAt &&
|
||||||
|
other.assetCount == this.assetCount &&
|
||||||
|
other.thumbnailId == this.thumbnailId &&
|
||||||
|
other.backupSelection == this.backupSelection &&
|
||||||
|
other.isAll == this.isAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAlbumEntityCompanion
|
||||||
|
extends i0.UpdateCompanion<i1.LocalAlbumEntityData> {
|
||||||
|
final i0.Value<String> id;
|
||||||
|
final i0.Value<String> name;
|
||||||
|
final i0.Value<DateTime> updatedAt;
|
||||||
|
final i0.Value<int> assetCount;
|
||||||
|
final i0.Value<String?> thumbnailId;
|
||||||
|
final i0.Value<i2.BackupSelection> backupSelection;
|
||||||
|
final i0.Value<bool> isAll;
|
||||||
|
const LocalAlbumEntityCompanion({
|
||||||
|
this.id = const i0.Value.absent(),
|
||||||
|
this.name = const i0.Value.absent(),
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
this.assetCount = const i0.Value.absent(),
|
||||||
|
this.thumbnailId = const i0.Value.absent(),
|
||||||
|
this.backupSelection = const i0.Value.absent(),
|
||||||
|
this.isAll = const i0.Value.absent(),
|
||||||
|
});
|
||||||
|
LocalAlbumEntityCompanion.insert({
|
||||||
|
required String id,
|
||||||
|
required String name,
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
this.assetCount = const i0.Value.absent(),
|
||||||
|
this.thumbnailId = const i0.Value.absent(),
|
||||||
|
required i2.BackupSelection backupSelection,
|
||||||
|
this.isAll = const i0.Value.absent(),
|
||||||
|
}) : id = i0.Value(id),
|
||||||
|
name = i0.Value(name),
|
||||||
|
backupSelection = i0.Value(backupSelection);
|
||||||
|
static i0.Insertable<i1.LocalAlbumEntityData> custom({
|
||||||
|
i0.Expression<String>? id,
|
||||||
|
i0.Expression<String>? name,
|
||||||
|
i0.Expression<DateTime>? updatedAt,
|
||||||
|
i0.Expression<int>? assetCount,
|
||||||
|
i0.Expression<String>? thumbnailId,
|
||||||
|
i0.Expression<int>? backupSelection,
|
||||||
|
i0.Expression<bool>? isAll,
|
||||||
|
}) {
|
||||||
|
return i0.RawValuesInsertable({
|
||||||
|
if (id != null) 'id': id,
|
||||||
|
if (name != null) 'name': name,
|
||||||
|
if (updatedAt != null) 'updated_at': updatedAt,
|
||||||
|
if (assetCount != null) 'asset_count': assetCount,
|
||||||
|
if (thumbnailId != null) 'thumbnail_id': thumbnailId,
|
||||||
|
if (backupSelection != null) 'backup_selection': backupSelection,
|
||||||
|
if (isAll != null) 'is_all': isAll,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.LocalAlbumEntityCompanion copyWith(
|
||||||
|
{i0.Value<String>? id,
|
||||||
|
i0.Value<String>? name,
|
||||||
|
i0.Value<DateTime>? updatedAt,
|
||||||
|
i0.Value<int>? assetCount,
|
||||||
|
i0.Value<String?>? thumbnailId,
|
||||||
|
i0.Value<i2.BackupSelection>? backupSelection,
|
||||||
|
i0.Value<bool>? isAll}) {
|
||||||
|
return i1.LocalAlbumEntityCompanion(
|
||||||
|
id: id ?? this.id,
|
||||||
|
name: name ?? this.name,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
assetCount: assetCount ?? this.assetCount,
|
||||||
|
thumbnailId: thumbnailId ?? this.thumbnailId,
|
||||||
|
backupSelection: backupSelection ?? this.backupSelection,
|
||||||
|
isAll: isAll ?? this.isAll,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
if (id.present) {
|
||||||
|
map['id'] = i0.Variable<String>(id.value);
|
||||||
|
}
|
||||||
|
if (name.present) {
|
||||||
|
map['name'] = i0.Variable<String>(name.value);
|
||||||
|
}
|
||||||
|
if (updatedAt.present) {
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||||
|
}
|
||||||
|
if (assetCount.present) {
|
||||||
|
map['asset_count'] = i0.Variable<int>(assetCount.value);
|
||||||
|
}
|
||||||
|
if (thumbnailId.present) {
|
||||||
|
map['thumbnail_id'] = i0.Variable<String>(thumbnailId.value);
|
||||||
|
}
|
||||||
|
if (backupSelection.present) {
|
||||||
|
map['backup_selection'] = i0.Variable<int>(i1
|
||||||
|
.$LocalAlbumEntityTable.$converterbackupSelection
|
||||||
|
.toSql(backupSelection.value));
|
||||||
|
}
|
||||||
|
if (isAll.present) {
|
||||||
|
map['is_all'] = i0.Variable<bool>(isAll.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('LocalAlbumEntityCompanion(')
|
||||||
|
..write('id: $id, ')
|
||||||
|
..write('name: $name, ')
|
||||||
|
..write('updatedAt: $updatedAt, ')
|
||||||
|
..write('assetCount: $assetCount, ')
|
||||||
|
..write('thumbnailId: $thumbnailId, ')
|
||||||
|
..write('backupSelection: $backupSelection, ')
|
||||||
|
..write('isAll: $isAll')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
||||||
|
class LocalAlbumAssetEntity extends Table with DriftDefaultsMixin {
|
||||||
|
const LocalAlbumAssetEntity();
|
||||||
|
|
||||||
|
TextColumn get assetId => text()
|
||||||
|
.references(LocalAssetEntity, #localId, onDelete: KeyAction.cascade)();
|
||||||
|
|
||||||
|
TextColumn get albumId =>
|
||||||
|
text().references(LocalAlbumEntity, #id, onDelete: KeyAction.cascade)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {assetId, albumId};
|
||||||
|
}
|
565
mobile/lib/infrastructure/entities/local_album_asset.entity.drift.dart
generated
Normal file
565
mobile/lib/infrastructure/entities/local_album_asset.entity.drift.dart
generated
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
|
||||||
|
as i1;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart'
|
||||||
|
as i2;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
|
||||||
|
as i3;
|
||||||
|
import 'package:drift/internal/modular.dart' as i4;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
|
||||||
|
as i5;
|
||||||
|
|
||||||
|
typedef $$LocalAlbumAssetEntityTableCreateCompanionBuilder
|
||||||
|
= i1.LocalAlbumAssetEntityCompanion Function({
|
||||||
|
required String assetId,
|
||||||
|
required String albumId,
|
||||||
|
});
|
||||||
|
typedef $$LocalAlbumAssetEntityTableUpdateCompanionBuilder
|
||||||
|
= i1.LocalAlbumAssetEntityCompanion Function({
|
||||||
|
i0.Value<String> assetId,
|
||||||
|
i0.Value<String> albumId,
|
||||||
|
});
|
||||||
|
|
||||||
|
final class $$LocalAlbumAssetEntityTableReferences extends i0.BaseReferences<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAlbumAssetEntityTable,
|
||||||
|
i1.LocalAlbumAssetEntityData> {
|
||||||
|
$$LocalAlbumAssetEntityTableReferences(
|
||||||
|
super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
|
static i3.$LocalAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||||
|
i4.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity')
|
||||||
|
.createAlias(i0.$_aliasNameGenerator(
|
||||||
|
i4.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i1.$LocalAlbumAssetEntityTable>(
|
||||||
|
'local_album_asset_entity')
|
||||||
|
.assetId,
|
||||||
|
i4.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity')
|
||||||
|
.localId));
|
||||||
|
|
||||||
|
i3.$$LocalAssetEntityTableProcessedTableManager get assetId {
|
||||||
|
final $_column = $_itemColumn<String>('asset_id')!;
|
||||||
|
|
||||||
|
final manager = i3
|
||||||
|
.$$LocalAssetEntityTableTableManager(
|
||||||
|
$_db,
|
||||||
|
i4.ReadDatabaseContainer($_db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity'))
|
||||||
|
.filter((f) => f.localId.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_assetIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return i0.ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static i5.$LocalAlbumEntityTable _albumIdTable(i0.GeneratedDatabase db) =>
|
||||||
|
i4.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity')
|
||||||
|
.createAlias(i0.$_aliasNameGenerator(
|
||||||
|
i4.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i1.$LocalAlbumAssetEntityTable>(
|
||||||
|
'local_album_asset_entity')
|
||||||
|
.albumId,
|
||||||
|
i4.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity')
|
||||||
|
.id));
|
||||||
|
|
||||||
|
i5.$$LocalAlbumEntityTableProcessedTableManager get albumId {
|
||||||
|
final $_column = $_itemColumn<String>('album_id')!;
|
||||||
|
|
||||||
|
final manager = i5
|
||||||
|
.$$LocalAlbumEntityTableTableManager(
|
||||||
|
$_db,
|
||||||
|
i4.ReadDatabaseContainer($_db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity'))
|
||||||
|
.filter((f) => f.id.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_albumIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return i0.ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumAssetEntityTableFilterComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAlbumAssetEntityTable> {
|
||||||
|
$$LocalAlbumAssetEntityTableFilterComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i3.$$LocalAssetEntityTableFilterComposer get assetId {
|
||||||
|
final i3.$$LocalAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.assetId,
|
||||||
|
referencedTable: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.localId,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i3.$$LocalAssetEntityTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i5.$$LocalAlbumEntityTableFilterComposer get albumId {
|
||||||
|
final i5.$$LocalAlbumEntityTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.albumId,
|
||||||
|
referencedTable: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$LocalAlbumEntityTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumAssetEntityTableOrderingComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAlbumAssetEntityTable> {
|
||||||
|
$$LocalAlbumAssetEntityTableOrderingComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i3.$$LocalAssetEntityTableOrderingComposer get assetId {
|
||||||
|
final i3.$$LocalAssetEntityTableOrderingComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.assetId,
|
||||||
|
referencedTable: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.localId,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i3.$$LocalAssetEntityTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>(
|
||||||
|
'local_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i5.$$LocalAlbumEntityTableOrderingComposer get albumId {
|
||||||
|
final i5.$$LocalAlbumEntityTableOrderingComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.albumId,
|
||||||
|
referencedTable: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$LocalAlbumEntityTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>(
|
||||||
|
'local_album_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumAssetEntityTableAnnotationComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAlbumAssetEntityTable> {
|
||||||
|
$$LocalAlbumAssetEntityTableAnnotationComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i3.$$LocalAssetEntityTableAnnotationComposer get assetId {
|
||||||
|
final i3.$$LocalAssetEntityTableAnnotationComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.assetId,
|
||||||
|
referencedTable: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.localId,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i3.$$LocalAssetEntityTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i3.$LocalAssetEntityTable>(
|
||||||
|
'local_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i5.$$LocalAlbumEntityTableAnnotationComposer get albumId {
|
||||||
|
final i5.$$LocalAlbumEntityTableAnnotationComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.albumId,
|
||||||
|
referencedTable: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$LocalAlbumEntityTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i4.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$LocalAlbumEntityTable>(
|
||||||
|
'local_album_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAlbumAssetEntityTableTableManager extends i0.RootTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAlbumAssetEntityTable,
|
||||||
|
i1.LocalAlbumAssetEntityData,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableFilterComposer,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableOrderingComposer,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableAnnotationComposer,
|
||||||
|
$$LocalAlbumAssetEntityTableCreateCompanionBuilder,
|
||||||
|
$$LocalAlbumAssetEntityTableUpdateCompanionBuilder,
|
||||||
|
(i1.LocalAlbumAssetEntityData, i1.$$LocalAlbumAssetEntityTableReferences),
|
||||||
|
i1.LocalAlbumAssetEntityData,
|
||||||
|
i0.PrefetchHooks Function({bool assetId, bool albumId})> {
|
||||||
|
$$LocalAlbumAssetEntityTableTableManager(
|
||||||
|
i0.GeneratedDatabase db, i1.$LocalAlbumAssetEntityTable table)
|
||||||
|
: super(i0.TableManagerState(
|
||||||
|
db: db,
|
||||||
|
table: table,
|
||||||
|
createFilteringComposer: () =>
|
||||||
|
i1.$$LocalAlbumAssetEntityTableFilterComposer(
|
||||||
|
$db: db, $table: table),
|
||||||
|
createOrderingComposer: () =>
|
||||||
|
i1.$$LocalAlbumAssetEntityTableOrderingComposer(
|
||||||
|
$db: db, $table: table),
|
||||||
|
createComputedFieldComposer: () =>
|
||||||
|
i1.$$LocalAlbumAssetEntityTableAnnotationComposer(
|
||||||
|
$db: db, $table: table),
|
||||||
|
updateCompanionCallback: ({
|
||||||
|
i0.Value<String> assetId = const i0.Value.absent(),
|
||||||
|
i0.Value<String> albumId = const i0.Value.absent(),
|
||||||
|
}) =>
|
||||||
|
i1.LocalAlbumAssetEntityCompanion(
|
||||||
|
assetId: assetId,
|
||||||
|
albumId: albumId,
|
||||||
|
),
|
||||||
|
createCompanionCallback: ({
|
||||||
|
required String assetId,
|
||||||
|
required String albumId,
|
||||||
|
}) =>
|
||||||
|
i1.LocalAlbumAssetEntityCompanion.insert(
|
||||||
|
assetId: assetId,
|
||||||
|
albumId: albumId,
|
||||||
|
),
|
||||||
|
withReferenceMapper: (p0) => p0
|
||||||
|
.map((e) => (
|
||||||
|
e.readTable(table),
|
||||||
|
i1.$$LocalAlbumAssetEntityTableReferences(db, table, e)
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
prefetchHooksCallback: ({assetId = false, albumId = 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.$$LocalAlbumAssetEntityTableReferences
|
||||||
|
._assetIdTable(db),
|
||||||
|
referencedColumn: i1.$$LocalAlbumAssetEntityTableReferences
|
||||||
|
._assetIdTable(db)
|
||||||
|
.localId,
|
||||||
|
) as T;
|
||||||
|
}
|
||||||
|
if (albumId) {
|
||||||
|
state = state.withJoin(
|
||||||
|
currentTable: table,
|
||||||
|
currentColumn: table.albumId,
|
||||||
|
referencedTable: i1.$$LocalAlbumAssetEntityTableReferences
|
||||||
|
._albumIdTable(db),
|
||||||
|
referencedColumn: i1.$$LocalAlbumAssetEntityTableReferences
|
||||||
|
._albumIdTable(db)
|
||||||
|
.id,
|
||||||
|
) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
getPrefetchedDataCallback: (items) async {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef $$LocalAlbumAssetEntityTableProcessedTableManager
|
||||||
|
= i0.ProcessedTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAlbumAssetEntityTable,
|
||||||
|
i1.LocalAlbumAssetEntityData,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableFilterComposer,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableOrderingComposer,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableAnnotationComposer,
|
||||||
|
$$LocalAlbumAssetEntityTableCreateCompanionBuilder,
|
||||||
|
$$LocalAlbumAssetEntityTableUpdateCompanionBuilder,
|
||||||
|
(
|
||||||
|
i1.LocalAlbumAssetEntityData,
|
||||||
|
i1.$$LocalAlbumAssetEntityTableReferences
|
||||||
|
),
|
||||||
|
i1.LocalAlbumAssetEntityData,
|
||||||
|
i0.PrefetchHooks Function({bool assetId, bool albumId})>;
|
||||||
|
|
||||||
|
class $LocalAlbumAssetEntityTable extends i2.LocalAlbumAssetEntity
|
||||||
|
with
|
||||||
|
i0
|
||||||
|
.TableInfo<$LocalAlbumAssetEntityTable, i1.LocalAlbumAssetEntityData> {
|
||||||
|
@override
|
||||||
|
final i0.GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$LocalAlbumAssetEntityTable(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 local_asset_entity (local_id) ON DELETE CASCADE'));
|
||||||
|
static const i0.VerificationMeta _albumIdMeta =
|
||||||
|
const i0.VerificationMeta('albumId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> albumId = i0.GeneratedColumn<String>(
|
||||||
|
'album_id', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: true,
|
||||||
|
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||||
|
'REFERENCES local_album_entity (id) ON DELETE CASCADE'));
|
||||||
|
@override
|
||||||
|
List<i0.GeneratedColumn> get $columns => [assetId, albumId];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
|
@override
|
||||||
|
String get actualTableName => $name;
|
||||||
|
static const String $name = 'local_album_asset_entity';
|
||||||
|
@override
|
||||||
|
i0.VerificationContext validateIntegrity(
|
||||||
|
i0.Insertable<i1.LocalAlbumAssetEntityData> 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('album_id')) {
|
||||||
|
context.handle(_albumIdMeta,
|
||||||
|
albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_albumIdMeta);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<i0.GeneratedColumn> get $primaryKey => {assetId, albumId};
|
||||||
|
@override
|
||||||
|
i1.LocalAlbumAssetEntityData map(Map<String, dynamic> data,
|
||||||
|
{String? tablePrefix}) {
|
||||||
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
|
return i1.LocalAlbumAssetEntityData(
|
||||||
|
assetId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!,
|
||||||
|
albumId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}album_id'])!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$LocalAlbumAssetEntityTable createAlias(String alias) {
|
||||||
|
return $LocalAlbumAssetEntityTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get withoutRowId => true;
|
||||||
|
@override
|
||||||
|
bool get isStrict => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAlbumAssetEntityData extends i0.DataClass
|
||||||
|
implements i0.Insertable<i1.LocalAlbumAssetEntityData> {
|
||||||
|
final String assetId;
|
||||||
|
final String albumId;
|
||||||
|
const LocalAlbumAssetEntityData(
|
||||||
|
{required this.assetId, required this.albumId});
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
map['asset_id'] = i0.Variable<String>(assetId);
|
||||||
|
map['album_id'] = i0.Variable<String>(albumId);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory LocalAlbumAssetEntityData.fromJson(Map<String, dynamic> json,
|
||||||
|
{i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return LocalAlbumAssetEntityData(
|
||||||
|
assetId: serializer.fromJson<String>(json['assetId']),
|
||||||
|
albumId: serializer.fromJson<String>(json['albumId']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'assetId': serializer.toJson<String>(assetId),
|
||||||
|
'albumId': serializer.toJson<String>(albumId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.LocalAlbumAssetEntityData copyWith({String? assetId, String? albumId}) =>
|
||||||
|
i1.LocalAlbumAssetEntityData(
|
||||||
|
assetId: assetId ?? this.assetId,
|
||||||
|
albumId: albumId ?? this.albumId,
|
||||||
|
);
|
||||||
|
LocalAlbumAssetEntityData copyWithCompanion(
|
||||||
|
i1.LocalAlbumAssetEntityCompanion data) {
|
||||||
|
return LocalAlbumAssetEntityData(
|
||||||
|
assetId: data.assetId.present ? data.assetId.value : this.assetId,
|
||||||
|
albumId: data.albumId.present ? data.albumId.value : this.albumId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('LocalAlbumAssetEntityData(')
|
||||||
|
..write('assetId: $assetId, ')
|
||||||
|
..write('albumId: $albumId')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(assetId, albumId);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is i1.LocalAlbumAssetEntityData &&
|
||||||
|
other.assetId == this.assetId &&
|
||||||
|
other.albumId == this.albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAlbumAssetEntityCompanion
|
||||||
|
extends i0.UpdateCompanion<i1.LocalAlbumAssetEntityData> {
|
||||||
|
final i0.Value<String> assetId;
|
||||||
|
final i0.Value<String> albumId;
|
||||||
|
const LocalAlbumAssetEntityCompanion({
|
||||||
|
this.assetId = const i0.Value.absent(),
|
||||||
|
this.albumId = const i0.Value.absent(),
|
||||||
|
});
|
||||||
|
LocalAlbumAssetEntityCompanion.insert({
|
||||||
|
required String assetId,
|
||||||
|
required String albumId,
|
||||||
|
}) : assetId = i0.Value(assetId),
|
||||||
|
albumId = i0.Value(albumId);
|
||||||
|
static i0.Insertable<i1.LocalAlbumAssetEntityData> custom({
|
||||||
|
i0.Expression<String>? assetId,
|
||||||
|
i0.Expression<String>? albumId,
|
||||||
|
}) {
|
||||||
|
return i0.RawValuesInsertable({
|
||||||
|
if (assetId != null) 'asset_id': assetId,
|
||||||
|
if (albumId != null) 'album_id': albumId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.LocalAlbumAssetEntityCompanion copyWith(
|
||||||
|
{i0.Value<String>? assetId, i0.Value<String>? albumId}) {
|
||||||
|
return i1.LocalAlbumAssetEntityCompanion(
|
||||||
|
assetId: assetId ?? this.assetId,
|
||||||
|
albumId: albumId ?? this.albumId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 (albumId.present) {
|
||||||
|
map['album_id'] = i0.Variable<String>(albumId.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('LocalAlbumAssetEntityCompanion(')
|
||||||
|
..write('assetId: $assetId, ')
|
||||||
|
..write('albumId: $albumId')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
33
mobile/lib/infrastructure/entities/local_asset.entity.dart
Normal file
33
mobile/lib/infrastructure/entities/local_asset.entity.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
||||||
|
@TableIndex(name: 'local_asset_checksum', columns: {#checksum})
|
||||||
|
class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
|
||||||
|
const LocalAssetEntity();
|
||||||
|
|
||||||
|
TextColumn get localId => text()();
|
||||||
|
|
||||||
|
TextColumn get checksum => text().nullable()();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {localId};
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LocalAssetEntityX on LocalAssetEntityData {
|
||||||
|
LocalAsset toDto() {
|
||||||
|
return LocalAsset(
|
||||||
|
localId: localId,
|
||||||
|
name: name,
|
||||||
|
checksum: checksum,
|
||||||
|
type: type,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
durationInSeconds: durationInSeconds,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
705
mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
generated
Normal file
705
mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
generated
Normal file
@ -0,0 +1,705 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
|
||||||
|
as i1;
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart' as i2;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'
|
||||||
|
as i3;
|
||||||
|
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
|
||||||
|
|
||||||
|
typedef $$LocalAssetEntityTableCreateCompanionBuilder
|
||||||
|
= i1.LocalAssetEntityCompanion Function({
|
||||||
|
required String name,
|
||||||
|
required i2.AssetType type,
|
||||||
|
i0.Value<DateTime> createdAt,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
i0.Value<int?> width,
|
||||||
|
i0.Value<int?> height,
|
||||||
|
i0.Value<int?> durationInSeconds,
|
||||||
|
required String localId,
|
||||||
|
i0.Value<String?> checksum,
|
||||||
|
});
|
||||||
|
typedef $$LocalAssetEntityTableUpdateCompanionBuilder
|
||||||
|
= i1.LocalAssetEntityCompanion Function({
|
||||||
|
i0.Value<String> name,
|
||||||
|
i0.Value<i2.AssetType> type,
|
||||||
|
i0.Value<DateTime> createdAt,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
i0.Value<int?> width,
|
||||||
|
i0.Value<int?> height,
|
||||||
|
i0.Value<int?> durationInSeconds,
|
||||||
|
i0.Value<String> localId,
|
||||||
|
i0.Value<String?> checksum,
|
||||||
|
});
|
||||||
|
|
||||||
|
class $$LocalAssetEntityTableFilterComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAssetEntityTable> {
|
||||||
|
$$LocalAssetEntityTableFilterComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.ColumnFilters<String> get name => $composableBuilder(
|
||||||
|
column: $table.name, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnWithTypeConverterFilters<i2.AssetType, i2.AssetType, int> get type =>
|
||||||
|
$composableBuilder(
|
||||||
|
column: $table.type,
|
||||||
|
builder: (column) => i0.ColumnWithTypeConverterFilters(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<int> get width => $composableBuilder(
|
||||||
|
column: $table.width, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<int> get height => $composableBuilder(
|
||||||
|
column: $table.height, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<int> get durationInSeconds => $composableBuilder(
|
||||||
|
column: $table.durationInSeconds,
|
||||||
|
builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<String> get localId => $composableBuilder(
|
||||||
|
column: $table.localId, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<String> get checksum => $composableBuilder(
|
||||||
|
column: $table.checksum, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAssetEntityTableOrderingComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAssetEntityTable> {
|
||||||
|
$$LocalAssetEntityTableOrderingComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.ColumnOrderings<String> get name => $composableBuilder(
|
||||||
|
column: $table.name, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<int> get type => $composableBuilder(
|
||||||
|
column: $table.type, 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<int> get width => $composableBuilder(
|
||||||
|
column: $table.width, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<int> get height => $composableBuilder(
|
||||||
|
column: $table.height, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<int> get durationInSeconds => $composableBuilder(
|
||||||
|
column: $table.durationInSeconds,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<String> get localId => $composableBuilder(
|
||||||
|
column: $table.localId, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<String> get checksum => $composableBuilder(
|
||||||
|
column: $table.checksum, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAssetEntityTableAnnotationComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAssetEntityTable> {
|
||||||
|
$$LocalAssetEntityTableAnnotationComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.GeneratedColumn<String> get name =>
|
||||||
|
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumnWithTypeConverter<i2.AssetType, int> get type =>
|
||||||
|
$composableBuilder(column: $table.type, 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<int> get width =>
|
||||||
|
$composableBuilder(column: $table.width, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<int> get height =>
|
||||||
|
$composableBuilder(column: $table.height, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<int> get durationInSeconds => $composableBuilder(
|
||||||
|
column: $table.durationInSeconds, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<String> get localId =>
|
||||||
|
$composableBuilder(column: $table.localId, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<String> get checksum =>
|
||||||
|
$composableBuilder(column: $table.checksum, builder: (column) => column);
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAssetEntityTable,
|
||||||
|
i1.LocalAssetEntityData,
|
||||||
|
i1.$$LocalAssetEntityTableFilterComposer,
|
||||||
|
i1.$$LocalAssetEntityTableOrderingComposer,
|
||||||
|
i1.$$LocalAssetEntityTableAnnotationComposer,
|
||||||
|
$$LocalAssetEntityTableCreateCompanionBuilder,
|
||||||
|
$$LocalAssetEntityTableUpdateCompanionBuilder,
|
||||||
|
(
|
||||||
|
i1.LocalAssetEntityData,
|
||||||
|
i0.BaseReferences<i0.GeneratedDatabase, i1.$LocalAssetEntityTable,
|
||||||
|
i1.LocalAssetEntityData>
|
||||||
|
),
|
||||||
|
i1.LocalAssetEntityData,
|
||||||
|
i0.PrefetchHooks Function()> {
|
||||||
|
$$LocalAssetEntityTableTableManager(
|
||||||
|
i0.GeneratedDatabase db, i1.$LocalAssetEntityTable table)
|
||||||
|
: super(i0.TableManagerState(
|
||||||
|
db: db,
|
||||||
|
table: table,
|
||||||
|
createFilteringComposer: () =>
|
||||||
|
i1.$$LocalAssetEntityTableFilterComposer($db: db, $table: table),
|
||||||
|
createOrderingComposer: () => i1
|
||||||
|
.$$LocalAssetEntityTableOrderingComposer($db: db, $table: table),
|
||||||
|
createComputedFieldComposer: () =>
|
||||||
|
i1.$$LocalAssetEntityTableAnnotationComposer(
|
||||||
|
$db: db, $table: table),
|
||||||
|
updateCompanionCallback: ({
|
||||||
|
i0.Value<String> name = const i0.Value.absent(),
|
||||||
|
i0.Value<i2.AssetType> type = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> width = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
|
i0.Value<String> localId = const i0.Value.absent(),
|
||||||
|
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||||
|
}) =>
|
||||||
|
i1.LocalAssetEntityCompanion(
|
||||||
|
name: name,
|
||||||
|
type: type,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
durationInSeconds: durationInSeconds,
|
||||||
|
localId: localId,
|
||||||
|
checksum: checksum,
|
||||||
|
),
|
||||||
|
createCompanionCallback: ({
|
||||||
|
required String name,
|
||||||
|
required i2.AssetType type,
|
||||||
|
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> width = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
|
required String localId,
|
||||||
|
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||||
|
}) =>
|
||||||
|
i1.LocalAssetEntityCompanion.insert(
|
||||||
|
name: name,
|
||||||
|
type: type,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
durationInSeconds: durationInSeconds,
|
||||||
|
localId: localId,
|
||||||
|
checksum: checksum,
|
||||||
|
),
|
||||||
|
withReferenceMapper: (p0) => p0
|
||||||
|
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
|
||||||
|
.toList(),
|
||||||
|
prefetchHooksCallback: null,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef $$LocalAssetEntityTableProcessedTableManager = i0.ProcessedTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$LocalAssetEntityTable,
|
||||||
|
i1.LocalAssetEntityData,
|
||||||
|
i1.$$LocalAssetEntityTableFilterComposer,
|
||||||
|
i1.$$LocalAssetEntityTableOrderingComposer,
|
||||||
|
i1.$$LocalAssetEntityTableAnnotationComposer,
|
||||||
|
$$LocalAssetEntityTableCreateCompanionBuilder,
|
||||||
|
$$LocalAssetEntityTableUpdateCompanionBuilder,
|
||||||
|
(
|
||||||
|
i1.LocalAssetEntityData,
|
||||||
|
i0.BaseReferences<i0.GeneratedDatabase, i1.$LocalAssetEntityTable,
|
||||||
|
i1.LocalAssetEntityData>
|
||||||
|
),
|
||||||
|
i1.LocalAssetEntityData,
|
||||||
|
i0.PrefetchHooks Function()>;
|
||||||
|
i0.Index get localAssetChecksum => i0.Index('local_asset_checksum',
|
||||||
|
'CREATE INDEX local_asset_checksum ON local_asset_entity (checksum)');
|
||||||
|
|
||||||
|
class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
||||||
|
with i0.TableInfo<$LocalAssetEntityTable, i1.LocalAssetEntityData> {
|
||||||
|
@override
|
||||||
|
final i0.GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$LocalAssetEntityTable(this.attachedDatabase, [this._alias]);
|
||||||
|
static const i0.VerificationMeta _nameMeta =
|
||||||
|
const i0.VerificationMeta('name');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>(
|
||||||
|
'name', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumnWithTypeConverter<i2.AssetType, int> type =
|
||||||
|
i0.GeneratedColumn<int>('type', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.int, requiredDuringInsert: true)
|
||||||
|
.withConverter<i2.AssetType>(
|
||||||
|
i1.$LocalAssetEntityTable.$convertertype);
|
||||||
|
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 _widthMeta =
|
||||||
|
const i0.VerificationMeta('width');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<int> width = i0.GeneratedColumn<int>(
|
||||||
|
'width', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||||
|
static const i0.VerificationMeta _heightMeta =
|
||||||
|
const i0.VerificationMeta('height');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<int> height = i0.GeneratedColumn<int>(
|
||||||
|
'height', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||||
|
static const i0.VerificationMeta _durationInSecondsMeta =
|
||||||
|
const i0.VerificationMeta('durationInSeconds');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<int> durationInSeconds =
|
||||||
|
i0.GeneratedColumn<int>('duration_in_seconds', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||||
|
static const i0.VerificationMeta _localIdMeta =
|
||||||
|
const i0.VerificationMeta('localId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> localId = i0.GeneratedColumn<String>(
|
||||||
|
'local_id', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
static const i0.VerificationMeta _checksumMeta =
|
||||||
|
const i0.VerificationMeta('checksum');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> checksum = i0.GeneratedColumn<String>(
|
||||||
|
'checksum', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.string, requiredDuringInsert: false);
|
||||||
|
@override
|
||||||
|
List<i0.GeneratedColumn> get $columns => [
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
durationInSeconds,
|
||||||
|
localId,
|
||||||
|
checksum
|
||||||
|
];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
|
@override
|
||||||
|
String get actualTableName => $name;
|
||||||
|
static const String $name = 'local_asset_entity';
|
||||||
|
@override
|
||||||
|
i0.VerificationContext validateIntegrity(
|
||||||
|
i0.Insertable<i1.LocalAssetEntityData> instance,
|
||||||
|
{bool isInserting = false}) {
|
||||||
|
final context = i0.VerificationContext();
|
||||||
|
final data = instance.toColumns(true);
|
||||||
|
if (data.containsKey('name')) {
|
||||||
|
context.handle(
|
||||||
|
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_nameMeta);
|
||||||
|
}
|
||||||
|
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('width')) {
|
||||||
|
context.handle(
|
||||||
|
_widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('height')) {
|
||||||
|
context.handle(_heightMeta,
|
||||||
|
height.isAcceptableOrUnknown(data['height']!, _heightMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('duration_in_seconds')) {
|
||||||
|
context.handle(
|
||||||
|
_durationInSecondsMeta,
|
||||||
|
durationInSeconds.isAcceptableOrUnknown(
|
||||||
|
data['duration_in_seconds']!, _durationInSecondsMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('local_id')) {
|
||||||
|
context.handle(_localIdMeta,
|
||||||
|
localId.isAcceptableOrUnknown(data['local_id']!, _localIdMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_localIdMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('checksum')) {
|
||||||
|
context.handle(_checksumMeta,
|
||||||
|
checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta));
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<i0.GeneratedColumn> get $primaryKey => {localId};
|
||||||
|
@override
|
||||||
|
i1.LocalAssetEntityData map(Map<String, dynamic> data,
|
||||||
|
{String? tablePrefix}) {
|
||||||
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
|
return i1.LocalAssetEntityData(
|
||||||
|
name: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
|
||||||
|
type: i1.$LocalAssetEntityTable.$convertertype.fromSql(attachedDatabase
|
||||||
|
.typeMapping
|
||||||
|
.read(i0.DriftSqlType.int, data['${effectivePrefix}type'])!),
|
||||||
|
createdAt: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
|
||||||
|
updatedAt: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
|
||||||
|
width: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.int, data['${effectivePrefix}width']),
|
||||||
|
height: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.int, data['${effectivePrefix}height']),
|
||||||
|
durationInSeconds: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
||||||
|
localId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}local_id'])!,
|
||||||
|
checksum: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}checksum']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$LocalAssetEntityTable createAlias(String alias) {
|
||||||
|
return $LocalAssetEntityTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
static i0.JsonTypeConverter2<i2.AssetType, int, int> $convertertype =
|
||||||
|
const i0.EnumIndexConverter<i2.AssetType>(i2.AssetType.values);
|
||||||
|
@override
|
||||||
|
bool get withoutRowId => true;
|
||||||
|
@override
|
||||||
|
bool get isStrict => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAssetEntityData extends i0.DataClass
|
||||||
|
implements i0.Insertable<i1.LocalAssetEntityData> {
|
||||||
|
final String name;
|
||||||
|
final i2.AssetType type;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final int? width;
|
||||||
|
final int? height;
|
||||||
|
final int? durationInSeconds;
|
||||||
|
final String localId;
|
||||||
|
final String? checksum;
|
||||||
|
const LocalAssetEntityData(
|
||||||
|
{required this.name,
|
||||||
|
required this.type,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.durationInSeconds,
|
||||||
|
required this.localId,
|
||||||
|
this.checksum});
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
map['name'] = i0.Variable<String>(name);
|
||||||
|
{
|
||||||
|
map['type'] = i0.Variable<int>(
|
||||||
|
i1.$LocalAssetEntityTable.$convertertype.toSql(type));
|
||||||
|
}
|
||||||
|
map['created_at'] = i0.Variable<DateTime>(createdAt);
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||||
|
if (!nullToAbsent || width != null) {
|
||||||
|
map['width'] = i0.Variable<int>(width);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || height != null) {
|
||||||
|
map['height'] = i0.Variable<int>(height);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || durationInSeconds != null) {
|
||||||
|
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
||||||
|
}
|
||||||
|
map['local_id'] = i0.Variable<String>(localId);
|
||||||
|
if (!nullToAbsent || checksum != null) {
|
||||||
|
map['checksum'] = i0.Variable<String>(checksum);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory LocalAssetEntityData.fromJson(Map<String, dynamic> json,
|
||||||
|
{i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return LocalAssetEntityData(
|
||||||
|
name: serializer.fromJson<String>(json['name']),
|
||||||
|
type: i1.$LocalAssetEntityTable.$convertertype
|
||||||
|
.fromJson(serializer.fromJson<int>(json['type'])),
|
||||||
|
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||||
|
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||||
|
width: serializer.fromJson<int?>(json['width']),
|
||||||
|
height: serializer.fromJson<int?>(json['height']),
|
||||||
|
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
||||||
|
localId: serializer.fromJson<String>(json['localId']),
|
||||||
|
checksum: serializer.fromJson<String?>(json['checksum']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'name': serializer.toJson<String>(name),
|
||||||
|
'type': serializer
|
||||||
|
.toJson<int>(i1.$LocalAssetEntityTable.$convertertype.toJson(type)),
|
||||||
|
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||||
|
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||||
|
'width': serializer.toJson<int?>(width),
|
||||||
|
'height': serializer.toJson<int?>(height),
|
||||||
|
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
||||||
|
'localId': serializer.toJson<String>(localId),
|
||||||
|
'checksum': serializer.toJson<String?>(checksum),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.LocalAssetEntityData copyWith(
|
||||||
|
{String? name,
|
||||||
|
i2.AssetType? type,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
i0.Value<int?> width = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
|
String? localId,
|
||||||
|
i0.Value<String?> checksum = const i0.Value.absent()}) =>
|
||||||
|
i1.LocalAssetEntityData(
|
||||||
|
name: name ?? this.name,
|
||||||
|
type: type ?? this.type,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
width: width.present ? width.value : this.width,
|
||||||
|
height: height.present ? height.value : this.height,
|
||||||
|
durationInSeconds: durationInSeconds.present
|
||||||
|
? durationInSeconds.value
|
||||||
|
: this.durationInSeconds,
|
||||||
|
localId: localId ?? this.localId,
|
||||||
|
checksum: checksum.present ? checksum.value : this.checksum,
|
||||||
|
);
|
||||||
|
LocalAssetEntityData copyWithCompanion(i1.LocalAssetEntityCompanion data) {
|
||||||
|
return LocalAssetEntityData(
|
||||||
|
name: data.name.present ? data.name.value : this.name,
|
||||||
|
type: data.type.present ? data.type.value : this.type,
|
||||||
|
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||||
|
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
|
||||||
|
width: data.width.present ? data.width.value : this.width,
|
||||||
|
height: data.height.present ? data.height.value : this.height,
|
||||||
|
durationInSeconds: data.durationInSeconds.present
|
||||||
|
? data.durationInSeconds.value
|
||||||
|
: this.durationInSeconds,
|
||||||
|
localId: data.localId.present ? data.localId.value : this.localId,
|
||||||
|
checksum: data.checksum.present ? data.checksum.value : this.checksum,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('LocalAssetEntityData(')
|
||||||
|
..write('name: $name, ')
|
||||||
|
..write('type: $type, ')
|
||||||
|
..write('createdAt: $createdAt, ')
|
||||||
|
..write('updatedAt: $updatedAt, ')
|
||||||
|
..write('width: $width, ')
|
||||||
|
..write('height: $height, ')
|
||||||
|
..write('durationInSeconds: $durationInSeconds, ')
|
||||||
|
..write('localId: $localId, ')
|
||||||
|
..write('checksum: $checksum')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(name, type, createdAt, updatedAt, width,
|
||||||
|
height, durationInSeconds, localId, checksum);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is i1.LocalAssetEntityData &&
|
||||||
|
other.name == this.name &&
|
||||||
|
other.type == this.type &&
|
||||||
|
other.createdAt == this.createdAt &&
|
||||||
|
other.updatedAt == this.updatedAt &&
|
||||||
|
other.width == this.width &&
|
||||||
|
other.height == this.height &&
|
||||||
|
other.durationInSeconds == this.durationInSeconds &&
|
||||||
|
other.localId == this.localId &&
|
||||||
|
other.checksum == this.checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAssetEntityCompanion
|
||||||
|
extends i0.UpdateCompanion<i1.LocalAssetEntityData> {
|
||||||
|
final i0.Value<String> name;
|
||||||
|
final i0.Value<i2.AssetType> type;
|
||||||
|
final i0.Value<DateTime> createdAt;
|
||||||
|
final i0.Value<DateTime> updatedAt;
|
||||||
|
final i0.Value<int?> width;
|
||||||
|
final i0.Value<int?> height;
|
||||||
|
final i0.Value<int?> durationInSeconds;
|
||||||
|
final i0.Value<String> localId;
|
||||||
|
final i0.Value<String?> checksum;
|
||||||
|
const LocalAssetEntityCompanion({
|
||||||
|
this.name = const i0.Value.absent(),
|
||||||
|
this.type = const i0.Value.absent(),
|
||||||
|
this.createdAt = const i0.Value.absent(),
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
this.width = const i0.Value.absent(),
|
||||||
|
this.height = const i0.Value.absent(),
|
||||||
|
this.durationInSeconds = const i0.Value.absent(),
|
||||||
|
this.localId = const i0.Value.absent(),
|
||||||
|
this.checksum = const i0.Value.absent(),
|
||||||
|
});
|
||||||
|
LocalAssetEntityCompanion.insert({
|
||||||
|
required String name,
|
||||||
|
required i2.AssetType type,
|
||||||
|
this.createdAt = const i0.Value.absent(),
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
this.width = const i0.Value.absent(),
|
||||||
|
this.height = const i0.Value.absent(),
|
||||||
|
this.durationInSeconds = const i0.Value.absent(),
|
||||||
|
required String localId,
|
||||||
|
this.checksum = const i0.Value.absent(),
|
||||||
|
}) : name = i0.Value(name),
|
||||||
|
type = i0.Value(type),
|
||||||
|
localId = i0.Value(localId);
|
||||||
|
static i0.Insertable<i1.LocalAssetEntityData> custom({
|
||||||
|
i0.Expression<String>? name,
|
||||||
|
i0.Expression<int>? type,
|
||||||
|
i0.Expression<DateTime>? createdAt,
|
||||||
|
i0.Expression<DateTime>? updatedAt,
|
||||||
|
i0.Expression<int>? width,
|
||||||
|
i0.Expression<int>? height,
|
||||||
|
i0.Expression<int>? durationInSeconds,
|
||||||
|
i0.Expression<String>? localId,
|
||||||
|
i0.Expression<String>? checksum,
|
||||||
|
}) {
|
||||||
|
return i0.RawValuesInsertable({
|
||||||
|
if (name != null) 'name': name,
|
||||||
|
if (type != null) 'type': type,
|
||||||
|
if (createdAt != null) 'created_at': createdAt,
|
||||||
|
if (updatedAt != null) 'updated_at': updatedAt,
|
||||||
|
if (width != null) 'width': width,
|
||||||
|
if (height != null) 'height': height,
|
||||||
|
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
||||||
|
if (localId != null) 'local_id': localId,
|
||||||
|
if (checksum != null) 'checksum': checksum,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.LocalAssetEntityCompanion copyWith(
|
||||||
|
{i0.Value<String>? name,
|
||||||
|
i0.Value<i2.AssetType>? type,
|
||||||
|
i0.Value<DateTime>? createdAt,
|
||||||
|
i0.Value<DateTime>? updatedAt,
|
||||||
|
i0.Value<int?>? width,
|
||||||
|
i0.Value<int?>? height,
|
||||||
|
i0.Value<int?>? durationInSeconds,
|
||||||
|
i0.Value<String>? localId,
|
||||||
|
i0.Value<String?>? checksum}) {
|
||||||
|
return i1.LocalAssetEntityCompanion(
|
||||||
|
name: name ?? this.name,
|
||||||
|
type: type ?? this.type,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
width: width ?? this.width,
|
||||||
|
height: height ?? this.height,
|
||||||
|
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||||
|
localId: localId ?? this.localId,
|
||||||
|
checksum: checksum ?? this.checksum,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
if (name.present) {
|
||||||
|
map['name'] = i0.Variable<String>(name.value);
|
||||||
|
}
|
||||||
|
if (type.present) {
|
||||||
|
map['type'] = i0.Variable<int>(
|
||||||
|
i1.$LocalAssetEntityTable.$convertertype.toSql(type.value));
|
||||||
|
}
|
||||||
|
if (createdAt.present) {
|
||||||
|
map['created_at'] = i0.Variable<DateTime>(createdAt.value);
|
||||||
|
}
|
||||||
|
if (updatedAt.present) {
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||||
|
}
|
||||||
|
if (width.present) {
|
||||||
|
map['width'] = i0.Variable<int>(width.value);
|
||||||
|
}
|
||||||
|
if (height.present) {
|
||||||
|
map['height'] = i0.Variable<int>(height.value);
|
||||||
|
}
|
||||||
|
if (durationInSeconds.present) {
|
||||||
|
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds.value);
|
||||||
|
}
|
||||||
|
if (localId.present) {
|
||||||
|
map['local_id'] = i0.Variable<String>(localId.value);
|
||||||
|
}
|
||||||
|
if (checksum.present) {
|
||||||
|
map['checksum'] = i0.Variable<String>(checksum.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('LocalAssetEntityCompanion(')
|
||||||
|
..write('name: $name, ')
|
||||||
|
..write('type: $type, ')
|
||||||
|
..write('createdAt: $createdAt, ')
|
||||||
|
..write('updatedAt: $updatedAt, ')
|
||||||
|
..write('width: $width, ')
|
||||||
|
..write('height: $height, ')
|
||||||
|
..write('durationInSeconds: $durationInSeconds, ')
|
||||||
|
..write('localId: $localId, ')
|
||||||
|
..write('checksum: $checksum')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart' as asset;
|
||||||
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
|
class AlbumMediaRepository implements IAlbumMediaRepository {
|
||||||
|
const AlbumMediaRepository();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<AssetPathEntity>> getAll({PMFilter? filter}) async {
|
||||||
|
return await PhotoManager.getAssetPathList(
|
||||||
|
hasAll: true,
|
||||||
|
filterOption: filter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<asset.LocalAsset>> getAssetsForAlbum(
|
||||||
|
AssetPathEntity assetPathEntity,
|
||||||
|
) async {
|
||||||
|
final assets = <AssetEntity>[];
|
||||||
|
int pageNumber = 0, lastPageCount = 0;
|
||||||
|
do {
|
||||||
|
final page = await assetPathEntity.getAssetListPaged(
|
||||||
|
page: pageNumber,
|
||||||
|
size: kFetchLocalAssetsBatchSize,
|
||||||
|
);
|
||||||
|
assets.addAll(page);
|
||||||
|
lastPageCount = page.length;
|
||||||
|
pageNumber++;
|
||||||
|
} while (lastPageCount == kFetchLocalAssetsBatchSize);
|
||||||
|
return assets.toDtoList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<AssetPathEntity> refresh(String albumId, {PMFilter? filter}) =>
|
||||||
|
AssetPathEntity.obtainPathFromProperties(
|
||||||
|
id: albumId,
|
||||||
|
optionGroup: filter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AssetEntityMediaRepoX on AssetEntity {
|
||||||
|
Future<asset.LocalAsset> toDto() async {
|
||||||
|
return asset.LocalAsset(
|
||||||
|
localId: id,
|
||||||
|
name: title ?? await titleAsync,
|
||||||
|
type: switch (type) {
|
||||||
|
AssetType.other => asset.AssetType.other,
|
||||||
|
AssetType.image => asset.AssetType.image,
|
||||||
|
AssetType.video => asset.AssetType.video,
|
||||||
|
AssetType.audio => asset.AssetType.audio,
|
||||||
|
},
|
||||||
|
createdAt: createDateTime,
|
||||||
|
updatedAt: modifiedDateTime,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
durationInSeconds: duration,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AssetEntityListMediaRepoX on List<AssetEntity> {
|
||||||
|
Future<List<asset.LocalAsset>> toDtoList() =>
|
||||||
|
Future.wait(map((a) => a.toDto()));
|
||||||
|
}
|
@ -3,6 +3,9 @@ import 'dart:async';
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:drift_flutter/drift_flutter.dart';
|
import 'package:drift_flutter/drift_flutter.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/db.interface.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_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/user.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
||||||
@ -25,7 +28,16 @@ class IsarDatabaseRepository implements IDatabaseRepository {
|
|||||||
Zone.current[_kzoneTxn] == null ? _db.writeTxn(callback) : callback();
|
Zone.current[_kzoneTxn] == null ? _db.writeTxn(callback) : callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@DriftDatabase(tables: [UserEntity, UserMetadataEntity, PartnerEntity])
|
@DriftDatabase(
|
||||||
|
tables: [
|
||||||
|
UserEntity,
|
||||||
|
UserMetadataEntity,
|
||||||
|
PartnerEntity,
|
||||||
|
LocalAlbumEntity,
|
||||||
|
LocalAssetEntity,
|
||||||
|
LocalAlbumAssetEntity,
|
||||||
|
],
|
||||||
|
)
|
||||||
class Drift extends $Drift implements IDatabaseRepository {
|
class Drift extends $Drift implements IDatabaseRepository {
|
||||||
Drift([QueryExecutor? executor])
|
Drift([QueryExecutor? executor])
|
||||||
: super(
|
: super(
|
||||||
|
@ -7,6 +7,12 @@ import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift
|
|||||||
as i2;
|
as i2;
|
||||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
|
||||||
as i3;
|
as i3;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
|
||||||
|
as i4;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
|
||||||
|
as i5;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
|
||||||
|
as i6;
|
||||||
|
|
||||||
abstract class $Drift extends i0.GeneratedDatabase {
|
abstract class $Drift extends i0.GeneratedDatabase {
|
||||||
$Drift(i0.QueryExecutor e) : super(e);
|
$Drift(i0.QueryExecutor e) : super(e);
|
||||||
@ -16,12 +22,25 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
i2.$UserMetadataEntityTable(this);
|
i2.$UserMetadataEntityTable(this);
|
||||||
late final i3.$PartnerEntityTable partnerEntity =
|
late final i3.$PartnerEntityTable partnerEntity =
|
||||||
i3.$PartnerEntityTable(this);
|
i3.$PartnerEntityTable(this);
|
||||||
|
late final i4.$LocalAssetEntityTable localAssetEntity =
|
||||||
|
i4.$LocalAssetEntityTable(this);
|
||||||
|
late final i5.$LocalAlbumEntityTable localAlbumEntity =
|
||||||
|
i5.$LocalAlbumEntityTable(this);
|
||||||
|
late final i6.$LocalAlbumAssetEntityTable localAlbumAssetEntity =
|
||||||
|
i6.$LocalAlbumAssetEntityTable(this);
|
||||||
@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?>>();
|
||||||
@override
|
@override
|
||||||
List<i0.DatabaseSchemaEntity> get allSchemaEntities =>
|
List<i0.DatabaseSchemaEntity> get allSchemaEntities => [
|
||||||
[userEntity, userMetadataEntity, partnerEntity];
|
userEntity,
|
||||||
|
userMetadataEntity,
|
||||||
|
partnerEntity,
|
||||||
|
localAssetEntity,
|
||||||
|
localAlbumEntity,
|
||||||
|
localAlbumAssetEntity,
|
||||||
|
i4.localAssetChecksum
|
||||||
|
];
|
||||||
@override
|
@override
|
||||||
i0.StreamQueryUpdateRules get streamUpdateRules =>
|
i0.StreamQueryUpdateRules get streamUpdateRules =>
|
||||||
const i0.StreamQueryUpdateRules(
|
const i0.StreamQueryUpdateRules(
|
||||||
@ -48,6 +67,29 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete),
|
i0.TableUpdate('partner_entity', kind: i0.UpdateKind.delete),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('local_album_entity', kind: i0.UpdateKind.update),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('local_album_asset_entity',
|
||||||
|
kind: i0.UpdateKind.delete),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('local_album_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('local_album_asset_entity',
|
||||||
|
kind: i0.UpdateKind.delete),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
@ -64,4 +106,10 @@ class $DriftManager {
|
|||||||
i2.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
|
i2.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
|
||||||
i3.$$PartnerEntityTableTableManager get partnerEntity =>
|
i3.$$PartnerEntityTableTableManager get partnerEntity =>
|
||||||
i3.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
|
i3.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
|
||||||
|
i4.$$LocalAssetEntityTableTableManager get localAssetEntity =>
|
||||||
|
i4.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity);
|
||||||
|
i5.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
|
||||||
|
i5.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
|
||||||
|
i6.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i6
|
||||||
|
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
|
class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAlbumRepository {
|
||||||
|
final Drift _db;
|
||||||
|
const DriftLocalAlbumRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> upsert(LocalAlbum localAlbum) {
|
||||||
|
final companion = LocalAlbumEntityCompanion.insert(
|
||||||
|
id: localAlbum.id,
|
||||||
|
name: localAlbum.name,
|
||||||
|
updatedAt: Value(localAlbum.updatedAt),
|
||||||
|
assetCount: Value(localAlbum.assetCount),
|
||||||
|
thumbnailId: Value.absentIfNull(localAlbum.thumbnailId),
|
||||||
|
backupSelection: localAlbum.backupSelection,
|
||||||
|
isAll: Value(localAlbum.isAll),
|
||||||
|
);
|
||||||
|
|
||||||
|
return _db.localAlbumEntity
|
||||||
|
.insertOne(companion, onConflict: DoUpdate((_) => companion));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<LocalAlbum>> getAll({SortLocalAlbumsBy? sortBy}) {
|
||||||
|
final query = _db.localAlbumEntity.select();
|
||||||
|
if (sortBy == SortLocalAlbumsBy.id) {
|
||||||
|
query.orderBy([(a) => OrderingTerm.asc(a.id)]);
|
||||||
|
}
|
||||||
|
return query.map((a) => a.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> delete(String albumId) => _db.managers.localAlbumEntity
|
||||||
|
.filter((a) => a.id.equals(albumId))
|
||||||
|
.delete();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> getAssetIdsOnlyInAlbum(String albumId) {
|
||||||
|
final assetId = _db.localAlbumAssetEntity.assetId;
|
||||||
|
final query = _db.localAlbumAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetId])
|
||||||
|
..groupBy(
|
||||||
|
[assetId],
|
||||||
|
having: _db.localAlbumAssetEntity.albumId.count().equals(1) &
|
||||||
|
_db.localAlbumAssetEntity.albumId.equals(albumId),
|
||||||
|
);
|
||||||
|
|
||||||
|
return query.map((row) => row.read(assetId)!).get();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
|
class DriftLocalAlbumAssetRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAlbumAssetRepository {
|
||||||
|
final Drift _db;
|
||||||
|
const DriftLocalAlbumAssetRepository(super._db) : _db = _db;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> linkAssetsToAlbum(String albumId, Iterable<String> assetIds) =>
|
||||||
|
_db.batch(
|
||||||
|
(batch) => batch.insertAll(
|
||||||
|
_db.localAlbumAssetEntity,
|
||||||
|
assetIds.map(
|
||||||
|
(a) => LocalAlbumAssetEntityCompanion.insert(
|
||||||
|
assetId: a,
|
||||||
|
albumId: albumId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<LocalAsset>> getAssetsForAlbum(String albumId) {
|
||||||
|
final query = _db.localAlbumAssetEntity.select().join(
|
||||||
|
[
|
||||||
|
innerJoin(
|
||||||
|
_db.localAssetEntity,
|
||||||
|
_db.localAlbumAssetEntity.assetId
|
||||||
|
.equalsExp(_db.localAssetEntity.localId),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)..where(_db.localAlbumAssetEntity.albumId.equals(albumId));
|
||||||
|
return query
|
||||||
|
.map((row) => row.readTable(_db.localAssetEntity).toDto())
|
||||||
|
.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> unlinkAssetsFromAlbum(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> assetIds,
|
||||||
|
) =>
|
||||||
|
_db.batch(
|
||||||
|
(batch) => batch.deleteWhere(
|
||||||
|
_db.localAlbumAssetEntity,
|
||||||
|
(f) => f.assetId.isIn(assetIds),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
|
class DriftLocalAssetRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAssetRepository {
|
||||||
|
final Drift _db;
|
||||||
|
const DriftLocalAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> deleteIds(Iterable<String> ids) => _db.batch(
|
||||||
|
(batch) => batch.deleteWhere(
|
||||||
|
_db.localAssetEntity,
|
||||||
|
(f) => f.localId.isIn(ids),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> upsertAll(Iterable<LocalAsset> localAssets) =>
|
||||||
|
_db.batch((batch) async {
|
||||||
|
batch.insertAllOnConflictUpdate(
|
||||||
|
_db.localAssetEntity,
|
||||||
|
localAssets.map(
|
||||||
|
(a) => LocalAssetEntityCompanion.insert(
|
||||||
|
name: a.name,
|
||||||
|
type: a.type,
|
||||||
|
createdAt: Value(a.createdAt),
|
||||||
|
updatedAt: Value(a.updatedAt),
|
||||||
|
width: Value.absentIfNull(a.width),
|
||||||
|
height: Value.absentIfNull(a.height),
|
||||||
|
durationInSeconds: Value.absentIfNull(a.durationInSeconds),
|
||||||
|
localId: a.localId,
|
||||||
|
checksum: Value.absentIfNull(a.checksum),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LocalAsset> get(String assetId) => _db.managers.localAssetEntity
|
||||||
|
.filter((f) => f.localId(assetId))
|
||||||
|
.map((a) => a.toDto())
|
||||||
|
.getSingle();
|
||||||
|
}
|
12
mobile/lib/infrastructure/utils/asset.mixin.dart
Normal file
12
mobile/lib/infrastructure/utils/asset.mixin.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
|
||||||
|
mixin AssetEntityMixin on Table {
|
||||||
|
TextColumn get name => text()();
|
||||||
|
IntColumn get type => intEnum<AssetType>()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
IntColumn get width => integer().nullable()();
|
||||||
|
IntColumn get height => integer().nullable()();
|
||||||
|
IntColumn get durationInSeconds => integer().nullable()();
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// ignore_for_file: avoid-unsafe-collection-methods
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
@ -12,16 +12,14 @@ import 'package:immich_mobile/entities/asset.entity.dart';
|
|||||||
import 'package:immich_mobile/services/background.service.dart';
|
import 'package:immich_mobile/services/background.service.dart';
|
||||||
import 'package:immich_mobile/services/hash.service.dart';
|
import 'package:immich_mobile/services/hash.service.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
|
||||||
|
|
||||||
|
import '../../external.mock.dart';
|
||||||
import '../../fixtures/asset.stub.dart';
|
import '../../fixtures/asset.stub.dart';
|
||||||
import '../../infrastructure/repository.mock.dart';
|
import '../../infrastructure/repository.mock.dart';
|
||||||
import '../../service.mocks.dart';
|
import '../../service.mocks.dart';
|
||||||
|
|
||||||
class MockAsset extends Mock implements Asset {}
|
class MockAsset extends Mock implements Asset {}
|
||||||
|
|
||||||
class MockAssetEntity extends Mock implements AssetEntity {}
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
late HashService sut;
|
late HashService sut;
|
||||||
late BackgroundService mockBackgroundService;
|
late BackgroundService mockBackgroundService;
|
||||||
|
361
mobile/test/domain/services/sync_service_test.dart
Normal file
361
mobile/test/domain/services/sync_service_test.dart
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart'
|
||||||
|
hide AssetType;
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/services/sync.service.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/album_media.repository.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
|
import '../../external.mock.dart';
|
||||||
|
import '../../fixtures/local_album.stub.dart';
|
||||||
|
import '../../fixtures/local_asset.stub.dart';
|
||||||
|
import '../../infrastructure/repository.mock.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('SyncService', () {
|
||||||
|
late SyncService sut;
|
||||||
|
late IAlbumMediaRepository mockAlbumMediaRepo;
|
||||||
|
late ILocalAlbumRepository mockLocalAlbumRepo;
|
||||||
|
late ILocalAssetRepository mockLocalAssetRepo;
|
||||||
|
late ILocalAlbumAssetRepository mockLocalAlbumAssetRepo;
|
||||||
|
|
||||||
|
const albumId = 'test-album-id';
|
||||||
|
final now = DateTime.now();
|
||||||
|
final earlier = now.subtract(const Duration(days: 1));
|
||||||
|
|
||||||
|
late LocalAlbum dbAlbum;
|
||||||
|
late LocalAlbum deviceAlbum;
|
||||||
|
late AssetPathEntity deviceAlbumEntity;
|
||||||
|
late List<LocalAsset> deviceAssets;
|
||||||
|
late List<LocalAsset> dbAssets;
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
mockAlbumMediaRepo = MockAlbumMediaRepository();
|
||||||
|
mockLocalAlbumRepo = MockLocalAlbumRepository();
|
||||||
|
mockLocalAssetRepo = MockLocalAssetRepository();
|
||||||
|
mockLocalAlbumAssetRepo = MockLocalAlbumAssetRepository();
|
||||||
|
|
||||||
|
sut = SyncService(
|
||||||
|
albumMediaRepository: mockAlbumMediaRepo,
|
||||||
|
localAlbumRepository: mockLocalAlbumRepo,
|
||||||
|
localAssetRepository: mockLocalAssetRepo,
|
||||||
|
localAlbumAssetRepository: mockLocalAlbumAssetRepo,
|
||||||
|
);
|
||||||
|
|
||||||
|
dbAlbum = LocalAlbum(
|
||||||
|
id: albumId,
|
||||||
|
name: 'Test Album',
|
||||||
|
updatedAt: earlier,
|
||||||
|
assetCount: 5,
|
||||||
|
backupSelection: BackupSelection.none,
|
||||||
|
);
|
||||||
|
|
||||||
|
deviceAlbumEntity = MockAssetPathEntity();
|
||||||
|
when(() => deviceAlbumEntity.id).thenReturn(albumId);
|
||||||
|
when(() => deviceAlbumEntity.name).thenReturn('Test Album');
|
||||||
|
when(() => deviceAlbumEntity.lastModified).thenReturn(now);
|
||||||
|
when(() => deviceAlbumEntity.isAll).thenReturn(false);
|
||||||
|
when(() => deviceAlbumEntity.assetCountAsync).thenAnswer((_) async => 5);
|
||||||
|
deviceAlbum = await deviceAlbumEntity.toDto();
|
||||||
|
|
||||||
|
deviceAssets = await Future.wait(
|
||||||
|
List.generate(5, (i) {
|
||||||
|
final asset = MockAssetEntity();
|
||||||
|
when(() => asset.id).thenReturn('asset-$i');
|
||||||
|
when(() => asset.title).thenReturn('Asset $i');
|
||||||
|
when(() => asset.createDateTime).thenReturn(now);
|
||||||
|
when(() => asset.modifiedDateTime).thenReturn(now);
|
||||||
|
when(() => asset.width).thenReturn(1920);
|
||||||
|
when(() => asset.height).thenReturn(1080);
|
||||||
|
when(() => asset.type).thenReturn(AssetType.image);
|
||||||
|
when(() => asset.duration).thenReturn(0);
|
||||||
|
return asset.toDto();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
dbAssets = await Future.wait(
|
||||||
|
List.generate(5, (i) {
|
||||||
|
final asset = MockAssetEntity();
|
||||||
|
when(() => asset.id).thenReturn('asset-$i');
|
||||||
|
when(() => asset.title).thenReturn('Asset $i');
|
||||||
|
when(() => asset.createDateTime).thenReturn(earlier);
|
||||||
|
when(() => asset.modifiedDateTime).thenReturn(earlier);
|
||||||
|
when(() => asset.width).thenReturn(1920);
|
||||||
|
when(() => asset.height).thenReturn(1080);
|
||||||
|
when(() => asset.type).thenReturn(AssetType.image);
|
||||||
|
when(() => asset.duration).thenReturn(0);
|
||||||
|
return asset.toDto();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
registerFallbackValue(FakeAssetEntity());
|
||||||
|
registerFallbackValue(FakeAssetPathEntity());
|
||||||
|
registerFallbackValue(LocalAssetStub.image1);
|
||||||
|
registerFallbackValue(LocalAlbumStub.album1);
|
||||||
|
|
||||||
|
when(() => mockAlbumMediaRepo.refresh(albumId))
|
||||||
|
.thenAnswer((_) async => deviceAlbumEntity);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAlbumMediaRepo.refresh(
|
||||||
|
albumId,
|
||||||
|
filter: any(named: 'filter'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => deviceAlbumEntity);
|
||||||
|
|
||||||
|
when(() => mockAlbumMediaRepo.getAssetsForAlbum(deviceAlbumEntity))
|
||||||
|
.thenAnswer((_) async => deviceAssets);
|
||||||
|
|
||||||
|
when(() => mockLocalAlbumAssetRepo.getAssetsForAlbum(albumId))
|
||||||
|
.thenAnswer((_) async => dbAssets);
|
||||||
|
|
||||||
|
when(() => mockLocalAssetRepo.upsertAll(any()))
|
||||||
|
.thenAnswer((_) async => {});
|
||||||
|
|
||||||
|
when(() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(any(), any()))
|
||||||
|
.thenAnswer((_) async => {});
|
||||||
|
|
||||||
|
when(() => mockLocalAlbumRepo.upsert(any())).thenAnswer((_) async => {});
|
||||||
|
|
||||||
|
when(() => mockLocalAlbumRepo.transaction<Null>(any()))
|
||||||
|
.thenAnswer((_) async {
|
||||||
|
final capturedCallback = verify(
|
||||||
|
() => mockLocalAlbumRepo.transaction<Null>(captureAny()),
|
||||||
|
).captured;
|
||||||
|
// Invoke the transaction callback
|
||||||
|
await (capturedCallback.firstOrNull as Future<Null> Function()?)
|
||||||
|
?.call();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'album filter should be properly configured with expected settings',
|
||||||
|
() {
|
||||||
|
// Access the album filter from the service
|
||||||
|
final albumFilter = sut.albumFilter;
|
||||||
|
|
||||||
|
// Verify image option settings
|
||||||
|
final imageOption = albumFilter.getOption(AssetType.image);
|
||||||
|
expect(imageOption.needTitle, isTrue);
|
||||||
|
expect(imageOption.sizeConstraint.ignoreSize, isTrue);
|
||||||
|
|
||||||
|
// Verify video option settings
|
||||||
|
final videoOption = albumFilter.getOption(AssetType.video);
|
||||||
|
expect(videoOption.needTitle, isTrue);
|
||||||
|
expect(videoOption.sizeConstraint.ignoreSize, isTrue);
|
||||||
|
expect(videoOption.durationConstraint.allowNullable, isTrue);
|
||||||
|
|
||||||
|
// Verify containsPathModified flag
|
||||||
|
expect(albumFilter.containsPathModified, isTrue);
|
||||||
|
|
||||||
|
// Verify time conditions are ignored
|
||||||
|
expect(albumFilter.createTimeCond.ignore, isTrue);
|
||||||
|
expect(albumFilter.updateTimeCond.ignore, isTrue);
|
||||||
|
|
||||||
|
// Verify ordering
|
||||||
|
expect(albumFilter.orders.length, 1);
|
||||||
|
expect(
|
||||||
|
albumFilter.orders.firstOrNull?.type,
|
||||||
|
OrderOptionType.createDate,
|
||||||
|
);
|
||||||
|
expect(albumFilter.orders.firstOrNull?.asc, isFalse);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
group('handleOnlyAssetsAdded: ', () {
|
||||||
|
// All the below tests expects the device album to have more assets
|
||||||
|
// than the DB album. This is to simulate the scenario where
|
||||||
|
// new assets are added to the device album.
|
||||||
|
setUp(() {
|
||||||
|
deviceAlbum = deviceAlbum.copyWith(assetCount: 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'early return when device album timestamp is not after DB album',
|
||||||
|
() async {
|
||||||
|
final result = await sut.handleOnlyAssetsAdded(
|
||||||
|
dbAlbum,
|
||||||
|
deviceAlbum.copyWith(updatedAt: earlier),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify: method returns without making any changes
|
||||||
|
expect(result, isFalse);
|
||||||
|
verifyNever(() => mockAlbumMediaRepo.getAssetsForAlbum(any()));
|
||||||
|
verifyNever(() => mockLocalAssetRepo.upsertAll(any()));
|
||||||
|
verifyNever(
|
||||||
|
() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(any(), any()),
|
||||||
|
);
|
||||||
|
verifyNever(() => mockLocalAlbumRepo.upsert(any()));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'early return when device album has fewer assets than DB album',
|
||||||
|
() async {
|
||||||
|
// Execute
|
||||||
|
final result = await sut.handleOnlyAssetsAdded(
|
||||||
|
dbAlbum,
|
||||||
|
deviceAlbum.copyWith(assetCount: dbAlbum.assetCount - 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, isFalse);
|
||||||
|
verifyNever(() => mockAlbumMediaRepo.getAssetsForAlbum(any()));
|
||||||
|
verifyNever(() => mockLocalAssetRepo.upsertAll(any()));
|
||||||
|
verifyNever(
|
||||||
|
() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(any(), any()),
|
||||||
|
);
|
||||||
|
verifyNever(() => mockLocalAlbumRepo.upsert(any()));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'correctly processes assets when new assets are added',
|
||||||
|
() async {
|
||||||
|
final result = await sut.handleOnlyAssetsAdded(dbAlbum, deviceAlbum);
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockAlbumMediaRepo.getAssetsForAlbum(deviceAlbumEntity),
|
||||||
|
).called(1);
|
||||||
|
|
||||||
|
verify(() => mockLocalAssetRepo.upsertAll(any())).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(
|
||||||
|
albumId,
|
||||||
|
deviceAssets.map((a) => a.localId),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
|
||||||
|
verify(() => mockLocalAlbumRepo.upsert(any())).called(1);
|
||||||
|
|
||||||
|
expect(result, isTrue);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'correct handling when filtering yields no new assets',
|
||||||
|
() async {
|
||||||
|
when(() => mockAlbumMediaRepo.getAssetsForAlbum(deviceAlbumEntity))
|
||||||
|
.thenAnswer((_) async => deviceAssets.sublist(0, 2));
|
||||||
|
|
||||||
|
final result = await sut.handleOnlyAssetsAdded(dbAlbum, deviceAlbum);
|
||||||
|
|
||||||
|
verify(() => mockAlbumMediaRepo.getAssetsForAlbum(deviceAlbumEntity))
|
||||||
|
.called(1);
|
||||||
|
|
||||||
|
verifyNever(() => mockLocalAssetRepo.upsertAll(any()));
|
||||||
|
verifyNever(
|
||||||
|
() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(any(), any()),
|
||||||
|
);
|
||||||
|
verifyNever(() => mockLocalAlbumRepo.upsert(any()));
|
||||||
|
|
||||||
|
expect(result, isFalse);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'thumbnail is updated when new asset is newer than existing thumbnail',
|
||||||
|
() async {
|
||||||
|
final oldThumbnailId = 'asset-100';
|
||||||
|
when(() => mockLocalAssetRepo.get(oldThumbnailId)).thenAnswer(
|
||||||
|
(_) async =>
|
||||||
|
LocalAssetStub.image1.copyWith(createdAt: DateTime(100)),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await sut.handleOnlyAssetsAdded(
|
||||||
|
dbAlbum.copyWith(thumbnailId: oldThumbnailId),
|
||||||
|
deviceAlbum,
|
||||||
|
);
|
||||||
|
|
||||||
|
final capturedAlbum =
|
||||||
|
verify(() => mockLocalAlbumRepo.upsert(captureAny()))
|
||||||
|
.captured
|
||||||
|
.singleOrNull as LocalAlbum?;
|
||||||
|
expect(capturedAlbum?.thumbnailId, isNot(equals(oldThumbnailId)));
|
||||||
|
expect(
|
||||||
|
capturedAlbum?.thumbnailId,
|
||||||
|
equals(deviceAssets.firstOrNull?.localId),
|
||||||
|
);
|
||||||
|
expect(result, isTrue);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'thumbnail preservation when new asset is older than existing thumbnail',
|
||||||
|
() async {
|
||||||
|
final oldThumbnailId = 'asset-100';
|
||||||
|
when(() => mockLocalAssetRepo.get(oldThumbnailId)).thenAnswer(
|
||||||
|
(_) async => LocalAssetStub.image1
|
||||||
|
.copyWith(createdAt: now.add(const Duration(days: 1))),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await sut.handleOnlyAssetsAdded(
|
||||||
|
dbAlbum.copyWith(thumbnailId: oldThumbnailId),
|
||||||
|
deviceAlbum,
|
||||||
|
);
|
||||||
|
|
||||||
|
final capturedAlbum =
|
||||||
|
verify(() => mockLocalAlbumRepo.upsert(captureAny()))
|
||||||
|
.captured
|
||||||
|
.singleOrNull as LocalAlbum?;
|
||||||
|
expect(capturedAlbum?.thumbnailId, equals(oldThumbnailId));
|
||||||
|
expect(result, isTrue);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('addLocalAlbum: ', () {
|
||||||
|
test('adding an album with no assets works correctly', () async {
|
||||||
|
when(() => deviceAlbumEntity.assetCountAsync)
|
||||||
|
.thenAnswer((_) async => 0);
|
||||||
|
|
||||||
|
await sut.addLocalAlbum(deviceAlbum.copyWith(assetCount: 0));
|
||||||
|
|
||||||
|
final albumUpsertCall =
|
||||||
|
verify(() => mockLocalAlbumRepo.upsert(captureAny()));
|
||||||
|
albumUpsertCall.called(1);
|
||||||
|
|
||||||
|
// Always refreshed
|
||||||
|
verify(
|
||||||
|
() => mockAlbumMediaRepo.refresh(albumId, filter: sut.albumFilter),
|
||||||
|
).called(1);
|
||||||
|
verifyNever(() => mockLocalAssetRepo.upsertAll(any()));
|
||||||
|
verifyNever(
|
||||||
|
() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(any(), any()),
|
||||||
|
);
|
||||||
|
|
||||||
|
final capturedAlbum =
|
||||||
|
albumUpsertCall.captured.singleOrNull as LocalAlbum?;
|
||||||
|
expect(capturedAlbum?.id, equals(albumId));
|
||||||
|
expect(capturedAlbum?.name, equals('Test Album'));
|
||||||
|
expect(capturedAlbum?.assetCount, equals(0));
|
||||||
|
expect(capturedAlbum?.thumbnailId, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'adding an album with multiple assets works correctly',
|
||||||
|
() async {
|
||||||
|
await sut.addLocalAlbum(deviceAlbum);
|
||||||
|
|
||||||
|
final albumUpsertCall =
|
||||||
|
verify(() => mockLocalAlbumRepo.upsert(captureAny()));
|
||||||
|
albumUpsertCall.called(1);
|
||||||
|
verify(() => mockLocalAssetRepo.upsertAll(any())).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockLocalAlbumAssetRepo.linkAssetsToAlbum(albumId, any()),
|
||||||
|
).called(1);
|
||||||
|
|
||||||
|
final capturedAlbum =
|
||||||
|
albumUpsertCall.captured.singleOrNull as LocalAlbum?;
|
||||||
|
expect(capturedAlbum?.assetCount, deviceAssets.length);
|
||||||
|
|
||||||
|
expect(capturedAlbum?.thumbnailId, deviceAssets.firstOrNull?.localId);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
10
mobile/test/external.mock.dart
Normal file
10
mobile/test/external.mock.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
|
class MockAssetEntity extends Mock implements AssetEntity {}
|
||||||
|
|
||||||
|
class FakeAssetEntity extends Fake implements AssetEntity {}
|
||||||
|
|
||||||
|
class MockAssetPathEntity extends Mock implements AssetPathEntity {}
|
||||||
|
|
||||||
|
class FakeAssetPathEntity extends Fake implements AssetPathEntity {}
|
15
mobile/test/fixtures/local_album.stub.dart
vendored
Normal file
15
mobile/test/fixtures/local_album.stub.dart
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
|
||||||
|
abstract final class LocalAlbumStub {
|
||||||
|
const LocalAlbumStub();
|
||||||
|
|
||||||
|
static LocalAlbum get album1 => LocalAlbum(
|
||||||
|
id: "album1",
|
||||||
|
name: "Album 1",
|
||||||
|
updatedAt: DateTime(2023),
|
||||||
|
assetCount: 1,
|
||||||
|
thumbnailId: null,
|
||||||
|
backupSelection: BackupSelection.none,
|
||||||
|
isAll: false,
|
||||||
|
);
|
||||||
|
}
|
17
mobile/test/fixtures/local_asset.stub.dart
vendored
Normal file
17
mobile/test/fixtures/local_asset.stub.dart
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/asset/asset.model.dart';
|
||||||
|
|
||||||
|
abstract final class LocalAssetStub {
|
||||||
|
const LocalAssetStub();
|
||||||
|
|
||||||
|
static LocalAsset get image1 => LocalAsset(
|
||||||
|
localId: "image1",
|
||||||
|
name: "image1.jpg",
|
||||||
|
checksum: "image1-checksum",
|
||||||
|
type: AssetType.image,
|
||||||
|
createdAt: DateTime(2019),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
durationInSeconds: 0,
|
||||||
|
);
|
||||||
|
}
|
@ -1,4 +1,8 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/album_media.interface.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
||||||
@ -18,6 +22,15 @@ class MockDeviceAssetRepository extends Mock
|
|||||||
|
|
||||||
class MockSyncStreamRepository extends Mock implements ISyncStreamRepository {}
|
class MockSyncStreamRepository extends Mock implements ISyncStreamRepository {}
|
||||||
|
|
||||||
|
class MockLocalAssetRepository extends Mock implements ILocalAssetRepository {}
|
||||||
|
|
||||||
|
class MockLocalAlbumRepository extends Mock implements ILocalAlbumRepository {}
|
||||||
|
|
||||||
|
class MockAlbumMediaRepository extends Mock implements IAlbumMediaRepository {}
|
||||||
|
|
||||||
|
class MockLocalAlbumAssetRepository extends Mock
|
||||||
|
implements ILocalAlbumAssetRepository {}
|
||||||
|
|
||||||
// API Repos
|
// API Repos
|
||||||
class MockUserApiRepository extends Mock implements IUserApiRepository {}
|
class MockUserApiRepository extends Mock implements IUserApiRepository {}
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@ import 'package:mocktail/mocktail.dart';
|
|||||||
|
|
||||||
import '../../domain/service.mock.dart';
|
import '../../domain/service.mock.dart';
|
||||||
import '../../fixtures/asset.stub.dart';
|
import '../../fixtures/asset.stub.dart';
|
||||||
import '../../infrastructure/repository.mock.dart';
|
import '../../infrastructure/repository.mock.dart'
|
||||||
|
hide MockAlbumMediaRepository;
|
||||||
import '../../repository.mocks.dart';
|
import '../../repository.mocks.dart';
|
||||||
import '../../service.mocks.dart';
|
import '../../service.mocks.dart';
|
||||||
import '../../test_utils.dart';
|
import '../../test_utils.dart';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user