230 lines
6.7 KiB
Dart
230 lines
6.7 KiB
Dart
import 'dart:convert';
|
|
import 'package:drift/drift.dart';
|
|
import 'package:island/database/message.dart';
|
|
import 'package:island/database/draft.dart';
|
|
import 'package:island/models/post.dart';
|
|
|
|
part 'drift_db.g.dart';
|
|
|
|
// Define the database
|
|
@DriftDatabase(tables: [ChatMessages, PostDrafts])
|
|
class AppDatabase extends _$AppDatabase {
|
|
AppDatabase(super.e);
|
|
|
|
@override
|
|
int get schemaVersion => 6;
|
|
|
|
@override
|
|
MigrationStrategy get migration => MigrationStrategy(
|
|
onCreate: (Migrator m) async {
|
|
await m.createAll();
|
|
},
|
|
onUpgrade: (Migrator m, int from, int to) async {
|
|
if (from < 2) {
|
|
// Add isRead column with default value false
|
|
await m.addColumn(chatMessages, chatMessages.isRead);
|
|
}
|
|
if (from < 4) {
|
|
// Drop old draft tables if they exist
|
|
await m.createTable(postDrafts);
|
|
}
|
|
if (from < 6) {
|
|
// Migrate from old schema to new schema with separate searchable fields
|
|
await _migrateToVersion6(m);
|
|
}
|
|
},
|
|
);
|
|
|
|
Future<void> _migrateToVersion6(Migrator m) async {
|
|
// Rename existing table to old if it exists
|
|
try {
|
|
await customStatement(
|
|
'ALTER TABLE post_drafts RENAME TO post_drafts_old',
|
|
);
|
|
} catch (e) {
|
|
// Table might not exist
|
|
}
|
|
|
|
// Drop the table
|
|
await customStatement('DROP TABLE IF EXISTS post_drafts');
|
|
|
|
// Create new table
|
|
await m.createTable(postDrafts);
|
|
|
|
// Migrate existing data if any
|
|
try {
|
|
final oldDrafts =
|
|
await customSelect(
|
|
'SELECT id, post, lastModified FROM post_drafts_old',
|
|
readsFrom: {postDrafts},
|
|
).get();
|
|
|
|
for (final row in oldDrafts) {
|
|
final postJson = row.read<String>('post');
|
|
final id = row.read<String>('id');
|
|
final lastModified = row.read<DateTime>('lastModified');
|
|
|
|
if (postJson.isNotEmpty) {
|
|
final post = SnPost.fromJson(jsonDecode(postJson));
|
|
await into(postDrafts).insert(
|
|
PostDraftsCompanion(
|
|
id: Value(id),
|
|
title: Value(post.title),
|
|
description: Value(post.description),
|
|
content: Value(post.content),
|
|
visibility: Value(post.visibility),
|
|
type: Value(post.type),
|
|
lastModified: Value(lastModified),
|
|
postData: Value(postJson),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Drop old table
|
|
await customStatement('DROP TABLE IF EXISTS post_drafts_old');
|
|
} catch (e) {
|
|
// If migration fails, just recreate the table
|
|
await m.createTable(postDrafts);
|
|
}
|
|
}
|
|
|
|
// Methods for chat messages
|
|
Future<List<ChatMessage>> getMessagesForRoom(
|
|
String roomId, {
|
|
int offset = 0,
|
|
int limit = 20,
|
|
}) {
|
|
return (select(chatMessages)
|
|
..where((m) => m.roomId.equals(roomId))
|
|
..orderBy([(m) => OrderingTerm.desc(m.createdAt)])
|
|
..limit(limit, offset: offset))
|
|
.get();
|
|
}
|
|
|
|
Future<int> saveMessage(ChatMessagesCompanion message) {
|
|
return into(chatMessages).insert(message, mode: InsertMode.insertOrReplace);
|
|
}
|
|
|
|
Future<int> updateMessage(ChatMessagesCompanion message) {
|
|
return into(chatMessages).insert(message, mode: InsertMode.insertOrReplace);
|
|
}
|
|
|
|
Future<int> updateMessageStatus(String id, MessageStatus status) {
|
|
return (update(chatMessages)..where(
|
|
(m) => m.id.equals(id),
|
|
)).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();
|
|
}
|
|
|
|
Future<int> getTotalMessagesForRoom(String roomId) {
|
|
return (select(
|
|
chatMessages,
|
|
)..where((m) => m.roomId.equals(roomId))).get().then((list) => list.length);
|
|
}
|
|
|
|
Future<List<LocalChatMessage>> searchMessages(
|
|
String roomId,
|
|
String query,
|
|
) async {
|
|
var selectStatement = select(chatMessages)
|
|
..where((m) => m.roomId.equals(roomId));
|
|
|
|
if (query.isNotEmpty) {
|
|
selectStatement =
|
|
selectStatement
|
|
..where((m) => m.content.like('%${query.toLowerCase()}%'));
|
|
}
|
|
|
|
final messages =
|
|
await (selectStatement
|
|
..orderBy([(m) => OrderingTerm.desc(m.createdAt)]))
|
|
.get();
|
|
return messages.map((msg) => companionToMessage(msg)).toList();
|
|
}
|
|
|
|
// Convert between Drift and model objects
|
|
ChatMessagesCompanion messageToCompanion(LocalChatMessage message) {
|
|
return ChatMessagesCompanion(
|
|
id: Value(message.id),
|
|
roomId: Value(message.roomId),
|
|
senderId: Value(message.senderId),
|
|
content: Value(message.toRemoteMessage().content),
|
|
nonce: Value(message.nonce),
|
|
data: Value(jsonEncode(message.data)),
|
|
createdAt: Value(message.createdAt),
|
|
status: Value(message.status),
|
|
isRead: Value(message.isRead),
|
|
);
|
|
}
|
|
|
|
LocalChatMessage companionToMessage(ChatMessage dbMessage) {
|
|
final data = jsonDecode(dbMessage.data);
|
|
return LocalChatMessage(
|
|
id: dbMessage.id,
|
|
roomId: dbMessage.roomId,
|
|
senderId: dbMessage.senderId,
|
|
data: data,
|
|
createdAt: dbMessage.createdAt,
|
|
status: dbMessage.status,
|
|
nonce: dbMessage.nonce,
|
|
isRead: dbMessage.isRead,
|
|
);
|
|
}
|
|
|
|
// Methods for post drafts
|
|
Future<List<SnPost>> getAllPostDrafts() async {
|
|
final drafts = await select(postDrafts).get();
|
|
return drafts
|
|
.map((draft) => SnPost.fromJson(jsonDecode(draft.postData)))
|
|
.toList();
|
|
}
|
|
|
|
Future<List<PostDraft>> getAllPostDraftRecords() async {
|
|
return await select(postDrafts).get();
|
|
}
|
|
|
|
Future<List<PostDraft>> searchPostDrafts(String query) async {
|
|
if (query.isEmpty) {
|
|
return await select(postDrafts).get();
|
|
}
|
|
|
|
final searchTerm = '%${query.toLowerCase()}%';
|
|
return await (select(postDrafts)
|
|
..where(
|
|
(draft) =>
|
|
draft.title.like(searchTerm) |
|
|
draft.description.like(searchTerm) |
|
|
draft.content.like(searchTerm),
|
|
)
|
|
..orderBy([(draft) => OrderingTerm.desc(draft.lastModified)]))
|
|
.get();
|
|
}
|
|
|
|
Future<void> addPostDraft(PostDraftsCompanion entry) async {
|
|
await into(postDrafts).insert(entry, mode: InsertMode.replace);
|
|
}
|
|
|
|
Future<void> deletePostDraft(String id) async {
|
|
await (delete(postDrafts)..where((tbl) => tbl.id.equals(id))).go();
|
|
}
|
|
|
|
Future<void> clearAllPostDrafts() async {
|
|
await delete(postDrafts).go();
|
|
}
|
|
|
|
Future<PostDraft?> getPostDraftById(String id) async {
|
|
return await (select(postDrafts)
|
|
..where((tbl) => tbl.id.equals(id))).getSingleOrNull();
|
|
}
|
|
}
|