diff --git a/src/jvm/src/main/kotlin/Field.kt b/src/jvm/src/main/kotlin/Field.kt index d15a838..9a4c899 100644 --- a/src/jvm/src/main/kotlin/Field.kt +++ b/src/jvm/src/main/kotlin/Field.kt @@ -1,5 +1,7 @@ package solutions.bitbadger.documents +import kotlin.jvm.Throws + /** * A field and its comparison * @@ -44,6 +46,7 @@ class Field private constructor( * @param format Whether the value should be retrieved as JSON or SQL (optional, default SQL) * @return The path for the field */ + @JvmOverloads fun path(dialect: Dialect, format: FieldFormat = FieldFormat.SQL): String = (if (qualifier == null) "" else "${qualifier}.") + nameToPath(name, dialect, format) @@ -65,6 +68,7 @@ class Field private constructor( * @return The `WHERE` clause for this field * @throws DocumentException If the field has no parameter name or the database dialect has not been set */ + @Throws(DocumentException::class) fun toWhere(): String { if (parameterName == null && !listOf(Op.EXISTS, Op.NOT_EXISTS).contains(comparison.op)) throw DocumentException("Parameter for $name must be specified") diff --git a/src/jvm/src/main/kotlin/query/CountQuery.kt b/src/jvm/src/main/kotlin/query/CountQuery.kt index 82b97b4..6439f6c 100644 --- a/src/jvm/src/main/kotlin/query/CountQuery.kt +++ b/src/jvm/src/main/kotlin/query/CountQuery.kt @@ -28,7 +28,9 @@ object CountQuery { * @param fields The field comparisons for the count * @param howMatched How fields should be compared (optional, defaults to ALL) * @return A query to count documents matching the given fields + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = diff --git a/src/jvm/src/main/kotlin/query/DeleteQuery.kt b/src/jvm/src/main/kotlin/query/DeleteQuery.kt index 8241a6e..7dd1b07 100644 --- a/src/jvm/src/main/kotlin/query/DeleteQuery.kt +++ b/src/jvm/src/main/kotlin/query/DeleteQuery.kt @@ -27,7 +27,9 @@ object DeleteQuery { * @param tableName The table from which documents should be deleted (may include schema) * @param docId The ID of the document (optional, used for type checking) * @return A query to delete a document by its ID + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byId(tableName: String, docId: TKey? = null) = @@ -40,7 +42,9 @@ object DeleteQuery { * @param fields The field comparisons for documents to be deleted * @param howMatched How fields should be compared (optional, defaults to ALL) * @return A query to delete documents matching for the given fields + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = diff --git a/src/jvm/src/main/kotlin/query/ExistsQuery.kt b/src/jvm/src/main/kotlin/query/ExistsQuery.kt index a77457e..e15f5ca 100644 --- a/src/jvm/src/main/kotlin/query/ExistsQuery.kt +++ b/src/jvm/src/main/kotlin/query/ExistsQuery.kt @@ -26,7 +26,9 @@ object ExistsQuery { * @param tableName The table in which existence should be checked (may include schema) * @param docId The ID of the document (optional, used for type checking) * @return A query to determine document existence by ID + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byId(tableName: String, docId: TKey? = null) = @@ -39,7 +41,9 @@ object ExistsQuery { * @param fields The field comparisons for the existence check * @param howMatched How fields should be compared (optional, defaults to ALL) * @return A query to determine document existence for the given fields + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = diff --git a/src/jvm/src/main/kotlin/query/FindQuery.kt b/src/jvm/src/main/kotlin/query/FindQuery.kt index 3606a2b..13077bf 100644 --- a/src/jvm/src/main/kotlin/query/FindQuery.kt +++ b/src/jvm/src/main/kotlin/query/FindQuery.kt @@ -28,7 +28,9 @@ object FindQuery { * @param tableName The table from which documents should be retrieved (may include schema) * @param docId The ID of the document (optional, used for type checking) * @return A query to retrieve a document by its ID + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byId(tableName: String, docId: TKey? = null) = @@ -41,7 +43,9 @@ object FindQuery { * @param fields The field comparisons for matching documents to retrieve * @param howMatched How fields should be compared (optional, defaults to ALL) * @return A query to retrieve documents matching the given fields + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = diff --git a/src/jvm/src/main/kotlin/query/Query.kt b/src/jvm/src/main/kotlin/query/Query.kt index c79203e..9381e81 100644 --- a/src/jvm/src/main/kotlin/query/Query.kt +++ b/src/jvm/src/main/kotlin/query/Query.kt @@ -1,10 +1,8 @@ @file:JvmName("QueryUtils") package solutions.bitbadger.documents.query -import solutions.bitbadger.documents.Configuration -import solutions.bitbadger.documents.Dialect -import solutions.bitbadger.documents.Field -import solutions.bitbadger.documents.FieldMatch +import solutions.bitbadger.documents.* +import kotlin.jvm.Throws // ~~~ TOP-LEVEL FUNCTIONS FOR THE QUERY PACKAGE ~~~ @@ -24,7 +22,9 @@ fun statementWhere(statement: String, where: String) = * @param statement The SQL statement to be run against a document by its ID * @param docId The ID of the document targeted * @returns A query addressing a document by its ID + * @throws DocumentException If the dialect has not been set */ +@Throws(DocumentException::class) fun byId(statement: String, docId: TKey) = statementWhere(statement, Where.byId(docId = docId)) @@ -36,6 +36,7 @@ fun byId(statement: String, docId: TKey) = * @param howMatched Whether to match any or all of the field conditions (optional; default ALL) * @return A query addressing documents by field matching conditions */ +@Throws(DocumentException::class) @JvmOverloads fun byFields(statement: String, fields: Collection>, howMatched: FieldMatch? = null) = statementWhere(statement, Where.byFields(fields, howMatched)) @@ -47,6 +48,7 @@ fun byFields(statement: String, fields: Collection>, howMatched: FieldM * @param dialect The SQL dialect for the generated clause * @return An `ORDER BY` clause for the given fields */ +@Throws(DocumentException::class) @JvmOverloads fun orderBy(fields: Collection>, dialect: Dialect? = null): String { val mode = dialect ?: Configuration.dialect("generate ORDER BY clause") diff --git a/src/jvm/src/main/kotlin/query/Where.kt b/src/jvm/src/main/kotlin/query/Where.kt index 626002e..da232ed 100644 --- a/src/jvm/src/main/kotlin/query/Where.kt +++ b/src/jvm/src/main/kotlin/query/Where.kt @@ -18,7 +18,9 @@ object Where { * @param fields The fields to be queried * @param howMatched How the fields should be matched (optional, defaults to `ALL`) * @return A `WHERE` clause fragment to match the given fields + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byFields(fields: Collection>, howMatched: FieldMatch? = null) = @@ -29,7 +31,10 @@ object Where { * * @param parameterName The parameter name to use for the ID placeholder (optional, defaults to ":id") * @param docId The ID value (optional; used for type determinations, string assumed if not provided) + * @return A `WHERE` clause fragment to match the document's ID + * @throws DocumentException If the dialect has not been set */ + @Throws(DocumentException::class) @JvmStatic @JvmOverloads fun byId(parameterName: String = ":id", docId: TKey? = null) = diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/FieldTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/FieldTest.java index 2a7572d..0c2f668 100644 --- a/src/jvm/src/test/java/solutions/bitbadger/documents/java/FieldTest.java +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/FieldTest.java @@ -5,6 +5,7 @@ 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.support.ForceDialect; import java.util.Collection; import java.util.List; @@ -22,7 +23,7 @@ final public class FieldTest { */ @AfterEach public void cleanUp() { - Configuration.setConnectionString(null); + ForceDialect.none(); } // ~~~ INSTANCE METHODS ~~~ @@ -71,7 +72,7 @@ final public class FieldTest { } @Test - @DisplayName("path generates for simple unqualified PostgreSQL field") + @DisplayName("path generates for simple unqualified field | PostgreSQL") public void pathPostgresSimpleUnqualified() { assertEquals("data->>'SomethingCool'", Field.greaterOrEqual("SomethingCool", 18).path(Dialect.POSTGRESQL, FieldFormat.SQL), @@ -79,7 +80,7 @@ final public class FieldTest { } @Test - @DisplayName("path generates for simple qualified PostgreSQL field") + @DisplayName("path generates for simple qualified field | PostgreSQL") public void pathPostgresSimpleQualified() { assertEquals("this.data->>'SomethingElse'", Field.less("SomethingElse", 9).withQualifier("this").path(Dialect.POSTGRESQL, FieldFormat.SQL), @@ -87,14 +88,14 @@ final public class FieldTest { } @Test - @DisplayName("path generates for nested unqualified PostgreSQL field") + @DisplayName("path generates for nested unqualified field | PostgreSQL") 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") + @DisplayName("path generates for nested qualified field | PostgreSQL") public void pathPostgresNestedQualified() { assertEquals("bird.data#>>'{Nest,Away}'", Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.POSTGRESQL, FieldFormat.SQL), @@ -102,14 +103,14 @@ final public class FieldTest { } @Test - @DisplayName("path generates for simple unqualified SQLite field") + @DisplayName("path generates for simple unqualified field | SQLite") 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") + @DisplayName("path generates for simple qualified field | SQLite") public void pathSQLiteSimpleQualified() { assertEquals("this.data->>'SomethingElse'", Field.less("SomethingElse", 9).withQualifier("this").path(Dialect.SQLITE, FieldFormat.SQL), @@ -117,14 +118,14 @@ final public class FieldTest { } @Test - @DisplayName("path generates for nested unqualified SQLite field") + @DisplayName("path generates for nested unqualified field | SQLite") 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") + @DisplayName("path generates for nested qualified field | SQLite") public void pathSQLiteNestedQualified() { assertEquals("bird.data->'Nest'->>'Away'", Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.SQLITE, FieldFormat.SQL), @@ -132,190 +133,196 @@ final public class FieldTest { } @Test - @DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)") - public void toWhereExistsNoQualPostgres() { - Configuration.setConnectionString(":postgresql:"); + @DisplayName("toWhere generates for exists w/o qualifier | PostgreSQL") + public void toWhereExistsNoQualPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for exists w/o qualifier | SQLite") + public void toWhereExistsNoQualSQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates for not-exists w/o qualifier | PostgreSQL") + public void toWhereNotExistsNoQualPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for not-exists w/o qualifier | SQLite") + public void toWhereNotExistsNoQualSQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates for BETWEEN w/o qualifier, numeric range | PostgreSQL") + public void toWhereBetweenNoQualNumericPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range | PostgreSQL") + public void toWhereBetweenNoQualAlphaPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for BETWEEN w/o qualifier | SQLite") + public void toWhereBetweenNoQualSQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates for BETWEEN w/ qualifier, numeric range | PostgreSQL") + public void toWhereBetweenQualNumericPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range | PostgreSQL") + public void toWhereBetweenQualAlphaPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for BETWEEN w/ qualifier | SQLite") + public void toWhereBetweenQualSQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates for IN/any, numeric values | PostgreSQL") + public void toWhereAnyNumericPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for IN/any, alphanumeric values | PostgreSQL") + public void toWhereAnyAlphaPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for IN/any | SQLite") + public void toWhereAnySQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates for inArray | PostgreSQL") + public void toWhereInArrayPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for inArray | SQLite") + public void toWhereInArraySQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates for others w/o qualifier | PostgreSQL") + public void toWhereOtherNoQualPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates for others w/o qualifier | SQLite") + public void toWhereOtherNoQualSQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates no-parameter w/ qualifier | PostgreSQL") + public void toWhereNoParamWithQualPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates no-parameter w/ qualifier | SQLite") + public void toWhereNoParamWithQualSQLite() throws DocumentException { + ForceDialect.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:"); + @DisplayName("toWhere generates parameter w/ qualifier | PostgreSQL") + public void toWhereParamWithQualPostgres() throws DocumentException { + ForceDialect.postgres(); 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:"); + @DisplayName("toWhere generates parameter w/ qualifier | SQLite") + public void toWhereParamWithQualSQLite() throws DocumentException { + ForceDialect.sqlite(); assertEquals("q.data->>'le_field' <= :it", Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(), "Field WHERE clause not generated correctly"); } + @Test + @DisplayName("toWhere fails when dialect is not set") + public void toWhereFailsNoDialect() { + assertThrows(DocumentException.class, () -> Field.equal("a", "oops").toWhere()); + } + // ~~~ STATIC TESTS ~~~ @Test @DisplayName("equal constructs a field w/o parameter name") public void equalCtor() { - Field field = Field.equal("Test", 14); + final Field field = Field.equal("Test", 14); assertEquals("Test", field.getName(), "Field name not filled correctly"); assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals(14, field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -326,7 +333,7 @@ final public class FieldTest { @Test @DisplayName("equal constructs a field w/ parameter name") public void equalParameterCtor() { - Field field = Field.equal("Test", 14, ":w"); + final Field field = Field.equal("Test", 14, ":w"); assertEquals("Test", field.getName(), "Field name not filled correctly"); assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals(14, field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -337,7 +344,7 @@ final public class FieldTest { @Test @DisplayName("greater constructs a field w/o parameter name") public void greaterCtor() { - Field field = Field.greater("Great", "night"); + final Field field = Field.greater("Great", "night"); assertEquals("Great", field.getName(), "Field name not filled correctly"); assertEquals(Op.GREATER, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("night", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -348,7 +355,7 @@ final public class FieldTest { @Test @DisplayName("greater constructs a field w/ parameter name") public void greaterParameterCtor() { - Field field = Field.greater("Great", "night", ":yeah"); + final Field field = Field.greater("Great", "night", ":yeah"); assertEquals("Great", field.getName(), "Field name not filled correctly"); assertEquals(Op.GREATER, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("night", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -359,7 +366,7 @@ final public class FieldTest { @Test @DisplayName("greaterOrEqual constructs a field w/o parameter name") public void greaterOrEqualCtor() { - Field field = Field.greaterOrEqual("Nice", 88L); + final Field field = Field.greaterOrEqual("Nice", 88L); assertEquals("Nice", field.getName(), "Field name not filled correctly"); assertEquals(Op.GREATER_OR_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); @@ -371,7 +378,7 @@ final public class FieldTest { @Test @DisplayName("greaterOrEqual constructs a field w/ parameter name") public void greaterOrEqualParameterCtor() { - Field field = Field.greaterOrEqual("Nice", 88L, ":nice"); + final Field field = Field.greaterOrEqual("Nice", 88L, ":nice"); assertEquals("Nice", field.getName(), "Field name not filled correctly"); assertEquals(Op.GREATER_OR_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); @@ -383,7 +390,7 @@ final public class FieldTest { @Test @DisplayName("less constructs a field w/o parameter name") public void lessCtor() { - Field field = Field.less("Lesser", "seven"); + final Field field = Field.less("Lesser", "seven"); assertEquals("Lesser", field.getName(), "Field name not filled correctly"); assertEquals(Op.LESS, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("seven", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -394,7 +401,7 @@ final public class FieldTest { @Test @DisplayName("less constructs a field w/ parameter name") public void lessParameterCtor() { - Field field = Field.less("Lesser", "seven", ":max"); + final Field field = Field.less("Lesser", "seven", ":max"); assertEquals("Lesser", field.getName(), "Field name not filled correctly"); assertEquals(Op.LESS, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("seven", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -405,7 +412,7 @@ final public class FieldTest { @Test @DisplayName("lessOrEqual constructs a field w/o parameter name") public void lessOrEqualCtor() { - Field field = Field.lessOrEqual("Nobody", "KNOWS"); + final Field field = Field.lessOrEqual("Nobody", "KNOWS"); assertEquals("Nobody", field.getName(), "Field name not filled correctly"); assertEquals(Op.LESS_OR_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); @@ -417,7 +424,7 @@ final public class FieldTest { @Test @DisplayName("lessOrEqual constructs a field w/ parameter name") public void lessOrEqualParameterCtor() { - Field field = Field.lessOrEqual("Nobody", "KNOWS", ":nope"); + final Field field = Field.lessOrEqual("Nobody", "KNOWS", ":nope"); assertEquals("Nobody", field.getName(), "Field name not filled correctly"); assertEquals(Op.LESS_OR_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); @@ -429,7 +436,7 @@ final public class FieldTest { @Test @DisplayName("notEqual constructs a field w/o parameter name") public void notEqualCtor() { - Field field = Field.notEqual("Park", "here"); + final Field field = Field.notEqual("Park", "here"); assertEquals("Park", field.getName(), "Field name not filled correctly"); assertEquals(Op.NOT_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("here", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -440,7 +447,7 @@ final public class FieldTest { @Test @DisplayName("notEqual constructs a field w/ parameter name") public void notEqualParameterCtor() { - Field field = Field.notEqual("Park", "here", ":now"); + final Field field = Field.notEqual("Park", "here", ":now"); assertEquals("Park", field.getName(), "Field name not filled correctly"); assertEquals(Op.NOT_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("here", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -451,7 +458,7 @@ final public class FieldTest { @Test @DisplayName("between constructs a field w/o parameter name") public void betweenCtor() { - Field> field = Field.between("Age", 18, 49); + final Field> field = Field.between("Age", 18, 49); assertEquals("Age", field.getName(), "Field name not filled correctly"); assertEquals(Op.BETWEEN, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals(18, field.getComparison().getValue().getFirst(), @@ -465,7 +472,7 @@ final public class FieldTest { @Test @DisplayName("between constructs a field w/ parameter name") public void betweenParameterCtor() { - Field> field = Field.between("Age", 18, 49, ":limit"); + final Field> field = Field.between("Age", 18, 49, ":limit"); assertEquals("Age", field.getName(), "Field name not filled correctly"); assertEquals(Op.BETWEEN, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals(18, field.getComparison().getValue().getFirst(), @@ -479,7 +486,7 @@ final public class FieldTest { @Test @DisplayName("any constructs a field w/o parameter name") public void anyCtor() { - Field> field = Field.any("Here", List.of(8, 16, 32)); + final Field> field = Field.any("Here", List.of(8, 16, 32)); assertEquals("Here", field.getName(), "Field name not filled correctly"); assertEquals(Op.IN, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals(List.of(8, 16, 32), field.getComparison().getValue(), @@ -491,7 +498,7 @@ final public class FieldTest { @Test @DisplayName("any constructs a field w/ parameter name") public void anyParameterCtor() { - Field> field = Field.any("Here", List.of(8, 16, 32), ":list"); + final Field> field = Field.any("Here", List.of(8, 16, 32), ":list"); assertEquals("Here", field.getName(), "Field name not filled correctly"); assertEquals(Op.IN, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals(List.of(8, 16, 32), field.getComparison().getValue(), @@ -503,7 +510,7 @@ final public class FieldTest { @Test @DisplayName("inArray constructs a field w/o parameter name") public void inArrayCtor() { - Field>> field = Field.inArray("ArrayField", "table", List.of("z")); + final Field>> field = Field.inArray("ArrayField", "table", List.of("z")); assertEquals("ArrayField", field.getName(), "Field name not filled correctly"); assertEquals(Op.IN_ARRAY, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("table", field.getComparison().getValue().getFirst(), @@ -517,7 +524,7 @@ final public class FieldTest { @Test @DisplayName("inArray constructs a field w/ parameter name") public void inArrayParameterCtor() { - Field>> field = Field.inArray("ArrayField", "table", List.of("z"), ":a"); + final Field>> field = Field.inArray("ArrayField", "table", List.of("z"), ":a"); assertEquals("ArrayField", field.getName(), "Field name not filled correctly"); assertEquals(Op.IN_ARRAY, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("table", field.getComparison().getValue().getFirst(), @@ -531,7 +538,7 @@ final public class FieldTest { @Test @DisplayName("exists constructs a field") public void existsCtor() { - Field field = Field.exists("Groovy"); + final Field field = Field.exists("Groovy"); assertEquals("Groovy", field.getName(), "Field name not filled correctly"); assertEquals(Op.EXISTS, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -542,7 +549,7 @@ final public class FieldTest { @Test @DisplayName("notExists constructs a field") public void notExistsCtor() { - Field field = Field.notExists("Groovy"); + final Field field = Field.notExists("Groovy"); assertEquals("Groovy", field.getName(), "Field name not filled correctly"); assertEquals(Op.NOT_EXISTS, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly"); @@ -553,7 +560,7 @@ final public class FieldTest { @Test @DisplayName("named constructs a field") public void namedCtor() { - Field field = Field.named("Tacos"); + final Field field = Field.named("Tacos"); assertEquals("Tacos", field.getName(), "Field name not filled correctly"); assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly"); assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly"); diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/CountQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/CountQueryTest.java index 1389ba9..02b916f 100644 --- a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/CountQueryTest.java +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/CountQueryTest.java @@ -18,7 +18,7 @@ import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; * Unit tests for the `Count` object */ @DisplayName("JVM | Java | Query | CountQuery") -public class CountQueryTest { +final public class CountQueryTest { /** * Clear the connection string (resets Dialect) @@ -37,7 +37,7 @@ public class CountQueryTest { @Test @DisplayName("byFields generates correctly | PostgreSQL") - public void byFieldsPostgres() { + public void byFieldsPostgres() throws DocumentException { ForceDialect.postgres(); assertEquals(String.format("SELECT COUNT(*) AS it FROM %s WHERE data->>'test' = :field0", TEST_TABLE), CountQuery.byFields(TEST_TABLE, List.of(Field.equal("test", "", ":field0"))), @@ -46,7 +46,7 @@ public class CountQueryTest { @Test @DisplayName("byFields generates correctly | SQLite") - public void byFieldsSQLite() { + public void byFieldsSQLite() throws DocumentException { ForceDialect.sqlite(); assertEquals(String.format("SELECT COUNT(*) AS it FROM %s WHERE data->>'test' = :field0", TEST_TABLE), CountQuery.byFields(TEST_TABLE, List.of(Field.equal("test", "", ":field0"))), diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DefinitionQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DefinitionQueryTest.java index f5e0cd2..3558285 100644 --- a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DefinitionQueryTest.java +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DefinitionQueryTest.java @@ -19,7 +19,7 @@ import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; * Unit tests for the `Definition` object */ @DisplayName("JVM | Java | Query | DefinitionQuery") -public class DefinitionQueryTest { +final public class DefinitionQueryTest { /** * Clear the connection string (resets Dialect) diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DeleteQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DeleteQueryTest.java new file mode 100644 index 0000000..4922f66 --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DeleteQueryTest.java @@ -0,0 +1,94 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.Field; +import solutions.bitbadger.documents.query.DeleteQuery; +import solutions.bitbadger.documents.support.ForceDialect; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; + +/** + * Unit tests for the `Delete` object + */ +@DisplayName("JVM | Java | Query | DeleteQuery") +final public class DeleteQueryTest { + + /** + * Clear the connection string (resets Dialect) + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("byId generates correctly | PostgreSQL") + public void byIdPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("DELETE FROM %s WHERE data->>'id' = :id", TEST_TABLE), DeleteQuery.byId(TEST_TABLE), + "Delete query not constructed correctly"); + } + + @Test + @DisplayName("byId generates correctly | SQLite") + public void byIdSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("DELETE FROM %s WHERE data->>'id' = :id", TEST_TABLE), DeleteQuery.byId(TEST_TABLE), + "Delete query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | PostgreSQL") + public void byFieldsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("DELETE FROM %s WHERE data->>'a' = :b", TEST_TABLE), + DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal("a", "", ":b"))), + "Delete query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | SQLite") + public void byFieldsSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("DELETE FROM %s WHERE data->>'a' = :b", TEST_TABLE), + DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal("a", "", ":b"))), + "Delete query not constructed correctly"); + } + + @Test + @DisplayName("byContains generates correctly | PostgreSQL") + public void byContainsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("DELETE FROM %s WHERE data @> :criteria", TEST_TABLE), + DeleteQuery.byContains(TEST_TABLE), "Delete query not constructed correctly"); + } + + @Test + @DisplayName("byContains fails | SQLite") + public void byContainsSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> DeleteQuery.byContains(TEST_TABLE)); + } + + @Test + @DisplayName("byJsonPath generates correctly | PostgreSQL") + public void byJsonPathPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("DELETE FROM %s WHERE jsonb_path_exists(data, :path::jsonpath)", TEST_TABLE), + DeleteQuery.byJsonPath(TEST_TABLE), "Delete query not constructed correctly"); + } + + @Test + @DisplayName("byJsonPath fails | SQLite") + public void byJsonPathSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> DeleteQuery.byJsonPath(TEST_TABLE)); + } +} diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DocumentQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DocumentQueryTest.java new file mode 100644 index 0000000..26307f5 --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/DocumentQueryTest.java @@ -0,0 +1,134 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.AutoId; +import solutions.bitbadger.documents.Configuration; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.query.DocumentQuery; +import solutions.bitbadger.documents.support.ForceDialect; + +import static org.junit.jupiter.api.Assertions.*; +import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; + +/** + * Unit tests for the `Document` object + */ +@DisplayName("JVM | Java | Query | DocumentQuery") +final public class DocumentQueryTest { + + /** + * Clear the connection string (resets Dialect) + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("insert generates no auto ID | PostgreSQL") + public void insertNoAutoPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("INSERT INTO %s VALUES (:data)", TEST_TABLE), DocumentQuery.insert(TEST_TABLE)); + } + + @Test + @DisplayName("insert generates no auto ID | SQLite") + public void insertNoAutoSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("INSERT INTO %s VALUES (:data)", TEST_TABLE), DocumentQuery.insert(TEST_TABLE)); + } + + @Test + @DisplayName("insert generates auto number | PostgreSQL") + public void insertAutoNumberPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("INSERT INTO %1$s VALUES (:data::jsonb || ('{\"id\":' " + + "|| (SELECT COALESCE(MAX((data->>'id')::numeric), 0) + 1 FROM %1$s) || '}')::jsonb)", + TEST_TABLE), + DocumentQuery.insert(TEST_TABLE, AutoId.NUMBER)); + } + + @Test + @DisplayName("insert generates auto number | SQLite") + public void insertAutoNumberSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("INSERT INTO %1$s VALUES (json_set(:data, '$.id', " + + "(SELECT coalesce(max(data->>'id'), 0) + 1 FROM %1$s)))", TEST_TABLE), + DocumentQuery.insert(TEST_TABLE, AutoId.NUMBER)); + } + + @Test + @DisplayName("insert generates auto UUID | PostgreSQL") + public void insertAutoUUIDPostgres() throws DocumentException { + ForceDialect.postgres(); + final String query = DocumentQuery.insert(TEST_TABLE, AutoId.UUID); + assertTrue(query.startsWith(String.format("INSERT INTO %s VALUES (:data::jsonb || '{\"id\":\"", TEST_TABLE)), + String.format("Query start not correct (actual: %s)", query)); + assertTrue(query.endsWith("\"}')"), "Query end not correct"); + } + + @Test + @DisplayName("insert generates auto UUID | SQLite") + public void insertAutoUUIDSQLite() throws DocumentException { + ForceDialect.sqlite(); + final String query = DocumentQuery.insert(TEST_TABLE, AutoId.UUID); + assertTrue(query.startsWith(String.format("INSERT INTO %s VALUES (json_set(:data, '$.id', '", TEST_TABLE)), + String.format("Query start not correct (actual: %s)", query)); + assertTrue(query.endsWith("'))"), "Query end not correct"); + } + + @Test + @DisplayName("insert generates auto random string | PostgreSQL") + public void insertAutoRandomPostgres() throws DocumentException { + try { + ForceDialect.postgres(); + Configuration.idStringLength = 8; + final String query = DocumentQuery.insert(TEST_TABLE, AutoId.RANDOM_STRING); + final String start = String.format("INSERT INTO %s VALUES (:data::jsonb || '{\"id\":\"", TEST_TABLE); + final String end = "\"}')"; + assertTrue(query.startsWith(start), String.format("Query start not correct (actual: %s)", query)); + assertTrue(query.endsWith(end), "Query end not correct"); + assertEquals(8, query.replace(start, "").replace(end, "").length(), "Random string length incorrect"); + } finally { + Configuration.idStringLength = 16; + } + } + + @Test + @DisplayName("insert generates auto random string | SQLite") + public void insertAutoRandomSQLite() throws DocumentException { + ForceDialect.sqlite(); + final String query = DocumentQuery.insert(TEST_TABLE, AutoId.RANDOM_STRING); + final String start = String.format("INSERT INTO %s VALUES (json_set(:data, '$.id', '", TEST_TABLE); + final String end = "'))"; + assertTrue(query.startsWith(start), String.format("Query start not correct (actual: %s)", query)); + assertTrue(query.endsWith(end), "Query end not correct"); + assertEquals(Configuration.idStringLength, query.replace(start, "").replace(end, "").length(), + "Random string length incorrect"); + } + + @Test + @DisplayName("insert fails when no dialect is set") + public void insertFailsUnknown() { + assertThrows(DocumentException.class, () -> DocumentQuery.insert(TEST_TABLE)); + } + + @Test + @DisplayName("save generates correctly") + public void save() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format( + "INSERT INTO %s VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data", + TEST_TABLE), + DocumentQuery.save(TEST_TABLE), "INSERT ON CONFLICT UPDATE statement not constructed correctly"); + } + + @Test + @DisplayName("update generates successfully") + public void update() { + assertEquals(String.format("UPDATE %s SET data = :data", TEST_TABLE), DocumentQuery.update(TEST_TABLE), + "Update query not constructed correctly"); + } +} diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/ExistsQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/ExistsQueryTest.java new file mode 100644 index 0000000..82a6c52 --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/ExistsQueryTest.java @@ -0,0 +1,97 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.Field; +import solutions.bitbadger.documents.query.ExistsQuery; +import solutions.bitbadger.documents.support.ForceDialect; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; + +/** + * Unit tests for the `Exists` object + */ +@DisplayName("JVM | Java | Query | ExistsQuery") +final public class ExistsQueryTest { + + /** + * Clear the connection string (resets Dialect) + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("byId generates correctly | PostgreSQL") + public void byIdPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("SELECT EXISTS (SELECT 1 FROM %s WHERE data->>'id' = :id) AS it", TEST_TABLE), + ExistsQuery.byId(TEST_TABLE), "Exists query not constructed correctly"); + } + + @Test + @DisplayName("byId generates correctly | SQLite") + public void byIdSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("SELECT EXISTS (SELECT 1 FROM %s WHERE data->>'id' = :id) AS it", TEST_TABLE), + ExistsQuery.byId(TEST_TABLE), "Exists query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | PostgreSQL") + public void byFieldsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format( + "SELECT EXISTS (SELECT 1 FROM %s WHERE (data->>'it')::numeric = :test) AS it", TEST_TABLE), + ExistsQuery.byFields(TEST_TABLE, List.of(Field.equal("it", 7, ":test"))), + "Exists query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | SQLite") + public void byFieldsSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("SELECT EXISTS (SELECT 1 FROM %s WHERE data->>'it' = :test) AS it", TEST_TABLE), + ExistsQuery.byFields(TEST_TABLE, List.of(Field.equal("it", 7, ":test"))), + "Exists query not constructed correctly"); + } + + @Test + @DisplayName("byContains generates correctly | PostgreSQL") + public void byContainsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("SELECT EXISTS (SELECT 1 FROM %s WHERE data @> :criteria) AS it", TEST_TABLE), + ExistsQuery.byContains(TEST_TABLE), "Exists query not constructed correctly"); + } + + @Test + @DisplayName("byContains fails | SQLite") + public void byContainsSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> ExistsQuery.byContains(TEST_TABLE)); + } + + @Test + @DisplayName("byJsonPath generates correctly | PostgreSQL") + public void byJsonPathPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format( + "SELECT EXISTS (SELECT 1 FROM %s WHERE jsonb_path_exists(data, :path::jsonpath)) AS it", + TEST_TABLE), + ExistsQuery.byJsonPath(TEST_TABLE), "Exists query not constructed correctly"); + } + + @Test + @DisplayName("byJsonPath fails | SQLite") + public void byJsonPathSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> ExistsQuery.byJsonPath(TEST_TABLE)); + } +} diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/FindQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/FindQueryTest.java new file mode 100644 index 0000000..bcc717e --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/FindQueryTest.java @@ -0,0 +1,102 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.Field; +import solutions.bitbadger.documents.query.FindQuery; +import solutions.bitbadger.documents.support.ForceDialect; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; + +/** + * Unit tests for the `Find` object + */ +@DisplayName("JVM | Java | Query | FindQuery") +final public class FindQueryTest { + + /** + * Clear the connection string (resets Dialect) + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("all generates correctly") + public void all() { + assertEquals(String.format("SELECT data FROM %s", TEST_TABLE), FindQuery.all(TEST_TABLE), + "Find query not constructed correctly"); + } + + @Test + @DisplayName("byId generates correctly | PostgreSQL") + public void byIdPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("SELECT data FROM %s WHERE data->>'id' = :id", TEST_TABLE), + FindQuery.byId(TEST_TABLE), "Find query not constructed correctly"); + } + + @Test + @DisplayName("byId generates correctly | SQLite") + public void byIdSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("SELECT data FROM %s WHERE data->>'id' = :id", TEST_TABLE), + FindQuery.byId(TEST_TABLE), "Find query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | PostgreSQL") + public void byFieldsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals( + String.format("SELECT data FROM %s WHERE data->>'a' = :b AND (data->>'c')::numeric < :d", TEST_TABLE), + FindQuery.byFields(TEST_TABLE, List.of(Field.equal("a", "", ":b"), Field.less("c", 14, ":d"))), + "Find query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | SQLite") + public void byFieldsSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("SELECT data FROM %s WHERE data->>'a' = :b AND data->>'c' < :d", TEST_TABLE), + FindQuery.byFields(TEST_TABLE, List.of(Field.equal("a", "", ":b"), Field.less("c", 14, ":d"))), + "Find query not constructed correctly"); + } + + @Test + @DisplayName("byContains generates correctly | PostgreSQL") + public void byContainsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("SELECT data FROM %s WHERE data @> :criteria", TEST_TABLE), + FindQuery.byContains(TEST_TABLE), "Find query not constructed correctly"); + } + + @Test + @DisplayName("byContains fails | SQLite") + public void byContainsSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> FindQuery.byContains(TEST_TABLE)); + } + + @Test + @DisplayName("byJsonPath generates correctly | PostgreSQL") + public void byJsonPathPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("SELECT data FROM %s WHERE jsonb_path_exists(data, :path::jsonpath)", TEST_TABLE), + FindQuery.byJsonPath(TEST_TABLE), "Find query not constructed correctly"); + } + + @Test + @DisplayName("byJsonPath fails | SQLite") + public void byJsonPathSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> FindQuery.byJsonPath(TEST_TABLE)); + } +} diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/PatchQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/PatchQueryTest.java new file mode 100644 index 0000000..56afbdc --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/PatchQueryTest.java @@ -0,0 +1,97 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.Field; +import solutions.bitbadger.documents.query.PatchQuery; +import solutions.bitbadger.documents.support.ForceDialect; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; + +/** + * Unit tests for the `Patch` object + */ +@DisplayName("JVM | Java | Query | PatchQuery") +final public class PatchQueryTest { + + /** + * Reset the dialect + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("byId generates correctly | PostgreSQL") + public void byIdPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data || :data WHERE data->>'id' = :id", TEST_TABLE), + PatchQuery.byId(TEST_TABLE), "Patch query not constructed correctly"); + } + + @Test + @DisplayName("byId generates correctly | SQLite") + public void byIdSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format( + "UPDATE %s SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id", TEST_TABLE), + PatchQuery.byId(TEST_TABLE), "Patch query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | PostgreSQL") + public void byFieldsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data || :data WHERE data->>'z' = :y", TEST_TABLE), + PatchQuery.byFields(TEST_TABLE, List.of(Field.equal("z", "", ":y"))), + "Patch query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | SQLite") + public void byFieldsSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format( + "UPDATE %s SET data = json_patch(data, json(:data)) WHERE data->>'z' = :y", TEST_TABLE), + PatchQuery.byFields(TEST_TABLE, List.of(Field.equal("z", "", ":y"))), + "Patch query not constructed correctly"); + } + + @Test + @DisplayName("byContains generates correctly | PostgreSQL") + public void byContainsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data || :data WHERE data @> :criteria", TEST_TABLE), + PatchQuery.byContains(TEST_TABLE), "Patch query not constructed correctly"); + } + + @Test + @DisplayName("byContains fails | SQLite") + public void byContainsSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> PatchQuery.byContains(TEST_TABLE)); + } + + @Test + @DisplayName("byJsonPath generates correctly | PostgreSQL") + public void byJsonPathPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)", + TEST_TABLE), + PatchQuery.byJsonPath(TEST_TABLE), "Patch query not constructed correctly"); + } + + @Test + @DisplayName("byJsonPath fails | SQLite") + public void byJsonPathSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> PatchQuery.byJsonPath(TEST_TABLE)); + } +} diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/QueryUtilsTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/QueryUtilsTest.java new file mode 100644 index 0000000..f815db0 --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/QueryUtilsTest.java @@ -0,0 +1,166 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.Dialect; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.Field; +import solutions.bitbadger.documents.FieldMatch; +import solutions.bitbadger.documents.query.QueryUtils; +import solutions.bitbadger.documents.support.ForceDialect; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Unit tests for the package-level query functions, presented as `QueryUtils` for Java-compatible use + */ +@DisplayName("JVM | Java | Query | QueryUtils") +final public class QueryUtilsTest { + + /** + * Clear the connection string (resets Dialect) + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("statementWhere generates correctly") + public void statementWhere() { + assertEquals("x WHERE y", QueryUtils.statementWhere("x", "y"), "Statements not combined correctly"); + } + + @Test + @DisplayName("byId generates a numeric ID query | PostgreSQL") + public void byIdNumericPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals("test WHERE (data->>'id')::numeric = :id", QueryUtils.byId("test", 9)); + } + + @Test + @DisplayName("byId generates an alphanumeric ID query | PostgreSQL") + public void byIdAlphaPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals("unit WHERE data->>'id' = :id", QueryUtils.byId("unit", "18")); + } + + @Test + @DisplayName("byId generates ID query | SQLite") + public void byIdSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals("yo WHERE data->>'id' = :id", QueryUtils.byId("yo", 27)); + } + + @Test + @DisplayName("byFields generates default field query | PostgreSQL") + public void byFieldsMultipleDefaultPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals("this WHERE data->>'a' = :the_a AND (data->>'b')::numeric = :b_value", + QueryUtils.byFields("this", List.of(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")))); + } + + @Test + @DisplayName("byFields generates default field query | SQLite") + public void byFieldsMultipleDefaultSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals("this WHERE data->>'a' = :the_a AND data->>'b' = :b_value", + QueryUtils.byFields("this", List.of(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")))); + } + + @Test + @DisplayName("byFields generates ANY field query | PostgreSQL") + public void byFieldsMultipleAnyPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals("that WHERE data->>'a' = :the_a OR (data->>'b')::numeric = :b_value", + QueryUtils.byFields("that", List.of(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")), + FieldMatch.ANY)); + } + + @Test + @DisplayName("byFields generates ANY field query | SQLite") + public void byFieldsMultipleAnySQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals("that WHERE data->>'a' = :the_a OR data->>'b' = :b_value", + QueryUtils.byFields("that", List.of(Field.equal("a", "", ":the_a"), Field.equal("b", 0, ":b_value")), + FieldMatch.ANY)); + } + + @Test + @DisplayName("orderBy generates for no fields") + public void orderByNone() throws DocumentException { + assertEquals("", QueryUtils.orderBy(List.of(), Dialect.POSTGRESQL), + "ORDER BY should have been blank (PostgreSQL)"); + assertEquals("", QueryUtils.orderBy(List.of(), Dialect.SQLITE), "ORDER BY should have been blank (SQLite)"); + } + + @Test + @DisplayName("orderBy generates single, no direction | PostgreSQL") + public void orderBySinglePostgres() throws DocumentException { + assertEquals(" ORDER BY data->>'TestField'", + QueryUtils.orderBy(List.of(Field.named("TestField")), Dialect.POSTGRESQL), + "ORDER BY not constructed correctly"); + } + + @Test + @DisplayName("orderBy generates single, no direction | SQLite") + public void orderBySingleSQLite() throws DocumentException { + assertEquals(" ORDER BY data->>'TestField'", + QueryUtils.orderBy(List.of(Field.named("TestField")), Dialect.SQLITE), + "ORDER BY not constructed correctly"); + } + + @Test + @DisplayName("orderBy generates multiple with direction | PostgreSQL") + public void orderByMultiplePostgres() throws DocumentException { + assertEquals(" ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC", + QueryUtils.orderBy(List.of( + 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 | SQLite") + public void orderByMultipleSQLite() throws DocumentException { + assertEquals(" ORDER BY data->'Nested'->'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC", + QueryUtils.orderBy(List.of( + 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") + public void orderByNumericPostgres() throws DocumentException { + assertEquals(" ORDER BY (data->>'Test')::numeric", + QueryUtils.orderBy(List.of(Field.named("n:Test")), Dialect.POSTGRESQL), + "ORDER BY not constructed correctly"); + } + + @Test + @DisplayName("orderBy generates numeric ordering | SQLite") + public void orderByNumericSQLite() throws DocumentException { + assertEquals(" ORDER BY data->>'Test'", QueryUtils.orderBy(List.of(Field.named("n:Test")), Dialect.SQLITE), + "ORDER BY not constructed correctly"); + } + + @Test + @DisplayName("orderBy generates case-insensitive ordering | PostgreSQL") + public void orderByCIPostgres() throws DocumentException { + assertEquals(" ORDER BY LOWER(data#>>'{Test,Field}') DESC NULLS FIRST", + QueryUtils.orderBy(List.of(Field.named("i:Test.Field DESC NULLS FIRST")), Dialect.POSTGRESQL), + "ORDER BY not constructed correctly"); + } + + @Test + @DisplayName("orderBy generates case-insensitive ordering | SQLite") + public void orderByCISQLite() throws DocumentException { + assertEquals(" ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST", + QueryUtils.orderBy(List.of(Field.named("i:Test.Field ASC NULLS LAST")), Dialect.SQLITE), + "ORDER BY not constructed correctly"); + } +} diff --git a/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/RemoveFieldsQueryTest.java b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/RemoveFieldsQueryTest.java new file mode 100644 index 0000000..027352e --- /dev/null +++ b/src/jvm/src/test/java/solutions/bitbadger/documents/java/query/RemoveFieldsQueryTest.java @@ -0,0 +1,110 @@ +package solutions.bitbadger.documents.java.query; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.Field; +import solutions.bitbadger.documents.Parameter; +import solutions.bitbadger.documents.ParameterType; +import solutions.bitbadger.documents.query.RemoveFieldsQuery; +import solutions.bitbadger.documents.support.ForceDialect; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE; + +/** + * Unit tests for the `RemoveFields` object + */ +@DisplayName("JVM | Java | Query | RemoveFieldsQuery") +final public class RemoveFieldsQueryTest { + + /** + * Reset the dialect + */ + @AfterEach + public void cleanUp() { + ForceDialect.none(); + } + + @Test + @DisplayName("byId generates correctly | PostgreSQL") + public void byIdPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data - :name::text[] WHERE data->>'id' = :id", TEST_TABLE), + RemoveFieldsQuery.byId(TEST_TABLE, List.of(new Parameter<>(":name", ParameterType.STRING, "{a,z}"))), + "Remove Fields query not constructed correctly"); + } + + @Test + @DisplayName("byId generates correctly | SQLite") + public void byIdSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("UPDATE %s SET data = json_remove(data, :name0, :name1) WHERE data->>'id' = :id", + TEST_TABLE), + RemoveFieldsQuery.byId(TEST_TABLE, List.of(new Parameter<>(":name0", ParameterType.STRING, "a"), + new Parameter<>(":name1", ParameterType.STRING, "z"))), + "Remove Field query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | PostgreSQL") + public void byFieldsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data - :name::text[] WHERE data->>'f' > :g", TEST_TABLE), + RemoveFieldsQuery.byFields(TEST_TABLE, List.of(new Parameter<>(":name", ParameterType.STRING, "{b,c}")), + List.of(Field.greater("f", "", ":g"))), + "Remove Field query not constructed correctly"); + } + + @Test + @DisplayName("byFields generates correctly | SQLite") + public void byFieldsSQLite() throws DocumentException { + ForceDialect.sqlite(); + assertEquals(String.format("UPDATE %s SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g", + TEST_TABLE), + RemoveFieldsQuery.byFields(TEST_TABLE, List.of(new Parameter<>(":name0", ParameterType.STRING, "b"), + new Parameter<>(":name1", ParameterType.STRING, "c")), + List.of(Field.greater("f", "", ":g"))), + "Remove Field query not constructed correctly"); + } + + @Test + @DisplayName("byContains generates correctly | PostgreSQL") + public void byContainsPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format("UPDATE %s SET data = data - :name::text[] WHERE data @> :criteria", TEST_TABLE), + RemoveFieldsQuery.byContains(TEST_TABLE, + List.of(new Parameter<>(":name", ParameterType.STRING, "{m,n}"))), + "Remove Field query not constructed correctly"); + } + + @Test + @DisplayName("byContains fails | SQLite") + public void byContainsSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> RemoveFieldsQuery.byContains(TEST_TABLE, List.of())); + } + + @Test + @DisplayName("byJsonPath generates correctly | PostgreSQL") + public void byJsonPathPostgres() throws DocumentException { + ForceDialect.postgres(); + assertEquals(String.format( + "UPDATE %s SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)", + TEST_TABLE), + RemoveFieldsQuery.byJsonPath(TEST_TABLE, + List.of(new Parameter<>(":name", ParameterType.STRING, "{o,p}"))), + "Remove Field query not constructed correctly"); + } + + @Test + @DisplayName("byJsonPath fails | SQLite") + public void byJsonPathSQLite() { + ForceDialect.sqlite(); + assertThrows(DocumentException.class, () -> RemoveFieldsQuery.byJsonPath(TEST_TABLE, List.of())); + } +} diff --git a/src/jvm/src/test/kotlin/query/DeleteQueryTest.kt b/src/jvm/src/test/kotlin/query/DeleteQueryTest.kt index 330b816..cc56578 100644 --- a/src/jvm/src/test/kotlin/query/DeleteQueryTest.kt +++ b/src/jvm/src/test/kotlin/query/DeleteQueryTest.kt @@ -4,10 +4,10 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import solutions.bitbadger.documents.Configuration -import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.Field +import solutions.bitbadger.documents.support.ForceDialect +import solutions.bitbadger.documents.support.TEST_TABLE import kotlin.test.assertEquals /** @@ -16,87 +16,89 @@ import kotlin.test.assertEquals @DisplayName("JVM | Kotlin | Query | DeleteQuery") class DeleteQueryTest { - /** Test table name */ - private val tbl = "test_table" - /** * Clear the connection string (resets Dialect) */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test - @DisplayName("byId generates correctly (PostgreSQL)") + @DisplayName("byId generates correctly | PostgreSQL") fun byIdPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "DELETE FROM $tbl WHERE data->>'id' = :id", - DeleteQuery.byId(tbl), "Delete query not constructed correctly" + "DELETE FROM $TEST_TABLE WHERE data->>'id' = :id", + DeleteQuery.byId(TEST_TABLE), "Delete query not constructed correctly" ) } @Test - @DisplayName("byId generates correctly (SQLite)") + @DisplayName("byId generates correctly | SQLite") fun byIdSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "DELETE FROM $tbl WHERE data->>'id' = :id", - DeleteQuery.byId(tbl), "Delete query not constructed correctly" + "DELETE FROM $TEST_TABLE WHERE data->>'id' = :id", + DeleteQuery.byId(TEST_TABLE), "Delete query not constructed correctly" ) } @Test - @DisplayName("byFields generates correctly (PostgreSQL)") + @DisplayName("byFields generates correctly | PostgreSQL") fun byFieldsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "DELETE FROM $tbl WHERE data->>'a' = :b", DeleteQuery.byFields(tbl, listOf(Field.equal("a", "", ":b"))), + "DELETE FROM $TEST_TABLE WHERE data->>'a' = :b", + DeleteQuery.byFields(TEST_TABLE, listOf(Field.equal("a", "", ":b"))), "Delete query not constructed correctly" ) } @Test - @DisplayName("byFields generates correctly (SQLite)") + @DisplayName("byFields generates correctly | SQLite") fun byFieldsSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "DELETE FROM $tbl WHERE data->>'a' = :b", DeleteQuery.byFields(tbl, listOf(Field.equal("a", "", ":b"))), + "DELETE FROM $TEST_TABLE WHERE data->>'a' = :b", + DeleteQuery.byFields(TEST_TABLE, listOf(Field.equal("a", "", ":b"))), "Delete query not constructed correctly" ) } @Test - @DisplayName("byContains generates correctly (PostgreSQL)") + @DisplayName("byContains generates correctly | PostgreSQL") fun byContainsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "DELETE FROM $tbl WHERE data @> :criteria", DeleteQuery.byContains(tbl), "Delete query not constructed correctly" - ) - } - - @Test - @DisplayName("byContains fails (SQLite)") - fun byContainsSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { DeleteQuery.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)", DeleteQuery.byJsonPath(tbl), + "DELETE FROM $TEST_TABLE WHERE data @> :criteria", + DeleteQuery.byContains(TEST_TABLE), "Delete query not constructed correctly" ) } @Test - @DisplayName("byJsonPath fails (SQLite)") + @DisplayName("byContains fails | SQLite") + fun byContainsSQLite() { + ForceDialect.sqlite() + assertThrows { DeleteQuery.byContains(TEST_TABLE) } + } + + @Test + @DisplayName("byJsonPath generates correctly | PostgreSQL") + fun byJsonPathPostgres() { + ForceDialect.postgres() + assertEquals( + "DELETE FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)", + DeleteQuery.byJsonPath(TEST_TABLE), + "Delete query not constructed correctly" + ) + } + + @Test + @DisplayName("byJsonPath fails | SQLite") fun byJsonPathSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { DeleteQuery.byJsonPath(tbl) } + ForceDialect.sqlite() + assertThrows { DeleteQuery.byJsonPath(TEST_TABLE) } } } diff --git a/src/jvm/src/test/kotlin/query/DocumentQueryTest.kt b/src/jvm/src/test/kotlin/query/DocumentQueryTest.kt index bb6d5bc..e57340e 100644 --- a/src/jvm/src/test/kotlin/query/DocumentQueryTest.kt +++ b/src/jvm/src/test/kotlin/query/DocumentQueryTest.kt @@ -6,8 +6,9 @@ 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 solutions.bitbadger.documents.support.ForceDialect +import solutions.bitbadger.documents.support.TEST_TABLE import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -17,92 +18,90 @@ import kotlin.test.assertTrue @DisplayName("JVM | Kotlin | Query | DocumentQuery") class DocumentQueryTest { - /** Test table name */ - private val tbl = "test_table" - /** * Clear the connection string (resets Dialect) */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test - @DisplayName("insert generates no auto ID (PostgreSQL)") + @DisplayName("insert generates no auto ID | PostgreSQL") fun insertNoAutoPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL - assertEquals("INSERT INTO $tbl VALUES (:data)", DocumentQuery.insert(tbl)) + ForceDialect.postgres() + assertEquals("INSERT INTO $TEST_TABLE VALUES (:data)", DocumentQuery.insert(TEST_TABLE)) } @Test - @DisplayName("insert generates no auto ID (SQLite)") + @DisplayName("insert generates no auto ID | SQLite") fun insertNoAutoSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertEquals("INSERT INTO $tbl VALUES (:data)", DocumentQuery.insert(tbl)) + ForceDialect.sqlite() + assertEquals("INSERT INTO $TEST_TABLE VALUES (:data)", DocumentQuery.insert(TEST_TABLE)) } @Test - @DisplayName("insert generates auto number (PostgreSQL)") + @DisplayName("insert generates auto number | PostgreSQL") fun insertAutoNumberPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "INSERT INTO $tbl VALUES (:data::jsonb || ('{\"id\":' " + - "|| (SELECT COALESCE(MAX((data->>'id')::numeric), 0) + 1 FROM $tbl) || '}')::jsonb)", - DocumentQuery.insert(tbl, AutoId.NUMBER) + "INSERT INTO $TEST_TABLE VALUES (:data::jsonb || ('{\"id\":' " + + "|| (SELECT COALESCE(MAX((data->>'id')::numeric), 0) + 1 FROM $TEST_TABLE) || '}')::jsonb)", + DocumentQuery.insert(TEST_TABLE, AutoId.NUMBER) ) } @Test - @DisplayName("insert generates auto number (SQLite)") + @DisplayName("insert generates auto number | SQLite") fun insertAutoNumberSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "INSERT INTO $tbl VALUES (json_set(:data, '$.id', " + - "(SELECT coalesce(max(data->>'id'), 0) + 1 FROM $tbl)))", - DocumentQuery.insert(tbl, AutoId.NUMBER) + "INSERT INTO $TEST_TABLE VALUES (json_set(:data, '$.id', " + + "(SELECT coalesce(max(data->>'id'), 0) + 1 FROM $TEST_TABLE)))", + DocumentQuery.insert(TEST_TABLE, AutoId.NUMBER) ) } @Test - @DisplayName("insert generates auto UUID (PostgreSQL)") + @DisplayName("insert generates auto UUID | PostgreSQL") fun insertAutoUUIDPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL - val query = DocumentQuery.insert(tbl, AutoId.UUID) + ForceDialect.postgres() + val query = DocumentQuery.insert(TEST_TABLE, AutoId.UUID) assertTrue( - query.startsWith("INSERT INTO $tbl VALUES (:data::jsonb || '{\"id\":\""), + query.startsWith("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\""), "Query start not correct (actual: $query)" ) assertTrue(query.endsWith("\"}')"), "Query end not correct") } @Test - @DisplayName("insert generates auto UUID (SQLite)") + @DisplayName("insert generates auto UUID | SQLite") fun insertAutoUUIDSQLite() { - Configuration.dialectValue = Dialect.SQLITE - val query = DocumentQuery.insert(tbl, AutoId.UUID) + ForceDialect.sqlite() + val query = DocumentQuery.insert(TEST_TABLE, AutoId.UUID) assertTrue( - query.startsWith("INSERT INTO $tbl VALUES (json_set(:data, '$.id', '"), + query.startsWith("INSERT INTO $TEST_TABLE 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)") + @DisplayName("insert generates auto random string | PostgreSQL") fun insertAutoRandomPostgres() { try { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() Configuration.idStringLength = 8 - val query = DocumentQuery.insert(tbl, AutoId.RANDOM_STRING) + val query = DocumentQuery.insert(TEST_TABLE, AutoId.RANDOM_STRING) assertTrue( - query.startsWith("INSERT INTO $tbl VALUES (:data::jsonb || '{\"id\":\""), + query.startsWith("INSERT INTO $TEST_TABLE 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, + query.replace("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\"", "") + .replace("\"}')", "").length, "Random string length incorrect" ) } finally { @@ -111,18 +110,18 @@ class DocumentQueryTest { } @Test - @DisplayName("insert generates auto random string (SQLite)") + @DisplayName("insert generates auto random string | SQLite") fun insertAutoRandomSQLite() { - Configuration.dialectValue = Dialect.SQLITE - val query = DocumentQuery.insert(tbl, AutoId.RANDOM_STRING) + ForceDialect.sqlite() + val query = DocumentQuery.insert(TEST_TABLE, AutoId.RANDOM_STRING) assertTrue( - query.startsWith("INSERT INTO $tbl VALUES (json_set(:data, '$.id', '"), + query.startsWith("INSERT INTO $TEST_TABLE 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, + query.replace("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '$.id', '", "").replace("'))", "").length, "Random string length incorrect" ) } @@ -130,21 +129,25 @@ class DocumentQueryTest { @Test @DisplayName("insert fails when no dialect is set") fun insertFailsUnknown() { - assertThrows { DocumentQuery.insert(tbl) } + assertThrows { DocumentQuery.insert(TEST_TABLE) } } @Test @DisplayName("save generates correctly") fun save() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "INSERT INTO $tbl VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data", - DocumentQuery.save(tbl), "INSERT ON CONFLICT UPDATE statement not constructed correctly" + "INSERT INTO $TEST_TABLE VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data", + DocumentQuery.save(TEST_TABLE), "INSERT ON CONFLICT UPDATE statement not constructed correctly" ) } @Test @DisplayName("update generates successfully") fun update() = - assertEquals("UPDATE $tbl SET data = :data", DocumentQuery.update(tbl), "Update query not constructed correctly") + assertEquals( + "UPDATE $TEST_TABLE SET data = :data", + DocumentQuery.update(TEST_TABLE), + "Update query not constructed correctly" + ) } diff --git a/src/jvm/src/test/kotlin/query/ExistsQueryTest.kt b/src/jvm/src/test/kotlin/query/ExistsQueryTest.kt index d9d09e2..991a036 100644 --- a/src/jvm/src/test/kotlin/query/ExistsQueryTest.kt +++ b/src/jvm/src/test/kotlin/query/ExistsQueryTest.kt @@ -8,98 +8,98 @@ import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.Field +import solutions.bitbadger.documents.support.ForceDialect +import solutions.bitbadger.documents.support.TEST_TABLE import kotlin.test.assertEquals /** * Unit tests for the `Exists` object */ -@DisplayName("Kotlin | Common | Query: Exists") +@DisplayName("JVM | Kotlin | Query | ExistsQuery") class ExistsQueryTest { - /** Test table name */ - private val tbl = "test_table" - /** * Clear the connection string (resets Dialect) */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test - @DisplayName("byId generates correctly (PostgreSQL)") + @DisplayName("byId generates correctly | PostgreSQL") fun byIdPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "SELECT EXISTS (SELECT 1 FROM $tbl WHERE data->>'id' = :id) AS it", - ExistsQuery.byId(tbl), "Exists query not constructed correctly" + "SELECT EXISTS (SELECT 1 FROM $TEST_TABLE WHERE data->>'id' = :id) AS it", + ExistsQuery.byId(TEST_TABLE), "Exists query not constructed correctly" ) } @Test - @DisplayName("byId generates correctly (SQLite)") + @DisplayName("byId generates correctly | SQLite") fun byIdSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "SELECT EXISTS (SELECT 1 FROM $tbl WHERE data->>'id' = :id) AS it", - ExistsQuery.byId(tbl), "Exists query not constructed correctly" + "SELECT EXISTS (SELECT 1 FROM $TEST_TABLE WHERE data->>'id' = :id) AS it", + ExistsQuery.byId(TEST_TABLE), "Exists query not constructed correctly" ) } @Test - @DisplayName("byFields generates correctly (PostgreSQL)") + @DisplayName("byFields generates correctly | PostgreSQL") fun byFieldsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "SELECT EXISTS (SELECT 1 FROM $tbl WHERE (data->>'it')::numeric = :test) AS it", - ExistsQuery.byFields(tbl, listOf(Field.equal("it", 7, ":test"))), + "SELECT EXISTS (SELECT 1 FROM $TEST_TABLE WHERE (data->>'it')::numeric = :test) AS it", + ExistsQuery.byFields(TEST_TABLE, listOf(Field.equal("it", 7, ":test"))), "Exists query not constructed correctly" ) } @Test - @DisplayName("byFields generates correctly (SQLite)") + @DisplayName("byFields generates correctly | SQLite") fun byFieldsSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "SELECT EXISTS (SELECT 1 FROM $tbl WHERE data->>'it' = :test) AS it", - ExistsQuery.byFields(tbl, listOf(Field.equal("it", 7, ":test"))), + "SELECT EXISTS (SELECT 1 FROM $TEST_TABLE WHERE data->>'it' = :test) AS it", + ExistsQuery.byFields(TEST_TABLE, listOf(Field.equal("it", 7, ":test"))), "Exists query not constructed correctly" ) } @Test - @DisplayName("byContains generates correctly (PostgreSQL)") + @DisplayName("byContains generates correctly | PostgreSQL") fun byContainsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "SELECT EXISTS (SELECT 1 FROM $tbl WHERE data @> :criteria) AS it", ExistsQuery.byContains(tbl), + "SELECT EXISTS (SELECT 1 FROM $TEST_TABLE WHERE data @> :criteria) AS it", + ExistsQuery.byContains(TEST_TABLE), "Exists query not constructed correctly" ) } @Test - @DisplayName("byContains fails (SQLite)") + @DisplayName("byContains fails | SQLite") fun byContainsSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { ExistsQuery.byContains(tbl) } + ForceDialect.sqlite() + assertThrows { ExistsQuery.byContains(TEST_TABLE) } } @Test - @DisplayName("byJsonPath generates correctly (PostgreSQL)") + @DisplayName("byJsonPath generates correctly | PostgreSQL") fun byJsonPathPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "SELECT EXISTS (SELECT 1 FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)) AS it", - ExistsQuery.byJsonPath(tbl), "Exists query not constructed correctly" + "SELECT EXISTS (SELECT 1 FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)) AS it", + ExistsQuery.byJsonPath(TEST_TABLE), "Exists query not constructed correctly" ) } @Test - @DisplayName("byJsonPath fails (SQLite)") + @DisplayName("byJsonPath fails | SQLite") fun byJsonPathSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { ExistsQuery.byJsonPath(tbl) } + ForceDialect.sqlite() + assertThrows { ExistsQuery.byJsonPath(TEST_TABLE) } } } diff --git a/src/jvm/src/test/kotlin/query/FindQueryTest.kt b/src/jvm/src/test/kotlin/query/FindQueryTest.kt index faeb505..e458bf2 100644 --- a/src/jvm/src/test/kotlin/query/FindQueryTest.kt +++ b/src/jvm/src/test/kotlin/query/FindQueryTest.kt @@ -4,10 +4,9 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import solutions.bitbadger.documents.Configuration -import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.Field +import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.TEST_TABLE import kotlin.test.assertEquals @@ -22,7 +21,7 @@ class FindQueryTest { */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test @@ -31,9 +30,9 @@ class FindQueryTest { assertEquals("SELECT data FROM $TEST_TABLE", FindQuery.all(TEST_TABLE), "Find query not constructed correctly") @Test - @DisplayName("byId generates correctly (PostgreSQL)") + @DisplayName("byId generates correctly | PostgreSQL") fun byIdPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( "SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id", FindQuery.byId(TEST_TABLE), "Find query not constructed correctly" @@ -41,9 +40,9 @@ class FindQueryTest { } @Test - @DisplayName("byId generates correctly (SQLite)") + @DisplayName("byId generates correctly | SQLite") fun byIdSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( "SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id", FindQuery.byId(TEST_TABLE), "Find query not constructed correctly" @@ -51,9 +50,9 @@ class FindQueryTest { } @Test - @DisplayName("byFields generates correctly (PostgreSQL)") + @DisplayName("byFields generates correctly | PostgreSQL") fun byFieldsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( "SELECT data FROM $TEST_TABLE WHERE data->>'a' = :b AND (data->>'c')::numeric < :d", FindQuery.byFields(TEST_TABLE, listOf(Field.equal("a", "", ":b"), Field.less("c", 14, ":d"))), @@ -62,9 +61,9 @@ class FindQueryTest { } @Test - @DisplayName("byFields generates correctly (SQLite)") + @DisplayName("byFields generates correctly | SQLite") fun byFieldsSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( "SELECT data FROM $TEST_TABLE WHERE data->>'a' = :b AND data->>'c' < :d", FindQuery.byFields(TEST_TABLE, listOf(Field.equal("a", "", ":b"), Field.less("c", 14, ":d"))), @@ -73,9 +72,9 @@ class FindQueryTest { } @Test - @DisplayName("byContains generates correctly (PostgreSQL)") + @DisplayName("byContains generates correctly | PostgreSQL") fun byContainsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( "SELECT data FROM $TEST_TABLE WHERE data @> :criteria", FindQuery.byContains(TEST_TABLE), "Find query not constructed correctly" @@ -83,16 +82,16 @@ class FindQueryTest { } @Test - @DisplayName("byContains fails (SQLite)") + @DisplayName("byContains fails | SQLite") fun byContainsSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertThrows { FindQuery.byContains(TEST_TABLE) } } @Test - @DisplayName("byJsonPath generates correctly (PostgreSQL)") + @DisplayName("byJsonPath generates correctly | PostgreSQL") fun byJsonPathPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( "SELECT data FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)", FindQuery.byJsonPath(TEST_TABLE), @@ -101,9 +100,9 @@ class FindQueryTest { } @Test - @DisplayName("byJsonPath fails (SQLite)") + @DisplayName("byJsonPath fails | SQLite") fun byJsonPathSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertThrows { FindQuery.byJsonPath(TEST_TABLE) } } } diff --git a/src/jvm/src/test/kotlin/query/PatchQueryTest.kt b/src/jvm/src/test/kotlin/query/PatchQueryTest.kt index 0afcdf8..dbb4169 100644 --- a/src/jvm/src/test/kotlin/query/PatchQueryTest.kt +++ b/src/jvm/src/test/kotlin/query/PatchQueryTest.kt @@ -4,10 +4,10 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import solutions.bitbadger.documents.Configuration -import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.Field +import solutions.bitbadger.documents.support.ForceDialect +import solutions.bitbadger.documents.support.TEST_TABLE import kotlin.test.assertEquals /** @@ -16,90 +16,87 @@ import kotlin.test.assertEquals @DisplayName("JVM | Kotlin | Query | PatchQuery") class PatchQueryTest { - /** Test table name */ - private val tbl = "test_table" - /** * Reset the dialect */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test - @DisplayName("byId generates correctly (PostgreSQL)") + @DisplayName("byId generates correctly | PostgreSQL") fun byIdPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data || :data WHERE data->>'id' = :id", - PatchQuery.byId(tbl), "Patch query not constructed correctly" + "UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'id' = :id", + PatchQuery.byId(TEST_TABLE), "Patch query not constructed correctly" ) } @Test - @DisplayName("byId generates correctly (SQLite)") + @DisplayName("byId generates correctly | SQLite") fun byIdSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "UPDATE $tbl SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id", - PatchQuery.byId(tbl), "Patch query not constructed correctly" + "UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id", + PatchQuery.byId(TEST_TABLE), "Patch query not constructed correctly" ) } @Test - @DisplayName("byFields generates correctly (PostgreSQL)") + @DisplayName("byFields generates correctly | PostgreSQL") fun byFieldsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data || :data WHERE data->>'z' = :y", - PatchQuery.byFields(tbl, listOf(Field.equal("z", "", ":y"))), + "UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'z' = :y", + PatchQuery.byFields(TEST_TABLE, listOf(Field.equal("z", "", ":y"))), "Patch query not constructed correctly" ) } @Test - @DisplayName("byFields generates correctly (SQLite)") + @DisplayName("byFields generates correctly | SQLite") fun byFieldsSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "UPDATE $tbl SET data = json_patch(data, json(:data)) WHERE data->>'z' = :y", - PatchQuery.byFields(tbl, listOf(Field.equal("z", "", ":y"))), + "UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'z' = :y", + PatchQuery.byFields(TEST_TABLE, listOf(Field.equal("z", "", ":y"))), "Patch query not constructed correctly" ) } @Test - @DisplayName("byContains generates correctly (PostgreSQL)") + @DisplayName("byContains generates correctly | PostgreSQL") fun byContainsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data || :data WHERE data @> :criteria", PatchQuery.byContains(tbl), + "UPDATE $TEST_TABLE SET data = data || :data WHERE data @> :criteria", PatchQuery.byContains(TEST_TABLE), "Patch query not constructed correctly" ) } @Test - @DisplayName("byContains fails (SQLite)") + @DisplayName("byContains fails | SQLite") fun byContainsSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { PatchQuery.byContains(tbl) } + ForceDialect.sqlite() + assertThrows { PatchQuery.byContains(TEST_TABLE) } } @Test - @DisplayName("byJsonPath generates correctly (PostgreSQL)") + @DisplayName("byJsonPath generates correctly | PostgreSQL") fun byJsonPathPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)", - PatchQuery.byJsonPath(tbl), "Patch query not constructed correctly" + "UPDATE $TEST_TABLE SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)", + PatchQuery.byJsonPath(TEST_TABLE), "Patch query not constructed correctly" ) } @Test - @DisplayName("byJsonPath fails (SQLite)") + @DisplayName("byJsonPath fails | SQLite") fun byJsonPathSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { PatchQuery.byJsonPath(tbl) } + ForceDialect.sqlite() + assertThrows { PatchQuery.byJsonPath(TEST_TABLE) } } } diff --git a/src/jvm/src/test/kotlin/query/QueryTest.kt b/src/jvm/src/test/kotlin/query/QueryTest.kt index c16b31a..1d3ec1d 100644 --- a/src/jvm/src/test/kotlin/query/QueryTest.kt +++ b/src/jvm/src/test/kotlin/query/QueryTest.kt @@ -3,10 +3,10 @@ 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 solutions.bitbadger.documents.support.ForceDialect import kotlin.test.assertEquals /** @@ -20,7 +20,7 @@ class QueryTest { */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test @@ -29,30 +29,30 @@ class QueryTest { assertEquals("x WHERE y", statementWhere("x", "y"), "Statements not combined correctly") @Test - @DisplayName("byId generates a numeric ID query (PostgreSQL)") + @DisplayName("byId generates a numeric ID query | PostgreSQL") fun byIdNumericPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals("test WHERE (data->>'id')::numeric = :id", byId("test", 9)) } @Test - @DisplayName("byId generates an alphanumeric ID query (PostgreSQL)") + @DisplayName("byId generates an alphanumeric ID query | PostgreSQL") fun byIdAlphaPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals("unit WHERE data->>'id' = :id", byId("unit", "18")) } @Test - @DisplayName("byId generates ID query (SQLite)") + @DisplayName("byId generates ID query | SQLite") fun byIdSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals("yo WHERE data->>'id' = :id", byId("yo", 27)) } @Test - @DisplayName("byFields generates default field query (PostgreSQL)") + @DisplayName("byFields generates default field query | PostgreSQL") fun byFieldsMultipleDefaultPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() 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"))) @@ -60,9 +60,9 @@ class QueryTest { } @Test - @DisplayName("byFields generates default field query (SQLite)") + @DisplayName("byFields generates default field query | SQLite") fun byFieldsMultipleDefaultSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.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"))) @@ -70,9 +70,9 @@ class QueryTest { } @Test - @DisplayName("byFields generates ANY field query (PostgreSQL)") + @DisplayName("byFields generates ANY field query | PostgreSQL") fun byFieldsMultipleAnyPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( "that WHERE data->>'a' = :the_a OR (data->>'b')::numeric = :b_value", byFields( @@ -83,9 +83,9 @@ class QueryTest { } @Test - @DisplayName("byFields generates ANY field query (SQLite)") + @DisplayName("byFields generates ANY field query | SQLite") fun byFieldsMultipleAnySQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( "that WHERE data->>'a' = :the_a OR data->>'b' = :b_value", byFields( @@ -103,7 +103,7 @@ class QueryTest { } @Test - @DisplayName("orderBy generates single, no direction for PostgreSQL") + @DisplayName("orderBy generates single, no direction | PostgreSQL") fun orderBySinglePostgres() = assertEquals( " ORDER BY data->>'TestField'", @@ -111,7 +111,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates single, no direction for SQLite") + @DisplayName("orderBy generates single, no direction | SQLite") fun orderBySingleSQLite() = assertEquals( " ORDER BY data->>'TestField'", orderBy(listOf(Field.named("TestField")), Dialect.SQLITE), @@ -119,7 +119,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates multiple with direction for PostgreSQL") + @DisplayName("orderBy generates multiple with direction | PostgreSQL") fun orderByMultiplePostgres() = assertEquals( " ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC", @@ -131,7 +131,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates multiple with direction for SQLite") + @DisplayName("orderBy generates multiple with direction | SQLite") fun orderByMultipleSQLite() = assertEquals( " ORDER BY data->'Nested'->'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC", @@ -143,7 +143,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates numeric ordering PostgreSQL") + @DisplayName("orderBy generates numeric ordering | PostgreSQL") fun orderByNumericPostgres() = assertEquals( " ORDER BY (data->>'Test')::numeric", @@ -151,7 +151,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates numeric ordering for SQLite") + @DisplayName("orderBy generates numeric ordering | SQLite") fun orderByNumericSQLite() = assertEquals( " ORDER BY data->>'Test'", orderBy(listOf(Field.named("n:Test")), Dialect.SQLITE), @@ -159,7 +159,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates case-insensitive ordering for PostgreSQL") + @DisplayName("orderBy generates case-insensitive ordering | PostgreSQL") fun orderByCIPostgres() = assertEquals( " ORDER BY LOWER(data#>>'{Test,Field}') DESC NULLS FIRST", @@ -168,7 +168,7 @@ class QueryTest { ) @Test - @DisplayName("orderBy generates case-insensitive ordering for SQLite") + @DisplayName("orderBy generates case-insensitive ordering | SQLite") fun orderByCISQLite() = assertEquals( " ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST", diff --git a/src/jvm/src/test/kotlin/query/RemoveFieldsQueryTest.kt b/src/jvm/src/test/kotlin/query/RemoveFieldsQueryTest.kt index d042f17..06a2523 100644 --- a/src/jvm/src/test/kotlin/query/RemoveFieldsQueryTest.kt +++ b/src/jvm/src/test/kotlin/query/RemoveFieldsQueryTest.kt @@ -5,6 +5,8 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import solutions.bitbadger.documents.* +import solutions.bitbadger.documents.support.ForceDialect +import solutions.bitbadger.documents.support.TEST_TABLE import kotlin.test.assertEquals /** @@ -13,36 +15,33 @@ import kotlin.test.assertEquals @DisplayName("JVM | Kotlin | Query | RemoveFieldsQuery") class RemoveFieldsQueryTest { - /** Test table name */ - private val tbl = "test_table" - /** * Reset the dialect */ @AfterEach fun cleanUp() { - Configuration.dialectValue = null + ForceDialect.none() } @Test - @DisplayName("byId generates correctly (PostgreSQL)") + @DisplayName("byId generates correctly | PostgreSQL") fun byIdPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data - :name::text[] WHERE data->>'id' = :id", - RemoveFieldsQuery.byId(tbl, listOf(Parameter(":name", ParameterType.STRING, "{a,z}"))), + "UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data->>'id' = :id", + RemoveFieldsQuery.byId(TEST_TABLE, listOf(Parameter(":name", ParameterType.STRING, "{a,z}"))), "Remove Fields query not constructed correctly" ) } @Test - @DisplayName("byId generates correctly (SQLite)") + @DisplayName("byId generates correctly | SQLite") fun byIdSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "UPDATE $tbl SET data = json_remove(data, :name0, :name1) WHERE data->>'id' = :id", + "UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'id' = :id", RemoveFieldsQuery.byId( - tbl, + TEST_TABLE, listOf( Parameter(":name0", ParameterType.STRING, "a"), Parameter(":name1", ParameterType.STRING, "z") @@ -53,13 +52,13 @@ class RemoveFieldsQueryTest { } @Test - @DisplayName("byFields generates correctly (PostgreSQL)") + @DisplayName("byFields generates correctly | PostgreSQL") fun byFieldsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data - :name::text[] WHERE data->>'f' > :g", + "UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data->>'f' > :g", RemoveFieldsQuery.byFields( - tbl, + TEST_TABLE, listOf(Parameter(":name", ParameterType.STRING, "{b,c}")), listOf(Field.greater("f", "", ":g")) ), @@ -68,13 +67,13 @@ class RemoveFieldsQueryTest { } @Test - @DisplayName("byFields generates correctly (SQLite)") + @DisplayName("byFields generates correctly | SQLite") fun byFieldsSQLite() { - Configuration.dialectValue = Dialect.SQLITE + ForceDialect.sqlite() assertEquals( - "UPDATE $tbl SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g", + "UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g", RemoveFieldsQuery.byFields( - tbl, + TEST_TABLE, listOf(Parameter(":name0", ParameterType.STRING, "b"), Parameter(":name1", ParameterType.STRING, "c")), listOf(Field.greater("f", "", ":g")) ), @@ -83,38 +82,38 @@ class RemoveFieldsQueryTest { } @Test - @DisplayName("byContains generates correctly (PostgreSQL)") + @DisplayName("byContains generates correctly | PostgreSQL") fun byContainsPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data - :name::text[] WHERE data @> :criteria", - RemoveFieldsQuery.byContains(tbl, listOf(Parameter(":name", ParameterType.STRING, "{m,n}"))), + "UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data @> :criteria", + RemoveFieldsQuery.byContains(TEST_TABLE, listOf(Parameter(":name", ParameterType.STRING, "{m,n}"))), "Remove Field query not constructed correctly" ) } @Test - @DisplayName("byContains fails (SQLite)") + @DisplayName("byContains fails | SQLite") fun byContainsSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { RemoveFieldsQuery.byContains(tbl, listOf()) } + ForceDialect.sqlite() + assertThrows { RemoveFieldsQuery.byContains(TEST_TABLE, listOf()) } } @Test - @DisplayName("byJsonPath generates correctly (PostgreSQL)") + @DisplayName("byJsonPath generates correctly | PostgreSQL") fun byJsonPathPostgres() { - Configuration.dialectValue = Dialect.POSTGRESQL + ForceDialect.postgres() assertEquals( - "UPDATE $tbl SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)", - RemoveFieldsQuery.byJsonPath(tbl, listOf(Parameter(":name", ParameterType.STRING, "{o,p}"))), + "UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)", + RemoveFieldsQuery.byJsonPath(TEST_TABLE, listOf(Parameter(":name", ParameterType.STRING, "{o,p}"))), "Remove Field query not constructed correctly" ) } @Test - @DisplayName("byJsonPath fails (SQLite)") + @DisplayName("byJsonPath fails | SQLite") fun byJsonPathSQLite() { - Configuration.dialectValue = Dialect.SQLITE - assertThrows { RemoveFieldsQuery.byJsonPath(tbl, listOf()) } + ForceDialect.sqlite() + assertThrows { RemoveFieldsQuery.byJsonPath(TEST_TABLE, listOf()) } } -} \ No newline at end of file +}