Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
5 changed files with 304 additions and 59 deletions
Showing only changes of commit eda312fe3b - Show all commits

View File

@ -0,0 +1,87 @@
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.CountQuery;
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 `Count` object
*/
@DisplayName("JVM | Java | Query | CountQuery")
public class CountQueryTest {
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
public void cleanUp() {
ForceDialect.none();
}
@Test
@DisplayName("all generates correctly")
public void all() {
assertEquals(String.format("SELECT COUNT(*) AS it FROM %s", TEST_TABLE), CountQuery.all(TEST_TABLE),
"Count query not constructed correctly");
}
@Test
@DisplayName("byFields generates correctly | PostgreSQL")
public void byFieldsPostgres() {
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"))),
"Count query not constructed correctly");
}
@Test
@DisplayName("byFields generates correctly | SQLite")
public void byFieldsSQLite() {
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"))),
"Count query not constructed correctly");
}
@Test
@DisplayName("byContains generates correctly | PostgreSQL")
public void byContainsPostgres() throws DocumentException {
ForceDialect.postgres();
assertEquals(String.format("SELECT COUNT(*) AS it FROM %s WHERE data @> :criteria", TEST_TABLE),
CountQuery.byContains(TEST_TABLE), "Count query not constructed correctly");
}
@Test
@DisplayName("byContains fails | SQLite")
public void byContainsSQLite() {
ForceDialect.sqlite();
assertThrows(DocumentException.class, () -> CountQuery.byContains(TEST_TABLE));
}
@Test
@DisplayName("byJsonPath generates correctly | PostgreSQL")
public void byJsonPathPostgres() throws DocumentException {
ForceDialect.postgres();
assertEquals(
String.format("SELECT COUNT(*) AS it FROM %s WHERE jsonb_path_exists(data, :path::jsonpath)",
TEST_TABLE),
CountQuery.byJsonPath(TEST_TABLE), "Count query not constructed correctly");
}
@Test
@DisplayName("byJsonPath fails | SQLite")
public void byJsonPathSQLite() {
ForceDialect.sqlite();
assertThrows(DocumentException.class, () -> CountQuery.byJsonPath(TEST_TABLE));
}
}

View File

