From f190f14e42d706b56339a92c99e6f290ea07d503 Mon Sep 17 00:00:00 2001 From: Vimal Jobanputra Date: Tue, 17 Oct 2023 09:51:44 +1300 Subject: [PATCH] Add query and controller endpoint for usage data (#102) --- .../nz/govt/eop/plan_limits/Controller.kt | 28 +++++++++++++++++ .../kotlin/nz/govt/eop/plan_limits/Queries.kt | 31 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Controller.kt b/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Controller.kt index f0ee615f..97c965a0 100644 --- a/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Controller.kt +++ b/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Controller.kt @@ -1,14 +1,18 @@ package nz.govt.eop.plan_limits +import java.time.LocalDate +import java.time.temporal.ChronoUnit.DAYS import java.util.concurrent.TimeUnit import org.jooq.* import org.springframework.http.CacheControl +import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.ResponseBody +import org.springframework.web.server.ResponseStatusException @Controller class Controller(val context: DSLContext, val queries: Queries, val manifest: Manifest) { @@ -79,4 +83,28 @@ class Controller(val context: DSLContext, val queries: Queries, val manifest: Ma .cacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)) .body(queries.flowLimits(councilId)) } + + @RequestMapping("/plan-limits/weekly-usage", produces = [MediaType.APPLICATION_JSON_VALUE]) + @ResponseBody + fun weeklyUsage( + @RequestParam(name = "councilId") councilId: Int, + @RequestParam("from") from: LocalDate, + @RequestParam("to") to: LocalDate, + @RequestParam("areaId") areaId: String? + ): ResponseEntity { + if (from >= to) { + throw ResponseStatusException( + HttpStatus.BAD_REQUEST, "The parameter \"to\" must be after \"from\"") + } + val difference = DAYS.between(from, to) + if (difference < 1 || difference >= 366) { + throw ResponseStatusException( + HttpStatus.BAD_REQUEST, + "The duration between \"from\" and \"to\" should be more than one day and at most one year") + } + + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)) + .body(queries.weeklyUsage(councilId, from, to, areaId)) + } } diff --git a/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Queries.kt b/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Queries.kt index 664e4765..1337ea10 100644 --- a/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Queries.kt +++ b/packages/Manager/src/main/kotlin/nz/govt/eop/plan_limits/Queries.kt @@ -1,5 +1,6 @@ package nz.govt.eop.plan_limits +import java.time.LocalDate import nz.govt.eop.si.jooq.tables.Councils.Companion.COUNCILS import nz.govt.eop.si.jooq.tables.FlowLimits.Companion.FLOW_LIMITS import nz.govt.eop.si.jooq.tables.FlowMeasurementSites.Companion.FLOW_MEASUREMENT_SITES @@ -8,8 +9,10 @@ import nz.govt.eop.si.jooq.tables.GroundwaterLimits.Companion.GROUNDWATER_LIMITS import nz.govt.eop.si.jooq.tables.PlanRegions.Companion.PLAN_REGIONS import nz.govt.eop.si.jooq.tables.Plans.Companion.PLANS import nz.govt.eop.si.jooq.tables.SurfaceWaterLimits.Companion.SURFACE_WATER_LIMITS +import nz.govt.eop.si.jooq.tables.WaterAllocationAndUsageByArea.Companion.WATER_ALLOCATION_AND_USAGE_BY_AREA import nz.govt.eop.si.jooq.tables.WaterAllocationsByArea.Companion.WATER_ALLOCATIONS_BY_AREA import org.jooq.* +import org.jooq.impl.DSL import org.jooq.impl.DSL.* import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component @@ -152,6 +155,34 @@ class Queries(@Autowired val context: DSLContext) { return buildFeatureCollection(context, innerQuery) } + fun weeklyUsage(councilId: Int, from: LocalDate, to: LocalDate, areaId: String? = null): String { + var whereCondition = DSL.noCondition() + if (areaId != null) { + whereCondition = whereCondition.and(WATER_ALLOCATION_AND_USAGE_BY_AREA.AREA_ID.eq(areaId)) + } + + val innerQuery = + select( + WATER_ALLOCATION_AND_USAGE_BY_AREA.AREA_ID, + sum(WATER_ALLOCATION_AND_USAGE_BY_AREA.ALLOCATION).`as`("total_allocation"), + sum(WATER_ALLOCATION_AND_USAGE_BY_AREA.ALLOCATION_DAILY) + .`as`("metered_daily_allocation"), + sum(WATER_ALLOCATION_AND_USAGE_BY_AREA.METERED_ALLOCATION_YEARLY) + .`as`("metered_yearly_allocation"), + sum(WATER_ALLOCATION_AND_USAGE_BY_AREA.DAILY_USAGE).`as`("daily_usage")) + .from(WATER_ALLOCATION_AND_USAGE_BY_AREA) + .where(whereCondition) + .and(WATER_ALLOCATION_AND_USAGE_BY_AREA.DATE.ge(from)) + .and(WATER_ALLOCATION_AND_USAGE_BY_AREA.DATE.le(to)) + .groupBy(WATER_ALLOCATION_AND_USAGE_BY_AREA.AREA_ID) + + val featureCollection: Field = + coalesce(function("json_agg", JSONB::class.java, field("inputs")), jsonArray()) + + val result = context.select(featureCollection).from(innerQuery.asTable("inputs")).fetch() + return result.firstNotNullOf { it.value1().toString() } + } + private fun buildFeatureCollection( dslContext: DSLContext, innerQuery: Select