separate database from source data

This commit is contained in:
Peter Maquiran
2024-08-07 19:30:20 +01:00
parent 75a8822e57
commit 159eb8d350
17 changed files with 189 additions and 197 deletions
@@ -1,12 +1,12 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams } from '@ionic/angular'; import { ModalController, NavParams } from '@ionic/angular';
import { TableMemberList } from 'src/app/module/chat/data/data-source/room/rooom-local-data-source.service';
import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service'; import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service';
import { ThemeService } from 'src/app/services/theme.service' import { ThemeService } from 'src/app/services/theme.service'
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
import { Observable as DexieObservable } from 'Dexie'; import { Observable as DexieObservable } from 'Dexie';
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service'; import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service';
import { MemberTable } from 'src/app/module/chat/infra/database/dexie/schema/members';
@Component({ @Component({
selector: 'app-set-room-owner', selector: 'app-set-room-owner',
@@ -18,7 +18,7 @@ export class SetRoomOwnerPage implements OnInit {
textSearch:string = ""; textSearch:string = "";
roomId:any; roomId:any;
members:any; members:any;
roomMembers$: DexieObservable<TableMemberList[] | undefined> roomMembers$: DexieObservable<MemberTable[] | undefined>
constructor( constructor(
private modalController: ModalController, private modalController: ModalController,
@@ -45,7 +45,7 @@ export class SetRoomOwnerPage implements OnInit {
this.textSearch = event.detail.value; this.textSearch = event.detail.value;
} }
separateLetter(record:TableMemberList, recordIndex, records:TableMemberList[]) { separateLetter(record:MemberTable, recordIndex, records:MemberTable[]) {
if(recordIndex == 0){ if(recordIndex == 0){
return record.wxFullName[0]; return record.wxFullName[0];
} }
@@ -59,7 +59,7 @@ export class SetRoomOwnerPage implements OnInit {
return null; return null;
} }
async setRoomOwner(user:TableMemberList) { async setRoomOwner(user:MemberTable) {
const result = await this.chatServiceService.setAdmin({ const result = await this.chatServiceService.setAdmin({
roomId: user.roomId, roomId: user.roomId,
@@ -1,4 +1,3 @@
import { TableRoom } from "../../../data-source/room/rooom-local-data-source.service";
import { RoomListItemOutPutDTO, RoomListOutPutDTO } from "../../../dto/room/roomListOutputDTO"; import { RoomListItemOutPutDTO, RoomListOutPutDTO } from "../../../dto/room/roomListOutputDTO";
export function messageListDetermineChanges(serverList: any[], localList: any[]) { export function messageListDetermineChanges(serverList: any[], localList: any[]) {
@@ -1,7 +1,7 @@
import { TableRoom } from "../../../data-source/room/rooom-local-data-source.service"; import { RoomTable } from "src/app/module/chat/infra/database/dexie/schema/room";
import { RoomListItemOutPutDTO, RoomListOutPutDTO } from "../../../dto/room/roomListOutputDTO"; import { RoomListItemOutPutDTO, RoomListOutPutDTO } from "../../../dto/room/roomListOutputDTO";
export function roomListDetermineChanges(serverRooms: RoomListItemOutPutDTO[], localRooms: TableRoom[]) { export function roomListDetermineChanges(serverRooms: RoomListItemOutPutDTO[], localRooms: RoomTable[]) {
const serverRoomMap = new Map(serverRooms.map(room => [room.chatRoom.id, room])); const serverRoomMap = new Map(serverRooms.map(room => [room.chatRoom.id, room]));
const localRoomMap = new Map(localRooms.map(room => [room.id, room])); const localRoomMap = new Map(localRooms.map(room => [room.id, room]));
@@ -1,7 +1,7 @@
import { TableMemberList } from "../../../data-source/room/rooom-local-data-source.service"; import { MemberTable } from "src/app/module/chat/infra/database/dexie/schema/members";
import { RoomByIdMemberItemOutputDTO } from "../../../dto/room/roomByIdOutputDTO"; import { RoomByIdMemberItemOutputDTO } from "../../../dto/room/roomByIdOutputDTO";
export function roomMemberListDetermineChanges(____serverRooms: RoomByIdMemberItemOutputDTO[], localRooms: TableMemberList[], roomId: string) { export function roomMemberListDetermineChanges(____serverRooms: RoomByIdMemberItemOutputDTO[], localRooms: MemberTable[], roomId: string) {
const PServerRooms: (RoomByIdMemberItemOutputDTO & {$roomIdUserId: string})[] = ____serverRooms.map( e=> { const PServerRooms: (RoomByIdMemberItemOutputDTO & {$roomIdUserId: string})[] = ____serverRooms.map( e=> {
@@ -5,7 +5,7 @@ import { z } from 'zod';
import { DexieRepository } from 'src/app/infra/repository/dexie/dexie-repository.service'; import { DexieRepository } from 'src/app/infra/repository/dexie/dexie-repository.service';
const TableMemberListSchema = z.object({ const MemberTableSchema = z.object({
$roomIdUserId: z.string().optional(), $roomIdUserId: z.string().optional(),
id: z.string(), id: z.string(),
roomId: z.string(), roomId: z.string(),
@@ -19,12 +19,12 @@ const TableMemberListSchema = z.object({
status: z.string() status: z.string()
}) })
export type ITableMemberList = z.infer<typeof TableMemberListSchema> export type IMemberTable = z.infer<typeof MemberTableSchema>
type ITableMemberListSchema = EntityTable<ITableMemberList, '$roomIdUserId'> type IMemberTableSchema = EntityTable<IMemberTable, '$roomIdUserId'>
// Database declaration (move this to its own module also) // Database declaration (move this to its own module also)
export const roomMemberList = new Dexie('roomMemberList') as Dexie & { export const roomMemberList = new Dexie('roomMemberList') as Dexie & {
memberList: EntityTable<ITableMemberList, '$roomIdUserId'>; memberList: EntityTable<IMemberTable, '$roomIdUserId'>;
}; };
roomMemberList.version(1).stores({ roomMemberList.version(1).stores({
@@ -34,7 +34,7 @@ roomMemberList.version(1).stores({
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class MemberListLocalDataSourceService extends DexieRepository<ITableMemberList> { export class MemberListLocalDataSourceService extends DexieRepository<IMemberTable> {
constructor() { constructor() {
super(roomMemberList.memberList); super(roomMemberList.memberList);
@@ -1,91 +1,30 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Dexie, EntityTable, liveQuery } from 'Dexie'; import { Dexie, EntityTable, liveQuery } from 'Dexie';
import { err, ok, Result } from 'neverthrow'; import { err, ok, Result } from 'neverthrow';
import { z } from 'zod';
import { from, Observable, Subject } from 'rxjs'; import { from, Observable, Subject } from 'rxjs';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { MessageInputDTO } from '../../dto/message/messageInputDtO'; import { MessageInputDTO } from '../../dto/message/messageInputDtO';
import { MessageEntity } from '../../../domain/entity/message'; import { MessageEntity } from '../../../domain/entity/message';
import { DexieRepository } from 'src/app/infra/repository/dexie/dexie-repository.service'; import { DexieRepository } from 'src/app/infra/repository/dexie/dexie-repository.service';
import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message';
import { chatDatabase } from '../../../infra/database/dexie/service';
const tableSchema = z.object({
$id: z.number().optional(),
id: z.string().optional(),
roomId: z.string().uuid(),
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(),
reaction: z.object({
id: z.string(),
reactedAt: z.string(),
reaction: z.string(),
sender: z.object({}),
}).array()
})
export const IncomingMessageSchema = z.object({
messageId: z.string().optional(),
roomId: z.string().uuid(),
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<typeof tableSchema>
// Database declaration (move this to its own module also)
export const messageDataSource = new Dexie('chat-message') as Dexie & {
message: EntityTable<TableMessage, '$id'>;
};
messageDataSource.version(1).stores({
message: '++$id, id, roomId, message, messageType, canEdit, oneShot, requireUnlock, messageId, info'
});
messageDataSource.message.mapToClass(MessageEntity);
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class MessageLocalDataSourceService extends DexieRepository<TableMessage> { export class MessageLocalDataSourceService extends DexieRepository<MessageTable> {
messageSubject = new Subject(); messageSubject = new Subject();
constructor() { constructor() {
super(messageDataSource.message) super(chatDatabase.message)
// messageDataSource.message.hook('creating', (primKey, obj, trans) => {
// // const newMessage = await trans.table('message').get(primKey);
// this.messageSubject.next(obj);
// // return newMessage
// })
} }
async setAllSenderToFalse() { async setAllSenderToFalse() {
try { try {
await messageDataSource.transaction('rw', messageDataSource.message, async () => { await chatDatabase.transaction('rw', chatDatabase.message, async () => {
// Perform the update operation within the transaction // Perform the update operation within the transaction
await messageDataSource.message.toCollection().modify({ sending: false }); await chatDatabase.message.toCollection().modify({ sending: false });
}); });
console.log('All messages updated successfully.'); console.log('All messages updated successfully.');
} catch (error) { } catch (error) {
@@ -93,10 +32,10 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
} }
async getLastMessageByRoomId(roomId: string): Promise<Result<undefined|TableMessage, any>> { async getLastMessageByRoomId(roomId: string): Promise<Result<undefined|MessageTable, any>> {
try { try {
console.log({roomId}) console.log({roomId})
const lastMessage = await messageDataSource.message const lastMessage = await chatDatabase.message
.where('roomId') .where('roomId')
.equals(roomId) .equals(roomId)
.reverse() .reverse()
@@ -108,10 +47,10 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
} }
async deleteByMessageId(id: string): Promise<Result<undefined|TableMessage, any>> { async deleteByMessageId(id: string): Promise<Result<undefined|MessageTable, any>> {
try { try {
console.log(id) console.log(id)
const lastMessage = await messageDataSource.message const lastMessage = await chatDatabase.message
.where('id') .where('id')
.equals(id).delete() .equals(id).delete()
@@ -124,10 +63,10 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
async sendMessage(data: MessageInputDTO) { async sendMessage(data: MessageInputDTO) {
(data as TableMessage).sending = true (data as MessageTable).sending = true
try { try {
const result = await messageDataSource.message.add(data) const result = await chatDatabase.message.add(data)
this.messageSubject.next({roomId: data.roomId}); this.messageSubject.next({roomId: data.roomId});
return ok(result as number) return ok(result as number)
} catch (e) { } catch (e) {
@@ -137,16 +76,12 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
incomingSocketMessage() {
}
// @ValidateSchema(tableSchema) // @ValidateSchema(tableSchema)
async createMessage(data: MessageInputDTO) { async createMessage(data: MessageInputDTO) {
try { try {
const result = await messageDataSource.message.add(data) const result = await chatDatabase.message.add(data)
this.messageSubject.next({roomId: data.roomId}); this.messageSubject.next({roomId: data.roomId});
return ok(result) return ok(result)
} catch (e) { } catch (e) {
@@ -158,7 +93,7 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
async createManyMessage(data: MessageInputDTO[]) { async createManyMessage(data: MessageInputDTO[]) {
try { try {
const result = await messageDataSource.message.bulkAdd(data) const result = await chatDatabase.message.bulkAdd(data)
this.messageSubject.next({roomId: data[0].roomId}); this.messageSubject.next({roomId: data[0].roomId});
return ok(result) return ok(result)
} catch (e) { } catch (e) {
@@ -172,7 +107,7 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
console.log({id}); console.log({id});
const existingMessage = await messageDataSource.message const existingMessage = await chatDatabase.message
.where('id') .where('id')
.equals(id) .equals(id)
.first(); .first();
@@ -190,10 +125,10 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
// not used // not used
async updateByMessageId(data: TableMessage ) { async updateByMessageId(data: MessageTable ) {
try { try {
const result = await messageDataSource.message.update(data.id as any, data) const result = await chatDatabase.message.update(data.id as any, data)
return ok(result) return ok(result)
} catch (e) { } catch (e) {
return err(false) return err(false)
@@ -202,7 +137,7 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
async findOrUpdate(data: TableMessage) { async findOrUpdate(data: MessageTable) {
const findResult = await this.findMessageById(data.id) const findResult = await this.findMessageById(data.id)
if(findResult.isOk()) { if(findResult.isOk()) {
@@ -213,17 +148,17 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
getItems(roomId: string) { getItems(roomId: string) {
return messageDataSource.message.where('roomId').equals(roomId).toArray() return chatDatabase.message.where('roomId').equals(roomId).toArray()
} }
getItemsLive(roomId: string) { getItemsLive(roomId: string) {
return liveQuery(() => messageDataSource.message.where('roomId').equals(roomId).sortBy('$id')) return liveQuery(() => chatDatabase.message.where('roomId').equals(roomId).sortBy('$id'))
} }
async findMessageById(id: string) { async findMessageById(id: string) {
try { try {
const a = await messageDataSource.message.where('id').equals(id).first() const a = await chatDatabase.message.where('id').equals(id).first()
if(a) { if(a) {
return ok(a) return ok(a)
@@ -238,9 +173,9 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
} }
subscribeToNewMessage(roomId: string): Observable<TableMessage> { subscribeToNewMessage(roomId: string): Observable<MessageTable> {
return this.messageSubject.pipe( return this.messageSubject.pipe(
filter((message: TableMessage) => filter((message: MessageTable) =>
message.roomId === roomId message.roomId === roomId
) )
) )
@@ -249,7 +184,7 @@ export class MessageLocalDataSourceService extends DexieRepository<TableMessage>
async getOfflineMessages () { async getOfflineMessages () {
try { try {
const allMessages = await messageDataSource.message const allMessages = await chatDatabase.message
.filter(msg => typeof msg.id !== 'string' && msg.sending == false) .filter(msg => typeof msg.id !== 'string' && msg.sending == false)
.toArray(); .toArray();
@@ -1,10 +1,10 @@
import { createAction, createFeatureSelector, createReducer, createSelector, on, props } from "@ngrx/store"; import { createAction, createFeatureSelector, createReducer, createSelector, on, props } from "@ngrx/store";
import { TableRoom } from "./rooom-local-data-source.service";
import { RoomOutPutDTO } from "../../dto/room/roomOutputDTO"; import { RoomOutPutDTO } from "../../dto/room/roomOutputDTO";
import { RoomTable } from "../../../infra/database/dexie/schema/room";
export interface ChatRoom { export interface ChatRoom {
[roomId: string]: TableRoom[]; [roomId: string]: RoomTable[];
} }
export interface RoomRemoteDataSourceState { export interface RoomRemoteDataSourceState {
@@ -5,72 +5,24 @@ import { err, ok, Result } from 'neverthrow';
import { z } from 'zod'; import { z } from 'zod';
import { ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; import { ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator';
import { MemberListUPdateStatusInputDTO } from '../../../domain/use-case/socket/member-list-update-status-use-case.service'; import { MemberListUPdateStatusInputDTO } from '../../../domain/use-case/socket/member-list-update-status-use-case.service';
import { MemberTable } from '../../../infra/database/dexie/schema/members';
import { chatDatabase } from '../../../infra/database/dexie/service';
import { RoomTable, RoomTableSchema } from '../../../infra/database/dexie/schema/room';
import { TypingTableSchema } from '../../../infra/database/dexie/schema/typing';
const tableSchema = z.object({
id: z.string(),
roomName: z.string(),
createdBy: z.object({
wxUserId: z.number(),
wxFullName: z.string(),
wxeMail: z.string().email(),
userPhoto: z.string().nullable().optional()// api check
}),
createdAt: z.any(),
expirationDate: z.any().nullable(),
})
const TableMemberListSchema = z.object({
$roomIdUserId: z.string().optional(),
id: z.string(),
roomId: z.string(),
wxUserId: z.number(),
wxFullName: z.string(),
wxeMail: z.string(),
userPhoto: z.string().nullable(),
joinAt: z.string(),
status: z.string(),
isAdmin: z.boolean()
})
export const TypingSchema = z.object({
id: z.string().optional(),
userId: z.string(),
roomId: z.string(),
entryDate: z.string()
})
export type TableRoom = z.infer<typeof tableSchema>
export type TableMemberList = z.infer<typeof TableMemberListSchema>
export type TypingList = z.infer<typeof TypingSchema>
// Database declaration (move this to its own module also)
export const roomDataSource = new Dexie('FriendDatabase') as Dexie & {
room: EntityTable<TableRoom, 'id'>;
memberList: EntityTable<TableMemberList, '$roomIdUserId'>;
typing: EntityTable<TableMemberList, '$roomIdUserId'>;
};
roomDataSource.version(1).stores({
room: 'id, createdBy, roomName, roomType, expirationDate, lastMessage',
memberList: '$roomIdUserId, userId, id, user, joinAt, roomId, status, wxUserId, isAdmin',
TypingList: '++id, userId, roomId, entryDate',
});
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class RoomLocalDataSourceService { export class RoomLocalDataSourceService {
private baseUrl = 'https://gdapi-dev.dyndns.info/stage/api/v2/Chat'; // Your base URL
constructor() {} constructor() {}
@ValidateSchema(TypingSchema) @ValidateSchema(TypingTableSchema)
async addUserTyping(data: any) { async addUserTyping(data: any) {
try { try {
const result = await roomDataSource.typing.add(data) const result = await chatDatabase.typing.add(data)
return ok(result) return ok(result)
} catch (e) { } catch (e) {
return err(false) return err(false)
@@ -81,10 +33,10 @@ export class RoomLocalDataSourceService {
} }
@ValidateSchema(tableSchema) @ValidateSchema(RoomTableSchema)
async createRoom(data: TableRoom) { async createRoom(data: RoomTable) {
try { try {
const result = await roomDataSource.room.add(data) const result = await chatDatabase.room.add(data)
return ok(result) return ok(result)
} catch (e) { } catch (e) {
return err(false) return err(false)
@@ -94,7 +46,7 @@ export class RoomLocalDataSourceService {
async deleteRoomById(id: string) { async deleteRoomById(id: string) {
try { try {
const result = await roomDataSource.room.delete(id) const result = await chatDatabase.room.delete(id)
return ok(result) return ok(result)
} catch (e) { } catch (e) {
return err(false) return err(false)
@@ -106,9 +58,9 @@ export class RoomLocalDataSourceService {
return this.deleteRoomById(id) return this.deleteRoomById(id)
} }
async updateRoom(data: TableRoom) { async updateRoom(data: RoomTable) {
try { try {
const result = await roomDataSource.room.update(data.id, data); const result = await chatDatabase.room.update(data.id, data);
return ok(result) return ok(result)
} catch (e) { } catch (e) {
@@ -116,7 +68,7 @@ export class RoomLocalDataSourceService {
} }
} }
async createOrUpdateRoom(data: TableRoom) { async createOrUpdateRoom(data: RoomTable) {
const createResult = await this.createRoom(data) const createResult = await this.createRoom(data)
if(createResult.isOk()) { if(createResult.isOk()) {
@@ -127,19 +79,19 @@ export class RoomLocalDataSourceService {
} }
async addMember(data: TableMemberList) { async addMember(data: MemberTable) {
try { try {
data.$roomIdUserId = data.roomId + data.wxUserId data.$roomIdUserId = data.roomId + data.wxUserId
const result = await roomDataSource.memberList.add(data) const result = await chatDatabase.members.add(data)
return ok(result) return ok(result)
} catch (e) { } catch (e) {
return err(false) return err(false)
} }
} }
async updateMemberRole(data: TableMemberList) { async updateMemberRole(data: MemberTable) {
try { try {
const result = await roomDataSource.memberList.where({ const result = await chatDatabase.members.where({
wxUserId:data.wxUserId, wxUserId:data.wxUserId,
roomId: data.roomId, roomId: data.roomId,
}).modify(data); }).modify(data);
@@ -152,10 +104,10 @@ export class RoomLocalDataSourceService {
async updateMembersStatus(data: MemberListUPdateStatusInputDTO) { async updateMembersStatus(data: MemberListUPdateStatusInputDTO) {
try { try {
await roomDataSource.memberList.toCollection().modify({ status: 'offline' }); await chatDatabase.members.toCollection().modify({ status: 'offline' });
for (const item of data) { for (const item of data) {
const wxUserId = item.value.userId; // Extract wxUserId const wxUserId = item.value.userId; // Extract wxUserId
await roomDataSource.memberList.where('wxUserId').equals(wxUserId).modify({ status: 'online' }); await chatDatabase.members.where('wxUserId').equals(wxUserId).modify({ status: 'online' });
} }
return ok(true) return ok(true)
} catch (error) { } catch (error) {
@@ -167,7 +119,7 @@ export class RoomLocalDataSourceService {
allMemberOnline(roomId:string) { allMemberOnline(roomId:string) {
return liveQuery(async () => { return liveQuery(async () => {
const allMessages = await roomDataSource.memberList const allMessages = await chatDatabase.members
.where('roomId') .where('roomId')
.equals(roomId) .equals(roomId)
.toArray(); .toArray();
@@ -179,10 +131,10 @@ export class RoomLocalDataSourceService {
async removeMemberFromRoom($roomIdUserId): Promise<Result<any ,any>> { async removeMemberFromRoom($roomIdUserId): Promise<Result<any ,any>> {
try { try {
const member = await roomDataSource.memberList.where({ $roomIdUserId: $roomIdUserId }).first(); const member = await chatDatabase.members.where({ $roomIdUserId: $roomIdUserId }).first();
if (member) { if (member) {
const result = await ok(roomDataSource.memberList.delete($roomIdUserId)); const result = await ok(chatDatabase.members.delete($roomIdUserId));
console.log(`Member with $roomIdUserId ${$roomIdUserId} removed from room ${member.roomId}.`); console.log(`Member with $roomIdUserId ${$roomIdUserId} removed from room ${member.roomId}.`);
return result return result
} else { } else {
@@ -197,7 +149,7 @@ export class RoomLocalDataSourceService {
async getRoomById(id: any) { async getRoomById(id: any) {
try { try {
const result = await roomDataSource.room.get(id) const result = await chatDatabase.room.get(id)
return ok(result) return ok(result)
} catch (e) { } catch (e) {
return err(false) return err(false)
@@ -206,32 +158,32 @@ export class RoomLocalDataSourceService {
async getRoomList() { async getRoomList() {
return await roomDataSource.room.toArray() return await chatDatabase.room.toArray()
} }
getMemberLive(data: {roomId, wxUserId}) { getMemberLive(data: {roomId, wxUserId}) {
const $roomIdUserId = data.roomId + data.wxUserId const $roomIdUserId = data.roomId + data.wxUserId
return liveQuery(() => roomDataSource.memberList.get($roomIdUserId)) as any; return liveQuery(() => chatDatabase.members.get($roomIdUserId)) as any;
} }
getItemsLive(): Observable<RoomListOutPutDTO[]> { getItemsLive(): Observable<RoomListOutPutDTO[]> {
return liveQuery(() => roomDataSource.room.toArray()) as any; return liveQuery(() => chatDatabase.room.toArray()) as any;
} }
getRoomByIdLive(id: any): Observable<RoomListItemOutPutDTO | undefined> { getRoomByIdLive(id: any): Observable<RoomListItemOutPutDTO | undefined> {
return liveQuery(() => roomDataSource.room.get(id)) as any; return liveQuery(() => chatDatabase.room.get(id)) as any;
} }
async getRoomMemberById(roomId: any) { async getRoomMemberById(roomId: any) {
return await roomDataSource.memberList.where({roomId}).toArray() return await chatDatabase.members.where({roomId}).toArray()
} }
getRoomMemberByIdLive(roomId: any) { getRoomMemberByIdLive(roomId: any) {
return liveQuery(() => roomDataSource.memberList.where({roomId}).toArray()) return liveQuery(() => chatDatabase.members.where({roomId}).toArray())
} }
getRoomMemberNoneAdminByIdLive(roomId: any) { getRoomMemberNoneAdminByIdLive(roomId: any) {
return liveQuery(async() => { return liveQuery(async() => {
const members = await roomDataSource.memberList.where({roomId}).toArray() const members = await chatDatabase.members.where({roomId}).toArray()
return members.filter(e => e.isAdmin != true) return members.filter(e => e.isAdmin != true)
}) })
} }
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MessageRemoteDataSourceService } from '../data-source/message/message-remote-data-source.service'; import { MessageRemoteDataSourceService } from '../data-source/message/message-remote-data-source.service';
import { MessageLiveDataSourceService } from '../data-source/message/message-live-data-source.service'; import { MessageLiveDataSourceService } from '../data-source/message/message-live-data-source.service';
import { MessageLocalDataSourceService, TableMessage } from '../data-source/message/message-local-data-source.service'; import { MessageLocalDataSourceService } from '../data-source/message/message-local-data-source.service';
import { SessionStore } from 'src/app/store/session.service'; import { SessionStore } from 'src/app/store/session.service';
import { SignalRService } from '../../infra/socket/signal-r.service'; import { SignalRService } from '../../infra/socket/signal-r.service';
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
@@ -13,6 +13,7 @@ import { MessageEntity } from '../../domain/entity/message';
import { InstanceId } from '../../domain/chat-service.service'; import { InstanceId } from '../../domain/chat-service.service';
import { MessageMapper } from '../../domain/mapper/messageMapper'; import { MessageMapper } from '../../domain/mapper/messageMapper';
import { MessageOutPutDataDTO } from '../dto/message/messageOutputDTO'; import { MessageOutPutDataDTO } from '../dto/message/messageOutputDTO';
import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message';
@Injectable({ @Injectable({
@@ -55,7 +56,7 @@ export class MessageRepositoryService {
delete sendMessageResult.value.sender delete sendMessageResult.value.sender
} }
let clone: TableMessage = { let clone: MessageTable = {
...sendMessageResult.value, ...sendMessageResult.value,
id: sendMessageResult.value.id, id: sendMessageResult.value.id,
$id : localActionResult.value $id : localActionResult.value
@@ -115,13 +116,13 @@ export class MessageRepositoryService {
const { addedItems, changedItems } = messageListDetermineChanges(result.value.data, localResult) const { addedItems, changedItems } = messageListDetermineChanges(result.value.data, localResult)
for(const message of changedItems) { for(const message of changedItems) {
let clone: TableMessage = message let clone: MessageTable = message
clone.roomId = id clone.roomId = id
await this.messageLocalDataSourceService.findOrUpdate(clone) await this.messageLocalDataSourceService.findOrUpdate(clone)
} }
for(const message of addedItems) { for(const message of addedItems) {
let clone: TableMessage = message let clone: MessageTable = message
clone.roomId = id clone.roomId = id
} }
@@ -1,12 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { SignalRService } from '../../../infra/socket/signal-r.service'; import { SignalRService } from '../../../infra/socket/signal-r.service';
import { MessageLiveDataSourceService } from '../../data-source/message/message-live-data-source.service'; import { MessageLiveDataSourceService } from '../../data-source/message/message-live-data-source.service';
import { MessageLocalDataSourceService, TableMessage } from '../../data-source/message/message-local-data-source.service'; import { MessageLocalDataSourceService } from '../../data-source/message/message-local-data-source.service';
import { MessageRemoteDataSourceService } from '../../data-source/message/message-remote-data-source.service'; import { MessageRemoteDataSourceService } from '../../data-source/message/message-remote-data-source.service';
import { InstanceId } from '../../../domain/chat-service.service'; import { InstanceId } from '../../../domain/chat-service.service';
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { MessageMapper } from 'src/app/module/chat/domain/mapper/messageMapper' import { MessageMapper } from 'src/app/module/chat/domain/mapper/messageMapper'
import { MessageOutPutDataDTO } from '../../dto/message/messageOutputDTO'; import { MessageOutPutDataDTO } from '../../dto/message/messageOutputDTO';
import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -44,7 +45,7 @@ export class SyncMessageRepositoryService {
delete sendMessageResult.value.sender delete sendMessageResult.value.sender
} }
let clone: TableMessage = { let clone: MessageTable = {
...sendMessageResult.value, ...sendMessageResult.value,
id: sendMessageResult.value.id, id: sendMessageResult.value.id,
$id : message.$id $id : message.$id
@@ -1,7 +1,8 @@
import { TableMemberList } from "../../data/data-source/room/rooom-local-data-source.service";
import { RoomByIdMemberItemOutputDTO } from "../../data/dto/room/roomByIdOutputDTO";
export function MemberListMapper(outputDto: RoomByIdMemberItemOutputDTO, roomId: string): TableMemberList { import { RoomByIdMemberItemOutputDTO } from "../../data/dto/room/roomByIdOutputDTO";
import { MemberTable } from "../../infra/database/dexie/schema/members";
export function MemberListMapper(outputDto: RoomByIdMemberItemOutputDTO, roomId: string): MemberTable {
return { return {
roomId: roomId, roomId: roomId,
wxUserId: outputDto.user.wxUserId, wxUserId: outputDto.user.wxUserId,
@@ -0,0 +1,19 @@
import { z } from "zod";
import { EntityTable } from 'Dexie';
export const MemberTableSchema = z.object({
$roomIdUserId: z.string().optional(),
id: z.string(),
roomId: z.string(),
wxUserId: z.number(),
wxFullName: z.string(),
wxeMail: z.string(),
userPhoto: z.string().nullable(),
joinAt: z.string(),
status: z.string(),
isAdmin: z.boolean()
})
export type MemberTable = z.infer<typeof MemberTableSchema>
export type DexieMembersTableSchema = EntityTable<MemberTable, '$roomIdUserId'>;
export const MemberTableColumn = '$roomIdUserId, userId, id, user, joinAt, roomId, status, wxUserId, isAdmin'
@@ -0,0 +1,31 @@
import { z } from "zod";
import { EntityTable } from 'Dexie';
export const MessageTable = z.object({
$id: z.number().optional(),
id: z.string().optional(),
roomId: z.string().uuid(),
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(),
reaction: z.object({
id: z.string(),
reactedAt: z.string(),
reaction: z.string(),
sender: z.object({}),
}).array()
})
export type MessageTable = z.infer<typeof MessageTable>
export type DexieMessageTable = EntityTable<MessageTable, '$id'>;
export const messageTableColumn = '++id, roomId, senderId, message, messageType, canEdit, oneShot, requireUnlock'
@@ -0,0 +1,19 @@
import { z } from "zod";
import { EntityTable } from 'Dexie';
export const RoomTableSchema = z.object({
id: z.string(),
roomName: z.string(),
createdBy: z.object({
wxUserId: z.number(),
wxFullName: z.string(),
wxeMail: z.string().email(),
userPhoto: z.string().nullable().optional()// api check
}),
createdAt: z.any(),
expirationDate: z.any().nullable(),
})
export type RoomTable = z.infer<typeof RoomTableSchema>
export type DexieRoomsTableSchema = EntityTable<RoomTable, 'id'>;
export const RoomTableColumn = 'id, createdBy, roomName, roomType, expirationDate, lastMessage'
@@ -0,0 +1,13 @@
import { z } from "zod";
import { EntityTable } from 'Dexie';
export const TypingTableSchema = z.object({
id: z.string().optional(),
userId: z.string(),
roomId: z.string(),
entryDate: z.string()
})
export type TypingTable = z.infer<typeof TypingTableSchema>
export type DexieTypingsTableSchema = EntityTable<TypingTable, 'id'>;
export const TypingTableColumn = '++id, userId, roomId, entryDate'
@@ -0,0 +1,21 @@
import { Dexie, EntityTable, liveQuery } from 'Dexie';
import { DexieMessageTable, messageTableColumn, MessageTable } from './schema/message';
import { DexieMembersTableSchema, MemberTableColumn } from './schema/members';
import { DexieRoomsTableSchema, RoomTableColumn } from './schema/room';
import { DexieTypingsTableSchema, TypingTableColumn } from './schema/typing';
// Database declaration (move this to its own module also)
export const chatDatabase = new Dexie('chat-database') as Dexie & {
message: DexieMessageTable,
members: DexieMembersTableSchema,
room: DexieRoomsTableSchema,
typing: DexieTypingsTableSchema
};
chatDatabase.version(1).stores({
message: messageTableColumn,
members: MemberTableColumn,
room: RoomTableColumn,
typing: TypingTableColumn
});
@@ -36,8 +36,7 @@ import { Observable as DexieObservable } from 'Dexie';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
import { MessageRepositoryService } from 'src/app/module/chat/data/repository/message-respository.service' import { MessageRepositoryService } from 'src/app/module/chat/data/repository/message-respository.service'
import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service' import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service'
import { TableMessage } from 'src/app/module/chat/data/data-source/message/message-local-data-source.service'; import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message';
import { TableMemberList } from 'src/app/module/chat/data/data-source/room/rooom-local-data-source.service';
import { MessageInputDTO } from 'src/app/module/chat/data/dto/message/messageInputDtO'; import { MessageInputDTO } from 'src/app/module/chat/data/dto/message/messageInputDtO';
import { RoomListItemOutPutDTO } from 'src/app/module/chat/data/dto/room/roomListOutputDTO'; import { RoomListItemOutPutDTO } from 'src/app/module/chat/data/dto/room/roomListOutputDTO';
import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository/user-typing-repository.service'; import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository/user-typing-repository.service';
@@ -46,6 +45,7 @@ import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.serv
import { EditMessagePage } from 'src/app/modals/edit-message/edit-message.page'; import { EditMessagePage } from 'src/app/modals/edit-message/edit-message.page';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { MessageEntity } from 'src/app/module/chat/domain/entity/message'; import { MessageEntity } from 'src/app/module/chat/domain/entity/message';
import { MemberTable } from 'src/app/module/chat/infra/database/dexie/schema/members';
const IMAGE_DIR = 'stored-images'; const IMAGE_DIR = 'stored-images';
@@ -125,8 +125,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
roomData$: DexieObservable<RoomListItemOutPutDTO | undefined> roomData$: DexieObservable<RoomListItemOutPutDTO | undefined>
roomStatus$: DexieObservable<Boolean > roomStatus$: DexieObservable<Boolean >
roomMessage$: DexieObservable<TableMessage[]> roomMessage$: DexieObservable<MessageTable[]>
roomMembers$: DexieObservable<TableMemberList[] | undefined> roomMembers$: DexieObservable<MemberTable[] | undefined>
//userTyping$: DexieObservable<UserTypingList[] | undefined> //userTyping$: DexieObservable<UserTypingList[] | undefined>
userTyping$: UserTypingList[] | undefined userTyping$: UserTypingList[] | undefined
newMessagesStream!: Subscription newMessagesStream!: Subscription