Reorg complete, jvm tests pass

This commit is contained in:
2025-03-14 22:38:23 -04:00
parent 2697ddaeed
commit 11e3200ff7
82 changed files with 232 additions and 537 deletions

View File

@@ -23,7 +23,8 @@ fun <TDoc> Connection.customList(
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<TDoc>,
mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Custom.list(query, parameters, clazz, this, mapFunc)
) =
solutions.bitbadger.documents.jvm.Custom.list(query, parameters, clazz, this, mapFunc)
/**
* Execute a query that returns one or no results
@@ -39,7 +40,8 @@ fun <TDoc> Connection.customSingle(
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<TDoc>,
mapFunc: (ResultSet, Class<TDoc>) -> TDoc
) = Custom.single(query, parameters, clazz, this, mapFunc)
) =
solutions.bitbadger.documents.jvm.Custom.single(query, parameters, clazz, this, mapFunc)
/**
* Execute a query that returns no results
@@ -48,7 +50,7 @@ fun <TDoc> Connection.customSingle(
* @param parameters Parameters to use for the query
*/
fun Connection.customNonQuery(query: String, parameters: Collection<Parameter<*>> = listOf()) =
Custom.nonQuery(query, parameters, this)
solutions.bitbadger.documents.jvm.Custom.nonQuery(query, parameters, this)
/**
* Execute a query that returns a scalar result
@@ -64,7 +66,8 @@ fun <T : Any> Connection.customScalar(
parameters: Collection<Parameter<*>> = listOf(),
clazz: Class<T>,
mapFunc: (ResultSet, Class<T>) -> T
) = Custom.scalar(query, parameters, clazz, this, mapFunc)
) =
solutions.bitbadger.documents.jvm.Custom.scalar(query, parameters, clazz, this, mapFunc)
// ~~~ DEFINITION QUERIES ~~~

View File

@@ -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.support.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `AutoId` enum
*/
@DisplayName("Java | Common | 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"));
}
}

View File

@@ -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 | Common | 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");
}
}

View File

@@ -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 | Common | 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");
}
}

View File

@@ -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 | Common | 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<String> field = Field.equal("abc", "22").withQualifier("me");
Field<String> 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<String> field = Field.equal("def", "44");
Field<String> 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<String> field = Field.equal("j", "k");
Field<String> 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<Integer> 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<Integer> 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<String> 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<String> 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<Long> 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<Long> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<Pair<Integer, Integer>> 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<Pair<Integer, Integer>> 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<Collection<Integer>> 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<Collection<Integer>> 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<Pair<String, Collection<String>>> 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<Pair<String, Collection<String>>> 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<String> 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<String> 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<String> 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");
}
}

View File

@@ -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 | Common | 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");
}
}

View File

@@ -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 | Common | 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");
}
}

View File

@@ -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 | Common | Parameter")
final public class ParameterTest {
@Test
@DisplayName("Construction with colon-prefixed name")
public void ctorWithColon() {
Parameter<String> 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<String> 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, ""));
}
}

View File

@@ -1,10 +1,10 @@
package solutions.bitbadger.documents.java.java;
package solutions.bitbadger.documents.java.jvm;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*;
import solutions.bitbadger.documents.java.jvm.Parameters;
import solutions.bitbadger.documents.jvm.Parameters;
import java.util.List;

View File