@ -0,0 +1,133 @@
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.DocumentIndex;
import solutions.bitbadger.documents.query.DefinitionQuery;
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 `Definition` object
*/
@DisplayName("JVM | Java | Query | DefinitionQuery")
public class DefinitionQueryTest {
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
public void cleanUp() {
ForceDialect.none();
}
@Test
@DisplayName("ensureTableFor generates correctly")
public void ensureTableFor() {
assertEquals("CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)",
DefinitionQuery.ensureTableFor("my.table", "JSONB"),
"CREATE TABLE statement not constructed correctly");
}
@Test
@DisplayName("ensureTable generates correctly | PostgreSQL")
public void ensureTablePostgres() throws DocumentException {
ForceDialect.postgres();
assertEquals(String.format("CREATE TABLE IF NOT EXISTS %s (data JSONB NOT NULL)", TEST_TABLE),
DefinitionQuery.ensureTable(TEST_TABLE));
}
@Test
@DisplayName("ensureTable generates correctly | SQLite")
public void ensureTableSQLite() throws DocumentException {
ForceDialect.sqlite();
assertEquals(String.format("CREATE TABLE IF NOT EXISTS %s (data TEXT NOT NULL)", TEST_TABLE),
DefinitionQuery.ensureTable(TEST_TABLE));
}
@Test
@DisplayName("ensureTable fails when no dialect is set")
public void ensureTableFailsUnknown() {
assertThrows(DocumentException.class, () -> DefinitionQuery.ensureTable(TEST_TABLE));
}
@Test
@DisplayName("ensureKey generates correctly with schema")
public void ensureKeyWithSchema() throws DocumentException {
assertEquals("CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data->>'id'))",
DefinitionQuery.ensureKey("test.table", Dialect.POSTGRESQL),
"CREATE INDEX for key statement with schema not constructed correctly");
}
@Test
@DisplayName("ensureKey generates correctly without schema")
public void ensureKeyWithoutSchema() throws DocumentException {
assertEquals(
String.format("CREATE UNIQUE INDEX IF NOT EXISTS idx_%1$s_key ON %1$s ((data->>'id'))", TEST_TABLE),
DefinitionQuery.ensureKey(TEST_TABLE, Dialect.SQLITE),
"CREATE INDEX for key statement without schema not constructed correctly");
}
@Test
@DisplayName("ensureIndexOn generates multiple fields and directions")
public void ensureIndexOnMultipleFields() throws DocumentException {
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table ((data->>'taco'), (data->>'guac') DESC, (data->>'salsa') ASC)",
DefinitionQuery.ensureIndexOn("test.table", "gibberish", List.of("taco", "guac DESC", "salsa ASC"),
Dialect.POSTGRESQL),
"CREATE INDEX for multiple field statement not constructed correctly");
}
@Test
@DisplayName("ensureIndexOn generates nested field | PostgreSQL")
public void ensureIndexOnNestedPostgres() throws DocumentException {
assertEquals(String.format("CREATE INDEX IF NOT EXISTS idx_%1$s_nest ON %1$s ((data#>>'{a,b,c}'))", TEST_TABLE),
DefinitionQuery.ensureIndexOn(TEST_TABLE, "nest", List.of("a.b.c"), Dialect.POSTGRESQL),
"CREATE INDEX for nested PostgreSQL field incorrect");
}
@Test
@DisplayName("ensureIndexOn generates nested field | SQLite")
public void ensureIndexOnNestedSQLite() throws DocumentException {
assertEquals(
String.format("CREATE INDEX IF NOT EXISTS idx_%1$s_nest ON %1$s ((data->'a'->'b'->>'c'))", TEST_TABLE),
DefinitionQuery.ensureIndexOn(TEST_TABLE, "nest", List.of("a.b.c"), Dialect.SQLITE),
"CREATE INDEX for nested SQLite field incorrect");
}
@Test
@DisplayName("ensureDocumentIndexOn generates Full | PostgreSQL")
public void ensureDocumentIndexOnFullPostgres() throws DocumentException {
ForceDialect.postgres();
assertEquals(String.format("CREATE INDEX IF NOT EXISTS idx_%1$s_document ON %1$s USING GIN (data)", TEST_TABLE),
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL),
"CREATE INDEX for full document index incorrect");
}
@Test
@DisplayName("ensureDocumentIndexOn generates Optimized | PostgreSQL")
public void ensureDocumentIndexOnOptimizedPostgres() throws DocumentException {
ForceDialect.postgres();
assertEquals(
String.format("CREATE INDEX IF NOT EXISTS idx_%1$s_document ON %1$s USING GIN (data jsonb_path_ops)",
TEST_TABLE),
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.OPTIMIZED),
"CREATE INDEX for optimized document index incorrect");
}
@Test
@DisplayName("ensureDocumentIndexOn fails | SQLite")
public void ensureDocumentIndexOnFailsSQLite() {
ForceDialect.sqlite();
assertThrows(DocumentException.class,
() -> DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL));
}
}

View File

