Initial Development #1

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

View File

@ -3,7 +3,7 @@ package solutions.bitbadger.documents.groovy
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.AutoId import solutions.bitbadger.documents.AutoId
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.groovy.support.* import solutions.bitbadger.documents.groovy.support.*
import static org.junit.jupiter.api.Assertions.* import static org.junit.jupiter.api.Assertions.*
@ -42,19 +42,17 @@ class AutoIdTest {
assertNotEquals result1, result2, 'There should have been 2 different strings generated' assertNotEquals result1, result2, 'There should have been 2 different strings generated'
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('needsAutoId fails for null document')
// @DisplayName('needsAutoId fails for null document') void needsAutoIdFailsForNullDocument() {
// void needsAutoIdFailsForNullDocument() { assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.DISABLED, null, 'id') }
// assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.DISABLED, null, 'id') } }
// }
// @Test
// TODO: resolve java.base open issue @DisplayName('needsAutoId fails for missing ID property')
// @Test void needsAutoIdFailsForMissingId() {
// @DisplayName('needsAutoId fails for missing ID property') assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.UUID, new IntIdClass(0), 'Id') }
// void needsAutoIdFailsForMissingId() { }
// assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.UUID, new IntIdClass(0), 'Id') }
// }
@Test @Test
@DisplayName('needsAutoId returns false if disabled') @DisplayName('needsAutoId returns false if disabled')
@ -118,12 +116,11 @@ class AutoIdTest {
'Number Auto ID with 2 should return false') 'Number Auto ID with 2 should return false')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('needsAutoId fails for Number strategy and non-number ID')
// @DisplayName('needsAutoId fails for Number strategy and non-number ID') void needsAutoIdFailsForNumberWithStringId() {
// void needsAutoIdFailsForNumberWithStringId() { assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.NUMBER, new StringIdClass(''), 'id') }
// assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.NUMBER, new StringIdClass(''), 'id') } }
// }
@Test @Test
@DisplayName('needsAutoId returns true for UUID strategy and blank ID') @DisplayName('needsAutoId returns true for UUID strategy and blank ID')
@ -139,12 +136,11 @@ class AutoIdTest {
'UUID Auto ID with non-blank should return false') 'UUID Auto ID with non-blank should return false')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('needsAutoId fails for UUID strategy and non-string ID')
// @DisplayName('needsAutoId fails for UUID strategy and non-string ID') void needsAutoIdFailsForUUIDNonString() {
// void needsAutoIdFailsForUUIDNonString() { assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.UUID, new IntIdClass(5), 'id') }
// assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.UUID, new IntIdClass(5), 'id') } }
// }
@Test @Test
@DisplayName('needsAutoId returns true for Random String strategy and blank ID') @DisplayName('needsAutoId returns true for Random String strategy and blank ID')
@ -160,12 +156,9 @@ class AutoIdTest {
'Random String Auto ID with non-blank should return false') 'Random String Auto ID with non-blank should return false')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('needsAutoId fails for Random String strategy and non-string ID')
// @DisplayName('needsAutoId fails for Random String strategy and non-string ID') void needsAutoIdFailsForRandomNonString() {
// void needsAutoIdFailsForRandomNonString() { assertThrows(DocumentException) { AutoId.needsAutoId(AutoId.RANDOM_STRING, new ShortIdClass((short) 55), 'id') }
// assertThrows(DocumentException) { }
// AutoId.needsAutoId(AutoId.RANDOM_STRING, new ShortIdClass((short) 55), 'id')
// }
// }
} }

View File

