Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
94 changed files with 903 additions and 328 deletions
Showing only changes of commit e0ec37e8c2 - Show all commits

View File

@ -2,7 +2,9 @@
<module version="4"> <module version="4">
<component name="AdditionalModuleElements"> <component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true"> <content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/src/integration-test/kotlin" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/common/src/kotlin" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/common/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/common/test/kotlin" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
</content> </content>
</component> </component>

View File

@ -61,7 +61,7 @@
<executions> <executions>
<execution> <execution>
<id>compile</id> <id>compile</id>
<phase>compile</phase> <phase>process-sources</phase>
<goals> <goals>
<goal>compile</goal> <goal>compile</goal>
</goals> </goals>

93
src/common/pom.xml Normal file
View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>solutions.bitbadger.documents</groupId>
<artifactId>common</artifactId>
<version>4.0.0-alpha1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>solutions.bitbadger</groupId>
<artifactId>documents</artifactId>
<version>4.0.0-alpha1-SNAPSHOT</version>
</parent>
<name>${project.groupId}:${project.artifactId}</name>
<description>Expose a document store interface for PostgreSQL and SQLite (Common Library)</description>
<url>https://bitbadger.solutions/open-source/relational-documents/jvm/</url>
<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<compilerPlugins>
<plugin>kotlinx-serialization</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-serialization</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>MainKt</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import kotlin.jvm.Throws import kotlin.jvm.Throws
import kotlin.reflect.full.* import kotlin.reflect.full.*
@ -10,10 +10,13 @@ import kotlin.reflect.jvm.isAccessible
enum class AutoId { enum class AutoId {
/** No automatic IDs will be generated */ /** No automatic IDs will be generated */
DISABLED, DISABLED,
/** Generate a `MAX`-plus-1 numeric ID */ /** Generate a `MAX`-plus-1 numeric ID */
NUMBER, NUMBER,
/** Generate a `UUID` string ID */ /** Generate a `UUID` string ID */
UUID, UUID,
/** Generate a random hex character string ID */ /** Generate a random hex character string ID */
RANDOM_STRING; RANDOM_STRING;
@ -24,7 +27,8 @@ enum class AutoId {
* *
* @return A `UUID` string * @return A `UUID` string
*/ */
@JvmStatic fun generateUUID(): String = @JvmStatic
fun generateUUID(): String =
java.util.UUID.randomUUID().toString().replace("-", "") java.util.UUID.randomUUID().toString().replace("-", "")
/** /**
@ -33,7 +37,8 @@ enum class AutoId {
* @param length The length of the string (optional; defaults to configured length) * @param length The length of the string (optional; defaults to configured length)
* @return A string of random hex characters of the requested length * @return A string of random hex characters of the requested length
*/ */
@JvmStatic fun generateRandomString(length: Int? = null): String = @JvmStatic
fun generateRandomString(length: Int? = null): String =
(length ?: Configuration.idStringLength).let { len -> (length ?: Configuration.idStringLength).let { len ->
kotlin.random.Random.nextBytes((len + 2) / 2) kotlin.random.Random.nextBytes((len + 2) / 2)
.joinToString("") { String.format("%02x", it) } .joinToString("") { String.format("%02x", it) }
@ -50,7 +55,8 @@ enum class AutoId {
* @throws DocumentException If bad input prevents the determination * @throws DocumentException If bad input prevents the determination
*/ */
@Throws(DocumentException::class) @Throws(DocumentException::class)
@JvmStatic fun <T> needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean { @JvmStatic
fun <T> needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean {
if (document == null) throw DocumentException("document cannot be null") if (document == null) throw DocumentException("document cannot be null")
if (strategy == DISABLED) return false if (strategy == DISABLED) return false

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* Information required to generate a JSON field comparison * Information required to generate a JSON field comparison

View File

@ -0,0 +1,63 @@
package solutions.bitbadger.documents.common
import java.sql.Connection
import java.sql.DriverManager
import kotlin.jvm.Throws
/**
* Configuration for the document library
*/
object Configuration {
/** The field in which a document's ID is stored */
@JvmField
var idField = "id"
/** The automatic ID strategy to use */
@JvmField
var autoIdStrategy = AutoId.DISABLED
/** The length of automatic random hex character string */
@JvmField
var idStringLength = 16
/** The derived dialect value from the connection string */
internal var dialectValue: Dialect? = null
/** The connection string for the JDBC connection */
@JvmStatic
var connectionString: String? = null
set(value) {
field = value
dialectValue = if (value.isNullOrBlank()) null else Dialect.deriveFromConnectionString(value)
}
/**
* Retrieve a new connection to the configured database
*
* @return A new connection to the configured database
* @throws IllegalArgumentException If the connection string is not set before calling this
*/
@JvmStatic
fun dbConn(): Connection {
if (connectionString == null) {
throw IllegalArgumentException("Please provide a connection string before attempting data access")
}
return DriverManager.getConnection(connectionString)
}
/**
* The dialect in use
*
* @param process The process being attempted
* @return The dialect for the current connection
* @throws DocumentException If the dialect has not been set
*/
@Throws(DocumentException::class)
@JvmStatic
@JvmOverloads
fun dialect(process: String? = null): Dialect =
dialectValue ?: throw DocumentException(
"Database mode not set" + if (process == null) "" else "; cannot $process"
)
}

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* The SQL dialect to use when building queries * The SQL dialect to use when building queries

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* An exception caused by invalid operations in the document library * An exception caused by invalid operations in the document library

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* The type of index to generate for the document * The type of index to generate for the document

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* A field and its comparison * A field and its comparison

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* The data format for a document field retrieval * The data format for a document field retrieval

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* How fields should be matched in by-field queries * How fields should be matched in by-field queries

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* A comparison operator used for fields * A comparison operator used for fields

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import java.sql.PreparedStatement import java.sql.PreparedStatement
import java.sql.Types import java.sql.Types

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* Derive parameter names; each instance wraps a counter to provide names for anonymous fields * Derive parameter names; each instance wraps a counter to provide names for anonymous fields

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
/** /**
* The types of parameters supported by the document library * The types of parameters supported by the document library
@ -6,8 +6,10 @@ package solutions.bitbadger.documents
enum class ParameterType { enum class ParameterType {
/** The parameter value is some sort of number (`Byte`, `Short`, `Int`, or `Long`) */ /** The parameter value is some sort of number (`Byte`, `Short`, `Int`, or `Long`) */
NUMBER, NUMBER,
/** The parameter value is a string */ /** The parameter value is a string */
STRING, STRING,
/** The parameter should be JSON-encoded */ /** The parameter should be JSON-encoded */
JSON, JSON,
} }

View File

@ -1,8 +1,8 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.query.byFields as byFieldsBase; import solutions.bitbadger.documents.common.query.byFields as byFieldsBase;
/** /**
* Functions to count documents * Functions to count documents

View File

@ -1,6 +1,6 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.*
/** /**
* Functions to create queries to define tables and indexes * Functions to create queries to define tables and indexes
@ -87,6 +87,6 @@ object Definition {
throw DocumentException("'Document indexes are only supported on PostgreSQL") throw DocumentException("'Document indexes are only supported on PostgreSQL")
} }
val (_, tbl) = splitSchemaAndTable(tableName) val (_, tbl) = splitSchemaAndTable(tableName)
return "CREATE INDEX IF NOT EXISTS idx_${tbl}_document ON $tableName USING GIN (data${indexType.sql})"; return "CREATE INDEX IF NOT EXISTS idx_${tbl}_document ON $tableName USING GIN (data${indexType.sql})"
} }
} }

View File

@ -1,9 +1,9 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.query.byFields as byFieldsBase import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
import solutions.bitbadger.documents.query.byId as byIdBase import solutions.bitbadger.documents.common.query.byId as byIdBase
/** /**
* Functions to delete documents * Functions to delete documents
@ -14,7 +14,6 @@ object Delete {
* Query to delete documents from a table * Query to delete documents from a table
* *
* @param tableName The table in which documents should be deleted (may include schema) * @param tableName The table in which documents should be deleted (may include schema)
* @param where The WHERE clause for the delete statement
* @return A query to delete documents * @return A query to delete documents
*/ */
private fun delete(tableName: String) = private fun delete(tableName: String) =

View File

@ -1,8 +1,8 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.AutoId import solutions.bitbadger.documents.common.AutoId
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
/** /**
* Functions for document-level operations * Functions for document-level operations

View File

@ -1,7 +1,7 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.common.FieldMatch
/** /**
* Functions to check for document existence * Functions to check for document existence

View File

@ -1,9 +1,9 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.query.byId as byIdBase import solutions.bitbadger.documents.common.query.byId as byIdBase
import solutions.bitbadger.documents.query.byFields as byFieldsBase import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
/** /**
* Functions to retrieve documents * Functions to retrieve documents

View File

@ -1,11 +1,11 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.query.byFields as byFieldsBase import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
import solutions.bitbadger.documents.query.byId as byIdBase import solutions.bitbadger.documents.common.query.byId as byIdBase
/** /**
* Functions to create queries to patch (partially update) JSON documents * Functions to create queries to patch (partially update) JSON documents

View File

@ -1,9 +1,9 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.common.FieldMatch
// ~~~ TOP-LEVEL FUNCTIONS FOR THE QUERY PACKAGE ~~~ // ~~~ TOP-LEVEL FUNCTIONS FOR THE QUERY PACKAGE ~~~

View File

@ -1,8 +1,8 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.query.byFields as byFieldsBase import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
import solutions.bitbadger.documents.query.byId as byIdBase import solutions.bitbadger.documents.common.query.byId as byIdBase
/** /**
* Functions to create queries to remove fields from documents * Functions to create queries to remove fields from documents

View File

@ -1,6 +1,10 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
/** /**
* Functions to create `WHERE` clause fragments * Functions to create `WHERE` clause fragments

View File

@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.AutoId; import solutions.bitbadger.documents.common.AutoId;
import solutions.bitbadger.documents.DocumentException; import solutions.bitbadger.documents.common.DocumentException;
import solutions.bitbadger.documents.java.testDocs.*; import solutions.bitbadger.documents.java.testDocs.*;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.*;
/** /**
* Unit tests for the `AutoId` enum * Unit tests for the `AutoId` enum
*/ */
@DisplayName("Java | AutoId") @DisplayName("Java | Common | AutoId")
final public class AutoIdTest { final public class AutoIdTest {
@Test @Test

View File

@ -1,15 +1,15 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.DocumentIndex; import solutions.bitbadger.documents.common.DocumentIndex;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* Unit tests for the `DocumentIndex` enum * Unit tests for the `DocumentIndex` enum
*/ */
@DisplayName("Java | DocumentIndex") @DisplayName("Java | Common | DocumentIndex")
final public class DocumentIndexTest { final public class DocumentIndexTest {
@Test @Test

View File

@ -1,15 +1,15 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.FieldMatch; import solutions.bitbadger.documents.common.FieldMatch;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* Unit tests for the `FieldMatch` enum * Unit tests for the `FieldMatch` enum
*/ */
@DisplayName("Java | FieldMatch") @DisplayName("Java | Common | FieldMatch")
final public class FieldMatchTest { final public class FieldMatchTest {
@Test @Test

View File

@ -1,10 +1,10 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import kotlin.Pair; import kotlin.Pair;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*; import solutions.bitbadger.documents.common.*;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.*;
/** /**
* Unit tests for the `Field` class * Unit tests for the `Field` class
*/ */
@DisplayName("Java | Field") @DisplayName("Java | Common | Field")
final public class FieldTest { final public class FieldTest {
/** /**

View File

@ -1,15 +1,15 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.Op; import solutions.bitbadger.documents.common.Op;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* Unit tests for the `Op` enum * Unit tests for the `Op` enum
*/ */
@DisplayName("Java | Op") @DisplayName("Java | Common | Op")
final public class OpTest { final public class OpTest {
@Test @Test

View File

@ -1,15 +1,15 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.ParameterName; import solutions.bitbadger.documents.common.ParameterName;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* Unit tests for the `ParameterName` class * Unit tests for the `ParameterName` class
*/ */
@DisplayName("Java | ParameterName") @DisplayName("Java | Common | ParameterName")
final public class ParameterNameTest { final public class ParameterNameTest {
@Test @Test

View File

@ -1,17 +1,17 @@
package solutions.bitbadger.documents.java; package solutions.bitbadger.documents.common.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.DocumentException; import solutions.bitbadger.documents.common.DocumentException;
import solutions.bitbadger.documents.Parameter; import solutions.bitbadger.documents.common.Parameter;
import solutions.bitbadger.documents.ParameterType; import solutions.bitbadger.documents.common.ParameterType;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* Unit tests for the `Parameter` class * Unit tests for the `Parameter` class
*/ */
@DisplayName("Java | Parameter") @DisplayName("Java | Common | Parameter")
final public class ParameterTest { final public class ParameterTest {
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -11,7 +11,7 @@ import kotlin.test.assertTrue
/** /**
* Unit tests for the `AutoId` enum * Unit tests for the `AutoId` enum
*/ */
@DisplayName("Kotlin | AutoId") @DisplayName("Kotlin | Common | AutoId")
class AutoIdTest { class AutoIdTest {
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -21,7 +21,8 @@ class ComparisonBetweenTest {
@Test @Test
@DisplayName("isNumeric is false with strings") @DisplayName("isNumeric is false with strings")
fun isNumericFalseForStringsAndBetween() = fun isNumericFalseForStringsAndBetween() =
assertFalse(ComparisonBetween(Pair("eh", "zed")).isNumeric, assertFalse(
ComparisonBetween(Pair("eh", "zed")).isNumeric,
"A BETWEEN with strings should not be numeric") "A BETWEEN with strings should not be numeric")
@Test @Test
@ -32,7 +33,8 @@ class ComparisonBetweenTest {
@Test @Test
@DisplayName("isNumeric is true with shorts") @DisplayName("isNumeric is true with shorts")
fun isNumericTrueForShortAndBetween() = fun isNumericTrueForShortAndBetween() =
assertTrue(ComparisonBetween(Pair<Short, Short>(0, 9)).isNumeric, assertTrue(
ComparisonBetween(Pair<Short, Short>(0, 9)).isNumeric,
"A BETWEEN with shorts should be numeric") "A BETWEEN with shorts should be numeric")
@Test @Test

View File

@ -0,0 +1,43 @@
package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
/**
* Unit tests for the `Configuration` object
*/
@DisplayName("Kotlin | Common | Configuration")
class ConfigurationTest {
@Test
@DisplayName("Default ID field is `id`")
fun defaultIdField() {
assertEquals("id", Configuration.idField, "Default ID field incorrect")
}
@Test
@DisplayName("Default Auto ID strategy is `DISABLED`")
fun defaultAutoId() {
assertEquals(AutoId.DISABLED, Configuration.autoIdStrategy, "Default Auto ID strategy should be `disabled`")
}
@Test
@DisplayName("Default ID string length should be 16")
fun defaultIdStringLength() {
assertEquals(16, Configuration.idStringLength, "Default ID string length should be 16")
}
@Test
@DisplayName("Dialect is derived from connection string")
fun dialectIsDerived() {
try {
assertThrows<DocumentException> { Configuration.dialect() }
Configuration.connectionString = "jdbc:postgresql:db"
assertEquals(Dialect.POSTGRESQL, Configuration.dialect())
} finally {
Configuration.connectionString = null
}
}
}

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -9,19 +9,21 @@ import kotlin.test.assertTrue
/** /**
* Unit tests for the `Dialect` enum * Unit tests for the `Dialect` enum
*/ */
@DisplayName("Dialect") @DisplayName("Kotlin | Common | Dialect")
class DialectTest { class DialectTest {
@Test @Test
@DisplayName("deriveFromConnectionString derives PostgreSQL correctly") @DisplayName("deriveFromConnectionString derives PostgreSQL correctly")
fun derivesPostgres() = fun derivesPostgres() =
assertEquals(Dialect.POSTGRESQL, Dialect.deriveFromConnectionString("jdbc:postgresql:db"), assertEquals(
Dialect.POSTGRESQL, Dialect.deriveFromConnectionString("jdbc:postgresql:db"),
"Dialect should have been PostgreSQL") "Dialect should have been PostgreSQL")
@Test @Test
@DisplayName("deriveFromConnectionString derives PostgreSQL correctly") @DisplayName("deriveFromConnectionString derives PostgreSQL correctly")
fun derivesSQLite() = fun derivesSQLite() =
assertEquals(Dialect.SQLITE, Dialect.deriveFromConnectionString("jdbc:sqlite:memory"), assertEquals(
Dialect.SQLITE, Dialect.deriveFromConnectionString("jdbc:sqlite:memory"),
"Dialect should have been SQLite") "Dialect should have been SQLite")
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `DocumentIndex` enum * Unit tests for the `DocumentIndex` enum
*/ */
@DisplayName("Kotlin | DocumentIndex") @DisplayName("Kotlin | Common | DocumentIndex")
class DocumentIndexTest { class DocumentIndexTest {
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `FieldMatch` enum * Unit tests for the `FieldMatch` enum
*/ */
@DisplayName("Kotlin | FieldMatch") @DisplayName("Kotlin | Common | FieldMatch")
class FieldMatchTest { class FieldMatchTest {
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
@ -11,7 +11,7 @@ import kotlin.test.assertNull
/** /**
* Unit tests for the `Field` class * Unit tests for the `Field` class
*/ */
@DisplayName("Kotlin | Field") @DisplayName("Kotlin | Common | Field")
class FieldTest { class FieldTest {
/** /**
@ -19,7 +19,7 @@ class FieldTest {
*/ */
@AfterEach @AfterEach
fun cleanUp() { fun cleanUp() {
Configuration.connectionString = null Configuration.dialectValue = null
} }
// ~~~ INSTANCE METHODS ~~~ // ~~~ INSTANCE METHODS ~~~
@ -122,7 +122,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)") @DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)")
fun toWhereExistsNoQualPostgres() { fun toWhereExistsNoQualPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(), assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -130,7 +130,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for exists w/o qualifier (SQLite)") @DisplayName("toWhere generates for exists w/o qualifier (SQLite)")
fun toWhereExistsNoQualSQLite() { fun toWhereExistsNoQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(), assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -138,7 +138,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for not-exists w/o qualifier (PostgreSQL)") @DisplayName("toWhere generates for not-exists w/o qualifier (PostgreSQL)")
fun toWhereNotExistsNoQualPostgres() { fun toWhereNotExistsNoQualPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(), assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -146,7 +146,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for not-exists w/o qualifier (SQLite)") @DisplayName("toWhere generates for not-exists w/o qualifier (SQLite)")
fun toWhereNotExistsNoQualSQLite() { fun toWhereNotExistsNoQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(), assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -154,7 +154,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, numeric range (PostgreSQL)") @DisplayName("toWhere generates for BETWEEN w/o qualifier, numeric range (PostgreSQL)")
fun toWhereBetweenNoQualNumericPostgres() { fun toWhereBetweenNoQualNumericPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax", assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").toWhere(), "Field WHERE clause not generated correctly") Field.between("age", 13, 17, "@age").toWhere(), "Field WHERE clause not generated correctly")
} }
@ -162,7 +162,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range (PostgreSQL)") @DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range (PostgreSQL)")
fun toWhereBetweenNoQualAlphaPostgres() { fun toWhereBetweenNoQualAlphaPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'city' BETWEEN :citymin AND :citymax", assertEquals("data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").toWhere(), Field.between("city", "Atlanta", "Chicago", ":city").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -171,7 +171,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier (SQLite)") @DisplayName("toWhere generates for BETWEEN w/o qualifier (SQLite)")
fun toWhereBetweenNoQualSQLite() { fun toWhereBetweenNoQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field.between("age", 13, 17, "@age").toWhere(), assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field.between("age", 13, 17, "@age").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -179,7 +179,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, numeric range (PostgreSQL)") @DisplayName("toWhere generates for BETWEEN w/ qualifier, numeric range (PostgreSQL)")
fun toWhereBetweenQualNumericPostgres() { fun toWhereBetweenQualNumericPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(test.data->>'age')::numeric BETWEEN @agemin AND @agemax", assertEquals("(test.data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("test").toWhere(), Field.between("age", 13, 17, "@age").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -188,7 +188,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range (PostgreSQL)") @DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range (PostgreSQL)")
fun toWhereBetweenQualAlphaPostgres() { fun toWhereBetweenQualAlphaPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("unit.data->>'city' BETWEEN :citymin AND :citymax", assertEquals("unit.data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").withQualifier("unit").toWhere(), Field.between("city", "Atlanta", "Chicago", ":city").withQualifier("unit").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -197,7 +197,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier (SQLite)") @DisplayName("toWhere generates for BETWEEN w/ qualifier (SQLite)")
fun toWhereBetweenQualSQLite() { fun toWhereBetweenQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("my.data->>'age' BETWEEN @agemin AND @agemax", assertEquals("my.data->>'age' BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("my").toWhere(), Field.between("age", 13, 17, "@age").withQualifier("my").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -206,7 +206,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for IN/any, numeric values (PostgreSQL)") @DisplayName("toWhere generates for IN/any, numeric values (PostgreSQL)")
fun toWhereAnyNumericPostgres() { fun toWhereAnyNumericPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'even')::numeric IN (:nbr_0, :nbr_1, :nbr_2)", assertEquals("(data->>'even')::numeric IN (:nbr_0, :nbr_1, :nbr_2)",
Field.any("even", listOf(2, 4, 6), ":nbr").toWhere(), "Field WHERE clause not generated correctly") Field.any("even", listOf(2, 4, 6), ":nbr").toWhere(), "Field WHERE clause not generated correctly")
} }
@ -214,7 +214,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for IN/any, alphanumeric values (PostgreSQL)") @DisplayName("toWhere generates for IN/any, alphanumeric values (PostgreSQL)")
fun toWhereAnyAlphaPostgres() { fun toWhereAnyAlphaPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'test' IN (:city_0, :city_1)", assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(), Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -223,7 +223,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for IN/any (SQLite)") @DisplayName("toWhere generates for IN/any (SQLite)")
fun toWhereAnySQLite() { fun toWhereAnySQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'test' IN (:city_0, :city_1)", assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(), Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -232,7 +232,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for inArray (PostgreSQL)") @DisplayName("toWhere generates for inArray (PostgreSQL)")
fun toWhereInArrayPostgres() { fun toWhereInArrayPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]", assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]",
Field.inArray("even", "tbl", listOf(2, 4, 6, 8), ":it").toWhere(), Field.inArray("even", "tbl", listOf(2, 4, 6, 8), ":it").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -241,7 +241,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for inArray (SQLite)") @DisplayName("toWhere generates for inArray (SQLite)")
fun toWhereInArraySQLite() { fun toWhereInArraySQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("EXISTS (SELECT 1 FROM json_each(tbl.data, '$.test') WHERE value IN (:city_0, :city_1))", assertEquals("EXISTS (SELECT 1 FROM json_each(tbl.data, '$.test') WHERE value IN (:city_0, :city_1))",
Field.inArray("test", "tbl", listOf("Atlanta", "Chicago"), ":city").toWhere(), Field.inArray("test", "tbl", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -250,7 +250,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for others w/o qualifier (PostgreSQL)") @DisplayName("toWhere generates for others w/o qualifier (PostgreSQL)")
fun toWhereOtherNoQualPostgres() { fun toWhereOtherNoQualPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(), assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -258,7 +258,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates for others w/o qualifier (SQLite)") @DisplayName("toWhere generates for others w/o qualifier (SQLite)")
fun toWhereOtherNoQualSQLite() { fun toWhereOtherNoQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(), assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -266,7 +266,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates no-parameter w/ qualifier (PostgreSQL)") @DisplayName("toWhere generates no-parameter w/ qualifier (PostgreSQL)")
fun toWhereNoParamWithQualPostgres() { fun toWhereNoParamWithQualPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(), assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -274,7 +274,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates no-parameter w/ qualifier (SQLite)") @DisplayName("toWhere generates no-parameter w/ qualifier (SQLite)")
fun toWhereNoParamWithQualSQLite() { fun toWhereNoParamWithQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(), assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
} }
@ -282,7 +282,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates parameter w/ qualifier (PostgreSQL)") @DisplayName("toWhere generates parameter w/ qualifier (PostgreSQL)")
fun toWhereParamWithQualPostgres() { fun toWhereParamWithQualPostgres() {
Configuration.connectionString = ":postgresql:" Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(q.data->>'le_field')::numeric <= :it", assertEquals("(q.data->>'le_field')::numeric <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(), Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")
@ -291,7 +291,7 @@ class FieldTest {
@Test @Test
@DisplayName("toWhere generates parameter w/ qualifier (SQLite)") @DisplayName("toWhere generates parameter w/ qualifier (SQLite)")
fun toWhereParamWithQualSQLite() { fun toWhereParamWithQualSQLite() {
Configuration.connectionString = ":sqlite:" Configuration.dialectValue = Dialect.SQLITE
assertEquals("q.data->>'le_field' <= :it", assertEquals("q.data->>'le_field' <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(), Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly") "Field WHERE clause not generated correctly")

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `Op` enum * Unit tests for the `Op` enum
*/ */
@DisplayName("Kotlin | Op") @DisplayName("Kotlin | Common | Op")
class OpTest { class OpTest {
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `ParameterName` class * Unit tests for the `ParameterName` class
*/ */
@DisplayName("Kotlin | ParameterName") @DisplayName("Kotlin | Common | ParameterName")
class ParameterNameTest { class ParameterNameTest {
@Test @Test

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents.common
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
@ -9,7 +9,7 @@ import kotlin.test.assertNull
/** /**
* Unit tests for the `Parameter` class * Unit tests for the `Parameter` class
*/ */
@DisplayName("Kotlin | Parameter") @DisplayName("Kotlin | Common | Parameter")
class ParameterTest { class ParameterTest {
@Test @Test

View File

@ -1,16 +1,19 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.common.Field
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Count` object * Unit tests for the `Count` object
*/ */
@DisplayName("Count (Query)") @DisplayName("Kotlin | Common | Query: Count")
class CountTest { class CountTest {
/** Test table name */ /** Test table name */

View File

@ -1,19 +1,19 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.DocumentIndex import solutions.bitbadger.documents.common.DocumentIndex
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Definition` object * Unit tests for the `Definition` object
*/ */
@DisplayName("Definition (Query)") @DisplayName("Kotlin | Common | Query: Definition")
class DefinitionTest { class DefinitionTest {
/** Test table name */ /** Test table name */

View File

@ -1,19 +1,19 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Delete` object * Unit tests for the `Delete` object
*/ */
@DisplayName("Delete (Query)") @DisplayName("Kotlin | Common | Query: Delete")
class DeleteTest { class DeleteTest {
/** Test table name */ /** Test table name */

View File

@ -1,17 +1,20 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.AutoId
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
/** /**
* Unit tests for the `Document` object * Unit tests for the `Document` object
*/ */
@DisplayName("Document (Query)") @DisplayName("Kotlin | Common | Query: Document")
class DocumentTest { class DocumentTest {
/** Test table name */ /** Test table name */

View File

@ -1,16 +1,19 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.common.Field
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Exists` object * Unit tests for the `Exists` object
*/ */
@DisplayName("Exists (Query)") @DisplayName("Kotlin | Common | Query: Exists")
class ExistsTest { class ExistsTest {
/** Test table name */ /** Test table name */

View File

@ -1,19 +1,19 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Find` object * Unit tests for the `Find` object
*/ */
@DisplayName("Find (Query)") @DisplayName("Kotlin | Common | Query: Find")
class FindTest { class FindTest {
/** Test table name */ /** Test table name */

View File

@ -1,19 +1,19 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.common.Field
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Patch` object * Unit tests for the `Patch` object
*/ */
@DisplayName("Patch (Query)") @DisplayName("Kotlin | Common | Query: Patch")
class PatchTest { class PatchTest {
/** Test table name */ /** Test table name */

View File

@ -1,15 +1,18 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the top-level query functions * Unit tests for the top-level query functions
*/ */
@DisplayName("Query") @DisplayName("Kotlin | Common | Query")
class QueryTest { class QueryTest {
/** /**

View File

@ -1,16 +1,20 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.common.Field
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `RemoveFields` object * Unit tests for the `RemoveFields` object
*/ */
@DisplayName("RemoveFields (Query)") @DisplayName("Kotlin | Common | Query: RemoveFields")
class RemoveFieldsTest { class RemoveFieldsTest {
/** Test table name */ /** Test table name */

View File

@ -1,16 +1,16 @@
package solutions.bitbadger.documents.query package solutions.bitbadger.documents.common.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
/** /**
* Unit tests for the `Where` object * Unit tests for the `Where` object
*/ */
@DisplayName("Where (Query)") @DisplayName("Kotlin | Common | Query: Where")
class WhereTest { class WhereTest {
/** /**

View File

@ -1,6 +1,9 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import solutions.bitbadger.documents.common.AutoId
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import java.sql.Connection import java.sql.Connection
import java.sql.DriverManager import java.sql.DriverManager
import kotlin.jvm.Throws import kotlin.jvm.Throws
@ -20,58 +23,8 @@ object Configuration {
coerceInputValues = true coerceInputValues = true
} }
/** The field in which a document's ID is stored */
@JvmField
var idField = "id"
/** The automatic ID strategy to use */
@JvmField
var autoIdStrategy = AutoId.DISABLED
/** The length of automatic random hex character string */
@JvmField
var idStringLength = 16
/** The JSON serializer to use for documents */ /** The JSON serializer to use for documents */
@JvmStatic
var serializer: DocumentSerializer = DocumentSerializerKotlin() var serializer: DocumentSerializer = DocumentSerializerKotlin()
/** The derived dialect value from the connection string */
internal var dialectValue: Dialect? = null
/** The connection string for the JDBC connection */
@JvmStatic
var connectionString: String? = null
set(value) {
field = value
dialectValue = if (value.isNullOrBlank()) null else Dialect.deriveFromConnectionString(value)
}
/**
* Retrieve a new connection to the configured database
*
* @return A new connection to the configured database
* @throws IllegalArgumentException If the connection string is not set before calling this
*/
@JvmStatic
fun dbConn(): Connection {
if (connectionString == null) {
throw IllegalArgumentException("Please provide a connection string before attempting data access")
}
return DriverManager.getConnection(connectionString)
}
/**
* The dialect in use
*
* @param process The process being attempted
* @return The dialect for the current connection
* @throws DocumentException If the dialect has not been set
*/
@Throws(DocumentException::class)
@JvmStatic
@JvmOverloads
fun dialect(process: String? = null): Dialect =
dialectValue ?: throw DocumentException(
"Database mode not set" + if (process == null) "" else "; cannot $process"
)
} }

View File

@ -1,5 +1,9 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.DocumentIndex
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.Parameter
import java.sql.Connection import java.sql.Connection
import java.sql.ResultSet import java.sql.ResultSet
@ -14,7 +18,7 @@ import java.sql.ResultSet
* @return A list of results for the given query * @return A list of results for the given query
*/ */
inline fun <reified TDoc> Connection.customList( inline fun <reified TDoc> Connection.customList(
query: String, parameters: Collection<Parameter<*>> = listOf(), mapFunc: (ResultSet) -> TDoc query: String, parameters: Collection<Parameter<*>> = listOf(), noinline mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Custom.list(query, parameters, this, mapFunc) ) = Custom.list(query, parameters, this, mapFunc)
/** /**
@ -26,7 +30,7 @@ inline fun <reified TDoc> Connection.customList(
* @return The document if one matches the query, `null` otherwise * @return The document if one matches the query, `null` otherwise
*/ */
inline fun <reified TDoc> Connection.customSingle( inline fun <reified TDoc> Connection.customSingle(
query: String, parameters: Collection<Parameter<*>> = listOf(), mapFunc: (ResultSet) -> TDoc query: String, parameters: Collection<Parameter<*>> = listOf(), noinline mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Custom.single(query, parameters, this, mapFunc) ) = Custom.single(query, parameters, this, mapFunc)
/** /**
@ -46,10 +50,10 @@ fun Connection.customNonQuery(query: String, parameters: Collection<Parameter<*>
* @param mapFunc The mapping function between the document and the domain item * @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query * @return The scalar value from the query
*/ */
inline fun <reified T> Connection.customScalar( inline fun <reified T : Any> Connection.customScalar(
query: String, query: String,
parameters: Collection<Parameter<*>> = listOf(), parameters: Collection<Parameter<*>> = listOf(),
mapFunc: (ResultSet) -> T & Any noinline mapFunc: (ResultSet, Class<T>) -> T
) = Custom.scalar(query, parameters, this, mapFunc) ) = Custom.scalar(query, parameters, this, mapFunc)
// ~~~ DEFINITION QUERIES ~~~ // ~~~ DEFINITION QUERIES ~~~

View File

@ -1,6 +1,10 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.query.Count import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.common.query.Count
import java.sql.Connection import java.sql.Connection
/** /**

View File

@ -1,5 +1,7 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.java.Custom
import java.sql.Connection import java.sql.Connection
import java.sql.ResultSet import java.sql.ResultSet
@ -13,13 +15,17 @@ object Custom {
* *
* @param query The query to retrieve the results * @param query The query to retrieve the results
* @param parameters Parameters to use for the query * @param parameters Parameters to use for the query
* @param clazz The class of the document to be returned
* @param conn The connection over which the query should be executed * @param conn The connection over which the query should be executed
* @param mapFunc The mapping function between the document and the domain item * @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query * @return A list of results for the given query
*/ */
inline fun <reified TDoc> list( inline fun <reified TDoc> list(
query: String, parameters: Collection<Parameter<*>> = listOf(), conn: Connection, mapFunc: (ResultSet) -> TDoc query: String,
) = Parameters.apply(conn, query, parameters).use { Results.toCustomList(it, mapFunc) } parameters: Collection<Parameter<*>> = listOf(),
conn: Connection,
noinline mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Custom.list(query, parameters, TDoc::class.java, conn, mapFunc)
/** /**
* Execute a query that returns a list of results (creates connection) * Execute a query that returns a list of results (creates connection)
@ -30,7 +36,9 @@ object Custom {
* @return A list of results for the given query * @return A list of results for the given query
*/ */
inline fun <reified TDoc> list( inline fun <reified TDoc> list(
query: String, parameters: Collection<Parameter<*>> = listOf(), mapFunc: (ResultSet) -> TDoc query: String,
parameters: Collection<Parameter<*>> = listOf(),
noinline mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Configuration.dbConn().use { list(query, parameters, it, mapFunc) } ) = Configuration.dbConn().use { list(query, parameters, it, mapFunc) }
/** /**
@ -43,8 +51,11 @@ object Custom {
* @return The document if one matches the query, `null` otherwise * @return The document if one matches the query, `null` otherwise
*/ */
inline fun <reified TDoc> single( inline fun <reified TDoc> single(
query: String, parameters: Collection<Parameter<*>> = listOf(), conn: Connection, mapFunc: (ResultSet) -> TDoc query: String,
) = list("$query LIMIT 1", parameters, conn, mapFunc).singleOrNull() parameters: Collection<Parameter<*>> = listOf(),
conn: Connection,
noinline mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Custom.single(query, parameters, TDoc::class.java, conn, mapFunc)
/** /**
* Execute a query that returns one or no results * Execute a query that returns one or no results
@ -55,7 +66,9 @@ object Custom {
* @return The document if one matches the query, `null` otherwise * @return The document if one matches the query, `null` otherwise
*/ */
inline fun <reified TDoc> single( inline fun <reified TDoc> single(
query: String, parameters: Collection<Parameter<*>> = listOf(), mapFunc: (ResultSet) -> TDoc query: String,
parameters: Collection<Parameter<*>> = listOf(),
noinline mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Configuration.dbConn().use { single(query, parameters, it, mapFunc) } ) = Configuration.dbConn().use { single(query, parameters, it, mapFunc) }
/** /**
@ -65,9 +78,8 @@ object Custom {
* @param conn The connection over which the query should be executed * @param conn The connection over which the query should be executed
* @param parameters Parameters to use for the query * @param parameters Parameters to use for the query
*/ */
fun nonQuery(query: String, parameters: Collection<Parameter<*>> = listOf(), conn: Connection) { fun nonQuery(query: String, parameters: Collection<Parameter<*>> = listOf(), conn: Connection) =
Parameters.apply(conn, query, parameters).use { it.executeUpdate() } Custom.nonQuery(query, parameters, conn)
}
/** /**
* Execute a query that returns no results * Execute a query that returns no results
@ -87,14 +99,12 @@ object Custom {
* @param mapFunc The mapping function between the document and the domain item * @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query * @return The scalar value from the query
*/ */
inline fun <reified T> scalar( inline fun <reified T : Any> scalar(
query: String, parameters: Collection<Parameter<*>> = listOf(), conn: Connection, mapFunc: (ResultSet) -> T & Any query: String,
) = Parameters.apply(conn, query, parameters).use { stmt -> parameters: Collection<Parameter<*>> = listOf(),
stmt.executeQuery().use { rs -> conn: Connection,
rs.next() noinline mapFunc: (ResultSet, Class<T>) -> T
mapFunc(rs) ) = Custom.scalar(query, parameters, T::class.java, conn, mapFunc)
}
}
/** /**
* Execute a query that returns a scalar result * Execute a query that returns a scalar result
@ -104,7 +114,7 @@ object Custom {
* @param mapFunc The mapping function between the document and the domain item * @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query * @return The scalar value from the query
*/ */
inline fun <reified T> scalar( inline fun <reified T : Any> scalar(
query: String, parameters: Collection<Parameter<*>> = listOf(), mapFunc: (ResultSet) -> T & Any query: String, parameters: Collection<Parameter<*>> = listOf(), noinline mapFunc: (ResultSet, Class<T>) -> T
) = Configuration.dbConn().use { scalar(query, parameters, it, mapFunc) } ) = Configuration.dbConn().use { scalar(query, parameters, it, mapFunc) }
} }

View File

@ -1,7 +1,8 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.DocumentIndex
import java.sql.Connection import java.sql.Connection
import solutions.bitbadger.documents.query.Definition import solutions.bitbadger.documents.common.query.Definition
/** /**
* Functions to define tables and indexes * Functions to define tables and indexes

View File

@ -1,6 +1,10 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.query.Delete import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.common.query.Delete
import java.sql.Connection import java.sql.Connection
/** /**

View File

@ -1,9 +1,12 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.AutoId
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.Field
import java.sql.Connection import java.sql.Connection
import solutions.bitbadger.documents.query.Document import solutions.bitbadger.documents.common.query.Document
import solutions.bitbadger.documents.query.Where import solutions.bitbadger.documents.common.query.Where
import solutions.bitbadger.documents.query.statementWhere import solutions.bitbadger.documents.common.query.statementWhere
/** /**
* Functions for manipulating documents * Functions for manipulating documents
@ -18,7 +21,7 @@ object Document {
* @param conn The connection on which the query should be executed * @param conn The connection on which the query should be executed
*/ */
@JvmStatic @JvmStatic
inline fun <reified TDoc> insert(tableName: String, document: TDoc, conn: Connection) { fun <TDoc> insert(tableName: String, document: TDoc, conn: Connection) {
val strategy = Configuration.autoIdStrategy val strategy = Configuration.autoIdStrategy
val query = if (strategy == AutoId.DISABLED) { val query = if (strategy == AutoId.DISABLED) {
Document.insert(tableName) Document.insert(tableName)
@ -60,7 +63,7 @@ object Document {
* @param document The document to be inserted * @param document The document to be inserted
*/ */
@JvmStatic @JvmStatic
inline fun <reified TDoc> insert(tableName: String, document: TDoc) = fun <TDoc> insert(tableName: String, document: TDoc) =
Configuration.dbConn().use { insert(tableName, document, it) } Configuration.dbConn().use { insert(tableName, document, it) }
/** /**
@ -71,7 +74,7 @@ object Document {
* @param conn The connection on which the query should be executed * @param conn The connection on which the query should be executed
*/ */
@JvmStatic @JvmStatic
inline fun <reified TDoc> save(tableName: String, document: TDoc, conn: Connection) = fun <TDoc> save(tableName: String, document: TDoc, conn: Connection) =
conn.customNonQuery(Document.save(tableName), listOf(Parameters.json(":data", document))) conn.customNonQuery(Document.save(tableName), listOf(Parameters.json(":data", document)))
/** /**
@ -81,7 +84,7 @@ object Document {
* @param document The document to be saved * @param document The document to be saved
*/ */
@JvmStatic @JvmStatic
inline fun <reified TDoc> save(tableName: String, document: TDoc) = fun <TDoc> save(tableName: String, document: TDoc) =
Configuration.dbConn().use { save(tableName, document, it) } Configuration.dbConn().use { save(tableName, document, it) }
/** /**
@ -93,7 +96,7 @@ object Document {
* @param conn The connection on which the query should be executed * @param conn The connection on which the query should be executed
*/ */
@JvmStatic @JvmStatic
inline fun <TKey, reified TDoc> update(tableName: String, docId: TKey, document: TDoc, conn: Connection) = fun <TKey, TDoc> update(tableName: String, docId: TKey, document: TDoc, conn: Connection) =
conn.customNonQuery( conn.customNonQuery(
statementWhere(Document.update(tableName), Where.byId(":id", docId)), statementWhere(Document.update(tableName), Where.byId(":id", docId)),
Parameters.addFields( Parameters.addFields(
@ -110,6 +113,6 @@ object Document {
* @param document The document to be replaced * @param document The document to be replaced
*/ */
@JvmStatic @JvmStatic
inline fun <TKey, reified TDoc> update(tableName: String, docId: TKey, document: TDoc) = fun <TKey, TDoc> update(tableName: String, docId: TKey, document: TDoc) =
Configuration.dbConn().use { update(tableName, docId, document, it) } Configuration.dbConn().use { update(tableName, docId, document, it) }
} }

View File

@ -1,6 +1,10 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.query.Exists import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.common.query.Exists
import java.sql.Connection import java.sql.Connection
/** /**

View File

@ -1,8 +1,12 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import java.sql.Connection import java.sql.Connection
import solutions.bitbadger.documents.query.Find import solutions.bitbadger.documents.common.query.Find
import solutions.bitbadger.documents.query.orderBy import solutions.bitbadger.documents.common.query.orderBy
/** /**
* Functions to find and retrieve documents * Functions to find and retrieve documents

View File

@ -1,5 +1,7 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.common.ParameterName
import java.sql.Connection import java.sql.Connection
import java.sql.PreparedStatement import java.sql.PreparedStatement
import java.sql.SQLException import java.sql.SQLException
@ -37,8 +39,9 @@ object Parameters {
* @param value The object to be encoded as JSON * @param value The object to be encoded as JSON
* @return A parameter with the value encoded * @return A parameter with the value encoded
*/ */
inline fun <reified T> json(name: String, value: T) = @JvmStatic
Parameter(name, ParameterType.JSON, Configuration.json.encodeToString(value)) fun <T> json(name: String, value: T) =
Parameter(name, ParameterType.JSON, Configuration.serializer.serialize(value))
/** /**
* Add field parameters to the given set of parameters * Add field parameters to the given set of parameters
@ -110,7 +113,9 @@ object Parameters {
* @param names The names of the fields to be removed * @param names The names of the fields to be removed
* @param parameterName The parameter name to use for the query * @param parameterName The parameter name to use for the query
* @return A list of parameters to use for building the query * @return A list of parameters to use for building the query
* @throws DocumentException If the dialect has not been set
*/ */
@Throws(DocumentException::class)
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
fun fieldNames(names: Collection<String>, parameterName: String = ":name"): MutableCollection<Parameter<*>> = fun fieldNames(names: Collection<String>, parameterName: String = ":name"): MutableCollection<Parameter<*>> =

View File

@ -1,6 +1,10 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.query.Patch import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.common.query.Patch
import java.sql.Connection import java.sql.Connection
/** /**

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.query.RemoveFields import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.common.query.RemoveFields
import java.sql.Connection import java.sql.Connection
/** /**

View File

@ -1,5 +1,8 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.java.Results
import java.sql.PreparedStatement import java.sql.PreparedStatement
import java.sql.ResultSet import java.sql.ResultSet
import java.sql.SQLException import java.sql.SQLException
@ -16,17 +19,18 @@ object Results {
* @param rs A `ResultSet` set to the row with the document to be constructed * @param rs A `ResultSet` set to the row with the document to be constructed
* @return The constructed domain item * @return The constructed domain item
*/ */
inline fun <reified TDoc> fromDocument(field: String, rs: ResultSet) = inline fun <reified TDoc> fromDocument(field: String): (ResultSet, Class<TDoc>) -> TDoc =
Configuration.json.decodeFromString<TDoc>(rs.getString(field)) { rs, _ -> Results.fromDocument(field, rs, TDoc::class.java) }
/** /**
* Create a domain item from a document * Create a domain item from a document
* *
* @param rs A `ResultSet` set to the row with the document to be constructed< * @param rs A `ResultSet` set to the row with the document to be constructed<
* @param clazz The class of the document to be returned
* @return The constructed domain item * @return The constructed domain item
*/ */
inline fun <reified TDoc> fromData(rs: ResultSet) = inline fun <reified TDoc> fromData(rs: ResultSet, clazz: Class<TDoc> = TDoc::class.java) =
fromDocument<TDoc>("data", rs) Results.fromDocument("data", rs, TDoc::class.java)
/** /**
* Create a list of items for the results of the given command, using the specified mapping function * Create a list of items for the results of the given command, using the specified mapping function
@ -36,7 +40,7 @@ object Results {
* @return A list of items from the query's result * @return A list of items from the query's result
* @throws DocumentException If there is a problem executing the query * @throws DocumentException If there is a problem executing the query
*/ */
inline fun <reified TDoc> toCustomList(stmt: PreparedStatement, mapFunc: (ResultSet) -> TDoc) = inline fun <reified TDoc : Any> toCustomList(stmt: PreparedStatement, mapFunc: (ResultSet) -> TDoc) =
try { try {
stmt.executeQuery().use { stmt.executeQuery().use {
val results = mutableListOf<TDoc>() val results = mutableListOf<TDoc>()
@ -55,10 +59,10 @@ object Results {
* @param rs A `ResultSet` set to the row with the count to retrieve * @param rs A `ResultSet` set to the row with the count to retrieve
* @return The count from the row * @return The count from the row
*/ */
fun toCount(rs: ResultSet) = fun toCount(rs: ResultSet, clazz: Class<Long> = Long::class.java) =
when (Configuration.dialect()) { when (Configuration.dialect()) {
Dialect.POSTGRESQL -> rs.getInt("it").toLong() Dialect.POSTGRESQL -> rs.getInt("it").toLong()
Dialect.SQLITE -> rs.getLong("it") Dialect.SQLITE -> rs.getLong("it")
} }
/** /**
@ -67,9 +71,9 @@ object Results {
* @param rs A `ResultSet` set to the row with the true/false value to retrieve * @param rs A `ResultSet` set to the row with the true/false value to retrieve
* @return The true/false value from the row * @return The true/false value from the row
*/ */
fun toExists(rs: ResultSet) = fun toExists(rs: ResultSet, clazz: Class<Boolean> = Boolean::class.java) =
when (Configuration.dialect()) { when (Configuration.dialect()) {
Dialect.POSTGRESQL -> rs.getBoolean("it") Dialect.POSTGRESQL -> rs.getBoolean("it")
Dialect.SQLITE -> toCount(rs) > 0L Dialect.SQLITE -> toCount(rs) > 0L
} }
} }

View File

@ -0,0 +1,143 @@
package solutions.bitbadger.documents.java
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.Parameters
import java.sql.Connection
import java.sql.ResultSet
object Custom {
/**
* Execute a query that returns a list of results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param clazz The class of the document to be returned
* @param conn The connection over which the query should be executed
* @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query
*/
@JvmStatic
fun <TDoc> list(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<TDoc>,
conn: Connection,
mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Parameters.apply(conn, query, parameters).use { Results.toCustomList(it, clazz, mapFunc) }
/**
* Execute a query that returns a list of results (creates connection)
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param clazz The class of the document to be returned
* @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query
*/
@JvmStatic
fun <TDoc> list(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<TDoc>,
mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Configuration.dbConn().use { list(query, parameters, clazz, it, mapFunc) }
/**
* Execute a query that returns one or no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param clazz The class of the document to be returned
* @param conn The connection over which the query should be executed
* @param mapFunc The mapping function between the document and the domain item
* @return The document if one matches the query, `null` otherwise
*/
@JvmStatic
fun <TDoc> single(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<TDoc>,
conn: Connection,
mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = list("$query LIMIT 1", parameters, clazz, conn, mapFunc).singleOrNull()
/**
* Execute a query that returns one or no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param clazz The class of the document to be returned
* @param mapFunc The mapping function between the document and the domain item
* @return The document if one matches the query, `null` otherwise
*/
@JvmStatic
fun <TDoc> single(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<TDoc>,
mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Configuration.dbConn().use { single(query, parameters, clazz, it, mapFunc) }
/**
* Execute a query that returns no results
*
* @param query The query to retrieve the results
* @param conn The connection over which the query should be executed
* @param parameters Parameters to use for the query
*/
@JvmStatic
fun nonQuery(query: String, parameters: Collection<Parameter<*>> = listOf(), conn: Connection) {
Parameters.apply(conn, query, parameters).use { it.executeUpdate() }
}
/**
* Execute a query that returns no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
*/
@JvmStatic
@JvmOverloads
fun nonQuery(query: String, parameters: Collection<Parameter<*>> = listOf()) =
Configuration.dbConn().use { nonQuery(query, parameters, it) }
/**
* Execute a query that returns a scalar result
*
* @param query The query to retrieve the result
* @param parameters Parameters to use for the query
* @param conn The connection over which the query should be executed
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
*/
@JvmStatic
fun <T : Any> scalar(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<T>,
conn: Connection,
mapFunc: (ResultSet, Class<T>) -> T
) = Parameters.apply(conn, query, parameters).use { stmt ->
stmt.executeQuery().use { rs ->
rs.next()
mapFunc(rs, clazz)
}
}
/**
* Execute a query that returns a scalar result
*
* @param query The query to retrieve the result
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
*/
fun <T : Any> scalar(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<T>,
mapFunc: (ResultSet, Class<T>) -> T
) = Configuration.dbConn().use { scalar(query, parameters, clazz, it, mapFunc) }
}

View File

@ -0,0 +1,91 @@
package solutions.bitbadger.documents.java
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException
import kotlin.jvm.Throws
object Results {
/**
* Create a domain item from a document, specifying the field in which the document is found
*
* @param field The field name containing the JSON document
* @param rs A `ResultSet` set to the row with the document to be constructed
* @param clazz The class of the document to be returned
* @return The constructed domain item
*/
@JvmStatic
fun <TDoc> fromDocument(field: String, rs: ResultSet, clazz: Class<TDoc>) =
Configuration.serializer.deserialize(rs.getString(field), clazz)
/**
* Create a domain item from a document
*
* @param rs A `ResultSet` set to the row with the document to be constructed<
* @param clazz The class of the document to be returned
* @return The constructed domain item
*/
@JvmStatic
fun <TDoc> fromData(rs: ResultSet, clazz: Class<TDoc>) =
fromDocument("data", rs, clazz)
/**
* Create a list of items for the results of the given command, using the specified mapping function
*
* @param stmt The prepared statement to execute
* @param mapFunc The mapping function from data reader to domain class instance
* @param clazz The class of the document to be returned
* @return A list of items from the query's result
* @throws DocumentException If there is a problem executing the query
*/
@Throws(DocumentException::class)
@JvmStatic
fun <TDoc> toCustomList(
stmt: PreparedStatement, clazz: Class<TDoc>, mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) =
try {
stmt.executeQuery().use {
val results = mutableListOf<TDoc>()
while (it.next()) {
results.add(mapFunc(it, clazz))
}
results.toList()
}
} catch (ex: SQLException) {
throw DocumentException("Error retrieving documents from query: ${ex.message}", ex)
}
/**
* Extract a count from the first column
*
* @param rs A `ResultSet` set to the row with the count to retrieve
* @return The count from the row
* @throws DocumentException If the dialect has not been set
*/
@Throws(DocumentException::class)
@JvmStatic
fun toCount(rs: ResultSet) =
when (Configuration.dialect()) {
Dialect.POSTGRESQL -> rs.getInt("it").toLong()
Dialect.SQLITE -> rs.getLong("it")
}
/**
* Extract a true/false value from the first column
*
* @param rs A `ResultSet` set to the row with the true/false value to retrieve
* @return The true/false value from the row
* @throws DocumentException If the dialect has not been set
*/
@Throws(DocumentException::class)
@JvmStatic
fun toExists(rs: ResultSet) =
when (Configuration.dialect()) {
Dialect.POSTGRESQL -> rs.getBoolean("it")
Dialect.SQLITE -> toCount(rs) > 0L
}
}

92
src/pom.xml Normal file
View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>solutions.bitbadger</groupId>
<artifactId>documents</artifactId>
<version>4.0.0-alpha1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>${project.groupId}:${project.artifactId}</name>
<description>Expose a document store interface for PostgreSQL and SQLite</description>
<url>https://bitbadger.solutions/open-source/solutions.bitbadger.documents</url>
<licenses>
<license>
<name>MIT License</name>
<url>https://www.opensource.org/licenses/mit-license.php</url>
</license>
</licenses>
<developers>
<developer>
<name>Daniel J. Summers</name>
<email>daniel@bitbadger.solutions</email>
<organization>Bit Badger Solutions</organization>
<organizationUrl>https://bitbadger.solutions</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:https://git.bitbadger.solutions/bit-badger/solutions.bitbadger.documents.git</connection>
<developerConnection>scm:git:https://git.bitbadger.solutions/bit-badger/solutions.bitbadger.documents.git</developerConnection>
<url>https://git.bitbadger.solutions/bit-badger/solutions.bitbadger.documents</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget>
<kotlin.version>2.1.0</kotlin.version>
<serialization.version>1.8.0</serialization.version>
</properties>
<modules>
<module>common</module>
</modules>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit5</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-json</artifactId>
<version>${serialization.version}</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -3,6 +3,8 @@ package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*; import solutions.bitbadger.documents.*;
import solutions.bitbadger.documents.common.Dialect;
import solutions.bitbadger.documents.common.DocumentException;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;

View File

@ -4,8 +4,11 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*; import solutions.bitbadger.documents.*;
import solutions.bitbadger.documents.common.DocumentException;
import solutions.bitbadger.documents.common.Field;
import solutions.bitbadger.documents.common.Parameter;
import solutions.bitbadger.documents.common.ParameterType;
import java.util.Collection;
import java.util.List; import java.util.List;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -63,9 +66,9 @@ final public class ParametersTest {
@Test @Test
@DisplayName("fieldNames generates a single parameter (PostgreSQL)") @DisplayName("fieldNames generates a single parameter (PostgreSQL)")
public void fieldNamesSinglePostgres() { public void fieldNamesSinglePostgres() throws DocumentException {
Configuration.setConnectionString(":postgresql:"); Configuration.setConnectionString(":postgresql:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test")).toArray(new Parameter<?>[] { }); Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test")).toArray(new Parameter<?>[]{});
assertEquals(1, nameParams.length, "There should be one name parameter"); assertEquals(1, nameParams.length, "There should be one name parameter");
assertEquals(":name", nameParams[0].getName(), "The parameter name is incorrect"); assertEquals(":name", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect"); assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
@ -74,10 +77,10 @@ final public class ParametersTest {
@Test @Test
@DisplayName("fieldNames generates multiple parameters (PostgreSQL)") @DisplayName("fieldNames generates multiple parameters (PostgreSQL)")
public void fieldNamesMultiplePostgres() { public void fieldNamesMultiplePostgres() throws DocumentException {
Configuration.setConnectionString(":postgresql:"); Configuration.setConnectionString(":postgresql:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today")) Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today"))
.toArray(new Parameter<?>[] { }); .toArray(new Parameter<?>[]{});
assertEquals(1, nameParams.length, "There should be one name parameter"); assertEquals(1, nameParams.length, "There should be one name parameter");
assertEquals(":name", nameParams[0].getName(), "The parameter name is incorrect"); assertEquals(":name", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect"); assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
@ -86,9 +89,9 @@ final public class ParametersTest {
@Test @Test
@DisplayName("fieldNames generates a single parameter (SQLite)") @DisplayName("fieldNames generates a single parameter (SQLite)")
public void fieldNamesSingleSQLite() { public void fieldNamesSingleSQLite() throws DocumentException {
Configuration.setConnectionString(":sqlite:"); Configuration.setConnectionString(":sqlite:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test")).toArray(new Parameter<?>[] { }); Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test")).toArray(new Parameter<?>[]{});
assertEquals(1, nameParams.length, "There should be one name parameter"); assertEquals(1, nameParams.length, "There should be one name parameter");
assertEquals(":name0", nameParams[0].getName(), "The parameter name is incorrect"); assertEquals(":name0", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect"); assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
@ -97,10 +100,10 @@ final public class ParametersTest {
@Test @Test
@DisplayName("fieldNames generates multiple parameters (SQLite)") @DisplayName("fieldNames generates multiple parameters (SQLite)")
public void fieldNamesMultipleSQLite() { public void fieldNamesMultipleSQLite() throws DocumentException {
Configuration.setConnectionString(":sqlite:"); Configuration.setConnectionString(":sqlite:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today")) Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today"))
.toArray(new Parameter<?>[] { }); .toArray(new Parameter<?>[]{});
assertEquals(3, nameParams.length, "There should be one name parameter"); assertEquals(3, nameParams.length, "There should be one name parameter");
assertEquals(":name0", nameParams[0].getName(), "The first parameter name is incorrect"); assertEquals(":name0", nameParams[0].getName(), "The first parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The first parameter type is incorrect"); assertEquals(ParameterType.STRING, nameParams[0].getType(), "The first parameter type is incorrect");

View File

@ -0,0 +1,22 @@
package solutions.bitbadger.documents.java.integration.postgresql;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.integration.postgresql.PgDB;
import solutions.bitbadger.documents.java.integration.common.Count;
/**
* PostgreSQL integration tests for the `Count` object / `count*` connection extension functions
*/
@DisplayName("Java | PostgreSQL: Count")
public class CountIT {
@Test
@DisplayName("all counts all documents")
public void all() {
try (PgDB db = new PgDB()) {
Count.all(db);
}
}
}

View File

@ -1,5 +1,6 @@
package solutions.bitbadger.documents.java.testDocs; package solutions.bitbadger.documents.java.testDocs;
import kotlinx.serialization.Serializable;
import solutions.bitbadger.documents.Document; import solutions.bitbadger.documents.Document;
import solutions.bitbadger.documents.integration.ThrowawayDatabase; import solutions.bitbadger.documents.integration.ThrowawayDatabase;
@ -7,6 +8,7 @@ import java.util.List;
import static solutions.bitbadger.documents.integration.TypesKt.TEST_TABLE; import static solutions.bitbadger.documents.integration.TypesKt.TEST_TABLE;
@Serializable
public class JsonDocument { public class JsonDocument {
private String id; private String id;
@ -70,8 +72,7 @@ public class JsonDocument {
public static void load(ThrowawayDatabase db, String tableName) { public static void load(ThrowawayDatabase db, String tableName) {
for (JsonDocument doc : testDocuments) { for (JsonDocument doc : testDocuments) {
// TODO: inline reified generics cannot be called from Java :( Document.insert(tableName, doc, db.getConn());
// Document.insert(tableName, doc, db.getConn());
} }
} }

View File

@ -2,8 +2,6 @@ package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -20,34 +18,4 @@ class ConfigurationTest {
assertFalse(Configuration.json.configuration.explicitNulls, "Explicit Nulls should not have been set") assertFalse(Configuration.json.configuration.explicitNulls, "Explicit Nulls should not have been set")
assertTrue(Configuration.json.configuration.coerceInputValues, "Coerce Input Values should have been set") assertTrue(Configuration.json.configuration.coerceInputValues, "Coerce Input Values should have been set")
} }
@Test
@DisplayName("Default ID field is `id`")
fun defaultIdField() {
assertEquals("id", Configuration.idField, "Default ID field incorrect")
}
@Test
@DisplayName("Default Auto ID strategy is `DISABLED`")
fun defaultAutoId() {
assertEquals(AutoId.DISABLED, Configuration.autoIdStrategy, "Default Auto ID strategy should be `disabled`")
}
@Test
@DisplayName("Default ID string length should be 16")
fun defaultIdStringLength() {
assertEquals(16, Configuration.idStringLength, "Default ID string length should be 16")
}
@Test
@DisplayName("Dialect is derived from connection string")
fun dialectIsDerived() {
try {
assertThrows<DocumentException> { Configuration.dialect() }
Configuration.connectionString = "jdbc:postgresql:db"
assertEquals(Dialect.POSTGRESQL, Configuration.dialect())
} finally {
Configuration.connectionString = null
}
}
} }

View File

@ -3,6 +3,7 @@ package solutions.bitbadger.documents
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.common.*
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotSame import kotlin.test.assertNotSame
@ -51,8 +52,10 @@ class ParametersTest {
@Test @Test
@DisplayName("replaceNamesInQuery replaces successfully") @DisplayName("replaceNamesInQuery replaces successfully")
fun replaceNamesInQuery() { fun replaceNamesInQuery() {
val parameters = listOf(Parameter(":data", ParameterType.JSON, "{}"), val parameters = listOf(
Parameter(":data_ext", ParameterType.STRING, "")) Parameter(":data", ParameterType.JSON, "{}"),
Parameter(":data_ext", ParameterType.STRING, "")
)
val query = "SELECT data, data_ext FROM tbl WHERE data = :data AND data_ext = :data_ext AND more_data = :data" val query = "SELECT data, data_ext FROM tbl WHERE data = :data AND data_ext = :data_ext AND more_data = :data"
assertEquals("SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?", assertEquals("SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?",
Parameters.replaceNamesInQuery(query, parameters), "Parameters not replaced correctly") Parameters.replaceNamesInQuery(query, parameters), "Parameters not replaced correctly")

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.JsonDocument import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase

View File

@ -1,12 +1,15 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.integration.JsonDocument import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase
import solutions.bitbadger.documents.query.Count import solutions.bitbadger.documents.common.query.Count
import solutions.bitbadger.documents.query.Delete import solutions.bitbadger.documents.common.query.Delete
import solutions.bitbadger.documents.query.Find import solutions.bitbadger.documents.common.query.Find
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
import kotlin.test.assertNull import kotlin.test.assertNull

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.DocumentIndex
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase
import kotlin.test.assertFalse import kotlin.test.assertFalse

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.JsonDocument import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.* import solutions.bitbadger.documents.integration.*
import kotlin.test.* import kotlin.test.*

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.JsonDocument import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.integration.* import solutions.bitbadger.documents.integration.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
@ -209,7 +211,8 @@ object Find {
fun firstByFieldsMatchOrdered(db: ThrowawayDatabase) { fun firstByFieldsMatchOrdered(db: ThrowawayDatabase) {
JsonDocument.load(db) JsonDocument.load(db)
val doc = db.conn.findFirstByFields<JsonDocument>(TEST_TABLE, listOf(Field.equal("sub.foo", "green")), orderBy = listOf(Field.named("n:numValue DESC"))) val doc = db.conn.findFirstByFields<JsonDocument>(TEST_TABLE, listOf(Field.equal("sub.foo", "green")), orderBy = listOf(
Field.named("n:numValue DESC")))
assertNotNull(doc, "There should have been a document returned") assertNotNull(doc, "There should have been a document returned")
assertEquals("four", doc.id, "An incorrect document was returned") assertEquals("four", doc.id, "An incorrect document was returned")
} }

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.JsonDocument import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.JsonDocument import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase

View File

@ -7,7 +7,7 @@ import kotlin.test.Test
/** /**
* PostgreSQL integration tests for the `Count` object / `count*` connection extension functions * PostgreSQL integration tests for the `Count` object / `count*` connection extension functions
*/ */
@DisplayName("PostgreSQL - Count") @DisplayName("Kotlin | PostgreSQL: Count")
class CountIT { class CountIT {
@Test @Test

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents.integration.postgresql package solutions.bitbadger.documents.integration.postgresql
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Count import solutions.bitbadger.documents.integration.common.Count
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Definition import solutions.bitbadger.documents.integration.common.Definition
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Delete import solutions.bitbadger.documents.integration.common.Delete
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Exists import solutions.bitbadger.documents.integration.common.Exists
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Find import solutions.bitbadger.documents.integration.common.Find
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Patch import solutions.bitbadger.documents.integration.common.Patch
import kotlin.test.Test import kotlin.test.Test

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.RemoveFields import solutions.bitbadger.documents.integration.common.RemoveFields
import kotlin.test.Test import kotlin.test.Test

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents.integration.sqlite package solutions.bitbadger.documents.integration.sqlite
import solutions.bitbadger.documents.* import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Parameter
import solutions.bitbadger.documents.common.ParameterType
import solutions.bitbadger.documents.integration.TEST_TABLE import solutions.bitbadger.documents.integration.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase import solutions.bitbadger.documents.integration.ThrowawayDatabase
import java.io.File import java.io.File