import { Injectable, inject } from '@angular/core'; import { Message, User, Room, Reaction, BanEntry } from '../../shared-kernel'; import type { ElectronApi } from '../../core/platform/electron/electron-api.models'; import { ElectronBridgeService } from '../../core/platform/electron/electron-bridge.service'; /** * Database service for the Electron (desktop) runtime. * * The SQLite database is managed by TypeORM in the Electron main process. * This service is a thin CQRS IPC client that dispatches structured * command/query objects through the unified preload channels. */ @Injectable({ providedIn: 'root' }) export class ElectronDatabaseService { private readonly electronBridge = inject(ElectronBridgeService); /** Shorthand accessor for the preload-exposed CQRS API. */ private get api(): ElectronApi { return this.electronBridge.requireApi(); } /** * No-op: the database is initialised in the main process before the * renderer window opens and requires no explicit bootstrap call here. */ async initialize(): Promise { /* no-op */ } /** Persist a single chat message. */ saveMessage(message: Message): Promise { return this.api.command({ type: 'save-message', payload: { message } }); } /** * Retrieve the latest messages for a room, sorted oldest-first for display. * * @param roomId - Target room. * @param limit - Maximum number of messages to return. * @param offset - Number of newer messages to skip (for pagination). * @param channelId - Optional channel scope; 'general' includes null/empty. * @param beforeTimestamp - Optional cursor; only messages strictly older * than this timestamp are returned (scroll-up paging). */ getMessages( roomId: string, limit = 100, offset = 0, channelId?: string, beforeTimestamp?: number ): Promise { return this.api.query({ type: 'get-messages', payload: { roomId, limit, offset, channelId, beforeTimestamp } }); } getMessagesSince(roomId: string, sinceTimestamp: number): Promise { return this.api.query({ type: 'get-messages-since', payload: { roomId, sinceTimestamp } }); } /** Permanently delete a message by ID. */ deleteMessage(messageId: string): Promise { return this.api.command({ type: 'delete-message', payload: { messageId } }); } /** Apply partial updates to an existing message. */ updateMessage(messageId: string, updates: Partial): Promise { return this.api.command({ type: 'update-message', payload: { messageId, updates } }); } /** Retrieve a single message by ID, or `null` if not found. */ getMessageById(messageId: string): Promise { return this.api.query({ type: 'get-message-by-id', payload: { messageId } }); } /** Remove every message belonging to a room. */ clearRoomMessages(roomId: string): Promise { return this.api.command({ type: 'clear-room-messages', payload: { roomId } }); } /** Persist a reaction (deduplication is handled main-process side). */ saveReaction(reaction: Reaction): Promise { return this.api.command({ type: 'save-reaction', payload: { reaction } }); } /** Remove a specific reaction (user + emoji + message). */ removeReaction(messageId: string, userId: string, emoji: string): Promise { return this.api.command({ type: 'remove-reaction', payload: { messageId, userId, emoji } }); } /** Return all reactions for a given message. */ getReactionsForMessage(messageId: string): Promise { return this.api.query({ type: 'get-reactions-for-message', payload: { messageId } }); } /** Persist a user record. */ saveUser(user: User): Promise { return this.api.command({ type: 'save-user', payload: { user } }); } /** Retrieve a user by ID, or `null` if not found. */ getUser(userId: string): Promise { return this.api.query({ type: 'get-user', payload: { userId } }); } /** Retrieve the last-authenticated ("current") user, or `null`. */ getCurrentUser(): Promise { return this.api.query({ type: 'get-current-user', payload: {} }); } /** Retrieve the persisted current user ID without loading the full user. */ getCurrentUserId(): Promise { return this.api.query({ type: 'get-current-user-id', payload: {} }); } /** Store which user ID is considered "current" (logged-in). */ setCurrentUserId(userId: string): Promise { return this.api.command({ type: 'set-current-user-id', payload: { userId } }); } /** Retrieve users associated with a room. */ getUsersByRoom(roomId: string): Promise { return this.api.query({ type: 'get-users-by-room', payload: { roomId } }); } /** Apply partial updates to an existing user. */ updateUser(userId: string, updates: Partial): Promise { return this.api.command({ type: 'update-user', payload: { userId, updates } }); } /** Persist a room record. */ saveRoom(room: Room): Promise { return this.api.command({ type: 'save-room', payload: { room } }); } /** Retrieve a room by ID, or `null` if not found. */ getRoom(roomId: string): Promise { return this.api.query({ type: 'get-room', payload: { roomId } }); } /** Return every persisted room. */ getAllRooms(): Promise { return this.api.query({ type: 'get-all-rooms', payload: {} }); } /** Delete a room by ID (also removes its messages). */ deleteRoom(roomId: string): Promise { return this.api.command({ type: 'delete-room', payload: { roomId } }); } /** Apply partial updates to an existing room. */ updateRoom(roomId: string, updates: Partial): Promise { return this.api.command({ type: 'update-room', payload: { roomId, updates } }); } /** Persist a ban entry. */ saveBan(ban: BanEntry): Promise { return this.api.command({ type: 'save-ban', payload: { ban } }); } /** Remove a ban by the banned user's `oderId`. */ removeBan(oderId: string): Promise { return this.api.command({ type: 'remove-ban', payload: { oderId } }); } /** Return active bans for a room. */ getBansForRoom(roomId: string): Promise { return this.api.query({ type: 'get-bans-for-room', payload: { roomId } }); } /** Check whether a user is currently banned from a room. */ isUserBanned(userId: string, roomId: string): Promise { return this.api.query({ type: 'is-user-banned', payload: { userId, roomId } }); } /** Persist attachment metadata. */ // eslint-disable-next-line saveAttachment(attachment: any): Promise { return this.api.command({ type: 'save-attachment', payload: { attachment } }); } /** Return all attachment records for a message. */ // eslint-disable-next-line getAttachmentsForMessage(messageId: string): Promise { // eslint-disable-next-line return this.api.query({ type: 'get-attachments-for-message', payload: { messageId } }); } /** Return every persisted attachment record. */ // eslint-disable-next-line getAllAttachments(): Promise { // eslint-disable-next-line return this.api.query({ type: 'get-all-attachments', payload: {} }); } /** Delete all attachment records for a message. */ deleteAttachmentsForMessage(messageId: string): Promise { return this.api.command({ type: 'delete-attachments-for-message', payload: { messageId } }); } /** Wipe every table, removing all persisted data. */ clearAllData(): Promise { return this.api.command({ type: 'clear-all-data', payload: {} }); } }