All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tri.timeseries.TimeSeriesQuery.kt Maven / Gradle / Ivy

/*-
 * #%L
 * coda-data
 * --
 * Copyright (C) 2020 - 2021 Elisha Peterson
 * --
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package tri.timeseries

import tri.area.AreaInfo
import java.time.YearMonth

/** Manages access to a variety of time series, and provides simple query access. */
open class TimeSeriesQuery(vararg _sources: TimeSeriesProcessor) {

    /** List of sources. */
    val sources = _sources.toList()
    /** Data associated with a given source. */
    private val sourceData: MutableMap>> = mutableMapOf()

//    /** Load all data into memory, grouped by area. */
//    private val data by lazy { sources.flatMap { it.data() }.groupByArea() }
//    /** Flat version of all data. */
//    private val flatData by lazy { data.flatMap { it.value } }
//    /** List of all areas in the data. */
//    private val areas by lazy { data.keys }

    //region QUERIES

//    /** Query all data based on area. */
//    fun byArea(area: AreaInfo) = data[area] ?: emptyList()

    /** Get all areas in the data set (loading all data). */
    fun allDataAreas() = allSources().flatMap { sourceData[it]!!.keys }.toSet()

    /** Get all data matching given area filter (loading all data). */
    fun allDataByArea(areaFilter: (AreaInfo) -> Boolean) = allSources().map { sourceData[it]!!.filterKeys(areaFilter) }
        .flatMap { it.values.flatten() }.groupByArea()

    /** Query by area and metric/qualifier. */
    fun by(area: AreaInfo, metric: String, qualifier: String = "") = sourcesFor(area, metric, qualifier)
        .flatMap { it.query(area, metric, qualifier) }

    /** Query all data based on area and metric. */
    fun by(areaFilter: (AreaInfo) -> Boolean, metricFilter: (String) -> Boolean, qualifierFilter: (String) -> Boolean = { true }) =
        sourcesFor(metricFilter, qualifierFilter).flatMap { it.query(areaFilter, metricFilter, qualifierFilter) }

//    /** Query all data based on a generic filter. */
//    fun by(filter: (TimeSeries) -> Boolean) = flatData.filter(filter)

    /** Query for daily version of time series. */
    open fun daily(area: AreaInfo, metric: String): TimeSeries? = null
    /** Query for cumulative version of time series. */
    open fun cumulative(area: AreaInfo, metric: String): TimeSeries? = null

    /** Query for weekly average version of time series. */
    open fun weeklyAverage(area: AreaInfo, metric: String): TimeSeries? = null
    /** Query for weekly total version of time series. */
    open fun weeklyTotal(area: AreaInfo, metric: String): TimeSeries? = null

    /** Query for 14-day total version of time series. */
    open fun biweeklyTotal(area: AreaInfo, metric: String): TimeSeries? = null

    /** Query for monthly average value. */
    open fun monthlyAverage(area: AreaInfo, metric: String, month: YearMonth): Double? = null
    /** Query for monthly total value. */
    open fun monthlyTotal(area: AreaInfo, metric: String, month: YearMonth): Double? = null

    //endregion

    //region UTILS

    /** Loads all data sources. */
    private fun allSources() = sources.onEach { it.loadData() }

    private fun sourcesFor(area: AreaInfo, metric: String, qualifier: String = "") = sources.filter { it.provides(area, metric, qualifier) }

    private fun sourcesFor(metricFilter: (String) -> Boolean, qualifierFilter: (String) -> Boolean) = sources.filter {
        it.metricsProvided().any(metricInfoFilter(metricFilter, qualifierFilter))
    }

    private fun metricInfoFilter(metricFilter: (String) -> Boolean, qualifierFilter: (String) -> Boolean): (MetricInfo) -> Boolean =
        { metricFilter(it.metric) && qualifierFilter(it.qualifier) }

    private fun TimeSeriesProcessor.query(area: AreaInfo, metric: String, qualifier: String? = ""): List {
        if (this !in sourceData.keys) loadData()
        return sourceData[this]!!.getOrElse(area) { listOf() }
            .filter { (it.metric == metric) && (qualifier == null || it.qualifier == qualifier) }
    }

    private fun TimeSeriesProcessor.query(areaFilter: (AreaInfo) -> Boolean, metricFilter: (String) -> Boolean, qualifierFilter: (String) -> Boolean): List {
        if (this !in sourceData.keys) loadData()
        val data = sourceData[this]!!
        val filter = metricInfoFilter(metricFilter, qualifierFilter)
        return data.filterKeys(areaFilter).flatMap { it.value.filter { filter(it.metricInfo) } }
    }

    private fun TimeSeriesProcessor.loadData() {
        sourceData[this] = data().groupByArea()
    }

    //endregion

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy