fix: coerce decimals in fuel-logs enhanced repository methods (#244) #245

Merged
egullickson merged 1 commits from issue-244-fuel-logs-enhanced-mapper into main 2026-05-16 02:58:52 +00:00
2 changed files with 26 additions and 12 deletions
Showing only changes of commit 0d90829d31 - Show all commits

View File

@@ -247,6 +247,20 @@ export class FuelLogsRepository {
}; };
} }
// Coerces DECIMAL columns from node-postgres strings to numbers while
// preserving snake_case row keys used by the enhanced API service callers.
private mapEnhancedRow(row: any): any {
if (!row) return null;
return {
...row,
fuel_units: row.fuel_units != null ? parseFloat(row.fuel_units) : row.fuel_units,
cost_per_unit: row.cost_per_unit != null ? parseFloat(row.cost_per_unit) : row.cost_per_unit,
total_cost: row.total_cost != null ? parseFloat(row.total_cost) : row.total_cost,
gallons: row.gallons != null ? parseFloat(row.gallons) : row.gallons,
price_per_gallon: row.price_per_gallon != null ? parseFloat(row.price_per_gallon) : row.price_per_gallon,
};
}
// Enhanced API support (new schema) // Enhanced API support (new schema)
async createEnhanced(data: { async createEnhanced(data: {
userId: string; userId: string;
@@ -293,7 +307,7 @@ export class FuelLogsRepository {
data.notes ?? null data.notes ?? null
]; ];
const res = await this.pool.query(query, values); const res = await this.pool.query(query, values);
return res.rows[0] ?? null; return this.mapEnhancedRow(res.rows[0] ?? null);
} }
async findByVehicleIdEnhanced(vehicleId: string): Promise<any[]> { async findByVehicleIdEnhanced(vehicleId: string): Promise<any[]> {
@@ -301,7 +315,7 @@ export class FuelLogsRepository {
`SELECT * FROM fuel_logs WHERE vehicle_id = $1 ORDER BY date_time DESC NULLS LAST, date DESC NULLS LAST, created_at DESC`, `SELECT * FROM fuel_logs WHERE vehicle_id = $1 ORDER BY date_time DESC NULLS LAST, date DESC NULLS LAST, created_at DESC`,
[vehicleId] [vehicleId]
); );
return res.rows; return res.rows.map(r => this.mapEnhancedRow(r));
} }
async findByUserIdEnhanced(userId: string): Promise<any[]> { async findByUserIdEnhanced(userId: string): Promise<any[]> {
@@ -309,12 +323,12 @@ export class FuelLogsRepository {
`SELECT * FROM fuel_logs WHERE user_id = $1 ORDER BY date_time DESC NULLS LAST, date DESC NULLS LAST, created_at DESC`, `SELECT * FROM fuel_logs WHERE user_id = $1 ORDER BY date_time DESC NULLS LAST, date DESC NULLS LAST, created_at DESC`,
[userId] [userId]
); );
return res.rows; return res.rows.map(r => this.mapEnhancedRow(r));
} }
async findByIdEnhanced(id: string): Promise<any | null> { async findByIdEnhanced(id: string): Promise<any | null> {
const res = await this.pool.query(`SELECT * FROM fuel_logs WHERE id = $1`, [id]); const res = await this.pool.query(`SELECT * FROM fuel_logs WHERE id = $1`, [id]);
return res.rows[0] ?? null; return this.mapEnhancedRow(res.rows[0] ?? null);
} }
async getPreviousLogByOdometer(vehicleId: string, odometerReading: number): Promise<any | null> { async getPreviousLogByOdometer(vehicleId: string, odometerReading: number): Promise<any | null> {
@@ -322,7 +336,7 @@ export class FuelLogsRepository {
`SELECT * FROM fuel_logs WHERE vehicle_id = $1 AND odometer IS NOT NULL AND odometer < $2 ORDER BY odometer DESC LIMIT 1`, `SELECT * FROM fuel_logs WHERE vehicle_id = $1 AND odometer IS NOT NULL AND odometer < $2 ORDER BY odometer DESC LIMIT 1`,
[vehicleId, odometerReading] [vehicleId, odometerReading]
); );
return res.rows[0] ?? null; return this.mapEnhancedRow(res.rows[0] ?? null);
} }
async getLatestLogForVehicle(vehicleId: string): Promise<any | null> { async getLatestLogForVehicle(vehicleId: string): Promise<any | null> {
@@ -330,7 +344,7 @@ export class FuelLogsRepository {
`SELECT * FROM fuel_logs WHERE vehicle_id = $1 ORDER BY date_time DESC NULLS LAST, date DESC NULLS LAST, created_at DESC LIMIT 1`, `SELECT * FROM fuel_logs WHERE vehicle_id = $1 ORDER BY date_time DESC NULLS LAST, date DESC NULLS LAST, created_at DESC LIMIT 1`,
[vehicleId] [vehicleId]
); );
return res.rows[0] ?? null; return this.mapEnhancedRow(res.rows[0] ?? null);
} }
async updateEnhanced(id: string, data: { async updateEnhanced(id: string, data: {
@@ -416,6 +430,6 @@ export class FuelLogsRepository {
return null; return null;
} }
return result.rows[0]; return this.mapEnhancedRow(result.rows[0]);
} }
} }

View File

@@ -234,8 +234,8 @@ export class FuelLogsService {
return { logCount: 0, totalFuelUnits: 0, totalCost: 0, averageCostPerUnit: 0, totalDistance: 0, averageEfficiency: 0, unitLabels: labels }; return { logCount: 0, totalFuelUnits: 0, totalCost: 0, averageCostPerUnit: 0, totalDistance: 0, averageEfficiency: 0, unitLabels: labels };
} }
const totalFuelUnits = rows.reduce((s, r) => s + (Number(r.fuel_units) || 0), 0); const totalFuelUnits = rows.reduce((s, r) => s + (r.fuel_units || 0), 0);
const totalCost = rows.reduce((s, r) => s + (Number(r.total_cost) || 0), 0); const totalCost = rows.reduce((s, r) => s + (r.total_cost || 0), 0);
const averageCostPerUnit = totalFuelUnits > 0 ? totalCost / totalFuelUnits : 0; const averageCostPerUnit = totalFuelUnits > 0 ? totalCost / totalFuelUnits : 0;
const sorted = [...rows].sort((a, b) => (new Date(b.date_time || b.date)).getTime() - (new Date(a.date_time || a.date)).getTime()); const sorted = [...rows].sort((a, b) => (new Date(b.date_time || b.date)).getTime() - (new Date(a.date_time || a.date)).getTime());
@@ -282,9 +282,9 @@ export class FuelLogsService {
tripDistance: row.trip_distance ?? undefined, tripDistance: row.trip_distance ?? undefined,
fuelType: row.fuel_type as FuelType, fuelType: row.fuel_type as FuelType,
fuelGrade: row.fuel_grade ?? undefined, fuelGrade: row.fuel_grade ?? undefined,
fuelUnits: Number(row.fuel_units), fuelUnits: row.fuel_units ?? 0,
costPerUnit: Number(row.cost_per_unit), costPerUnit: row.cost_per_unit ?? 0,
totalCost: Number(row.total_cost), totalCost: row.total_cost ?? 0,
locationData: row.location_data ?? undefined, locationData: row.location_data ?? undefined,
notes: row.notes ?? undefined, notes: row.notes ?? undefined,
efficiency: efficiency, efficiency: efficiency,