Collapse into top-level module
This commit is contained in:
160
src/test/kotlin/AutoIdTest.kt
Normal file
160
src/test/kotlin/AutoIdTest.kt
Normal file
@@ -0,0 +1,160 @@
|
||||
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.assertNotEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class AutoIdTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Generates a UUID string")
|
||||
fun 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")
|
||||
fun generateRandomStringEven() {
|
||||
val 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")
|
||||
fun generateRandomStringOdd() {
|
||||
val result = AutoId.generateRandomString(11)
|
||||
assertEquals(11, result.length, "There should have been 11 characters in $result")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Generates different random hex character strings")
|
||||
fun generateRandomStringIsRandom() {
|
||||
val result1 = AutoId.generateRandomString(16)
|
||||
val result2 = AutoId.generateRandomString(16)
|
||||
assertNotEquals(result1, result2, "There should have been 2 different strings generated")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId fails for null document")
|
||||
fun needsAutoIdFailsForNullDocument() {
|
||||
assertThrows<IllegalArgumentException> { AutoId.needsAutoId(AutoId.DISABLED, null, "id") }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId fails for missing ID property")
|
||||
fun needsAutoIdFailsForMissingId() {
|
||||
assertThrows<IllegalArgumentException> { AutoId.needsAutoId(AutoId.UUID, IntIdClass(0), "Id") }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId returns false if disabled")
|
||||
fun needsAutoIdFalseIfDisabled() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.DISABLED, "", ""), "Disabled Auto ID should always return false")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId returns true for Number strategy and byte ID of 0")
|
||||
fun needsAutoIdTrueForByteWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, ByteIdClass(0), "id"), "Number Auto ID with 0 should return true")
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId returns true for Number strategy and short ID of 0")
|
||||
fun needsAutoIdTrueForShortWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, ShortIdClass(0), "id"), "Number Auto ID with 0 should return true")
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId returns true for Number strategy and int ID of 0")
|
||||
fun needsAutoIdTrueForIntWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, IntIdClass(0), "id"), "Number Auto ID with 0 should return true")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId returns false for Number strategy and int ID of non-0")
|
||||
fun needsAutoIdFalseForIntWithNonZero() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, IntIdClass(6), "id"), "Number Auto ID with 6 should return false")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId returns true for Number strategy and long ID of 0")
|
||||
fun needsAutoIdTrueForLongWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, LongIdClass(0), "id"), "Number Auto ID with 0 should return true")
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId fails for Number strategy and non-number ID")
|
||||
fun needsAutoIdFailsForNumberWithStringId() {
|
||||
assertThrows<IllegalArgumentException> { AutoId.needsAutoId(AutoId.NUMBER, StringIdClass(""), "id") }
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId fails for UUID strategy and non-string ID")
|
||||
fun needsAutoIdFailsForUUIDNonString() {
|
||||
assertThrows<IllegalArgumentException> { AutoId.needsAutoId(AutoId.UUID, IntIdClass(5), "id") }
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("needsAutoId fails for Random String strategy and non-string ID")
|
||||
fun needsAutoIdFailsForRandomNonString() {
|
||||
assertThrows<IllegalArgumentException> { AutoId.needsAutoId(AutoId.RANDOM_STRING, ShortIdClass(55), "id") }
|
||||
}
|
||||
}
|
||||
|
||||
data class ByteIdClass(var id: Byte)
|
||||
data class ShortIdClass(var id: Short)
|
||||
data class IntIdClass(var id: Int)
|
||||
data class LongIdClass(var id: Long)
|
||||
data class StringIdClass(var id: String)
|
||||
26
src/test/kotlin/ConfigurationTest.kt
Normal file
26
src/test/kotlin/ConfigurationTest.kt
Normal file
@@ -0,0 +1,26 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
20
src/test/kotlin/FieldMatchTest.kt
Normal file
20
src/test/kotlin/FieldMatchTest.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class FieldMatchTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("ANY uses proper SQL")
|
||||
fun any() {
|
||||
assertEquals("OR", FieldMatch.ANY.sql, "ANY should use OR")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("ALL uses proper SQL")
|
||||
fun all() {
|
||||
assertEquals("AND", FieldMatch.ALL.sql, "ALL should use AND")
|
||||
}
|
||||
}
|
||||
277
src/test/kotlin/FieldTest.kt
Normal file
277
src/test/kotlin/FieldTest.kt
Normal file
@@ -0,0 +1,277 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class FieldTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("equal constructs a field")
|
||||
fun equalCtor() {
|
||||
val field = Field.equal("Test", 14)
|
||||
assertEquals("Test", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.EQUAL, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals(14, field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("greater constructs a field")
|
||||
fun greaterCtor() {
|
||||
val field = Field.greater("Great", "night")
|
||||
assertEquals("Great", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.GREATER, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("night", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("greaterOrEqual constructs a field")
|
||||
fun greaterOrEqualCtor() {
|
||||
val field = Field.greaterOrEqual("Nice", 88L)
|
||||
assertEquals("Nice", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.GREATER_OR_EQUAL, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals(88L, field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("less constructs a field")
|
||||
fun lessCtor() {
|
||||
val field = Field.less("Lesser", "seven")
|
||||
assertEquals("Lesser", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.LESS, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("seven", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("lessOrEqual constructs a field")
|
||||
fun lessOrEqualCtor() {
|
||||
val field = Field.lessOrEqual("Nobody", "KNOWS")
|
||||
assertEquals("Nobody", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.LESS_OR_EQUAL, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("KNOWS", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("notEqual constructs a field")
|
||||
fun notEqualCtor() {
|
||||
val field = Field.notEqual("Park", "here")
|
||||
assertEquals("Park", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.NOT_EQUAL, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("here", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("between constructs a field")
|
||||
fun betweenCtor() {
|
||||
val field = Field.between("Age", 18, 49)
|
||||
assertEquals("Age", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.BETWEEN, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals(18, field.comparison.value.first, "Field comparison min value not filled correctly")
|
||||
assertEquals(49, field.comparison.value.second, "Field comparison max value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("any constructs a field")
|
||||
fun inCtor() {
|
||||
val field = Field.any("Here", listOf(8, 16, 32))
|
||||
assertEquals("Here", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.IN, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals(listOf(8, 16, 32), field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("inArray constructs a field")
|
||||
fun inArrayCtor() {
|
||||
val field = Field.inArray("ArrayField", "table", listOf("z"))
|
||||
assertEquals("ArrayField", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.IN_ARRAY, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("table", field.comparison.value.first, "Field comparison table not filled correctly")
|
||||
assertEquals(listOf("z"), field.comparison.value.second, "Field comparison values not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("exists constructs a field")
|
||||
fun existsCtor() {
|
||||
val field = Field.exists("Groovy")
|
||||
assertEquals("Groovy", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.EXISTS, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("notExists constructs a field")
|
||||
fun notExistsCtor() {
|
||||
val field = Field.notExists("Groovy")
|
||||
assertEquals("Groovy", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.NOT_EXISTS, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("named constructs a field")
|
||||
fun namedCtor() {
|
||||
val field = Field.named("Tacos")
|
||||
assertEquals("Tacos", field.name, "Field name not filled correctly")
|
||||
assertEquals(Op.EQUAL, field.comparison.op, "Field comparison operation not filled correctly")
|
||||
assertEquals("", field.comparison.value, "Field comparison value not filled correctly")
|
||||
assertNull(field.parameterName, "The parameter name should have been null")
|
||||
assertNull(field.qualifier, "The qualifier should have been null")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nameToPath creates a simple PostgreSQL SQL name")
|
||||
fun nameToPathPostgresSimpleSQL() {
|
||||
assertEquals("data->>'Simple'", Field.nameToPath("Simple", Dialect.POSTGRESQL, FieldFormat.SQL),
|
||||
"Path not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nameToPath creates a simple SQLite SQL name")
|
||||
fun nameToPathSQLiteSimpleSQL() {
|
||||
assertEquals("data->>'Simple'", Field.nameToPath("Simple", Dialect.SQLITE, FieldFormat.SQL),
|
||||
"Path not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nameToPath creates a nested PostgreSQL SQL name")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun nameToPathPostgresSimpleJSON() {
|
||||
assertEquals("data->'Simple'", Field.nameToPath("Simple", Dialect.POSTGRESQL, FieldFormat.JSON),
|
||||
"Path not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nameToPath creates a simple SQLite JSON name")
|
||||
fun nameToPathSQLiteSimpleJSON() {
|
||||
assertEquals("data->'Simple'", Field.nameToPath("Simple", Dialect.SQLITE, FieldFormat.JSON),
|
||||
"Path not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nameToPath creates a nested PostgreSQL JSON name")
|
||||
fun 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")
|
||||
fun 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")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("withParameterName adjusts the parameter name")
|
||||
fun withParameterName() {
|
||||
assertEquals(":name", Field.equal("Bob", "Tom").withParameterName(":name").parameterName,
|
||||
"Parameter name not filled correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("withQualifier adjust the table qualifier")
|
||||
fun withQualifier() {
|
||||
assertEquals("joe", Field.equal("Bill", "Matt").withQualifier("joe").qualifier,
|
||||
"Qualifier not filled correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("path generates for simple unqualified PostgreSQL field")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun 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")
|
||||
fun pathSQLiteNestedQualified() {
|
||||
assertEquals("bird.data->'Nest'->>'Away'",
|
||||
Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.SQLITE, FieldFormat.SQL),
|
||||
"Path not correct")
|
||||
}
|
||||
}
|
||||
74
src/test/kotlin/OpTest.kt
Normal file
74
src/test/kotlin/OpTest.kt
Normal file
@@ -0,0 +1,74 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class OpTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("EQUAL uses proper SQL")
|
||||
fun equalSQL() {
|
||||
assertEquals("=", Op.EQUAL.sql, "The SQL for equal is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("GREATER uses proper SQL")
|
||||
fun greaterSQL() {
|
||||
assertEquals(">", Op.GREATER.sql, "The SQL for greater is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("GREATER_OR_EQUAL uses proper SQL")
|
||||
fun greaterOrEqualSQL() {
|
||||
assertEquals(">=", Op.GREATER_OR_EQUAL.sql, "The SQL for greater-or-equal is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LESS uses proper SQL")
|
||||
fun lessSQL() {
|
||||
assertEquals("<", Op.LESS.sql, "The SQL for less is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LESS_OR_EQUAL uses proper SQL")
|
||||
fun lessOrEqualSQL() {
|
||||
assertEquals("<=", Op.LESS_OR_EQUAL.sql, "The SQL for less-or-equal is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("NOT_EQUAL uses proper SQL")
|
||||
fun notEqualSQL() {
|
||||
assertEquals("<>", Op.NOT_EQUAL.sql, "The SQL for not-equal is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("BETWEEN uses proper SQL")
|
||||
fun betweenSQL() {
|
||||
assertEquals("BETWEEN", Op.BETWEEN.sql, "The SQL for between is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("IN uses proper SQL")
|
||||
fun inSQL() {
|
||||
assertEquals("IN", Op.IN.sql, "The SQL for in is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("IN_ARRAY uses proper SQL")
|
||||
fun inArraySQL() {
|
||||
assertEquals("?|", Op.IN_ARRAY.sql, "The SQL for in-array is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("EXISTS uses proper SQL")
|
||||
fun existsSQL() {
|
||||
assertEquals("IS NOT NULL", Op.EXISTS.sql, "The SQL for exists is incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("NOT_EXISTS uses proper SQL")
|
||||
fun notExistsSQL() {
|
||||
assertEquals("IS NULL", Op.NOT_EXISTS.sql, "The SQL for not-exists is incorrect")
|
||||
}
|
||||
}
|
||||
26
src/test/kotlin/ParameterNameTest.kt
Normal file
26
src/test/kotlin/ParameterNameTest.kt
Normal file
@@ -0,0 +1,26 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ParameterNameTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("derive works when given existing names")
|
||||
fun withExisting() {
|
||||
val names = 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")
|
||||
fun allAnonymous() {
|
||||
val names = 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")
|
||||
}
|
||||
}
|
||||
34
src/test/kotlin/ParameterTest.kt
Normal file
34
src/test/kotlin/ParameterTest.kt
Normal file
@@ -0,0 +1,34 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class ParameterTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Construction with colon-prefixed name")
|
||||
fun ctorWithColon() {
|
||||
val p = Parameter(":test", ParameterType.STRING, "ABC")
|
||||
assertEquals(":test", p.name, "Parameter name was incorrect")
|
||||
assertEquals(ParameterType.STRING, p.type, "Parameter type was incorrect")
|
||||
assertEquals("ABC", p.value, "Parameter value was incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Construction with at-sign-prefixed name")
|
||||
fun ctorWithAtSign() {
|
||||
val p = Parameter("@yo", ParameterType.NUMBER, null)
|
||||
assertEquals("@yo", p.name, "Parameter name was incorrect")
|
||||
assertEquals(ParameterType.NUMBER, p.type, "Parameter type was incorrect")
|
||||
assertNull(p.value, "Parameter value was incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Construction fails with incorrect prefix")
|
||||
fun ctorFailsForPrefix() {
|
||||
assertThrows<DocumentException> { Parameter("it", ParameterType.JSON, "") }
|
||||
}
|
||||
}
|
||||
18
src/test/kotlin/ParametersTest.kt
Normal file
18
src/test/kotlin/ParametersTest.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ParametersTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("replaceNamesInQuery replaces successfully")
|
||||
fun replaceNamesInQuery() {
|
||||
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")
|
||||
}
|
||||
}
|
||||
197
src/test/kotlin/QueryTest.kt
Normal file
197
src/test/kotlin/QueryTest.kt
Normal file
@@ -0,0 +1,197 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class QueryTest {
|
||||
|
||||
/** Test table name */
|
||||
private val tbl = "test_table"
|
||||
|
||||
@Test
|
||||
@DisplayName("statementWhere generates correctly")
|
||||
fun statementWhere() {
|
||||
assertEquals("x WHERE y", Query.statementWhere("x", "y"), "Statements not combined correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Definition.ensureTableFor generates correctly")
|
||||
fun ensureTableFor() {
|
||||
assertEquals("CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)",
|
||||
Query.Definition.ensureTableFor("my.table", "JSONB"), "CREATE TABLE statement not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Definition.ensureKey generates correctly with schema")
|
||||
fun ensureKeyWithSchema() {
|
||||
assertEquals("CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data->>'id'))",
|
||||
Query.Definition.ensureKey("test.table", Dialect.POSTGRESQL),
|
||||
"CREATE INDEX for key statement with schema not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Definition.ensureKey generates correctly without schema")
|
||||
fun ensureKeyWithoutSchema() {
|
||||
assertEquals("CREATE UNIQUE INDEX IF NOT EXISTS idx_${tbl}_key ON $tbl ((data->>'id'))",
|
||||
Query.Definition.ensureKey(tbl, Dialect.SQLITE),
|
||||
"CREATE INDEX for key statement without schema not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Definition.ensureIndexOn generates multiple fields and directions")
|
||||
fun ensureIndexOnMultipleFields() {
|
||||
assertEquals(
|
||||
"CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table ((data->>'taco'), (data->>'guac') DESC, (data->>'salsa') ASC)",
|
||||
Query.Definition.ensureIndexOn("test.table", "gibberish", listOf("taco", "guac DESC", "salsa ASC"),
|
||||
Dialect.POSTGRESQL),
|
||||
"CREATE INDEX for multiple field statement not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Definition.ensureIndexOn generates nested PostgreSQL field")
|
||||
fun ensureIndexOnNestedPostgres() {
|
||||
assertEquals("CREATE INDEX IF NOT EXISTS idx_${tbl}_nest ON $tbl ((data#>>'{a,b,c}'))",
|
||||
Query.Definition.ensureIndexOn(tbl, "nest", listOf("a.b.c"), Dialect.POSTGRESQL),
|
||||
"CREATE INDEX for nested PostgreSQL field incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Definition.ensureIndexOn generates nested SQLite field")
|
||||
fun ensureIndexOnNestedSQLite() {
|
||||
assertEquals("CREATE INDEX IF NOT EXISTS idx_${tbl}_nest ON $tbl ((data->'a'->'b'->>'c'))",
|
||||
Query.Definition.ensureIndexOn(tbl, "nest", listOf("a.b.c"), Dialect.SQLITE),
|
||||
"CREATE INDEX for nested SQLite field incorrect")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("insert generates correctly")
|
||||
fun insert() {
|
||||
try {
|
||||
Configuration.connectionString = "postgresql"
|
||||
assertEquals(
|
||||
"INSERT INTO $tbl VALUES (:data)",
|
||||
Query.insert(tbl),
|
||||
"INSERT statement not constructed correctly"
|
||||
)
|
||||
} finally {
|
||||
Configuration.connectionString = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("save generates correctly")
|
||||
fun save() {
|
||||
try {
|
||||
Configuration.connectionString = "postgresql"
|
||||
assertEquals(
|
||||
"INSERT INTO $tbl VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data",
|
||||
Query.save(tbl), "INSERT ON CONFLICT UPDATE statement not constructed correctly"
|
||||
)
|
||||
} finally {
|
||||
Configuration.connectionString = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("count generates correctly")
|
||||
fun count() {
|
||||
assertEquals("SELECT COUNT(*) AS it FROM $tbl", Query.count(tbl), "Count query not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("exists generates correctly")
|
||||
fun exists() {
|
||||
assertEquals("SELECT EXISTS (SELECT 1 FROM $tbl WHERE turkey) AS it", Query.exists(tbl, "turkey"),
|
||||
"Exists query not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("find generates correctly")
|
||||
fun find() {
|
||||
assertEquals("SELECT data FROM $tbl", Query.find(tbl), "Find query not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("update generates successfully")
|
||||
fun update() {
|
||||
assertEquals("UPDATE $tbl SET data = :data", Query.update(tbl), "Update query not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("delete generates successfully")
|
||||
fun delete() {
|
||||
assertEquals("DELETE FROM $tbl", Query.delete(tbl), "Delete query not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates for no fields")
|
||||
fun orderByNone() {
|
||||
assertEquals("", Query.orderBy(listOf(), Dialect.POSTGRESQL), "ORDER BY should have been blank (PostgreSQL)")
|
||||
assertEquals("", Query.orderBy(listOf(), Dialect.SQLITE), "ORDER BY should have been blank (SQLite)")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates single, no direction for PostgreSQL")
|
||||
fun orderBySinglePostgres() {
|
||||
assertEquals(" ORDER BY data->>'TestField'",
|
||||
Query.orderBy(listOf(Field.named("TestField")), Dialect.POSTGRESQL), "ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates single, no direction for SQLite")
|
||||
fun orderBySingleSQLite() {
|
||||
assertEquals(" ORDER BY data->>'TestField'", Query.orderBy(listOf(Field.named("TestField")), Dialect.SQLITE),
|
||||
"ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates multiple with direction for PostgreSQL")
|
||||
fun orderByMultiplePostgres() {
|
||||
assertEquals(" ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC",
|
||||
Query.orderBy(
|
||||
listOf(Field.named("Nested.Test.Field DESC"), Field.named("AnotherField"), Field.named("It DESC")),
|
||||
Dialect.POSTGRESQL),
|
||||
"ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates multiple with direction for SQLite")
|
||||
fun orderByMultipleSQLite() {
|
||||
assertEquals(" ORDER BY data->'Nested'->'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC",
|
||||
Query.orderBy(
|
||||
listOf(Field.named("Nested.Test.Field DESC"), Field.named("AnotherField"), Field.named("It DESC")),
|
||||
Dialect.SQLITE),
|
||||
"ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates numeric ordering PostgreSQL")
|
||||
fun orderByNumericPostgres() {
|
||||
assertEquals(" ORDER BY (data->>'Test')::numeric",
|
||||
Query.orderBy(listOf(Field.named("n:Test")), Dialect.POSTGRESQL), "ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates numeric ordering for SQLite")
|
||||
fun orderByNumericSQLite() {
|
||||
assertEquals(" ORDER BY data->>'Test'", Query.orderBy(listOf(Field.named("n:Test")), Dialect.SQLITE),
|
||||
"ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates case-insensitive ordering for PostgreSQL")
|
||||
fun orderByCIPostgres() {
|
||||
assertEquals(" ORDER BY LOWER(data#>>'{Test,Field}') DESC NULLS FIRST",
|
||||
Query.orderBy(listOf(Field.named("i:Test.Field DESC NULLS FIRST")), Dialect.POSTGRESQL),
|
||||
"ORDER BY not constructed correctly")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("orderBy generates case-insensitive ordering for SQLite")
|
||||
fun orderByCISQLite() {
|
||||
assertEquals(" ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST",
|
||||
Query.orderBy(listOf(Field.named("i:Test.Field ASC NULLS LAST")), Dialect.SQLITE),
|
||||
"ORDER BY not constructed correctly")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user