diff --git a/common/src/main/kotlin/org/imdc/extensions/common/DatasetExtensions.kt b/common/src/main/kotlin/org/imdc/extensions/common/DatasetExtensions.kt index 5b31d60..29c5fe1 100644 --- a/common/src/main/kotlin/org/imdc/extensions/common/DatasetExtensions.kt +++ b/common/src/main/kotlin/org/imdc/extensions/common/DatasetExtensions.kt @@ -50,7 +50,8 @@ object DatasetExtensions { ) val dataset = parsedArgs.requirePyObject("dataset").toJava() val mapper = parsedArgs.requirePyObject("mapper") - val preserveColumnTypes = parsedArgs.getBoolean("preserveColumnTypes").filter { it }.isPresent + val preserveColumnTypes = + parsedArgs.getBoolean("preserveColumnTypes").filter { it }.isPresent val columnTypes = if (preserveColumnTypes) { dataset.columnTypes @@ -58,7 +59,8 @@ object DatasetExtensions { List(dataset.columnCount) { Any::class.java } } - val builder = DatasetBuilder.newBuilder().colNames(dataset.columnNames).colTypes(columnTypes) + val builder = + DatasetBuilder.newBuilder().colNames(dataset.columnNames).colTypes(columnTypes) for (row in dataset.rowIndices) { val columnValues = Array(dataset.columnCount) { col -> @@ -144,7 +146,11 @@ object DatasetExtensions { return printDataset(appendable, dataset, includeTypes) } - internal fun printDataset(appendable: Appendable, dataset: Dataset, includeTypes: Boolean = false) { + internal fun printDataset( + appendable: Appendable, + dataset: Dataset, + includeTypes: Boolean = false, + ) { val typeNames = List(dataset.columnCount) { column -> if (includeTypes) { dataset.getColumnType(column).simpleName @@ -252,6 +258,33 @@ object DatasetExtensions { ) } + @Suppress("unused") + @ScriptFunction(docBundlePrefix = "DatasetExtensions") + @KeywordArgs( + names = ["dataset", "table"], + types = [Dataset::class, String::class], + ) + fun insertDataset(args: Array, keywords: Array): List { + val parserArgs = PyArgParser.parseArgs( + args, + keywords, + arrayOf("dataset", "table"), + Array(2) { Any::class.java }, + "insertDataset", + ) + val dataset = parserArgs.requirePyObject("dataset").toJava() + val table = parserArgs.requireString("table") + + val columnNames = dataset.columnNames.joinToString(", ") + val valuePlaceholders = dataset.columnIndices.joinToString { "?" } + val insertString = "INSERT INTO $table ($columnNames) VALUES " + dataset.rowIndices.joinToString { "($valuePlaceholders)" } + val valueList = dataset.rowIndices.flatMap { row -> + dataset.columnIndices.map { col -> dataset[row, col] } + } + + return listOf(insertString, valueList) + } + @Suppress("unused") @ScriptFunction(docBundlePrefix = "DatasetExtensions") @KeywordArgs( @@ -293,7 +326,8 @@ object DatasetExtensions { val sheet = workbook.getSheetAt(sheetNumber) val headerRow = parsedArgs.getInteger("headerRow").orElse(-1) - val firstRow = parsedArgs.getInteger("firstRow").orElseGet { max(sheet.firstRowNum, headerRow + 1) } + val firstRow = parsedArgs.getInteger("firstRow") + .orElseGet { max(sheet.firstRowNum, headerRow + 1) } val lastRow = parsedArgs.getInteger("lastRow").orElseGet { sheet.lastRowNum } val dataRange = firstRow..lastRow @@ -309,7 +343,8 @@ object DatasetExtensions { val firstColumn = parsedArgs.getInteger("firstColumn").orElseGet { columnRow.firstCellNum.toInt() } val lastColumn = - parsedArgs.getInteger("lastColumn").map { it + 1 }.orElseGet { columnRow.lastCellNum.toInt() } + parsedArgs.getInteger("lastColumn").map { it + 1 } + .orElseGet { columnRow.lastCellNum.toInt() } if (firstColumn >= lastColumn) { throw Py.ValueError("firstColumn ($firstColumn) must be less than lastColumn ($lastColumn)") } diff --git a/common/src/main/resources/org/imdc/extensions/common/DatasetExtensions.properties b/common/src/main/resources/org/imdc/extensions/common/DatasetExtensions.properties index b7a5530..3d4f46b 100644 --- a/common/src/main/resources/org/imdc/extensions/common/DatasetExtensions.properties +++ b/common/src/main/resources/org/imdc/extensions/common/DatasetExtensions.properties @@ -48,6 +48,11 @@ columnsEqual.param.ignoreCase=Pass True if the column names should be compared c columnsEqual.param.includeTypes=Pass True if the column types must match as well. Defaults to True. columnsEqual.returns=True if the two datasets have the same columns, per additional parameters. +insertDataset.desc=Insert a dataset into a sql database table +insertDataset.param.dataset=The dataset to insert. Must not be null. +insertDataset.param.table=The name of the table to insert into. Must not be null. +insertDataset.returns=List where 0 is String Query and 1 is List of args + builder.desc=Creates a new dataset using supplied column names and types. builder.param.**columns=Optional. Keyword arguments can be supplied to predefine column names and types. The value of the argument should be string "typecode" (see system.dataset.fromCSV) or a Java or Python class instance. builder.returns=A DatasetBuilder object. Use addRow(value, ...) to add new values, and build() to construct the final dataset. \ diff --git a/common/src/test/kotlin/org/imdc/extensions/common/DatasetExtensionsTests.kt b/common/src/test/kotlin/org/imdc/extensions/common/DatasetExtensionsTests.kt index c3c8215..8f84440 100644 --- a/common/src/test/kotlin/org/imdc/extensions/common/DatasetExtensionsTests.kt +++ b/common/src/test/kotlin/org/imdc/extensions/common/DatasetExtensionsTests.kt @@ -3,6 +3,7 @@ package org.imdc.extensions.common import com.inductiveautomation.ignition.common.BasicDataset import com.inductiveautomation.ignition.common.Dataset import com.inductiveautomation.ignition.common.util.DatasetBuilder +import io.kotest.assertions.asClue import io.kotest.assertions.withClue import io.kotest.engine.spec.tempfile import io.kotest.matchers.shouldBe @@ -103,6 +104,15 @@ class DatasetExtensionsTests : JythonTest( } } + context("Insert Dataset") { + test("Dataset to String") { + eval>("utils.insertDataset(dataset, 'testing')").asClue { + it[0] shouldBe "INSERT INTO testing (a, b, c) VALUES (?, ?, ?), (?, ?, ?)" + it[1] shouldBe listOf(1, 3.14, "pi", 2, 6.28, "tau") + } + } + } + context("Filter tests") { test("Constant filter") { eval("utils.filter(dataset, lambda **kwargs: False)").asClue {