♻️ Optimize message data structure

This commit is contained in:
2025-09-23 14:00:43 +08:00
parent c79b1d7aab
commit b2ac5fbef2
12 changed files with 1041 additions and 502 deletions

View File

@@ -12,7 +12,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase(super.e);
@override
int get schemaVersion => 6;
int get schemaVersion => 7;
@override
MigrationStrategy get migration => MigrationStrategy(
@@ -21,8 +21,8 @@ class AppDatabase extends _$AppDatabase {
},
onUpgrade: (Migrator m, int from, int to) async {
if (from < 2) {
// Add isRead column with default value false
await m.addColumn(chatMessages, chatMessages.isRead);
// Add isDeleted column with default value false
await m.addColumn(chatMessages, chatMessages.isDeleted);
}
if (from < 4) {
// Drop old draft tables if they exist
@@ -32,6 +32,19 @@ class AppDatabase extends _$AppDatabase {
// Migrate from old schema to new schema with separate searchable fields
await _migrateToVersion6(m);
}
if (from < 7) {
// Add new columns from SnChatMessage
await m.addColumn(chatMessages, chatMessages.updatedAt);
await m.addColumn(chatMessages, chatMessages.deletedAt);
await m.addColumn(chatMessages, chatMessages.type);
await m.addColumn(chatMessages, chatMessages.meta);
await m.addColumn(chatMessages, chatMessages.membersMentioned);
await m.addColumn(chatMessages, chatMessages.editedAt);
await m.addColumn(chatMessages, chatMessages.attachments);
await m.addColumn(chatMessages, chatMessages.reactions);
await m.addColumn(chatMessages, chatMessages.repliedMessageId);
await m.addColumn(chatMessages, chatMessages.forwardedMessageId);
}
},
);
@@ -116,12 +129,6 @@ class AppDatabase extends _$AppDatabase {
)).write(ChatMessagesCompanion(status: Value(status)));
}
Future<int> markMessageAsRead(String id) {
return (update(chatMessages)..where(
(m) => m.id.equals(id),
)).write(ChatMessagesCompanion(isRead: const Value(true)));
}
Future<int> deleteMessage(String id) {
return (delete(chatMessages)..where((m) => m.id.equals(id))).go();
}
@@ -154,16 +161,26 @@ class AppDatabase extends _$AppDatabase {
// Convert between Drift and model objects
ChatMessagesCompanion messageToCompanion(LocalChatMessage message) {
final remote = message.toRemoteMessage();
return ChatMessagesCompanion(
id: Value(message.id),
roomId: Value(message.roomId),
senderId: Value(message.senderId),
content: Value(message.toRemoteMessage().content),
content: Value(remote.content),
nonce: Value(message.nonce),
data: Value(jsonEncode(message.data)),
createdAt: Value(message.createdAt),
status: Value(message.status),
isRead: Value(message.isRead),
updatedAt: Value(remote.updatedAt),
deletedAt: Value(remote.deletedAt),
type: Value(remote.type),
meta: Value(remote.meta),
membersMentioned: Value(remote.membersMentioned),
editedAt: Value(remote.editedAt),
attachments: Value(remote.attachments.map((e) => e.toJson()).toList()),
reactions: Value(remote.reactions.map((e) => e.toJson()).toList()),
repliedMessageId: Value(remote.repliedMessageId),
forwardedMessageId: Value(remote.forwardedMessageId),
);
}
@@ -177,7 +194,6 @@ class AppDatabase extends _$AppDatabase {
createdAt: dbMessage.createdAt,
status: dbMessage.status,
nonce: dbMessage.nonce,
isRead: dbMessage.isRead,
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,41 @@
import 'dart:convert';
import 'package:drift/drift.dart';
import 'package:island/models/chat.dart';
import 'package:island/models/file.dart';
class MapConverter extends TypeConverter<Map<String, dynamic>, String> {
const MapConverter();
@override
Map<String, dynamic> fromSql(String fromDb) => json.decode(fromDb);
@override
String toSql(Map<String, dynamic> value) => json.encode(value);
}
class ListStringConverter extends TypeConverter<List<String>, String> {
const ListStringConverter();
@override
List<String> fromSql(String fromDb) => List<String>.from(json.decode(fromDb));
@override
String toSql(List<String> value) => json.encode(value);
}
class ListMapConverter
extends TypeConverter<List<Map<String, dynamic>>, String> {
const ListMapConverter();
@override
List<Map<String, dynamic>> fromSql(String fromDb) =>
List<Map<String, dynamic>>.from(json.decode(fromDb));
@override
String toSql(List<Map<String, dynamic>> value) => json.encode(value);
}
class ChatMessages extends Table {
TextColumn get id => text()();
TextColumn get roomId => text()();
@@ -11,7 +45,24 @@ class ChatMessages extends Table {
TextColumn get data => text()();
DateTimeColumn get createdAt => dateTime()();
IntColumn get status => intEnum<MessageStatus>()();
BoolColumn get isRead => boolean().withDefault(const Constant(false))();
BoolColumn get isDeleted =>
boolean().nullable().withDefault(const Constant(false))();
DateTimeColumn get updatedAt => dateTime().nullable()();
DateTimeColumn get deletedAt => dateTime().nullable()();
TextColumn get type => text().withDefault(const Constant('text'))();
TextColumn get meta =>
text().map(const MapConverter()).withDefault(const Constant('{}'))();
TextColumn get membersMentioned =>
text()
.map(const ListStringConverter())
.withDefault(const Constant('[]'))();
DateTimeColumn get editedAt => dateTime().nullable()();
TextColumn get attachments =>
text().map(const ListMapConverter()).withDefault(const Constant('[]'))();
TextColumn get reactions =>
text().map(const ListMapConverter()).withDefault(const Constant('[]'))();
TextColumn get repliedMessageId => text().nullable()();
TextColumn get forwardedMessageId => text().nullable()();
@override
Set<Column> get primaryKey => {id};