Notification updates

This commit is contained in:
Eric Gullickson
2025-12-21 19:56:52 -06:00
parent 144f1d5bb0
commit 719c80ecd8
80 changed files with 7552 additions and 678 deletions

View File

@@ -5,40 +5,74 @@ import type { DocumentRecord, DocumentType } from '../domain/documents.types';
export class DocumentsRepository {
constructor(private readonly db: Pool = pool) {}
// ========================
// Row Mapper
// ========================
private mapDocumentRecord(row: any): DocumentRecord {
return {
id: row.id,
userId: row.user_id,
vehicleId: row.vehicle_id,
documentType: row.document_type,
title: row.title,
notes: row.notes,
details: row.details,
storageBucket: row.storage_bucket,
storageKey: row.storage_key,
fileName: row.file_name,
contentType: row.content_type,
fileSize: row.file_size,
fileHash: row.file_hash,
issuedDate: row.issued_date,
expirationDate: row.expiration_date,
emailNotifications: row.email_notifications,
createdAt: row.created_at,
updatedAt: row.updated_at,
deletedAt: row.deleted_at
};
}
// ========================
// CRUD Operations
// ========================
async insert(doc: {
id: string;
user_id: string;
vehicle_id: string;
document_type: DocumentType;
userId: string;
vehicleId: string;
documentType: DocumentType;
title: string;
notes?: string | null;
details?: any;
issued_date?: string | null;
expiration_date?: string | null;
issuedDate?: string | null;
expirationDate?: string | null;
emailNotifications?: boolean;
}): Promise<DocumentRecord> {
const res = await this.db.query(
`INSERT INTO documents (
id, user_id, vehicle_id, document_type, title, notes, details, issued_date, expiration_date
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)
id, user_id, vehicle_id, document_type, title, notes, details, issued_date, expiration_date, email_notifications
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
RETURNING *`,
[
doc.id,
doc.user_id,
doc.vehicle_id,
doc.document_type,
doc.userId,
doc.vehicleId,
doc.documentType,
doc.title,
doc.notes ?? null,
doc.details ?? null,
doc.issued_date ?? null,
doc.expiration_date ?? null,
doc.issuedDate ?? null,
doc.expirationDate ?? null,
doc.emailNotifications ?? false,
]
);
return res.rows[0] as DocumentRecord;
return this.mapDocumentRecord(res.rows[0]);
}
async findById(id: string, userId: string): Promise<DocumentRecord | null> {
const res = await this.db.query(`SELECT * FROM documents WHERE id = $1 AND user_id = $2 AND deleted_at IS NULL`, [id, userId]);
return res.rows[0] || null;
return res.rows[0] ? this.mapDocumentRecord(res.rows[0]) : null;
}
async listByUser(userId: string, filters?: { vehicleId?: string; type?: DocumentType; expiresBefore?: string }): Promise<DocumentRecord[]> {
@@ -50,31 +84,32 @@ export class DocumentsRepository {
if (filters?.expiresBefore) { conds.push(`expiration_date <= $${i++}`); params.push(filters.expiresBefore); }
const sql = `SELECT * FROM documents WHERE ${conds.join(' AND ')} ORDER BY created_at DESC`;
const res = await this.db.query(sql, params);
return res.rows as DocumentRecord[];
return res.rows.map(row => this.mapDocumentRecord(row));
}
async softDelete(id: string, userId: string): Promise<void> {
await this.db.query(`UPDATE documents SET deleted_at = NOW() WHERE id = $1 AND user_id = $2`, [id, userId]);
}
async updateMetadata(id: string, userId: string, patch: Partial<Pick<DocumentRecord, 'title'|'notes'|'details'|'issued_date'|'expiration_date'>>): Promise<DocumentRecord | null> {
async updateMetadata(id: string, userId: string, patch: Partial<Pick<DocumentRecord, 'title'|'notes'|'details'|'issuedDate'|'expirationDate'|'emailNotifications'>>): Promise<DocumentRecord | null> {
const fields: string[] = [];
const params: any[] = [];
let i = 1;
if (patch.title !== undefined) { fields.push(`title = $${i++}`); params.push(patch.title); }
if (patch.notes !== undefined) { fields.push(`notes = $${i++}`); params.push(patch.notes); }
if (patch.details !== undefined) { fields.push(`details = $${i++}`); params.push(patch.details); }
if (patch.issued_date !== undefined) { fields.push(`issued_date = $${i++}`); params.push(patch.issued_date); }
if (patch.expiration_date !== undefined) { fields.push(`expiration_date = $${i++}`); params.push(patch.expiration_date); }
if (patch.issuedDate !== undefined) { fields.push(`issued_date = $${i++}`); params.push(patch.issuedDate); }
if (patch.expirationDate !== undefined) { fields.push(`expiration_date = $${i++}`); params.push(patch.expirationDate); }
if (patch.emailNotifications !== undefined) { fields.push(`email_notifications = $${i++}`); params.push(patch.emailNotifications); }
if (!fields.length) return this.findById(id, userId);
params.push(id, userId);
const sql = `UPDATE documents SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} AND deleted_at IS NULL RETURNING *`;
const res = await this.db.query(sql, params);
return res.rows[0] || null;
return res.rows[0] ? this.mapDocumentRecord(res.rows[0]) : null;
}
async updateStorageMeta(id: string, userId: string, meta: {
storage_bucket: string; storage_key: string; file_name: string; content_type: string; file_size: number; file_hash?: string | null;
storageBucket: string; storageKey: string; fileName: string; contentType: string; fileSize: number; fileHash?: string | null;
}): Promise<DocumentRecord | null> {
const res = await this.db.query(
`UPDATE documents SET
@@ -86,9 +121,9 @@ export class DocumentsRepository {
file_hash = $6
WHERE id = $7 AND user_id = $8 AND deleted_at IS NULL
RETURNING *`,
[meta.storage_bucket, meta.storage_key, meta.file_name, meta.content_type, meta.file_size, meta.file_hash ?? null, id, userId]
[meta.storageBucket, meta.storageKey, meta.fileName, meta.contentType, meta.fileSize, meta.fileHash ?? null, id, userId]
);
return res.rows[0] || null;
return res.rows[0] ? this.mapDocumentRecord(res.rows[0]) : null;
}
}