diff --git a/documents.iml b/documents.iml
index ce12650..7b09b3a 100644
--- a/documents.iml
+++ b/documents.iml
@@ -3,6 +3,7 @@
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 83150c0..19963a3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,7 +38,7 @@
UTF-8official
- 1.8
+ 112.1.01.8.0
@@ -111,6 +111,14 @@
MainKt
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 9
+ 9
+
+
diff --git a/src/main/kotlin/AutoId.kt b/src/main/kotlin/AutoId.kt
index a5bfa54..3e4c4c8 100644
--- a/src/main/kotlin/AutoId.kt
+++ b/src/main/kotlin/AutoId.kt
@@ -1,6 +1,8 @@
package solutions.bitbadger.documents
+import kotlin.jvm.Throws
import kotlin.reflect.full.*
+import kotlin.reflect.jvm.isAccessible
/**
* Strategies for automatic document IDs
@@ -22,7 +24,7 @@ enum class AutoId {
*
* @return A `UUID` string
*/
- fun generateUUID(): String =
+ @JvmStatic fun generateUUID(): String =
java.util.UUID.randomUUID().toString().replace("-", "")
/**
@@ -31,7 +33,7 @@ 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
*/
- 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) }
@@ -47,12 +49,13 @@ enum class AutoId {
* @return `true` if the document needs an automatic ID, `false` if not
* @throws DocumentException If bad input prevents the determination
*/
- fun needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean {
+ @Throws(DocumentException::class)
+ @JvmStatic fun needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean {
if (document == null) throw DocumentException("document cannot be null")
- if (strategy == DISABLED) return false;
+ if (strategy == DISABLED) return false
- val id = document!!::class.memberProperties.find { it.name == idProp }
+ val id = document!!::class.memberProperties.find { it.name == idProp }?.apply { isAccessible = true }
if (id == null) throw DocumentException("$idProp not found in document")
if (strategy == NUMBER) {
@@ -65,11 +68,12 @@ enum class AutoId {
}
}
- if (id.returnType == String::class.createType()) {
+ val typ = id.returnType.toString()
+ if (typ.endsWith("String") || typ.endsWith("String!")) {
return id.call(document) == ""
}
- throw DocumentException("$idProp was not a string; cannot auto-generate UUID or random string")
+ throw DocumentException("$idProp was not a string ($typ); cannot auto-generate UUID or random string")
}
}
}
diff --git a/src/main/kotlin/Configuration.kt b/src/main/kotlin/Configuration.kt
index 8c2b484..7313eea 100644
--- a/src/main/kotlin/Configuration.kt
+++ b/src/main/kotlin/Configuration.kt
@@ -3,6 +3,7 @@ package solutions.bitbadger.documents
import kotlinx.serialization.json.Json
import java.sql.Connection
import java.sql.DriverManager
+import kotlin.jvm.Throws
object Configuration {
@@ -12,25 +13,33 @@ object Configuration {
* The default sets `encodeDefaults` to `true` and `explicitNulls` to `false`; see
* https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md for all configuration options
*/
+ @JvmField
var json = Json {
- encodeDefaults = true
- explicitNulls = false
+ encodeDefaults = true
+ explicitNulls = false
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 */
+ 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
@@ -43,6 +52,7 @@ object Configuration {
* @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")
@@ -57,7 +67,11 @@ object Configuration {
* @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")
+ "Database mode not set" + if (process == null) "" else "; cannot $process"
+ )
}
diff --git a/src/main/kotlin/Field.kt b/src/main/kotlin/Field.kt
index 4a3d8e8..d15a838 100644
--- a/src/main/kotlin/Field.kt
+++ b/src/main/kotlin/Field.kt
@@ -69,18 +69,18 @@ class Field private constructor(
if (parameterName == null && !listOf(Op.EXISTS, Op.NOT_EXISTS).contains(comparison.op))
throw DocumentException("Parameter for $name must be specified")
- val dialect = Configuration.dialect("make field WHERE clause")
+ val dialect = Configuration.dialect("make field WHERE clause")
val fieldName = path(dialect, if (comparison.op == Op.IN_ARRAY) FieldFormat.JSON else FieldFormat.SQL)
val fieldPath = when (dialect) {
Dialect.POSTGRESQL -> if (comparison.isNumeric) "($fieldName)::numeric" else fieldName
- Dialect.SQLITE -> fieldName
+ Dialect.SQLITE -> fieldName
}
val criteria = when (comparison.op) {
in listOf(Op.EXISTS, Op.NOT_EXISTS) -> ""
- Op.BETWEEN -> " ${parameterName}min AND ${parameterName}max"
- Op.IN -> " ($inParameterNames)"
+ Op.BETWEEN -> " ${parameterName}min AND ${parameterName}max"
+ Op.IN -> " ($inParameterNames)"
Op.IN_ARRAY -> if (dialect == Dialect.POSTGRESQL) " ARRAY[$inParameterNames]" else ""
- else -> " $parameterName"
+ else -> " $parameterName"
}
@Suppress("UNCHECKED_CAST")
@@ -134,7 +134,7 @@ class Field private constructor(
}
override fun toString() =
- "Field ${parameterName ?: ""} $comparison${qualifier?.let { " (qualifier $it)"} ?: ""}"
+ "Field ${parameterName ?: ""} $comparison${qualifier?.let { " (qualifier $it)" } ?: ""}"
companion object {
@@ -146,6 +146,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun equal(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.EQUAL, value), paramName)
@@ -157,6 +159,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun greater(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.GREATER, value), paramName)
@@ -168,6 +172,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun greaterOrEqual(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.GREATER_OR_EQUAL, value), paramName)
@@ -179,6 +185,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun less(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.LESS, value), paramName)
@@ -190,6 +198,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun lessOrEqual(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.LESS_OR_EQUAL, value), paramName)
@@ -201,6 +211,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun notEqual(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.NOT_EQUAL, value), paramName)
@@ -213,6 +225,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun between(name: String, minValue: T, maxValue: T, paramName: String? = null) =
Field(name, ComparisonBetween(Pair(minValue, maxValue)), paramName)
@@ -224,6 +238,8 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun any(name: String, values: Collection, paramName: String? = null) =
Field(name, ComparisonIn(values), paramName)
@@ -236,18 +252,50 @@ class Field private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison
*/
+ @JvmStatic
+ @JvmOverloads
fun inArray(name: String, tableName: String, values: Collection, paramName: String? = null) =
Field(name, ComparisonInArray(Pair(tableName, values)), paramName)
+ /**
+ * Create a field where a document field should exist
+ *
+ * @param name The name of the field whose existence should be checked
+ * @return A `Field` with the given comparison
+ */
+ @JvmStatic
fun exists(name: String) =
Field(name, ComparisonSingle(Op.EXISTS, ""))
+ /**
+ * Create a field where a document field should not exist
+ *
+ * @param name The name of the field whose existence should be checked
+ * @return A `Field` with the given comparison
+ */
+ @JvmStatic
fun notExists(name: String) =
Field(name, ComparisonSingle(Op.NOT_EXISTS, ""))
+ /**
+ * Create a field with a given named comparison (useful for ordering fields)
+ *
+ * @param name The name of the field
+ * @return A `Field` with the given name (comparison equal to an empty string)
+ */
+ @JvmStatic
fun named(name: String) =
Field(name, ComparisonSingle(Op.EQUAL, ""))
+ /**
+ * Convert a name to the SQL path for the given dialect
+ *
+ * @param name The field name to be translated
+ * @param dialect The database for which the path should be created
+ * @param format Whether the field should be retrieved as a JSON value or a SQL value
+ * @return The path to the JSON field
+ */
+ @JvmStatic
fun nameToPath(name: String, dialect: Dialect, format: FieldFormat): String {
val path = StringBuilder("data")
val extra = if (format == FieldFormat.SQL) ">" else ""
@@ -266,4 +314,4 @@ class Field private constructor(
return path.toString()
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/kotlin/Parameters.kt b/src/main/kotlin/Parameters.kt
index 4da353b..3bf15b2 100644
--- a/src/main/kotlin/Parameters.kt
+++ b/src/main/kotlin/Parameters.kt
@@ -3,6 +3,7 @@ package solutions.bitbadger.documents
import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.SQLException
+import kotlin.jvm.Throws
/**
* Functions to assist with the creation and implementation of parameters for SQL queries
@@ -17,6 +18,7 @@ object Parameters {
* @param fields The collection of fields to be named
* @return The collection of fields with parameter names assigned
*/
+ @JvmStatic
fun nameFields(fields: Collection>): Collection> {
val name = ParameterName()
return fields.map {
@@ -45,6 +47,7 @@ object Parameters {
* @param existing Any existing parameters for the query (optional, defaults to empty collection)
* @return A collection of parameters for the query
*/
+ @JvmStatic
fun addFields(fields: Collection>, existing: MutableCollection> = mutableListOf()) =
fields.fold(existing) { acc, field -> field.appendParameter(acc) }
@@ -55,6 +58,7 @@ object Parameters {
* @param parameters The parameters for the query
* @return The query, with name parameters changed to `?`s
*/
+ @JvmStatic
fun replaceNamesInQuery(query: String, parameters: Collection>) =
parameters.sortedByDescending { it.name.length }.fold(query) { acc, param -> acc.replace(param.name, "?") }
@@ -67,6 +71,8 @@ object Parameters {
* @return A `PreparedStatement` with the parameter names replaced with `?` and parameter values bound
* @throws DocumentException If parameter names are invalid or number value types are invalid
*/
+ @Throws(DocumentException::class)
+ @JvmStatic
fun apply(conn: Connection, query: String, parameters: Collection>): PreparedStatement {
if (parameters.isEmpty()) return try {
@@ -105,6 +111,8 @@ object Parameters {
* @param parameterName The parameter name to use for the query
* @return A list of parameters to use for building the query
*/
+ @JvmStatic
+ @JvmOverloads
fun fieldNames(names: Collection, parameterName: String = ":name"): MutableCollection> =
when (Configuration.dialect("generate field name parameters")) {
Dialect.POSTGRESQL -> mutableListOf(
diff --git a/src/test/java/solutions/bitbadger/documents/java/AutoIdTest.java b/src/test/java/solutions/bitbadger/documents/java/AutoIdTest.java
new file mode 100644
index 0000000..6375b24
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/AutoIdTest.java
@@ -0,0 +1,217 @@
+package solutions.bitbadger.documents.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.java.testDocs.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for the `AutoId` enum
+ */
+@DisplayName("Java | AutoId")
+final public class AutoIdTest {
+
+ @Test
+ @DisplayName("Generates a UUID string")
+ public void generateUUID() {
+ assertEquals(32, AutoId.generateUUID().length(), "The UUID should have been a 32-character string");
+ }
+
+ @Test
+ @DisplayName("Generates a random hex character string of an even length")
+ public void generateRandomStringEven() {
+ final String result = AutoId.generateRandomString(8);
+ assertEquals(8, result.length(), "There should have been 8 characters in " + result);
+ }
+
+ @Test
+ @DisplayName("Generates a random hex character string of an odd length")
+ public void generateRandomStringOdd() {
+ final String result = AutoId.generateRandomString(11);
+ assertEquals(11, result.length(), "There should have been 11 characters in " + result);
+ }
+
+ @Test
+ @DisplayName("Generates different random hex character strings")
+ public void generateRandomStringIsRandom() {
+ final String result1 = AutoId.generateRandomString(16);
+ final String result2 = AutoId.generateRandomString(16);
+ assertNotEquals(result1, result2, "There should have been 2 different strings generated");
+ }
+
+ @Test
+ @DisplayName("needsAutoId fails for null document")
+ public void needsAutoIdFailsForNullDocument() {
+ assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.DISABLED, null, "id"));
+ }
+
+ @Test
+ @DisplayName("needsAutoId fails for missing ID property")
+ public void needsAutoIdFailsForMissingId() {
+ assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.UUID, new IntIdClass(0), "Id"));
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false if disabled")
+ public void needsAutoIdFalseIfDisabled() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.DISABLED, "", ""), "Disabled Auto ID should always return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns true for Number strategy and byte ID of 0")
+ public void needsAutoIdTrueForByteWithZero() {
+ try {
+ assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new ByteIdClass((byte) 0), "id"),
+ "Number Auto ID with 0 should return true");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false for Number strategy and byte ID of non-0")
+ public void needsAutoIdFalseForByteWithNonZero() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new ByteIdClass((byte) 77), "id"),
+ "Number Auto ID with 77 should return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns true for Number strategy and short ID of 0")
+ public void needsAutoIdTrueForShortWithZero() {
+ try {
+ assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new ShortIdClass((short) 0), "id"),
+ "Number Auto ID with 0 should return true");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false for Number strategy and short ID of non-0")
+ public void needsAutoIdFalseForShortWithNonZero() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new ShortIdClass((short) 31), "id"),
+ "Number Auto ID with 31 should return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns true for Number strategy and int ID of 0")
+ public void needsAutoIdTrueForIntWithZero() {
+ try {
+ assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new IntIdClass(0), "id"),
+ "Number Auto ID with 0 should return true");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false for Number strategy and int ID of non-0")
+ public void needsAutoIdFalseForIntWithNonZero() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new IntIdClass(6), "id"),
+ "Number Auto ID with 6 should return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns true for Number strategy and long ID of 0")
+ public void needsAutoIdTrueForLongWithZero() {
+ try {
+ assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new LongIdClass(0L), "id"),
+ "Number Auto ID with 0 should return true");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false for Number strategy and long ID of non-0")
+ public void needsAutoIdFalseForLongWithNonZero() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new LongIdClass(2L), "id"),
+ "Number Auto ID with 2 should return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId fails for Number strategy and non-number ID")
+ public void needsAutoIdFailsForNumberWithStringId() {
+ assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.NUMBER, new StringIdClass(""), "id"));
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns true for UUID strategy and blank ID")
+ public void needsAutoIdTrueForUUIDWithBlank() {
+ try {
+ assertTrue(AutoId.needsAutoId(AutoId.UUID, new StringIdClass(""), "id"),
+ "UUID Auto ID with blank should return true");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false for UUID strategy and non-blank ID")
+ public void needsAutoIdFalseForUUIDNotBlank() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.UUID, new StringIdClass("howdy"), "id"),
+ "UUID Auto ID with non-blank should return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId fails for UUID strategy and non-string ID")
+ public void needsAutoIdFailsForUUIDNonString() {
+ assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.UUID, new IntIdClass(5), "id"));
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns true for Random String strategy and blank ID")
+ public void needsAutoIdTrueForRandomWithBlank() {
+ try {
+ assertTrue(AutoId.needsAutoId(AutoId.RANDOM_STRING, new StringIdClass(""), "id"),
+ "Random String Auto ID with blank should return true");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId returns false for Random String strategy and non-blank ID")
+ public void needsAutoIdFalseForRandomNotBlank() {
+ try {
+ assertFalse(AutoId.needsAutoId(AutoId.RANDOM_STRING, new StringIdClass("full"), "id"),
+ "Random String Auto ID with non-blank should return false");
+ } catch (DocumentException ex) {
+ fail(ex);
+ }
+ }
+
+ @Test
+ @DisplayName("needsAutoId fails for Random String strategy and non-string ID")
+ public void needsAutoIdFailsForRandomNonString() {
+ assertThrows(DocumentException.class,
+ () -> AutoId.needsAutoId(AutoId.RANDOM_STRING, new ShortIdClass((short) 55), "id"));
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/ConfigurationTest.java b/src/test/java/solutions/bitbadger/documents/java/ConfigurationTest.java
new file mode 100644
index 0000000..ed6a71a
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/ConfigurationTest.java
@@ -0,0 +1,56 @@
+package solutions.bitbadger.documents.java;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import solutions.bitbadger.documents.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for the `Configuration` object
+ */
+@DisplayName("Java | Configuration")
+final public class ConfigurationTest {
+
+ @Test
+ @DisplayName("Default JSON options are as expected")
+ public void defaultJsonOptions() {
+ assertTrue(Configuration.json.getConfiguration().getEncodeDefaults(), "Encode Defaults should have been set");
+ assertFalse(Configuration.json.getConfiguration().getExplicitNulls(),
+ "Explicit Nulls should not have been set");
+ assertTrue(Configuration.json.getConfiguration().getCoerceInputValues(),
+ "Coerce Input Values should have been set");
+ }
+
+ @Test
+ @DisplayName("Default ID field is `id`")
+ public void defaultIdField() {
+ assertEquals("id", Configuration.idField, "Default ID field incorrect");
+ }
+
+ @Test
+ @DisplayName("Default Auto ID strategy is `DISABLED`")
+ public void defaultAutoId() {
+ assertEquals(AutoId.DISABLED, Configuration.autoIdStrategy, "Default Auto ID strategy should be `disabled`");
+ }
+
+ @Test
+ @DisplayName("Default ID string length should be 16")
+ public void defaultIdStringLength() {
+ assertEquals(16, Configuration.idStringLength, "Default ID string length should be 16");
+ }
+
+ @Test
+ @DisplayName("Dialect is derived from connection string")
+ public void dialectIsDerived() {
+ try {
+ assertThrows(DocumentException.class, Configuration::dialect);
+ Configuration.setConnectionString("jdbc:postgresql:db");
+ assertEquals(Dialect.POSTGRESQL, Configuration.dialect());
+ } catch (DocumentException ex) {
+ fail(ex);
+ } finally {
+ Configuration.setConnectionString(null);
+ }
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/DocumentIndexTest.java b/src/test/java/solutions/bitbadger/documents/java/DocumentIndexTest.java
new file mode 100644
index 0000000..c54f9cb
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/DocumentIndexTest.java
@@ -0,0 +1,26 @@
+package solutions.bitbadger.documents.java;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import solutions.bitbadger.documents.DocumentIndex;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit tests for the `DocumentIndex` enum
+ */
+@DisplayName("Java | DocumentIndex")
+final public class DocumentIndexTest {
+
+ @Test
+ @DisplayName("FULL uses proper SQL")
+ public void fullSQL() {
+ assertEquals("", DocumentIndex.FULL.getSql(), "The SQL for Full is incorrect");
+ }
+
+ @Test
+ @DisplayName("OPTIMIZED uses proper SQL")
+ public void optimizedSQL() {
+ assertEquals(" jsonb_path_ops", DocumentIndex.OPTIMIZED.getSql(), "The SQL for Optimized is incorrect");
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/FieldMatchTest.java b/src/test/java/solutions/bitbadger/documents/java/FieldMatchTest.java
new file mode 100644
index 0000000..c974534
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/FieldMatchTest.java
@@ -0,0 +1,26 @@
+package solutions.bitbadger.documents.java;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import solutions.bitbadger.documents.FieldMatch;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit tests for the `FieldMatch` enum
+ */
+@DisplayName("Java | FieldMatch")
+final public class FieldMatchTest {
+
+ @Test
+ @DisplayName("ANY uses proper SQL")
+ public void any() {
+ assertEquals("OR", FieldMatch.ANY.getSql(), "ANY should use OR");
+ }
+
+ @Test
+ @DisplayName("ALL uses proper SQL")
+ public void all() {
+ assertEquals("AND", FieldMatch.ALL.getSql(), "ALL should use AND");
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/FieldTest.java b/src/test/java/solutions/bitbadger/documents/java/FieldTest.java
new file mode 100644
index 0000000..287b1ef
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/FieldTest.java
@@ -0,0 +1,629 @@
+package solutions.bitbadger.documents.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 java.util.Collection;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for the `Field` class
+ */
+@DisplayName("Java | Field")
+final public class FieldTest {
+
+ /**
+ * Clear the connection string (resets Dialect)
+ */
+ @AfterEach
+ public void cleanUp() {
+ Configuration.setConnectionString(null);
+ }
+
+ // ~~~ INSTANCE METHODS ~~~
+
+ @Test
+ @DisplayName("withParameterName fails for invalid name")
+ public void withParamNameFails() {
+ assertThrows(DocumentException.class, () -> Field.equal("it", "").withParameterName("2424"));
+ }
+
+ @Test
+ @DisplayName("withParameterName works with colon prefix")
+ public void withParamNameColon() {
+ Field field = Field.equal("abc", "22").withQualifier("me");
+ Field withParam = field.withParameterName(":test");
+ assertNotSame(field, withParam, "A new Field instance should have been created");
+ assertEquals(field.getName(), withParam.getName(), "Name should have been preserved");
+ assertEquals(field.getComparison(), withParam.getComparison(), "Comparison should have been preserved");
+ assertEquals(":test", withParam.getParameterName(), "Parameter name not set correctly");
+ assertEquals(field.getQualifier(), withParam.getQualifier(), "Qualifier should have been preserved");
+ }
+
+ @Test
+ @DisplayName("withParameterName works with at-sign prefix")
+ public void withParamNameAtSign() {
+ Field field = Field.equal("def", "44");
+ Field withParam = field.withParameterName("@unit");
+ assertNotSame(field, withParam, "A new Field instance should have been created");
+ assertEquals(field.getName(), withParam.getName(), "Name should have been preserved");
+ assertEquals(field.getComparison(), withParam.getComparison(), "Comparison should have been preserved");
+ assertEquals("@unit", withParam.getParameterName(), "Parameter name not set correctly");
+ assertEquals(field.getQualifier(), withParam.getQualifier(), "Qualifier should have been preserved");
+ }
+
+ @Test
+ @DisplayName("withQualifier sets qualifier correctly")
+ public void withQualifier() {
+ Field field = Field.equal("j", "k");
+ Field withQual = field.withQualifier("test");
+ assertNotSame(field, withQual, "A new Field instance should have been created");
+ assertEquals(field.getName(), withQual.getName(), "Name should have been preserved");
+ assertEquals(field.getComparison(), withQual.getComparison(), "Comparison should have been preserved");
+ assertEquals(field.getParameterName(), withQual.getParameterName(),
+ "Parameter Name should have been preserved");
+ assertEquals("test", withQual.getQualifier(), "Qualifier not set correctly");
+ }
+
+ @Test
+ @DisplayName("path generates for simple unqualified PostgreSQL field")
+ public void pathPostgresSimpleUnqualified() {
+ assertEquals("data->>'SomethingCool'",
+ Field.greaterOrEqual("SomethingCool", 18).path(Dialect.POSTGRESQL, FieldFormat.SQL),
+ "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for simple qualified PostgreSQL field")
+ public void pathPostgresSimpleQualified() {
+ assertEquals("this.data->>'SomethingElse'",
+ Field.less("SomethingElse", 9).withQualifier("this").path(Dialect.POSTGRESQL, FieldFormat.SQL),
+ "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for nested unqualified PostgreSQL field")
+ public void pathPostgresNestedUnqualified() {
+ assertEquals("data#>>'{My,Nested,Field}'",
+ Field.equal("My.Nested.Field", "howdy").path(Dialect.POSTGRESQL, FieldFormat.SQL), "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for nested qualified PostgreSQL field")
+ public void pathPostgresNestedQualified() {
+ assertEquals("bird.data#>>'{Nest,Away}'",
+ Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.POSTGRESQL, FieldFormat.SQL),
+ "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for simple unqualified SQLite field")
+ public void pathSQLiteSimpleUnqualified() {
+ assertEquals("data->>'SomethingCool'",
+ Field.greaterOrEqual("SomethingCool", 18).path(Dialect.SQLITE, FieldFormat.SQL), "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for simple qualified SQLite field")
+ public void pathSQLiteSimpleQualified() {
+ assertEquals("this.data->>'SomethingElse'",
+ Field.less("SomethingElse", 9).withQualifier("this").path(Dialect.SQLITE, FieldFormat.SQL),
+ "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for nested unqualified SQLite field")
+ public void pathSQLiteNestedUnqualified() {
+ assertEquals("data->'My'->'Nested'->>'Field'",
+ Field.equal("My.Nested.Field", "howdy").path(Dialect.SQLITE, FieldFormat.SQL), "Path not correct");
+ }
+
+ @Test
+ @DisplayName("path generates for nested qualified SQLite field")
+ public void pathSQLiteNestedQualified() {
+ assertEquals("bird.data->'Nest'->>'Away'",
+ Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.SQLITE, FieldFormat.SQL),
+ "Path not correct");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)")
+ public void toWhereExistsNoQualPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for exists w/o qualifier (SQLite)")
+ public void toWhereExistsNoQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for not-exists w/o qualifier (PostgreSQL)")
+ public void toWhereNotExistsNoQualPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for not-exists w/o qualifier (SQLite)")
+ public void toWhereNotExistsNoQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for BETWEEN w/o qualifier, numeric range (PostgreSQL)")
+ public void toWhereBetweenNoQualNumericPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax",
+ Field.between("age", 13, 17, "@age").toWhere(), "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range (PostgreSQL)")
+ public void toWhereBetweenNoQualAlphaPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("data->>'city' BETWEEN :citymin AND :citymax",
+ Field.between("city", "Atlanta", "Chicago", ":city").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for BETWEEN w/o qualifier (SQLite)")
+ public void toWhereBetweenNoQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field.between("age", 13, 17, "@age").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for BETWEEN w/ qualifier, numeric range (PostgreSQL)")
+ public void toWhereBetweenQualNumericPostgres() {
+ Configuration.setConnectionString(":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");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range (PostgreSQL)")
+ public void toWhereBetweenQualAlphaPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("unit.data->>'city' BETWEEN :citymin AND :citymax",
+ Field.between("city", "Atlanta", "Chicago", ":city").withQualifier("unit").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for BETWEEN w/ qualifier (SQLite)")
+ public void toWhereBetweenQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("my.data->>'age' BETWEEN @agemin AND @agemax",
+ Field.between("age", 13, 17, "@age").withQualifier("my").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for IN/any, numeric values (PostgreSQL)")
+ public void toWhereAnyNumericPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("(data->>'even')::numeric IN (:nbr_0, :nbr_1, :nbr_2)",
+ Field.any("even", List.of(2, 4, 6), ":nbr").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for IN/any, alphanumeric values (PostgreSQL)")
+ public void toWhereAnyAlphaPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("data->>'test' IN (:city_0, :city_1)",
+ Field.any("test", List.of("Atlanta", "Chicago"), ":city").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for IN/any (SQLite)")
+ public void toWhereAnySQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("data->>'test' IN (:city_0, :city_1)",
+ Field.any("test", List.of("Atlanta", "Chicago"), ":city").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for inArray (PostgreSQL)")
+ public void toWhereInArrayPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]",
+ Field.inArray("even", "tbl", List.of(2, 4, 6, 8), ":it").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for inArray (SQLite)")
+ public void toWhereInArraySQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("EXISTS (SELECT 1 FROM json_each(tbl.data, '$.test') WHERE value IN (:city_0, :city_1))",
+ Field.inArray("test", "tbl", List.of("Atlanta", "Chicago"), ":city").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for others w/o qualifier (PostgreSQL)")
+ public void toWhereOtherNoQualPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates for others w/o qualifier (SQLite)")
+ public void toWhereOtherNoQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates no-parameter w/ qualifier (PostgreSQL)")
+ public void toWhereNoParamWithQualPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates no-parameter w/ qualifier (SQLite)")
+ public void toWhereNoParamWithQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates parameter w/ qualifier (PostgreSQL)")
+ public void toWhereParamWithQualPostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ assertEquals("(q.data->>'le_field')::numeric <= :it",
+ Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ @Test
+ @DisplayName("toWhere generates parameter w/ qualifier (SQLite)")
+ public void toWhereParamWithQualSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ assertEquals("q.data->>'le_field' <= :it",
+ Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
+ "Field WHERE clause not generated correctly");
+ }
+
+ // ~~~ STATIC TESTS ~~~
+
+ @Test
+ @DisplayName("equal constructs a field w/o parameter name")
+ public void equalCtor() {
+ Field field = Field.equal("Test", 14);
+ assertEquals("Test", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals(14, field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("equal constructs a field w/ parameter name")
+ public void equalParameterCtor() {
+ Field field = Field.equal("Test", 14, ":w");
+ assertEquals("Test", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals(14, field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertEquals(":w", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("greater constructs a field w/o parameter name")
+ public void greaterCtor() {
+ Field field = Field.greater("Great", "night");
+ assertEquals("Great", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.GREATER, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("night", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("greater constructs a field w/ parameter name")
+ public void greaterParameterCtor() {
+ Field field = Field.greater("Great", "night", ":yeah");
+ assertEquals("Great", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.GREATER, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("night", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertEquals(":yeah", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("greaterOrEqual constructs a field w/o parameter name")
+ public void greaterOrEqualCtor() {
+ Field field = Field.greaterOrEqual("Nice", 88L);
+ assertEquals("Nice", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.GREATER_OR_EQUAL, field.getComparison().getOp(),
+ "Field comparison operation not filled correctly");
+ assertEquals(88L, field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("greaterOrEqual constructs a field w/ parameter name")
+ public void greaterOrEqualParameterCtor() {
+ Field field = Field.greaterOrEqual("Nice", 88L, ":nice");
+ assertEquals("Nice", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.GREATER_OR_EQUAL, field.getComparison().getOp(),
+ "Field comparison operation not filled correctly");
+ assertEquals(88L, field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertEquals(":nice", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("less constructs a field w/o parameter name")
+ public void lessCtor() {
+ Field field = Field.less("Lesser", "seven");
+ assertEquals("Lesser", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.LESS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("seven", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("less constructs a field w/ parameter name")
+ public void lessParameterCtor() {
+ Field field = Field.less("Lesser", "seven", ":max");
+ assertEquals("Lesser", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.LESS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("seven", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertEquals(":max", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("lessOrEqual constructs a field w/o parameter name")
+ public void lessOrEqualCtor() {
+ Field field = Field.lessOrEqual("Nobody", "KNOWS");
+ assertEquals("Nobody", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.LESS_OR_EQUAL, field.getComparison().getOp(),
+ "Field comparison operation not filled correctly");
+ assertEquals("KNOWS", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("lessOrEqual constructs a field w/ parameter name")
+ public void lessOrEqualParameterCtor() {
+ Field field = Field.lessOrEqual("Nobody", "KNOWS", ":nope");
+ assertEquals("Nobody", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.LESS_OR_EQUAL, field.getComparison().getOp(),
+ "Field comparison operation not filled correctly");
+ assertEquals("KNOWS", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertEquals(":nope", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("notEqual constructs a field w/o parameter name")
+ public void notEqualCtor() {
+ Field field = Field.notEqual("Park", "here");
+ assertEquals("Park", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.NOT_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("here", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("notEqual constructs a field w/ parameter name")
+ public void notEqualParameterCtor() {
+ Field field = Field.notEqual("Park", "here", ":now");
+ assertEquals("Park", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.NOT_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("here", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertEquals(":now", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("between constructs a field w/o parameter name")
+ public void betweenCtor() {
+ Field> field = Field.between("Age", 18, 49);
+ assertEquals("Age", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.BETWEEN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals(18, field.getComparison().getValue().getFirst(),
+ "Field comparison min value not filled correctly");
+ assertEquals(49, field.getComparison().getValue().getSecond(),
+ "Field comparison max value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("between constructs a field w/ parameter name")
+ public void betweenParameterCtor() {
+ Field> field = Field.between("Age", 18, 49, ":limit");
+ assertEquals("Age", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.BETWEEN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals(18, field.getComparison().getValue().getFirst(),
+ "Field comparison min value not filled correctly");
+ assertEquals(49, field.getComparison().getValue().getSecond(),
+ "Field comparison max value not filled correctly");
+ assertEquals(":limit", field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("any constructs a field w/o parameter name")
+ public void anyCtor() {
+ Field> field = Field.any("Here", List.of(8, 16, 32));
+ assertEquals("Here", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.IN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals(List.of(8, 16, 32), field.getComparison().getValue(),
+ "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("any constructs a field w/ parameter name")
+ public void anyParameterCtor() {
+ Field> field = Field.any("Here", List.of(8, 16, 32), ":list");
+ assertEquals("Here", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.IN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals(List.of(8, 16, 32), field.getComparison().getValue(),
+ "Field comparison value not filled correctly");
+ assertEquals(":list", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("inArray constructs a field w/o parameter name")
+ public void inArrayCtor() {
+ Field>> field = Field.inArray("ArrayField", "table", List.of("z"));
+ assertEquals("ArrayField", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.IN_ARRAY, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("table", field.getComparison().getValue().getFirst(),
+ "Field comparison table not filled correctly");
+ assertEquals(List.of("z"), field.getComparison().getValue().getSecond(),
+ "Field comparison values not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("inArray constructs a field w/ parameter name")
+ public void inArrayParameterCtor() {
+ Field>> field = Field.inArray("ArrayField", "table", List.of("z"), ":a");
+ assertEquals("ArrayField", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.IN_ARRAY, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("table", field.getComparison().getValue().getFirst(),
+ "Field comparison table not filled correctly");
+ assertEquals(List.of("z"), field.getComparison().getValue().getSecond(),
+ "Field comparison values not filled correctly");
+ assertEquals(":a", field.getParameterName(), "Field parameter name not filled correctly");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("exists constructs a field")
+ public void existsCtor() {
+ Field field = Field.exists("Groovy");
+ assertEquals("Groovy", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.EXISTS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("notExists constructs a field")
+ public void notExistsCtor() {
+ Field field = Field.notExists("Groovy");
+ assertEquals("Groovy", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.NOT_EXISTS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("named constructs a field")
+ public void namedCtor() {
+ Field field = Field.named("Tacos");
+ assertEquals("Tacos", field.getName(), "Field name not filled correctly");
+ assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
+ assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly");
+ assertNull(field.getParameterName(), "The parameter name should have been null");
+ assertNull(field.getQualifier(), "The qualifier should have been null");
+ }
+
+ @Test
+ @DisplayName("static constructors fail for invalid parameter name")
+ public void staticCtorsFailOnParamName() {
+ assertThrows(DocumentException.class, () -> Field.equal("a", "b", "that ain't it, Jack..."));
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a simple PostgreSQL SQL name")
+ public void nameToPathPostgresSimpleSQL() {
+ assertEquals("data->>'Simple'", Field.nameToPath("Simple", Dialect.POSTGRESQL, FieldFormat.SQL),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a simple SQLite SQL name")
+ public void nameToPathSQLiteSimpleSQL() {
+ assertEquals("data->>'Simple'", Field.nameToPath("Simple", Dialect.SQLITE, FieldFormat.SQL),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a nested PostgreSQL SQL name")
+ public void nameToPathPostgresNestedSQL() {
+ assertEquals("data#>>'{A,Long,Path,to,the,Property}'",
+ Field.nameToPath("A.Long.Path.to.the.Property", Dialect.POSTGRESQL, FieldFormat.SQL),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a nested SQLite SQL name")
+ public void nameToPathSQLiteNestedSQL() {
+ assertEquals("data->'A'->'Long'->'Path'->'to'->'the'->>'Property'",
+ Field.nameToPath("A.Long.Path.to.the.Property", Dialect.SQLITE, FieldFormat.SQL),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a simple PostgreSQL JSON name")
+ public void nameToPathPostgresSimpleJSON() {
+ assertEquals("data->'Simple'", Field.nameToPath("Simple", Dialect.POSTGRESQL, FieldFormat.JSON),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a simple SQLite JSON name")
+ public void nameToPathSQLiteSimpleJSON() {
+ assertEquals("data->'Simple'", Field.nameToPath("Simple", Dialect.SQLITE, FieldFormat.JSON),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a nested PostgreSQL JSON name")
+ public void nameToPathPostgresNestedJSON() {
+ assertEquals("data#>'{A,Long,Path,to,the,Property}'",
+ Field.nameToPath("A.Long.Path.to.the.Property", Dialect.POSTGRESQL, FieldFormat.JSON),
+ "Path not constructed correctly");
+ }
+
+ @Test
+ @DisplayName("nameToPath creates a nested SQLite JSON name")
+ public void nameToPathSQLiteNestedJSON() {
+ assertEquals("data->'A'->'Long'->'Path'->'to'->'the'->'Property'",
+ Field.nameToPath("A.Long.Path.to.the.Property", Dialect.SQLITE, FieldFormat.JSON),
+ "Path not constructed correctly");
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/OpTest.java b/src/test/java/solutions/bitbadger/documents/java/OpTest.java
new file mode 100644
index 0000000..3a319cf
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/OpTest.java
@@ -0,0 +1,80 @@
+package solutions.bitbadger.documents.java;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import solutions.bitbadger.documents.Op;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit tests for the `Op` enum
+ */
+@DisplayName("Java | Op")
+final public class OpTest {
+
+ @Test
+ @DisplayName("EQUAL uses proper SQL")
+ public void equalSQL() {
+ assertEquals("=", Op.EQUAL.getSql(), "The SQL for equal is incorrect");
+ }
+
+ @Test
+ @DisplayName("GREATER uses proper SQL")
+ public void greaterSQL() {
+ assertEquals(">", Op.GREATER.getSql(), "The SQL for greater is incorrect");
+ }
+
+ @Test
+ @DisplayName("GREATER_OR_EQUAL uses proper SQL")
+ public void greaterOrEqualSQL() {
+ assertEquals(">=", Op.GREATER_OR_EQUAL.getSql(), "The SQL for greater-or-equal is incorrect");
+ }
+
+ @Test
+ @DisplayName("LESS uses proper SQL")
+ public void lessSQL() {
+ assertEquals("<", Op.LESS.getSql(), "The SQL for less is incorrect");
+ }
+
+ @Test
+ @DisplayName("LESS_OR_EQUAL uses proper SQL")
+ public void lessOrEqualSQL() {
+ assertEquals("<=", Op.LESS_OR_EQUAL.getSql(), "The SQL for less-or-equal is incorrect");
+ }
+
+ @Test
+ @DisplayName("NOT_EQUAL uses proper SQL")
+ public void notEqualSQL() {
+ assertEquals("<>", Op.NOT_EQUAL.getSql(), "The SQL for not-equal is incorrect");
+ }
+
+ @Test
+ @DisplayName("BETWEEN uses proper SQL")
+ public void betweenSQL() {
+ assertEquals("BETWEEN", Op.BETWEEN.getSql(), "The SQL for between is incorrect");
+ }
+
+ @Test
+ @DisplayName("IN uses proper SQL")
+ public void inSQL() {
+ assertEquals("IN", Op.IN.getSql(), "The SQL for in is incorrect");
+ }
+
+ @Test
+ @DisplayName("IN_ARRAY uses proper SQL")
+ public void inArraySQL() {
+ assertEquals("??|", Op.IN_ARRAY.getSql(), "The SQL for in-array is incorrect");
+ }
+
+ @Test
+ @DisplayName("EXISTS uses proper SQL")
+ public void existsSQL() {
+ assertEquals("IS NOT NULL", Op.EXISTS.getSql(), "The SQL for exists is incorrect");
+ }
+
+ @Test
+ @DisplayName("NOT_EXISTS uses proper SQL")
+ public void notExistsSQL() {
+ assertEquals("IS NULL", Op.NOT_EXISTS.getSql(), "The SQL for not-exists is incorrect");
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/ParameterNameTest.java b/src/test/java/solutions/bitbadger/documents/java/ParameterNameTest.java
new file mode 100644
index 0000000..15d5498
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/ParameterNameTest.java
@@ -0,0 +1,32 @@
+package solutions.bitbadger.documents.java;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import solutions.bitbadger.documents.ParameterName;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Unit tests for the `ParameterName` class
+ */
+@DisplayName("Java | ParameterName")
+final public class ParameterNameTest {
+
+ @Test
+ @DisplayName("derive works when given existing names")
+ public void withExisting() {
+ ParameterName names = new ParameterName();
+ assertEquals(":taco", names.derive(":taco"), "Name should have been :taco");
+ assertEquals(":field0", names.derive(null), "Counter should not have advanced for named field");
+ }
+
+ @Test
+ @DisplayName("derive works when given all anonymous fields")
+ public void allAnonymous() {
+ ParameterName names = new ParameterName();
+ assertEquals(":field0", names.derive(null), "Anonymous field name should have been returned");
+ assertEquals(":field1", names.derive(null), "Counter should have advanced from previous call");
+ assertEquals(":field2", names.derive(null), "Counter should have advanced from previous call");
+ assertEquals(":field3", names.derive(null), "Counter should have advanced from previous call");
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/ParameterTest.java b/src/test/java/solutions/bitbadger/documents/java/ParameterTest.java
new file mode 100644
index 0000000..2e6556b
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/ParameterTest.java
@@ -0,0 +1,40 @@
+package solutions.bitbadger.documents.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 static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for the `Parameter` class
+ */
+@DisplayName("Java | Parameter")
+final public class ParameterTest {
+
+ @Test
+ @DisplayName("Construction with colon-prefixed name")
+ public void ctorWithColon() {
+ Parameter p = new Parameter<>(":test", ParameterType.STRING, "ABC");
+ assertEquals(":test", p.getName(), "Parameter name was incorrect");
+ assertEquals(ParameterType.STRING, p.getType(), "Parameter type was incorrect");
+ assertEquals("ABC", p.getValue(), "Parameter value was incorrect");
+ }
+
+ @Test
+ @DisplayName("Construction with at-sign-prefixed name")
+ public void ctorWithAtSign() {
+ Parameter p = new Parameter<>("@yo", ParameterType.NUMBER, null);
+ assertEquals("@yo", p.getName(), "Parameter name was incorrect");
+ assertEquals(ParameterType.NUMBER, p.getType(), "Parameter type was incorrect");
+ assertNull(p.getValue(), "Parameter value was incorrect");
+ }
+
+ @Test
+ @DisplayName("Construction fails with incorrect prefix")
+ public void ctorFailsForPrefix() {
+ assertThrows(DocumentException.class, () -> new Parameter<>("it", ParameterType.JSON, ""));
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/ParametersTest.java b/src/test/java/solutions/bitbadger/documents/java/ParametersTest.java
new file mode 100644
index 0000000..6c011d1
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/ParametersTest.java
@@ -0,0 +1,121 @@
+package solutions.bitbadger.documents.java;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import solutions.bitbadger.documents.*;
+
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for the `Parameters` object
+ */
+@DisplayName("Java | Parameters")
+final public class ParametersTest {
+
+ /**
+ * Reset the dialect
+ */
+ @AfterEach
+ public void cleanUp() {
+ Configuration.setConnectionString(null);
+ }
+
+ @Test
+ @DisplayName("nameFields works with no changes")
+ public void nameFieldsNoChange() {
+ List> fields = List.of(Field.equal("a", "", ":test"), Field.exists("q"), Field.equal("b", "", ":me"));
+ Field>[] named = Parameters.nameFields(fields).toArray(new Field>[] { });
+ assertEquals(fields.size(), named.length, "There should have been 3 fields in the list");
+ assertSame(fields.get(0), named[0], "The first field should be the same");
+ assertSame(fields.get(1), named[1], "The second field should be the same");
+ assertSame(fields.get(2), named[2], "The third field should be the same");
+ }
+
+ @Test
+ @DisplayName("nameFields works when changing fields")
+ public void nameFieldsChange() {
+ List> fields = List.of(
+ Field.equal("a", ""), Field.equal("e", "", ":hi"), Field.equal("b", ""), Field.notExists("z"));
+ Field>[] named = Parameters.nameFields(fields).toArray(new Field>[] { });
+ assertEquals(fields.size(), named.length, "There should have been 4 fields in the list");
+ assertNotSame(fields.get(0), named[0], "The first field should not be the same");
+ assertEquals(":field0", named[0].getParameterName(), "First parameter name incorrect");
+ assertSame(fields.get(1), named[1], "The second field should be the same");
+ assertNotSame(fields.get(2), named[2], "The third field should not be the same");
+ assertEquals(":field1", named[2].getParameterName(), "Third parameter name incorrect");
+ assertSame(fields.get(3), named[3], "The fourth field should be the same");
+ }
+
+ @Test
+ @DisplayName("replaceNamesInQuery replaces successfully")
+ public void replaceNamesInQuery() {
+ List> parameters = List.of(new Parameter<>(":data", ParameterType.JSON, "{}"),
+ new Parameter<>(":data_ext", ParameterType.STRING, ""));
+ String 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");
+ }
+
+ @Test
+ @DisplayName("fieldNames generates a single parameter (PostgreSQL)")
+ public void fieldNamesSinglePostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ 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");
+ assertEquals("{test}", nameParams[0].getValue(), "The parameter value is incorrect");
+ }
+
+ @Test
+ @DisplayName("fieldNames generates multiple parameters (PostgreSQL)")
+ public void fieldNamesMultiplePostgres() {
+ Configuration.setConnectionString(":postgresql:");
+ Parameter>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today"))
+ .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");
+ assertEquals("{test,this,today}", nameParams[0].getValue(), "The parameter value is incorrect");
+ }
+
+ @Test
+ @DisplayName("fieldNames generates a single parameter (SQLite)")
+ public void fieldNamesSingleSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ 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");
+ assertEquals("test", nameParams[0].getValue(), "The parameter value is incorrect");
+ }
+
+ @Test
+ @DisplayName("fieldNames generates multiple parameters (SQLite)")
+ public void fieldNamesMultipleSQLite() {
+ Configuration.setConnectionString(":sqlite:");
+ Parameter>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today"))
+ .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");
+ assertEquals("test", nameParams[0].getValue(), "The first parameter value is incorrect");
+ assertEquals(":name1", nameParams[1].getName(), "The second parameter name is incorrect");
+ assertEquals(ParameterType.STRING, nameParams[1].getType(), "The second parameter type is incorrect");
+ assertEquals("this", nameParams[1].getValue(), "The second parameter value is incorrect");
+ assertEquals(":name2", nameParams[2].getName(), "The third parameter name is incorrect");
+ assertEquals(ParameterType.STRING, nameParams[2].getType(), "The third parameter type is incorrect");
+ assertEquals("today", nameParams[2].getValue(), "The third parameter value is incorrect");
+ }
+
+ @Test
+ @DisplayName("fieldNames fails if dialect not set")
+ public void fieldNamesFails() {
+ assertThrows(DocumentException.class, () -> Parameters.fieldNames(List.of()));
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/testDocs/ByteIdClass.java b/src/test/java/solutions/bitbadger/documents/java/testDocs/ByteIdClass.java
new file mode 100644
index 0000000..c0d41e7
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/testDocs/ByteIdClass.java
@@ -0,0 +1,18 @@
+package solutions.bitbadger.documents.java.testDocs;
+
+public class ByteIdClass {
+
+ private byte id;
+
+ public byte getId() {
+ return id;
+ }
+
+ public void setId(byte id) {
+ this.id = id;
+ }
+
+ public ByteIdClass(byte id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/testDocs/IntIdClass.java b/src/test/java/solutions/bitbadger/documents/java/testDocs/IntIdClass.java
new file mode 100644
index 0000000..1d7a0cc
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/testDocs/IntIdClass.java
@@ -0,0 +1,18 @@
+package solutions.bitbadger.documents.java.testDocs;
+
+public class IntIdClass {
+
+ private int id;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public IntIdClass(int id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/testDocs/LongIdClass.java b/src/test/java/solutions/bitbadger/documents/java/testDocs/LongIdClass.java
new file mode 100644
index 0000000..1ee8bc0
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/testDocs/LongIdClass.java
@@ -0,0 +1,18 @@
+package solutions.bitbadger.documents.java.testDocs;
+
+public class LongIdClass {
+
+ private long id;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public LongIdClass(long id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/testDocs/ShortIdClass.java b/src/test/java/solutions/bitbadger/documents/java/testDocs/ShortIdClass.java
new file mode 100644
index 0000000..83a2f3c
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/testDocs/ShortIdClass.java
@@ -0,0 +1,18 @@
+package solutions.bitbadger.documents.java.testDocs;
+
+public class ShortIdClass {
+
+ private short id;
+
+ public short getId() {
+ return id;
+ }
+
+ public void setId(short id) {
+ this.id = id;
+ }
+
+ public ShortIdClass(short id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/java/solutions/bitbadger/documents/java/testDocs/StringIdClass.java b/src/test/java/solutions/bitbadger/documents/java/testDocs/StringIdClass.java
new file mode 100644
index 0000000..3013885
--- /dev/null
+++ b/src/test/java/solutions/bitbadger/documents/java/testDocs/StringIdClass.java
@@ -0,0 +1,18 @@
+package solutions.bitbadger.documents.java.testDocs;
+
+public class StringIdClass {
+
+ private String id;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public StringIdClass(String id) {
+ this.id = id;
+ }
+}
diff --git a/src/test/kotlin/AutoIdTest.kt b/src/test/kotlin/AutoIdTest.kt
index e67df54..58cc9aa 100644
--- a/src/test/kotlin/AutoIdTest.kt
+++ b/src/test/kotlin/AutoIdTest.kt
@@ -11,7 +11,7 @@ import kotlin.test.assertTrue
/**
* Unit tests for the `AutoId` enum
*/
-@DisplayName("AutoId")
+@DisplayName("Kotlin | AutoId")
class AutoIdTest {
@Test
@@ -66,8 +66,10 @@ class AutoIdTest {
@Test
@DisplayName("needsAutoId returns false for Number strategy and byte ID of non-0")
fun needsAutoIdFalseForByteWithNonZero() =
- assertFalse(AutoId.needsAutoId(AutoId.NUMBER, ByteIdClass(77), "id"),
- "Number Auto ID with 77 should return false")
+ assertFalse(
+ AutoId.needsAutoId(AutoId.NUMBER, ByteIdClass(77), "id"),
+ "Number Auto ID with 77 should return false"
+ )
@Test
@DisplayName("needsAutoId returns true for Number strategy and short ID of 0")
@@ -77,8 +79,10 @@ class AutoIdTest {
@Test
@DisplayName("needsAutoId returns false for Number strategy and short ID of non-0")
fun needsAutoIdFalseForShortWithNonZero() =
- assertFalse(AutoId.needsAutoId(AutoId.NUMBER, ShortIdClass(31), "id"),
- "Number Auto ID with 31 should return false")
+ assertFalse(
+ AutoId.needsAutoId(AutoId.NUMBER, ShortIdClass(31), "id"),
+ "Number Auto ID with 31 should return false"
+ )
@Test
@DisplayName("needsAutoId returns true for Number strategy and int ID of 0")
@@ -98,7 +102,10 @@ class AutoIdTest {
@Test
@DisplayName("needsAutoId returns false for Number strategy and long ID of non-0")
fun needsAutoIdFalseForLongWithNonZero() =
- assertFalse(AutoId.needsAutoId(AutoId.NUMBER, IntIdClass(2), "id"), "Number Auto ID with 2 should return false")
+ assertFalse(
+ AutoId.needsAutoId(AutoId.NUMBER, LongIdClass(2), "id"),
+ "Number Auto ID with 2 should return false"
+ )
@Test
@DisplayName("needsAutoId fails for Number strategy and non-number ID")
@@ -109,14 +116,18 @@ class AutoIdTest {
@Test
@DisplayName("needsAutoId returns true for UUID strategy and blank ID")
fun needsAutoIdTrueForUUIDWithBlank() =
- assertTrue(AutoId.needsAutoId(AutoId.UUID, StringIdClass(""), "id"),
- "UUID Auto ID with blank should return true")
+ assertTrue(
+ AutoId.needsAutoId(AutoId.UUID, StringIdClass(""), "id"),
+ "UUID Auto ID with blank should return true"
+ )
@Test
@DisplayName("needsAutoId returns false for UUID strategy and non-blank ID")
fun needsAutoIdFalseForUUIDNotBlank() =
- assertFalse(AutoId.needsAutoId(AutoId.UUID, StringIdClass("howdy"), "id"),
- "UUID Auto ID with non-blank should return false")
+ assertFalse(
+ AutoId.needsAutoId(AutoId.UUID, StringIdClass("howdy"), "id"),
+ "UUID Auto ID with non-blank should return false"
+ )
@Test
@DisplayName("needsAutoId fails for UUID strategy and non-string ID")
@@ -127,14 +138,18 @@ class AutoIdTest {
@Test
@DisplayName("needsAutoId returns true for Random String strategy and blank ID")
fun needsAutoIdTrueForRandomWithBlank() =
- assertTrue(AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass(""), "id"),
- "Random String Auto ID with blank should return true")
+ assertTrue(
+ AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass(""), "id"),
+ "Random String Auto ID with blank should return true"
+ )
@Test
@DisplayName("needsAutoId returns false for Random String strategy and non-blank ID")
fun needsAutoIdFalseForRandomNotBlank() =
- assertFalse(AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass("full"), "id"),
- "Random String Auto ID with non-blank should return false")
+ assertFalse(
+ AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass("full"), "id"),
+ "Random String Auto ID with non-blank should return false"
+ )
@Test
@DisplayName("needsAutoId fails for Random String strategy and non-string ID")
diff --git a/src/test/kotlin/ConfigurationTest.kt b/src/test/kotlin/ConfigurationTest.kt
index 9e83235..22754a5 100644
--- a/src/test/kotlin/ConfigurationTest.kt
+++ b/src/test/kotlin/ConfigurationTest.kt
@@ -10,7 +10,7 @@ import kotlin.test.assertTrue
/**
* Unit tests for the `Configuration` object
*/
-@DisplayName("Configuration")
+@DisplayName("Kotlin | Configuration")
class ConfigurationTest {
@Test
diff --git a/src/test/kotlin/DocumentIndexTest.kt b/src/test/kotlin/DocumentIndexTest.kt
index 0947752..9747cde 100644
--- a/src/test/kotlin/DocumentIndexTest.kt
+++ b/src/test/kotlin/DocumentIndexTest.kt
@@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `DocumentIndex` enum
*/
-@DisplayName("Op")
+@DisplayName("Kotlin | DocumentIndex")
class DocumentIndexTest {
@Test
diff --git a/src/test/kotlin/FieldMatchTest.kt b/src/test/kotlin/FieldMatchTest.kt
index 00ba366..ceb1725 100644
--- a/src/test/kotlin/FieldMatchTest.kt
+++ b/src/test/kotlin/FieldMatchTest.kt
@@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `FieldMatch` enum
*/
-@DisplayName("FieldMatch")
+@DisplayName("Kotlin | FieldMatch")
class FieldMatchTest {
@Test
diff --git a/src/test/kotlin/FieldTest.kt b/src/test/kotlin/FieldTest.kt
index 5356893..783979b 100644
--- a/src/test/kotlin/FieldTest.kt
+++ b/src/test/kotlin/FieldTest.kt
@@ -11,7 +11,7 @@ import kotlin.test.assertNull
/**
* Unit tests for the `Field` class
*/
-@DisplayName("Field")
+@DisplayName("Kotlin | Field")
class FieldTest {
/**
diff --git a/src/test/kotlin/OpTest.kt b/src/test/kotlin/OpTest.kt
index f30797a..5e6d6cd 100644
--- a/src/test/kotlin/OpTest.kt
+++ b/src/test/kotlin/OpTest.kt
@@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `Op` enum
*/
-@DisplayName("Op")
+@DisplayName("Kotlin | Op")
class OpTest {
@Test
diff --git a/src/test/kotlin/ParameterNameTest.kt b/src/test/kotlin/ParameterNameTest.kt
index 44ed76b..b08f6bb 100644
--- a/src/test/kotlin/ParameterNameTest.kt
+++ b/src/test/kotlin/ParameterNameTest.kt
@@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/**
* Unit tests for the `ParameterName` class
*/
-@DisplayName("ParameterName")
+@DisplayName("Kotlin | ParameterName")
class ParameterNameTest {
@Test
diff --git a/src/test/kotlin/ParameterTest.kt b/src/test/kotlin/ParameterTest.kt
index 9f08515..959ad25 100644
--- a/src/test/kotlin/ParameterTest.kt
+++ b/src/test/kotlin/ParameterTest.kt
@@ -9,7 +9,7 @@ import kotlin.test.assertNull
/**
* Unit tests for the `Parameter` class
*/
-@DisplayName("Parameter")
+@DisplayName("Kotlin | Parameter")
class ParameterTest {
@Test
diff --git a/src/test/kotlin/ParametersTest.kt b/src/test/kotlin/ParametersTest.kt
index e3d64a2..686ed67 100644
--- a/src/test/kotlin/ParametersTest.kt
+++ b/src/test/kotlin/ParametersTest.kt
@@ -11,7 +11,7 @@ import kotlin.test.assertSame
/**
* Unit tests for the `Parameters` object
*/
-@DisplayName("Parameters")
+@DisplayName("Kotlin | Parameters")
class ParametersTest {
/**