From d1d41de61c50ccdcc06e3f4bee8d26fe81992974 Mon Sep 17 00:00:00 2001 From: Peva Blanchard Date: Sat, 11 Nov 2023 12:29:21 +0100 Subject: [PATCH] plugin: basic data source csv loader --- .../reducer/DataExpressionReducer.kt | 2 +- .../datasources/LcaDataSourceOperations.kt | 42 +++++++++++++++++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt index 6173e7a45..12afeca72 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt @@ -46,7 +46,7 @@ class DataExpressionReducer( private fun reduceDataFrom(expression: EDataFrom): DataExpression { val source = dataSourceRegister[DataSourceKey(expression.source)] ?: throw EvaluatorException("unknown data source ${expression.source}") - return sourceOps.read(source, expression.row, expression.column) + return reduce(sourceOps.read(source, expression.row, expression.column)) } private fun reduceUnitOf(unitOf: EUnitOf): DataExpression { diff --git a/plugin/src/main/kotlin/ch/kleis/lcaac/plugin/datasources/LcaDataSourceOperations.kt b/plugin/src/main/kotlin/ch/kleis/lcaac/plugin/datasources/LcaDataSourceOperations.kt index e566c4bfc..dae9d9934 100644 --- a/plugin/src/main/kotlin/ch/kleis/lcaac/plugin/datasources/LcaDataSourceOperations.kt +++ b/plugin/src/main/kotlin/ch/kleis/lcaac/plugin/datasources/LcaDataSourceOperations.kt @@ -1,15 +1,49 @@ package ch.kleis.lcaac.plugin.datasources import ch.kleis.lcaac.core.datasource.DataSourceOperations -import ch.kleis.lcaac.core.lang.expression.DataExpression -import ch.kleis.lcaac.core.lang.expression.DataSourceExpression -import ch.kleis.lcaac.core.lang.expression.SliceIndex +import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException +import ch.kleis.lcaac.core.lang.expression.* import ch.kleis.lcaac.core.math.QuantityOperations +import org.apache.commons.csv.CSVFormat +import org.apache.commons.csv.CSVParser +import java.nio.file.Path class LcaDataSourceOperations( private val ops: QuantityOperations, ) : DataSourceOperations { override fun read(source: DataSourceExpression, row: SliceIndex, column: SliceIndex): DataExpression { - TODO("Not yet implemented") + if (row !is StrIndex || column !is StrIndex) { + throw EvaluatorException("Not supported yet") + } + return when (source) { + is ECsvSource -> readCsv(source, row, column) + } + } + + private val format = CSVFormat.DEFAULT.builder() + .setHeader() + .setSkipHeaderRecord(true) + .build() + + // TODO: Very inefficient, csv is scanned on every call + private fun readCsv(source: ECsvSource, row: StrIndex, column: StrIndex): DataExpression { + val schema = source.schema + val columnType = schema[column.s] ?: throw EvaluatorException("${column.s} not found in schema") + + val file = Path.of(source.location).toFile() + val index = source.index ?: throw EvaluatorException("Requires index") + val parser = CSVParser(file.inputStream().reader(), format) + val rawValue = parser.records.find { + it[index] == row.s + }?.get(column.s) + ?: throw EvaluatorException("value not found (row=${row.s}, col=${column.s})") + + return when(columnType) { + is CQuantity -> { + val amount = ops.pure(rawValue.toDouble()) + return EQuantityScale(amount, columnType.unit) + } + is CText -> EStringLiteral(rawValue) + } } }