Files
Toju/server/src/cqrs/mappers.ts

107 lines
3.0 KiB
TypeScript

import { AuthUserEntity } from '../entities/AuthUserEntity';
import { ServerEntity } from '../entities/ServerEntity';
import { JoinRequestEntity } from '../entities/JoinRequestEntity';
import {
AuthUserPayload,
ServerChannelPayload,
ServerPayload,
JoinRequestPayload
} from './types';
function channelNameKey(type: ServerChannelPayload['type'], name: string): string {
return `${type}:${name.toLocaleLowerCase()}`;
}
function parseStringArray(raw: string | null | undefined): string[] {
try {
const parsed = JSON.parse(raw || '[]');
return Array.isArray(parsed)
? parsed.filter((value): value is string => typeof value === 'string')
: [];
} catch {
return [];
}
}
function parseServerChannels(raw: string | null | undefined): ServerChannelPayload[] {
try {
const parsed = JSON.parse(raw || '[]');
if (!Array.isArray(parsed)) {
return [];
}
const seenIds = new Set<string>();
const seenNames = new Set<string>();
return parsed
.filter((channel): channel is Record<string, unknown> => !!channel && typeof channel === 'object')
.map((channel, index) => {
const id = typeof channel.id === 'string' ? channel.id.trim() : '';
const name = typeof channel.name === 'string' ? channel.name.trim().replace(/\s+/g, ' ') : '';
const type = channel.type === 'text' || channel.type === 'voice' ? channel.type : null;
const position = typeof channel.position === 'number' ? channel.position : index;
const nameKey = type ? channelNameKey(type, name) : '';
if (!id || !name || !type || seenIds.has(id) || seenNames.has(nameKey)) {
return null;
}
seenIds.add(id);
seenNames.add(nameKey);
return {
id,
name,
type,
position
} satisfies ServerChannelPayload;
})
.filter((channel): channel is ServerChannelPayload => !!channel);
} catch {
return [];
}
}
export function rowToAuthUser(row: AuthUserEntity): AuthUserPayload {
return {
id: row.id,
username: row.username,
passwordHash: row.passwordHash,
displayName: row.displayName,
createdAt: row.createdAt
};
}
export function rowToServer(row: ServerEntity): ServerPayload {
return {
id: row.id,
name: row.name,
description: row.description ?? undefined,
ownerId: row.ownerId,
ownerPublicKey: row.ownerPublicKey,
hasPassword: !!row.passwordHash,
passwordHash: row.passwordHash ?? undefined,
isPrivate: !!row.isPrivate,
maxUsers: row.maxUsers,
currentUsers: row.currentUsers,
tags: parseStringArray(row.tags),
channels: parseServerChannels(row.channels),
createdAt: row.createdAt,
lastSeen: row.lastSeen
};
}
export function rowToJoinRequest(row: JoinRequestEntity): JoinRequestPayload {
return {
id: row.id,
serverId: row.serverId,
userId: row.userId,
userPublicKey: row.userPublicKey,
displayName: row.displayName,
status: row.status as JoinRequestPayload['status'],
createdAt: row.createdAt
};
}