diff --git a/pom.xml b/pom.xml
index 29a2dc5..dace3da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -167,7 +167,7 @@
io.mockk
- mockk
+ mockk-jvm
1.13.7
test
diff --git a/src/main/kotlin/no/liflig/documentstore/dao/Dao.kt b/src/main/kotlin/no/liflig/documentstore/dao/Dao.kt
index a07ca7e..78cd539 100644
--- a/src/main/kotlin/no/liflig/documentstore/dao/Dao.kt
+++ b/src/main/kotlin/no/liflig/documentstore/dao/Dao.kt
@@ -45,7 +45,7 @@ interface Dao
*/
interface CrudDao> : Dao {
- fun create(entity: A,): VersionedEntity
+ fun create(entity: A): VersionedEntity
fun get(id: I, forUpdate: Boolean = false): VersionedEntity?
@@ -252,6 +252,7 @@ abstract class AbstractSearchRepository(
sqlWhere: String = "TRUE",
limit: Int? = null,
offset: Int? = null,
+ domainPredicate: ((A) -> Boolean)? = null,
orderBy: String? = null,
orderDesc: Boolean = false,
bind: Query.() -> Query = { this }
@@ -259,10 +260,10 @@ abstract class AbstractSearchRepository(
val transaction = transactionHandle.get()
if (transaction != null) {
- innerGetByPredicate(sqlWhere, transaction, limit, offset, orderBy, orderDesc, bind)
+ innerGetByPredicate(sqlWhere, transaction, limit, offset, domainPredicate, orderBy, orderDesc, bind)
} else {
jdbi.open().use { handle ->
- innerGetByPredicate(sqlWhere, handle, limit, offset, orderBy, orderDesc, bind)
+ innerGetByPredicate(sqlWhere, handle, limit, offset, domainPredicate, orderBy, orderDesc, bind)
}
}
}
@@ -272,12 +273,11 @@ abstract class AbstractSearchRepository(
handle: Handle,
limit: Int? = null,
offset: Int? = null,
+ domainPredicate: ((A) -> Boolean)? = null,
orderBy: String? = null,
desc: Boolean = false,
bind: Query.() -> Query = { this }
): MutableList> {
- val limitString = limit?.let { "LIMIT $it" } ?: ""
- val offsetString = offset?.let { "OFFSET $it" } ?: ""
val orderDirection = if (desc) "DESC" else "ASC"
val orderByString = orderBy ?: "created_at"
@@ -288,13 +288,15 @@ abstract class AbstractSearchRepository(
FROM "$sqlTableName"
WHERE ($sqlWhere)
ORDER BY $orderByString $orderDirection
- $limitString
- $offsetString
""".trimIndent()
)
.bind()
.map(rowMapper)
- .list()
+ .stream()
+ .run { domainPredicate?.let { filter { agg -> it(agg.item) } } ?: this }
+ .run { offset?.let { skip(it.toLong()) } ?: this }
+ .run { limit?.let{ limit(it.toLong()) } ?: this }
+ .toList()
}
}
@@ -360,6 +362,7 @@ inline fun mapExceptions(block: () -> T): T {
is InterruptedIOException,
is ConnectionException,
is CloseException -> throw UnavailableDaoException(e)
+
is NoCountReceivedFromSearchQueryException -> throw e
else -> throw UnknownDaoException(e)
diff --git a/src/test/kotlin/no/liflig/documentstore/DomainfilterTest.kt b/src/test/kotlin/no/liflig/documentstore/DomainfilterTest.kt
new file mode 100644
index 0000000..6099f7e
--- /dev/null
+++ b/src/test/kotlin/no/liflig/documentstore/DomainfilterTest.kt
@@ -0,0 +1,101 @@
+package no.liflig.documentstore
+
+import io.kotest.matchers.collections.shouldHaveSize
+import io.kotest.matchers.ints.exactly
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
+import kotlinx.coroutines.runBlocking
+import no.liflig.documentstore.dao.CrudDaoJdbi
+import no.liflig.documentstore.dao.SearchRepositoryWithCountJdbi
+import no.liflig.documentstore.testexamples.ExampleEntity
+import no.liflig.documentstore.testexamples.ExampleId
+import no.liflig.documentstore.testexamples.ExampleQueryObject
+import no.liflig.documentstore.testexamples.ExampleSearchRepository
+import no.liflig.documentstore.testexamples.ExampleSerializationAdapter
+import no.liflig.documentstore.testexamples.ExampleTextSearchQuery
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.TestInstance
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+class DomainPredicateTest {
+ val jdbi = createTestDatabase()
+
+ val serializationAdapter = ExampleSerializationAdapter()
+
+ val dao = CrudDaoJdbi(jdbi, "example", serializationAdapter)
+
+ val searchRepository = ExampleSearchRepository(jdbi, "example", serializationAdapter)
+
+ val searchRepositoryWithCountJdbi = SearchRepositoryWithCountJdbi(
+ jdbi, "example", serializationAdapter,
+ )
+
+ @BeforeEach
+ fun clearDatabase(){
+ searchRepository.listAll().forEach {
+ dao.delete(it.item.id, it.version)
+ }
+ }
+ @Test
+ fun domainPredicateWorks() {
+ runBlocking {
+ dao.create(ExampleEntity.create("Hello Tes"))
+ dao.create(ExampleEntity.create("Hello Alfred"))
+ dao.create(ExampleEntity.create("Bye Ted"))
+ dao.create(ExampleEntity.create("Bye Alfred"))
+
+ searchRepository.search(
+ ExampleQueryObject(
+ domainPredicate = { it.text.contains("Hello") },
+ )
+ ) shouldHaveSize 2
+ }
+ }
+
+ @Test
+ fun limitWorks() {
+ runBlocking {
+ val mockAdapter: ExampleSerializationAdapter = mockk {
+ every { fromJson(any()) } returns ExampleEntity.create("")
+ }
+ val searchRepository = ExampleSearchRepository(jdbi, "example", mockAdapter)
+ dao.create(ExampleEntity.create("Hello Tes"))
+ dao.create(ExampleEntity.create("Hello Alfred"))
+ dao.create(ExampleEntity.create("Bye Ted"))
+ dao.create(ExampleEntity.create("Bye Alfred"))
+
+ val result = searchRepository.search(
+ ExampleQueryObject(
+ limit = 1
+ )
+ )
+
+ result shouldHaveSize 1
+ verify(exactly = 1) { mockAdapter.fromJson(any()) }
+ }
+ }
+
+ @Test
+ fun offSetWorks() {
+ runBlocking {
+ val mockAdapter: ExampleSerializationAdapter = mockk {
+ every { fromJson(any()) } returns ExampleEntity.create("")
+ }
+ val searchRepository = ExampleSearchRepository(jdbi, "example", mockAdapter)
+ dao.create(ExampleEntity.create("Hello Tes"))
+ dao.create(ExampleEntity.create("Hello Alfred"))
+ dao.create(ExampleEntity.create("Bye Ted"))
+ dao.create(ExampleEntity.create("Bye Alfred"))
+
+ val result = searchRepository.search(
+ ExampleQueryObject(
+ offset = 3
+ )
+ )
+
+ result shouldHaveSize 1
+ }
+ }
+}
diff --git a/src/test/kotlin/no/liflig/documentstore/TransactionalTest.kt b/src/test/kotlin/no/liflig/documentstore/TransactionalTest.kt
index 6bf3719..4b7522b 100644
--- a/src/test/kotlin/no/liflig/documentstore/TransactionalTest.kt
+++ b/src/test/kotlin/no/liflig/documentstore/TransactionalTest.kt
@@ -10,6 +10,14 @@ import no.liflig.documentstore.dao.SearchRepositoryWithCountJdbi
import no.liflig.documentstore.dao.coTransactional
import no.liflig.documentstore.dao.transactional
import no.liflig.documentstore.entity.Version
+import no.liflig.documentstore.testexamples.ExampleEntity
+import no.liflig.documentstore.testexamples.ExampleId
+import no.liflig.documentstore.testexamples.ExampleQueryObject
+import no.liflig.documentstore.testexamples.ExampleSearchRepository
+import no.liflig.documentstore.testexamples.ExampleSearchRepositoryWithCount
+import no.liflig.documentstore.testexamples.ExampleSerializationAdapter
+import no.liflig.documentstore.testexamples.ExampleTextSearchQuery
+import no.liflig.documentstore.testexamples.OrderBy
import no.liflig.snapshot.verifyJsonSnapshot
import org.jdbi.v3.core.Jdbi
import org.junit.jupiter.api.Named
@@ -310,12 +318,12 @@ class TransactionalTest {
daoWithCount.create(ExampleEntity.create("B"))
daoWithCount.create(ExampleEntity.create("C"))
- val queryWithLimitLessThanCount = ExampleQueryObject(limit = 2, offset = 0)
+ val queryWithLimitLessThanCount = ExampleQueryObject(limit = 2, offset = 0)
val result1 = searchRepositoryWithCount.searchWithCount(queryWithLimitLessThanCount)
assertEquals(result1.entities.size, queryWithLimitLessThanCount.limit)
assertEquals(result1.count, 3)
- val queryWithOffsetHigherThanCount = ExampleQueryObject(limit = 2, offset = 1000)
+ val queryWithOffsetHigherThanCount = ExampleQueryObject(limit = 2, offset = 1000)
val result2 = searchRepositoryWithCount.searchWithCount(queryWithOffsetHigherThanCount)
assertEquals(result2.count, 3)
}
diff --git a/src/test/kotlin/no/liflig/documentstore/ExampleEntity.kt b/src/test/kotlin/no/liflig/documentstore/testexamples/ExampleEntity.kt
similarity index 98%
rename from src/test/kotlin/no/liflig/documentstore/ExampleEntity.kt
rename to src/test/kotlin/no/liflig/documentstore/testexamples/ExampleEntity.kt
index 4e51d8c..00e4d3b 100644
--- a/src/test/kotlin/no/liflig/documentstore/ExampleEntity.kt
+++ b/src/test/kotlin/no/liflig/documentstore/testexamples/ExampleEntity.kt
@@ -1,6 +1,6 @@
@file:UseSerializers(InstantSerializer::class)
-package no.liflig.documentstore
+package no.liflig.documentstore.testexamples
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
diff --git a/src/test/kotlin/no/liflig/documentstore/ExampleSearchRepository.kt b/src/test/kotlin/no/liflig/documentstore/testexamples/ExampleSearchRepository.kt
similarity index 77%
rename from src/test/kotlin/no/liflig/documentstore/ExampleSearchRepository.kt
rename to src/test/kotlin/no/liflig/documentstore/testexamples/ExampleSearchRepository.kt
index 426332b..821d19c 100644
--- a/src/test/kotlin/no/liflig/documentstore/ExampleSearchRepository.kt
+++ b/src/test/kotlin/no/liflig/documentstore/testexamples/ExampleSearchRepository.kt
@@ -1,6 +1,6 @@
@file:UseSerializers(InstantSerializer::class)
-package no.liflig.documentstore
+package no.liflig.documentstore.testexamples
import kotlinx.serialization.UseSerializers
import no.liflig.documentstore.dao.AbstractSearchRepository
@@ -9,12 +9,15 @@ import no.liflig.documentstore.dao.EntitiesWithCount
import no.liflig.documentstore.dao.SearchRepositoryQuery
import no.liflig.documentstore.dao.SerializationAdapter
import no.liflig.documentstore.entity.VersionedEntity
+import org.checkerframework.checker.units.qual.A
+import org.checkerframework.checker.units.qual.C
import org.jdbi.v3.core.Jdbi
import org.jdbi.v3.core.statement.Query
-data class ExampleQueryObject(
+data class ExampleQueryObject(
val limit: Int? = null,
val offset: Int? = null,
+ val domainPredicate: ((A) -> Boolean)? = null,
val orderBy: OrderBy? = null,
val orderDesc: Boolean = false,
)
@@ -29,17 +32,20 @@ class ExampleSearchRepository(
sqlTableName: String,
serializationAdapter: SerializationAdapter
) :
- AbstractSearchRepository(
+ AbstractSearchRepository>(
jdbi, sqlTableName, serializationAdapter
) {
override fun listByIds(ids: List): List> {
TODO("Not yet implemented")
}
- override fun search(query: ExampleQueryObject): List> =
+ fun listAll(): List> = getByPredicate()
+
+ override fun search(query: ExampleQueryObject): List> =
getByPredicate(
limit = query.limit,
offset = query.offset,
+ domainPredicate = query.domainPredicate,
orderDesc = query.orderDesc,
orderBy =
when (query.orderBy) {
@@ -55,17 +61,17 @@ class ExampleSearchRepositoryWithCount(
sqlTableName: String,
serializationAdapter: SerializationAdapter
) :
- AbstractSearchRepositoryWithCount(
+ AbstractSearchRepositoryWithCount>(
jdbi,
sqlTableName,
serializationAdapter,
) {
- override fun search(query: ExampleQueryObject): List> {
+ override fun search(query: ExampleQueryObject): List> {
TODO("Not yet implemented")
}
override fun searchWithCount(
- query: ExampleQueryObject
+ query: ExampleQueryObject
): EntitiesWithCount {
return getByPredicateWithCount(
limit = query.limit,
diff --git a/src/test/kotlin/no/liflig/documentstore/ExampleSerializationAdapter.kt b/src/test/kotlin/no/liflig/documentstore/testexamples/ExampleSerializationAdapter.kt
similarity index 91%
rename from src/test/kotlin/no/liflig/documentstore/ExampleSerializationAdapter.kt
rename to src/test/kotlin/no/liflig/documentstore/testexamples/ExampleSerializationAdapter.kt
index 340c07b..a8b08e6 100644
--- a/src/test/kotlin/no/liflig/documentstore/ExampleSerializationAdapter.kt
+++ b/src/test/kotlin/no/liflig/documentstore/testexamples/ExampleSerializationAdapter.kt
@@ -1,4 +1,4 @@
-package no.liflig.documentstore
+package no.liflig.documentstore.testexamples
import kotlinx.serialization.json.Json
import no.liflig.documentstore.dao.SerializationAdapter
diff --git a/src/test/kotlin/no/liflig/documentstore/InstantSerializer.kt b/src/test/kotlin/no/liflig/documentstore/testexamples/InstantSerializer.kt
similarity index 94%
rename from src/test/kotlin/no/liflig/documentstore/InstantSerializer.kt
rename to src/test/kotlin/no/liflig/documentstore/testexamples/InstantSerializer.kt
index 9bd1139..42aa8fb 100644
--- a/src/test/kotlin/no/liflig/documentstore/InstantSerializer.kt
+++ b/src/test/kotlin/no/liflig/documentstore/testexamples/InstantSerializer.kt
@@ -1,4 +1,4 @@
-package no.liflig.documentstore
+package no.liflig.documentstore.testexamples
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind