All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lightningkite.ktordb.InMemoryFieldCollection.kt Maven / Gradle / Ivy

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
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy