import type { Low } from 'lowdb'; import { nanoid } from 'nanoid'; import { type New, type Updated } from '../../types'; import { type Group, type GroupError, GroupErrors } from '../../types/group'; import type { IGroupRepo } from '../groupRepo'; import type { LowStorage } from './_init'; export class LowGroupRepo implements IGroupRepo { private readonly db; constructor(db: Low) { this.db = db; } async getAll(): Promise { return this.db.data.groups; } async getById(id: string): Promise { return this.db.data.groups.find((g) => g.id === id); } async create(group: New): Promise { if (this.db.data.groups.find((g) => g.name === group.name)) { return GroupErrors.DUPLICATE_NAME; } for (const deviceId of group.devices) { if (!this.db.data.devices.some((d) => d.id === deviceId)) { return GroupErrors.UNKNOWN_DEVICE; } } await this.db.update(({ groups }) => { groups.push({ id: nanoid(), ...group }); }); return undefined; } async update(group: Updated): Promise { if (this.db.data.groups.find((g) => g.name === group.name && g.id !== group.id)) { return GroupErrors.DUPLICATE_NAME; } for (const deviceId of group.devices ?? []) { if (!this.db.data.devices.some((d) => d.id === deviceId)) { return GroupErrors.UNKNOWN_DEVICE; } } let found = false; await this.db.update(({ groups }) => { const existingGroup = groups.find((g) => g.id === group.id); if (!existingGroup) return; Object.assign(existingGroup, group); found = true; }); return found ? undefined : GroupErrors.NOT_FOUND; } async delete(groupId: string): Promise { let found = false; this.db.data.groups = this.db.data.groups.filter((g) => { if (g.id === groupId) { found = true; return false; } return true; }); if (found) { this.db.data.users.forEach((u) => (u.groups = u.groups.filter((gid) => gid != groupId))); await this.db.write(); } return found ? undefined : GroupErrors.NOT_FOUND; } async countUsers(groupId: string): Promise { return this.db.data.users.filter((u) => u.groups.includes(groupId)).length; } }