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">
<component name="AdditionalModuleElements">
<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" />
</content>
</component>

View File

@ -61,7 +61,7 @@
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</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.reflect.full.*
@ -10,10 +10,13 @@ import kotlin.reflect.jvm.isAccessible
enum class AutoId {
/** No automatic IDs will be generated */
DISABLED,
/** Generate a `MAX`-plus-1 numeric ID */
NUMBER,
/** Generate a `UUID` string ID */
UUID,
/** Generate a random hex character string ID */
RANDOM_STRING;
@ -24,7 +27,8 @@ enum class AutoId {
*
* @return A `UUID` string
*/
@JvmStatic fun generateUUID(): String =
@JvmStatic
fun generateUUID(): String =
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)
* @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 ->
kotlin.random.Random.nextBytes((len + 2) / 2)
.joinToString("") { String.format("%02x", it) }
@ -50,7 +55,8 @@ enum class AutoId {
* @throws DocumentException If bad input prevents the determination
*/
@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 (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

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

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

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents
package solutions.bitbadger.documents.common
/**
* 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

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents
package solutions.bitbadger.documents.common
/**
* 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

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents
package solutions.bitbadger.documents.common
/**
* 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.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

View File

@ -1,4 +1,4 @@
package solutions.bitbadger.documents
package solutions.bitbadger.documents.common
/**
* The types of parameters supported by the document library
@ -6,8 +6,10 @@ package solutions.bitbadger.documents
enum class ParameterType {
/** The parameter value is some sort of number (`Byte`, `Short`, `Int`, or `Long`) */
NUMBER,
/** The parameter value is a string */
STRING,
/** The parameter should be JSON-encoded */
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.FieldMatch
import solutions.bitbadger.documents.query.byFields as byFieldsBase;
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.query.byFields as byFieldsBase;
/**
* 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
@ -87,6 +87,6 @@ object Definition {
throw DocumentException("'Document indexes are only supported on PostgreSQL")
}
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.FieldMatch
import solutions.bitbadger.documents.query.byFields as byFieldsBase
import solutions.bitbadger.documents.query.byId as byIdBase
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
import solutions.bitbadger.documents.common.query.byId as byIdBase
/**
* Functions to delete documents
@ -14,7 +14,6 @@ object Delete {
* Query to delete documents from a table
*
* @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
*/
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.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.common.AutoId
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
/**
* 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.FieldMatch
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
/**
* 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.FieldMatch
import solutions.bitbadger.documents.query.byId as byIdBase
import solutions.bitbadger.documents.query.byFields as byFieldsBase
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.common.query.byId as byIdBase
import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
/**
* 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.Dialect
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.FieldMatch
import solutions.bitbadger.documents.query.byFields as byFieldsBase
import solutions.bitbadger.documents.query.byId as byIdBase
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 solutions.bitbadger.documents.common.query.byFields as byFieldsBase
import solutions.bitbadger.documents.common.query.byId as byIdBase
/**
* 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.Dialect
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.FieldMatch
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
// ~~~ 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.query.byFields as byFieldsBase
import solutions.bitbadger.documents.query.byId as byIdBase
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.common.query.byFields as byFieldsBase
import solutions.bitbadger.documents.common.query.byId as byIdBase
/**
* 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

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.Test;
import solutions.bitbadger.documents.AutoId;
import solutions.bitbadger.documents.DocumentException;
import solutions.bitbadger.documents.common.AutoId;
import solutions.bitbadger.documents.common.DocumentException;
import solutions.bitbadger.documents.java.testDocs.*;
import static org.junit.jupiter.api.Assertions.*;
@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `AutoId` enum
*/
@DisplayName("Java | AutoId")
@DisplayName("Java | Common | AutoId")
final public class AutoIdTest {
@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.Test;
import solutions.bitbadger.documents.DocumentIndex;
import solutions.bitbadger.documents.common.DocumentIndex;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `DocumentIndex` enum
*/
@DisplayName("Java | DocumentIndex")
@DisplayName("Java | Common | DocumentIndex")
final public class DocumentIndexTest {
@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.Test;
import solutions.bitbadger.documents.FieldMatch;
import solutions.bitbadger.documents.common.FieldMatch;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `FieldMatch` enum
*/
@DisplayName("Java | FieldMatch")
@DisplayName("Java | Common | FieldMatch")
final public class FieldMatchTest {
@Test

View File

@ -1,10 +1,10 @@
package solutions.bitbadger.documents.java;
package solutions.bitbadger.documents.common.java;
import kotlin.Pair;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*;
import solutions.bitbadger.documents.common.*;
import java.util.Collection;
import java.util.List;
@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `Field` class
*/
@DisplayName("Java | Field")
@DisplayName("Java | Common | Field")
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.Test;
import solutions.bitbadger.documents.Op;
import solutions.bitbadger.documents.common.Op;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `Op` enum
*/
@DisplayName("Java | Op")
@DisplayName("Java | Common | Op")
final public class OpTest {
@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.Test;
import solutions.bitbadger.documents.ParameterName;
import solutions.bitbadger.documents.common.ParameterName;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `ParameterName` class
*/
@DisplayName("Java | ParameterName")
@DisplayName("Java | Common | ParameterName")
final public class ParameterNameTest {
@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.Test;
import solutions.bitbadger.documents.DocumentException;
import solutions.bitbadger.documents.Parameter;
import solutions.bitbadger.documents.ParameterType;
import solutions.bitbadger.documents.common.DocumentException;
import solutions.bitbadger.documents.common.Parameter;
import solutions.bitbadger.documents.common.ParameterType;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `Parameter` class
*/
@DisplayName("Java | Parameter")
@DisplayName("Java | Common | Parameter")
final public class ParameterTest {
@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.Test
@ -11,7 +11,7 @@ import kotlin.test.assertTrue
/**
* Unit tests for the `AutoId` enum
*/
@DisplayName("Kotlin | AutoId")
@DisplayName("Kotlin | Common | AutoId")
class AutoIdTest {
@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.Test
@ -21,7 +21,8 @@ class ComparisonBetweenTest {
@Test
@DisplayName("isNumeric is false with strings")
fun isNumericFalseForStringsAndBetween() =
assertFalse(ComparisonBetween(Pair("eh", "zed")).isNumeric,
assertFalse(
ComparisonBetween(Pair("eh", "zed")).isNumeric,
"A BETWEEN with strings should not be numeric")
@Test
@ -32,7 +33,8 @@ class ComparisonBetweenTest {
@Test
@DisplayName("isNumeric is true with shorts")
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")
@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.Test
@ -9,19 +9,21 @@ import kotlin.test.assertTrue
/**
* Unit tests for the `Dialect` enum
*/
@DisplayName("Dialect")
@DisplayName("Kotlin | Common | Dialect")
class DialectTest {
@Test
@DisplayName("deriveFromConnectionString derives PostgreSQL correctly")
fun derivesPostgres() =
assertEquals(Dialect.POSTGRESQL, Dialect.deriveFromConnectionString("jdbc:postgresql:db"),
assertEquals(
Dialect.POSTGRESQL, Dialect.deriveFromConnectionString("jdbc:postgresql:db"),
"Dialect should have been PostgreSQL")
@Test
@DisplayName("deriveFromConnectionString derives PostgreSQL correctly")
fun derivesSQLite() =
assertEquals(Dialect.SQLITE, Dialect.deriveFromConnectionString("jdbc:sqlite:memory"),
assertEquals(
Dialect.SQLITE, Dialect.deriveFromConnectionString("jdbc:sqlite:memory"),
"Dialect should have been SQLite")
@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.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `DocumentIndex` enum
*/
@DisplayName("Kotlin | DocumentIndex")
@DisplayName("Kotlin | Common | DocumentIndex")
class DocumentIndexTest {
@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.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `FieldMatch` enum
*/
@DisplayName("Kotlin | FieldMatch")
@DisplayName("Kotlin | Common | FieldMatch")
class FieldMatchTest {
@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.DisplayName
@ -11,7 +11,7 @@ import kotlin.test.assertNull
/**
* Unit tests for the `Field` class
*/
@DisplayName("Kotlin | Field")
@DisplayName("Kotlin | Common | Field")
class FieldTest {
/**
@ -19,7 +19,7 @@ class FieldTest {
*/
@AfterEach
fun cleanUp() {
Configuration.connectionString = null
Configuration.dialectValue = null
}
// ~~~ INSTANCE METHODS ~~~
@ -122,7 +122,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)")
fun toWhereExistsNoQualPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -130,7 +130,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for exists w/o qualifier (SQLite)")
fun toWhereExistsNoQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -138,7 +138,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for not-exists w/o qualifier (PostgreSQL)")
fun toWhereNotExistsNoQualPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -146,7 +146,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for not-exists w/o qualifier (SQLite)")
fun toWhereNotExistsNoQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -154,7 +154,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, numeric range (PostgreSQL)")
fun toWhereBetweenNoQualNumericPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").toWhere(), "Field WHERE clause not generated correctly")
}
@ -162,7 +162,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range (PostgreSQL)")
fun toWhereBetweenNoQualAlphaPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").toWhere(),
"Field WHERE clause not generated correctly")
@ -171,7 +171,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier (SQLite)")
fun toWhereBetweenNoQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field.between("age", 13, 17, "@age").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -179,7 +179,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, numeric range (PostgreSQL)")
fun toWhereBetweenQualNumericPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(test.data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly")
@ -188,7 +188,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range (PostgreSQL)")
fun toWhereBetweenQualAlphaPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("unit.data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").withQualifier("unit").toWhere(),
"Field WHERE clause not generated correctly")
@ -197,7 +197,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier (SQLite)")
fun toWhereBetweenQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("my.data->>'age' BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("my").toWhere(),
"Field WHERE clause not generated correctly")
@ -206,7 +206,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for IN/any, numeric values (PostgreSQL)")
fun toWhereAnyNumericPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
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")
}
@ -214,7 +214,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for IN/any, alphanumeric values (PostgreSQL)")
fun toWhereAnyAlphaPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly")
@ -223,7 +223,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for IN/any (SQLite)")
fun toWhereAnySQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly")
@ -232,7 +232,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for inArray (PostgreSQL)")
fun toWhereInArrayPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]",
Field.inArray("even", "tbl", listOf(2, 4, 6, 8), ":it").toWhere(),
"Field WHERE clause not generated correctly")
@ -241,7 +241,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for inArray (SQLite)")
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))",
Field.inArray("test", "tbl", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly")
@ -250,7 +250,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for others w/o qualifier (PostgreSQL)")
fun toWhereOtherNoQualPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -258,7 +258,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates for others w/o qualifier (SQLite)")
fun toWhereOtherNoQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -266,7 +266,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates no-parameter w/ qualifier (PostgreSQL)")
fun toWhereNoParamWithQualPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -274,7 +274,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates no-parameter w/ qualifier (SQLite)")
fun toWhereNoParamWithQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly")
}
@ -282,7 +282,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates parameter w/ qualifier (PostgreSQL)")
fun toWhereParamWithQualPostgres() {
Configuration.connectionString = ":postgresql:"
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(q.data->>'le_field')::numeric <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly")
@ -291,7 +291,7 @@ class FieldTest {
@Test
@DisplayName("toWhere generates parameter w/ qualifier (SQLite)")
fun toWhereParamWithQualSQLite() {
Configuration.connectionString = ":sqlite:"
Configuration.dialectValue = Dialect.SQLITE
assertEquals("q.data->>'le_field' <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"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.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `Op` enum
*/
@DisplayName("Kotlin | Op")
@DisplayName("Kotlin | Common | Op")
class OpTest {
@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.Test
@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `ParameterName` class
*/
@DisplayName("Kotlin | ParameterName")
@DisplayName("Kotlin | Common | ParameterName")
class ParameterNameTest {
@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.assertThrows
@ -9,7 +9,7 @@ import kotlin.test.assertNull
/**
* Unit tests for the `Parameter` class
*/
@DisplayName("Kotlin | Parameter")
@DisplayName("Kotlin | Common | Parameter")
class ParameterTest {
@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.DisplayName
import org.junit.jupiter.api.Test
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
/**
* Unit tests for the `Count` object
*/
@DisplayName("Count (Query)")
@DisplayName("Kotlin | Common | Query: Count")
class CountTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.DocumentIndex
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Dialect
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.common.DocumentIndex
import kotlin.test.assertEquals
/**
* Unit tests for the `Definition` object
*/
@DisplayName("Definition (Query)")
@DisplayName("Kotlin | Common | Query: Definition")
class DefinitionTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
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
/**
* Unit tests for the `Delete` object
*/
@DisplayName("Delete (Query)")
@DisplayName("Kotlin | Common | Query: Delete")
class DeleteTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
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.assertTrue
/**
* Unit tests for the `Document` object
*/
@DisplayName("Document (Query)")
@DisplayName("Kotlin | Common | Query: Document")
class DocumentTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
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
/**
* Unit tests for the `Exists` object
*/
@DisplayName("Exists (Query)")
@DisplayName("Kotlin | Common | Query: Exists")
class ExistsTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
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
/**
* Unit tests for the `Find` object
*/
@DisplayName("Find (Query)")
@DisplayName("Kotlin | Common | Query: Find")
class FindTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
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
/**
* Unit tests for the `Patch` object
*/
@DisplayName("Patch (Query)")
@DisplayName("Kotlin | Common | Query: Patch")
class PatchTest {
/** 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.DisplayName
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
/**
* Unit tests for the top-level query functions
*/
@DisplayName("Query")
@DisplayName("Kotlin | Common | Query")
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.DisplayName
import org.junit.jupiter.api.Test
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
/**
* Unit tests for the `RemoveFields` object
*/
@DisplayName("RemoveFields (Query)")
@DisplayName("Kotlin | Common | Query: RemoveFields")
class RemoveFieldsTest {
/** 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.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.*
import kotlin.test.assertEquals
/**
* Unit tests for the `Where` object
*/
@DisplayName("Where (Query)")
@DisplayName("Kotlin | Common | Query: Where")
class WhereTest {
/**

View File

@ -1,6 +1,9 @@
package solutions.bitbadger.documents
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.DriverManager
import kotlin.jvm.Throws
@ -20,58 +23,8 @@ object Configuration {
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 */
@JvmStatic
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
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.ResultSet
@ -14,7 +18,7 @@ import java.sql.ResultSet
* @return A list of results for the given query
*/
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)
/**
@ -26,7 +30,7 @@ inline fun <reified TDoc> Connection.customList(
* @return The document if one matches the query, `null` otherwise
*/
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)
/**
@ -46,10 +50,10 @@ fun Connection.customNonQuery(query: String, parameters: Collection<Parameter<*>
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
*/
inline fun <reified T> Connection.customScalar(
inline fun <reified T : Any> Connection.customScalar(
query: String,
parameters: Collection<Parameter<*>> = listOf(),
mapFunc: (ResultSet) -> T & Any
noinline mapFunc: (ResultSet, Class<T>) -> T
) = Custom.scalar(query, parameters, this, mapFunc)
// ~~~ DEFINITION QUERIES ~~~

View File

@ -1,6 +1,10 @@
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
/**

View File

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

View File

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

View File

@ -1,6 +1,10 @@
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
/**

View File

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

View File

@ -1,6 +1,10 @@
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
/**

View File

@ -1,8 +1,12 @@
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 solutions.bitbadger.documents.query.Find
import solutions.bitbadger.documents.query.orderBy
import solutions.bitbadger.documents.common.query.Find
import solutions.bitbadger.documents.common.query.orderBy
/**
* Functions to find and retrieve documents

View File

@ -1,5 +1,7 @@
package solutions.bitbadger.documents
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.common.ParameterName
import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.SQLException
@ -37,8 +39,9 @@ object Parameters {
* @param value The object to be encoded as JSON
* @return A parameter with the value encoded
*/
inline fun <reified T> json(name: String, value: T) =
Parameter(name, ParameterType.JSON, Configuration.json.encodeToString(value))
@JvmStatic
fun <T> json(name: String, value: T) =
Parameter(name, ParameterType.JSON, Configuration.serializer.serialize(value))
/**
* 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 parameterName The parameter name to use for 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
@JvmOverloads
fun fieldNames(names: Collection<String>, parameterName: String = ":name"): MutableCollection<Parameter<*>> =

View File

@ -1,6 +1,10 @@
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
/**

View File

@ -1,6 +1,7 @@
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
/**

View File

@ -1,5 +1,8 @@
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.ResultSet
import java.sql.SQLException
@ -16,17 +19,18 @@ object Results {
* @param rs A `ResultSet` set to the row with the document to be constructed
* @return The constructed domain item
*/
inline fun <reified TDoc> fromDocument(field: String, rs: ResultSet) =
Configuration.json.decodeFromString<TDoc>(rs.getString(field))
inline fun <reified TDoc> fromDocument(field: String): (ResultSet, Class<TDoc>) -> TDoc =
{ rs, _ -> Results.fromDocument(field, rs, TDoc::class.java) }
/**
* 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
*/
inline fun <reified TDoc> fromData(rs: ResultSet) =
fromDocument<TDoc>("data", rs)
inline fun <reified TDoc> fromData(rs: ResultSet, clazz: Class<TDoc> = TDoc::class.java) =
Results.fromDocument("data", rs, TDoc::class.java)
/**
* 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
* @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 {
stmt.executeQuery().use {
val results = mutableListOf<TDoc>()
@ -55,10 +59,10 @@ object Results {
* @param rs A `ResultSet` set to the row with the count to retrieve
* @return The count from the row
*/
fun toCount(rs: ResultSet) =
fun toCount(rs: ResultSet, clazz: Class<Long> = Long::class.java) =
when (Configuration.dialect()) {
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
* @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()) {
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.Test;
import solutions.bitbadger.documents.*;
import solutions.bitbadger.documents.common.Dialect;
import solutions.bitbadger.documents.common.DocumentException;
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.Test;
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 static org.junit.jupiter.api.Assertions.*;
@ -63,9 +66,9 @@ final public class ParametersTest {
@Test
@DisplayName("fieldNames generates a single parameter (PostgreSQL)")
public void fieldNamesSinglePostgres() {
public void fieldNamesSinglePostgres() throws DocumentException {
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(":name", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
@ -74,10 +77,10 @@ final public class ParametersTest {
@Test
@DisplayName("fieldNames generates multiple parameters (PostgreSQL)")
public void fieldNamesMultiplePostgres() {
public void fieldNamesMultiplePostgres() throws DocumentException {
Configuration.setConnectionString(":postgresql:");
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(":name", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
@ -86,9 +89,9 @@ final public class ParametersTest {
@Test
@DisplayName("fieldNames generates a single parameter (SQLite)")
public void fieldNamesSingleSQLite() {
public void fieldNamesSingleSQLite() throws DocumentException {
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(":name0", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
@ -97,10 +100,10 @@ final public class ParametersTest {
@Test
@DisplayName("fieldNames generates multiple parameters (SQLite)")
public void fieldNamesMultipleSQLite() {
public void fieldNamesMultipleSQLite() throws DocumentException {
Configuration.setConnectionString(":sqlite:");
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(":name0", nameParams[0].getName(), "The first parameter name 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;
import kotlinx.serialization.Serializable;
import solutions.bitbadger.documents.Document;
import solutions.bitbadger.documents.integration.ThrowawayDatabase;
@ -7,6 +8,7 @@ import java.util.List;
import static solutions.bitbadger.documents.integration.TypesKt.TEST_TABLE;
@Serializable
public class JsonDocument {
private String id;
@ -70,8 +72,7 @@ public class JsonDocument {
public static void load(ThrowawayDatabase db, String tableName) {
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.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -20,34 +18,4 @@ class ConfigurationTest {
assertFalse(Configuration.json.configuration.explicitNulls, "Explicit Nulls should not 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.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.common.*
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotSame
@ -51,8 +52,10 @@ class ParametersTest {
@Test
@DisplayName("replaceNamesInQuery replaces successfully")
fun replaceNamesInQuery() {
val parameters = listOf(Parameter(":data", ParameterType.JSON, "{}"),
Parameter(":data_ext", ParameterType.STRING, ""))
val parameters = listOf(
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"
assertEquals("SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?",
Parameters.replaceNamesInQuery(query, parameters), "Parameters not replaced correctly")

View File

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

View File

@ -1,12 +1,15 @@
package solutions.bitbadger.documents.integration.common
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.TEST_TABLE
import solutions.bitbadger.documents.integration.ThrowawayDatabase
import solutions.bitbadger.documents.query.Count
import solutions.bitbadger.documents.query.Delete
import solutions.bitbadger.documents.query.Find
import solutions.bitbadger.documents.common.query.Count
import solutions.bitbadger.documents.common.query.Delete
import solutions.bitbadger.documents.common.query.Find
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.common.FieldMatch
import solutions.bitbadger.documents.integration.*
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
@ -209,7 +211,8 @@ object Find {
fun firstByFieldsMatchOrdered(db: ThrowawayDatabase) {
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")
assertEquals("four", doc.id, "An incorrect document was returned")
}

View File

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

View File

@ -1,6 +1,7 @@
package solutions.bitbadger.documents.integration.common
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.Field
import solutions.bitbadger.documents.integration.JsonDocument
import solutions.bitbadger.documents.integration.TEST_TABLE
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
*/
@DisplayName("PostgreSQL - Count")
@DisplayName("Kotlin | PostgreSQL: Count")
class CountIT {
@Test

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents.integration.postgresql
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.ThrowawayDatabase

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.integration.sqlite
import org.junit.jupiter.api.DisplayName
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 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.assertThrows
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Definition
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.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Delete
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.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Exists
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.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Find
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.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.Patch
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.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.common.DocumentException
import solutions.bitbadger.documents.integration.common.RemoveFields
import kotlin.test.Test

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents.integration.sqlite
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.ThrowawayDatabase
import java.io.File