@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.AutoId import solutions.bitbadger.documents.AutoId
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.Configuration
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.Dialect
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import static org.junit.jupiter.api.Assertions.* import static org.junit.jupiter.api.Assertions.*
@ -37,8 +37,7 @@ class ConfigurationTest {
@DisplayName('Dialect is derived from connection string') @DisplayName('Dialect is derived from connection string')
void dialectIsDerived() { void dialectIsDerived() {
try { try {
// TODO: uncomment once java.base open issue resolved assertThrows(DocumentException) { Configuration.dialect() }
//assertThrows(DocumentException) { Configuration.dialect() }
Configuration.connectionString = 'jdbc:postgresql:db' Configuration.connectionString = 'jdbc:postgresql:db'
assertEquals Dialect.POSTGRESQL, Configuration.dialect() assertEquals Dialect.POSTGRESQL, Configuration.dialect()
} finally { } finally {

View File

@ -4,7 +4,7 @@ import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.Dialect
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.FieldFormat import solutions.bitbadger.documents.FieldFormat
import solutions.bitbadger.documents.Op import solutions.bitbadger.documents.Op
@ -28,12 +28,11 @@ class FieldTest {
// ~~~ INSTANCE METHODS ~~~ // ~~~ INSTANCE METHODS ~~~
// TODO: fix java.base open issue @Test
// @Test @DisplayName('withParameterName fails for invalid name')
// @DisplayName('withParameterName fails for invalid name') void withParamNameFails() {
// void withParamNameFails() { assertThrows(DocumentException) { Field.equal('it', '').withParameterName('2424') }
// assertThrows(DocumentException) { Field.equal('it', '').withParameterName('2424') } }
// }
@Test @Test
@DisplayName('withParameterName works with colon prefix') @DisplayName('withParameterName works with colon prefix')
@ -351,7 +350,7 @@ class FieldTest {
assertEquals 'Great', field.name, 'Field name not filled correctly' assertEquals 'Great', field.name, 'Field name not filled correctly'
assertEquals Op.GREATER, field.comparison.op, 'Field comparison operation 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 'night', field.comparison.value, 'Field comparison value not filled correctly'
assertEquals('Field parameter name not filled correctly', ':yeah', field.parameterName) assertEquals ':yeah', field.parameterName, 'Field parameter name not filled correctly'
assertNull field.qualifier, 'The qualifier should have been null' assertNull field.qualifier, 'The qualifier should have been null'
} }
@ -546,12 +545,11 @@ class FieldTest {
assertNull field.qualifier, 'The qualifier should have been null' assertNull field.qualifier, 'The qualifier should have been null'
} }
// TODO: fix java.base open issue @Test
// @Test @DisplayName('static constructors fail for invalid parameter name')
// @DisplayName('static constructors fail for invalid parameter name') void staticCtorsFailOnParamName() {
// void staticCtorsFailOnParamName() { assertThrows(DocumentException) { Field.equal('a', 'b', "that ain't it, Jack...") }
// assertThrows(DocumentException) { Field.equal('a', 'b', "that ain't it, Jack...") } }
// }
@Test @Test
@DisplayName('nameToPath creates a simple PostgreSQL SQL name') @DisplayName('nameToPath creates a simple PostgreSQL SQL name')

View File

@ -2,7 +2,7 @@ package solutions.bitbadger.documents.groovy
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Parameter import solutions.bitbadger.documents.Parameter
import solutions.bitbadger.documents.ParameterType import solutions.bitbadger.documents.ParameterType
@ -32,10 +32,9 @@ class ParameterTest {
assertNull p.value, 'Parameter value was incorrect' assertNull p.value, 'Parameter value was incorrect'
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('Construction fails with incorrect prefix')
// @DisplayName('Construction fails with incorrect prefix') void ctorFailsForPrefix() {
// void ctorFailsForPrefix() { assertThrows(DocumentException) { new Parameter('it', ParameterType.JSON, '') }
// assertThrows(DocumentException) { new Parameter('it', ParameterType.JSON, '') } }
// }
} }

View File

@ -3,14 +3,14 @@ package solutions.bitbadger.documents.groovy.jvm
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.Parameter import solutions.bitbadger.documents.Parameter
import solutions.bitbadger.documents.ParameterType import solutions.bitbadger.documents.ParameterType
import solutions.bitbadger.documents.jvm.Parameters import solutions.bitbadger.documents.jvm.Parameters
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Parameters` object * Unit tests for the `Parameters` object
@ -31,10 +31,10 @@ class ParametersTest {
void nameFieldsNoChange() { void nameFieldsNoChange() {
def fields = List.of(Field.equal('a', '', ':test'), Field.exists('q'), Field.equal('b', '', ':me')) def fields = List.of(Field.equal('a', '', ':test'), Field.exists('q'), Field.equal('b', '', ':me'))
def named = Parameters.nameFields(fields).toList() def named = Parameters.nameFields(fields).toList()
assertEquals('There should have been 3 fields in the list', fields.size(), named.size()) assertEquals fields.size(), named.size(), 'There should have been 3 fields in the list'
assertSame('The first field should be the same', fields[0], named[0]) assertSame fields[0], named[0], 'The first field should be the same'
assertSame('The second field should be the same', fields[1], named[1]) assertSame fields[1], named[1], 'The second field should be the same'
assertSame('The third field should be the same', fields[2], named[2]) assertSame fields[2], named[2], 'The third field should be the same'
} }
@Test @Test
@ -43,13 +43,13 @@ class ParametersTest {
def fields = List.of(Field.equal('a', ''), Field.equal('e', '', ':hi'), Field.equal('b', ''), def fields = List.of(Field.equal('a', ''), Field.equal('e', '', ':hi'), Field.equal('b', ''),
Field.notExists('z')) Field.notExists('z'))
def named = Parameters.nameFields(fields).toList() def named = Parameters.nameFields(fields).toList()
assertEquals('There should have been 4 fields in the list', fields.size(), named.size()) assertEquals fields.size(), named.size(), 'There should have been 4 fields in the list'
assertNotSame('The first field should not be the same', fields[0], named[0]) assertNotSame fields[0], named[0], 'The first field should not be the same'
assertEquals('First parameter name incorrect', ':field0', named[0].parameterName) assertEquals ':field0', named[0].parameterName, 'First parameter name incorrect'
assertSame('The second field should be the same', fields[1], named[1]) assertSame fields[1], named[1], 'The second field should be the same'
assertNotSame('The third field should not be the same', fields[2], named[2]) assertNotSame fields[2], named[2], 'The third field should not be the same'
assertEquals('Third parameter name incorrect', ':field1', named[2].parameterName) assertEquals ':field1', named[2].parameterName, 'Third parameter name incorrect'
assertSame('The fourth field should be the same', fields[3], named[3]) assertSame fields[3], named[3], 'The fourth field should be the same'
} }
@Test @Test
@ -58,9 +58,8 @@ class ParametersTest {
def parameters = List.of(new Parameter(':data', ParameterType.JSON, '{}'), def parameters = List.of(new Parameter(':data', ParameterType.JSON, '{}'),
new Parameter(':data_ext', ParameterType.STRING, '')) 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' def query = 'SELECT data, data_ext FROM tbl WHERE data = :data AND data_ext = :data_ext AND more_data = :data'
assertEquals('Parameters not replaced correctly', assertEquals('SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?',
'SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?', Parameters.replaceNamesInQuery(query, parameters), 'Parameters not replaced correctly')
Parameters.replaceNamesInQuery(query, parameters))
} }
@Test @Test
@ -68,10 +67,10 @@ class ParametersTest {
void fieldNamesSinglePostgres() { void fieldNamesSinglePostgres() {
ForceDialect.postgres() ForceDialect.postgres()
def nameParams = Parameters.fieldNames(List.of('test')).toList() def nameParams = Parameters.fieldNames(List.of('test')).toList()
assertEquals('There should be one name parameter', 1, nameParams.size()) assertEquals 1, nameParams.size(), 'There should be one name parameter'
assertEquals('The parameter name is incorrect', ':name', nameParams[0].name) assertEquals ':name', nameParams[0].name, 'The parameter name is incorrect'
assertEquals('The parameter type is incorrect', ParameterType.STRING, nameParams[0].type) assertEquals ParameterType.STRING, nameParams[0].type, 'The parameter type is incorrect'
assertEquals('The parameter value is incorrect', '{test}', nameParams[0].value) assertEquals '{test}', nameParams[0].value, 'The parameter value is incorrect'
} }
@Test @Test
@ -79,10 +78,10 @@ class ParametersTest {
void fieldNamesMultiplePostgres() { void fieldNamesMultiplePostgres() {
ForceDialect.postgres() ForceDialect.postgres()
def nameParams = Parameters.fieldNames(List.of('test', 'this', 'today')).toList() def nameParams = Parameters.fieldNames(List.of('test', 'this', 'today')).toList()
assertEquals('There should be one name parameter', 1, nameParams.size()) assertEquals 1, nameParams.size(), 'There should be one name parameter'
assertEquals('The parameter name is incorrect', ':name', nameParams[0].name) assertEquals ':name', nameParams[0].name, 'The parameter name is incorrect'
assertEquals('The parameter type is incorrect', ParameterType.STRING, nameParams[0].type) assertEquals ParameterType.STRING, nameParams[0].type, 'The parameter type is incorrect'
assertEquals('The parameter value is incorrect', '{test,this,today}', nameParams[0].value) assertEquals '{test,this,today}', nameParams[0].value, 'The parameter value is incorrect'
} }
@Test @Test
@ -90,10 +89,10 @@ class ParametersTest {
void fieldNamesSingleSQLite() { void fieldNamesSingleSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
def nameParams = Parameters.fieldNames(List.of('test')).toList() def nameParams = Parameters.fieldNames(List.of('test')).toList()
assertEquals('There should be one name parameter', 1, nameParams.size()) assertEquals 1, nameParams.size(), 'There should be one name parameter'
assertEquals('The parameter name is incorrect', ':name0', nameParams[0].name) assertEquals ':name0', nameParams[0].name, 'The parameter name is incorrect'
assertEquals('The parameter type is incorrect', ParameterType.STRING, nameParams[0].type) assertEquals ParameterType.STRING, nameParams[0].type, 'The parameter type is incorrect'
assertEquals('The parameter value is incorrect', 'test', nameParams[0].value) assertEquals 'test', nameParams[0].value, 'The parameter value is incorrect'
} }
@Test @Test
@ -101,22 +100,21 @@ class ParametersTest {
void fieldNamesMultipleSQLite() { void fieldNamesMultipleSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
def nameParams = Parameters.fieldNames(List.of('test', 'this', 'today')).toList() def nameParams = Parameters.fieldNames(List.of('test', 'this', 'today')).toList()
assertEquals('There should be one name parameter', 3, nameParams.size()) assertEquals 3, nameParams.size(), 'There should be one name parameter'
assertEquals('The first parameter name is incorrect', ':name0', nameParams[0].name) assertEquals ':name0', nameParams[0].name, 'The first parameter name is incorrect'
assertEquals('The first parameter type is incorrect', ParameterType.STRING, nameParams[0].type) assertEquals ParameterType.STRING, nameParams[0].type, 'The first parameter type is incorrect'
assertEquals('The first parameter value is incorrect', 'test', nameParams[0].value) assertEquals 'test', nameParams[0].value, 'The first parameter value is incorrect'
assertEquals('The second parameter name is incorrect', ':name1', nameParams[1].name) assertEquals ':name1', nameParams[1].name, 'The second parameter name is incorrect'
assertEquals('The second parameter type is incorrect', ParameterType.STRING, nameParams[1].type) assertEquals ParameterType.STRING, nameParams[1].type, 'The second parameter type is incorrect'
assertEquals('The second parameter value is incorrect', 'this', nameParams[1].value) assertEquals 'this', nameParams[1].value, 'The second parameter value is incorrect'
assertEquals('The third parameter name is incorrect', ':name2', nameParams[2].name) assertEquals ':name2', nameParams[2].name, 'The third parameter name is incorrect'
assertEquals('The third parameter type is incorrect', ParameterType.STRING, nameParams[2].type) assertEquals ParameterType.STRING, nameParams[2].type, 'The third parameter type is incorrect'
assertEquals('The third parameter value is incorrect', 'today', nameParams[2].value) assertEquals 'today', nameParams[2].value, 'The third parameter value is incorrect'
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('fieldNames fails if dialect not set')
// @DisplayName('fieldNames fails if dialect not set') void fieldNamesFails() {
// void fieldNamesFails() { assertThrows(DocumentException) { Parameters.fieldNames(List.of()) }
// assertThrows(DocumentException) { Parameters.fieldNames(List.of()) } }
// }
} }

View File

@ -6,48 +6,48 @@ import solutions.bitbadger.documents.support.ThrowawayDatabase
import static solutions.bitbadger.documents.extensions.ConnExt.* import static solutions.bitbadger.documents.extensions.ConnExt.*
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
class CountFunctions { class CountFunctions {
static void all(ThrowawayDatabase db) { static void all(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been 5 documents in the table', 5L, countAll(db.conn, TEST_TABLE)) assertEquals 5L, countAll(db.conn, TEST_TABLE), 'There should have been 5 documents in the table'
} }
static void byFieldsNumeric(ThrowawayDatabase db) { static void byFieldsNumeric(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been 3 matching documents', 3L, assertEquals(3L, countByFields(db.conn, TEST_TABLE, List.of(Field.between('numValue', 10, 20))),
countByFields(db.conn, TEST_TABLE, List.of(Field.between('numValue', 10, 20)))) 'There should have been 3 matching documents')
} }
static void byFieldsAlpha(ThrowawayDatabase db) { static void byFieldsAlpha(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been 1 matching document', 1L, assertEquals(1L, countByFields(db.conn, TEST_TABLE, List.of(Field.between('value', 'aardvark', 'apple'))),
countByFields(db.conn, TEST_TABLE, List.of(Field.between('value', 'aardvark', 'apple')))) 'There should have been 1 matching document')
} }
static void byContainsMatch(ThrowawayDatabase db) { static void byContainsMatch(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been 2 matching documents', 2L, assertEquals(2L, countByContains(db.conn, TEST_TABLE, Map.of('value', 'purple')),
countByContains(db.conn, TEST_TABLE, Map.of('value', 'purple'))) 'There should have been 2 matching documents')
} }
static void byContainsNoMatch(ThrowawayDatabase db) { static void byContainsNoMatch(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been no matching documents', 0L, assertEquals(0L, countByContains(db.conn, TEST_TABLE, Map.of('value', 'magenta')),
countByContains(db.conn, TEST_TABLE, Map.of('value', 'magenta'))) 'There should have been no matching documents')
} }
static void byJsonPathMatch(ThrowawayDatabase db) { static void byJsonPathMatch(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been 2 matching documents', 2L, assertEquals(2L, countByJsonPath(db.conn, TEST_TABLE, '$.numValue ? (@ < 5)'),
countByJsonPath(db.conn, TEST_TABLE, '$.numValue ? (@ < 5)')) 'There should have been 2 matching documents')
} }
static void byJsonPathNoMatch(ThrowawayDatabase db) { static void byJsonPathNoMatch(ThrowawayDatabase db) {
JsonDocument.load(db) JsonDocument.load(db)
assertEquals('There should have been no matching documents', 0L, assertEquals(0L, countByJsonPath(db.conn, TEST_TABLE, '$.numValue ? (@ > 100)'),
countByJsonPath(db.conn, TEST_TABLE, '$.numValue ? (@ > 100)')) 'There should have been no matching documents')
} }
} }

View File

@ -14,12 +14,42 @@ class CountIT {
@Test @Test
@DisplayName("all counts all documents") @DisplayName("all counts all documents")
void all() { void all() {
PgDB db = new PgDB() new PgDB().withCloseable { CountFunctions.all(it) }
try {
CountFunctions.all(db)
} finally {
db.close()
}
} }
@Test
@DisplayName("byFields counts documents by a numeric value")
void byFieldsNumeric() {
new PgDB().withCloseable { CountFunctions.byFieldsNumeric(it) }
}
@Test
@DisplayName("byFields counts documents by a alphanumeric value")
void byFieldsAlpha() {
new PgDB().withCloseable { CountFunctions.byFieldsAlpha(it) }
}
@Test
@DisplayName("byContains counts documents when matches are found")
void byContainsMatch() {
new PgDB().withCloseable { CountFunctions.byContainsMatch(it) }
}
@Test
@DisplayName("byContains counts documents when no matches are found")
void byContainsNoMatch() {
new PgDB().withCloseable { CountFunctions.byContainsNoMatch(it) }
}
@Test
@DisplayName("byJsonPath counts documents when matches are found")
void byJsonPathMatch() {
new PgDB().withCloseable { CountFunctions.byJsonPathMatch(it) }
}
@Test
@DisplayName("byJsonPath counts documents when no matches are found")
void byJsonPathNoMatch() {
new PgDB().withCloseable { CountFunctions.byJsonPathNoMatch(it) }
}
} }

View File

@ -0,0 +1,50 @@
package solutions.bitbadger.documents.groovy.jvm.integration.sqlite
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.groovy.jvm.integration.common.CountFunctions
import solutions.bitbadger.documents.jvm.integration.sqlite.SQLiteDB
import static org.junit.jupiter.api.Assertions.assertThrows
/**
* SQLite integration tests for the `Count` object / `count*` connection extension functions
*/
@DisplayName("JVM | Groovy | SQLite: Count")
class CountIT {
@Test
@DisplayName("all counts all documents")
void all() {
new SQLiteDB().withCloseable { CountFunctions.all(it) }
}
@Test
@DisplayName("byFields counts documents by a numeric value")
void byFieldsNumeric() {
new SQLiteDB().withCloseable { CountFunctions.byFieldsNumeric(it) }
}
@Test
@DisplayName("byFields counts documents by a alphanumeric value")
void byFieldsAlpha() {
new SQLiteDB().withCloseable { CountFunctions.byFieldsAlpha(it) }
}
@Test
@DisplayName("byContains fails")
void byContainsMatch() {
new SQLiteDB().withCloseable { db ->
assertThrows(DocumentException) { CountFunctions.byContainsMatch(db) }
}
}
@Test
@DisplayName("byJsonPath fails")
void byJsonPathMatch() {
new SQLiteDB().withCloseable { db ->
assertThrows(DocumentException) { CountFunctions.byJsonPathMatch(db) }
}
}
}

View File

@ -3,13 +3,13 @@ package solutions.bitbadger.documents.groovy.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.query.CountQuery import solutions.bitbadger.documents.query.CountQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Count` object * Unit tests for the `Count` object
@ -28,59 +28,55 @@ class CountQueryTest {
@Test @Test
@DisplayName('all generates correctly') @DisplayName('all generates correctly')
void all() { void all() {
assertEquals('Count query not constructed correctly', "SELECT COUNT(*) AS it FROM $TEST_TABLE".toString(), assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE".toString(), CountQuery.all(TEST_TABLE),
CountQuery.all(TEST_TABLE)) 'Count query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | PostgreSQL') @DisplayName('byFields generates correctly | PostgreSQL')
void byFieldsPostgres() { void byFieldsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Count query not constructed correctly', assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0".toString(),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0".toString(), CountQuery.byFields(TEST_TABLE, List.of(Field.equal('test', '', ':field0'))),
CountQuery.byFields(TEST_TABLE, List.of(Field.equal('test', '', ':field0')))) 'Count query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | SQLite') @DisplayName('byFields generates correctly | SQLite')
void byFieldsSQLite() { void byFieldsSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Count query not constructed correctly', assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0".toString(),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data->>'test' = :field0".toString(), CountQuery.byFields(TEST_TABLE, List.of(Field.equal('test', '', ':field0'))),
CountQuery.byFields(TEST_TABLE, List.of(Field.equal('test', '', ':field0')))) 'Count query not constructed correctly')
} }
@Test @Test
@DisplayName('byContains generates correctly | PostgreSQL') @DisplayName('byContains generates correctly | PostgreSQL')
void byContainsPostgres() { void byContainsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Count query not constructed correctly', assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data @> :criteria".toString(),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE data @> :criteria".toString(), CountQuery.byContains(TEST_TABLE), 'Count query not constructed correctly')
CountQuery.byContains(TEST_TABLE))
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byContains fails | SQLite')
// @DisplayName('byContains fails | SQLite') void byContainsSQLite() {
// void byContainsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { CountQuery.byContains(TEST_TABLE) }
// assertThrows(DocumentException) { CountQuery.byContains(TEST_TABLE) } }
// }
@Test @Test
@DisplayName('byJsonPath generates correctly | PostgreSQL') @DisplayName('byJsonPath generates correctly | PostgreSQL')
void byJsonPathPostgres() { void byJsonPathPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Count query not constructed correctly', assertEquals("SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
"SELECT COUNT(*) AS it FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(), CountQuery.byJsonPath(TEST_TABLE), 'Count query not constructed correctly')
CountQuery.byJsonPath(TEST_TABLE))
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byJsonPath fails | SQLite')
// @DisplayName('byJsonPath fails | SQLite') void byJsonPathSQLite() {
// void byJsonPathSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { CountQuery.byJsonPath(TEST_TABLE) }
// assertThrows(DocumentException) { CountQuery.byJsonPath(TEST_TABLE) } }
// }
} }

