Initial Development #1
@ -98,4 +98,23 @@ object Parameters {
 | 
				
			|||||||
            throw DocumentException("Error creating query / binding parameters: ${ex.message}", ex)
 | 
					            throw DocumentException("Error creating query / binding parameters: ${ex.message}", ex)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create parameters for field names to be removed from a document
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param names The names of the fields to be removed
 | 
				
			||||||
 | 
					     * @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") =
 | 
				
			||||||
 | 
					        when (Configuration.dialect("generate field name parameters")) {
 | 
				
			||||||
 | 
					            Dialect.POSTGRESQL -> listOf(Parameter(parameterName, ParameterType.STRING, if (names.size == 1) {
 | 
				
			||||||
 | 
					                    names.elementAt(0)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    names.joinToString(",").let { "{$it}" }
 | 
				
			||||||
 | 
					                }))
 | 
				
			||||||
 | 
					            Dialect.SQLITE -> names.mapIndexed { index, name ->
 | 
				
			||||||
 | 
					                Parameter("$parameterName$index", ParameterType.STRING, name)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -51,7 +51,7 @@ object Patch {
 | 
				
			|||||||
     * @param tableName The name of the table where the document is stored
 | 
					     * @param tableName The name of the table where the document is stored
 | 
				
			||||||
     * @return A query to patch JSON documents by JSON containment
 | 
					     * @return A query to patch JSON documents by JSON containment
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    fun <TKey> byContains(tableName: String) =
 | 
					    fun byContains(tableName: String) =
 | 
				
			||||||
        statementWhere(patch(tableName), Where.jsonContains())
 | 
					        statementWhere(patch(tableName), Where.jsonContains())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -60,6 +60,6 @@ object Patch {
 | 
				
			|||||||
     * @param tableName The name of the table where the document is stored
 | 
					     * @param tableName The name of the table where the document is stored
 | 
				
			||||||
     * @return A query to patch JSON documents by JSON path match
 | 
					     * @return A query to patch JSON documents by JSON path match
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    fun <TKey> byJsonPath(tableName: String) =
 | 
					    fun byJsonPath(tableName: String) =
 | 
				
			||||||
        statementWhere(patch(tableName), Where.jsonPathMatches())
 | 
					        statementWhere(patch(tableName), Where.jsonPathMatches())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										74
									
								
								src/main/kotlin/query/RemoveFields.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/main/kotlin/query/RemoveFields.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					package solutions.bitbadger.documents.query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.*
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.query.byFields as byFieldsBase
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.query.byId as byIdBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Functions to create queries to remove fields from documents
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					object RemoveFields {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a query to remove fields based on the given parameters
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param tableName The name of the table in which documents should have fields removed
 | 
				
			||||||
 | 
					     * @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>>) =
 | 
				
			||||||
 | 
					        when (Configuration.dialect("generate field removal query")) {
 | 
				
			||||||
 | 
					            Dialect.POSTGRESQL -> "UPDATE $tableName SET data = data - ${toRemove[0].name}::text[]"
 | 
				
			||||||
 | 
					            Dialect.SQLITE -> toRemove.joinToString(", ") { it.name }.let {
 | 
				
			||||||
 | 
					                "UPDATE $tableName SET data = json_remove(data, $it)"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A query to patch (partially update) a JSON document by its ID
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param tableName The name of the table where the document is stored
 | 
				
			||||||
 | 
					     * @param toRemove The parameters for the fields to be removed
 | 
				
			||||||
 | 
					     * @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) =
 | 
				
			||||||
 | 
					        byIdBase(removeFields(tableName, toRemove), docId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A query to patch (partially update) a JSON document using field match criteria
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param tableName The name of the table where the documents are stored
 | 
				
			||||||
 | 
					     * @param toRemove The parameters for the fields to be removed
 | 
				
			||||||
 | 
					     * @param fields The field criteria
 | 
				
			||||||
 | 
					     * @param howMatched How the fields should be matched (optional, defaults to `ALL`)
 | 
				
			||||||
 | 
					     * @return A query to patch JSON documents by field match criteria
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fun byFields(
 | 
				
			||||||
 | 
					        tableName: String,
 | 
				
			||||||
 | 
					        toRemove: List<Parameter<String>>,
 | 
				
			||||||
 | 
					        fields: Collection<Field<*>>,
 | 
				
			||||||
 | 
					        howMatched: FieldMatch? = null
 | 
				
			||||||
 | 
					    ) =
 | 
				
			||||||
 | 
					        byFieldsBase(removeFields(tableName, toRemove), fields, howMatched)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A query to patch (partially update) a JSON document by JSON containment (PostgreSQL only)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param tableName The name of the table where the document is stored
 | 
				
			||||||
 | 
					     * @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>>) =
 | 
				
			||||||
 | 
					        statementWhere(removeFields(tableName, toRemove), Where.jsonContains())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A query to patch (partially update) a JSON document by JSON path match (PostgreSQL only)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param tableName The name of the table where the document is stored
 | 
				
			||||||
 | 
					     * @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>>) =
 | 
				
			||||||
 | 
					        statementWhere(removeFields(tableName, toRemove), Where.jsonPathMatches())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package solutions.bitbadger.documents
 | 
					package solutions.bitbadger.documents
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.AfterEach
 | 
				
			||||||
import org.junit.jupiter.api.DisplayName
 | 
					import org.junit.jupiter.api.DisplayName
 | 
				
			||||||
import kotlin.test.Test
 | 
					import kotlin.test.Test
 | 
				
			||||||
import kotlin.test.assertEquals
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
@ -12,6 +13,14 @@ import kotlin.test.assertSame
 | 
				
			|||||||
@DisplayName("Parameters")
 | 
					@DisplayName("Parameters")
 | 
				
			||||||
class ParametersTest {
 | 
					class ParametersTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Clear the connection string (resets Dialect)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @AfterEach
 | 
				
			||||||
 | 
					    fun cleanUp() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    @DisplayName("nameFields works with no changes")
 | 
					    @DisplayName("nameFields works with no changes")
 | 
				
			||||||
    fun nameFieldsNoChange() {
 | 
					    fun nameFieldsNoChange() {
 | 
				
			||||||
@ -47,4 +56,54 @@ class ParametersTest {
 | 
				
			|||||||
        assertEquals("SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?",
 | 
					        assertEquals("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), "Parameters not replaced correctly")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("fieldNames generates a single parameter (PostgreSQL)")
 | 
				
			||||||
 | 
					    fun fieldNamesSinglePostgres() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.POSTGRESQL
 | 
				
			||||||
 | 
					        val nameParams = Parameters.fieldNames(listOf("test"))
 | 
				
			||||||
 | 
					        assertEquals(1, nameParams.size, "There should be one name parameter")
 | 
				
			||||||
 | 
					        assertEquals(":name", nameParams[0].name, "The parameter name is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(ParameterType.STRING, nameParams[0].type, "The parameter type is incorrect")
 | 
				
			||||||
 | 
					        assertEquals("test", nameParams[0].value, "The parameter value is incorrect")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("fieldNames generates multiple parameters (PostgreSQL)")
 | 
				
			||||||
 | 
					    fun fieldNamesMultiplePostgres() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.POSTGRESQL
 | 
				
			||||||
 | 
					        val nameParams = Parameters.fieldNames(listOf("test", "this", "today"))
 | 
				
			||||||
 | 
					        assertEquals(1, nameParams.size, "There should be one name parameter")
 | 
				
			||||||
 | 
					        assertEquals(":name", nameParams[0].name, "The parameter name is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(ParameterType.STRING, nameParams[0].type, "The parameter type is incorrect")
 | 
				
			||||||
 | 
					        assertEquals("{test,this,today}", nameParams[0].value, "The parameter value is incorrect")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("fieldNames generates a single parameter (SQLite)")
 | 
				
			||||||
 | 
					    fun fieldNamesSingleSQLite() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.SQLITE
 | 
				
			||||||
 | 
					        val nameParams = Parameters.fieldNames(listOf("test"))
 | 
				
			||||||
 | 
					        assertEquals(1, nameParams.size, "There should be one name parameter")
 | 
				
			||||||
 | 
					        assertEquals(":name0", nameParams[0].name, "The parameter name is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(ParameterType.STRING, nameParams[0].type, "The parameter type is incorrect")
 | 
				
			||||||
 | 
					        assertEquals("test", nameParams[0].value, "The parameter value is incorrect")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("fieldNames generates multiple parameters (SQLite)")
 | 
				
			||||||
 | 
					    fun fieldNamesMultipleSQLite() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.SQLITE
 | 
				
			||||||
 | 
					        val nameParams = Parameters.fieldNames(listOf("test", "this", "today"))
 | 
				
			||||||
 | 
					        assertEquals(3, nameParams.size, "There should be one name parameter")
 | 
				
			||||||
 | 
					        assertEquals(":name0", nameParams[0].name, "The first parameter name is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(ParameterType.STRING, nameParams[0].type, "The first parameter type is incorrect")
 | 
				
			||||||
 | 
					        assertEquals("test", nameParams[0].value, "The first parameter value is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(":name1", nameParams[1].name, "The second parameter name is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(ParameterType.STRING, nameParams[1].type, "The second parameter type is incorrect")
 | 
				
			||||||
 | 
					        assertEquals("this", nameParams[1].value, "The second parameter value is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(":name2", nameParams[2].name, "The third parameter name is incorrect")
 | 
				
			||||||
 | 
					        assertEquals(ParameterType.STRING, nameParams[2].type, "The third parameter type is incorrect")
 | 
				
			||||||
 | 
					        assertEquals("today", nameParams[2].value, "The third parameter value is incorrect")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										102
									
								
								src/test/kotlin/query/DeleteTest.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/test/kotlin/query/DeleteTest.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					package solutions.bitbadger.documents.query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.AfterEach
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.DisplayName
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Test
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.assertThrows
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.Configuration
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.Dialect
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.DocumentException
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.Field
 | 
				
			||||||
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Unit tests for the `Delete` object
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@DisplayName("Delete (Query)")
 | 
				
			||||||
 | 
					class DeleteTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Test table name */
 | 
				
			||||||
 | 
					    private val tbl = "test_table"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Clear the connection string (resets Dialect)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @AfterEach
 | 
				
			||||||
 | 
					    fun cleanUp() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byId generates correctly (PostgreSQL)")
 | 
				
			||||||
 | 
					    fun byIdPostgres() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.POSTGRESQL
 | 
				
			||||||
 | 
					        assertEquals(
 | 
				
			||||||
 | 
					            "DELETE FROM $tbl WHERE data->>'id' = :id",
 | 
				
			||||||
 | 
					            Delete.byId<String>(tbl), "Delete query not constructed correctly"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byId generates correctly (SQLite)")
 | 
				
			||||||
 | 
					    fun byIdSQLite() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.SQLITE
 | 
				
			||||||
 | 
					        assertEquals(
 | 
				
			||||||
 | 
					            "DELETE FROM $tbl WHERE data->>'id' = :id",
 | 
				
			||||||
 | 
					            Delete.byId<String>(tbl), "Delete query not constructed correctly"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byFields generates correctly (PostgreSQL)")
 | 
				
			||||||
 | 
					    fun byFieldsPostgres() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.POSTGRESQL
 | 
				
			||||||
 | 
					        assertEquals(
 | 
				
			||||||
 | 
					            "DELETE FROM $tbl WHERE data->>'a' = :b", Delete.byFields(tbl, listOf(Field.equal("a", "", ":b"))),
 | 
				
			||||||
 | 
					            "Delete query not constructed correctly"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byFields generates correctly (SQLite)")
 | 
				
			||||||
 | 
					    fun byFieldsSQLite() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.SQLITE
 | 
				
			||||||
 | 
					        assertEquals(
 | 
				
			||||||
 | 
					            "DELETE FROM $tbl WHERE data->>'a' = :b", Delete.byFields(tbl, listOf(Field.equal("a", "", ":b"))),
 | 
				
			||||||
 | 
					            "Delete query not constructed correctly"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byContains generates correctly (PostgreSQL)")
 | 
				
			||||||
 | 
					    fun byContainsPostgres() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.POSTGRESQL
 | 
				
			||||||
 | 
					        assertEquals(
 | 
				
			||||||
 | 
					            "DELETE FROM $tbl WHERE data @> :criteria", Delete.byContains(tbl), "Delete query not constructed correctly"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byContains fails (SQLite)")
 | 
				
			||||||
 | 
					    fun byContainsSQLite() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.SQLITE
 | 
				
			||||||
 | 
					        assertThrows<DocumentException> { Delete.byContains(tbl) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byJsonPath generates correctly (PostgreSQL)")
 | 
				
			||||||
 | 
					    fun byJsonPathPostgres() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.POSTGRESQL
 | 
				
			||||||
 | 
					        assertEquals(
 | 
				
			||||||
 | 
					            "DELETE FROM $tbl WHERE jsonb_path_exists(data, :path::jsonpath)", Delete.byJsonPath(tbl),
 | 
				
			||||||
 | 
					            "Delete query not constructed correctly"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("byJsonPath fails (SQLite)")
 | 
				
			||||||
 | 
					    fun byJsonPathSQLite() {
 | 
				
			||||||
 | 
					        Configuration.dialectValue = Dialect.SQLITE
 | 
				
			||||||
 | 
					        assertThrows<DocumentException> { Delete.byJsonPath(tbl) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -11,7 +11,7 @@ import solutions.bitbadger.documents.Field
 | 
				
			|||||||
import kotlin.test.assertEquals
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Unit tests for the `Exists` object
 | 
					 * Unit tests for the `Find` object
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@DisplayName("Find (Query)")
 | 
					@DisplayName("Find (Query)")
 | 
				
			||||||
class FindTest {
 | 
					class FindTest {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user