import { Injectable } from '@angular/core'; import { Dexie, EntityTable, liveQuery } from 'Dexie'; import { err, ok } from 'neverthrow'; import { z } from 'zod'; import { from, Observable, Subject } from 'rxjs'; import { filter, switchMap } from 'rxjs/operators'; import { MessageInputDTO } from '../../dto/message/messageInputDtO'; const tableSchema = z.object({ id: z.any().optional(), messageId: z.string().optional(), roomId: z.string().uuid(), senderId: z.number(), message: z.string(), messageType: z.number(), canEdit: z.boolean(), oneShot: z.boolean(), sentAt: z.string().optional(), requireUnlock: z.boolean(), sender: z.object({ wxUserId: z.number(), wxFullName: z.string(), wxeMail: z.string(), userPhoto: z.string(), }), sending: z.boolean().optional() }) export type TableMessage = z.infer // Database declaration (move this to its own module also) export const messageDataSource = new Dexie('chat-message') as Dexie & { message: EntityTable; }; messageDataSource.version(1).stores({ message: '++id, roomId, senderId, message, messageType, canEdit, oneShot, requireUnlock, messageId' }); @Injectable({ providedIn: 'root' }) export class MessageLocalDataSourceService { messageSubject = new Subject(); constructor() { messageDataSource.message.hook('creating', (primKey, obj, trans) => { // const newMessage = await trans.table('message').get(primKey); this.messageSubject.next(obj); // return newMessage }) } async sendMessage(data: MessageInputDTO) { (data as TableMessage).sending = true try { const result = await messageDataSource.message.add(data) return ok(result as string) } catch (e) { return err(false) } } async createMessage(data: MessageInputDTO) { try { const result = await messageDataSource.message.add(data) return ok(result as string) } catch (e) { return err(false) } } async update(data: TableMessage ) { try { const result = await messageDataSource.message.update(data.id, data) return ok(result) } catch (e) { return err(false) } } async findOrUpdate(data: TableMessage) { const findResult = await this.findMessageById(data.messageId) if(findResult.isOk()) { return this.update({...findResult.value, ...data}) } else { return this.createMessage(data) } } getItemsLive(roomId: string) { return liveQuery(() => messageDataSource.message.where('roomId').equals(roomId).sortBy('id') ) } async findMessageById(messageId: string) { try { const a = await messageDataSource.message.where('messageId').equals(messageId).first() if(a) { return ok(a) } else { return err('not found') } } catch (e) { return err('DB error') } } subscribeToNewMessage(roomId: string): Observable { return this.messageSubject.pipe( filter((message: TableMessage) => message.roomId === roomId ) ) } }