Initial Development #1
@ -23,13 +23,10 @@ data class ArrayDocument(val id: String, val values: List<String>) {
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class JsonDocument(val id: String, val value: String, val numValue: Int, val sub: SubDocument?) {
|
||||
data class JsonDocument(val id: String, val value: String = "", val numValue: Int = 0, val sub: SubDocument? = null) {
|
||||
companion object {
|
||||
/** An empty JsonDocument */
|
||||
val emptyDoc = JsonDocument("", "", 0, null)
|
||||
|
||||
/** Documents to use for testing */
|
||||
val testDocuments = listOf(
|
||||
private val testDocuments = listOf(
|
||||
JsonDocument("one", "FIRST!", 0, null),
|
||||
JsonDocument("two", "another", 10, SubDocument("green", "blue")),
|
||||
JsonDocument("three", "", 4, null),
|
||||
|
@ -56,7 +56,7 @@ object Document {
|
||||
Configuration.autoIdStrategy = AutoId.UUID
|
||||
assertEquals(0L, db.conn.countAll(TEST_TABLE), "There should be no documents in the table")
|
||||
|
||||
db.conn.insert(TEST_TABLE, JsonDocument.emptyDoc)
|
||||
db.conn.insert(TEST_TABLE, JsonDocument(""))
|
||||
|
||||
val after = db.conn.findAll<JsonDocument>(TEST_TABLE)
|
||||
assertEquals(1, after.size, "There should have been 1 document returned")
|
||||
@ -71,10 +71,10 @@ object Document {
|
||||
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, JsonDocument.emptyDoc)
|
||||
db.conn.insert(TEST_TABLE, JsonDocument(""))
|
||||
|
||||
Configuration.idStringLength = 21
|
||||
db.conn.insert(TEST_TABLE, JsonDocument.emptyDoc)
|
||||
db.conn.insert(TEST_TABLE, JsonDocument(""))
|
||||
|
||||
val after = db.conn.findAll<JsonDocument>(TEST_TABLE)
|
||||
assertEquals(2, after.size, "There should have been 2 documents returned")
|
||||
|
@ -7,7 +7,7 @@ import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Integration tests for the `Find` object
|
||||
* Integration tests for the `Patch` object
|
||||
*/
|
||||
object Patch {
|
||||
|
||||
|
106
src/integration-test/kotlin/common/RemoveFields.kt
Normal file
106
src/integration-test/kotlin/common/RemoveFields.kt
Normal file
@ -0,0 +1,106 @@
|
||||
package solutions.bitbadger.documents.common
|
||||
|
||||
import solutions.bitbadger.documents.*
|
||||
import kotlin.test.*
|
||||
|
||||
|
||||
/**
|
||||
* Integration tests for the `RemoveFields` object
|
||||
*/
|
||||
object RemoveFields {
|
||||
|
||||
fun byIdMatchFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
db.conn.removeFieldsById(TEST_TABLE, "two", listOf("sub", "value"))
|
||||
val doc = db.conn.findById<String, JsonDocument>(TEST_TABLE, "two")
|
||||
assertNotNull(doc, "There should have been a document returned")
|
||||
assertEquals("", doc.value, "The value should have been empty")
|
||||
assertNull(doc.sub, "The sub-document should have been removed")
|
||||
}
|
||||
|
||||
fun byIdMatchNoFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
assertFalse { db.conn.existsByFields(TEST_TABLE, listOf(Field.exists("a_field_that_does_not_exist"))) }
|
||||
db.conn.removeFieldsById(TEST_TABLE, "one", listOf("a_field_that_does_not_exist")) // no exception = pass
|
||||
}
|
||||
|
||||
fun byIdNoMatch(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
assertFalse { db.conn.existsById(TEST_TABLE, "fifty") }
|
||||
db.conn.removeFieldsById(TEST_TABLE, "fifty", listOf("sub")) // no exception = pass
|
||||
}
|
||||
|
||||
fun byFieldsMatchFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
val fields = listOf(Field.equal("numValue", 17))
|
||||
db.conn.removeFieldsByFields(TEST_TABLE, fields, listOf("sub"))
|
||||
val doc = db.conn.findFirstByFields<JsonDocument>(TEST_TABLE, fields)
|
||||
assertNotNull(doc, "The document should have been returned")
|
||||
assertEquals("four", doc.id, "An incorrect document was returned")
|
||||
assertNull(doc.sub, "The sub-document should have been removed")
|
||||
}
|
||||
|
||||
fun byFieldsMatchNoFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
assertFalse { db.conn.existsByFields(TEST_TABLE, listOf(Field.exists("nada"))) }
|
||||
db.conn.removeFieldsByFields(TEST_TABLE, listOf(Field.equal("numValue", 17)), listOf("nada")) // no exn = pass
|
||||
}
|
||||
|
||||
fun byFieldsNoMatch(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
val fields = listOf(Field.notEqual("missing", "nope"))
|
||||
assertFalse { db.conn.existsByFields(TEST_TABLE, fields) }
|
||||
db.conn.removeFieldsByFields(TEST_TABLE, fields, listOf("value")) // no exception = pass
|
||||
}
|
||||
|
||||
fun byContainsMatchFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
val criteria = mapOf("sub" to mapOf("foo" to "green"))
|
||||
db.conn.removeFieldsByContains(TEST_TABLE, criteria, listOf("value"))
|
||||
val docs = db.conn.findByContains<JsonDocument, Map<String, Map<String, String>>>(TEST_TABLE, criteria)
|
||||
assertEquals(2, docs.size, "There should have been 2 documents returned")
|
||||
docs.forEach {
|
||||
assertTrue(listOf("two", "four").contains(it.id), "An incorrect document was returned (${it.id})")
|
||||
assertEquals("", it.value, "The value should have been empty")
|
||||
}
|
||||
}
|
||||
|
||||
fun byContainsMatchNoFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
assertFalse { db.conn.existsByFields(TEST_TABLE, listOf(Field.exists("invalid_field"))) }
|
||||
db.conn.removeFieldsByContains(TEST_TABLE, mapOf("sub" to mapOf("foo" to "green")), listOf("invalid_field"))
|
||||
// no exception = pass
|
||||
}
|
||||
|
||||
fun byContainsNoMatch(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
val contains = mapOf("value" to "substantial")
|
||||
assertFalse { db.conn.existsByContains(TEST_TABLE, contains) }
|
||||
db.conn.removeFieldsByContains(TEST_TABLE, contains, listOf("numValue"))
|
||||
}
|
||||
|
||||
fun byJsonPathMatchFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
val path = "$.value ? (@ == \"purple\")"
|
||||
db.conn.removeFieldsByJsonPath(TEST_TABLE, path, listOf("sub"))
|
||||
val docs = db.conn.findByJsonPath<JsonDocument>(TEST_TABLE, path)
|
||||
assertEquals(2, docs.size, "There should have been 2 documents returned")
|
||||
docs.forEach {
|
||||
assertTrue(listOf("four", "five").contains(it.id), "An incorrect document was returned (${it.id})")
|
||||
assertNull(it.sub, "The sub-document should have been removed")
|
||||
}
|
||||
}
|
||||
|
||||
fun byJsonPathMatchNoFields(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
assertFalse { db.conn.existsByFields(TEST_TABLE, listOf(Field.exists("submarine"))) }
|
||||
db.conn.removeFieldsByJsonPath(TEST_TABLE, "$.value ? (@ == \"purple\")", listOf("submarine")) // no exn = pass
|
||||
}
|
||||
|
||||
fun byJsonPathNoMatch(db: ThrowawayDatabase) {
|
||||
JsonDocument.load(db)
|
||||
val path = "$.value ? (@ == \"mauve\")"
|
||||
assertFalse { db.conn.existsByJsonPath(TEST_TABLE, path) }
|
||||
db.conn.removeFieldsByJsonPath(TEST_TABLE, path, listOf("value")) // no exception = pass
|
||||
}
|
||||
}
|
72
src/integration-test/kotlin/postgresql/RemoveFieldsIT.kt
Normal file
72
src/integration-test/kotlin/postgresql/RemoveFieldsIT.kt
Normal file
@ -0,0 +1,72 @@
|
||||
package solutions.bitbadger.documents.postgresql
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import solutions.bitbadger.documents.common.RemoveFields
|
||||
import kotlin.test.Test
|
||||
|
||||
/**
|
||||
* PostgreSQL integration tests for the `RemoveFields` object / `removeFieldsBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName("PostgreSQL - RemoveFields")
|
||||
class RemoveFieldsIT {
|
||||
|
||||
@Test
|
||||
@DisplayName("byId removes fields from an existing document")
|
||||
fun byIdMatchFields() =
|
||||
PgDB().use(RemoveFields::byIdMatchFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byId succeeds when fields do not exist on an existing document")
|
||||
fun byIdMatchNoFields() =
|
||||
PgDB().use(RemoveFields::byIdMatchNoFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byId succeeds when no document exists")
|
||||
fun byIdNoMatch() =
|
||||
PgDB().use(RemoveFields::byIdNoMatch)
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields removes fields from matching documents")
|
||||
fun byFieldsMatchFields() =
|
||||
PgDB().use(RemoveFields::byFieldsMatchFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields succeeds when fields do not exist on matching documents")
|
||||
fun byFieldsMatchNoFields() =
|
||||
PgDB().use(RemoveFields::byFieldsMatchNoFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields succeeds when no matching documents exist")
|
||||
fun byFieldsNoMatch() =
|
||||
PgDB().use(RemoveFields::byFieldsNoMatch)
|
||||
|
||||
@Test
|
||||
@DisplayName("byContains removes fields from matching documents")
|
||||
fun byContainsMatchFields() =
|
||||
PgDB().use(RemoveFields::byContainsMatchFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byContains succeeds when fields do not exist on matching documents")
|
||||
fun byContainsMatchNoFields() =
|
||||
PgDB().use(RemoveFields::byContainsMatchNoFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byContains succeeds when no matching documents exist")
|
||||
fun byContainsNoMatch() =
|
||||
PgDB().use(RemoveFields::byContainsNoMatch)
|
||||
|
||||
@Test
|
||||
@DisplayName("byJsonPath removes fields from matching documents")
|
||||
fun byJsonPathMatchFields() =
|
||||
PgDB().use(RemoveFields::byJsonPathMatchFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byJsonPath succeeds when fields do not exist on matching documents")
|
||||
fun byJsonPathMatchNoFields() =
|
||||
PgDB().use(RemoveFields::byJsonPathMatchNoFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byJsonPath succeeds when no matching documents exist")
|
||||
fun byJsonPathNoMatch() =
|
||||
PgDB().use(RemoveFields::byJsonPathNoMatch)
|
||||
}
|
56
src/integration-test/kotlin/sqlite/RemoveFieldsIT.kt
Normal file
56
src/integration-test/kotlin/sqlite/RemoveFieldsIT.kt
Normal file
@ -0,0 +1,56 @@
|
||||
package solutions.bitbadger.documents.sqlite
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import solutions.bitbadger.documents.DocumentException
|
||||
import solutions.bitbadger.documents.common.RemoveFields
|
||||
import kotlin.test.Test
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `RemoveFields` object / `removeFieldsBy*` connection extension functions
|
||||
*/
|
||||
@DisplayName("SQLite - RemoveFields")
|
||||
class RemoveFieldsIT {
|
||||
|
||||
@Test
|
||||
@DisplayName("byId removes fields from an existing document")
|
||||
fun byIdMatchFields() =
|
||||
SQLiteDB().use(RemoveFields::byIdMatchFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byId succeeds when fields do not exist on an existing document")
|
||||
fun byIdMatchNoFields() =
|
||||
SQLiteDB().use(RemoveFields::byIdMatchNoFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byId succeeds when no document exists")
|
||||
fun byIdNoMatch() =
|
||||
SQLiteDB().use(RemoveFields::byIdNoMatch)
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields removes fields from matching documents")
|
||||
fun byFieldsMatchFields() =
|
||||
SQLiteDB().use(RemoveFields::byFieldsMatchFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields succeeds when fields do not exist on matching documents")
|
||||
fun byFieldsMatchNoFields() =
|
||||
SQLiteDB().use(RemoveFields::byFieldsMatchNoFields)
|
||||
|
||||
@Test
|
||||
@DisplayName("byFields succeeds when no matching documents exist")
|
||||
fun byFieldsNoMatch() =
|
||||
SQLiteDB().use(RemoveFields::byFieldsNoMatch)
|
||||
|
||||
@Test
|
||||
@DisplayName("byContains fails")
|
||||
fun byContainsFails() {
|
||||
assertThrows<DocumentException> { SQLiteDB().use(RemoveFields::byContainsMatchFields) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("byJsonPath fails")
|
||||
fun byJsonPathFails() {
|
||||
assertThrows<DocumentException> { SQLiteDB().use(RemoveFields::byJsonPathMatchFields) }
|
||||
}
|
||||
}
|
@ -13,8 +13,9 @@ object Configuration {
|
||||
* https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md for all configuration options
|
||||
*/
|
||||
var json = Json {
|
||||
encodeDefaults = true
|
||||
explicitNulls = false
|
||||
encodeDefaults = true
|
||||
explicitNulls = false
|
||||
coerceInputValues = true
|
||||
}
|
||||
|
||||
/** The field in which a document's ID is stored */
|
||||
|
@ -356,6 +356,60 @@ inline fun <reified TContains, reified TPatch> Connection.patchByContains(
|
||||
inline fun <reified TPatch> Connection.patchByJsonPath(tableName: String, path: String, patch: TPatch) =
|
||||
Patch.byJsonPath(tableName, path, patch, this)
|
||||
|
||||
// ~~~ DOCUMENT FIELD REMOVAL QUERIES ~~~
|
||||
|
||||
/**
|
||||
* Remove fields from a document by its ID
|
||||
*
|
||||
* @param tableName The name of the table in which the document's fields should be removed
|
||||
* @param docId The ID of the document to have fields removed
|
||||
* @param toRemove The names of the fields to be removed
|
||||
*/
|
||||
fun <TKey> Connection.removeFieldsById(tableName: String, docId: TKey, toRemove: Collection<String>) =
|
||||
RemoveFields.byId(tableName, docId, toRemove, this)
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a field comparison
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param fields The fields which should be compared
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @param howMatched How the fields should be matched
|
||||
*/
|
||||
fun Connection.removeFieldsByFields(
|
||||
tableName: String,
|
||||
fields: Collection<Field<*>>,
|
||||
toRemove: Collection<String>,
|
||||
howMatched: FieldMatch? = null
|
||||
) =
|
||||
RemoveFields.byFields(tableName, fields, toRemove, howMatched, this)
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a JSON containment query (PostgreSQL only)
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param criteria The object against which JSON containment should be checked
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @throws DocumentException If called on a SQLite connection
|
||||
*/
|
||||
inline fun <reified TContains> Connection.removeFieldsByContains(
|
||||
tableName: String,
|
||||
criteria: TContains,
|
||||
toRemove: Collection<String>
|
||||
) =
|
||||
RemoveFields.byContains(tableName, criteria, toRemove, this)
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a JSON Path match query (PostgreSQL only)
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param path The JSON path comparison to match
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @throws DocumentException If called on a SQLite connection
|
||||
*/
|
||||
fun Connection.removeFieldsByJsonPath(tableName: String, path: String, toRemove: Collection<String>) =
|
||||
RemoveFields.byJsonPath(tableName, path, toRemove, this)
|
||||
|
||||
// ~~~ DOCUMENT DELETION QUERIES ~~~
|
||||
|
||||
/**
|
||||
|
@ -105,14 +105,14 @@ object Parameters {
|
||||
* @param parameterName The parameter name to use for the query
|
||||
* @return A list of parameters to use for building the query
|
||||
*/
|
||||
fun fieldNames(names: Collection<String>, parameterName: String = ":name") =
|
||||
fun fieldNames(names: Collection<String>, parameterName: String = ":name"): MutableCollection<Parameter<*>> =
|
||||
when (Configuration.dialect("generate field name parameters")) {
|
||||
Dialect.POSTGRESQL -> listOf(
|
||||
Dialect.POSTGRESQL -> mutableListOf(
|
||||
Parameter(parameterName, ParameterType.STRING, names.joinToString(",").let { "{$it}" })
|
||||
)
|
||||
|
||||
Dialect.SQLITE -> names.mapIndexed { index, name ->
|
||||
Parameter("$parameterName$index", ParameterType.STRING, name)
|
||||
}
|
||||
}.toMutableList()
|
||||
}
|
||||
}
|
||||
|
154
src/main/kotlin/RemoveFields.kt
Normal file
154
src/main/kotlin/RemoveFields.kt
Normal file
@ -0,0 +1,154 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import solutions.bitbadger.documents.query.RemoveFields
|
||||
import java.sql.Connection
|
||||
|
||||
/**
|
||||
* Functions to remove fields from documents
|
||||
*/
|
||||
object RemoveFields {
|
||||
|
||||
/**
|
||||
* Translate field paths to JSON paths for SQLite queries
|
||||
*
|
||||
* @param parameters The parameters for the specified fields
|
||||
* @return The parameters for the specified fields, translated if used for SQLite
|
||||
*/
|
||||
private fun translatePath(parameters: MutableCollection<Parameter<*>>): MutableCollection<Parameter<*>> {
|
||||
val dialect = Configuration.dialect("remove fields")
|
||||
return when (dialect) {
|
||||
Dialect.POSTGRESQL -> parameters
|
||||
Dialect.SQLITE -> parameters.map { Parameter(it.name, it.type, "$.${it.value}") }.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove fields from a document by its ID
|
||||
*
|
||||
* @param tableName The name of the table in which the document's fields should be removed
|
||||
* @param docId The ID of the document to have fields removed
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @param conn The connection on which the update should be executed
|
||||
*/
|
||||
fun <TKey> byId(tableName: String, docId: TKey, toRemove: Collection<String>, conn: Connection) {
|
||||
val nameParams = Parameters.fieldNames(toRemove)
|
||||
conn.customNonQuery(
|
||||
RemoveFields.byId(tableName, nameParams, docId),
|
||||
Parameters.addFields(
|
||||
listOf(Field.equal(Configuration.idField, docId, ":id")),
|
||||
translatePath(nameParams)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove fields from a document by its ID
|
||||
*
|
||||
* @param tableName The name of the table in which the document's fields should be removed
|
||||
* @param docId The ID of the document to have fields removed
|
||||
* @param toRemove The names of the fields to be removed
|
||||
*/
|
||||
fun <TKey> byId(tableName: String, docId: TKey, toRemove: Collection<String>) =
|
||||
Configuration.dbConn().use { byId(tableName, docId, toRemove, it) }
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a field comparison
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param fields The fields which should be compared
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @param howMatched How the fields should be matched
|
||||
* @param conn The connection on which the update should be executed
|
||||
*/
|
||||
fun byFields(
|
||||
tableName: String,
|
||||
fields: Collection<Field<*>>,
|
||||
toRemove: Collection<String>,
|
||||
howMatched: FieldMatch? = null,
|
||||
conn: Connection
|
||||
) {
|
||||
val named = Parameters.nameFields(fields)
|
||||
val nameParams = Parameters.fieldNames(toRemove)
|
||||
conn.customNonQuery(
|
||||
RemoveFields.byFields(tableName, nameParams, named, howMatched),
|
||||
Parameters.addFields(named, translatePath(nameParams))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a field comparison
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param fields The fields which should be compared
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @param howMatched How the fields should be matched
|
||||
*/
|
||||
fun byFields(
|
||||
tableName: String,
|
||||
fields: Collection<Field<*>>,
|
||||
toRemove: Collection<String>,
|
||||
howMatched: FieldMatch? = null
|
||||
) =
|
||||
Configuration.dbConn().use { byFields(tableName, fields, toRemove, howMatched, it) }
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a JSON containment query (PostgreSQL only)
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param criteria The object against which JSON containment should be checked
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @param conn The connection on which the update should be executed
|
||||
* @throws DocumentException If called on a SQLite connection
|
||||
*/
|
||||
inline fun <reified TContains> byContains(
|
||||
tableName: String,
|
||||
criteria: TContains,
|
||||
toRemove: Collection<String>,
|
||||
conn: Connection
|
||||
) {
|
||||
val nameParams = Parameters.fieldNames(toRemove)
|
||||
conn.customNonQuery(
|
||||
RemoveFields.byContains(tableName, nameParams),
|
||||
listOf(Parameters.json(":criteria", criteria), *nameParams.toTypedArray())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a JSON containment query (PostgreSQL only)
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param criteria The object against which JSON containment should be checked
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @throws DocumentException If called on a SQLite connection
|
||||
*/
|
||||
inline fun <reified TContains> byContains(tableName: String, criteria: TContains, toRemove: Collection<String>) =
|
||||
Configuration.dbConn().use { byContains(tableName, criteria, toRemove, it) }
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a JSON Path match query (PostgreSQL only)
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param path The JSON path comparison to match
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @param conn The connection on which the update should be executed
|
||||
* @throws DocumentException If called on a SQLite connection
|
||||
*/
|
||||
fun byJsonPath(tableName: String, path: String, toRemove: Collection<String>, conn: Connection) {
|
||||
val nameParams = Parameters.fieldNames(toRemove)
|
||||
conn.customNonQuery(
|
||||
RemoveFields.byJsonPath(tableName, nameParams),
|
||||
listOf(Parameter(":path", ParameterType.STRING, path), *nameParams.toTypedArray())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove fields from documents using a JSON Path match query (PostgreSQL only)
|
||||
*
|
||||
* @param tableName The name of the table in which document fields should be removed
|
||||
* @param path The JSON path comparison to match
|
||||
* @param toRemove The names of the fields to be removed
|
||||
* @throws DocumentException If called on a SQLite connection
|
||||
*/
|
||||
fun byJsonPath(tableName: String, path: String, toRemove: Collection<String>) =
|
||||
Configuration.dbConn().use { byJsonPath(tableName, path, toRemove, it) }
|
||||
}
|
@ -16,9 +16,9 @@ object RemoveFields {
|
||||
* @param toRemove The parameters for the fields to be removed
|
||||
* @return A query to remove fields from documents in the given table
|
||||
*/
|
||||
private fun removeFields(tableName: String, toRemove: List<Parameter<String>>) =
|
||||
private fun removeFields(tableName: String, toRemove: Collection<Parameter<*>>) =
|
||||
when (Configuration.dialect("generate field removal query")) {
|
||||
Dialect.POSTGRESQL -> "UPDATE $tableName SET data = data - ${toRemove[0].name}::text[]"
|
||||
Dialect.POSTGRESQL -> "UPDATE $tableName SET data = data - ${toRemove.elementAt(0).name}::text[]"
|
||||
Dialect.SQLITE -> toRemove.joinToString(", ") { it.name }.let {
|
||||
"UPDATE $tableName SET data = json_remove(data, $it)"
|
||||
}
|
||||
@ -32,7 +32,7 @@ object RemoveFields {
|
||||
* @param docId The ID of the document to be updated (optional, used for type checking)
|
||||
* @return A query to patch a JSON document by its ID
|
||||
*/
|
||||
fun <TKey> byId(tableName: String, toRemove: List<Parameter<String>>, docId: TKey? = null) =
|
||||
fun <TKey> byId(tableName: String, toRemove: Collection<Parameter<*>>, docId: TKey? = null) =
|
||||
byIdBase(removeFields(tableName, toRemove), docId)
|
||||
|
||||
/**
|
||||
@ -46,7 +46,7 @@ object RemoveFields {
|
||||
*/
|
||||
fun byFields(
|
||||
tableName: String,
|
||||
toRemove: List<Parameter<String>>,
|
||||
toRemove: Collection<Parameter<*>>,
|
||||
fields: Collection<Field<*>>,
|
||||
howMatched: FieldMatch? = null
|
||||
) =
|
||||
@ -59,7 +59,7 @@ object RemoveFields {
|
||||
* @param toRemove The parameters for the fields to be removed
|
||||
* @return A query to patch JSON documents by JSON containment
|
||||
*/
|
||||
fun byContains(tableName: String, toRemove: List<Parameter<String>>) =
|
||||
fun byContains(tableName: String, toRemove: Collection<Parameter<*>>) =
|
||||
statementWhere(removeFields(tableName, toRemove), Where.jsonContains())
|
||||
|
||||
/**
|
||||
@ -69,6 +69,6 @@ object RemoveFields {
|
||||
* @param toRemove The parameters for the fields to be removed
|
||||
* @return A query to patch JSON documents by JSON path match
|
||||
*/
|
||||
fun byJsonPath(tableName: String, toRemove: List<Parameter<String>>) =
|
||||
fun byJsonPath(tableName: String, toRemove: Collection<Parameter<*>>) =
|
||||
statementWhere(removeFields(tableName, toRemove), Where.jsonPathMatches())
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ class ConfigurationTest {
|
||||
fun defaultJsonOptions() {
|
||||
assertTrue(Configuration.json.configuration.encodeDefaults, "Encode Defaults should have been set")
|
||||
assertFalse(Configuration.json.configuration.explicitNulls, "Explicit Nulls should not have been set")
|
||||
assertTrue(Configuration.json.configuration.coerceInputValues, "Coerce Input Values should have been set")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -62,7 +62,7 @@ class ParametersTest {
|
||||
@DisplayName("fieldNames generates a single parameter (PostgreSQL)")
|
||||
fun fieldNamesSinglePostgres() {
|
||||
Configuration.dialectValue = Dialect.POSTGRESQL
|
||||
val nameParams = Parameters.fieldNames(listOf("test"))
|
||||
val nameParams = Parameters.fieldNames(listOf("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")
|
||||
@ -73,7 +73,7 @@ class ParametersTest {
|
||||
@DisplayName("fieldNames generates multiple parameters (PostgreSQL)")
|
||||
fun fieldNamesMultiplePostgres() {
|
||||
Configuration.dialectValue = Dialect.POSTGRESQL
|
||||
val nameParams = Parameters.fieldNames(listOf("test", "this", "today"))
|
||||
val nameParams = Parameters.fieldNames(listOf("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")
|
||||
@ -84,7 +84,7 @@ class ParametersTest {
|
||||
@DisplayName("fieldNames generates a single parameter (SQLite)")
|
||||
fun fieldNamesSingleSQLite() {
|
||||
Configuration.dialectValue = Dialect.SQLITE
|
||||
val nameParams = Parameters.fieldNames(listOf("test"))
|
||||
val nameParams = Parameters.fieldNames(listOf("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")
|
||||
@ -95,7 +95,7 @@ class ParametersTest {
|
||||
@DisplayName("fieldNames generates multiple parameters (SQLite)")
|
||||
fun fieldNamesMultipleSQLite() {
|
||||
Configuration.dialectValue = Dialect.SQLITE
|
||||
val nameParams = Parameters.fieldNames(listOf("test", "this", "today"))
|
||||
val nameParams = Parameters.fieldNames(listOf("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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user