View File

@ -4,13 +4,13 @@ import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.Dialect import solutions.bitbadger.documents.Dialect
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.DocumentIndex import solutions.bitbadger.documents.DocumentIndex
import solutions.bitbadger.documents.query.DefinitionQuery import solutions.bitbadger.documents.query.DefinitionQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Definition` object * Unit tests for the `Definition` object
@ -29,9 +29,8 @@ class DefinitionQueryTest {
@Test @Test
@DisplayName('ensureTableFor generates correctly') @DisplayName('ensureTableFor generates correctly')
void ensureTableFor() { void ensureTableFor() {
assertEquals('CREATE TABLE statement not constructed correctly', assertEquals('CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)',
'CREATE TABLE IF NOT EXISTS my.table (data JSONB NOT NULL)', DefinitionQuery.ensureTableFor('my.table', 'JSONB'), 'CREATE TABLE statement not constructed correctly')
DefinitionQuery.ensureTableFor('my.table', 'JSONB'))
} }
@Test @Test
@ -50,79 +49,80 @@ class DefinitionQueryTest {
DefinitionQuery.ensureTable(TEST_TABLE)) DefinitionQuery.ensureTable(TEST_TABLE))
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('ensureTable fails when no dialect is set')
// @DisplayName('ensureTable fails when no dialect is set') void ensureTableFailsUnknown() {
// void ensureTableFailsUnknown() { assertThrows(DocumentException) { DefinitionQuery.ensureTable(TEST_TABLE) }
// assertThrows(DocumentException) { DefinitionQuery.ensureTable(TEST_TABLE) } }
// }
@Test @Test
@DisplayName('ensureKey generates correctly with schema') @DisplayName('ensureKey generates correctly with schema')
void ensureKeyWithSchema() { void ensureKeyWithSchema() {
assertEquals('CREATE INDEX for key statement with schema not constructed correctly', assertEquals("CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data->>'id'))",
"CREATE UNIQUE INDEX IF NOT EXISTS idx_table_key ON test.table ((data->>'id'))", DefinitionQuery.ensureKey('test.table', Dialect.POSTGRESQL),
DefinitionQuery.ensureKey('test.table', Dialect.POSTGRESQL)) 'CREATE INDEX for key statement with schema not constructed correctly')
} }
@Test @Test
@DisplayName('ensureKey generates correctly without schema') @DisplayName('ensureKey generates correctly without schema')
void ensureKeyWithoutSchema() { void ensureKeyWithoutSchema() {
assertEquals('CREATE INDEX for key statement without schema not constructed correctly', assertEquals(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_${TEST_TABLE}_key ON $TEST_TABLE ((data->>'id'))".toString(), "CREATE UNIQUE INDEX IF NOT EXISTS idx_${TEST_TABLE}_key ON $TEST_TABLE ((data->>'id'))".toString(),
DefinitionQuery.ensureKey(TEST_TABLE, Dialect.SQLITE)) DefinitionQuery.ensureKey(TEST_TABLE, Dialect.SQLITE),
'CREATE INDEX for key statement without schema not constructed correctly')
} }
@Test @Test
@DisplayName('ensureIndexOn generates multiple fields and directions') @DisplayName('ensureIndexOn generates multiple fields and directions')
void ensureIndexOnMultipleFields() { void ensureIndexOnMultipleFields() {
assertEquals('CREATE INDEX for multiple field statement not constructed correctly', assertEquals(
"CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table ((data->>'taco'), (data->>'guac') DESC, (data->>'salsa') ASC)" "CREATE INDEX IF NOT EXISTS idx_table_gibberish ON test.table ((data->>'taco'), (data->>'guac') DESC, (data->>'salsa') ASC)",
.toString(),
DefinitionQuery.ensureIndexOn('test.table', 'gibberish', List.of('taco', 'guac DESC', 'salsa ASC'), DefinitionQuery.ensureIndexOn('test.table', 'gibberish', List.of('taco', 'guac DESC', 'salsa ASC'),
Dialect.POSTGRESQL)) Dialect.POSTGRESQL),
'CREATE INDEX for multiple field statement not constructed correctly')
} }
@Test @Test
@DisplayName('ensureIndexOn generates nested field | PostgreSQL') @DisplayName('ensureIndexOn generates nested field | PostgreSQL')
void ensureIndexOnNestedPostgres() { void ensureIndexOnNestedPostgres() {
assertEquals('CREATE INDEX for nested PostgreSQL field incorrect', assertEquals("CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_nest ON $TEST_TABLE ((data#>>'{a,b,c}'))".toString(),
"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),
DefinitionQuery.ensureIndexOn(TEST_TABLE, 'nest', List.of('a.b.c'), Dialect.POSTGRESQL)) 'CREATE INDEX for nested PostgreSQL field incorrect')
} }
@Test @Test
@DisplayName('ensureIndexOn generates nested field | SQLite') @DisplayName('ensureIndexOn generates nested field | SQLite')
void ensureIndexOnNestedSQLite() { void ensureIndexOnNestedSQLite() {
assertEquals('CREATE INDEX for nested SQLite field incorrect', assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_nest ON $TEST_TABLE ((data->'a'->'b'->>'c'))".toString(), "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)) DefinitionQuery.ensureIndexOn(TEST_TABLE, 'nest', List.of('a.b.c'), Dialect.SQLITE),
'CREATE INDEX for nested SQLite field incorrect')
} }
@Test @Test
@DisplayName('ensureDocumentIndexOn generates Full | PostgreSQL') @DisplayName('ensureDocumentIndexOn generates Full | PostgreSQL')
void ensureDocumentIndexOnFullPostgres() { void ensureDocumentIndexOnFullPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('CREATE INDEX for full document index incorrect', assertEquals("CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data)".toString(),
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data)".toString(), DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL),
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL)) 'CREATE INDEX for full document index incorrect')
} }
@Test @Test
@DisplayName('ensureDocumentIndexOn generates Optimized | PostgreSQL') @DisplayName('ensureDocumentIndexOn generates Optimized | PostgreSQL')
void ensureDocumentIndexOnOptimizedPostgres() { void ensureDocumentIndexOnOptimizedPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('CREATE INDEX for optimized document index incorrect', assertEquals(
"CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data jsonb_path_ops)" "CREATE INDEX IF NOT EXISTS idx_${TEST_TABLE}_document ON $TEST_TABLE USING GIN (data jsonb_path_ops)"
.toString(), .toString(),
DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.OPTIMIZED)) DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.OPTIMIZED),
'CREATE INDEX for optimized document index incorrect')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('ensureDocumentIndexOn fails | SQLite')
// @DisplayName('ensureDocumentIndexOn fails | SQLite') void ensureDocumentIndexOnFailsSQLite() {
// void ensureDocumentIndexOnFailsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL) }
// assertThrows(DocumentException) { DefinitionQuery.ensureDocumentIndexOn(TEST_TABLE, DocumentIndex.FULL) } }
// }
} }

View File

@ -3,13 +3,13 @@ package solutions.bitbadger.documents.groovy.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.query.DeleteQuery import solutions.bitbadger.documents.query.DeleteQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Delete` object * Unit tests for the `Delete` object
@ -29,66 +29,63 @@ class DeleteQueryTest {
@DisplayName('byId generates correctly | PostgreSQL') @DisplayName('byId generates correctly | PostgreSQL')
void byIdPostgres() { void byIdPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Delete query not constructed correctly', assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), DeleteQuery.byId(TEST_TABLE),
"DELETE FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), DeleteQuery.byId(TEST_TABLE)) 'Delete query not constructed correctly')
} }
@Test @Test
@DisplayName('byId generates correctly | SQLite') @DisplayName('byId generates correctly | SQLite')
void byIdSQLite() { void byIdSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Delete query not constructed correctly', assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), DeleteQuery.byId(TEST_TABLE),
"DELETE FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), DeleteQuery.byId(TEST_TABLE)) 'Delete query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | PostgreSQL') @DisplayName('byFields generates correctly | PostgreSQL')
void byFieldsPostgres() { void byFieldsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Delete query not constructed correctly', assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'a' = :b".toString(),
"DELETE FROM $TEST_TABLE WHERE data->>'a' = :b".toString(), DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b'))),
DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b')))) 'Delete query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | SQLite') @DisplayName('byFields generates correctly | SQLite')
void byFieldsSQLite() { void byFieldsSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Delete query not constructed correctly', assertEquals("DELETE FROM $TEST_TABLE WHERE data->>'a' = :b".toString(),
"DELETE FROM $TEST_TABLE WHERE data->>'a' = :b".toString(), DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b'))),
DeleteQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b')))) 'Delete query not constructed correctly')
} }
@Test @Test
@DisplayName('byContains generates correctly | PostgreSQL') @DisplayName('byContains generates correctly | PostgreSQL')
void byContainsPostgres() { void byContainsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Delete query not constructed correctly', assertEquals("DELETE FROM $TEST_TABLE WHERE data @> :criteria".toString(), DeleteQuery.byContains(TEST_TABLE),
"DELETE FROM $TEST_TABLE WHERE data @> :criteria".toString(), DeleteQuery.byContains(TEST_TABLE)) 'Delete query not constructed correctly')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byContains fails | SQLite')
// @DisplayName('byContains fails | SQLite') void byContainsSQLite() {
// void byContainsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { DeleteQuery.byContains(TEST_TABLE) }
// assertThrows(DocumentException) { DeleteQuery.byContains(TEST_TABLE) } }
// }
@Test @Test
@DisplayName('byJsonPath generates correctly | PostgreSQL') @DisplayName('byJsonPath generates correctly | PostgreSQL')
void byJsonPathPostgres() { void byJsonPathPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Delete query not constructed correctly', assertEquals("DELETE FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
"DELETE FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(), DeleteQuery.byJsonPath(TEST_TABLE), 'Delete query not constructed correctly')
DeleteQuery.byJsonPath(TEST_TABLE))
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byJsonPath fails | SQLite')
// @DisplayName('byJsonPath fails | SQLite') void byJsonPathSQLite() {
// void byJsonPathSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { DeleteQuery.byJsonPath(TEST_TABLE) }
// assertThrows(DocumentException) { DeleteQuery.byJsonPath(TEST_TABLE) } }
// }
} }