@@ -1,15 +1,15 @@
package solutions.bitbadger.documents.java.java.integration.common;
package solutions.bitbadger.documents.java.jvm.integration.common;
import solutions.bitbadger.documents.Field;
import solutions.bitbadger.documents.java.jvm.Count;
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase;
import solutions.bitbadger.documents.java.java.testDocs.JsonDocument;
import solutions.bitbadger.documents.jvm.Count;
import solutions.bitbadger.documents.support.ThrowawayDatabase;
import solutions.bitbadger.documents.java.support.JsonDocument;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static solutions.bitbadger.documents.java.integration.TypesKt.TEST_TABLE;
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE;
/**
* Integration tests for the `Count` object

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.java.integration.postgresql;
package solutions.bitbadger.documents.java.jvm.integration.postgresql;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.java.integration.postgresql.PgDB;
import solutions.bitbadger.documents.java.java.integration.common.CountFunctions;
import solutions.bitbadger.documents.java.jvm.integration.common.CountFunctions;
import solutions.bitbadger.documents.jvm.integration.postgresql.PgDB;
/**
* PostgreSQL integration tests for the `Count` object / `count*` connection extension functions

View File

@@ -1,10 +1,10 @@
package solutions.bitbadger.documents.java.java.integration.sqlite;
package solutions.bitbadger.documents.java.jvm.integration.sqlite;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.DocumentException;
import solutions.bitbadger.documents.java.integration.sqlite.SQLiteDB;
import solutions.bitbadger.documents.java.java.integration.common.CountFunctions;
import solutions.bitbadger.documents.java.jvm.integration.common.CountFunctions;
import solutions.bitbadger.documents.jvm.integration.sqlite.SQLiteDB;
import static org.junit.jupiter.api.Assertions.assertThrows;

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
public class ByteIdClass {

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
public class IntIdClass {

View File

@@ -1,12 +1,12 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
import kotlinx.serialization.Serializable;
import solutions.bitbadger.documents.java.jvm.Document;
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase;
import solutions.bitbadger.documents.jvm.Document;
import solutions.bitbadger.documents.support.ThrowawayDatabase;
import java.util.List;
import static solutions.bitbadger.documents.java.integration.TypesKt.TEST_TABLE;
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE;
@Serializable
public class JsonDocument {

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
public class LongIdClass {

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
public class ShortIdClass {

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
public class StringIdClass {

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.java.testDocs;
package solutions.bitbadger.documents.java.support;
public class SubDocument {

View File

@@ -0,0 +1,165 @@
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
/**
* Unit tests for the `AutoId` enum
*/
@DisplayName("Kotlin | Common | AutoId")
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<DocumentException> { AutoId.needsAutoId(AutoId.DISABLED, null, "id") }
}
@Test
@DisplayName("needsAutoId fails for missing ID property")
fun needsAutoIdFailsForMissingId() {
assertThrows<DocumentException> { 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, LongIdClass(2), "id"),
"Number Auto ID with 2 should return false"
)
@Test
@DisplayName("needsAutoId fails for Number strategy and non-number ID")
fun needsAutoIdFailsForNumberWithStringId() {
assertThrows<DocumentException> { 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<DocumentException> { 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<DocumentException> { AutoId.needsAutoId(AutoId.RANDOM_STRING, ShortIdClass(55), "id") }
}
}
data class ByteIdClass(val id: Byte)
data class ShortIdClass(val id: Short)
data class IntIdClass(val id: Int)
data class LongIdClass(val id: Long)
data class StringIdClass(val id: String)

View File

@@ -0,0 +1,168 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
/**
* Unit tests for the `ComparisonBetween` class
*/
@DisplayName("ComparisonBetween")
class ComparisonBetweenTest {
@Test
@DisplayName("op is set to BETWEEN")
fun op() =
assertEquals(Op.BETWEEN, ComparisonBetween(Pair(0, 0)).op, "Between comparison should have BETWEEN op")
@Test
@DisplayName("isNumeric is false with strings")
fun isNumericFalseForStringsAndBetween() =
assertFalse(
ComparisonBetween(Pair("eh", "zed")).isNumeric,
"A BETWEEN with strings should not be numeric")
@Test
@DisplayName("isNumeric is true with bytes")
fun isNumericTrueForByteAndBetween() =
assertTrue(ComparisonBetween(Pair<Byte, Byte>(7, 11)).isNumeric, "A BETWEEN with bytes should be numeric")
@Test
@DisplayName("isNumeric is true with shorts")
fun isNumericTrueForShortAndBetween() =
assertTrue(
ComparisonBetween(Pair<Short, Short>(0, 9)).isNumeric,
"A BETWEEN with shorts should be numeric")
@Test
@DisplayName("isNumeric is true with ints")
fun isNumericTrueForIntAndBetween() =
assertTrue(ComparisonBetween(Pair(15, 44)).isNumeric, "A BETWEEN with ints should be numeric")
@Test
@DisplayName("isNumeric is true with longs")
fun isNumericTrueForLongAndBetween() =
assertTrue(ComparisonBetween(Pair(9L, 12L)).isNumeric, "A BETWEEN with longs should be numeric")
}
/**
* Unit tests for the `ComparisonIn` class
*/
@DisplayName("ComparisonIn")
class ComparisonInTest {
@Test
@DisplayName("op is set to IN")
fun op() =
assertEquals(Op.IN, ComparisonIn(listOf<String>()).op, "In comparison should have IN op")
@Test
@DisplayName("isNumeric is false for empty list of values")
fun isNumericFalseForEmptyList() =
assertFalse(ComparisonIn(listOf<Int>()).isNumeric, "An IN with empty list should not be numeric")
@Test
@DisplayName("isNumeric is false with strings")
fun isNumericFalseForStringsAndIn() =
assertFalse(ComparisonIn(listOf("a", "b", "c")).isNumeric, "An IN with strings should not be numeric")
@Test
@DisplayName("isNumeric is true with bytes")
fun isNumericTrueForByteAndIn() =
assertTrue(ComparisonIn(listOf<Byte>(4, 8)).isNumeric, "An IN with bytes should be numeric")
@Test
@DisplayName("isNumeric is true with shorts")
fun isNumericTrueForShortAndIn() =
assertTrue(ComparisonIn(listOf<Short>(18, 22)).isNumeric, "An IN with shorts should be numeric")
@Test
@DisplayName("isNumeric is true with ints")
fun isNumericTrueForIntAndIn() =
assertTrue(ComparisonIn(listOf(7, 8, 9)).isNumeric, "An IN with ints should be numeric")
@Test
@DisplayName("isNumeric is true with longs")
fun isNumericTrueForLongAndIn() =
assertTrue(ComparisonIn(listOf(3L)).isNumeric, "An IN with longs should be numeric")
}
/**
* Unit tests for the `ComparisonInArray` class
*/
@DisplayName("ComparisonInArray")
class ComparisonInArrayTest {
@Test
@DisplayName("op is set to IN_ARRAY")
fun op() =
assertEquals(
Op.IN_ARRAY,
ComparisonInArray(Pair("tbl", listOf<String>())).op,
"InArray comparison should have IN_ARRAY op"
)
@Test
@DisplayName("isNumeric is false for empty list of values")
fun isNumericFalseForEmptyList() =
assertFalse(ComparisonIn(listOf<Int>()).isNumeric, "An IN_ARRAY with empty list should not be numeric")
@Test
@DisplayName("isNumeric is false with strings")
fun isNumericFalseForStringsAndIn() =
assertFalse(ComparisonIn(listOf("a", "b", "c")).isNumeric, "An IN_ARRAY with strings should not be numeric")
@Test
@DisplayName("isNumeric is false with bytes")
fun isNumericTrueForByteAndIn() =
assertTrue(ComparisonIn(listOf<Byte>(4, 8)).isNumeric, "An IN_ARRAY with bytes should not be numeric")
@Test
@DisplayName("isNumeric is false with shorts")
fun isNumericTrueForShortAndIn() =
assertTrue(ComparisonIn(listOf<Short>(18, 22)).isNumeric, "An IN_ARRAY with shorts should not be numeric")
@Test
@DisplayName("isNumeric is false with ints")
fun isNumericTrueForIntAndIn() =
assertTrue(ComparisonIn(listOf(7, 8, 9)).isNumeric, "An IN_ARRAY with ints should not be numeric")
@Test
@DisplayName("isNumeric is false with longs")
fun isNumericTrueForLongAndIn() =
assertTrue(ComparisonIn(listOf(3L)).isNumeric, "An IN_ARRAY with longs should not be numeric")
}
/**
* Unit tests for the `ComparisonSingle` class
*/
@DisplayName("ComparisonSingle")
class ComparisonSingleTest {
@Test
@DisplayName("isNumeric is false for string value")
fun isNumericFalseForString() =
assertFalse(ComparisonSingle(Op.EQUAL, "80").isNumeric, "A string should not be numeric")
@Test
@DisplayName("isNumeric is true for byte value")
fun isNumericTrueForByte() =
assertTrue(ComparisonSingle(Op.EQUAL, 47.toByte()).isNumeric, "A byte should be numeric")
@Test
@DisplayName("isNumeric is true for short value")
fun isNumericTrueForShort() =
assertTrue(ComparisonSingle(Op.EQUAL, 2.toShort()).isNumeric, "A short should be numeric")
@Test
@DisplayName("isNumeric is true for int value")
fun isNumericTrueForInt() =
assertTrue(ComparisonSingle(Op.EQUAL, 555).isNumeric, "An int should be numeric")
@Test
@DisplayName("isNumeric is true for long value")
fun isNumericTrueForLong() =
assertTrue(ComparisonSingle(Op.EQUAL, 82L).isNumeric, "A long should be numeric")
}

View File

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

View File

@@ -0,0 +1,40 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
/**
* Unit tests for the `Dialect` enum
*/
@DisplayName("Kotlin | Common | Dialect")
class DialectTest {
@Test
@DisplayName("deriveFromConnectionString derives PostgreSQL correctly")
fun derivesPostgres() =
assertEquals(
Dialect.POSTGRESQL, Dialect.deriveFromConnectionString("jdbc:postgresql:db"),
"Dialect should have been PostgreSQL")
@Test
@DisplayName("deriveFromConnectionString derives PostgreSQL correctly")
fun derivesSQLite() =
assertEquals(
Dialect.SQLITE, Dialect.deriveFromConnectionString("jdbc:sqlite:memory"),
"Dialect should have been SQLite")
@Test
@DisplayName("deriveFromConnectionString fails when the connection string is unknown")
fun deriveFailsWhenUnknown() {
try {
Dialect.deriveFromConnectionString("SQL Server")
} catch (ex: DocumentException) {
assertNotNull(ex.message, "The exception message should not have been null")
assertTrue(ex.message!!.contains("[SQL Server]"),
"The connection string should have been in the exception message")
}
}
}

View File

@@ -0,0 +1,24 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
/**
* Unit tests for the `DocumentIndex` enum
*/
@DisplayName("Kotlin | Common | DocumentIndex")
class DocumentIndexTest {
@Test
@DisplayName("FULL uses proper SQL")
fun fullSQL() {
assertEquals("", DocumentIndex.FULL.sql, "The SQL for Full is incorrect")
}
@Test
@DisplayName("OPTIMIZED uses proper SQL")
fun optimizedSQL() {
assertEquals(" jsonb_path_ops", DocumentIndex.OPTIMIZED.sql, "The SQL for Optimized is incorrect")
}
}

View File

@@ -0,0 +1,24 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
/**
* Unit tests for the `FieldMatch` enum
*/
@DisplayName("Kotlin | Common | FieldMatch")
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")
}
}

View File

@@ -0,0 +1,594 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertNotSame
import kotlin.test.assertNull
/**
* Unit tests for the `Field` class
*/
@DisplayName("Kotlin | Common | Field")
class FieldTest {
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
// ~~~ INSTANCE METHODS ~~~
@Test
@DisplayName("withParameterName fails for invalid name")
fun withParamNameFails() {
assertThrows<DocumentException> { Field.equal("it", "").withParameterName("2424") }
}
@Test
@DisplayName("withParameterName works with colon prefix")
fun withParamNameColon() {
val field = Field.equal("abc", "22").withQualifier("me")
val withParam = field.withParameterName(":test")
assertNotSame(field, withParam, "A new Field instance should have been created")
assertEquals(field.name, withParam.name, "Name should have been preserved")
assertEquals(field.comparison, withParam.comparison, "Comparison should have been preserved")
assertEquals(":test", withParam.parameterName, "Parameter name not set correctly")
assertEquals(field.qualifier, withParam.qualifier, "Qualifier should have been preserved")
}
@Test
@DisplayName("withParameterName works with at-sign prefix")
fun withParamNameAtSign() {
val field = Field.equal("def", "44")
val withParam = field.withParameterName("@unit")
assertNotSame(field, withParam, "A new Field instance should have been created")
assertEquals(field.name, withParam.name, "Name should have been preserved")
assertEquals(field.comparison, withParam.comparison, "Comparison should have been preserved")
assertEquals("@unit", withParam.parameterName, "Parameter name not set correctly")
assertEquals(field.qualifier, withParam.qualifier, "Qualifier should have been preserved")
}
@Test
@DisplayName("withQualifier sets qualifier correctly")
fun withQualifier() {
val field = Field.equal("j", "k")
val withQual = field.withQualifier("test")
assertNotSame(field, withQual, "A new Field instance should have been created")
assertEquals(field.name, withQual.name, "Name should have been preserved")
assertEquals(field.comparison, withQual.comparison, "Comparison should have been preserved")
assertEquals(field.parameterName, withQual.parameterName, "Parameter Name should have been preserved")
assertEquals("test", withQual.qualifier, "Qualifier not set 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")
@Test
@DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)")
fun toWhereExistsNoQualPostgres() {
Configuration.dialectValue = Dialect.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)")
fun toWhereExistsNoQualSQLite() {
Configuration.dialectValue = Dialect.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)")
fun toWhereNotExistsNoQualPostgres() {
Configuration.dialectValue = Dialect.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)")
fun toWhereNotExistsNoQualSQLite() {
Configuration.dialectValue = Dialect.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)")
fun toWhereBetweenNoQualNumericPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").toWhere(), "Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range (PostgreSQL)")
fun toWhereBetweenNoQualAlphaPostgres() {
Configuration.dialectValue = Dialect.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)")
fun toWhereBetweenNoQualSQLite() {
Configuration.dialectValue = Dialect.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)")
fun toWhereBetweenQualNumericPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(test.data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range (PostgreSQL)")
fun toWhereBetweenQualAlphaPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("unit.data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").withQualifier("unit").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier (SQLite)")
fun toWhereBetweenQualSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("my.data->>'age' BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("my").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for IN/any, numeric values (PostgreSQL)")
fun toWhereAnyNumericPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'even')::numeric IN (:nbr_0, :nbr_1, :nbr_2)",
Field.any("even", listOf(2, 4, 6), ":nbr").toWhere(), "Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for IN/any, alphanumeric values (PostgreSQL)")
fun toWhereAnyAlphaPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for IN/any (SQLite)")
fun toWhereAnySQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for inArray (PostgreSQL)")
fun toWhereInArrayPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]",
Field.inArray("even", "tbl", listOf(2, 4, 6, 8), ":it").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for inArray (SQLite)")
fun toWhereInArraySQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("EXISTS (SELECT 1 FROM json_each(tbl.data, '$.test') WHERE value IN (:city_0, :city_1))",
Field.inArray("test", "tbl", listOf("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates for others w/o qualifier (PostgreSQL)")
fun toWhereOtherNoQualPostgres() {
Configuration.dialectValue = Dialect.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)")
fun toWhereOtherNoQualSQLite() {
Configuration.dialectValue = Dialect.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)")
fun toWhereNoParamWithQualPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates no-parameter w/ qualifier (SQLite)")
fun toWhereNoParamWithQualSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates parameter w/ qualifier (PostgreSQL)")
fun toWhereParamWithQualPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(q.data->>'le_field')::numeric <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly")
}
@Test
@DisplayName("toWhere generates parameter w/ qualifier (SQLite)")
fun toWhereParamWithQualSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("q.data->>'le_field' <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly")
}
// ~~~ COMPANION OBJECT TESTS ~~~
@Test
@DisplayName("equal constructs a field w/o parameter name")
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("equal constructs a field w/ parameter name")
fun equalParameterCtor() {
val field = Field.equal("Test", 14, ":w")
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")
assertEquals(":w", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("greater constructs a field w/o parameter name")
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("greater constructs a field w/ parameter name")
fun greaterParameterCtor() {
val field = Field.greater("Great", "night", ":yeah")
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")
assertEquals(":yeah", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("greaterOrEqual constructs a field w/o parameter name")
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("greaterOrEqual constructs a field w/ parameter name")
fun greaterOrEqualParameterCtor() {
val field = Field.greaterOrEqual("Nice", 88L, ":nice")
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")
assertEquals(":nice", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("less constructs a field w/o parameter name")
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("less constructs a field w/ parameter name")
fun lessParameterCtor() {
val field = Field.less("Lesser", "seven", ":max")
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")
assertEquals(":max", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("lessOrEqual constructs a field w/o parameter name")
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("lessOrEqual constructs a field w/ parameter name")
fun lessOrEqualParameterCtor() {
val field = Field.lessOrEqual("Nobody", "KNOWS", ":nope")
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")
assertEquals(":nope", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("notEqual constructs a field w/o parameter name")
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("notEqual constructs a field w/ parameter name")
fun notEqualParameterCtor() {
val field = Field.notEqual("Park", "here", ":now")
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")
assertEquals(":now", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("between constructs a field w/o parameter name")
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("between constructs a field w/ parameter name")
fun betweenParameterCtor() {
val field = Field.between("Age", 18, 49, ":limit")
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")
assertEquals(":limit", field.parameterName, "The parameter name should have been null")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("any constructs a field w/o parameter name")
fun anyCtor() {
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("any constructs a field w/ parameter name")
fun anyParameterCtor() {
val field = Field.any("Here", listOf(8, 16, 32), ":list")
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")
assertEquals(":list", field.parameterName, "Field parameter name not filled correctly")
assertNull(field.qualifier, "The qualifier should have been null")
}
@Test
@DisplayName("inArray constructs a field w/o parameter name")
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("inArray constructs a field w/ parameter name")
fun inArrayParameterCtor() {
val field = Field.inArray("ArrayField", "table", listOf("z"), ":a")
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")
assertEquals(":a", field.parameterName, "Field parameter name not filled correctly")
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("static constructors fail for invalid parameter name")
fun staticCtorsFailOnParamName() {
assertThrows<DocumentException> { Field.equal("a", "b", "that ain't it, Jack...") }
}
@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")
}

View File

@@ -0,0 +1,78 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
/**
* Unit tests for the `Op` enum
*/
@DisplayName("Kotlin | Common | Op")
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")
}
}

View File

@@ -0,0 +1,30 @@
package solutions.bitbadger.documents
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
/**
* Unit tests for the `ParameterName` class
*/
@DisplayName("Kotlin | Common | ParameterName")
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")
}
}

View File

@@ -0,0 +1,38 @@
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
/**
* Unit tests for the `Parameter` class
*/
@DisplayName("Kotlin | Common | Parameter")
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, "") }
}
}

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java
package solutions.bitbadger.documents.jvm
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
@@ -38,7 +38,8 @@ class ParametersTest {
@DisplayName("nameFields works when changing fields")
fun nameFieldsChange() {
val fields = listOf(
Field.equal("a", ""), Field.equal("e", "", ":hi"), Field.equal("b", ""), Field.notExists("z"))
Field.equal("a", ""), Field.equal("e", "", ":hi"), Field.equal("b", ""), Field.notExists("z")
)
val named = Parameters.nameFields(fields)
assertEquals(fields.size, named.size, "There should have been 4 fields in the list")
assertNotSame(fields.elementAt(0), named.elementAt(0), "The first field should not be the same")

View File

@@ -1,13 +1,8 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.java.extensions.countAll
import solutions.bitbadger.documents.java.extensions.countByContains
import solutions.bitbadger.documents.java.extensions.countByFields
import solutions.bitbadger.documents.java.extensions.countByJsonPath
import solutions.bitbadger.documents.java.integration.JsonDocument
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.*
import kotlin.test.assertEquals
/**

View File

@@ -1,16 +1,12 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.Parameter
import solutions.bitbadger.documents.ParameterType
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.java.*
import solutions.bitbadger.documents.java.extensions.*
import solutions.bitbadger.documents.java.integration.JsonDocument
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.java.jvm.Results
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.jvm.Results
import solutions.bitbadger.documents.query.Count
import solutions.bitbadger.documents.query.Delete
import solutions.bitbadger.documents.query.Find
import solutions.bitbadger.documents.support.*
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

View File

@@ -1,11 +1,11 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.DocumentIndex
import solutions.bitbadger.documents.java.extensions.ensureDocumentIndex
import solutions.bitbadger.documents.java.extensions.ensureFieldIndex
import solutions.bitbadger.documents.java.extensions.ensureTable
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.extensions.ensureDocumentIndex
import solutions.bitbadger.documents.extensions.ensureFieldIndex
import solutions.bitbadger.documents.extensions.ensureTable
import solutions.bitbadger.documents.support.TEST_TABLE
import solutions.bitbadger.documents.support.ThrowawayDatabase
import kotlin.test.assertFalse
import kotlin.test.assertTrue

View File

@@ -1,10 +1,10 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.java.extensions.*
import solutions.bitbadger.documents.java.integration.JsonDocument
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.JsonDocument
import solutions.bitbadger.documents.support.TEST_TABLE
import solutions.bitbadger.documents.support.ThrowawayDatabase
import kotlin.test.assertEquals
/**

View File

@@ -1,11 +1,10 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import AutoId
import solutions.bitbadger.documents.AutoId
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.java.extensions.*
import solutions.bitbadger.documents.java.integration.*
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.*
import kotlin.test.*
/**

View File

@@ -1,13 +1,8 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.java.extensions.existsByContains
import solutions.bitbadger.documents.java.extensions.existsByFields
import solutions.bitbadger.documents.java.extensions.existsById
import solutions.bitbadger.documents.java.extensions.existsByJsonPath
import solutions.bitbadger.documents.java.integration.JsonDocument
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.*
import kotlin.test.assertFalse
import kotlin.test.assertTrue

View File

@@ -1,11 +1,10 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.FieldMatch
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.java.extensions.*
import solutions.bitbadger.documents.java.integration.*
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.*
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

View File

@@ -1,10 +1,8 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.java.extensions.*
import solutions.bitbadger.documents.java.integration.JsonDocument
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.*
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull

View File

@@ -1,10 +1,8 @@
package solutions.bitbadger.documents.java.integration.common
package solutions.bitbadger.documents.jvm.integration.common
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.java.extensions.*
import solutions.bitbadger.documents.java.integration.JsonDocument
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.extensions.*
import solutions.bitbadger.documents.support.*
import kotlin.test.*

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Count
import solutions.bitbadger.documents.jvm.integration.common.Count
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Custom
import solutions.bitbadger.documents.jvm.integration.common.Custom
import kotlin.test.Test

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Definition
import solutions.bitbadger.documents.jvm.integration.common.Definition
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Delete
import solutions.bitbadger.documents.jvm.integration.common.Delete
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Document
import solutions.bitbadger.documents.jvm.integration.common.Document
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Exists
import solutions.bitbadger.documents.jvm.integration.common.Exists
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Find
import solutions.bitbadger.documents.jvm.integration.common.Find
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Patch
import solutions.bitbadger.documents.jvm.integration.common.Patch
import kotlin.test.Test
/**

View File

@@ -1,18 +1,11 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import AutoId
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Parameter
import solutions.bitbadger.documents.ParameterType
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.java.*
import solutions.bitbadger.documents.java.extensions.customNonQuery
import solutions.bitbadger.documents.java.extensions.customScalar
import solutions.bitbadger.documents.java.extensions.ensureTable
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.java.jvm.DocumentConfig
import solutions.bitbadger.documents.java.jvm.Results
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.extensions.customNonQuery
import solutions.bitbadger.documents.extensions.customScalar
import solutions.bitbadger.documents.extensions.ensureTable
import solutions.bitbadger.documents.jvm.*
import solutions.bitbadger.documents.support.*
/**
* A wrapper for a throwaway PostgreSQL database

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.postgresql
package solutions.bitbadger.documents.jvm.integration.postgresql
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.RemoveFields
import solutions.bitbadger.documents.jvm.integration.common.RemoveFields
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.Count
import solutions.bitbadger.documents.jvm.integration.common.Count
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Custom
import solutions.bitbadger.documents.jvm.integration.common.Custom
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.Definition
import solutions.bitbadger.documents.jvm.integration.common.Definition
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.Delete
import solutions.bitbadger.documents.jvm.integration.common.Delete
import kotlin.test.Test
/**

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import solutions.bitbadger.documents.java.integration.common.Document
import solutions.bitbadger.documents.jvm.integration.common.Document
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.Exists
import solutions.bitbadger.documents.jvm.integration.common.Exists
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.Find
import solutions.bitbadger.documents.jvm.integration.common.Find
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.Patch
import solutions.bitbadger.documents.jvm.integration.common.Patch
import kotlin.test.Test
/**

View File

@@ -1,9 +1,9 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.integration.common.RemoveFields
import solutions.bitbadger.documents.jvm.integration.common.RemoveFields
import kotlin.test.Test
/**

View File

@@ -1,17 +1,10 @@
package solutions.bitbadger.documents.java.integration.sqlite
package solutions.bitbadger.documents.jvm.integration.sqlite
import AutoId
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Parameter
import solutions.bitbadger.documents.ParameterType
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.java.*
import solutions.bitbadger.documents.java.extensions.customScalar
import solutions.bitbadger.documents.java.extensions.ensureTable
import solutions.bitbadger.documents.java.integration.TEST_TABLE
import solutions.bitbadger.documents.java.integration.ThrowawayDatabase
import solutions.bitbadger.documents.java.jvm.DocumentConfig
import solutions.bitbadger.documents.java.jvm.Results
import solutions.bitbadger.documents.*
import solutions.bitbadger.documents.extensions.customScalar
import solutions.bitbadger.documents.extensions.ensureTable
import solutions.bitbadger.documents.jvm.*
import solutions.bitbadger.documents.support.*
import java.io.File
/**

View File

@@ -0,0 +1,90 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
import kotlin.test.assertEquals
/**
* Unit tests for the `Count` object
*/
@DisplayName("Kotlin | Common | Query: Count")
class CountTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("all generates correctly")
fun all() =
assertEquals("SELECT COUNT(*) AS it FROM $tbl", Count.all(tbl), "Count query not constructed correctly")
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT COUNT(*) AS it FROM $tbl WHERE data->>'test' = :field0",
Count.byFields(tbl, listOf(Field.equal("test", "", ":field0"))),
"Count query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"SELECT COUNT(*) AS it FROM $tbl WHERE data->>'test' = :field0",
Count.byFields(tbl, listOf(Field.equal("test", "", ":field0"))),
"Count query not constructed correctly"
)
}
@Test
@DisplayName("byContains generates correctly (PostgreSQL)")
fun byContainsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT COUNT(*) AS it FROM $tbl WHERE data @> :criteria", Count.byContains(tbl),
"Count query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Count.byContains(tbl) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT COUNT(*) AS it FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)",
Count.byJsonPath(tbl), "Count query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Count.byJsonPath(tbl) }
}
}

View File

@@ -0,0 +1,134 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.DocumentIndex
import kotlin.test.assertEquals
/**
* Unit tests for the `Definition` object
*/
@DisplayName("Kotlin | Common | Query: Definition")
class DefinitionTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("ensureTableFor generates correctly")
fun ensureTableFor() =
assertEquals(
"CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)",
Definition.ensureTableFor("my.table", "JSONB"), "CREATE TABLE statement not constructed correctly"
)
@Test
@DisplayName("ensureTable generates correctly (PostgreSQL)")
fun ensureTablePostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("CREATE TABLE IF NOT EXISTS $tbl (data JSONB NOT NULL)", Definition.ensureTable(tbl))
}
@Test
@DisplayName("ensureTable generates correctly (SQLite)")
fun ensureTableSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("CREATE TABLE IF NOT EXISTS $tbl (data TEXT NOT NULL)", Definition.ensureTable(tbl))
}
@Test
@DisplayName("ensureTable fails when no dialect is set")
fun ensureTableFailsUnknown() {
assertThrows<DocumentException> { Definition.ensureTable(tbl) }
}
@Test
@DisplayName("ensureKey generates correctly with schema")
fun ensureKeyWithSchema() =
assertEquals(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data->>'id'))",
Definition.ensureKey("test.table", Dialect.POSTGRESQL),
"CREATE INDEX for key statement with schema not constructed correctly"
)
@Test
@DisplayName("ensureKey generates correctly without schema")
fun ensureKeyWithoutSchema() =
assertEquals(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_${tbl}_key ON $tbl ((data->>'id'))",
Definition.ensureKey(tbl, Dialect.SQLITE),
"CREATE INDEX for key statement without schema not constructed correctly"
)
@Test
@DisplayName("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)",
Definition.ensureIndexOn(
"test.table", "gibberish", listOf("taco", "guac DESC", "salsa ASC"),
Dialect.POSTGRESQL
),
"CREATE INDEX for multiple field statement not constructed correctly"
)
@Test
@DisplayName("ensureIndexOn generates nested PostgreSQL field")
fun ensureIndexOnNestedPostgres() =
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_nest ON $tbl ((data#>>'{a,b,c}'))",
Definition.ensureIndexOn(tbl, "nest", listOf("a.b.c"), Dialect.POSTGRESQL),
"CREATE INDEX for nested PostgreSQL field incorrect"
)
@Test
@DisplayName("ensureIndexOn generates nested SQLite field")
fun ensureIndexOnNestedSQLite() =
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_nest ON $tbl ((data->'a'->'b'->>'c'))",
Definition.ensureIndexOn(tbl, "nest", listOf("a.b.c"), Dialect.SQLITE),
"CREATE INDEX for nested SQLite field incorrect"
)
@Test
@DisplayName("ensureDocumentIndexOn generates Full for PostgreSQL")
fun ensureDocumentIndexOnFullPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_document ON $tbl USING GIN (data)",
Definition.ensureDocumentIndexOn(tbl, DocumentIndex.FULL),
"CREATE INDEX for full document index incorrect"
)
}
@Test
@DisplayName("ensureDocumentIndexOn generates Optimized for PostgreSQL")
fun ensureDocumentIndexOnOptimizedPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_document ON $tbl USING GIN (data jsonb_path_ops)",
Definition.ensureDocumentIndexOn(tbl, DocumentIndex.OPTIMIZED),
"CREATE INDEX for optimized document index incorrect"
)
}
@Test
@DisplayName("ensureDocumentIndexOn fails for SQLite")
fun ensureDocumentIndexOnFailsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Definition.ensureDocumentIndexOn(tbl, DocumentIndex.FULL) }
}
}

View File

@@ -0,0 +1,102 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
import kotlin.test.assertEquals
/**
* Unit tests for the `Delete` object
*/
@DisplayName("Kotlin | Common | Query: Delete")
class DeleteTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("byId generates correctly (PostgreSQL)")
fun byIdPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"DELETE FROM $tbl WHERE data->>'id' = :id",
Delete.byId<String>(tbl), "Delete query not constructed correctly"
)
}
@Test
@DisplayName("byId generates correctly (SQLite)")
fun byIdSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"DELETE FROM $tbl WHERE data->>'id' = :id",
Delete.byId<String>(tbl), "Delete query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"DELETE FROM $tbl WHERE data->>'a' = :b", Delete.byFields(tbl, listOf(Field.equal("a", "", ":b"))),
"Delete query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (SQLite)")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"DELETE FROM $tbl WHERE data->>'a' = :b", Delete.byFields(tbl, listOf(Field.equal("a", "", ":b"))),
"Delete query not constructed correctly"
)
}
@Test
@DisplayName("byContains generates correctly (PostgreSQL)")
fun byContainsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"DELETE FROM $tbl WHERE data @> :criteria", Delete.byContains(tbl), "Delete query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Delete.byContains(tbl) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"DELETE FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)", Delete.byJsonPath(tbl),
"Delete query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Delete.byJsonPath(tbl) }
}
}

View File

@@ -0,0 +1,150 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.AutoId
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import kotlin.test.assertEquals
import kotlin.test.assertTrue
/**
* Unit tests for the `Document` object
*/
@DisplayName("Kotlin | Common | Query: Document")
class DocumentTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("insert generates no auto ID (PostgreSQL)")
fun insertNoAutoPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("INSERT INTO $tbl VALUES (:data)", Document.insert(tbl))
}
@Test
@DisplayName("insert generates no auto ID (SQLite)")
fun insertNoAutoSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("INSERT INTO $tbl VALUES (:data)", Document.insert(tbl))
}
@Test
@DisplayName("insert generates auto number (PostgreSQL)")
fun insertAutoNumberPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"INSERT INTO $tbl VALUES (:data::jsonb || ('{\"id\":' " +
"|| (SELECT COALESCE(MAX((data->>'id')::numeric), 0) + 1 FROM $tbl) || '}')::jsonb)",
Document.insert(tbl, AutoId.NUMBER)
)
}
@Test
@DisplayName("insert generates auto number (SQLite)")
fun insertAutoNumberSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"INSERT INTO $tbl VALUES (json_set(:data, '$.id', " +
"(SELECT coalesce(max(data->>'id'), 0) + 1 FROM $tbl)))",
Document.insert(tbl, AutoId.NUMBER)
)
}
@Test
@DisplayName("insert generates auto UUID (PostgreSQL)")
fun insertAutoUUIDPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
val query = Document.insert(tbl, AutoId.UUID)
assertTrue(
query.startsWith("INSERT INTO $tbl VALUES (:data::jsonb || '{\"id\":\""),
"Query start not correct (actual: $query)"
)
assertTrue(query.endsWith("\"}')"), "Query end not correct")
}
@Test
@DisplayName("insert generates auto UUID (SQLite)")
fun insertAutoUUIDSQLite() {
Configuration.dialectValue = Dialect.SQLITE
val query = Document.insert(tbl, AutoId.UUID)
assertTrue(
query.startsWith("INSERT INTO $tbl VALUES (json_set(:data, '$.id', '"),
"Query start not correct (actual: $query)"
)
assertTrue(query.endsWith("'))"), "Query end not correct")
}
@Test
@DisplayName("insert generates auto random string (PostgreSQL)")
fun insertAutoRandomPostgres() {
try {
Configuration.dialectValue = Dialect.POSTGRESQL
Configuration.idStringLength = 8
val query = Document.insert(tbl, AutoId.RANDOM_STRING)
assertTrue(
query.startsWith("INSERT INTO $tbl VALUES (:data::jsonb || '{\"id\":\""),
"Query start not correct (actual: $query)"
)
assertTrue(query.endsWith("\"}')"), "Query end not correct")
assertEquals(
8,
query.replace("INSERT INTO $tbl VALUES (:data::jsonb || '{\"id\":\"", "").replace("\"}')", "").length,
"Random string length incorrect"
)
} finally {
Configuration.idStringLength = 16
}
}
@Test
@DisplayName("insert generates auto random string (SQLite)")
fun insertAutoRandomSQLite() {
Configuration.dialectValue = Dialect.SQLITE
val query = Document.insert(tbl, AutoId.RANDOM_STRING)
assertTrue(
query.startsWith("INSERT INTO $tbl VALUES (json_set(:data, '$.id', '"),
"Query start not correct (actual: $query)"
)
assertTrue(query.endsWith("'))"), "Query end not correct")
assertEquals(
Configuration.idStringLength,
query.replace("INSERT INTO $tbl VALUES (json_set(:data, '$.id', '", "").replace("'))", "").length,
"Random string length incorrect"
)
}
@Test
@DisplayName("insert fails when no dialect is set")
fun insertFailsUnknown() {
assertThrows<DocumentException> { Document.insert(tbl) }
}
@Test
@DisplayName("save generates correctly")
fun save() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"INSERT INTO $tbl VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data",
Document.save(tbl), "INSERT ON CONFLICT UPDATE statement not constructed correctly"
)
}
@Test
@DisplayName("update generates successfully")
fun update() =
assertEquals("UPDATE $tbl SET data = :data", Document.update(tbl), "Update query not constructed correctly")
}

View File

@@ -0,0 +1,105 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
import kotlin.test.assertEquals
/**
* Unit tests for the `Exists` object
*/
@DisplayName("Kotlin | Common | Query: Exists")
class ExistsTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("byId generates correctly (PostgreSQL)")
fun byIdPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT EXISTS (SELECT 1 FROM $tbl WHERE data->>'id' = :id) AS it",
Exists.byId<String>(tbl), "Exists query not constructed correctly"
)
}
@Test
@DisplayName("byId generates correctly (SQLite)")
fun byIdSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"SELECT EXISTS (SELECT 1 FROM $tbl WHERE data->>'id' = :id) AS it",
Exists.byId<String>(tbl), "Exists query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT EXISTS (SELECT 1 FROM $tbl WHERE (data->>'it')::numeric = :test) AS it",
Exists.byFields(tbl, listOf(Field.equal("it", 7, ":test"))),
"Exists query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (SQLite)")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"SELECT EXISTS (SELECT 1 FROM $tbl WHERE data->>'it' = :test) AS it",
Exists.byFields(tbl, listOf(Field.equal("it", 7, ":test"))),
"Exists query not constructed correctly"
)
}
@Test
@DisplayName("byContains generates correctly (PostgreSQL)")
fun byContainsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT EXISTS (SELECT 1 FROM $tbl WHERE data @> :criteria) AS it", Exists.byContains(tbl),
"Exists query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Exists.byContains(tbl) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT EXISTS (SELECT 1 FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)) AS it",
Exists.byJsonPath(tbl), "Exists query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Exists.byJsonPath(tbl) }
}
}

View File

@@ -0,0 +1,110 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
import kotlin.test.assertEquals
/**
* Unit tests for the `Find` object
*/
@DisplayName("Kotlin | Common | Query: Find")
class FindTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("all generates correctly")
fun all() =
assertEquals("SELECT data FROM $tbl", Find.all(tbl), "Find query not constructed correctly")
@Test
@DisplayName("byId generates correctly (PostgreSQL)")
fun byIdPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT data FROM $tbl WHERE data->>'id' = :id",
Find.byId<String>(tbl), "Find query not constructed correctly"
)
}
@Test
@DisplayName("byId generates correctly (SQLite)")
fun byIdSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"SELECT data FROM $tbl WHERE data->>'id' = :id",
Find.byId<String>(tbl), "Find query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT data FROM $tbl WHERE data->>'a' = :b AND (data->>'c')::numeric < :d",
Find.byFields(tbl, listOf(Field.equal("a", "", ":b"), Field.less("c", 14, ":d"))),
"Find query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (SQLite)")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"SELECT data FROM $tbl WHERE data->>'a' = :b AND data->>'c' < :d",
Find.byFields(tbl, listOf(Field.equal("a", "", ":b"), Field.less("c", 14, ":d"))),
"Find query not constructed correctly"
)
}
@Test
@DisplayName("byContains generates correctly (PostgreSQL)")
fun byContainsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT data FROM $tbl WHERE data @> :criteria", Find.byContains(tbl),
"Find query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Find.byContains(tbl) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"SELECT data FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)", Find.byJsonPath(tbl),
"Find query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Find.byJsonPath(tbl) }
}
}

View File

@@ -0,0 +1,105 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field
import kotlin.test.assertEquals
/**
* Unit tests for the `Patch` object
*/
@DisplayName("Kotlin | Common | Query: Patch")
class PatchTest {
/** Test table name */
private val tbl = "test_table"
/**
* Reset the dialect
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("byId generates correctly (PostgreSQL)")
fun byIdPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data || :data WHERE data->>'id' = :id",
Patch.byId<String>(tbl), "Patch query not constructed correctly"
)
}
@Test
@DisplayName("byId generates correctly (SQLite)")
fun byIdSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"UPDATE $tbl SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id",
Patch.byId<String>(tbl), "Patch query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data || :data WHERE data->>'z' = :y",
Patch.byFields(tbl, listOf(Field.equal("z", "", ":y"))),
"Patch query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (SQLite)")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"UPDATE $tbl SET data = json_patch(data, json(:data)) WHERE data->>'z' = :y",
Patch.byFields(tbl, listOf(Field.equal("z", "", ":y"))),
"Patch query not constructed correctly"
)
}
@Test
@DisplayName("byContains generates correctly (PostgreSQL)")
fun byContainsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data || :data WHERE data @> :criteria", Patch.byContains(tbl),
"Patch query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Patch.byContains(tbl) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)",
Patch.byJsonPath(tbl), "Patch query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Patch.byJsonPath(tbl) }
}
}

View File

@@ -0,0 +1,178 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.FieldMatch
import kotlin.test.assertEquals
/**
* Unit tests for the top-level query functions
*/
@DisplayName("Kotlin | Common | Query")
class QueryTest {
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("statementWhere generates correctly")
fun statementWhere() =
assertEquals("x WHERE y", statementWhere("x", "y"), "Statements not combined correctly")
@Test
@DisplayName("byId generates a numeric ID query (PostgreSQL)")
fun byIdNumericPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("test WHERE (data->>'id')::numeric = :id", byId("test", 9))
}
@Test
@DisplayName("byId generates an alphanumeric ID query (PostgreSQL)")
fun byIdAlphaPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("unit WHERE data->>'id' = :id", byId("unit", "18"))
}
@Test
@DisplayName("byId generates ID query (SQLite)")
fun byIdSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("yo WHERE data->>'id' = :id", byId("yo", 27))
}
@Test
@DisplayName("byFields generates default field query (PostgreSQL)")
fun byFieldsMultipleDefaultPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"this WHERE data->>'a' = :the_a AND (data->>'b')::numeric = :b_value",
byFields("this", listOf(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")))
)
}
@Test
@DisplayName("byFields generates default field query (SQLite)")
fun byFieldsMultipleDefaultSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"this WHERE data->>'a' = :the_a AND data->>'b' = :b_value",
byFields("this", listOf(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")))
)
}
@Test
@DisplayName("byFields generates ANY field query (PostgreSQL)")
fun byFieldsMultipleAnyPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"that WHERE data->>'a' = :the_a OR (data->>'b')::numeric = :b_value",
byFields(
"that", listOf(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")),
FieldMatch.ANY
)
)
}
@Test
@DisplayName("byFields generates ANY field query (SQLite)")
fun byFieldsMultipleAnySQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"that WHERE data->>'a' = :the_a OR data->>'b' = :b_value",
byFields(
"that", listOf(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")),
FieldMatch.ANY
)
)
}
@Test
@DisplayName("orderBy generates for no fields")
fun orderByNone() {
assertEquals("", orderBy(listOf(), Dialect.POSTGRESQL), "ORDER BY should have been blank (PostgreSQL)")
assertEquals("", 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'",
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'", 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",
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",
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",
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'", 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",
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",
orderBy(listOf(Field.named("i:Test.Field ASC NULLS LAST")), Dialect.SQLITE),
"ORDER BY not constructed correctly"
)
}

View File

@@ -0,0 +1,120 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.*
import kotlin.test.assertEquals
/**
* Unit tests for the `RemoveFields` object
*/
@DisplayName("Kotlin | Common | Query: RemoveFields")
class RemoveFieldsTest {
/** Test table name */
private val tbl = "test_table"
/**
* Reset the dialect
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("byId generates correctly (PostgreSQL)")
fun byIdPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data - :name::text[] WHERE data->>'id' = :id",
RemoveFields.byId<String>(tbl, listOf(Parameter(":name", ParameterType.STRING, "{a,z}"))),
"Remove Fields query not constructed correctly"
)
}
@Test
@DisplayName("byId generates correctly (SQLite)")
fun byIdSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"UPDATE $tbl SET data = json_remove(data, :name0, :name1) WHERE data->>'id' = :id",
RemoveFields.byId<String>(
tbl,
listOf(
Parameter(":name0", ParameterType.STRING, "a"),
Parameter(":name1", ParameterType.STRING, "z")
)
),
"Remove Field query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
fun byFieldsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data - :name::text[] WHERE data->>'f' > :g",
RemoveFields.byFields(
tbl,
listOf(Parameter(":name", ParameterType.STRING, "{b,c}")),
listOf(Field.greater("f", "", ":g"))
),
"Remove Field query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (SQLite)")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"UPDATE $tbl SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g",
RemoveFields.byFields(
tbl,
listOf(Parameter(":name0", ParameterType.STRING, "b"), Parameter(":name1", ParameterType.STRING, "c")),
listOf(Field.greater("f", "", ":g"))
),
"Remove Field query not constructed correctly"
)
}
@Test
@DisplayName("byContains generates correctly (PostgreSQL)")
fun byContainsPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data - :name::text[] WHERE data @> :criteria",
RemoveFields.byContains(tbl, listOf(Parameter(":name", ParameterType.STRING, "{m,n}"))),
"Remove Field query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { RemoveFields.byContains(tbl, listOf()) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"UPDATE $tbl SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)",
RemoveFields.byJsonPath(tbl, listOf(Parameter(":name", ParameterType.STRING, "{o,p}"))),
"Remove Field query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { RemoveFields.byJsonPath(tbl, listOf()) }
}
}

View File

@@ -0,0 +1,176 @@
package solutions.bitbadger.documents.query
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.*
import kotlin.test.assertEquals
/**
* Unit tests for the `Where` object
*/
@DisplayName("Kotlin | Common | Query: Where")
class WhereTest {
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
}
@Test
@DisplayName("byFields is blank when given no fields")
fun byFieldsBlankIfEmpty() =
assertEquals("", Where.byFields(listOf()))
@Test
@DisplayName("byFields generates one numeric field (PostgreSQL)")
fun byFieldsOneFieldPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'it')::numeric = :that", Where.byFields(listOf(Field.equal("it", 9, ":that"))))
}
@Test
@DisplayName("byFields generates one alphanumeric field (PostgreSQL)")
fun byFieldsOneAlphaFieldPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'it' = :that", Where.byFields(listOf(Field.equal("it", "", ":that"))))
}
@Test
@DisplayName("byFields generates one field (SQLite)")
fun byFieldsOneFieldSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'it' = :that", Where.byFields(listOf(Field.equal("it", "", ":that"))))
}
@Test
@DisplayName("byFields generates multiple fields w/ default match (PostgreSQL)")
fun byFieldsMultipleDefaultPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"data->>'1' = :one AND (data->>'2')::numeric = :two AND data->>'3' = :three",
Where.byFields(
listOf(Field.equal("1", "", ":one"), Field.equal("2", 0L, ":two"), Field.equal("3", "", ":three"))
)
)
}
@Test
@DisplayName("byFields generates multiple fields w/ default match (SQLite)")
fun byFieldsMultipleDefaultSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"data->>'1' = :one AND data->>'2' = :two AND data->>'3' = :three",
Where.byFields(
listOf(Field.equal("1", "", ":one"), Field.equal("2", 0L, ":two"), Field.equal("3", "", ":three"))
)
)
}
@Test
@DisplayName("byFields generates multiple fields w/ ANY match (PostgreSQL)")
fun byFieldsMultipleAnyPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals(
"data->>'1' = :one OR (data->>'2')::numeric = :two OR data->>'3' = :three",
Where.byFields(
listOf(Field.equal("1", "", ":one"), Field.equal("2", 0L, ":two"), Field.equal("3", "", ":three")),
FieldMatch.ANY
)
)
}
@Test
@DisplayName("byFields generates multiple fields w/ ANY match (SQLite)")
fun byFieldsMultipleAnySQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals(
"data->>'1' = :one OR data->>'2' = :two OR data->>'3' = :three",
Where.byFields(
listOf(Field.equal("1", "", ":one"), Field.equal("2", 0L, ":two"), Field.equal("3", "", ":three")),
FieldMatch.ANY
)
)
}
@Test
@DisplayName("byId generates defaults for alphanumeric key (PostgreSQL)")
fun byIdDefaultAlphaPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'id' = :id", Where.byId(docId = ""))
}
@Test
@DisplayName("byId generates defaults for numeric key (PostgreSQL)")
fun byIdDefaultNumericPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("(data->>'id')::numeric = :id", Where.byId(docId = 5))
}
@Test
@DisplayName("byId generates defaults (SQLite)")
fun byIdDefaultSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'id' = :id", Where.byId(docId = ""))
}
@Test
@DisplayName("byId generates named ID (PostgreSQL)")
fun byIdDefaultNamedPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data->>'id' = :key", Where.byId<String>(":key"))
}
@Test
@DisplayName("byId generates named ID (SQLite)")
fun byIdDefaultNamedSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("data->>'id' = :key", Where.byId<String>(":key"))
}
@Test
@DisplayName("jsonContains generates defaults (PostgreSQL)")
fun jsonContainsDefaultPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data @> :criteria", Where.jsonContains())
}
@Test
@DisplayName("jsonContains generates named parameter (PostgreSQL)")
fun jsonContainsNamedPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("data @> :it", Where.jsonContains(":it"))
}
@Test
@DisplayName("jsonContains fails (SQLite)")
fun jsonContainsFailsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Where.jsonContains() }
}
@Test
@DisplayName("jsonPathMatches generates defaults (PostgreSQL)")
fun jsonPathMatchDefaultPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("jsonb_path_exists(data, :path::jsonpath)", Where.jsonPathMatches())
}
@Test
@DisplayName("jsonPathMatches generates named parameter (PostgreSQL)")
fun jsonPathMatchNamedPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("jsonb_path_exists(data, :jp::jsonpath)", Where.jsonPathMatches(":jp"))
}
@Test
@DisplayName("jsonPathMatches fails (SQLite)")
fun jsonPathFailsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { Where.jsonPathMatches() }
}
}

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java
package solutions.bitbadger.documents.support
import solutions.bitbadger.documents.DocumentSerializer
import com.fasterxml.jackson.databind.ObjectMapper

View File

@@ -1,4 +1,4 @@
package solutions.bitbadger.documents.java.integration
package solutions.bitbadger.documents.support
import java.sql.Connection

View File

@@ -1,7 +1,7 @@
package solutions.bitbadger.documents.java.integration
package solutions.bitbadger.documents.support
import kotlinx.serialization.Serializable
import solutions.bitbadger.documents.java.extensions.insert
import solutions.bitbadger.documents.extensions.insert
/** The test table name to use for integration tests */
const val TEST_TABLE = "test_table"