117 lines
4.2 KiB
TypeScript
117 lines
4.2 KiB
TypeScript
/**
|
|
* In-Memory User Repository
|
|
*
|
|
* Stores users in memory for demo/development purposes.
|
|
*/
|
|
|
|
import { Logger } from '@core/shared/application';
|
|
import type { IUserRepository, StoredUser } from '../../domain/repositories/IUserRepository';
|
|
|
|
export class InMemoryUserRepository implements IUserRepository {
|
|
private users: Map<string, StoredUser> = new Map();
|
|
private emailIndex: Map<string, string> = new Map(); // email -> userId
|
|
private readonly logger: Logger;
|
|
|
|
constructor(logger: Logger, initialUsers: StoredUser[] = []) {
|
|
this.logger = logger;
|
|
this.logger.info('InMemoryUserRepository initialized.');
|
|
for (const user of initialUsers) {
|
|
this.users.set(user.id, user);
|
|
this.emailIndex.set(user.email.toLowerCase(), user.id);
|
|
this.logger.debug(`Seeded user: ${user.id} (${user.email}).`);
|
|
}
|
|
}
|
|
|
|
async findByEmail(email: string): Promise<StoredUser | null> {
|
|
this.logger.debug(`Finding user by email: ${email}`);
|
|
try {
|
|
const userId = this.emailIndex.get(email.toLowerCase());
|
|
if (!userId) {
|
|
this.logger.warn(`User with email ${email} not found.`);
|
|
return null;
|
|
}
|
|
const user = this.users.get(userId) ?? null;
|
|
if (user) {
|
|
this.logger.info(`Found user by email: ${email}.`);
|
|
} else {
|
|
this.logger.warn(`User with ID ${userId} (from email index) not found.`);
|
|
}
|
|
return user;
|
|
} catch (error) {
|
|
this.logger.error(`Error finding user by email ${email}:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async findById(id: string): Promise<StoredUser | null> {
|
|
this.logger.debug(`Finding user by id: ${id}`);
|
|
try {
|
|
const user = this.users.get(id) ?? null;
|
|
if (user) {
|
|
this.logger.info(`Found user: ${id}.`);
|
|
} else {
|
|
this.logger.warn(`User with id ${id} not found.`);
|
|
}
|
|
return user;
|
|
} catch (error) {
|
|
this.logger.error(`Error finding user by id ${id}:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async create(user: StoredUser): Promise<StoredUser> {
|
|
this.logger.debug(`Creating user: ${user.id} with email: ${user.email}`);
|
|
try {
|
|
if (this.emailIndex.has(user.email.toLowerCase())) {
|
|
this.logger.warn(`Email ${user.email} already exists.`);
|
|
throw new Error('Email already exists');
|
|
}
|
|
this.users.set(user.id, user);
|
|
this.emailIndex.set(user.email.toLowerCase(), user.id);
|
|
this.logger.info(`User ${user.id} (${user.email}) created successfully.`);
|
|
return user;
|
|
} catch (error) {
|
|
this.logger.error(`Error creating user ${user.id} (${user.email}):`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async update(user: StoredUser): Promise<StoredUser> {
|
|
this.logger.debug(`Updating user: ${user.id} with email: ${user.email}`);
|
|
try {
|
|
const existing = this.users.get(user.id);
|
|
if (!existing) {
|
|
this.logger.warn(`User with ID ${user.id} not found for update.`);
|
|
throw new Error('User not found');
|
|
}
|
|
// If email changed, update index
|
|
if (existing.email.toLowerCase() !== user.email.toLowerCase()) {
|
|
if (this.emailIndex.has(user.email.toLowerCase()) && this.emailIndex.get(user.email.toLowerCase()) !== user.id) {
|
|
this.logger.warn(`Cannot update user ${user.id} to email ${user.email} as it's already taken.`);
|
|
throw new Error('Email already exists for another user');
|
|
}
|
|
this.logger.debug(`Updating email index from ${existing.email} to ${user.email}.`);
|
|
this.emailIndex.delete(existing.email.toLowerCase());
|
|
this.emailIndex.set(user.email.toLowerCase(), user.id);
|
|
}
|
|
this.users.set(user.id, user);
|
|
this.logger.info(`User ${user.id} (${user.email}) updated successfully.`);
|
|
return user;
|
|
} catch (error) {
|
|
this.logger.error(`Error updating user ${user.id} (${user.email}):`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async emailExists(email: string): Promise<boolean> {
|
|
this.logger.debug(`Checking existence of email: ${email}`);
|
|
try {
|
|
const exists = this.emailIndex.has(email.toLowerCase());
|
|
this.logger.debug(`Email ${email} exists: ${exists}.`);
|
|
return exists;
|
|
} catch (error) {
|
|
this.logger.error(`Error checking existence of email ${email}:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
} |