Reorg modules; complete impls/tests
This commit is contained in:
8
src/groovy/groovy.iml
Normal file
8
src/groovy/groovy.iml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="AdditionalModuleElements">
|
||||
<content url="file://$MODULE_DIR$" dumb="true">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
</content>
|
||||
</component>
|
||||
</module>
|
||||
109
src/groovy/pom.xml
Normal file
109
src/groovy/pom.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>solutions.bitbadger</groupId>
|
||||
<artifactId>documents</artifactId>
|
||||
<version>4.0.0-alpha1-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>solutions.bitbadger.documents</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
|
||||
<name>${project.groupId}:${project.artifactId}</name>
|
||||
<description>Expose a document store interface for PostgreSQL and SQLite (Groovy Library)</description>
|
||||
<url>https://bitbadger.solutions/open-source/relational-documents/jvm/</url>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<version>4.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>addSources</goal>
|
||||
<goal>addTestSources</goal>
|
||||
<goal>generateStubs</goal>
|
||||
<goal>compile</goal>
|
||||
<goal>generateTestStubs</goal>
|
||||
<goal>compileTests</goal>
|
||||
<goal>removeStubs</goal>
|
||||
<goal>removeTestStubs</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
<scope>runtime</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>${failsafe.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>solutions.bitbadger.documents</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-test</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-test-junit5</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
0
src/groovy/src/main/groovy/.gitkeep
Normal file
0
src/groovy/src/main/groovy/.gitkeep
Normal file
3
src/groovy/src/main/java/module-info.java
Normal file
3
src/groovy/src/main/java/module-info.java
Normal file
@@ -0,0 +1,3 @@
|
||||
module solutions.bitbadger.documents.groovy {
|
||||
requires solutions.bitbadger.documents.core;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
moduleName=Document Extensions for Connection
|
||||
moduleVersion=4.0.0-alpha1
|
||||
extensionClasses=solutions.bitbadger.documents.java.extensions.ConnExt
|
||||
@@ -0,0 +1,163 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.AutoId
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `AutoId` enum
|
||||
*/
|
||||
@DisplayName('Groovy | AutoId')
|
||||
class AutoIdTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('Generates a UUID string')
|
||||
void generateUUID() {
|
||||
assertEquals 32, AutoId.generateUUID().length(), 'The UUID should have been a 32-character string'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Generates a random hex character string of an even length')
|
||||
void generateRandomStringEven() {
|
||||
def result = AutoId.generateRandomString 8
|
||||
assertEquals 8, result.length(), "There should have been 8 characters in $result"
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Generates a random hex character string of an odd length')
|
||||
void generateRandomStringOdd() {
|
||||
def result = AutoId.generateRandomString 11
|
||||
assertEquals 11, result.length(), "There should have been 11 characters in $result"
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Generates different random hex character strings')
|
||||
void generateRandomStringIsRandom() {
|
||||
def result1 = AutoId.generateRandomString 16
|
||||
def result2 = AutoId.generateRandomString 16
|
||||
assertNotEquals result1, result2, 'There should have been 2 different strings generated'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId fails for null document')
|
||||
void needsAutoIdFailsForNullDocument() {
|
||||
assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.DISABLED, null, 'id') }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId fails for missing ID property')
|
||||
void needsAutoIdFailsForMissingId() {
|
||||
assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.UUID, new IntIdClass(0), 'Id') }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false if disabled')
|
||||
void needsAutoIdFalseIfDisabled() {
|
||||
assertFalse AutoId.needsAutoId(AutoId.DISABLED, '', ''), 'Disabled Auto ID should always return false'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns true for Number strategy and byte ID of 0')
|
||||
void needsAutoIdTrueForByteWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new ByteIdClass((byte) 0), 'id'),
|
||||
'Number Auto ID with 0 should return true')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false for Number strategy and byte ID of non-0')
|
||||
void needsAutoIdFalseForByteWithNonZero() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new ByteIdClass((byte) 77), 'id'),
|
||||
'Number Auto ID with 77 should return false')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns true for Number strategy and short ID of 0')
|
||||
void needsAutoIdTrueForShortWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new ShortIdClass((short) 0), 'id'),
|
||||
'Number Auto ID with 0 should return true')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false for Number strategy and short ID of non-0')
|
||||
void needsAutoIdFalseForShortWithNonZero() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new ShortIdClass((short) 31), 'id'),
|
||||
'Number Auto ID with 31 should return false')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns true for Number strategy and int ID of 0')
|
||||
void needsAutoIdTrueForIntWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new IntIdClass(0), 'id'),
|
||||
'Number Auto ID with 0 should return true')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false for Number strategy and int ID of non-0')
|
||||
void needsAutoIdFalseForIntWithNonZero() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new IntIdClass(6), 'id'),
|
||||
'Number Auto ID with 6 should return false')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns true for Number strategy and long ID of 0')
|
||||
void needsAutoIdTrueForLongWithZero() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new LongIdClass(0L), 'id'),
|
||||
'Number Auto ID with 0 should return true')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false for Number strategy and long ID of non-0')
|
||||
void needsAutoIdFalseForLongWithNonZero() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new LongIdClass(2L), 'id'),
|
||||
'Number Auto ID with 2 should return false')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId fails for Number strategy and non-number ID')
|
||||
void needsAutoIdFailsForNumberWithStringId() {
|
||||
assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.NUMBER, new StringIdClass(''), 'id') }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns true for UUID strategy and blank ID')
|
||||
void needsAutoIdTrueForUUIDWithBlank() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.UUID, new StringIdClass(''), 'id'),
|
||||
'UUID Auto ID with blank should return true')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false for UUID strategy and non-blank ID')
|
||||
void needsAutoIdFalseForUUIDNotBlank() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.UUID, new StringIdClass('howdy'), 'id'),
|
||||
'UUID Auto ID with non-blank should return false')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId fails for UUID strategy and non-string ID')
|
||||
void needsAutoIdFailsForUUIDNonString() {
|
||||
assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.UUID, new IntIdClass(5), 'id') }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns true for Random String strategy and blank ID')
|
||||
void needsAutoIdTrueForRandomWithBlank() {
|
||||
assertTrue(AutoId.needsAutoId(AutoId.RANDOM_STRING, new StringIdClass(''), 'id'),
|
||||
'Random String Auto ID with blank should return true')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId returns false for Random String strategy and non-blank ID')
|
||||
void needsAutoIdFalseForRandomNotBlank() {
|
||||
assertFalse(AutoId.needsAutoId(AutoId.RANDOM_STRING, new StringIdClass('full'), 'id'),
|
||||
'Random String Auto ID with non-blank should return false')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('needsAutoId fails for Random String strategy and non-string ID')
|
||||
void needsAutoIdFailsForRandomNonString() {
|
||||
assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.RANDOM_STRING, new ShortIdClass((short) 55), 'id') }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
class ByteIdClass {
|
||||
byte id
|
||||
|
||||
ByteIdClass(byte id) {
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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.Dialect
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Configuration` object
|
||||
*/
|
||||
@DisplayName('Groovy | Configuration')
|
||||
class ConfigurationTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('Default ID field is "id"')
|
||||
void defaultIdField() {
|
||||
assertEquals 'id', Configuration.idField, 'Default ID field incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Default Auto ID strategy is DISABLED')
|
||||
void defaultAutoId() {
|
||||
assertEquals AutoId.DISABLED, Configuration.autoIdStrategy, 'Default Auto ID strategy should be DISABLED'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Default ID string length should be 16')
|
||||
void defaultIdStringLength() {
|
||||
assertEquals 16, Configuration.idStringLength, 'Default ID string length should be 16'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Dialect is derived from connection string')
|
||||
void dialectIsDerived() {
|
||||
try {
|
||||
assertThrows(DocumentException) { Configuration.dialect() }
|
||||
Configuration.connectionString = 'jdbc:postgresql:db'
|
||||
assertEquals Dialect.POSTGRESQL, Configuration.dialect()
|
||||
} finally {
|
||||
Configuration.connectionString = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Count` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | CountQuery')
|
||||
class CountQueryTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all generates correctly')
|
||||
void all() {
|
||||
assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE".toString(), CountQuery.all(TEST_TABLE),
|
||||
'Count query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | PostgreSQL')
|
||||
void byFieldsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0".toString(),
|
||||
CountQuery.byFields(TEST_TABLE, List.of(Field.equal('test', '', ':field0'))),
|
||||
'Count query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | SQLite')
|
||||
void byFieldsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0".toString(),
|
||||
CountQuery.byFields(TEST_TABLE, List.of(Field.equal('test', '', ':field0'))),
|
||||
'Count query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains generates correctly | PostgreSQL')
|
||||
void byContainsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data @> :criteria".toString(),
|
||||
CountQuery.byContains(TEST_TABLE), 'Count query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails | SQLite')
|
||||
void byContainsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { CountQuery.byContains(TEST_TABLE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath generates correctly | PostgreSQL')
|
||||
void byJsonPathPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
|
||||
CountQuery.byJsonPath(TEST_TABLE), 'Count query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails | SQLite')
|
||||
void byJsonPathSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { CountQuery.byJsonPath(TEST_TABLE) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Definition` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | DefinitionQuery')
|
||||
class DefinitionQueryTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureTableFor generates correctly')
|
||||
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')
|
||||
void ensureTablePostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("CREATE TABLE IF NOT EXISTS $TEST_TABLE (data JSONB NOT NULL)".toString(),
|
||||
DefinitionQuery.ensureTable(TEST_TABLE))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureTable generates correctly | SQLite')
|
||||
void ensureTableSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("CREATE TABLE IF NOT EXISTS $TEST_TABLE (data TEXT NOT NULL)".toString(),
|
||||
DefinitionQuery.ensureTable(TEST_TABLE))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureTable fails when no dialect is set')
|
||||
void ensureTableFailsUnknown() {
|
||||
assertThrows(DocumentException) { DefinitionQuery.ensureTable(TEST_TABLE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureKey generates correctly with schema')
|
||||
void ensureKeyWithSchema() {
|
||||
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')
|
||||
void ensureKeyWithoutSchema() {
|
||||
assertEquals(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS idx_${TEST_TABLE}_key ON $TEST_TABLE ((data->>'id'))".toString(),
|
||||
DefinitionQuery.ensureKey(TEST_TABLE, Dialect.SQLITE),
|
||||
'CREATE INDEX for key statement without schema not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureIndexOn generates multiple fields and directions')
|
||||
void ensureIndexOnMultipleFields() {
|
||||
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')
|
||||
void ensureIndexOnNestedPostgres() {
|
||||
assertEquals("CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_nest ON $TEST_TABLE ((data#>>'{a,b,c}'))".toString(),
|
||||
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')
|
||||
void ensureIndexOnNestedSQLite() {
|
||||
assertEquals(
|
||||
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_nest ON $TEST_TABLE ((data->'a'->'b'->>'c'))".toString(),
|
||||
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')
|
||||
void ensureDocumentIndexOnFullPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data)".toString(),
|
||||
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL),
|
||||
'CREATE INDEX for full document index incorrect')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureDocumentIndexOn generates Optimized | PostgreSQL')
|
||||
void ensureDocumentIndexOnOptimizedPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals(
|
||||
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data jsonb_path_ops)"
|
||||
.toString(),
|
||||
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.OPTIMIZED),
|
||||
'CREATE INDEX for optimized document index incorrect')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureDocumentIndexOn fails | SQLite')
|
||||
void ensureDocumentIndexOnFailsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Delete` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | DeleteQuery')
|
||||
class DeleteQueryTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | PostgreSQL')
|
||||
void byIdPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), DeleteQuery.byId(TEST_TABLE),
|
||||
'Delete query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | SQLite')
|
||||
void byIdSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), DeleteQuery.byId(TEST_TABLE),
|
||||
'Delete query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | PostgreSQL')
|
||||
void byFieldsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'a' = :b".toString(),
|
||||
DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b'))),
|
||||
'Delete query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | SQLite')
|
||||
void byFieldsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'a' = :b".toString(),
|
||||
DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b'))),
|
||||
'Delete query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains generates correctly | PostgreSQL')
|
||||
void byContainsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("DELETE FROM $TEST_TABLE WHERE data @> :criteria".toString(), DeleteQuery.byContains(TEST_TABLE),
|
||||
'Delete query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails | SQLite')
|
||||
void byContainsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { DeleteQuery.byContains(TEST_TABLE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath generates correctly | PostgreSQL')
|
||||
void byJsonPathPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("DELETE FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
|
||||
DeleteQuery.byJsonPath(TEST_TABLE), 'Delete query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails | SQLite')
|
||||
void byJsonPathSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { DeleteQuery.byJsonPath(TEST_TABLE) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.Dialect
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Dialect` enum
|
||||
*/
|
||||
@DisplayName('Groovy | Dialect')
|
||||
class DialectTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('deriveFromConnectionString derives PostgreSQL correctly')
|
||||
void derivesPostgres() {
|
||||
assertEquals(Dialect.POSTGRESQL, Dialect.deriveFromConnectionString('jdbc:postgresql:db'),
|
||||
'Dialect should have been PostgreSQL')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('deriveFromConnectionString derives SQLite correctly')
|
||||
void derivesSQLite() {
|
||||
assertEquals(Dialect.SQLITE, Dialect.deriveFromConnectionString('jdbc:sqlite:memory'),
|
||||
'Dialect should have been SQLite')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('deriveFromConnectionString fails when the connection string is unknown')
|
||||
void deriveFailsWhenUnknown() {
|
||||
try {
|
||||
Dialect.deriveFromConnectionString 'SQL Server'
|
||||
fail 'Dialect derivation should have failed'
|
||||
} catch (DocumentException ex) {
|
||||
assertNotNull ex.message, 'The exception message should not have been null'
|
||||
assertTrue(ex.message.contains('[SQL Server]'),
|
||||
'The connection string should have been in the exception message')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentIndex
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
/**
|
||||
* Unit tests for the `DocumentIndex` enum
|
||||
*/
|
||||
@DisplayName('Groovy | DocumentIndex')
|
||||
class DocumentIndexTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('FULL uses proper SQL')
|
||||
void fullSQL() {
|
||||
assertEquals '', DocumentIndex.FULL.sql, 'The SQL for Full is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('OPTIMIZED uses proper SQL')
|
||||
void optimizedSQL() {
|
||||
assertEquals ' jsonb_path_ops', DocumentIndex.OPTIMIZED.sql, 'The SQL for Optimized is incorrect'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Document` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | DocumentQuery')
|
||||
class DocumentQueryTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert generates no auto ID | PostgreSQL')
|
||||
void insertNoAutoPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("INSERT INTO $TEST_TABLE VALUES (:data)".toString(), DocumentQuery.insert(TEST_TABLE))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert generates no auto ID | SQLite')
|
||||
void insertNoAutoSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("INSERT INTO $TEST_TABLE VALUES (:data)".toString(), DocumentQuery.insert(TEST_TABLE))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert generates auto number | PostgreSQL')
|
||||
void insertAutoNumberPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || ('{\"id\":' || (SELECT ".toString() +
|
||||
"COALESCE(MAX((data->>'id')::numeric), 0) + 1 FROM $TEST_TABLE) || '}')::jsonb)".toString(),
|
||||
DocumentQuery.insert(TEST_TABLE, AutoId.NUMBER))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert generates auto number | SQLite')
|
||||
void insertAutoNumberSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', ".toString() +
|
||||
"(SELECT coalesce(max(data->>'id'), 0) + 1 FROM $TEST_TABLE)))".toString(),
|
||||
DocumentQuery.insert(TEST_TABLE, AutoId.NUMBER))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert generates auto UUID | PostgreSQL')
|
||||
void insertAutoUUIDPostgres() {
|
||||
ForceDialect.postgres()
|
||||
def query = DocumentQuery.insert TEST_TABLE, AutoId.UUID
|
||||
assertTrue(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')
|
||||
void insertAutoUUIDSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
def query = DocumentQuery.insert TEST_TABLE, AutoId.UUID
|
||||
assertTrue(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')
|
||||
void insertAutoRandomPostgres() {
|
||||
try {
|
||||
ForceDialect.postgres()
|
||||
Configuration.idStringLength = 8
|
||||
def query = DocumentQuery.insert TEST_TABLE, AutoId.RANDOM_STRING
|
||||
assertTrue(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 $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\"", '')
|
||||
.replace("\"}')", '').length(),
|
||||
'Random string length incorrect')
|
||||
} finally {
|
||||
Configuration.idStringLength = 16
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert generates auto random string | SQLite')
|
||||
void insertAutoRandomSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
def query = DocumentQuery.insert TEST_TABLE, AutoId.RANDOM_STRING
|
||||
assertTrue(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 $TEST_TABLE VALUES (json_set(:data, '\$.id', '", '').replace("'))", '')
|
||||
.length(),
|
||||
'Random string length incorrect')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert fails when no dialect is set')
|
||||
void insertFailsUnknown() {
|
||||
assertThrows(DocumentException) { DocumentQuery.insert(TEST_TABLE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('save generates correctly')
|
||||
void save() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals(
|
||||
"INSERT INTO $TEST_TABLE VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data"
|
||||
.toString(),
|
||||
DocumentQuery.save(TEST_TABLE), 'INSERT ON CONFLICT UPDATE statement not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('update generates successfully')
|
||||
void update() {
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = :data".toString(), DocumentQuery.update(TEST_TABLE),
|
||||
'Update query not constructed correctly')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.FieldMatch
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
/**
|
||||
* Unit tests for the `FieldMatch` enum
|
||||
*/
|
||||
@DisplayName('Groovy | FieldMatch')
|
||||
class FieldMatchTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('ANY uses proper SQL')
|
||||
void anySQL() {
|
||||
assertEquals 'OR', FieldMatch.ANY.sql, 'ANY should use OR'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ALL uses proper SQL')
|
||||
void allSQL() {
|
||||
assertEquals 'AND', FieldMatch.ALL.sql, 'ALL should use AND'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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.FieldFormat
|
||||
import solutions.bitbadger.documents.Op
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Field` class
|
||||
*/
|
||||
@DisplayName('Groovy | Field')
|
||||
class FieldTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
// ~~~ INSTANCE METHODS ~~~
|
||||
|
||||
@Test
|
||||
@DisplayName('withParameterName fails for invalid name')
|
||||
void withParamNameFails() {
|
||||
assertThrows(DocumentException) { Field.equal('it', '').withParameterName('2424') }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('withParameterName works with colon prefix')
|
||||
void withParamNameColon() {
|
||||
def field = Field.equal('abc', '22').withQualifier 'me'
|
||||
def withParam = field.withParameterName ':test'
|
||||
assertNotSame field, withParam, 'A new Field instance should have been created'
|
||||
assertEquals field.name, withParam.name, 'Name should have been preserved'
|
||||
assertEquals field.comparison, withParam.comparison, 'Comparison should have been preserved'
|
||||
assertEquals ':test', withParam.parameterName, 'Parameter name not set correctly'
|
||||
assertEquals field.qualifier, withParam.qualifier, 'Qualifier should have been preserved'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('withParameterName works with at-sign prefix')
|
||||
void withParamNameAtSign() {
|
||||
def field = Field.equal 'def', '44'
|
||||
def withParam = field.withParameterName '@unit'
|
||||
assertNotSame field, withParam, 'A new Field instance should have been created'
|
||||
assertEquals field.name, withParam.name, 'Name should have been preserved'
|
||||
assertEquals field.comparison, withParam.comparison, 'Comparison should have been preserved'
|
||||
assertEquals '@unit', withParam.parameterName, 'Parameter name not set correctly'
|
||||
assertEquals field.qualifier, withParam.qualifier, 'Qualifier should have been preserved'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('withQualifier sets qualifier correctly')
|
||||
void withQualifier() {
|
||||
def field = Field.equal 'j', 'k'
|
||||
def withQual = field.withQualifier 'test'
|
||||
assertNotSame field, withQual, 'A new Field instance should have been created'
|
||||
assertEquals field.name, withQual.name, 'Name should have been preserved'
|
||||
assertEquals field.comparison, withQual.comparison, 'Comparison should have been preserved'
|
||||
assertEquals field.parameterName, withQual.parameterName, 'Parameter Name should have been preserved'
|
||||
assertEquals 'test', withQual.qualifier, 'Qualifier not set correctly'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('path generates for simple unqualified PostgreSQL field')
|
||||
void pathPostgresSimpleUnqualified() {
|
||||
assertEquals("data->>'SomethingCool'",
|
||||
Field.greaterOrEqual('SomethingCool', 18).path(Dialect.POSTGRESQL, FieldFormat.SQL), 'Path not correct')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('path generates for simple qualified PostgreSQL field')
|
||||
void pathPostgresSimpleQualified() {
|
||||
assertEquals("this.data->>'SomethingElse'",
|
||||
Field.less('SomethingElse', 9).withQualifier('this').path(Dialect.POSTGRESQL, FieldFormat.SQL),
|
||||
'Path not correct')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('path generates for nested unqualified PostgreSQL field')
|
||||
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')
|
||||
void pathPostgresNestedQualified() {
|
||||
assertEquals("bird.data#>>'{Nest,Away}'",
|
||||
Field.equal('Nest.Away', 'doc').withQualifier('bird').path(Dialect.POSTGRESQL, FieldFormat.SQL),
|
||||
'Path not correct')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('path generates for simple unqualified SQLite field')
|
||||
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')
|
||||
void pathSQLiteSimpleQualified() {
|
||||
assertEquals("this.data->>'SomethingElse'",
|
||||
Field.less('SomethingElse', 9).withQualifier('this').path(Dialect.SQLITE, FieldFormat.SQL),
|
||||
'Path not correct')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('path generates for nested unqualified SQLite field')
|
||||
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')
|
||||
void pathSQLiteNestedQualified() {
|
||||
assertEquals("bird.data->'Nest'->>'Away'",
|
||||
Field.equal('Nest.Away', 'doc').withQualifier('bird').path(Dialect.SQLITE, FieldFormat.SQL),
|
||||
'Path not correct')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('toWhere generates for exists w/o qualifier | PostgreSQL')
|
||||
void toWhereExistsNoQualPostgres() {
|
||||
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')
|
||||
void toWhereExistsNoQualSQLite() {
|
||||
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')
|
||||
void toWhereNotExistsNoQualPostgres() {
|
||||
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')
|
||||
void toWhereNotExistsNoQualSQLite() {
|
||||
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')
|
||||
void toWhereBetweenNoQualNumericPostgres() {
|
||||
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')
|
||||
void toWhereBetweenNoQualAlphaPostgres() {
|
||||
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')
|
||||
void toWhereBetweenNoQualSQLite() {
|
||||
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')
|
||||
void toWhereBetweenQualNumericPostgres() {
|
||||
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')
|
||||
void toWhereBetweenQualAlphaPostgres() {
|
||||
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')
|
||||
void toWhereBetweenQualSQLite() {
|
||||
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')
|
||||
void toWhereAnyNumericPostgres() {
|
||||
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')
|
||||
void toWhereAnyAlphaPostgres() {
|
||||
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')
|
||||
void toWhereAnySQLite() {
|
||||
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')
|
||||
void toWhereInArrayPostgres() {
|
||||
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')
|
||||
void toWhereInArraySQLite() {
|
||||
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')
|
||||
void toWhereOtherNoQualPostgres() {
|
||||
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')
|
||||
void toWhereOtherNoQualSQLite() {
|
||||
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')
|
||||
void toWhereNoParamWithQualPostgres() {
|
||||
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')
|
||||
void toWhereNoParamWithQualSQLite() {
|
||||
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')
|
||||
void toWhereParamWithQualPostgres() {
|
||||
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')
|
||||
void toWhereParamWithQualSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("q.data->>'le_field' <= :it",
|
||||
Field.lessOrEqual('le_field', 18, ':it').withQualifier('q').toWhere(),
|
||||
'Field WHERE clause not generated correctly')
|
||||
}
|
||||
|
||||
// ~~~ STATIC CONSTRUCTOR TESTS ~~~
|
||||
|
||||
@Test
|
||||
@DisplayName('equal constructs a field w/o parameter name')
|
||||
void equalCtor() {
|
||||
def field = Field.equal 'Test', 14
|
||||
assertEquals 'Test', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 14, field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('equal constructs a field w/ parameter name')
|
||||
void equalParameterCtor() {
|
||||
def field = Field.equal 'Test', 14, ':w'
|
||||
assertEquals 'Test', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 14, field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':w', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('greater constructs a field w/o parameter name')
|
||||
void greaterCtor() {
|
||||
def field = Field.greater 'Great', 'night'
|
||||
assertEquals 'Great', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.GREATER, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'night', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('greater constructs a field w/ parameter name')
|
||||
void greaterParameterCtor() {
|
||||
def field = Field.greater 'Great', 'night', ':yeah'
|
||||
assertEquals 'Great', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.GREATER, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'night', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':yeah', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('greaterOrEqual constructs a field w/o parameter name')
|
||||
void greaterOrEqualCtor() {
|
||||
def field = Field.greaterOrEqual 'Nice', 88L
|
||||
assertEquals 'Nice', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.GREATER_OR_EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 88L, field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('greaterOrEqual constructs a field w/ parameter name')
|
||||
void greaterOrEqualParameterCtor() {
|
||||
def field = Field.greaterOrEqual 'Nice', 88L, ':nice'
|
||||
assertEquals 'Nice', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.GREATER_OR_EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 88L, field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':nice', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('less constructs a field w/o parameter name')
|
||||
void lessCtor() {
|
||||
def field = Field.less 'Lesser', 'seven'
|
||||
assertEquals 'Lesser', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.LESS, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'seven', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('less constructs a field w/ parameter name')
|
||||
void lessParameterCtor() {
|
||||
def field = Field.less 'Lesser', 'seven', ':max'
|
||||
assertEquals 'Lesser', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.LESS, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'seven', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':max', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('lessOrEqual constructs a field w/o parameter name')
|
||||
void lessOrEqualCtor() {
|
||||
def field = Field.lessOrEqual 'Nobody', 'KNOWS'
|
||||
assertEquals 'Nobody', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.LESS_OR_EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'KNOWS', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('lessOrEqual constructs a field w/ parameter name')
|
||||
void lessOrEqualParameterCtor() {
|
||||
def field = Field.lessOrEqual 'Nobody', 'KNOWS', ':nope'
|
||||
assertEquals 'Nobody', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.LESS_OR_EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'KNOWS', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':nope', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('notEqual constructs a field w/o parameter name')
|
||||
void notEqualCtor() {
|
||||
def field = Field.notEqual 'Park', 'here'
|
||||
assertEquals 'Park', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.NOT_EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'here', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('notEqual constructs a field w/ parameter name')
|
||||
void notEqualParameterCtor() {
|
||||
def field = Field.notEqual 'Park', 'here', ':now'
|
||||
assertEquals 'Park', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.NOT_EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'here', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':now', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('between constructs a field w/o parameter name')
|
||||
void betweenCtor() {
|
||||
def field = Field.between 'Age', 18, 49
|
||||
assertEquals 'Age', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.BETWEEN, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 18, field.comparison.value.first, 'Field comparison min value not filled correctly'
|
||||
assertEquals 49, field.comparison.value.second, 'Field comparison max value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('between constructs a field w/ parameter name')
|
||||
void betweenParameterCtor() {
|
||||
def field = Field.between 'Age', 18, 49, ':limit'
|
||||
assertEquals 'Age', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.BETWEEN, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 18, field.comparison.value.first, 'Field comparison min value not filled correctly'
|
||||
assertEquals 49, field.comparison.value.second, 'Field comparison max value not filled correctly'
|
||||
assertEquals ':limit', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('any constructs a field w/o parameter name')
|
||||
void anyCtor() {
|
||||
def field = Field.any 'Here', List.of(8, 16, 32)
|
||||
assertEquals 'Here', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.IN, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals List.of(8, 16, 32), field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('any constructs a field w/ parameter name')
|
||||
void anyParameterCtor() {
|
||||
def field = Field.any 'Here', List.of(8, 16, 32), ':list'
|
||||
assertEquals 'Here', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.IN, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals List.of(8, 16, 32), field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertEquals ':list', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('inArray constructs a field w/o parameter name')
|
||||
void inArrayCtor() {
|
||||
def field = Field.inArray 'ArrayField', 'table', List.of('z')
|
||||
assertEquals 'ArrayField', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.IN_ARRAY, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'table', field.comparison.value.first, 'Field comparison table not filled correctly'
|
||||
assertEquals List.of('z'), field.comparison.value.second, 'Field comparison values not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('inArray constructs a field w/ parameter name')
|
||||
void inArrayParameterCtor() {
|
||||
def field = Field.inArray 'ArrayField', 'table', List.of('z'), ':a'
|
||||
assertEquals 'ArrayField', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.IN_ARRAY, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals 'table', field.comparison.value.first, 'Field comparison table not filled correctly'
|
||||
assertEquals List.of('z'), field.comparison.value.second, 'Field comparison values not filled correctly'
|
||||
assertEquals ':a', field.parameterName, 'Field parameter name not filled correctly'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('exists constructs a field')
|
||||
void existsCtor() {
|
||||
def field = Field.exists 'Groovy'
|
||||
assertEquals 'Groovy', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.EXISTS, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals '', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('notExists constructs a field')
|
||||
void notExistsCtor() {
|
||||
def field = Field.notExists 'Groovy'
|
||||
assertEquals 'Groovy', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.NOT_EXISTS, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals '', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('named constructs a field')
|
||||
void namedCtor() {
|
||||
def field = Field.named 'Tacos'
|
||||
assertEquals 'Tacos', field.name, 'Field name not filled correctly'
|
||||
assertEquals Op.EQUAL, field.comparison.op, 'Field comparison operation not filled correctly'
|
||||
assertEquals '', field.comparison.value, 'Field comparison value not filled correctly'
|
||||
assertNull field.parameterName, 'The parameter name should have been null'
|
||||
assertNull field.qualifier, 'The qualifier should have been null'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('static constructors fail for invalid parameter name')
|
||||
void staticCtorsFailOnParamName() {
|
||||
assertThrows(DocumentException) { Field.equal('a', 'b', "that ain't it, Jack...") }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a simple PostgreSQL SQL name')
|
||||
void nameToPathPostgresSimpleSQL() {
|
||||
assertEquals("data->>'Simple'", Field.nameToPath('Simple', Dialect.POSTGRESQL, FieldFormat.SQL),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a simple SQLite SQL name')
|
||||
void nameToPathSQLiteSimpleSQL() {
|
||||
assertEquals("data->>'Simple'", Field.nameToPath('Simple', Dialect.SQLITE, FieldFormat.SQL),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a nested PostgreSQL SQL name')
|
||||
void nameToPathPostgresNestedSQL() {
|
||||
assertEquals("data#>>'{A,Long,Path,to,the,Property}'",
|
||||
Field.nameToPath('A.Long.Path.to.the.Property', Dialect.POSTGRESQL, FieldFormat.SQL),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a nested SQLite SQL name')
|
||||
void nameToPathSQLiteNestedSQL() {
|
||||
assertEquals("data->'A'->'Long'->'Path'->'to'->'the'->>'Property'",
|
||||
Field.nameToPath('A.Long.Path.to.the.Property', Dialect.SQLITE, FieldFormat.SQL),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a simple PostgreSQL JSON name')
|
||||
void nameToPathPostgresSimpleJSON() {
|
||||
assertEquals("data->'Simple'", Field.nameToPath('Simple', Dialect.POSTGRESQL, FieldFormat.JSON),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a simple SQLite JSON name')
|
||||
void nameToPathSQLiteSimpleJSON() {
|
||||
assertEquals("data->'Simple'", Field.nameToPath('Simple', Dialect.SQLITE, FieldFormat.JSON),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a nested PostgreSQL JSON name')
|
||||
void nameToPathPostgresNestedJSON() {
|
||||
assertEquals("data#>'{A,Long,Path,to,the,Property}'",
|
||||
Field.nameToPath('A.Long.Path.to.the.Property', Dialect.POSTGRESQL, FieldFormat.JSON),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameToPath creates a nested SQLite JSON name')
|
||||
void nameToPathSQLiteNestedJSON() {
|
||||
assertEquals("data->'A'->'Long'->'Path'->'to'->'the'->'Property'",
|
||||
Field.nameToPath('A.Long.Path.to.the.Property', Dialect.SQLITE, FieldFormat.JSON),
|
||||
'Path not constructed correctly')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Find` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | FindQuery')
|
||||
class FindQueryTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all generates correctly')
|
||||
void all() {
|
||||
assertEquals("SELECT data FROM $TEST_TABLE".toString(), FindQuery.all(TEST_TABLE),
|
||||
'Find query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | PostgreSQL')
|
||||
void byIdPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), FindQuery.byId(TEST_TABLE),
|
||||
'Find query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | SQLite')
|
||||
void byIdSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), FindQuery.byId(TEST_TABLE),
|
||||
'Find query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | PostgreSQL')
|
||||
void byFieldsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'a' = :b AND (data->>'c')::numeric < :d".toString(),
|
||||
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')
|
||||
void byFieldsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'a' = :b AND data->>'c' < :d".toString(),
|
||||
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')
|
||||
void byContainsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT data FROM $TEST_TABLE WHERE data @> :criteria".toString(),
|
||||
FindQuery.byContains(TEST_TABLE), 'Find query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails | SQLite')
|
||||
void byContainsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { FindQuery.byContains(TEST_TABLE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath generates correctly | PostgreSQL')
|
||||
void byJsonPathPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("SELECT data FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
|
||||
FindQuery.byJsonPath(TEST_TABLE), 'Find query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails | SQLite')
|
||||
void byJsonPathSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { FindQuery.byJsonPath(TEST_TABLE) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import solutions.bitbadger.documents.Configuration
|
||||
|
||||
final class ForceDialect {
|
||||
|
||||
static void postgres() {
|
||||
Configuration.connectionString = ":postgresql:"
|
||||
}
|
||||
|
||||
static void sqlite() {
|
||||
Configuration.connectionString = ":sqlite:"
|
||||
}
|
||||
|
||||
static void none() {
|
||||
Configuration.connectionString = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
class IntIdClass {
|
||||
int id
|
||||
|
||||
IntIdClass(int id) {
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
class LongIdClass {
|
||||
long id
|
||||
|
||||
LongIdClass(long id) {
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.Op
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
/**
|
||||
* Unit tests for the `Op` enum
|
||||
*/
|
||||
@DisplayName('Groovy | Op')
|
||||
class OpTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('EQUAL uses proper SQL')
|
||||
void equalSQL() {
|
||||
assertEquals '=', Op.EQUAL.sql, 'The SQL for equal is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('GREATER uses proper SQL')
|
||||
void greaterSQL() {
|
||||
assertEquals '>', Op.GREATER.sql, 'The SQL for greater is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('GREATER_OR_EQUAL uses proper SQL')
|
||||
void greaterOrEqualSQL() {
|
||||
assertEquals '>=', Op.GREATER_OR_EQUAL.sql, 'The SQL for greater-or-equal is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('LESS uses proper SQL')
|
||||
void lessSQL() {
|
||||
assertEquals '<', Op.LESS.sql, 'The SQL for less is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('LESS_OR_EQUAL uses proper SQL')
|
||||
void lessOrEqualSQL() {
|
||||
assertEquals '<=', Op.LESS_OR_EQUAL.sql, 'The SQL for less-or-equal is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('NOT_EQUAL uses proper SQL')
|
||||
void notEqualSQL() {
|
||||
assertEquals '<>', Op.NOT_EQUAL.sql, 'The SQL for not-equal is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('BETWEEN uses proper SQL')
|
||||
void betweenSQL() {
|
||||
assertEquals 'BETWEEN', Op.BETWEEN.sql, 'The SQL for between is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('IN uses proper SQL')
|
||||
void inSQL() {
|
||||
assertEquals 'IN', Op.IN.sql, 'The SQL for in is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('IN_ARRAY uses proper SQL')
|
||||
void inArraySQL() {
|
||||
assertEquals '??|', Op.IN_ARRAY.sql, 'The SQL for in-array is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('EXISTS uses proper SQL')
|
||||
void existsSQL() {
|
||||
assertEquals 'IS NOT NULL', Op.EXISTS.sql, 'The SQL for exists is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('NOT_EXISTS uses proper SQL')
|
||||
void notExistsSQL() {
|
||||
assertEquals 'IS NULL', Op.NOT_EXISTS.sql, 'The SQL for not-exists is incorrect'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.ParameterName
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
/**
|
||||
* Unit tests for the `ParameterName` class
|
||||
*/
|
||||
@DisplayName('Groovy | ParameterName')
|
||||
class ParameterNameTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('derive works when given existing names')
|
||||
void withExisting() {
|
||||
def names = new ParameterName()
|
||||
assertEquals ':taco', names.derive(':taco'), 'Name should have been :taco'
|
||||
assertEquals ':field0', names.derive(null), 'Counter should not have advanced for named field'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('derive works when given all anonymous fields')
|
||||
void allAnonymous() {
|
||||
def names = new ParameterName()
|
||||
assertEquals ':field0', names.derive(null), 'Anonymous field name should have been returned'
|
||||
assertEquals ':field1', names.derive(null), 'Counter should have advanced from previous call'
|
||||
assertEquals ':field2', names.derive(null), 'Counter should have advanced from previous call'
|
||||
assertEquals ':field3', names.derive(null), 'Counter should have advanced from previous call'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
import solutions.bitbadger.documents.Parameter
|
||||
import solutions.bitbadger.documents.ParameterType
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Parameter` class
|
||||
*/
|
||||
@DisplayName('Groovy | Parameter')
|
||||
class ParameterTest {
|
||||
|
||||
@Test
|
||||
@DisplayName('Construction with colon-prefixed name')
|
||||
void ctorWithColon() {
|
||||
def p = new Parameter(':test', ParameterType.STRING, 'ABC')
|
||||
assertEquals ':test', p.name, 'Parameter name was incorrect'
|
||||
assertEquals ParameterType.STRING, p.type, 'Parameter type was incorrect'
|
||||
assertEquals 'ABC', p.value, 'Parameter value was incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Construction with at-sign-prefixed name')
|
||||
void ctorWithAtSign() {
|
||||
def p = new Parameter('@yo', ParameterType.NUMBER, null)
|
||||
assertEquals '@yo', p.name, 'Parameter name was incorrect'
|
||||
assertEquals ParameterType.NUMBER, p.type, 'Parameter type was incorrect'
|
||||
assertNull p.value, 'Parameter value was incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('Construction fails with incorrect prefix')
|
||||
void ctorFailsForPrefix() {
|
||||
assertThrows(DocumentException) { new Parameter('it', ParameterType.JSON, '') }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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.java.Parameters
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Parameters` object
|
||||
*/
|
||||
@DisplayName('Groovy | Parameters')
|
||||
class ParametersTest {
|
||||
|
||||
/**
|
||||
* Reset the dialect
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameFields works with no changes')
|
||||
void nameFieldsNoChange() {
|
||||
def fields = List.of(Field.equal('a', '', ':test'), Field.exists('q'), Field.equal('b', '', ':me'))
|
||||
def named = Parameters.nameFields(fields).toList()
|
||||
assertEquals fields.size(), named.size(), 'There should have been 3 fields in the list'
|
||||
assertSame fields[0], named[0], 'The first field should be the same'
|
||||
assertSame fields[1], named[1], 'The second field should be the same'
|
||||
assertSame fields[2], named[2], 'The third field should be the same'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nameFields works when changing fields')
|
||||
void nameFieldsChange() {
|
||||
def fields = List.of(Field.equal('a', ''), Field.equal('e', '', ':hi'), Field.equal('b', ''),
|
||||
Field.notExists('z'))
|
||||
def named = Parameters.nameFields(fields).toList()
|
||||
assertEquals fields.size(), named.size(), 'There should have been 4 fields in the list'
|
||||
assertNotSame fields[0], named[0], 'The first field should not be the same'
|
||||
assertEquals ':field0', named[0].parameterName, 'First parameter name incorrect'
|
||||
assertSame fields[1], named[1], 'The second field should be the same'
|
||||
assertNotSame fields[2], named[2], 'The third field should not be the same'
|
||||
assertEquals ':field1', named[2].parameterName, 'Third parameter name incorrect'
|
||||
assertSame fields[3], named[3], 'The fourth field should be the same'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('replaceNamesInQuery replaces successfully')
|
||||
void replaceNamesInQuery() {
|
||||
def parameters = List.of(new Parameter(':data', ParameterType.JSON, '{}'),
|
||||
new Parameter(':data_ext', ParameterType.STRING, ''))
|
||||
def query = 'SELECT data, data_ext FROM tbl WHERE data = :data AND data_ext = :data_ext AND more_data = :data'
|
||||
assertEquals('SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?',
|
||||
Parameters.replaceNamesInQuery(query, parameters), 'Parameters not replaced correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('fieldNames generates a single parameter (PostgreSQL)')
|
||||
void fieldNamesSinglePostgres() {
|
||||
ForceDialect.postgres()
|
||||
def nameParams = Parameters.fieldNames(List.of('test')).toList()
|
||||
assertEquals 1, nameParams.size(), 'There should be one name parameter'
|
||||
assertEquals ':name', nameParams[0].name, 'The parameter name is incorrect'
|
||||
assertEquals ParameterType.STRING, nameParams[0].type, 'The parameter type is incorrect'
|
||||
assertEquals '{test}', nameParams[0].value, 'The parameter value is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('fieldNames generates multiple parameters (PostgreSQL)')
|
||||
void fieldNamesMultiplePostgres() {
|
||||
ForceDialect.postgres()
|
||||
def nameParams = Parameters.fieldNames(List.of('test', 'this', 'today')).toList()
|
||||
assertEquals 1, nameParams.size(), 'There should be one name parameter'
|
||||
assertEquals ':name', nameParams[0].name, 'The parameter name is incorrect'
|
||||
assertEquals ParameterType.STRING, nameParams[0].type, 'The parameter type is incorrect'
|
||||
assertEquals '{test,this,today}', nameParams[0].value, 'The parameter value is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('fieldNames generates a single parameter (SQLite)')
|
||||
void fieldNamesSingleSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
def nameParams = Parameters.fieldNames(List.of('test')).toList()
|
||||
assertEquals 1, nameParams.size(), 'There should be one name parameter'
|
||||
assertEquals ':name0', nameParams[0].name, 'The parameter name is incorrect'
|
||||
assertEquals ParameterType.STRING, nameParams[0].type, 'The parameter type is incorrect'
|
||||
assertEquals 'test', nameParams[0].value, 'The parameter value is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('fieldNames generates multiple parameters (SQLite)')
|
||||
void fieldNamesMultipleSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
def nameParams = Parameters.fieldNames(List.of('test', 'this', 'today')).toList()
|
||||
assertEquals 3, nameParams.size(), 'There should be one name parameter'
|
||||
assertEquals ':name0', nameParams[0].name, 'The first parameter name is incorrect'
|
||||
assertEquals ParameterType.STRING, nameParams[0].type, 'The first parameter type is incorrect'
|
||||
assertEquals 'test', nameParams[0].value, 'The first parameter value is incorrect'
|
||||
assertEquals ':name1', nameParams[1].name, 'The second parameter name is incorrect'
|
||||
assertEquals ParameterType.STRING, nameParams[1].type, 'The second parameter type is incorrect'
|
||||
assertEquals 'this', nameParams[1].value, 'The second parameter value is incorrect'
|
||||
assertEquals ':name2', nameParams[2].name, 'The third parameter name is incorrect'
|
||||
assertEquals ParameterType.STRING, nameParams[2].type, 'The third parameter type is incorrect'
|
||||
assertEquals 'today', nameParams[2].value, 'The third parameter value is incorrect'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('fieldNames fails if dialect not set')
|
||||
void fieldNamesFails() {
|
||||
assertThrows(DocumentException) { Parameters.fieldNames(List.of()) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Patch` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | PatchQuery')
|
||||
class PatchQueryTest {
|
||||
|
||||
/**
|
||||
* Reset the dialect
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | PostgreSQL')
|
||||
void byIdPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'id' = :id".toString(),
|
||||
PatchQuery.byId(TEST_TABLE), 'Patch query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | SQLite')
|
||||
void byIdSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id".toString(),
|
||||
PatchQuery.byId(TEST_TABLE), 'Patch query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | PostgreSQL')
|
||||
void byFieldsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'z' = :y".toString(),
|
||||
PatchQuery.byFields(TEST_TABLE, List.of(Field.equal('z', '', ':y'))),
|
||||
'Patch query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates correctly | SQLite')
|
||||
void byFieldsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'z' = :y".toString(),
|
||||
PatchQuery.byFields(TEST_TABLE, List.of(Field.equal('z', '', ':y'))),
|
||||
'Patch query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains generates correctly | PostgreSQL')
|
||||
void byContainsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = data || :data WHERE data @> :criteria".toString(),
|
||||
PatchQuery.byContains(TEST_TABLE), 'Patch query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails | SQLite')
|
||||
void byContainsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { PatchQuery.byContains(TEST_TABLE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath generates correctly | PostgreSQL')
|
||||
void byJsonPathPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals(
|
||||
"UPDATE $TEST_TABLE SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
|
||||
PatchQuery.byJsonPath(TEST_TABLE), 'Patch query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails | SQLite')
|
||||
void byJsonPathSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { PatchQuery.byJsonPath(TEST_TABLE) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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.Field
|
||||
import solutions.bitbadger.documents.FieldMatch
|
||||
import solutions.bitbadger.documents.query.QueryUtils
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `QueryUtils` class
|
||||
*/
|
||||
@DisplayName('Groovy | Query | QueryUtils')
|
||||
class QueryUtilsTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('statementWhere generates correctly')
|
||||
void statementWhere() {
|
||||
assertEquals 'x WHERE y', QueryUtils.statementWhere('x', 'y'), 'Statements not combined correctly'
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates a numeric ID query | PostgreSQL')
|
||||
void byIdNumericPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "test WHERE (data->>'id')::numeric = :id", QueryUtils.byId('test', 9)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates an alphanumeric ID query | PostgreSQL')
|
||||
void byIdAlphaPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "unit WHERE data->>'id' = :id", QueryUtils.byId('unit', '18')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates ID query | SQLite')
|
||||
void byIdSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals "yo WHERE data->>'id' = :id", QueryUtils.byId('yo', 27)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates default field query | PostgreSQL')
|
||||
void byFieldsMultipleDefaultPostgres() {
|
||||
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')
|
||||
void byFieldsMultipleDefaultSQLite() {
|
||||
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')
|
||||
void byFieldsMultipleAnyPostgres() {
|
||||
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')
|
||||
void byFieldsMultipleAnySQLite() {
|
||||
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')
|
||||
void orderByNone() {
|
||||
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')
|
||||
void orderBySinglePostgres() {
|
||||
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')
|
||||
void orderBySingleSQLite() {
|
||||
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')
|
||||
void orderByMultiplePostgres() {
|
||||
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')
|
||||
void orderByMultipleSQLite() {
|
||||
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')
|
||||
void orderByNumericPostgres() {
|
||||
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')
|
||||
void orderByNumericSQLite() {
|
||||
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')
|
||||
void orderByCIPostgres() {
|
||||
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')
|
||||
void orderByCISQLite() {
|
||||
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')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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 static Types.TEST_TABLE
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `RemoveFields` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | RemoveFieldsQuery')
|
||||
class RemoveFieldsQueryTest {
|
||||
|
||||
/**
|
||||
* Reset the dialect
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates correctly | PostgreSQL')
|
||||
void byIdPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data->>'id' = :id".toString(),
|
||||
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')
|
||||
void byIdSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals(
|
||||
"UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'id' = :id".toString(),
|
||||
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')
|
||||
void byFieldsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data->>'f' > :g".toString(),
|
||||
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')
|
||||
void byFieldsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g".toString(),
|
||||
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')
|
||||
void byContainsPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data @> :criteria".toString(),
|
||||
RemoveFieldsQuery.byContains(TEST_TABLE,
|
||||
List.of(new Parameter(':name', ParameterType.STRING, '{m,n}'))),
|
||||
'Remove Field query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails | SQLite')
|
||||
void byContainsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { RemoveFieldsQuery.byContains(TEST_TABLE, List.of()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath generates correctly | PostgreSQL')
|
||||
void byJsonPathPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals(
|
||||
"UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)"
|
||||
.toString(),
|
||||
RemoveFieldsQuery.byJsonPath(TEST_TABLE,
|
||||
List.of(new Parameter(':name', ParameterType.STRING, '{o,p}'))),
|
||||
'Remove Field query not constructed correctly')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails | SQLite')
|
||||
void byJsonPathSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { RemoveFieldsQuery.byJsonPath(TEST_TABLE, List.of()) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
class ShortIdClass {
|
||||
short id
|
||||
|
||||
ShortIdClass(short id) {
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
class StringIdClass {
|
||||
String id
|
||||
|
||||
StringIdClass(String id) {
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
final class Types {
|
||||
|
||||
public static final String TEST_TABLE = 'test_table'
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package solutions.bitbadger.documents.groovy.tests
|
||||
|
||||
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.FieldMatch
|
||||
import solutions.bitbadger.documents.query.Where
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
/**
|
||||
* Unit tests for the `Where` object
|
||||
*/
|
||||
@DisplayName('Groovy | Query | Where')
|
||||
class WhereTest {
|
||||
|
||||
/**
|
||||
* Clear the connection string (resets Dialect)
|
||||
*/
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
ForceDialect.none()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields is blank when given no fields')
|
||||
void byFieldsBlankIfEmpty() {
|
||||
assertEquals '', Where.byFields(List.of())
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates one numeric field | PostgreSQL')
|
||||
void byFieldsOneFieldPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "(data->>'it')::numeric = :that", Where.byFields(List.of(Field.equal('it', 9, ':that')))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates one alphanumeric field | PostgreSQL')
|
||||
void byFieldsOneAlphaFieldPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "data->>'it' = :that", Where.byFields(List.of(Field.equal('it', '', ':that')))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates one field | SQLite')
|
||||
void byFieldsOneFieldSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals "data->>'it' = :that", Where.byFields(List.of(Field.equal('it', '', ':that')))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates multiple fields w/ default match | PostgreSQL')
|
||||
void byFieldsMultipleDefaultPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("data->>'1' = :one AND (data->>'2')::numeric = :two AND data->>'3' = :three",
|
||||
Where.byFields(
|
||||
List.of(Field.equal('1', '', ':one'), Field.equal('2', 0L, ':two'),
|
||||
Field.equal('3', '', ':three'))))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates multiple fields w/ default match | SQLite')
|
||||
void byFieldsMultipleDefaultSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("data->>'1' = :one AND data->>'2' = :two AND data->>'3' = :three",
|
||||
Where.byFields(
|
||||
List.of(Field.equal('1', '', ':one'), Field.equal('2', 0L, ':two'),
|
||||
Field.equal('3', '', ':three'))))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates multiple fields w/ ANY match | PostgreSQL')
|
||||
void byFieldsMultipleAnyPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals("data->>'1' = :one OR (data->>'2')::numeric = :two OR data->>'3' = :three",
|
||||
Where.byFields(
|
||||
List.of(Field.equal('1', '', ':one'), Field.equal('2', 0L, ':two'),
|
||||
Field.equal('3', '', ':three')),
|
||||
FieldMatch.ANY))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields generates multiple fields w/ ANY match | SQLite')
|
||||
void byFieldsMultipleAnySQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals("data->>'1' = :one OR data->>'2' = :two OR data->>'3' = :three",
|
||||
Where.byFields(
|
||||
List.of(Field.equal('1', '', ':one'), Field.equal('2', 0L, ':two'),
|
||||
Field.equal('3', '', ':three')),
|
||||
FieldMatch.ANY))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates defaults for alphanumeric key | PostgreSQL')
|
||||
void byIdDefaultAlphaPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "data->>'id' = :id", Where.byId()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates defaults for numeric key | PostgreSQL')
|
||||
void byIdDefaultNumericPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "(data->>'id')::numeric = :id", Where.byId(":id", 5)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates defaults | SQLite')
|
||||
void byIdDefaultSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals "data->>'id' = :id", Where.byId()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates named ID | PostgreSQL')
|
||||
void byIdDefaultNamedPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals "data->>'id' = :key", Where.byId(':key')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId generates named ID | SQLite')
|
||||
void byIdDefaultNamedSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertEquals "data->>'id' = :key", Where.byId(':key')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('jsonContains generates defaults | PostgreSQL')
|
||||
void jsonContainsDefaultPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals 'data @> :criteria', Where.jsonContains()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('jsonContains generates named parameter | PostgreSQL')
|
||||
void jsonContainsNamedPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals 'data @> :it', Where.jsonContains(':it')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('jsonContains fails | SQLite')
|
||||
void jsonContainsFailsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { Where.jsonContains() }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('jsonPathMatches generates defaults | PostgreSQL')
|
||||
void jsonPathMatchDefaultPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals 'jsonb_path_exists(data, :path::jsonpath)', Where.jsonPathMatches()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('jsonPathMatches generates named parameter | PostgreSQL')
|
||||
void jsonPathMatchNamedPostgres() {
|
||||
ForceDialect.postgres()
|
||||
assertEquals 'jsonb_path_exists(data, :jp::jsonpath)', Where.jsonPathMatches(':jp')
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('jsonPathMatches fails | SQLite')
|
||||
void jsonPathFailsSQLite() {
|
||||
ForceDialect.sqlite()
|
||||
assertThrows(DocumentException) { Where.jsonPathMatches() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
class ArrayDocument {
|
||||
|
||||
String id
|
||||
List<String> values
|
||||
|
||||
ArrayDocument(String id = '', List<String> values = List.of()) {
|
||||
this.id = id
|
||||
this.values = values
|
||||
}
|
||||
|
||||
/** A set of documents used for integration tests */
|
||||
static List<ArrayDocument> testDocuments = List.of(
|
||||
new ArrayDocument("first", List.of("a", "b", "c")),
|
||||
new ArrayDocument("second", List.of("c", "d", "e")),
|
||||
new ArrayDocument("third", List.of("x", "y", "z")))
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Field
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class CountFunctions {
|
||||
|
||||
static void all(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should have been 5 documents in the table'
|
||||
}
|
||||
|
||||
static void byFieldsNumeric(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(3L, db.conn.countByFields(TEST_TABLE, List.of(Field.between('numValue', 10, 20))),
|
||||
'There should have been 3 matching documents')
|
||||
}
|
||||
|
||||
static void byFieldsAlpha(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(1L, db.conn.countByFields(TEST_TABLE, List.of(Field.between('value', 'aardvark', 'apple'))),
|
||||
'There should have been 1 matching document')
|
||||
}
|
||||
|
||||
static void byContainsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(2L, db.conn.countByContains(TEST_TABLE, Map.of('value', 'purple')),
|
||||
'There should have been 2 matching documents')
|
||||
}
|
||||
|
||||
static void byContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(0L, db.conn.countByContains(TEST_TABLE, Map.of('value', 'magenta')),
|
||||
'There should have been no matching documents')
|
||||
}
|
||||
|
||||
static void byJsonPathMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(2L, db.conn.countByJsonPath(TEST_TABLE, '$.numValue ? (@ < 5)'),
|
||||
'There should have been 2 matching documents')
|
||||
}
|
||||
|
||||
static void byJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(0L, db.conn.countByJsonPath(TEST_TABLE, '$.numValue ? (@ > 100)'),
|
||||
'There should have been no matching documents')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Configuration
|
||||
import solutions.bitbadger.documents.Field
|
||||
import solutions.bitbadger.documents.Parameter
|
||||
import solutions.bitbadger.documents.ParameterType
|
||||
import solutions.bitbadger.documents.java.Results
|
||||
import solutions.bitbadger.documents.query.CountQuery
|
||||
import solutions.bitbadger.documents.query.DeleteQuery
|
||||
import solutions.bitbadger.documents.query.FindQuery
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class CustomFunctions {
|
||||
|
||||
static void listEmpty(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.deleteByFields TEST_TABLE, List.of(Field.exists(Configuration.idField))
|
||||
def result = db.conn.customList FindQuery.all(TEST_TABLE), List.of(), JsonDocument, Results.&fromData
|
||||
assertEquals 0, result.size(), 'There should have been no results'
|
||||
}
|
||||
|
||||
static void listAll(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def result = db.conn.customList FindQuery.all(TEST_TABLE), List.of(), JsonDocument, Results.&fromData
|
||||
assertEquals 5, result.size(), 'There should have been 5 results'
|
||||
}
|
||||
|
||||
static void singleNone(ThrowawayDatabase db) {
|
||||
assertFalse(db.conn.customSingle(FindQuery.all(TEST_TABLE), List.of(), JsonDocument, Results.&fromData)
|
||||
.isPresent(),
|
||||
'There should not have been a document returned')
|
||||
|
||||
}
|
||||
|
||||
static void singleOne(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertTrue(db.conn.customSingle(FindQuery.all(TEST_TABLE), List.of(), JsonDocument, Results.&fromData)
|
||||
.isPresent(),
|
||||
'There should not have been a document returned')
|
||||
}
|
||||
|
||||
static void nonQueryChanges(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(5L, db.conn.customScalar(CountQuery.all(TEST_TABLE), List.of(), Long, Results.&toCount),
|
||||
'There should have been 5 documents in the table')
|
||||
db.conn.customNonQuery("DELETE FROM $TEST_TABLE")
|
||||
assertEquals(0L, db.conn.customScalar(CountQuery.all(TEST_TABLE), List.of(), Long, Results.&toCount),
|
||||
'There should have been no documents in the table')
|
||||
}
|
||||
|
||||
static void nonQueryNoChanges(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(5L, db.conn.customScalar(CountQuery.all(TEST_TABLE), List.of(), Long, Results.&toCount),
|
||||
'There should have been 5 documents in the table')
|
||||
db.conn.customNonQuery(DeleteQuery.byId(TEST_TABLE, 'eighty-two'),
|
||||
List.of(new Parameter(':id', ParameterType.STRING, 'eighty-two')))
|
||||
assertEquals(5L, db.conn.customScalar(CountQuery.all(TEST_TABLE), List.of(), Long, Results.&toCount),
|
||||
'There should still have been 5 documents in the table')
|
||||
}
|
||||
|
||||
static void scalar(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(3L,
|
||||
db.conn.customScalar("SELECT 3 AS it FROM $TEST_TABLE LIMIT 1", List.of(), Long, Results.&toCount),
|
||||
'The number 3 should have been returned')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.DocumentIndex
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class DefinitionFunctions {
|
||||
|
||||
static void ensureTable(ThrowawayDatabase db) {
|
||||
assertFalse db.dbObjectExists('ensured'), 'The "ensured" table should not exist'
|
||||
assertFalse db.dbObjectExists('idx_ensured_key'), 'The PK index for the "ensured" table should not exist'
|
||||
db.conn.ensureTable 'ensured'
|
||||
assertTrue db.dbObjectExists('ensured'), 'The "ensured" table should exist'
|
||||
assertTrue db.dbObjectExists('idx_ensured_key'), 'The PK index for the "ensured" table should now exist'
|
||||
}
|
||||
|
||||
static void ensureFieldIndex(ThrowawayDatabase db) {
|
||||
assertFalse db.dbObjectExists("idx_${TEST_TABLE}_test"), 'The test index should not exist'
|
||||
db.conn.ensureFieldIndex TEST_TABLE, 'test', List.of('id', 'category')
|
||||
assertTrue db.dbObjectExists("idx_${TEST_TABLE}_test"), 'The test index should now exist'
|
||||
}
|
||||
|
||||
static void ensureDocumentIndexFull(ThrowawayDatabase db) {
|
||||
assertFalse db.dbObjectExists('doc_table'), 'The "doc_table" table should not exist'
|
||||
db.conn.ensureTable 'doc_table'
|
||||
assertTrue db.dbObjectExists('doc_table'), 'The "doc_table" table should exist'
|
||||
assertFalse db.dbObjectExists('idx_doc_table_document'), 'The document index should not exist'
|
||||
db.conn.ensureDocumentIndex 'doc_table', DocumentIndex.FULL
|
||||
assertTrue db.dbObjectExists('idx_doc_table_document'), 'The document index should exist'
|
||||
}
|
||||
|
||||
static void ensureDocumentIndexOptimized(ThrowawayDatabase db) {
|
||||
assertFalse db.dbObjectExists('doc_table'), 'The "doc_table" table should not exist'
|
||||
db.conn.ensureTable 'doc_table'
|
||||
assertTrue db.dbObjectExists('doc_table'), 'The "doc_table" table should exist'
|
||||
assertFalse db.dbObjectExists('idx_doc_table_document'), 'The document index should not exist'
|
||||
db.conn.ensureDocumentIndex 'doc_table', DocumentIndex.OPTIMIZED
|
||||
assertTrue db.dbObjectExists('idx_doc_table_document'), 'The document index should exist'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Field
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class DeleteFunctions {
|
||||
|
||||
static void byIdMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteById TEST_TABLE, 'four'
|
||||
assertEquals 4L, db.conn.countAll(TEST_TABLE), 'There should now be 4 documents in the table'
|
||||
}
|
||||
|
||||
static void byIdNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteById TEST_TABLE, 'negative four'
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should still be 5 documents in the table'
|
||||
}
|
||||
|
||||
static void byFieldsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteByFields TEST_TABLE, List.of(Field.notEqual('value', 'purple'))
|
||||
assertEquals 2L, db.conn.countAll(TEST_TABLE), 'There should now be 2 documents in the table'
|
||||
}
|
||||
|
||||
static void byFieldsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteByFields TEST_TABLE, List.of(Field.equal('value', 'crimson'))
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should still be 5 documents in the table'
|
||||
}
|
||||
|
||||
static void byContainsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteByContains TEST_TABLE, Map.of('value', 'purple')
|
||||
assertEquals 3L, db.conn.countAll(TEST_TABLE), 'There should now be 3 documents in the table'
|
||||
}
|
||||
|
||||
static void byContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteByContains TEST_TABLE, Map.of('target', 'acquired')
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should still be 5 documents in the table'
|
||||
}
|
||||
|
||||
static void byJsonPathMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteByJsonPath TEST_TABLE, '$.value ? (@ == "purple")'
|
||||
assertEquals 3L, db.conn.countAll(TEST_TABLE), 'There should now be 3 documents in the table'
|
||||
}
|
||||
|
||||
static void byJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should be 5 documents in the table'
|
||||
db.conn.deleteByJsonPath TEST_TABLE, '$.numValue ? (@ > 100)'
|
||||
assertEquals 5L, db.conn.countAll(TEST_TABLE), 'There should still be 5 documents in the table'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.AutoId
|
||||
import solutions.bitbadger.documents.Configuration
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
import solutions.bitbadger.documents.Field
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class DocumentFunctions {
|
||||
|
||||
static void insertDefault(ThrowawayDatabase db) {
|
||||
assertEquals 0L, db.conn.countAll(TEST_TABLE), 'There should be no documents in the table'
|
||||
def doc = new JsonDocument('turkey', 'yum', 5, new SubDocument('gobble', 'gobble!'))
|
||||
db.conn.insert TEST_TABLE, doc
|
||||
def after = db.conn.findAll TEST_TABLE, JsonDocument
|
||||
assertEquals 1, after.size(), 'There should be one document in the table'
|
||||
assertEquals doc.id, after[0].id, 'The document ID was not inserted correctly'
|
||||
assertEquals doc.value, after[0].value, 'The document value was not inserted correctly'
|
||||
assertEquals doc.numValue, after[0].numValue, 'The document numValue was not inserted correctly'
|
||||
assertNotNull doc.sub, "The subdocument was not inserted"
|
||||
assertEquals doc.sub.foo, after[0].sub.foo, 'The subdocument "foo" property was not inserted correctly'
|
||||
assertEquals doc.sub.bar, after[0].sub.bar, 'The subdocument "bar" property was not inserted correctly'
|
||||
}
|
||||
|
||||
static void insertDupe(ThrowawayDatabase db) {
|
||||
db.conn.insert TEST_TABLE, new JsonDocument('a', '', 0, null)
|
||||
assertThrows(DocumentException, () -> db.conn.insert(TEST_TABLE, new JsonDocument('a', 'b', 22, null)),
|
||||
'Inserting a document with a duplicate key should have thrown an exception')
|
||||
}
|
||||
|
||||
static void insertNumAutoId(ThrowawayDatabase db) {
|
||||
try {
|
||||
Configuration.autoIdStrategy = AutoId.NUMBER
|
||||
Configuration.idField = 'key'
|
||||
assertEquals 0L, db.conn.countAll(TEST_TABLE), 'There should be no documents in the table'
|
||||
|
||||
db.conn.insert TEST_TABLE, new NumIdDocument(0, 'one')
|
||||
db.conn.insert TEST_TABLE, new NumIdDocument(0, 'two')
|
||||
db.conn.insert TEST_TABLE, new NumIdDocument(77, 'three')
|
||||
db.conn.insert TEST_TABLE, new NumIdDocument(0, 'four')
|
||||
|
||||
def after = db.conn.findAll TEST_TABLE, NumIdDocument, List.of(Field.named('key'))
|
||||
assertEquals 4, after.size(), 'There should have been 4 documents returned'
|
||||
assertEquals('1|2|77|78',
|
||||
after*.key*.toString().inject('') { acc, it -> acc == '' ? it : "$acc|$it" }.toString(),
|
||||
'The IDs were not generated correctly')
|
||||
} finally {
|
||||
Configuration.autoIdStrategy = AutoId.DISABLED
|
||||
Configuration.idField = 'id'
|
||||
}
|
||||
}
|
||||
|
||||
static void insertUUIDAutoId(ThrowawayDatabase db) {
|
||||
try {
|
||||
Configuration.autoIdStrategy = AutoId.UUID
|
||||
assertEquals 0L, db.conn.countAll(TEST_TABLE), 'There should be no documents in the table'
|
||||
|
||||
db.conn.insert TEST_TABLE, new JsonDocument('')
|
||||
|
||||
def after = db.conn.findAll TEST_TABLE, JsonDocument
|
||||
assertEquals 1, after.size(), 'There should have been 1 document returned'
|
||||
assertEquals 32, after[0].id.length(), 'The ID was not generated correctly'
|
||||
} finally {
|
||||
Configuration.autoIdStrategy = AutoId.DISABLED
|
||||
}
|
||||
}
|
||||
|
||||
static void insertStringAutoId(ThrowawayDatabase db) {
|
||||
try {
|
||||
Configuration.autoIdStrategy = AutoId.RANDOM_STRING
|
||||
assertEquals 0L, db.conn.countAll(TEST_TABLE), 'There should be no documents in the table'
|
||||
|
||||
db.conn.insert TEST_TABLE, new JsonDocument('')
|
||||
|
||||
Configuration.idStringLength = 21
|
||||
db.conn.insert TEST_TABLE, new JsonDocument('')
|
||||
|
||||
def after = db.conn.findAll TEST_TABLE, JsonDocument
|
||||
assertEquals 2, after.size(), 'There should have been 2 documents returned'
|
||||
assertEquals 16, after[0].id.length(), "The first document's ID was not generated correctly"
|
||||
assertEquals 21, after[1].id.length(), "The second document's ID was not generated correctly"
|
||||
} finally {
|
||||
Configuration.autoIdStrategy = AutoId.DISABLED
|
||||
Configuration.idStringLength = 16
|
||||
}
|
||||
}
|
||||
|
||||
static void saveMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.save TEST_TABLE, new JsonDocument('two', '', 44)
|
||||
def tryDoc = db.conn.findById TEST_TABLE, 'two', JsonDocument
|
||||
assertTrue tryDoc.isPresent(), 'There should have been a document returned'
|
||||
def doc = tryDoc.get()
|
||||
assertEquals 'two', doc.id, 'An incorrect document was returned'
|
||||
assertEquals '', doc.value, 'The "value" field was not updated'
|
||||
assertEquals 44, doc.numValue, 'The "numValue" field was not updated'
|
||||
assertNull doc.sub, 'The "sub" field was not updated'
|
||||
}
|
||||
|
||||
static void saveNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.save TEST_TABLE, new JsonDocument('test', '', 0, new SubDocument('a', 'b'))
|
||||
assertTrue(db.conn.findById(TEST_TABLE, 'test', JsonDocument).isPresent(),
|
||||
'The test document should have been saved')
|
||||
}
|
||||
|
||||
static void updateMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.update TEST_TABLE, 'one', new JsonDocument('one', 'howdy', 8, new SubDocument('y', 'z'))
|
||||
def tryDoc = db.conn.findById TEST_TABLE, 'one', JsonDocument
|
||||
assertTrue tryDoc.isPresent(), 'There should have been a document returned'
|
||||
def doc = tryDoc.get()
|
||||
assertEquals 'one', doc.id, 'An incorrect document was returned'
|
||||
assertEquals 'howdy', doc.value, 'The "value" field was not updated'
|
||||
assertEquals 8, doc.numValue, 'The "numValue" field was not updated'
|
||||
assertNotNull doc.sub, 'The sub-document should not be null'
|
||||
assertEquals 'y', doc.sub.foo, 'The sub-document "foo" field was not updated'
|
||||
assertEquals 'z', doc.sub.bar, 'The sub-document "bar" field was not updated'
|
||||
}
|
||||
|
||||
static void updateNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsById(TEST_TABLE, 'two-hundred')
|
||||
db.conn.update TEST_TABLE, 'two-hundred', new JsonDocument('two-hundred', '', 200)
|
||||
assertFalse db.conn.existsById(TEST_TABLE, 'two-hundred')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Field
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class ExistsFunctions {
|
||||
|
||||
static void byIdMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertTrue db.conn.existsById(TEST_TABLE, 'three'), 'The document with ID "three" should exist'
|
||||
}
|
||||
|
||||
static void byIdNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsById(TEST_TABLE, 'seven'), 'The document with ID "seven" should not exist'
|
||||
}
|
||||
|
||||
static void byFieldsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertTrue(db.conn.existsByFields(TEST_TABLE, List.of(Field.equal('numValue', 10))),
|
||||
'Matching documents should have been found')
|
||||
}
|
||||
|
||||
static void byFieldsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.existsByFields(TEST_TABLE, List.of(Field.equal('nothing', 'none'))),
|
||||
'No matching documents should have been found')
|
||||
}
|
||||
|
||||
static void byContainsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertTrue(db.conn.existsByContains(TEST_TABLE, Map.of('value', 'purple')),
|
||||
'Matching documents should have been found')
|
||||
}
|
||||
|
||||
static void byContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.existsByContains(TEST_TABLE, Map.of('value', 'violet')),
|
||||
'Matching documents should not have been found')
|
||||
}
|
||||
|
||||
static void byJsonPathMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertTrue(db.conn.existsByJsonPath(TEST_TABLE, '$.numValue ? (@ == 10)'),
|
||||
'Matching documents should have been found')
|
||||
}
|
||||
|
||||
static void byJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.existsByJsonPath(TEST_TABLE, '$.numValue ? (@ == 10.1)'),
|
||||
'Matching documents should not have been found')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Configuration
|
||||
import solutions.bitbadger.documents.Field
|
||||
import solutions.bitbadger.documents.FieldMatch
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class FindFunctions {
|
||||
|
||||
private static String docIds(List<JsonDocument> docs) {
|
||||
return docs*.id.inject('') { acc, it -> acc == '' ? it : "$acc|$it" }
|
||||
}
|
||||
|
||||
static void allDefault(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals 5, db.conn.findAll(TEST_TABLE, JsonDocument).size(), 'There should have been 5 documents returned'
|
||||
}
|
||||
|
||||
static void allAscending(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findAll TEST_TABLE, JsonDocument, List.of(Field.named('id'))
|
||||
assertEquals 5, docs.size(), 'There should have been 5 documents returned'
|
||||
assertEquals 'five|four|one|three|two', docIds(docs), 'The documents were not ordered correctly'
|
||||
}
|
||||
|
||||
static void allDescending(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findAll TEST_TABLE, JsonDocument, List.of(Field.named('id DESC'))
|
||||
assertEquals 5, docs.size(), 'There should have been 5 documents returned'
|
||||
assertEquals 'two|three|one|four|five', docIds(docs), 'The documents were not ordered correctly'
|
||||
}
|
||||
|
||||
static void allNumOrder(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findAll(TEST_TABLE, JsonDocument,
|
||||
List.of(Field.named('sub.foo NULLS LAST'), Field.named('n:numValue')))
|
||||
assertEquals 5, docs.size(), 'There should have been 5 documents returned'
|
||||
assertEquals 'two|four|one|three|five', docIds(docs), 'The documents were not ordered correctly'
|
||||
}
|
||||
|
||||
static void allEmpty(ThrowawayDatabase db) {
|
||||
assertEquals 0, db.conn.findAll(TEST_TABLE, JsonDocument).size(), 'There should have been no documents returned'
|
||||
}
|
||||
|
||||
static void byIdString(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findById TEST_TABLE, 'two', JsonDocument
|
||||
assertTrue doc.isPresent(), 'The document should have been returned'
|
||||
assertEquals 'two', doc.get().id, 'An incorrect document was returned'
|
||||
}
|
||||
|
||||
static void byIdNumber(ThrowawayDatabase db) {
|
||||
Configuration.idField = 'key'
|
||||
try {
|
||||
db.conn.insert TEST_TABLE, new NumIdDocument(18, 'howdy')
|
||||
assertTrue(db.conn.findById(TEST_TABLE, 18, NumIdDocument).isPresent(),
|
||||
'The document should have been returned')
|
||||
} finally {
|
||||
Configuration.idField = 'id'
|
||||
}
|
||||
}
|
||||
|
||||
static void byIdNotFound(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.findById(TEST_TABLE, 'x', JsonDocument).isPresent(),
|
||||
'There should have been no document returned')
|
||||
}
|
||||
|
||||
static void byFieldsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByFields(TEST_TABLE,
|
||||
List.of(Field.any('value', List.of('blue', 'purple')), Field.exists('sub')), JsonDocument,
|
||||
FieldMatch.ALL)
|
||||
assertEquals 1, docs.size(), 'There should have been a document returned'
|
||||
assertEquals 'four', docs[0].id, 'The incorrect document was returned'
|
||||
}
|
||||
|
||||
static void byFieldsMatchOrdered(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByFields(TEST_TABLE, List.of(Field.equal('value', 'purple')), JsonDocument, null,
|
||||
List.of(Field.named('id')))
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
assertEquals 'five|four', docIds(docs), 'The documents were not ordered correctly'
|
||||
}
|
||||
|
||||
static void byFieldsMatchNumIn(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByFields TEST_TABLE, List.of(Field.any('numValue', List.of(2, 4, 6, 8))), JsonDocument
|
||||
assertEquals 1, docs.size(), 'There should have been a document returned'
|
||||
assertEquals 'three', docs[0].id, 'The incorrect document was returned'
|
||||
}
|
||||
|
||||
static void byFieldsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(0, db.conn.findByFields(TEST_TABLE, List.of(Field.greater('numValue', 100)), JsonDocument).size(),
|
||||
'There should have been no documents returned')
|
||||
}
|
||||
|
||||
static void byFieldsMatchInArray(ThrowawayDatabase db) {
|
||||
ArrayDocument.testDocuments.forEach { db.conn.insert TEST_TABLE, it }
|
||||
def docs = db.conn.findByFields(TEST_TABLE, List.of(Field.inArray('values', TEST_TABLE, List.of('c'))),
|
||||
ArrayDocument)
|
||||
assertEquals 2, docs.size(), 'There should have been two documents returned'
|
||||
assertTrue(List.of('first', 'second').contains(docs[0].id),
|
||||
"An incorrect document was returned (${docs[0].id})")
|
||||
assertTrue(List.of('first', 'second').contains(docs[1].id),
|
||||
"An incorrect document was returned (${docs[1].id})")
|
||||
}
|
||||
|
||||
static void byFieldsNoMatchInArray(ThrowawayDatabase db) {
|
||||
ArrayDocument.testDocuments.forEach { db.conn.insert TEST_TABLE, it }
|
||||
assertEquals(0,
|
||||
db.conn.findByFields(TEST_TABLE, List.of(Field.inArray('values', TEST_TABLE, List.of('j'))),
|
||||
ArrayDocument).size(),
|
||||
'There should have been no documents returned')
|
||||
}
|
||||
|
||||
static void byContainsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByContains TEST_TABLE, Map.of('value', 'purple'), JsonDocument
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
assertTrue List.of('four', 'five').contains(docs[0].id), "An incorrect document was returned (${docs[0].id})"
|
||||
assertTrue List.of('four', 'five').contains(docs[1].id), "An incorrect document was returned (${docs[1].id})"
|
||||
}
|
||||
|
||||
static void byContainsMatchOrdered(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByContains(TEST_TABLE, Map.of('sub', Map.of('foo', 'green')), JsonDocument,
|
||||
List.of(Field.named('value')))
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
assertEquals 'two|four', docIds(docs), 'The documents were not ordered correctly'
|
||||
}
|
||||
|
||||
static void byContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(0, db.conn.findByContains(TEST_TABLE, Map.of('value', 'indigo'), JsonDocument).size(),
|
||||
'There should have been no documents returned')
|
||||
}
|
||||
|
||||
static void byJsonPathMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByJsonPath TEST_TABLE, '$.numValue ? (@ > 10)', JsonDocument
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
assertTrue List.of('four', 'five').contains(docs[0].id), "An incorrect document was returned (${docs[0].id})"
|
||||
assertTrue List.of('four', 'five').contains(docs[1].id), "An incorrect document was returned (${docs[1].id})"
|
||||
}
|
||||
|
||||
static void byJsonPathMatchOrdered(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def docs = db.conn.findByJsonPath TEST_TABLE, '$.numValue ? (@ > 10)', JsonDocument, List.of(Field.named('id'))
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
assertEquals 'five|four', docIds(docs), 'The documents were not ordered correctly'
|
||||
}
|
||||
|
||||
static void byJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertEquals(0, db.conn.findByJsonPath(TEST_TABLE, '$.numValue ? (@ > 100)', JsonDocument).size(),
|
||||
'There should have been no documents returned')
|
||||
}
|
||||
|
||||
static void firstByFieldsMatchOne(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByFields TEST_TABLE, List.of(Field.equal('value', 'another')), JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'two', doc.get().id, 'The incorrect document was returned'
|
||||
}
|
||||
|
||||
static void firstByFieldsMatchMany(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByFields TEST_TABLE, List.of(Field.equal('sub.foo', 'green')), JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertTrue List.of('two', 'four').contains(doc.get().id), "An incorrect document was returned (${doc.get().id})"
|
||||
}
|
||||
|
||||
static void firstByFieldsMatchOrdered(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByFields(TEST_TABLE, List.of(Field.equal('sub.foo', 'green')), JsonDocument, null,
|
||||
List.of(Field.named('n:numValue DESC')))
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'four', doc.get().id, 'An incorrect document was returned'
|
||||
}
|
||||
|
||||
static void firstByFieldsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.findFirstByFields(TEST_TABLE, List.of(Field.equal('value', 'absent')), JsonDocument)
|
||||
.isPresent(),
|
||||
'There should have been no document returned')
|
||||
}
|
||||
|
||||
static void firstByContainsMatchOne(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByContains TEST_TABLE, Map.of('value', 'FIRST!'), JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'one', doc.get().id, 'An incorrect document was returned'
|
||||
}
|
||||
|
||||
static void firstByContainsMatchMany(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByContains TEST_TABLE, Map.of('value', 'purple'), JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertTrue(List.of('four', 'five').contains(doc.get().id),
|
||||
"An incorrect document was returned (${doc.get().id})")
|
||||
}
|
||||
|
||||
static void firstByContainsMatchOrdered(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByContains(TEST_TABLE, Map.of('value', 'purple'), JsonDocument,
|
||||
List.of(Field.named('sub.bar NULLS FIRST')))
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'five', doc.get().id, 'An incorrect document was returned'
|
||||
}
|
||||
|
||||
static void firstByContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.findFirstByContains(TEST_TABLE, Map.of('value', 'indigo'), JsonDocument).isPresent(),
|
||||
'There should have been no document returned')
|
||||
}
|
||||
|
||||
static void firstByJsonPathMatchOne(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByJsonPath TEST_TABLE, '$.numValue ? (@ == 10)', JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'two', doc.get().id, 'An incorrect document was returned'
|
||||
}
|
||||
|
||||
static void firstByJsonPathMatchMany(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByJsonPath TEST_TABLE, '$.numValue ? (@ > 10)', JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertTrue(List.of('four', 'five').contains(doc.get().id),
|
||||
"An incorrect document was returned (${doc.get().id})")
|
||||
}
|
||||
|
||||
static void firstByJsonPathMatchOrdered(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def doc = db.conn.findFirstByJsonPath(TEST_TABLE, '$.numValue ? (@ > 10)', JsonDocument,
|
||||
List.of(Field.named('id DESC')))
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'four', doc.get().id, 'An incorrect document was returned'
|
||||
}
|
||||
|
||||
static void firstByJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse(db.conn.findFirstByJsonPath(TEST_TABLE, '$.numValue ? (@ > 100)', JsonDocument).isPresent(),
|
||||
'There should have been no document returned')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import solutions.bitbadger.documents.DocumentSerializer
|
||||
|
||||
/**
|
||||
* A JSON serializer using Jackson's default options
|
||||
*/
|
||||
class JacksonDocumentSerializer implements DocumentSerializer {
|
||||
|
||||
private def mapper = new ObjectMapper()
|
||||
|
||||
@Override
|
||||
def <TDoc> String serialize(TDoc document) {
|
||||
return mapper.writeValueAsString(document)
|
||||
}
|
||||
|
||||
@Override
|
||||
def <TDoc> TDoc deserialize(String json, Class<TDoc> clazz) {
|
||||
return mapper.readValue(json, clazz)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
class JsonDocument {
|
||||
String id
|
||||
String value
|
||||
int numValue
|
||||
SubDocument sub
|
||||
|
||||
JsonDocument(String id = null, String value = "", int numValue = 0, SubDocument sub = null) {
|
||||
this.id = id
|
||||
this.value = value
|
||||
this.numValue = numValue
|
||||
this.sub = sub
|
||||
}
|
||||
|
||||
private static final List<JsonDocument> testDocuments = List.of(
|
||||
new JsonDocument("one", "FIRST!", 0),
|
||||
new JsonDocument("two", "another", 10, new SubDocument("green", "blue")),
|
||||
new JsonDocument("three", "", 4),
|
||||
new JsonDocument("four", "purple", 17, new SubDocument("green", "red")),
|
||||
new JsonDocument("five", "purple", 18))
|
||||
|
||||
static void load(ThrowawayDatabase db, String tableName = TEST_TABLE) {
|
||||
testDocuments.forEach { db.conn.insert(tableName, it) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
class NumIdDocument {
|
||||
int key
|
||||
String value
|
||||
|
||||
NumIdDocument(int key = 0, String value = "") {
|
||||
this.key = key
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Field
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class PatchFunctions {
|
||||
|
||||
static void byIdMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.patchById TEST_TABLE, 'one', Map.of('numValue', 44)
|
||||
def doc = db.conn.findById TEST_TABLE, 'one', JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'one', doc.get().id, 'An incorrect document was returned'
|
||||
assertEquals 44, doc.get().numValue, 'The document was not patched'
|
||||
}
|
||||
|
||||
static void byIdNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsById(TEST_TABLE, 'forty-seven'), 'Document with ID "forty-seven" should not exist'
|
||||
db.conn.patchById TEST_TABLE, 'forty-seven', Map.of('foo', 'green') // no exception = pass
|
||||
}
|
||||
|
||||
static void byFieldsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.patchByFields TEST_TABLE, List.of(Field.equal('value', 'purple')), Map.of('numValue', 77)
|
||||
assertEquals(2, db.conn.countByFields(TEST_TABLE, List.of(Field.equal('numValue', 77))),
|
||||
'There should have been 2 documents with numeric value 77')
|
||||
}
|
||||
|
||||
static void byFieldsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def fields = List.of Field.equal('value', 'burgundy')
|
||||
assertFalse db.conn.existsByFields(TEST_TABLE, fields), 'There should be no documents with value of "burgundy"'
|
||||
db.conn.patchByFields TEST_TABLE, fields, Map.of('foo', 'green') // no exception = pass
|
||||
}
|
||||
|
||||
static void byContainsMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def contains = Map.of 'value', 'another'
|
||||
db.conn.patchByContains TEST_TABLE, contains, Map.of('numValue', 12)
|
||||
def doc = db.conn.findFirstByContains TEST_TABLE, contains, JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals 'two', doc.get().id, 'The incorrect document was returned'
|
||||
assertEquals 12, doc.get().numValue, 'The document was not updated'
|
||||
}
|
||||
|
||||
static void byContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def contains = Map.of 'value', 'updated'
|
||||
assertFalse db.conn.existsByContains(TEST_TABLE, contains), 'There should be no matching documents'
|
||||
db.conn.patchByContains TEST_TABLE, contains, Map.of('sub.foo', 'green') // no exception = pass
|
||||
}
|
||||
|
||||
static void byJsonPathMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def path = '$.numValue ? (@ > 10)'
|
||||
db.conn.patchByJsonPath TEST_TABLE, path, Map.of('value', 'blue')
|
||||
def docs = db.conn.findByJsonPath TEST_TABLE, path, JsonDocument
|
||||
assertEquals 2, docs.size(), 'There should have been two documents returned'
|
||||
docs.forEach {
|
||||
assertTrue List.of('four', 'five').contains(it.id), "An incorrect document was returned (${it.id})"
|
||||
assertEquals 'blue', it.value, "The value for ID ${it.id} was incorrect"
|
||||
}
|
||||
}
|
||||
|
||||
static void byJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def path = '$.numValue ? (@ > 100)'
|
||||
assertFalse(db.conn.existsByJsonPath(TEST_TABLE, path),
|
||||
'There should be no documents with numeric values over 100')
|
||||
db.conn.patchByJsonPath TEST_TABLE, path, Map.of('value', 'blue') // no exception = pass
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Configuration
|
||||
import solutions.bitbadger.documents.Parameter
|
||||
import solutions.bitbadger.documents.ParameterType
|
||||
import solutions.bitbadger.documents.java.DocumentConfig
|
||||
import solutions.bitbadger.documents.java.Results
|
||||
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
/**
|
||||
* A wrapper for a throwaway PostgreSQL database
|
||||
*/
|
||||
class PgDB implements ThrowawayDatabase {
|
||||
|
||||
PgDB() {
|
||||
Configuration.setConnectionString connString('postgres')
|
||||
Configuration.dbConn().withCloseable { it.customNonQuery "CREATE DATABASE $dbName" }
|
||||
|
||||
Configuration.setConnectionString connString(dbName)
|
||||
conn = Configuration.dbConn()
|
||||
conn.ensureTable TEST_TABLE
|
||||
|
||||
// Use a Jackson-based document serializer for testing
|
||||
DocumentConfig.serializer = new JacksonDocumentSerializer()
|
||||
}
|
||||
|
||||
void close() {
|
||||
conn.close()
|
||||
Configuration.setConnectionString connString('postgres')
|
||||
Configuration.dbConn().withCloseable { it.customNonQuery "DROP DATABASE $dbName" }
|
||||
Configuration.setConnectionString null
|
||||
}
|
||||
|
||||
boolean dbObjectExists(String name) {
|
||||
conn.customScalar('SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = :name) AS it',
|
||||
List.of(new Parameter(':name', ParameterType.STRING, name)), Boolean, Results.&toExists)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a connection string for the given database
|
||||
*
|
||||
* @param database The database to which the library should connect
|
||||
* @return The connection string for the database
|
||||
*/
|
||||
private static String connString(String database) {
|
||||
return "jdbc:postgresql://localhost/$database?user=postgres&password=postgres"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Count` object / `count*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Count')
|
||||
final class PostgreSQLCountIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('all counts all documents')
|
||||
void all() {
|
||||
new PgDB().withCloseable CountFunctions.&all
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields counts documents by a numeric value')
|
||||
void byFieldsNumeric() {
|
||||
new PgDB().withCloseable CountFunctions.&byFieldsNumeric
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields counts documents by a alphanumeric value')
|
||||
void byFieldsAlpha() {
|
||||
new PgDB().withCloseable CountFunctions.&byFieldsAlpha
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains counts documents when matches are found')
|
||||
void byContainsMatch() {
|
||||
new PgDB().withCloseable CountFunctions.&byContainsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains counts documents when no matches are found')
|
||||
void byContainsNoMatch() {
|
||||
new PgDB().withCloseable CountFunctions.&byContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath counts documents when matches are found')
|
||||
void byJsonPathMatch() {
|
||||
new PgDB().withCloseable CountFunctions.&byJsonPathMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath counts documents when no matches are found')
|
||||
void byJsonPathNoMatch() {
|
||||
new PgDB().withCloseable CountFunctions.&byJsonPathNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Custom` object / `custom*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Custom')
|
||||
final class PostgreSQLCustomIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('list succeeds with empty list')
|
||||
void listEmpty() {
|
||||
new PgDB().withCloseable CustomFunctions.&listEmpty
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('list succeeds with a non-empty list')
|
||||
void listAll() {
|
||||
new PgDB().withCloseable CustomFunctions.&listAll
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('single succeeds when document not found')
|
||||
void singleNone() {
|
||||
new PgDB().withCloseable CustomFunctions.&singleNone
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('single succeeds when a document is found')
|
||||
void singleOne() {
|
||||
new PgDB().withCloseable CustomFunctions.&singleOne
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nonQuery makes changes')
|
||||
void nonQueryChanges() {
|
||||
new PgDB().withCloseable CustomFunctions.&nonQueryChanges
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nonQuery makes no changes when where clause matches nothing')
|
||||
void nonQueryNoChanges() {
|
||||
new PgDB().withCloseable CustomFunctions.&nonQueryNoChanges
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('scalar succeeds')
|
||||
void scalar() {
|
||||
new PgDB().withCloseable CustomFunctions.&scalar
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Definition` object / `ensure*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Definition')
|
||||
final class PostgreSQLDefinitionIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureTable creates table and index')
|
||||
void ensureTable() {
|
||||
new PgDB().withCloseable DefinitionFunctions.&ensureTable
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureFieldIndex creates an index')
|
||||
void ensureFieldIndex() {
|
||||
new PgDB().withCloseable DefinitionFunctions.&ensureFieldIndex
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureDocumentIndex creates a full index')
|
||||
void ensureDocumentIndexFull() {
|
||||
new PgDB().withCloseable DefinitionFunctions.&ensureDocumentIndexFull
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureDocumentIndex creates an optimized index')
|
||||
void ensureDocumentIndexOptimized() {
|
||||
new PgDB().withCloseable DefinitionFunctions.&ensureDocumentIndexOptimized
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Delete` object / `deleteBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Delete')
|
||||
final class PostgreSQLDeleteIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId deletes a matching ID')
|
||||
void byIdMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byIdMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds when no ID matches')
|
||||
void byIdNoMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields deletes matching documents')
|
||||
void byFieldsMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains deletes matching documents')
|
||||
void byContainsMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byContainsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains succeeds when no documents match')
|
||||
void byContainsNoMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath deletes matching documents')
|
||||
void byJsonPathMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byJsonPathMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath succeeds when no documents match')
|
||||
void byJsonPathNoMatch() {
|
||||
new PgDB().withCloseable DeleteFunctions.&byJsonPathNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Document')
|
||||
final class PostgreSQLDocumentIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('insert works with default values')
|
||||
void insertDefault() {
|
||||
new PgDB().withCloseable DocumentFunctions.&insertDefault
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert fails with duplicate key')
|
||||
void insertDupe() {
|
||||
new PgDB().withCloseable DocumentFunctions.&insertDupe
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert succeeds with numeric auto IDs')
|
||||
void insertNumAutoId() {
|
||||
new PgDB().withCloseable DocumentFunctions.&insertNumAutoId
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert succeeds with UUID auto ID')
|
||||
void insertUUIDAutoId() {
|
||||
new PgDB().withCloseable DocumentFunctions.&insertUUIDAutoId
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert succeeds with random string auto ID')
|
||||
void insertStringAutoId() {
|
||||
new PgDB().withCloseable DocumentFunctions.&insertStringAutoId
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('save updates an existing document')
|
||||
void saveMatch() {
|
||||
new PgDB().withCloseable DocumentFunctions.&saveMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('save inserts a new document')
|
||||
void saveNoMatch() {
|
||||
new PgDB().withCloseable DocumentFunctions.&saveNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('update replaces an existing document')
|
||||
void updateMatch() {
|
||||
new PgDB().withCloseable DocumentFunctions.&updateMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('update succeeds when no document exists')
|
||||
void updateNoMatch() {
|
||||
new PgDB().withCloseable DocumentFunctions.&updateNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Exists` object / `existsBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Exists')
|
||||
final class PostgreSQLExistsIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId returns true when a document matches the ID')
|
||||
void byIdMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byIdMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId returns false when no document matches the ID')
|
||||
void byIdNoMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields returns true when documents match')
|
||||
void byFieldsMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields returns false when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains returns true when documents match')
|
||||
void byContainsMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byContainsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains returns false when no documents match')
|
||||
void byContainsNoMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath returns true when documents match')
|
||||
void byJsonPathMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byJsonPathMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath returns false when no documents match')
|
||||
void byJsonPathNoMatch() {
|
||||
new PgDB().withCloseable ExistsFunctions.&byJsonPathNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Find` object / `find*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Find')
|
||||
final class PostgreSQLFindIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('all retrieves all documents')
|
||||
void allDefault() {
|
||||
new PgDB().withCloseable FindFunctions.&allDefault
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all sorts data ascending')
|
||||
void allAscending() {
|
||||
new PgDB().withCloseable FindFunctions.&allAscending
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all sorts data descending')
|
||||
void allDescending() {
|
||||
new PgDB().withCloseable FindFunctions.&allDescending
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all sorts data numerically')
|
||||
void allNumOrder() {
|
||||
new PgDB().withCloseable FindFunctions.&allNumOrder
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all succeeds with an empty table')
|
||||
void allEmpty() {
|
||||
new PgDB().withCloseable FindFunctions.&allEmpty
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId retrieves a document via a string ID')
|
||||
void byIdString() {
|
||||
new PgDB().withCloseable FindFunctions.&byIdString
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId retrieves a document via a numeric ID')
|
||||
void byIdNumber() {
|
||||
new PgDB().withCloseable FindFunctions.&byIdNumber
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId returns null when a matching ID is not found')
|
||||
void byIdNotFound() {
|
||||
new PgDB().withCloseable FindFunctions.&byIdNotFound
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves matching documents')
|
||||
void byFieldsMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves ordered matching documents')
|
||||
void byFieldsMatchOrdered() {
|
||||
new PgDB().withCloseable FindFunctions.&byFieldsMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves matching documents with a numeric IN clause')
|
||||
void byFieldsMatchNumIn() {
|
||||
new PgDB().withCloseable FindFunctions.&byFieldsMatchNumIn
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves matching documents with an IN_ARRAY comparison')
|
||||
void byFieldsMatchInArray() {
|
||||
new PgDB().withCloseable FindFunctions.&byFieldsMatchInArray
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match an IN_ARRAY comparison')
|
||||
void byFieldsNoMatchInArray() {
|
||||
new PgDB().withCloseable FindFunctions.&byFieldsNoMatchInArray
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains retrieves matching documents')
|
||||
void byContainsMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&byContainsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains retrieves ordered matching documents')
|
||||
void byContainsMatchOrdered() {
|
||||
new PgDB().withCloseable FindFunctions.&byContainsMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains succeeds when no documents match')
|
||||
void byContainsNoMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&byContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath retrieves matching documents')
|
||||
void byJsonPathMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&byJsonPathMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath retrieves ordered matching documents')
|
||||
void byJsonPathMatchOrdered() {
|
||||
new PgDB().withCloseable FindFunctions.&byJsonPathMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath succeeds when no documents match')
|
||||
void byJsonPathNoMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&byJsonPathNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields retrieves a matching document')
|
||||
void firstByFieldsMatchOne() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByFieldsMatchOne
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields retrieves a matching document among many')
|
||||
void firstByFieldsMatchMany() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByFieldsMatchMany
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields retrieves a matching document among many (ordered)')
|
||||
void firstByFieldsMatchOrdered() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByFieldsMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields returns null when no document matches')
|
||||
void firstByFieldsNoMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByContains retrieves a matching document')
|
||||
void firstByContainsMatchOne() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByContainsMatchOne
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByContains retrieves a matching document among many')
|
||||
void firstByContainsMatchMany() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByContainsMatchMany
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByContains retrieves a matching document among many (ordered)')
|
||||
void firstByContainsMatchOrdered() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByContainsMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByContains returns null when no document matches')
|
||||
void firstByContainsNoMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByJsonPath retrieves a matching document')
|
||||
void firstByJsonPathMatchOne() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByJsonPathMatchOne
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByJsonPath retrieves a matching document among many')
|
||||
void firstByJsonPathMatchMany() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByJsonPathMatchMany
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByJsonPath retrieves a matching document among many (ordered)')
|
||||
void firstByJsonPathMatchOrdered() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByJsonPathMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByJsonPath returns null when no document matches')
|
||||
void firstByJsonPathNoMatch() {
|
||||
new PgDB().withCloseable FindFunctions.&firstByJsonPathNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `Patch` object / `patchBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: Patch')
|
||||
final class PostgreSQLPatchIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId patches an existing document')
|
||||
void byIdMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byIdMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds for a non-existent document')
|
||||
void byIdNoMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields patches matching document')
|
||||
void byFieldsMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains patches matching document')
|
||||
void byContainsMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byContainsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains succeeds when no documents match')
|
||||
void byContainsNoMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath patches matching document')
|
||||
void byJsonPathMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byJsonPathMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath succeeds when no documents match')
|
||||
void byJsonPathNoMatch() {
|
||||
new PgDB().withCloseable PatchFunctions.&byJsonPathNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `RemoveFields` object / `removeFieldsBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | PostgreSQL: RemoveFields')
|
||||
final class PostgreSQLRemoveFieldsIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId removes fields from an existing document')
|
||||
void byIdMatchFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byIdMatchFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds when fields do not exist on an existing document')
|
||||
void byIdMatchNoFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byIdMatchNoFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds when no document exists')
|
||||
void byIdNoMatch() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields removes fields from matching documents')
|
||||
void byFieldsMatchFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byFieldsMatchFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when fields do not exist on matching documents')
|
||||
void byFieldsMatchNoFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byFieldsMatchNoFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no matching documents exist')
|
||||
void byFieldsNoMatch() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains removes fields from matching documents')
|
||||
void byContainsMatchFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byContainsMatchFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains succeeds when fields do not exist on matching documents')
|
||||
void byContainsMatchNoFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byContainsMatchNoFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains succeeds when no matching documents exist')
|
||||
void byContainsNoMatch() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byContainsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath removes fields from matching documents')
|
||||
void byJsonPathMatchFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byJsonPathMatchFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath succeeds when fields do not exist on matching documents')
|
||||
void byJsonPathMatchNoFields() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byJsonPathMatchNoFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath succeeds when no matching documents exist')
|
||||
void byJsonPathNoMatch() {
|
||||
new PgDB().withCloseable RemoveFieldsFunctions.&byJsonPathNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Field
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
final class RemoveFieldsFunctions {
|
||||
|
||||
static void byIdMatchFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
db.conn.removeFieldsById TEST_TABLE, 'two', List.of('sub', 'value')
|
||||
def doc = db.conn.findById TEST_TABLE, 'two', JsonDocument
|
||||
assertTrue doc.isPresent(), 'There should have been a document returned'
|
||||
assertEquals '', doc.get().value, 'The value should have been empty'
|
||||
assertNull doc.get().sub, 'The sub-document should have been removed'
|
||||
}
|
||||
|
||||
static void byIdMatchNoFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsByFields(TEST_TABLE, List.of(Field.exists('a_field_that_does_not_exist')))
|
||||
db.conn.removeFieldsById TEST_TABLE, 'one', List.of('a_field_that_does_not_exist') // no exception = pass
|
||||
}
|
||||
|
||||
static void byIdNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsById(TEST_TABLE, 'fifty')
|
||||
db.conn.removeFieldsById TEST_TABLE, 'fifty', List.of('sub') // no exception = pass
|
||||
}
|
||||
|
||||
static void byFieldsMatchFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def fields = List.of Field.equal('numValue', 17)
|
||||
db.conn.removeFieldsByFields TEST_TABLE, fields, List.of('sub')
|
||||
def doc = db.conn.findFirstByFields TEST_TABLE, fields, JsonDocument
|
||||
assertTrue doc.isPresent(), 'The document should have been returned'
|
||||
assertEquals 'four', doc.get().id, 'An incorrect document was returned'
|
||||
assertNull doc.get().sub, 'The sub-document should have been removed'
|
||||
}
|
||||
|
||||
static void byFieldsMatchNoFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsByFields(TEST_TABLE, List.of(Field.exists('nada')))
|
||||
db.conn.removeFieldsByFields TEST_TABLE, List.of(Field.equal('numValue', 17)), List.of('nada') // no exn = pass
|
||||
}
|
||||
|
||||
static void byFieldsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def fields = List.of Field.notEqual('missing', 'nope')
|
||||
assertFalse db.conn.existsByFields(TEST_TABLE, fields)
|
||||
db.conn.removeFieldsByFields TEST_TABLE, fields, List.of('value') // no exception = pass
|
||||
}
|
||||
|
||||
static void byContainsMatchFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def criteria = Map.of('sub', Map.of('foo', 'green'))
|
||||
db.conn.removeFieldsByContains TEST_TABLE, criteria, List.of('value')
|
||||
def docs = db.conn.findByContains TEST_TABLE, criteria, JsonDocument
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
docs.forEach {
|
||||
assertTrue List.of('two', 'four').contains(it.id), "An incorrect document was returned (${it.id})"
|
||||
assertEquals '', it.value, 'The value should have been empty'
|
||||
}
|
||||
}
|
||||
|
||||
static void byContainsMatchNoFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsByFields(TEST_TABLE, List.of(Field.exists('invalid_field')))
|
||||
db.conn.removeFieldsByContains TEST_TABLE, Map.of('sub', Map.of('foo', 'green')), List.of('invalid_field')
|
||||
// no exception = pass
|
||||
}
|
||||
|
||||
static void byContainsNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def contains = Map.of 'value', 'substantial'
|
||||
assertFalse db.conn.existsByContains(TEST_TABLE, contains)
|
||||
db.conn.removeFieldsByContains TEST_TABLE, contains, List.of('numValue')
|
||||
}
|
||||
|
||||
static void byJsonPathMatchFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def path = '$.value ? (@ == "purple")'
|
||||
db.conn.removeFieldsByJsonPath TEST_TABLE, path, List.of('sub')
|
||||
def docs = db.conn.findByJsonPath TEST_TABLE, path, JsonDocument
|
||||
assertEquals 2, docs.size(), 'There should have been 2 documents returned'
|
||||
docs.forEach {
|
||||
assertTrue List.of('four', 'five').contains(it.id), "An incorrect document was returned (${it.id})"
|
||||
assertNull it.sub, 'The sub-document should have been removed'
|
||||
}
|
||||
}
|
||||
|
||||
static void byJsonPathMatchNoFields(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
assertFalse db.conn.existsByFields(TEST_TABLE, List.of(Field.exists('submarine')))
|
||||
db.conn.removeFieldsByJsonPath TEST_TABLE, '$.value ? (@ == "purple")', List.of('submarine') // no exn = pass
|
||||
}
|
||||
|
||||
static void byJsonPathNoMatch(ThrowawayDatabase db) {
|
||||
JsonDocument.load db
|
||||
def path = '$.value ? (@ == "mauve")'
|
||||
assertFalse db.conn.existsByJsonPath(TEST_TABLE, path)
|
||||
db.conn.removeFieldsByJsonPath TEST_TABLE, path, List.of('value') // no exception = pass
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Count` object / `count*` connection extension functions
|
||||
*/
|
||||
@DisplayName("Groovy | SQLite: Count")
|
||||
final class SQLiteCountIT {
|
||||
|
||||
@Test
|
||||
@DisplayName("all counts all documents")
|
||||
void all() {
|
||||
new SQLiteDB().withCloseable CountFunctions.&all
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields counts documents by a numeric value")
|
||||
void byFieldsNumeric() {
|
||||
new SQLiteDB().withCloseable CountFunctions.&byFieldsNumeric
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields counts documents by a alphanumeric value")
|
||||
void byFieldsAlpha() {
|
||||
new SQLiteDB().withCloseable CountFunctions.&byFieldsAlpha
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("byContains fails")
|
||||
void byContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { CountFunctions.byContainsMatch db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("byJsonPath fails")
|
||||
void byJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { CountFunctions.byJsonPathMatch db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Custom` object / `custom*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Custom')
|
||||
final class SQLiteCustomIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('list succeeds with empty list')
|
||||
void listEmpty() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&listEmpty
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('list succeeds with a non-empty list')
|
||||
void listAll() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&listAll
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('single succeeds when document not found')
|
||||
void singleNone() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&singleNone
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('single succeeds when a document is found')
|
||||
void singleOne() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&singleOne
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nonQuery makes changes')
|
||||
void nonQueryChanges() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&nonQueryChanges
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('nonQuery makes no changes when where clause matches nothing')
|
||||
void nonQueryNoChanges() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&nonQueryNoChanges
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('scalar succeeds')
|
||||
void scalar() {
|
||||
new SQLiteDB().withCloseable CustomFunctions.&scalar
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.Configuration
|
||||
import solutions.bitbadger.documents.Parameter
|
||||
import solutions.bitbadger.documents.ParameterType
|
||||
import solutions.bitbadger.documents.java.DocumentConfig
|
||||
import solutions.bitbadger.documents.java.Results
|
||||
|
||||
import static solutions.bitbadger.documents.groovy.tests.Types.TEST_TABLE
|
||||
|
||||
/**
|
||||
* A wrapper for a throwaway SQLite database
|
||||
*/
|
||||
class SQLiteDB implements ThrowawayDatabase {
|
||||
|
||||
SQLiteDB() {
|
||||
Configuration.setConnectionString "jdbc:sqlite:${dbName}.db"
|
||||
conn = Configuration.dbConn()
|
||||
conn.ensureTable TEST_TABLE
|
||||
|
||||
// Use a Jackson-based document serializer for testing
|
||||
DocumentConfig.serializer = new JacksonDocumentSerializer()
|
||||
}
|
||||
|
||||
void close() {
|
||||
conn.close()
|
||||
new File("${dbName}.db").delete()
|
||||
Configuration.setConnectionString null
|
||||
}
|
||||
|
||||
boolean dbObjectExists(String name) {
|
||||
conn.customScalar("SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE name = :name) AS it",
|
||||
List.of(new Parameter(":name", ParameterType.STRING, name)), Boolean, Results.&toExists)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Definition` object / `ensure*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Definition')
|
||||
final class SQLiteDefinitionIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureTable creates table and index')
|
||||
void ensureTable() {
|
||||
new SQLiteDB().withCloseable DefinitionFunctions.&ensureTable
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureFieldIndex creates an index')
|
||||
void ensureFieldIndex() {
|
||||
new SQLiteDB().withCloseable DefinitionFunctions.&ensureFieldIndex
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureDocumentIndex fails for full index')
|
||||
void ensureDocumentIndexFull() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { DefinitionFunctions::ensureDocumentIndexFull db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('ensureDocumentIndex fails for optimized index')
|
||||
void ensureDocumentIndexOptimized() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { DefinitionFunctions::ensureDocumentIndexOptimized db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Delete` object / `deleteBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Delete')
|
||||
final class SQLiteDeleteIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId deletes a matching ID')
|
||||
void byIdMatch() {
|
||||
new SQLiteDB().withCloseable DeleteFunctions.&byIdMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds when no ID matches')
|
||||
void byIdNoMatch() {
|
||||
new SQLiteDB().withCloseable DeleteFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields deletes matching documents')
|
||||
void byFieldsMatch() {
|
||||
new SQLiteDB().withCloseable DeleteFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new SQLiteDB().withCloseable DeleteFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails')
|
||||
void byContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { DeleteFunctions.byContainsMatch db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails')
|
||||
void byJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { DeleteFunctions.byJsonPathMatch db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Document')
|
||||
final class SQLiteDocumentIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('insert works with default values')
|
||||
void insertDefault() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&insertDefault
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert fails with duplicate key')
|
||||
void insertDupe() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&insertDupe
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert succeeds with numeric auto IDs')
|
||||
void insertNumAutoId() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&insertNumAutoId
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert succeeds with UUID auto ID')
|
||||
void insertUUIDAutoId() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&insertUUIDAutoId
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('insert succeeds with random string auto ID')
|
||||
void insertStringAutoId() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&insertStringAutoId
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('save updates an existing document')
|
||||
void saveMatch() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&saveMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('save inserts a new document')
|
||||
void saveNoMatch() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&saveNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('update replaces an existing document')
|
||||
void updateMatch() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&updateMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('update succeeds when no document exists')
|
||||
void updateNoMatch() {
|
||||
new SQLiteDB().withCloseable DocumentFunctions.&updateNoMatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Exists` object / `existsBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Exists')
|
||||
final class SQLiteExistsIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId returns true when a document matches the ID')
|
||||
void byIdMatch() {
|
||||
new SQLiteDB().withCloseable ExistsFunctions.&byIdMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId returns false when no document matches the ID')
|
||||
void byIdNoMatch() {
|
||||
new SQLiteDB().withCloseable ExistsFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields returns true when documents match')
|
||||
void byFieldsMatch() {
|
||||
new SQLiteDB().withCloseable ExistsFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields returns false when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new SQLiteDB().withCloseable ExistsFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails')
|
||||
void byContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { ExistsFunctions.byContainsMatch db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails')
|
||||
void byJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { ExistsFunctions.byJsonPathMatch db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Find` object / `find*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Find')
|
||||
final class SQLiteFindIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('all retrieves all documents')
|
||||
void allDefault() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&allDefault
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all sorts data ascending')
|
||||
void allAscending() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&allAscending
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all sorts data descending')
|
||||
void allDescending() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&allDescending
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all sorts data numerically')
|
||||
void allNumOrder() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&allNumOrder
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('all succeeds with an empty table')
|
||||
void allEmpty() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&allEmpty
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId retrieves a document via a string ID')
|
||||
void byIdString() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byIdString
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId retrieves a document via a numeric ID')
|
||||
void byIdNumber() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byIdNumber
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId returns null when a matching ID is not found')
|
||||
void byIdNotFound() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byIdNotFound
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves matching documents')
|
||||
void byFieldsMatch() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves ordered matching documents')
|
||||
void byFieldsMatchOrdered() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byFieldsMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves matching documents with a numeric IN clause')
|
||||
void byFieldsMatchNumIn() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byFieldsMatchNumIn
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields retrieves matching documents with an IN_ARRAY comparison')
|
||||
void byFieldsMatchInArray() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byFieldsMatchInArray
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match an IN_ARRAY comparison')
|
||||
void byFieldsNoMatchInArray() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&byFieldsNoMatchInArray
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails')
|
||||
void byContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { FindFunctions.byContainsMatch db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails')
|
||||
void byJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { FindFunctions.byJsonPathMatch db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields retrieves a matching document')
|
||||
void firstByFieldsMatchOne() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&firstByFieldsMatchOne
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields retrieves a matching document among many')
|
||||
void firstByFieldsMatchMany() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&firstByFieldsMatchMany
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields retrieves a matching document among many (ordered)')
|
||||
void firstByFieldsMatchOrdered() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&firstByFieldsMatchOrdered
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByFields returns null when no document matches')
|
||||
void firstByFieldsNoMatch() {
|
||||
new SQLiteDB().withCloseable FindFunctions.&firstByFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByContains fails')
|
||||
void firstByContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { FindFunctions.firstByContainsMatchOne db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('firstByJsonPath fails')
|
||||
void firstByJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { FindFunctions.firstByJsonPathMatchOne db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Patch` object / `patchBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: Patch')
|
||||
final class SQLitePatchIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId patches an existing document')
|
||||
void byIdMatch() {
|
||||
new SQLiteDB().withCloseable PatchFunctions.&byIdMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds for a non-existent document')
|
||||
void byIdNoMatch() {
|
||||
new SQLiteDB().withCloseable PatchFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields patches matching document')
|
||||
void byFieldsMatch() {
|
||||
new SQLiteDB().withCloseable PatchFunctions.&byFieldsMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no documents match')
|
||||
void byFieldsNoMatch() {
|
||||
new SQLiteDB().withCloseable PatchFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails')
|
||||
void byContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { PatchFunctions.byContainsMatch db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails')
|
||||
void byJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { PatchFunctions.byJsonPathMatch db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `RemoveFields` object / `removeFieldsBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName('Groovy | SQLite: RemoveFields')
|
||||
final class SQLiteRemoveFieldsIT {
|
||||
|
||||
@Test
|
||||
@DisplayName('byId removes fields from an existing document')
|
||||
void byIdMatchFields() {
|
||||
new SQLiteDB().withCloseable RemoveFieldsFunctions.&byIdMatchFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds when fields do not exist on an existing document')
|
||||
void byIdMatchNoFields() {
|
||||
new SQLiteDB().withCloseable RemoveFieldsFunctions.&byIdMatchNoFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byId succeeds when no document exists')
|
||||
void byIdNoMatch() {
|
||||
new SQLiteDB().withCloseable RemoveFieldsFunctions.&byIdNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields removes fields from matching documents')
|
||||
void byFieldsMatchFields() {
|
||||
new SQLiteDB().withCloseable RemoveFieldsFunctions.&byFieldsMatchFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when fields do not exist on matching documents')
|
||||
void byFieldsMatchNoFields() {
|
||||
new SQLiteDB().withCloseable RemoveFieldsFunctions.&byFieldsMatchNoFields
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byFields succeeds when no matching documents exist')
|
||||
void byFieldsNoMatch() {
|
||||
new SQLiteDB().withCloseable RemoveFieldsFunctions.&byFieldsNoMatch
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byContains fails')
|
||||
void byContainsFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { RemoveFieldsFunctions.byContainsMatchFields db }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName('byJsonPath fails')
|
||||
void byJsonPathFails() {
|
||||
new SQLiteDB().withCloseable { db ->
|
||||
assertThrows(DocumentException) { RemoveFieldsFunctions.byJsonPathMatchFields db }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
class SubDocument {
|
||||
String foo
|
||||
String bar
|
||||
|
||||
SubDocument(String foo = "", String bar = "") {
|
||||
this.foo = foo
|
||||
this.bar = bar
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package solutions.bitbadger.documents.groovy.tests.integration
|
||||
|
||||
import solutions.bitbadger.documents.AutoId
|
||||
import java.sql.Connection
|
||||
|
||||
/**
|
||||
* Common trait for PostgreSQL and SQLite throwaway databases
|
||||
*/
|
||||
trait ThrowawayDatabase implements AutoCloseable {
|
||||
|
||||
/** The database connection for the throwaway database */
|
||||
Connection conn
|
||||
|
||||
/**
|
||||
* Determine if a database object exists
|
||||
*
|
||||
* @param name The name of the object whose existence should be checked
|
||||
* @return True if the object exists, false if not
|
||||
*/
|
||||
abstract boolean dbObjectExists(String name)
|
||||
|
||||
/** The name for the throwaway database */
|
||||
String dbName = "throwaway_${AutoId.generateRandomString(8)}"
|
||||
}
|
||||
15
src/groovy/src/test/java/module-info.java
Normal file
15
src/groovy/src/test/java/module-info.java
Normal file
@@ -0,0 +1,15 @@
|
||||
module solutions.bitbadger.documents.groovy.tests {
|
||||
requires solutions.bitbadger.documents.core;
|
||||
requires solutions.bitbadger.documents.groovy;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires java.desktop;
|
||||
requires java.sql;
|
||||
requires org.apache.groovy;
|
||||
requires org.junit.jupiter.api;
|
||||
|
||||
exports solutions.bitbadger.documents.groovy.tests;
|
||||
exports solutions.bitbadger.documents.groovy.tests.integration;
|
||||
|
||||
opens solutions.bitbadger.documents.groovy.tests;
|
||||
opens solutions.bitbadger.documents.groovy.tests.integration;
|
||||
}
|
||||
Reference in New Issue
Block a user