com.lightningkite.ktordb.InMemoryFieldCollection.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of db Show documentation
Show all versions of db Show documentation
An abstract tool for communicating with different types of databases.
The newest version!
package com.lightningkite.ktordb
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
import kotlin.reflect.KProperty1
open class InMemoryFieldCollection(val data: MutableList = ArrayList()) :
AbstractSignalFieldCollection() {
private val lock = ReentrantLock()
val changeChannel = MutableSharedFlow>()
override suspend fun find(
condition: Condition,
orderBy: List>,
skip: Int,
limit: Int,
maxQueryMs: Long
): Flow = flow {
val result = lock.withLock {
data.asSequence()
.filter { condition(it) }
.let {
orderBy.comparator?.let { c ->
it.sortedWith(c)
} ?: it
}
.drop(skip)
.take(limit)
.toList()
}
result
.forEach {
emit(it)
}
}
override suspend fun count(condition: Condition): Int = data.count { condition(it) }
override suspend fun groupCount(
condition: Condition,
groupBy: KProperty1,
): Map = data.groupingBy { groupBy.get(it) }.eachCount()
override suspend fun aggregate(
aggregate: Aggregate,
condition: Condition,
property: KProperty1
): Double? = data.asSequence().map { property.get(it).toDouble() }.aggregate(aggregate)
override suspend fun groupAggregate(
aggregate: Aggregate,
condition: Condition,
groupBy: KProperty1,
property: KProperty1,
): Map =
data.asSequence().mapNotNull { groupBy.get(it) to (property.get(it)?.toDouble() ?: return@mapNotNull null) }
.aggregate(aggregate)
override suspend fun insertImpl(models: List): List = lock.withLock {
data.addAll(models)
models.forEach { model ->
changeChannel.tryEmit(EntryChange(null, model))
}
return models
}
override suspend fun replaceOneImpl(condition: Condition, model: Model): EntryChange = lock.withLock {
for (it in data.indices) {
val old = data[it]
if (condition(old)) {
data[it] = model
val changes = EntryChange(old, model)
changeChannel.tryEmit(changes)
return changes
}
}
return EntryChange(null, null)
}
override suspend fun upsertOneImpl(
condition: Condition,
modification: Modification,
model: Model
): EntryChange = lock.withLock {
for (it in data.indices) {
val old = data[it]
if (condition(old)) {
val changed = modification(old)
data[it] = changed
val changes = EntryChange(old, changed)
changeChannel.tryEmit(changes)
return changes
}
}
data.add(model)
val changes = EntryChange(null, model)
changeChannel.tryEmit(changes)
return changes
}
override suspend fun updateOneImpl(
condition: Condition,
modification: Modification
): EntryChange = lock.withLock {
for (it in data.indices) {
val old = data[it]
if (condition(old)) {
val new = modification(old)
data[it] = new
val changes = EntryChange(old, new)
changeChannel.tryEmit(changes)
return changes
}
}
return EntryChange(null, null)
}
override suspend fun updateManyImpl(
condition: Condition,
modification: Modification
): CollectionChanges = lock.withLock {
val changes = ArrayList>()
var counter = 0
data.indices.forEach {
val old = data[it]
if (condition(old)) {
val new = modification(old)
data[it] = new
val change = EntryChange(old, new)
changeChannel.tryEmit(change)
changes.add(change)
counter++
}
}
return CollectionChanges(changes = changes)
}
override suspend fun deleteOneImpl(condition: Condition): Model? = lock.withLock {
for (it in data.indices) {
val old = data[it]
if (condition(old)) {
data.removeAt(it)
changeChannel.tryEmit(EntryChange(old, null))
return old
}
}
return null
}
override suspend fun deleteManyImpl(condition: Condition): List = lock.withLock {
val removed = ArrayList()
data.removeAll {
if (condition(it)) {
changeChannel.tryEmit(EntryChange(it, null))
removed.add(it)
true
} else {
false
}
}
return removed
}
override suspend fun watch(condition: Condition): Flow> =
changeChannel.onEach { delay(1L) }
override suspend fun replaceOneIgnoringResultImpl(condition: Condition, model: Model): Boolean =
replaceOne(condition, model).new != null
override suspend fun upsertOneIgnoringResultImpl(
condition: Condition,
modification: Modification,
model: Model
): Boolean = upsertOne(condition, modification, model).old != null
override suspend fun updateOneIgnoringResultImpl(
condition: Condition,
modification: Modification
): Boolean = updateOne(condition, modification).new != null
override suspend fun updateManyIgnoringResultImpl(
condition: Condition,
modification: Modification
): Int = updateMany(condition, modification).changes.size
override suspend fun deleteOneIgnoringOldImpl(condition: Condition): Boolean = deleteOne(condition) != null
override suspend fun deleteManyIgnoringOldImpl(condition: Condition): Int = deleteMany(condition).size
}