mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
feat(mobile): drift user metadata sync (#19894)
* feat(mobile): drift user metadata sync * change text to jsonb * update primary key --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
parent
daea57f7d2
commit
0acbf1199a
2
mobile/drift_schemas/main/drift_schema_v1.json
generated
2
mobile/drift_schemas/main/drift_schema_v1.json
generated
File diff suppressed because one or more lines are too long
@ -1,5 +1,12 @@
|
||||
import 'dart:ui';
|
||||
|
||||
enum UserMetadataKey {
|
||||
// do not change this order!
|
||||
onboarding,
|
||||
preferences,
|
||||
license,
|
||||
}
|
||||
|
||||
enum AvatarColor {
|
||||
// do not change this order or reuse indices for other purposes, adding is OK
|
||||
primary("primary"),
|
||||
@ -31,7 +38,45 @@ enum AvatarColor {
|
||||
};
|
||||
}
|
||||
|
||||
class UserPreferences {
|
||||
class Onboarding {
|
||||
final bool isOnboarded;
|
||||
|
||||
const Onboarding({required this.isOnboarded});
|
||||
|
||||
Onboarding copyWith({bool? isOnboarded}) {
|
||||
return Onboarding(isOnboarded: isOnboarded ?? this.isOnboarded);
|
||||
}
|
||||
|
||||
Map<String, Object?> toMap() {
|
||||
final onboarding = <String, Object?>{};
|
||||
onboarding["isOnboarded"] = isOnboarded;
|
||||
return onboarding;
|
||||
}
|
||||
|
||||
factory Onboarding.fromMap(Map<String, Object?> map) {
|
||||
return Onboarding(isOnboarded: map["isOnboarded"] as bool);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''Onboarding {
|
||||
isOnboarded: $isOnboarded,
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant Onboarding other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return isOnboarded == other.isOnboarded;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => isOnboarded.hashCode;
|
||||
}
|
||||
|
||||
// TODO: wait to be overwritten
|
||||
class Preferences {
|
||||
final bool foldersEnabled;
|
||||
final bool memoriesEnabled;
|
||||
final bool peopleEnabled;
|
||||
@ -41,7 +86,7 @@ class UserPreferences {
|
||||
final AvatarColor userAvatarColor;
|
||||
final bool showSupportBadge;
|
||||
|
||||
const UserPreferences({
|
||||
const Preferences({
|
||||
this.foldersEnabled = false,
|
||||
this.memoriesEnabled = true,
|
||||
this.peopleEnabled = true,
|
||||
@ -52,7 +97,7 @@ class UserPreferences {
|
||||
this.showSupportBadge = true,
|
||||
});
|
||||
|
||||
UserPreferences copyWith({
|
||||
Preferences copyWith({
|
||||
bool? foldersEnabled,
|
||||
bool? memoriesEnabled,
|
||||
bool? peopleEnabled,
|
||||
@ -62,7 +107,7 @@ class UserPreferences {
|
||||
AvatarColor? userAvatarColor,
|
||||
bool? showSupportBadge,
|
||||
}) {
|
||||
return UserPreferences(
|
||||
return Preferences(
|
||||
foldersEnabled: foldersEnabled ?? this.foldersEnabled,
|
||||
memoriesEnabled: memoriesEnabled ?? this.memoriesEnabled,
|
||||
peopleEnabled: peopleEnabled ?? this.peopleEnabled,
|
||||
@ -87,8 +132,8 @@ class UserPreferences {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
factory UserPreferences.fromMap(Map<String, Object?> map) {
|
||||
return UserPreferences(
|
||||
factory Preferences.fromMap(Map<String, Object?> map) {
|
||||
return Preferences(
|
||||
foldersEnabled: map["folders-Enabled"] as bool? ?? false,
|
||||
memoriesEnabled: map["memories-Enabled"] as bool? ?? true,
|
||||
peopleEnabled: map["people-Enabled"] as bool? ?? true,
|
||||
@ -102,4 +147,173 @@ class UserPreferences {
|
||||
showSupportBadge: map["purchase-ShowSupportBadge"] as bool? ?? true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''Preferences: {
|
||||
foldersEnabled: $foldersEnabled,
|
||||
memoriesEnabled: $memoriesEnabled,
|
||||
peopleEnabled: $peopleEnabled,
|
||||
ratingsEnabled: $ratingsEnabled,
|
||||
sharedLinksEnabled: $sharedLinksEnabled,
|
||||
tagsEnabled: $tagsEnabled,
|
||||
userAvatarColor: $userAvatarColor,
|
||||
showSupportBadge: $showSupportBadge,
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant Preferences other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.foldersEnabled == foldersEnabled &&
|
||||
other.memoriesEnabled == memoriesEnabled &&
|
||||
other.peopleEnabled == peopleEnabled &&
|
||||
other.ratingsEnabled == ratingsEnabled &&
|
||||
other.sharedLinksEnabled == sharedLinksEnabled &&
|
||||
other.tagsEnabled == tagsEnabled &&
|
||||
other.userAvatarColor == userAvatarColor &&
|
||||
other.showSupportBadge == showSupportBadge;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return foldersEnabled.hashCode ^
|
||||
memoriesEnabled.hashCode ^
|
||||
peopleEnabled.hashCode ^
|
||||
ratingsEnabled.hashCode ^
|
||||
sharedLinksEnabled.hashCode ^
|
||||
tagsEnabled.hashCode ^
|
||||
userAvatarColor.hashCode ^
|
||||
showSupportBadge.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
class License {
|
||||
final DateTime activatedAt;
|
||||
final String activationKey;
|
||||
final String licenseKey;
|
||||
|
||||
const License({
|
||||
required this.activatedAt,
|
||||
required this.activationKey,
|
||||
required this.licenseKey,
|
||||
});
|
||||
|
||||
License copyWith({
|
||||
DateTime? activatedAt,
|
||||
String? activationKey,
|
||||
String? licenseKey,
|
||||
}) {
|
||||
return License(
|
||||
activatedAt: activatedAt ?? this.activatedAt,
|
||||
activationKey: activationKey ?? this.activationKey,
|
||||
licenseKey: licenseKey ?? this.licenseKey,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, Object?> toMap() {
|
||||
final license = <String, Object?>{};
|
||||
license["activatedAt"] = activatedAt;
|
||||
license["activationKey"] = activationKey;
|
||||
license["licenseKey"] = licenseKey;
|
||||
return license;
|
||||
}
|
||||
|
||||
factory License.fromMap(Map<String, Object?> map) {
|
||||
return License(
|
||||
activatedAt: map["activatedAt"] as DateTime,
|
||||
activationKey: map["activationKey"] as String,
|
||||
licenseKey: map["licenseKey"] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''License {
|
||||
activatedAt: $activatedAt,
|
||||
activationKey: $activationKey,
|
||||
licenseKey: $licenseKey,
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant License other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return activatedAt == other.activatedAt &&
|
||||
activationKey == other.activationKey &&
|
||||
licenseKey == other.licenseKey;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
|
||||
}
|
||||
|
||||
// Model for a user metadata stored in the server
|
||||
class UserMetadata {
|
||||
final String userId;
|
||||
final UserMetadataKey key;
|
||||
final Onboarding? onboarding;
|
||||
final Preferences? preferences;
|
||||
final License? license;
|
||||
|
||||
const UserMetadata({
|
||||
required this.userId,
|
||||
required this.key,
|
||||
this.onboarding,
|
||||
this.preferences,
|
||||
this.license,
|
||||
}) : assert(
|
||||
onboarding != null || preferences != null || license != null,
|
||||
'One of onboarding, preferences and license must be provided',
|
||||
);
|
||||
|
||||
UserMetadata copyWith({
|
||||
String? userId,
|
||||
UserMetadataKey? key,
|
||||
Onboarding? onboarding,
|
||||
Preferences? preferences,
|
||||
License? license,
|
||||
}) {
|
||||
return UserMetadata(
|
||||
userId: userId ?? this.userId,
|
||||
key: key ?? this.key,
|
||||
onboarding: onboarding ?? this.onboarding,
|
||||
preferences: preferences ?? this.preferences,
|
||||
license: license ?? this.license,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''UserMetadata: {
|
||||
userId: $userId,
|
||||
key: $key,
|
||||
onboarding: ${onboarding ?? "<NA>"},
|
||||
preferences: ${preferences ?? "<NA>"},
|
||||
license: ${license ?? "<NA>"},
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant UserMetadata other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.userId == userId &&
|
||||
other.key == key &&
|
||||
other.onboarding == onboarding &&
|
||||
other.preferences == preferences &&
|
||||
other.license == license;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return userId.hashCode ^
|
||||
key.hashCode ^
|
||||
onboarding.hashCode ^
|
||||
preferences.hashCode ^
|
||||
license.hashCode;
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +179,14 @@ class SyncStreamService {
|
||||
data.cast(),
|
||||
debugLabel: 'partner',
|
||||
);
|
||||
case SyncEntityType.userMetadataV1:
|
||||
return _syncStreamRepository.updateUserMetadatasV1(
|
||||
data.cast(),
|
||||
);
|
||||
case SyncEntityType.userMetadataDeleteV1:
|
||||
return _syncStreamRepository.deleteUserMetadatasV1(
|
||||
data.cast(),
|
||||
);
|
||||
default:
|
||||
_logger.warning("Unknown sync data type: $type");
|
||||
}
|
||||
|
@ -8,14 +8,16 @@ class UserMetadataEntity extends Table with DriftDefaultsMixin {
|
||||
|
||||
TextColumn get userId =>
|
||||
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
|
||||
TextColumn get preferences => text().map(userPreferenceConverter)();
|
||||
|
||||
IntColumn get key => intEnum<UserMetadataKey>()();
|
||||
|
||||
BlobColumn get value => blob().map(userMetadataConverter)();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {userId};
|
||||
Set<Column> get primaryKey => {userId, key};
|
||||
}
|
||||
|
||||
final JsonTypeConverter2<UserPreferences, String, Object?>
|
||||
userPreferenceConverter = TypeConverter.json2(
|
||||
fromJson: (json) => UserPreferences.fromMap(json as Map<String, Object?>),
|
||||
toJson: (pref) => pref.toMap(),
|
||||
final JsonTypeConverter2<Map<String, Object?>, Uint8List, Object?>
|
||||
userMetadataConverter = TypeConverter.jsonb(
|
||||
fromJson: (json) => json as Map<String, Object?>,
|
||||
);
|
||||
|
@ -4,21 +4,24 @@ import 'package:drift/drift.dart' as i0;
|
||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'
|
||||
as i1;
|
||||
import 'package:immich_mobile/domain/models/user_metadata.model.dart' as i2;
|
||||
import 'dart:typed_data' as i3;
|
||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart'
|
||||
as i3;
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
|
||||
as i4;
|
||||
import 'package:drift/internal/modular.dart' as i5;
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
|
||||
as i5;
|
||||
import 'package:drift/internal/modular.dart' as i6;
|
||||
|
||||
typedef $$UserMetadataEntityTableCreateCompanionBuilder
|
||||
= i1.UserMetadataEntityCompanion Function({
|
||||
required String userId,
|
||||
required i2.UserPreferences preferences,
|
||||
required i2.UserMetadataKey key,
|
||||
required Map<String, Object?> value,
|
||||
});
|
||||
typedef $$UserMetadataEntityTableUpdateCompanionBuilder
|
||||
= i1.UserMetadataEntityCompanion Function({
|
||||
i0.Value<String> userId,
|
||||
i0.Value<i2.UserPreferences> preferences,
|
||||
i0.Value<i2.UserMetadataKey> key,
|
||||
i0.Value<Map<String, Object?>> value,
|
||||
});
|
||||
|
||||
final class $$UserMetadataEntityTableReferences extends i0.BaseReferences<
|
||||
@ -28,26 +31,26 @@ final class $$UserMetadataEntityTableReferences extends i0.BaseReferences<
|
||||
$$UserMetadataEntityTableReferences(
|
||||
super.$_db, super.$_table, super.$_typedResult);
|
||||
|
||||
static i4.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||
static i5.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$UserMetadataEntityTable>(
|
||||
'user_metadata_entity')
|
||||
.userId,
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.id));
|
||||
|
||||
i4.$$UserEntityTableProcessedTableManager get userId {
|
||||
i5.$$UserEntityTableProcessedTableManager get userId {
|
||||
final $_column = $_itemColumn<String>('user_id')!;
|
||||
|
||||
final manager = i4
|
||||
final manager = i5
|
||||
.$$UserEntityTableTableManager(
|
||||
$_db,
|
||||
i5.ReadDatabaseContainer($_db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'))
|
||||
i6.ReadDatabaseContainer($_db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'))
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_userIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
@ -65,26 +68,31 @@ class $$UserMetadataEntityTableFilterComposer
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.ColumnWithTypeConverterFilters<i2.UserPreferences, i2.UserPreferences,
|
||||
String>
|
||||
get preferences => $composableBuilder(
|
||||
column: $table.preferences,
|
||||
i0.ColumnWithTypeConverterFilters<i2.UserMetadataKey, i2.UserMetadataKey, int>
|
||||
get key => $composableBuilder(
|
||||
column: $table.key,
|
||||
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
|
||||
|
||||
i4.$$UserEntityTableFilterComposer get userId {
|
||||
final i4.$$UserEntityTableFilterComposer composer = $composerBuilder(
|
||||
i0.ColumnWithTypeConverterFilters<Map<String, Object?>, Map<String, Object>,
|
||||
i3.Uint8List>
|
||||
get value => $composableBuilder(
|
||||
column: $table.value,
|
||||
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
|
||||
|
||||
i5.$$UserEntityTableFilterComposer get userId {
|
||||
final i5.$$UserEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.userId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||
referencedTable: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i4.$$UserEntityTableFilterComposer(
|
||||
i5.$$UserEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
@ -103,24 +111,26 @@ class $$UserMetadataEntityTableOrderingComposer
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.ColumnOrderings<String> get preferences => $composableBuilder(
|
||||
column: $table.preferences,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
i0.ColumnOrderings<int> get key => $composableBuilder(
|
||||
column: $table.key, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i4.$$UserEntityTableOrderingComposer get userId {
|
||||
final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder(
|
||||
i0.ColumnOrderings<i3.Uint8List> get value => $composableBuilder(
|
||||
column: $table.value, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i5.$$UserEntityTableOrderingComposer get userId {
|
||||
final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.userId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||
referencedTable: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i4.$$UserEntityTableOrderingComposer(
|
||||
i5.$$UserEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
@ -139,24 +149,27 @@ class $$UserMetadataEntityTableAnnotationComposer
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.GeneratedColumnWithTypeConverter<i2.UserPreferences, String>
|
||||
get preferences => $composableBuilder(
|
||||
column: $table.preferences, builder: (column) => column);
|
||||
i0.GeneratedColumnWithTypeConverter<i2.UserMetadataKey, int> get key =>
|
||||
$composableBuilder(column: $table.key, builder: (column) => column);
|
||||
|
||||
i4.$$UserEntityTableAnnotationComposer get userId {
|
||||
final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
|
||||
i0.GeneratedColumnWithTypeConverter<Map<String, Object?>, i3.Uint8List>
|
||||
get value =>
|
||||
$composableBuilder(column: $table.value, builder: (column) => column);
|
||||
|
||||
i5.$$UserEntityTableAnnotationComposer get userId {
|
||||
final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.userId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||
referencedTable: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i4.$$UserEntityTableAnnotationComposer(
|
||||
i5.$$UserEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
@ -193,19 +206,23 @@ class $$UserMetadataEntityTableTableManager extends i0.RootTableManager<
|
||||
$db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
i0.Value<String> userId = const i0.Value.absent(),
|
||||
i0.Value<i2.UserPreferences> preferences = const i0.Value.absent(),
|
||||
i0.Value<i2.UserMetadataKey> key = const i0.Value.absent(),
|
||||
i0.Value<Map<String, Object?>> value = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.UserMetadataEntityCompanion(
|
||||
userId: userId,
|
||||
preferences: preferences,
|
||||
key: key,
|
||||
value: value,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String userId,
|
||||
required i2.UserPreferences preferences,
|
||||
required i2.UserMetadataKey key,
|
||||
required Map<String, Object?> value,
|
||||
}) =>
|
||||
i1.UserMetadataEntityCompanion.insert(
|
||||
userId: userId,
|
||||
preferences: preferences,
|
||||
key: key,
|
||||
value: value,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map((e) => (
|
||||
@ -266,7 +283,7 @@ typedef $$UserMetadataEntityTableProcessedTableManager
|
||||
i1.UserMetadataEntityData,
|
||||
i0.PrefetchHooks Function({bool userId})>;
|
||||
|
||||
class $UserMetadataEntityTable extends i3.UserMetadataEntity
|
||||
class $UserMetadataEntityTable extends i4.UserMetadataEntity
|
||||
with i0.TableInfo<$UserMetadataEntityTable, i1.UserMetadataEntityData> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
@ -282,14 +299,20 @@ class $UserMetadataEntityTable extends i3.UserMetadataEntity
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES user_entity (id) ON DELETE CASCADE'));
|
||||
@override
|
||||
late final i0.GeneratedColumnWithTypeConverter<i2.UserPreferences, String>
|
||||
preferences = i0.GeneratedColumn<String>(
|
||||
'preferences', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true)
|
||||
.withConverter<i2.UserPreferences>(
|
||||
i1.$UserMetadataEntityTable.$converterpreferences);
|
||||
late final i0.GeneratedColumnWithTypeConverter<i2.UserMetadataKey, int> key =
|
||||
i0.GeneratedColumn<int>('key', aliasedName, false,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: true)
|
||||
.withConverter<i2.UserMetadataKey>(
|
||||
i1.$UserMetadataEntityTable.$converterkey);
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [userId, preferences];
|
||||
late final i0
|
||||
.GeneratedColumnWithTypeConverter<Map<String, Object?>, i3.Uint8List>
|
||||
value = i0.GeneratedColumn<i3.Uint8List>('value', aliasedName, false,
|
||||
type: i0.DriftSqlType.blob, requiredDuringInsert: true)
|
||||
.withConverter<Map<String, Object?>>(
|
||||
i1.$UserMetadataEntityTable.$convertervalue);
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [userId, key, value];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
@ -311,7 +334,7 @@ class $UserMetadataEntityTable extends i3.UserMetadataEntity
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {userId};
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {userId, key};
|
||||
@override
|
||||
i1.UserMetadataEntityData map(Map<String, dynamic> data,
|
||||
{String? tablePrefix}) {
|
||||
@ -319,9 +342,12 @@ class $UserMetadataEntityTable extends i3.UserMetadataEntity
|
||||
return i1.UserMetadataEntityData(
|
||||
userId: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}user_id'])!,
|
||||
preferences: i1.$UserMetadataEntityTable.$converterpreferences.fromSql(
|
||||
attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.string, data['${effectivePrefix}preferences'])!),
|
||||
key: i1.$UserMetadataEntityTable.$converterkey.fromSql(attachedDatabase
|
||||
.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}key'])!),
|
||||
value: i1.$UserMetadataEntityTable.$convertervalue.fromSql(
|
||||
attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.blob, data['${effectivePrefix}value'])!),
|
||||
);
|
||||
}
|
||||
|
||||
@ -330,8 +356,11 @@ class $UserMetadataEntityTable extends i3.UserMetadataEntity
|
||||
return $UserMetadataEntityTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static i0.JsonTypeConverter2<i2.UserPreferences, String, Object?>
|
||||
$converterpreferences = i3.userPreferenceConverter;
|
||||
static i0.JsonTypeConverter2<i2.UserMetadataKey, int, int> $converterkey =
|
||||
const i0.EnumIndexConverter<i2.UserMetadataKey>(
|
||||
i2.UserMetadataKey.values);
|
||||
static i0.JsonTypeConverter2<Map<String, Object?>, i3.Uint8List, Object?>
|
||||
$convertervalue = i4.userMetadataConverter;
|
||||
@override
|
||||
bool get withoutRowId => true;
|
||||
@override
|
||||
@ -341,16 +370,21 @@ class $UserMetadataEntityTable extends i3.UserMetadataEntity
|
||||
class UserMetadataEntityData extends i0.DataClass
|
||||
implements i0.Insertable<i1.UserMetadataEntityData> {
|
||||
final String userId;
|
||||
final i2.UserPreferences preferences;
|
||||
final i2.UserMetadataKey key;
|
||||
final Map<String, Object?> value;
|
||||
const UserMetadataEntityData(
|
||||
{required this.userId, required this.preferences});
|
||||
{required this.userId, required this.key, required this.value});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['user_id'] = i0.Variable<String>(userId);
|
||||
{
|
||||
map['preferences'] = i0.Variable<String>(
|
||||
i1.$UserMetadataEntityTable.$converterpreferences.toSql(preferences));
|
||||
map['key'] = i0.Variable<int>(
|
||||
i1.$UserMetadataEntityTable.$converterkey.toSql(key));
|
||||
}
|
||||
{
|
||||
map['value'] = i0.Variable<i3.Uint8List>(
|
||||
i1.$UserMetadataEntityTable.$convertervalue.toSql(value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@ -360,8 +394,10 @@ class UserMetadataEntityData extends i0.DataClass
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return UserMetadataEntityData(
|
||||
userId: serializer.fromJson<String>(json['userId']),
|
||||
preferences: i1.$UserMetadataEntityTable.$converterpreferences
|
||||
.fromJson(serializer.fromJson<Object?>(json['preferences'])),
|
||||
key: i1.$UserMetadataEntityTable.$converterkey
|
||||
.fromJson(serializer.fromJson<int>(json['key'])),
|
||||
value: i1.$UserMetadataEntityTable.$convertervalue
|
||||
.fromJson(serializer.fromJson<Object?>(json['value'])),
|
||||
);
|
||||
}
|
||||
@override
|
||||
@ -369,24 +405,28 @@ class UserMetadataEntityData extends i0.DataClass
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'userId': serializer.toJson<String>(userId),
|
||||
'preferences': serializer.toJson<Object?>(i1
|
||||
.$UserMetadataEntityTable.$converterpreferences
|
||||
.toJson(preferences)),
|
||||
'key': serializer
|
||||
.toJson<int>(i1.$UserMetadataEntityTable.$converterkey.toJson(key)),
|
||||
'value': serializer.toJson<Object?>(
|
||||
i1.$UserMetadataEntityTable.$convertervalue.toJson(value)),
|
||||
};
|
||||
}
|
||||
|
||||
i1.UserMetadataEntityData copyWith(
|
||||
{String? userId, i2.UserPreferences? preferences}) =>
|
||||
{String? userId,
|
||||
i2.UserMetadataKey? key,
|
||||
Map<String, Object?>? value}) =>
|
||||
i1.UserMetadataEntityData(
|
||||
userId: userId ?? this.userId,
|
||||
preferences: preferences ?? this.preferences,
|
||||
key: key ?? this.key,
|
||||
value: value ?? this.value,
|
||||
);
|
||||
UserMetadataEntityData copyWithCompanion(
|
||||
i1.UserMetadataEntityCompanion data) {
|
||||
return UserMetadataEntityData(
|
||||
userId: data.userId.present ? data.userId.value : this.userId,
|
||||
preferences:
|
||||
data.preferences.present ? data.preferences.value : this.preferences,
|
||||
key: data.key.present ? data.key.value : this.key,
|
||||
value: data.value.present ? data.value.value : this.value,
|
||||
);
|
||||
}
|
||||
|
||||
@ -394,49 +434,60 @@ class UserMetadataEntityData extends i0.DataClass
|
||||
String toString() {
|
||||
return (StringBuffer('UserMetadataEntityData(')
|
||||
..write('userId: $userId, ')
|
||||
..write('preferences: $preferences')
|
||||
..write('key: $key, ')
|
||||
..write('value: $value')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(userId, preferences);
|
||||
int get hashCode => Object.hash(userId, key, value);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.UserMetadataEntityData &&
|
||||
other.userId == this.userId &&
|
||||
other.preferences == this.preferences);
|
||||
other.key == this.key &&
|
||||
other.value == this.value);
|
||||
}
|
||||
|
||||
class UserMetadataEntityCompanion
|
||||
extends i0.UpdateCompanion<i1.UserMetadataEntityData> {
|
||||
final i0.Value<String> userId;
|
||||
final i0.Value<i2.UserPreferences> preferences;
|
||||
final i0.Value<i2.UserMetadataKey> key;
|
||||
final i0.Value<Map<String, Object?>> value;
|
||||
const UserMetadataEntityCompanion({
|
||||
this.userId = const i0.Value.absent(),
|
||||
this.preferences = const i0.Value.absent(),
|
||||
this.key = const i0.Value.absent(),
|
||||
this.value = const i0.Value.absent(),
|
||||
});
|
||||
UserMetadataEntityCompanion.insert({
|
||||
required String userId,
|
||||
required i2.UserPreferences preferences,
|
||||
required i2.UserMetadataKey key,
|
||||
required Map<String, Object?> value,
|
||||
}) : userId = i0.Value(userId),
|
||||
preferences = i0.Value(preferences);
|
||||
key = i0.Value(key),
|
||||
value = i0.Value(value);
|
||||
static i0.Insertable<i1.UserMetadataEntityData> custom({
|
||||
i0.Expression<String>? userId,
|
||||
i0.Expression<String>? preferences,
|
||||
i0.Expression<int>? key,
|
||||
i0.Expression<i3.Uint8List>? value,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (userId != null) 'user_id': userId,
|
||||
if (preferences != null) 'preferences': preferences,
|
||||
if (key != null) 'key': key,
|
||||
if (value != null) 'value': value,
|
||||
});
|
||||
}
|
||||
|
||||
i1.UserMetadataEntityCompanion copyWith(
|
||||
{i0.Value<String>? userId, i0.Value<i2.UserPreferences>? preferences}) {
|
||||
{i0.Value<String>? userId,
|
||||
i0.Value<i2.UserMetadataKey>? key,
|
||||
i0.Value<Map<String, Object?>>? value}) {
|
||||
return i1.UserMetadataEntityCompanion(
|
||||
userId: userId ?? this.userId,
|
||||
preferences: preferences ?? this.preferences,
|
||||
key: key ?? this.key,
|
||||
value: value ?? this.value,
|
||||
);
|
||||
}
|
||||
|
||||
@ -446,10 +497,13 @@ class UserMetadataEntityCompanion
|
||||
if (userId.present) {
|
||||
map['user_id'] = i0.Variable<String>(userId.value);
|
||||
}
|
||||
if (preferences.present) {
|
||||
map['preferences'] = i0.Variable<String>(i1
|
||||
.$UserMetadataEntityTable.$converterpreferences
|
||||
.toSql(preferences.value));
|
||||
if (key.present) {
|
||||
map['key'] = i0.Variable<int>(
|
||||
i1.$UserMetadataEntityTable.$converterkey.toSql(key.value));
|
||||
}
|
||||
if (value.present) {
|
||||
map['value'] = i0.Variable<i3.Uint8List>(
|
||||
i1.$UserMetadataEntityTable.$convertervalue.toSql(value.value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@ -458,7 +512,8 @@ class UserMetadataEntityCompanion
|
||||
String toString() {
|
||||
return (StringBuffer('UserMetadataEntityCompanion(')
|
||||
..write('userId: $userId, ')
|
||||
..write('preferences: $preferences')
|
||||
..write('key: $key, ')
|
||||
..write('value: $value')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ class SyncApiRepository {
|
||||
SyncRequestType.memoryToAssetsV1,
|
||||
SyncRequestType.stacksV1,
|
||||
SyncRequestType.partnerStacksV1,
|
||||
SyncRequestType.userMetadataV1,
|
||||
],
|
||||
).toJson(),
|
||||
);
|
||||
@ -170,6 +171,8 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
|
||||
SyncEntityType.partnerStackV1: SyncStackV1.fromJson,
|
||||
SyncEntityType.partnerStackBackfillV1: SyncStackV1.fromJson,
|
||||
SyncEntityType.partnerStackDeleteV1: SyncStackDeleteV1.fromJson,
|
||||
SyncEntityType.userMetadataV1: SyncUserMetadataV1.fromJson,
|
||||
SyncEntityType.userMetadataDeleteV1: SyncUserMetadataDeleteV1.fromJson,
|
||||
};
|
||||
|
||||
class _SyncAckV1 {
|
||||
|
@ -4,6 +4,7 @@ import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/memory.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart';
|
||||
@ -14,6 +15,7 @@ import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.d
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole;
|
||||
@ -461,6 +463,53 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateUserMetadatasV1(
|
||||
Iterable<SyncUserMetadataV1> data,
|
||||
) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final userMetadata in data) {
|
||||
final companion = UserMetadataEntityCompanion(
|
||||
value: Value(userMetadata.value as Map<String, Object?>),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.userMetadataEntity,
|
||||
companion.copyWith(
|
||||
userId: Value(userMetadata.userId),
|
||||
key: Value(userMetadata.key.toUserMetadataKey()),
|
||||
),
|
||||
onConflict: DoUpdate((_) => companion),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Error: deleteUserMetadatasV1', error, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteUserMetadatasV1(
|
||||
Iterable<SyncUserMetadataDeleteV1> data,
|
||||
) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final userMetadata in data) {
|
||||
batch.delete(
|
||||
_db.userMetadataEntity,
|
||||
UserMetadataEntityCompanion(
|
||||
userId: Value(userMetadata.userId),
|
||||
key: Value(userMetadata.key.toUserMetadataKey()),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Error: deleteUserMetadatasV1', error, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension on AssetTypeEnum {
|
||||
@ -506,6 +555,15 @@ extension on api.AssetVisibility {
|
||||
};
|
||||
}
|
||||
|
||||
extension on String {
|
||||
UserMetadataKey toUserMetadataKey() => switch (this) {
|
||||
"onboarding" => UserMetadataKey.onboarding,
|
||||
"preferences" => UserMetadataKey.preferences,
|
||||
"license" => UserMetadataKey.license,
|
||||
_ => throw Exception('Unknown UserMetadataKey value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
extension on String {
|
||||
Duration? toDuration() {
|
||||
try {
|
||||
|
@ -0,0 +1,38 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
|
||||
class DriftUserMetadataRepository extends DriftDatabaseRepository {
|
||||
final Drift _db;
|
||||
const DriftUserMetadataRepository(this._db) : super(_db);
|
||||
|
||||
Future<List<UserMetadata>> getUserMetadata(String userId) {
|
||||
final query = _db.userMetadataEntity.select()
|
||||
..where((e) => e.userId.equals(userId));
|
||||
|
||||
return query.map((userMetadata) {
|
||||
return userMetadata.toDto();
|
||||
}).get();
|
||||
}
|
||||
}
|
||||
|
||||
extension on UserMetadataEntityData {
|
||||
UserMetadata toDto() => switch (key) {
|
||||
UserMetadataKey.onboarding => UserMetadata(
|
||||
userId: userId,
|
||||
key: key,
|
||||
onboarding: Onboarding.fromMap(value),
|
||||
),
|
||||
UserMetadataKey.preferences => UserMetadata(
|
||||
userId: userId,
|
||||
key: key,
|
||||
preferences: Preferences.fromMap(value),
|
||||
),
|
||||
UserMetadataKey.license => UserMetadata(
|
||||
userId: userId,
|
||||
key: key,
|
||||
license: License.fromMap(value),
|
||||
),
|
||||
};
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/user_metadata.repository.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
|
||||
final userMetadataRepository = Provider<DriftUserMetadataRepository>(
|
||||
(ref) => DriftUserMetadataRepository(ref.watch(driftProvider)),
|
||||
);
|
@ -101,6 +101,10 @@ void main() {
|
||||
debugLabel: any(named: 'debugLabel'),
|
||||
),
|
||||
).thenAnswer(successHandler);
|
||||
when(() => mockSyncStreamRepo.updateUserMetadatasV1(any()))
|
||||
.thenAnswer(successHandler);
|
||||
when(() => mockSyncStreamRepo.deleteUserMetadatasV1(any()))
|
||||
.thenAnswer(successHandler);
|
||||
|
||||
sut = SyncStreamService(
|
||||
syncApiRepository: mockSyncApiRepo,
|
||||
|
Loading…
x
Reference in New Issue
Block a user