From 9d1954eb6fe60480aaf384a5e368d70a837590fc Mon Sep 17 00:00:00 2001 From: Davide Ferrari Date: Sun, 11 Jan 2026 18:02:59 +0100 Subject: [PATCH] feat(stats): add SQL query for max distance between charges Uses SQLite LAG window function to efficiently find the maximum distance traveled between consecutive charges. Includes both all-time and date-range variants for year filtering support. --- .../data/local/dao/ChargeSummaryDao.kt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/app/src/main/java/com/matedroid/data/local/dao/ChargeSummaryDao.kt b/app/src/main/java/com/matedroid/data/local/dao/ChargeSummaryDao.kt index ffdb2bd..86d4b3b 100644 --- a/app/src/main/java/com/matedroid/data/local/dao/ChargeSummaryDao.kt +++ b/app/src/main/java/com/matedroid/data/local/dao/ChargeSummaryDao.kt @@ -157,4 +157,80 @@ interface ChargeSummaryDao { ORDER BY year DESC """) suspend fun getYears(carId: Int): List + + // === Window Function Queries (requires API 29+) === + + /** + * Find the maximum distance traveled between two consecutive charges. + * Uses LAG window function to get the previous charge's odometer. + */ + @Query(""" + WITH consecutive_charges AS ( + SELECT + chargeId, + startDate, + odometer, + LAG(chargeId) OVER (ORDER BY startDate) as prevChargeId, + LAG(startDate) OVER (ORDER BY startDate) as prevDate, + LAG(odometer) OVER (ORDER BY startDate) as prevOdometer + FROM charges_summary + WHERE carId = :carId + ) + SELECT + prevChargeId as fromChargeId, + chargeId as toChargeId, + odometer - prevOdometer as distance, + prevDate as fromDate, + startDate as toDate + FROM consecutive_charges + WHERE prevOdometer IS NOT NULL + ORDER BY distance DESC + LIMIT 1 + """) + suspend fun maxDistanceBetweenCharges(carId: Int): MaxDistanceBetweenChargesResult? + + /** + * Find the maximum distance traveled between two consecutive charges within a date range. + * Both charges must be within the range. + */ + @Query(""" + WITH consecutive_charges AS ( + SELECT + chargeId, + startDate, + odometer, + LAG(chargeId) OVER (ORDER BY startDate) as prevChargeId, + LAG(startDate) OVER (ORDER BY startDate) as prevDate, + LAG(odometer) OVER (ORDER BY startDate) as prevOdometer + FROM charges_summary + WHERE carId = :carId + ) + SELECT + prevChargeId as fromChargeId, + chargeId as toChargeId, + odometer - prevOdometer as distance, + prevDate as fromDate, + startDate as toDate + FROM consecutive_charges + WHERE prevOdometer IS NOT NULL + AND prevDate >= :startDate AND startDate < :endDate + ORDER BY distance DESC + LIMIT 1 + """) + suspend fun maxDistanceBetweenChargesInRange( + carId: Int, + startDate: String, + endDate: String + ): MaxDistanceBetweenChargesResult? } + +/** + * Result of max distance between charges query. + */ +data class MaxDistanceBetweenChargesResult( + val fromChargeId: Int, + val toChargeId: Int, + val distance: Double, + val fromDate: String, + val toDate: String +)