更新测试案例
This commit is contained in:
238
apps/im_app/lib/data/repositories/user_repository_impl.dart
Normal file
238
apps/im_app/lib/data/repositories/user_repository_impl.dart
Normal file
@@ -0,0 +1,238 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:im_app/data/local/drift/app_database.dart';
|
||||
import 'package:im_app/domain/entities/user.dart';
|
||||
import 'package:im_app/domain/repositories/user_repository.dart';
|
||||
import 'package:storage_sdk/storage_sdk.dart';
|
||||
|
||||
/// 用户仓储实现
|
||||
///
|
||||
/// ## 职责
|
||||
/// - 所有 DB 操作通过 [StorageSdkApi],不直接接触 AppDatabase
|
||||
/// - DriftUser ↔ Domain User 映射
|
||||
/// - 持久化决策由调用方决定
|
||||
///
|
||||
/// ## 数据流
|
||||
/// ```
|
||||
/// 网络:User.fromJson(json) → (可选) saveUser(user) → StorageSdkApi → DB
|
||||
/// 监听:StorageSdkApi.watchWhere/watchAll → DriftUser → _toEntity() → UI
|
||||
/// 部分更新:updateFields(uid, UsersCompanion) → StorageSdkApi.updateWhere
|
||||
/// ```
|
||||
class UserRepositoryImpl implements UserRepository {
|
||||
final StorageSdkApi _storage;
|
||||
|
||||
UserRepositoryImpl(this._storage);
|
||||
|
||||
// ── DB row → Domain ──────────────────────────────────────────────────────
|
||||
|
||||
User _toEntity(DriftUser row) => User(
|
||||
uid: row.uid,
|
||||
uuid: row.uuid,
|
||||
lastOnline: row.lastOnline,
|
||||
profilePic: row.profilePic,
|
||||
profilePicGaussian: row.profilePicGaussian,
|
||||
nickname: row.nickname,
|
||||
depositName: row.depositName,
|
||||
hasSetDepositName: row.hasSetDepositName,
|
||||
contact: row.contact,
|
||||
countryCode: row.countryCode,
|
||||
username: row.username,
|
||||
role: row.role,
|
||||
relationship: row.relationship,
|
||||
friendStatus: row.friendStatus,
|
||||
bio: row.bio,
|
||||
userAlias: row.userAlias,
|
||||
requestAt: row.requestAt,
|
||||
deletedAt: row.deletedAt,
|
||||
email: row.email,
|
||||
recoveryEmail: row.recoveryEmail,
|
||||
remark: row.remark,
|
||||
source: row.source,
|
||||
addIndex: row.addIndex,
|
||||
incomingSoundId: row.incomingSoundId,
|
||||
outgoingSoundId: row.outgoingSoundId,
|
||||
notificationSoundId: row.notificationSoundId,
|
||||
sendMessageSoundId: row.sendMessageSoundId,
|
||||
groupNotificationSoundId: row.groupNotificationSoundId,
|
||||
groupTags: row.groupTags,
|
||||
friendTags: row.friendTags,
|
||||
publicKey: row.publicKey,
|
||||
configBits: row.configBits,
|
||||
hint: row.hint,
|
||||
);
|
||||
|
||||
// ── Domain → DB companion ────────────────────────────────────────────────
|
||||
|
||||
UsersCompanion _toCompanion(User user) => UsersCompanion(
|
||||
uid: Value(user.uid),
|
||||
uuid: Value(user.uuid),
|
||||
lastOnline: Value(user.lastOnline),
|
||||
profilePic: Value(user.profilePic),
|
||||
profilePicGaussian: Value(user.profilePicGaussian ?? ''),
|
||||
nickname: Value(user.nickname),
|
||||
depositName: Value(user.depositName),
|
||||
hasSetDepositName: Value(user.hasSetDepositName ?? 0),
|
||||
contact: Value(user.contact),
|
||||
countryCode: Value(user.countryCode),
|
||||
username: Value(user.username),
|
||||
role: Value(user.role),
|
||||
relationship: Value(user.relationship),
|
||||
friendStatus: Value(user.friendStatus),
|
||||
bio: Value(user.bio),
|
||||
userAlias: Value(user.userAlias),
|
||||
requestAt: Value(user.requestAt),
|
||||
deletedAt: Value(user.deletedAt),
|
||||
email: Value(user.email),
|
||||
recoveryEmail: Value(user.recoveryEmail),
|
||||
remark: Value(user.remark),
|
||||
source: Value(user.source),
|
||||
addIndex: Value(user.addIndex),
|
||||
incomingSoundId: Value(user.incomingSoundId ?? 0),
|
||||
outgoingSoundId: Value(user.outgoingSoundId ?? 0),
|
||||
notificationSoundId: Value(user.notificationSoundId ?? 0),
|
||||
sendMessageSoundId: Value(user.sendMessageSoundId ?? 0),
|
||||
groupNotificationSoundId: Value(user.groupNotificationSoundId ?? 0),
|
||||
groupTags: Value(user.groupTags ?? '[]'),
|
||||
friendTags: Value(user.friendTags ?? '[]'),
|
||||
publicKey: Value(user.publicKey),
|
||||
configBits: Value(user.configBits ?? 0),
|
||||
hint: Value(user.hint),
|
||||
);
|
||||
|
||||
// ── 监听 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// 监听单个用户
|
||||
@override
|
||||
Stream<User?> watchUser(int uid) {
|
||||
return _storage
|
||||
.watchFirst<DriftUser, $UsersTable>((t) => t.uid.equals(uid))
|
||||
.map((row) => row != null ? _toEntity(row) : null);
|
||||
}
|
||||
|
||||
/// 监听指定 uid 列表
|
||||
@override
|
||||
Stream<List<User>> watchUsers(List<int> uids) {
|
||||
return _storage
|
||||
.watchWhere<DriftUser, $UsersTable>((t) => t.uid.isIn(uids))
|
||||
.map((rows) => rows.map(_toEntity).toList());
|
||||
}
|
||||
|
||||
/// 监听所有用户
|
||||
@override
|
||||
Stream<List<User>> watchAllUsers() {
|
||||
return _storage.watchAll<DriftUser>().map(
|
||||
(rows) => rows.map(_toEntity).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
// ── 读取 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@override
|
||||
Future<User?> getUser(int uid) async {
|
||||
final row = await _storage.selectFirst<DriftUser, $UsersTable>(
|
||||
(t) => t.uid.equals(uid),
|
||||
);
|
||||
return row != null ? _toEntity(row) : null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<User>> getAllUsers() async {
|
||||
final rows = await _storage.selectAll<DriftUser>();
|
||||
return rows.map(_toEntity).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<User>> getUsers({required int offset, required int limit}) async {
|
||||
final rows = await _storage.rawQuery(
|
||||
'SELECT * FROM user ORDER BY id LIMIT ? OFFSET ?',
|
||||
[limit, offset],
|
||||
);
|
||||
return rows
|
||||
.map(
|
||||
(row) => User(
|
||||
uid: row.read<int>('uid'),
|
||||
uuid: row.readNullable<String>('uuid'),
|
||||
lastOnline: row.readNullable<int>('last_online'),
|
||||
profilePic: row.readNullable<String>('profile_pic'),
|
||||
profilePicGaussian: row.readNullable<String>(
|
||||
'profile_pic_gaussian',
|
||||
),
|
||||
nickname: row.readNullable<String>('nickname'),
|
||||
depositName: row.readNullable<String>('deposit_name'),
|
||||
hasSetDepositName: row.readNullable<int>('has_set_deposit_name'),
|
||||
contact: row.readNullable<String>('contact'),
|
||||
countryCode: row.readNullable<String>('country_code'),
|
||||
username: row.readNullable<String>('username'),
|
||||
role: row.readNullable<int>('role'),
|
||||
relationship: row.readNullable<int>('relationship'),
|
||||
friendStatus: row.readNullable<int>('friend_status'),
|
||||
bio: row.readNullable<String>('bio'),
|
||||
userAlias: row.readNullable<String>('user_alias'),
|
||||
requestAt: row.readNullable<int>('request_at'),
|
||||
deletedAt: row.readNullable<int>('deleted_at'),
|
||||
email: row.readNullable<String>('email'),
|
||||
recoveryEmail: row.readNullable<String>('recovery_email'),
|
||||
remark: row.readNullable<String>('remark'),
|
||||
source: row.readNullable<String>('source'),
|
||||
addIndex: row.readNullable<int>('add_index'),
|
||||
incomingSoundId: row.readNullable<int>('incoming_sound_id'),
|
||||
outgoingSoundId: row.readNullable<int>('outgoing_sound_id'),
|
||||
notificationSoundId: row.readNullable<int>('notification_sound_id'),
|
||||
sendMessageSoundId: row.readNullable<int>('send_message_sound_id'),
|
||||
groupNotificationSoundId: row.readNullable<int>(
|
||||
'group_notification_sound_id',
|
||||
),
|
||||
groupTags: row.readNullable<String>('group_tags'),
|
||||
friendTags: row.readNullable<String>('friend_tags'),
|
||||
publicKey: row.readNullable<String>('public_key'),
|
||||
configBits: row.readNullable<int>('config_bits'),
|
||||
hint: row.readNullable<String>('hint'),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> countUsers() async {
|
||||
return _storage.count<DriftUser, $UsersTable>();
|
||||
}
|
||||
|
||||
// ── 写入 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@override
|
||||
Future<void> saveUser(User user) async {
|
||||
await _storage.insertOrReplace<DriftUser>(_toCompanion(user));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveUsers(List<User> users) async {
|
||||
await _storage.batchInsertOrReplace<DriftUser>(
|
||||
users.map(_toCompanion).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
/// 仅更新指定列,其他列不变
|
||||
///
|
||||
/// 示例:
|
||||
/// ```dart
|
||||
/// await userRepo.updateFields(uid, UsersCompanion(
|
||||
/// nickname: Value('New Name'),
|
||||
/// lastOnline: Value(DateTime.now().millisecondsSinceEpoch),
|
||||
/// ));
|
||||
/// ```
|
||||
@override
|
||||
Future<void> updateFields(int uid, UsersCompanion companion) async {
|
||||
await _storage.updateWhere<DriftUser, $UsersTable>(
|
||||
companion,
|
||||
(t) => t.uid.equals(uid),
|
||||
);
|
||||
}
|
||||
|
||||
// ── 删除 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@override
|
||||
Future<void> deleteUser(int uid) async {
|
||||
await _storage.deleteWhere<DriftUser, $UsersTable>(
|
||||
(t) => t.uid.equals(uid),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user