View File

@ -5,12 +5,12 @@ import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import solutions.bitbadger.documents.AutoId import solutions.bitbadger.documents.AutoId
import solutions.bitbadger.documents.Configuration import solutions.bitbadger.documents.Configuration
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.query.DocumentQuery import solutions.bitbadger.documents.query.DocumentQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Document` object * Unit tests for the `Document` object
@ -62,20 +62,20 @@ class DocumentQueryTest {
@DisplayName('insert generates auto UUID | PostgreSQL') @DisplayName('insert generates auto UUID | PostgreSQL')
void insertAutoUUIDPostgres() { void insertAutoUUIDPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
def query = DocumentQuery.insert(TEST_TABLE, AutoId.UUID) def query = DocumentQuery.insert TEST_TABLE, AutoId.UUID
assertTrue("Query start not correct (actual: $query)", assertTrue(query.startsWith("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\""),
query.startsWith("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\"")) "Query start not correct (actual: $query)")
assertTrue('Query end not correct', query.endsWith("\"}')")) assertTrue query.endsWith("\"}')"), 'Query end not correct'
} }
@Test @Test
@DisplayName('insert generates auto UUID | SQLite') @DisplayName('insert generates auto UUID | SQLite')
void insertAutoUUIDSQLite() { void insertAutoUUIDSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
def query = DocumentQuery.insert(TEST_TABLE, AutoId.UUID) def query = DocumentQuery.insert TEST_TABLE, AutoId.UUID
assertTrue("Query start not correct (actual: $query)", assertTrue(query.startsWith("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', '"),
query.startsWith("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', '")) "Query start not correct (actual: $query)")
assertTrue('Query end not correct', query.endsWith("'))")) assertTrue query.endsWith("'))"), 'Query end not correct'
} }
@Test @Test
@ -84,13 +84,14 @@ class DocumentQueryTest {
try { try {
ForceDialect.postgres() ForceDialect.postgres()
Configuration.idStringLength = 8 Configuration.idStringLength = 8
def query = DocumentQuery.insert(TEST_TABLE, AutoId.RANDOM_STRING) def query = DocumentQuery.insert TEST_TABLE, AutoId.RANDOM_STRING
assertTrue("Query start not correct (actual: $query)", assertTrue(query.startsWith("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\""),
query.startsWith("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\"")) "Query start not correct (actual: $query)")
assertTrue('Query end not correct', query.endsWith("\"}')")) assertTrue query.endsWith("\"}')"), 'Query end not correct'
assertEquals('Random string length incorrect', 8, assertEquals(8,
query.replace("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\"", '') query.replace("INSERT INTO $TEST_TABLE VALUES (:data::jsonb || '{\"id\":\"", '')
.replace("\"}')", '').length()) .replace("\"}')", '').length(),
'Random string length incorrect')
} finally { } finally {
Configuration.idStringLength = 16 Configuration.idStringLength = 16
} }
@ -100,36 +101,36 @@ class DocumentQueryTest {
@DisplayName('insert generates auto random string | SQLite') @DisplayName('insert generates auto random string | SQLite')
void insertAutoRandomSQLite() { void insertAutoRandomSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
def query = DocumentQuery.insert(TEST_TABLE, AutoId.RANDOM_STRING) def query = DocumentQuery.insert TEST_TABLE, AutoId.RANDOM_STRING
assertTrue("Query start not correct (actual: $query)", assertTrue(query.startsWith("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', '"),
query.startsWith("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', '")) "Query start not correct (actual: $query)")
assertTrue('Query end not correct', query.endsWith("'))")) assertTrue query.endsWith("'))"), 'Query end not correct'
assertEquals('Random string length incorrect', Configuration.idStringLength, assertEquals(Configuration.idStringLength,
query.replace("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', '", '').replace("'))", '') query.replace("INSERT INTO $TEST_TABLE VALUES (json_set(:data, '\$.id', '", '').replace("'))", '')
.length()) .length(),
'Random string length incorrect')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('insert fails when no dialect is set')
// @DisplayName('insert fails when no dialect is set') void insertFailsUnknown() {
// void insertFailsUnknown() { assertThrows(DocumentException) { DocumentQuery.insert(TEST_TABLE) }
// assertThrows(DocumentException) { DocumentQuery.insert(TEST_TABLE) } }
// }
@Test @Test
@DisplayName('save generates correctly') @DisplayName('save generates correctly')
void save() { void save() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('INSERT ON CONFLICT UPDATE statement not constructed correctly', assertEquals(
"INSERT INTO $TEST_TABLE VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data" "INSERT INTO $TEST_TABLE VALUES (:data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data"
.toString(), .toString(),
DocumentQuery.save(TEST_TABLE)) DocumentQuery.save(TEST_TABLE), 'INSERT ON CONFLICT UPDATE statement not constructed correctly')
} }
@Test @Test
@DisplayName('update generates successfully') @DisplayName('update generates successfully')
void update() { void update() {
assertEquals('Update query not constructed correctly', "UPDATE $TEST_TABLE SET data = :data".toString(), assertEquals("UPDATE $TEST_TABLE SET data = :data".toString(), DocumentQuery.update(TEST_TABLE),
DocumentQuery.update(TEST_TABLE)) 'Update query not constructed correctly')
} }
} }

View File

@ -3,13 +3,13 @@ package solutions.bitbadger.documents.groovy.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.query.FindQuery import solutions.bitbadger.documents.query.FindQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Find` object * Unit tests for the `Find` object
@ -28,74 +28,71 @@ class FindQueryTest {
@Test @Test
@DisplayName('all generates correctly') @DisplayName('all generates correctly')
void all() { void all() {
assertEquals('Find query not constructed correctly', "SELECT data FROM $TEST_TABLE".toString(), assertEquals("SELECT data FROM $TEST_TABLE".toString(), FindQuery.all(TEST_TABLE),
FindQuery.all(TEST_TABLE)) 'Find query not constructed correctly')
} }
@Test @Test
@DisplayName('byId generates correctly | PostgreSQL') @DisplayName('byId generates correctly | PostgreSQL')
void byIdPostgres() { void byIdPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Find query not constructed correctly', assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), FindQuery.byId(TEST_TABLE),
"SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), FindQuery.byId(TEST_TABLE)) 'Find query not constructed correctly')
} }
@Test @Test
@DisplayName('byId generates correctly | SQLite') @DisplayName('byId generates correctly | SQLite')
void byIdSQLite() { void byIdSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Find query not constructed correctly', assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), FindQuery.byId(TEST_TABLE),
"SELECT data FROM $TEST_TABLE WHERE data->>'id' = :id".toString(), FindQuery.byId(TEST_TABLE)) 'Find query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | PostgreSQL') @DisplayName('byFields generates correctly | PostgreSQL')
void byFieldsPostgres() { void byFieldsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Find query not constructed correctly', assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'a' = :b AND (data->>'c')::numeric < :d".toString(),
"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'))),
FindQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b'), Field.less('c', 14, ':d')))) 'Find query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | SQLite') @DisplayName('byFields generates correctly | SQLite')
void byFieldsSQLite() { void byFieldsSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Find query not constructed correctly', assertEquals("SELECT data FROM $TEST_TABLE WHERE data->>'a' = :b AND data->>'c' < :d".toString(),
"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'))),
FindQuery.byFields(TEST_TABLE, List.of(Field.equal('a', '', ':b'), Field.less('c', 14, ':d')))) 'Find query not constructed correctly')
} }
@Test @Test
@DisplayName('byContains generates correctly | PostgreSQL') @DisplayName('byContains generates correctly | PostgreSQL')
void byContainsPostgres() { void byContainsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Find query not constructed correctly', assertEquals("SELECT data FROM $TEST_TABLE WHERE data @> :criteria".toString(),
"SELECT data FROM $TEST_TABLE WHERE data @> :criteria".toString(), FindQuery.byContains(TEST_TABLE)) FindQuery.byContains(TEST_TABLE), 'Find query not constructed correctly')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byContains fails | SQLite')
// @DisplayName('byContains fails | SQLite') void byContainsSQLite() {
// void byContainsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { FindQuery.byContains(TEST_TABLE) }
// assertThrows(DocumentException) { FindQuery.byContains(TEST_TABLE) } }
// }
@Test @Test
@DisplayName('byJsonPath generates correctly | PostgreSQL') @DisplayName('byJsonPath generates correctly | PostgreSQL')
void byJsonPathPostgres() { void byJsonPathPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Find query not constructed correctly', assertEquals("SELECT data FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
"SELECT data FROM $TEST_TABLE WHERE jsonb_path_exists(data, :path::jsonpath)".toString(), FindQuery.byJsonPath(TEST_TABLE), 'Find query not constructed correctly')
FindQuery.byJsonPath(TEST_TABLE))
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byJsonPath fails | SQLite')
// @DisplayName('byJsonPath fails | SQLite') void byJsonPathSQLite() {
// void byJsonPathSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { FindQuery.byJsonPath(TEST_TABLE) }
// assertThrows(DocumentException) { FindQuery.byJsonPath(TEST_TABLE) } }
// }
} }

View File

@ -3,13 +3,13 @@ package solutions.bitbadger.documents.groovy.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.query.PatchQuery import solutions.bitbadger.documents.query.PatchQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Patch` object * Unit tests for the `Patch` object
@ -29,69 +29,64 @@ class PatchQueryTest {
@DisplayName('byId generates correctly | PostgreSQL') @DisplayName('byId generates correctly | PostgreSQL')
void byIdPostgres() { void byIdPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Patch query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'id' = :id".toString(),
"UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'id' = :id".toString(), PatchQuery.byId(TEST_TABLE), 'Patch query not constructed correctly')
PatchQuery.byId(TEST_TABLE))
} }
@Test @Test
@DisplayName('byId generates correctly | SQLite') @DisplayName('byId generates correctly | SQLite')
void byIdSQLite() { void byIdSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Patch query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id".toString(),
"UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'id' = :id".toString(), PatchQuery.byId(TEST_TABLE), 'Patch query not constructed correctly')
PatchQuery.byId(TEST_TABLE))
} }
@Test @Test
@DisplayName('byFields generates correctly | PostgreSQL') @DisplayName('byFields generates correctly | PostgreSQL')
void byFieldsPostgres() { void byFieldsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Patch query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'z' = :y".toString(),
"UPDATE $TEST_TABLE SET data = data || :data WHERE data->>'z' = :y".toString(), PatchQuery.byFields(TEST_TABLE, List.of(Field.equal('z', '', ':y'))),
PatchQuery.byFields(TEST_TABLE, List.of(Field.equal('z', '', ':y')))) 'Patch query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | SQLite') @DisplayName('byFields generates correctly | SQLite')
void byFieldsSQLite() { void byFieldsSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Patch query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = json_patch(data, json(:data)) WHERE data->>'z' = :y".toString(),
"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'))),
PatchQuery.byFields(TEST_TABLE, List.of(Field.equal('z', '', ':y')))) 'Patch query not constructed correctly')
} }
@Test @Test
@DisplayName('byContains generates correctly | PostgreSQL') @DisplayName('byContains generates correctly | PostgreSQL')
void byContainsPostgres() { void byContainsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Patch query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = data || :data WHERE data @> :criteria".toString(),
"UPDATE $TEST_TABLE SET data = data || :data WHERE data @> :criteria".toString(), PatchQuery.byContains(TEST_TABLE), 'Patch query not constructed correctly')
PatchQuery.byContains(TEST_TABLE))
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byContains fails | SQLite')
// @DisplayName('byContains fails | SQLite') void byContainsSQLite() {
// void byContainsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { PatchQuery.byContains(TEST_TABLE) }
// assertThrows(DocumentException) { PatchQuery.byContains(TEST_TABLE) } }
// }
@Test @Test
@DisplayName('byJsonPath generates correctly | PostgreSQL') @DisplayName('byJsonPath generates correctly | PostgreSQL')
void byJsonPathPostgres() { void byJsonPathPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Patch query not constructed correctly', assertEquals(
"UPDATE $TEST_TABLE SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)".toString(), "UPDATE $TEST_TABLE SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)".toString(),
PatchQuery.byJsonPath(TEST_TABLE)) PatchQuery.byJsonPath(TEST_TABLE), 'Patch query not constructed correctly')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byJsonPath fails | SQLite')
// @DisplayName('byJsonPath fails | SQLite') void byJsonPathSQLite() {
// void byJsonPathSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { PatchQuery.byJsonPath(TEST_TABLE) }
// assertThrows(DocumentException) { PatchQuery.byJsonPath(TEST_TABLE) } }
// }
} }

View File

@ -9,7 +9,7 @@ import solutions.bitbadger.documents.FieldMatch
import solutions.bitbadger.documents.query.QueryUtils import solutions.bitbadger.documents.query.QueryUtils
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `QueryUtils` class * Unit tests for the `QueryUtils` class
@ -28,28 +28,28 @@ class QueryUtilsTest {
@Test @Test
@DisplayName('statementWhere generates correctly') @DisplayName('statementWhere generates correctly')
void statementWhere() { void statementWhere() {
assertEquals('Statements not combined correctly', 'x WHERE y', QueryUtils.statementWhere('x', 'y')) assertEquals 'x WHERE y', QueryUtils.statementWhere('x', 'y'), 'Statements not combined correctly'
} }
@Test @Test
@DisplayName('byId generates a numeric ID query | PostgreSQL') @DisplayName('byId generates a numeric ID query | PostgreSQL')
void byIdNumericPostgres() { void byIdNumericPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("test WHERE (data->>'id')::numeric = :id", QueryUtils.byId('test', 9)) assertEquals "test WHERE (data->>'id')::numeric = :id", QueryUtils.byId('test', 9)
} }
@Test @Test
@DisplayName('byId generates an alphanumeric ID query | PostgreSQL') @DisplayName('byId generates an alphanumeric ID query | PostgreSQL')
void byIdAlphaPostgres() { void byIdAlphaPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("unit WHERE data->>'id' = :id", QueryUtils.byId('unit', '18')) assertEquals "unit WHERE data->>'id' = :id", QueryUtils.byId('unit', '18')
} }
@Test @Test
@DisplayName('byId generates ID query | SQLite') @DisplayName('byId generates ID query | SQLite')
void byIdSQLite() { void byIdSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals("yo WHERE data->>'id' = :id", QueryUtils.byId('yo', 27)) assertEquals "yo WHERE data->>'id' = :id", QueryUtils.byId('yo', 27)
} }
@Test @Test
@ -89,71 +89,75 @@ class QueryUtilsTest {
@Test @Test
@DisplayName('orderBy generates for no fields') @DisplayName('orderBy generates for no fields')
void orderByNone() { void orderByNone() {
assertEquals('ORDER BY should have been blank (PostgreSQL)', '', QueryUtils.orderBy(List.of(), assertEquals('', QueryUtils.orderBy(List.of(), Dialect.POSTGRESQL),
Dialect.POSTGRESQL)) 'ORDER BY should have been blank (PostgreSQL)')
assertEquals('ORDER BY should have been blank (SQLite)', '', QueryUtils.orderBy(List.of(), Dialect.SQLITE)) assertEquals '', QueryUtils.orderBy(List.of(), Dialect.SQLITE), 'ORDER BY should have been blank (SQLite)'
} }
@Test @Test
@DisplayName('orderBy generates single, no direction | PostgreSQL') @DisplayName('orderBy generates single, no direction | PostgreSQL')
void orderBySinglePostgres() { void orderBySinglePostgres() {
assertEquals('ORDER BY not constructed correctly', " ORDER BY data->>'TestField'", assertEquals(" ORDER BY data->>'TestField'",
QueryUtils.orderBy(List.of(Field.named('TestField')), Dialect.POSTGRESQL)) QueryUtils.orderBy(List.of(Field.named('TestField')), Dialect.POSTGRESQL),
'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates single, no direction | SQLite') @DisplayName('orderBy generates single, no direction | SQLite')
void orderBySingleSQLite() { void orderBySingleSQLite() {
assertEquals('ORDER BY not constructed correctly', " ORDER BY data->>'TestField'", assertEquals(" ORDER BY data->>'TestField'",
QueryUtils.orderBy(List.of(Field.named('TestField')), Dialect.SQLITE)) QueryUtils.orderBy(List.of(Field.named('TestField')), Dialect.SQLITE),
'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates multiple with direction | PostgreSQL') @DisplayName('orderBy generates multiple with direction | PostgreSQL')
void orderByMultiplePostgres() { void orderByMultiplePostgres() {
assertEquals('ORDER BY not constructed correctly', assertEquals(" ORDER BY data#>>'{Nested,Test,Field}' DESC, data->>'AnotherField', data->>'It' DESC",
" 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'), QueryUtils.orderBy(List.of(Field.named('Nested.Test.Field DESC'), Field.named('AnotherField'),
Field.named('It DESC')), Field.named('It DESC')),
Dialect.POSTGRESQL)) Dialect.POSTGRESQL),
'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates multiple with direction | SQLite') @DisplayName('orderBy generates multiple with direction | SQLite')
void orderByMultipleSQLite() { void orderByMultipleSQLite() {
assertEquals('ORDER BY not constructed correctly', assertEquals(" ORDER BY data->'Nested'->'Test'->>'Field' DESC, data->>'AnotherField', data->>'It' DESC",
" 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'), QueryUtils.orderBy(List.of(Field.named('Nested.Test.Field DESC'), Field.named('AnotherField'),
Field.named('It DESC')), Field.named('It DESC')),
Dialect.SQLITE)) Dialect.SQLITE),
'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates numeric ordering | PostgreSQL') @DisplayName('orderBy generates numeric ordering | PostgreSQL')
void orderByNumericPostgres() { void orderByNumericPostgres() {
assertEquals('ORDER BY not constructed correctly', " ORDER BY (data->>'Test')::numeric", assertEquals(" ORDER BY (data->>'Test')::numeric",
QueryUtils.orderBy(List.of(Field.named('n:Test')), Dialect.POSTGRESQL)) QueryUtils.orderBy(List.of(Field.named('n:Test')), Dialect.POSTGRESQL),
'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates numeric ordering | SQLite') @DisplayName('orderBy generates numeric ordering | SQLite')
void orderByNumericSQLite() { void orderByNumericSQLite() {
assertEquals('ORDER BY not constructed correctly', " ORDER BY data->>'Test'", assertEquals(" ORDER BY data->>'Test'", QueryUtils.orderBy(List.of(Field.named('n:Test')), Dialect.SQLITE),
QueryUtils.orderBy(List.of(Field.named('n:Test')), Dialect.SQLITE)) 'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates case-insensitive ordering | PostgreSQL') @DisplayName('orderBy generates case-insensitive ordering | PostgreSQL')
void orderByCIPostgres() { void orderByCIPostgres() {
assertEquals('ORDER BY not constructed correctly', " ORDER BY LOWER(data#>>'{Test,Field}') DESC NULLS FIRST", assertEquals(" ORDER BY LOWER(data#>>'{Test,Field}') DESC NULLS FIRST",
QueryUtils.orderBy(List.of(Field.named('i:Test.Field DESC NULLS FIRST')), Dialect.POSTGRESQL)) QueryUtils.orderBy(List.of(Field.named('i:Test.Field DESC NULLS FIRST')), Dialect.POSTGRESQL),
'ORDER BY not constructed correctly')
} }
@Test @Test
@DisplayName('orderBy generates case-insensitive ordering | SQLite') @DisplayName('orderBy generates case-insensitive ordering | SQLite')
void orderByCISQLite() { void orderByCISQLite() {
assertEquals('ORDER BY not constructed correctly', assertEquals(" ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST",
" ORDER BY data->'Test'->>'Field' COLLATE NOCASE ASC NULLS LAST", QueryUtils.orderBy(List.of(Field.named('i:Test.Field ASC NULLS LAST')), Dialect.SQLITE),
QueryUtils.orderBy(List.of(Field.named('i:Test.Field ASC NULLS LAST')), Dialect.SQLITE)) 'ORDER BY not constructed correctly')
} }
} }

View File

@ -3,7 +3,7 @@ package solutions.bitbadger.documents.groovy.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.Parameter import solutions.bitbadger.documents.Parameter
import solutions.bitbadger.documents.ParameterType import solutions.bitbadger.documents.ParameterType
@ -11,7 +11,7 @@ import solutions.bitbadger.documents.query.RemoveFieldsQuery
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE import static solutions.bitbadger.documents.support.TypesKt.TEST_TABLE
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `RemoveFields` object * Unit tests for the `RemoveFields` object
@ -31,77 +31,77 @@ class RemoveFieldsQueryTest {
@DisplayName('byId generates correctly | PostgreSQL') @DisplayName('byId generates correctly | PostgreSQL')
void byIdPostgres() { void byIdPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Remove Fields query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data->>'id' = :id".toString(),
"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}'))),
RemoveFieldsQuery.byId(TEST_TABLE, List.of(new Parameter(':name', ParameterType.STRING, '{a,z}')))) 'Remove Fields query not constructed correctly')
} }
@Test @Test
@DisplayName('byId generates correctly | SQLite') @DisplayName('byId generates correctly | SQLite')
void byIdSQLite() { void byIdSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Remove Field query not constructed correctly', assertEquals(
"UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'id' = :id".toString(), "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'), RemoveFieldsQuery.byId(TEST_TABLE, List.of(new Parameter(':name0', ParameterType.STRING, 'a'),
new Parameter(':name1', ParameterType.STRING, 'z')))) new Parameter(':name1', ParameterType.STRING, 'z'))),
'Remove Field query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | PostgreSQL') @DisplayName('byFields generates correctly | PostgreSQL')
void byFieldsPostgres() { void byFieldsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Remove Field query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data->>'f' > :g".toString(),
"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}')), RemoveFieldsQuery.byFields(TEST_TABLE, List.of(new Parameter(':name', ParameterType.STRING, '{b,c}')),
List.of(Field.greater('f', '', ':g')))) List.of(Field.greater('f', '', ':g'))),
'Remove Field query not constructed correctly')
} }
@Test @Test
@DisplayName('byFields generates correctly | SQLite') @DisplayName('byFields generates correctly | SQLite')
void byFieldsSQLite() { void byFieldsSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals('Remove Field query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g".toString(),
"UPDATE $TEST_TABLE SET data = json_remove(data, :name0, :name1) WHERE data->>'f' > :g".toString(),
RemoveFieldsQuery.byFields(TEST_TABLE, RemoveFieldsQuery.byFields(TEST_TABLE,
List.of(new Parameter(':name0', ParameterType.STRING, 'b'), List.of(new Parameter(':name0', ParameterType.STRING, 'b'),
new Parameter(':name1', ParameterType.STRING, 'c')), new Parameter(':name1', ParameterType.STRING, 'c')),
List.of(Field.greater('f', '', ':g')))) List.of(Field.greater('f', '', ':g'))),
'Remove Field query not constructed correctly')
} }
@Test @Test
@DisplayName('byContains generates correctly | PostgreSQL') @DisplayName('byContains generates correctly | PostgreSQL')
void byContainsPostgres() { void byContainsPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Remove Field query not constructed correctly', assertEquals("UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data @> :criteria".toString(),
"UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE data @> :criteria".toString(),
RemoveFieldsQuery.byContains(TEST_TABLE, RemoveFieldsQuery.byContains(TEST_TABLE,
List.of(new Parameter(':name', ParameterType.STRING, '{m,n}')))) List.of(new Parameter(':name', ParameterType.STRING, '{m,n}'))),
'Remove Field query not constructed correctly')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byContains fails | SQLite')
// @DisplayName('byContains fails | SQLite') void byContainsSQLite() {
// void byContainsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { RemoveFieldsQuery.byContains(TEST_TABLE, List.of()) }
// assertThrows(DocumentException) { RemoveFieldsQuery.byContains(TEST_TABLE, List.of()) } }
// }
@Test @Test
@DisplayName('byJsonPath generates correctly | PostgreSQL') @DisplayName('byJsonPath generates correctly | PostgreSQL')
void byJsonPathPostgres() { void byJsonPathPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('Remove Field query not constructed correctly', assertEquals(
"UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)" "UPDATE $TEST_TABLE SET data = data - :name::text[] WHERE jsonb_path_exists(data, :path::jsonpath)"
.toString(), .toString(),
RemoveFieldsQuery.byJsonPath(TEST_TABLE, RemoveFieldsQuery.byJsonPath(TEST_TABLE,
List.of(new Parameter(':name', ParameterType.STRING, '{o,p}')))) List.of(new Parameter(':name', ParameterType.STRING, '{o,p}'))),
'Remove Field query not constructed correctly')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('byJsonPath fails | SQLite')
// @DisplayName('byJsonPath fails | SQLite') void byJsonPathSQLite() {
// void byJsonPathSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { RemoveFieldsQuery.byJsonPath(TEST_TABLE, List.of()) }
// assertThrows(DocumentException) { RemoveFieldsQuery.byJsonPath(TEST_TABLE, List.of()) } }
// }
} }

View File

@ -3,13 +3,13 @@ package solutions.bitbadger.documents.groovy.query
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
//import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.Field import solutions.bitbadger.documents.Field
import solutions.bitbadger.documents.FieldMatch import solutions.bitbadger.documents.FieldMatch
import solutions.bitbadger.documents.query.Where import solutions.bitbadger.documents.query.Where
import solutions.bitbadger.documents.support.ForceDialect import solutions.bitbadger.documents.support.ForceDialect
import static groovy.test.GroovyAssert.* import static org.junit.jupiter.api.Assertions.*
/** /**
* Unit tests for the `Where` object * Unit tests for the `Where` object
@ -28,28 +28,28 @@ class WhereTest {
@Test @Test
@DisplayName('byFields is blank when given no fields') @DisplayName('byFields is blank when given no fields')
void byFieldsBlankIfEmpty() { void byFieldsBlankIfEmpty() {
assertEquals('', Where.byFields(List.of())) assertEquals '', Where.byFields(List.of())
} }
@Test @Test
@DisplayName('byFields generates one numeric field | PostgreSQL') @DisplayName('byFields generates one numeric field | PostgreSQL')
void byFieldsOneFieldPostgres() { void byFieldsOneFieldPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("(data->>'it')::numeric = :that", Where.byFields(List.of(Field.equal('it', 9, ':that')))) assertEquals "(data->>'it')::numeric = :that", Where.byFields(List.of(Field.equal('it', 9, ':that')))
} }
@Test @Test
@DisplayName('byFields generates one alphanumeric field | PostgreSQL') @DisplayName('byFields generates one alphanumeric field | PostgreSQL')
void byFieldsOneAlphaFieldPostgres() { void byFieldsOneAlphaFieldPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("data->>'it' = :that", Where.byFields(List.of(Field.equal('it', '', ':that')))) assertEquals "data->>'it' = :that", Where.byFields(List.of(Field.equal('it', '', ':that')))
} }
@Test @Test
@DisplayName('byFields generates one field | SQLite') @DisplayName('byFields generates one field | SQLite')
void byFieldsOneFieldSQLite() { void byFieldsOneFieldSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals("data->>'it' = :that", Where.byFields(List.of(Field.equal('it', '', ':that')))) assertEquals "data->>'it' = :that", Where.byFields(List.of(Field.equal('it', '', ':that')))
} }
@Test @Test
@ -98,78 +98,76 @@ class WhereTest {
@DisplayName('byId generates defaults for alphanumeric key | PostgreSQL') @DisplayName('byId generates defaults for alphanumeric key | PostgreSQL')
void byIdDefaultAlphaPostgres() { void byIdDefaultAlphaPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("data->>'id' = :id", Where.byId()) assertEquals "data->>'id' = :id", Where.byId()
} }
@Test @Test
@DisplayName('byId generates defaults for numeric key | PostgreSQL') @DisplayName('byId generates defaults for numeric key | PostgreSQL')
void byIdDefaultNumericPostgres() { void byIdDefaultNumericPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("(data->>'id')::numeric = :id", Where.byId(":id", 5)) assertEquals "(data->>'id')::numeric = :id", Where.byId(":id", 5)
} }
@Test @Test
@DisplayName('byId generates defaults | SQLite') @DisplayName('byId generates defaults | SQLite')
void byIdDefaultSQLite() { void byIdDefaultSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals("data->>'id' = :id", Where.byId()) assertEquals "data->>'id' = :id", Where.byId()
} }
@Test @Test
@DisplayName('byId generates named ID | PostgreSQL') @DisplayName('byId generates named ID | PostgreSQL')
void byIdDefaultNamedPostgres() { void byIdDefaultNamedPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals("data->>'id' = :key", Where.byId(':key')) assertEquals "data->>'id' = :key", Where.byId(':key')
} }
@Test @Test
@DisplayName('byId generates named ID | SQLite') @DisplayName('byId generates named ID | SQLite')
void byIdDefaultNamedSQLite() { void byIdDefaultNamedSQLite() {
ForceDialect.sqlite() ForceDialect.sqlite()
assertEquals("data->>'id' = :key", Where.byId(':key')) assertEquals "data->>'id' = :key", Where.byId(':key')
} }
@Test @Test
@DisplayName('jsonContains generates defaults | PostgreSQL') @DisplayName('jsonContains generates defaults | PostgreSQL')
void jsonContainsDefaultPostgres() { void jsonContainsDefaultPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('data @> :criteria', Where.jsonContains()) assertEquals 'data @> :criteria', Where.jsonContains()
} }
@Test @Test
@DisplayName('jsonContains generates named parameter | PostgreSQL') @DisplayName('jsonContains generates named parameter | PostgreSQL')
void jsonContainsNamedPostgres() { void jsonContainsNamedPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('data @> :it', Where.jsonContains(':it')) assertEquals 'data @> :it', Where.jsonContains(':it')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('jsonContains fails | SQLite')
// @DisplayName('jsonContains fails | SQLite') void jsonContainsFailsSQLite() {
// void jsonContainsFailsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { Where.jsonContains() }
// assertThrows(DocumentException) { Where.jsonContains() } }
// }
@Test @Test
@DisplayName('jsonPathMatches generates defaults | PostgreSQL') @DisplayName('jsonPathMatches generates defaults | PostgreSQL')
void jsonPathMatchDefaultPostgres() { void jsonPathMatchDefaultPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('jsonb_path_exists(data, :path::jsonpath)', Where.jsonPathMatches()) assertEquals 'jsonb_path_exists(data, :path::jsonpath)', Where.jsonPathMatches()
} }
@Test @Test
@DisplayName('jsonPathMatches generates named parameter | PostgreSQL') @DisplayName('jsonPathMatches generates named parameter | PostgreSQL')
void jsonPathMatchNamedPostgres() { void jsonPathMatchNamedPostgres() {
ForceDialect.postgres() ForceDialect.postgres()
assertEquals('jsonb_path_exists(data, :jp::jsonpath)', Where.jsonPathMatches(':jp')) assertEquals 'jsonb_path_exists(data, :jp::jsonpath)', Where.jsonPathMatches(':jp')
} }
// TODO: resolve java.base open issue @Test
// @Test @DisplayName('jsonPathMatches fails | SQLite')
// @DisplayName('jsonPathMatches fails | SQLite') void jsonPathFailsSQLite() {
// void jsonPathFailsSQLite() { ForceDialect.sqlite()
// ForceDialect.sqlite() assertThrows(DocumentException) { Where.jsonPathMatches() }
// assertThrows(DocumentException) { Where.jsonPathMatches() } }
// }
} }

View File

@ -26,8 +26,6 @@ class JsonDocument {
new JsonDocument("five", "purple", 18)) new JsonDocument("five", "purple", 18))
static void load(ThrowawayDatabase db, String tableName = TEST_TABLE) { static void load(ThrowawayDatabase db, String tableName = TEST_TABLE) {
for (doc in testDocuments) { testDocuments.forEach { Document.insert(tableName, it, db.conn) }
Document.insert(tableName, doc, db.conn)
}
} }
} }