Skip to content

Commit

Permalink
Init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
TrulsStenrud committed Aug 28, 2023
1 parent d5588bf commit 630dd4a
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
</dependency>
<dependency>
<groupId>io.mockk</groupId>
<artifactId>mockk</artifactId>
<artifactId>mockk-jvm</artifactId>
<version>1.13.7</version>
<scope>test</scope>
</dependency>
Expand Down
19 changes: 11 additions & 8 deletions src/main/kotlin/no/liflig/documentstore/dao/Dao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interface Dao
*/
interface CrudDao<I : EntityId, A : EntityRoot<I>> : Dao {

fun create(entity: A,): VersionedEntity<A>
fun create(entity: A): VersionedEntity<A>

fun get(id: I, forUpdate: Boolean = false): VersionedEntity<A>?

Expand Down Expand Up @@ -252,17 +252,18 @@ abstract class AbstractSearchRepository<I, A, Q>(
sqlWhere: String = "TRUE",
limit: Int? = null,
offset: Int? = null,
domainPredicate: ((A) -> Boolean)? = null,
orderBy: String? = null,
orderDesc: Boolean = false,
bind: Query.() -> Query = { this }
): List<VersionedEntity<A>> = mapExceptions {
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)
}
}
}
Expand All @@ -272,12 +273,11 @@ abstract class AbstractSearchRepository<I, A, Q>(
handle: Handle,
limit: Int? = null,
offset: Int? = null,
domainPredicate: ((A) -> Boolean)? = null,
orderBy: String? = null,
desc: Boolean = false,
bind: Query.() -> Query = { this }
): MutableList<VersionedEntity<A>> {
val limitString = limit?.let { "LIMIT $it" } ?: ""
val offsetString = offset?.let { "OFFSET $it" } ?: ""
val orderDirection = if (desc) "DESC" else "ASC"
val orderByString = orderBy ?: "created_at"

Expand All @@ -288,13 +288,15 @@ abstract class AbstractSearchRepository<I, A, Q>(
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()
}
}

Expand Down Expand Up @@ -360,6 +362,7 @@ inline fun <T> mapExceptions(block: () -> T): T {
is InterruptedIOException,
is ConnectionException,
is CloseException -> throw UnavailableDaoException(e)

is NoCountReceivedFromSearchQueryException -> throw e

else -> throw UnknownDaoException(e)
Expand Down
101 changes: 101 additions & 0 deletions src/test/kotlin/no/liflig/documentstore/DomainfilterTest.kt
Original file line number Diff line number Diff line change
@@ -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<ExampleId, ExampleEntity, ExampleTextSearchQuery>(
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
}
}
}
12 changes: 10 additions & 2 deletions src/test/kotlin/no/liflig/documentstore/TransactionalTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<ExampleEntity>(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<ExampleEntity>(limit = 2, offset = 1000)
val result2 = searchRepositoryWithCount.searchWithCount(queryWithOffsetHigherThanCount)
assertEquals(result2.count, 3)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<A>(
val limit: Int? = null,
val offset: Int? = null,
val domainPredicate: ((A) -> Boolean)? = null,
val orderBy: OrderBy? = null,
val orderDesc: Boolean = false,
)
Expand All @@ -29,17 +32,20 @@ class ExampleSearchRepository(
sqlTableName: String,
serializationAdapter: SerializationAdapter<ExampleEntity>
) :
AbstractSearchRepository<ExampleId, ExampleEntity, ExampleQueryObject>(
AbstractSearchRepository<ExampleId, ExampleEntity, ExampleQueryObject<ExampleEntity>>(
jdbi, sqlTableName, serializationAdapter
) {
override fun listByIds(ids: List<ExampleId>): List<VersionedEntity<ExampleEntity>> {
TODO("Not yet implemented")
}

override fun search(query: ExampleQueryObject): List<VersionedEntity<ExampleEntity>> =
fun listAll(): List<VersionedEntity<ExampleEntity>> = getByPredicate()

override fun search(query: ExampleQueryObject<ExampleEntity>): List<VersionedEntity<ExampleEntity>> =
getByPredicate(
limit = query.limit,
offset = query.offset,
domainPredicate = query.domainPredicate,
orderDesc = query.orderDesc,
orderBy =
when (query.orderBy) {
Expand All @@ -55,17 +61,17 @@ class ExampleSearchRepositoryWithCount(
sqlTableName: String,
serializationAdapter: SerializationAdapter<ExampleEntity>
) :
AbstractSearchRepositoryWithCount<ExampleId, ExampleEntity, ExampleQueryObject>(
AbstractSearchRepositoryWithCount<ExampleId, ExampleEntity, ExampleQueryObject<ExampleEntity>>(
jdbi,
sqlTableName,
serializationAdapter,
) {
override fun search(query: ExampleQueryObject): List<VersionedEntity<ExampleEntity>> {
override fun search(query: ExampleQueryObject<ExampleEntity>): List<VersionedEntity<ExampleEntity>> {
TODO("Not yet implemented")
}

override fun searchWithCount(
query: ExampleQueryObject
query: ExampleQueryObject<ExampleEntity>
): EntitiesWithCount<ExampleEntity> {
return getByPredicateWithCount(
limit = query.limit,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package no.liflig.documentstore
package no.liflig.documentstore.testexamples

import kotlinx.serialization.json.Json
import no.liflig.documentstore.dao.SerializationAdapter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package no.liflig.documentstore
package no.liflig.documentstore.testexamples

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
Expand Down

0 comments on commit 630dd4a

Please sign in to comment.