@ -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,75 +16,72 @@ import kotlin.test.assertEquals
@DisplayName("JVM | Kotlin | Query | CountQuery")
class CountQueryTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
ForceDialect.none()
}
@Test
@DisplayName("all generates correctly")
fun all() =
assertEquals("SELECT COUNT(*) AS it FROM $tbl", CountQuery.all(tbl), "Count query not constructed correctly")
assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE", CountQuery.all(TEST_TABLE), "Count 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 COUNT(*) AS it FROM $tbl WHERE data->>'test' = :field0",
CountQuery.byFields(tbl, listOf(Field.equal("test", "", ":field0"))),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0",
CountQuery.byFields(TEST_TABLE, listOf(Field.equal("test", "", ":field0"))),
"Count query not constructed correctly"
)
}
@Test
@DisplayName("byFields generates correctly (PostgreSQL)")
@DisplayName("byFields generates correctly | SQLite")
fun byFieldsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
ForceDialect.sqlite()
assertEquals(
"SELECT COUNT(*) AS it FROM $tbl WHERE data->>'test' = :field0",
CountQuery.byFields(tbl, listOf(Field.equal("test", "", ":field0"))),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0",
CountQuery.byFields(TEST_TABLE, listOf(Field.equal("test", "", ":field0"))),
"Count 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 COUNT(*) AS it FROM $tbl WHERE data @> :criteria", CountQuery.byContains(tbl),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data @> :criteria", CountQuery.byContains(TEST_TABLE),
"Count query not constructed correctly"
)
}
@Test
@DisplayName("byContains fails (SQLite)")
@DisplayName("byContains fails | SQLite")
fun byContainsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { CountQuery.byContains(tbl) }
ForceDialect.sqlite()
assertThrows<DocumentException> { CountQuery.byContains(TEST_TABLE) }
}
@Test
@DisplayName("byJsonPath generates correctly (PostgreSQL)")
@DisplayName("byJsonPath generates correctly | PostgreSQL")
fun byJsonPathPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
ForceDialect.postgres()
assertEquals(
"SELECT COUNT(*) AS it FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)",
CountQuery.byJsonPath(tbl), "Count query not constructed correctly"
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)",
CountQuery.byJsonPath(TEST_TABLE), "Count query not constructed correctly"
)
}
@Test
@DisplayName("byJsonPath fails (SQLite)")
@DisplayName("byJsonPath fails | SQLite")
fun byJsonPathSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { CountQuery.byJsonPath(tbl) }
ForceDialect.sqlite()
assertThrows<DocumentException> { CountQuery.byJsonPath(TEST_TABLE) }
}
}

View File

@ -4,10 +4,11 @@ import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.DocumentIndex
import solutions.bitbadger.documents.support.ForceDialect
import solutions.bitbadger.documents.support.TEST_TABLE
import kotlin.test.assertEquals
/**
@ -16,15 +17,12 @@ import kotlin.test.assertEquals
@DisplayName("JVM | Kotlin | Query | DefinitionQuery")
class DefinitionQueryTest {
/** Test table name */
private val tbl = "test_table"
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
fun cleanUp() {
Configuration.dialectValue = null
ForceDialect.none()
}
@Test
@ -36,23 +34,29 @@ class DefinitionQueryTest {
)
@Test
@DisplayName("ensureTable generates correctly (PostgreSQL)")
@DisplayName("ensureTable generates correctly | PostgreSQL")
fun ensureTablePostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
assertEquals("CREATE TABLE IF NOT EXISTS $tbl (data JSONB NOT NULL)", DefinitionQuery.ensureTable(tbl))
ForceDialect.postgres()
assertEquals(
"CREATE TABLE IF NOT EXISTS $TEST_TABLE (data JSONB NOT NULL)",
DefinitionQuery.ensureTable(TEST_TABLE)
)
}
@Test
@DisplayName("ensureTable generates correctly (SQLite)")
@DisplayName("ensureTable generates correctly | SQLite")
fun ensureTableSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertEquals("CREATE TABLE IF NOT EXISTS $tbl (data TEXT NOT NULL)", DefinitionQuery.ensureTable(tbl))
ForceDialect.sqlite()
assertEquals(
"CREATE TABLE IF NOT EXISTS $TEST_TABLE (data TEXT NOT NULL)",
DefinitionQuery.ensureTable(TEST_TABLE)
)
}
@Test
@DisplayName("ensureTable fails when no dialect is set")
fun ensureTableFailsUnknown() {
assertThrows<DocumentException> { DefinitionQuery.ensureTable(tbl) }
assertThrows<DocumentException> { DefinitionQuery.ensureTable(TEST_TABLE) }
}
@Test
@ -68,8 +72,8 @@ class DefinitionQueryTest {
@DisplayName("ensureKey generates correctly without schema")
fun ensureKeyWithoutSchema() =
assertEquals(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_${tbl}_key ON $tbl ((data->>'id'))",
DefinitionQuery.ensureKey(tbl, Dialect.SQLITE),
"CREATE UNIQUE INDEX IF NOT EXISTS idx_${TEST_TABLE}_key ON $TEST_TABLE ((data->>'id'))",
DefinitionQuery.ensureKey(TEST_TABLE, Dialect.SQLITE),
"CREATE INDEX for key statement without schema not constructed correctly"
)
@ -86,49 +90,49 @@ class DefinitionQueryTest {
)
@Test
@DisplayName("ensureIndexOn generates nested PostgreSQL field")
@DisplayName("ensureIndexOn generates nested field | PostgreSQL")
fun ensureIndexOnNestedPostgres() =
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_nest ON $tbl ((data#>>'{a,b,c}'))",
DefinitionQuery.ensureIndexOn(tbl, "nest", listOf("a.b.c"), Dialect.POSTGRESQL),
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_nest ON $TEST_TABLE ((data#>>'{a,b,c}'))",
DefinitionQuery.ensureIndexOn(TEST_TABLE, "nest", listOf("a.b.c"), Dialect.POSTGRESQL),
"CREATE INDEX for nested PostgreSQL field incorrect"
)
@Test
@DisplayName("ensureIndexOn generates nested SQLite field")
@DisplayName("ensureIndexOn generates nested field | SQLite")
fun ensureIndexOnNestedSQLite() =
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_nest ON $tbl ((data->'a'->'b'->>'c'))",
DefinitionQuery.ensureIndexOn(tbl, "nest", listOf("a.b.c"), Dialect.SQLITE),
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_nest ON $TEST_TABLE ((data->'a'->'b'->>'c'))",
DefinitionQuery.ensureIndexOn(TEST_TABLE, "nest", listOf("a.b.c"), Dialect.SQLITE),
"CREATE INDEX for nested SQLite field incorrect"
)
@Test
@DisplayName("ensureDocumentIndexOn generates Full for PostgreSQL")
@DisplayName("ensureDocumentIndexOn generates Full | PostgreSQL")
fun ensureDocumentIndexOnFullPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
ForceDialect.postgres()
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_document ON $tbl USING GIN (data)",
DefinitionQuery.ensureDocumentIndexOn(tbl, DocumentIndex.FULL),
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data)",
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL),
"CREATE INDEX for full document index incorrect"
)
}
@Test
@DisplayName("ensureDocumentIndexOn generates Optimized for PostgreSQL")
@DisplayName("ensureDocumentIndexOn generates Optimized | PostgreSQL")
fun ensureDocumentIndexOnOptimizedPostgres() {
Configuration.dialectValue = Dialect.POSTGRESQL
ForceDialect.postgres()
assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${tbl}_document ON $tbl USING GIN (data jsonb_path_ops)",
DefinitionQuery.ensureDocumentIndexOn(tbl, DocumentIndex.OPTIMIZED),
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data jsonb_path_ops)",
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.OPTIMIZED),
"CREATE INDEX for optimized document index incorrect"
)
}
@Test
@DisplayName("ensureDocumentIndexOn fails for SQLite")
@DisplayName("ensureDocumentIndexOn fails | SQLite")
fun ensureDocumentIndexOnFailsSQLite() {
Configuration.dialectValue = Dialect.SQLITE
assertThrows<DocumentException> { DefinitionQuery.ensureDocumentIndexOn(tbl, DocumentIndex.FULL) }
ForceDialect.sqlite()
assertThrows<DocumentException> { DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL) }
}
}

View File

@ -0,0 +1,24 @@
package solutions.bitbadger.documents.support
import solutions.bitbadger.documents.Configuration
/**
* These functions use a dummy connection string to force the given dialect for a given test
*/
object ForceDialect {
@JvmStatic
fun postgres() {
Configuration.connectionString = ":postgresql:"
}
@JvmStatic
fun sqlite() {
Configuration.connectionString = ":sqlite:"
}
@JvmStatic
fun none() {
Configuration.connectionString = null
}
}