import type pg from 'pg'; import { BrandSlugAlreadyExistsError } from '../domain/errors.js'; import type { Brand, BrandPatch, NewBrand } from '../domain/brand.js'; import type { BrandRepository } from '../domain/ports.js'; interface BrandRow { id: string; name: string; slug: string; seo_title: string | null; seo_description: string | null; created_at: Date; updated_at: Date; } const UNIQUE_VIOLATION = '23505'; const UPDATABLE: ReadonlyArray<[keyof BrandPatch, string]> = [ ['name', 'name'], ['slug', 'slug'], ['seoTitle', 'seo_title'], ['seoDescription', 'seo_description'], ]; export class PgBrandRepository implements BrandRepository { constructor(private readonly pool: pg.Pool) {} async findById(id: string): Promise { const result = await this.pool.query('SELECT * FROM brands_brands WHERE id = $1', [ id, ]); const row = result.rows[0]; return row ? toBrand(row) : undefined; } async findBySlug(slug: string): Promise { const result = await this.pool.query('SELECT * FROM brands_brands WHERE slug = $1', [ slug, ]); const row = result.rows[0]; return row ? toBrand(row) : undefined; } async list(): Promise { const result = await this.pool.query( 'SELECT * FROM brands_brands ORDER BY name ASC, id ASC', ); return result.rows.map(toBrand); } async create(input: NewBrand): Promise { try { const result = await this.pool.query( `INSERT INTO brands_brands (name, slug, seo_title, seo_description) VALUES ($1, $2, $3, $4) RETURNING *`, [input.name, input.slug, input.seoTitle ?? null, input.seoDescription ?? null], ); const row = result.rows[0]; if (!row) { throw new Error('brands_brands INSERT returned no row'); } return toBrand(row); } catch (error) { if (isPgError(error, UNIQUE_VIOLATION)) { throw new BrandSlugAlreadyExistsError(); } throw error; } } async update(id: string, patch: BrandPatch): Promise { const setClauses: string[] = []; const values: unknown[] = []; for (const [key, column] of UPDATABLE) { if (key in patch) { values.push(patch[key]); setClauses.push(`${column} = $${values.length}`); } } if (setClauses.length === 0) { return this.findById(id); } values.push(id); try { const result = await this.pool.query( `UPDATE brands_brands SET ${setClauses.join(', ')}, updated_at = now() WHERE id = $${values.length} RETURNING *`, values, ); const row = result.rows[0]; return row ? toBrand(row) : undefined; } catch (error) { if (isPgError(error, UNIQUE_VIOLATION)) { throw new BrandSlugAlreadyExistsError(); } throw error; } } async delete(id: string): Promise { await this.pool.query('DELETE FROM brands_brands WHERE id = $1', [id]); } } function toBrand(row: BrandRow): Brand { return { id: row.id, name: row.name, slug: row.slug, seoTitle: row.seo_title, seoDescription: row.seo_description, createdAt: row.created_at, updatedAt: row.updated_at, }; } function isPgError(error: unknown, code: string): boolean { return typeof error === 'object' && error !== null && 'code' in error && error.code === code; }