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

com.lightningkite.lightningdb.simpleSignals.kt Maven / Gradle / Ivy

The newest version!
package com.lightningkite.lightningdb

import kotlinx.coroutines.flow.FlowCollector

/**
 * Runs after an item is created.
 */
fun  FieldCollection.postCreate(
    onCreate: suspend (Model) -> Unit
): FieldCollection = object : FieldCollection by this@postCreate {
    override val wraps = this@postCreate
    override suspend fun insert(models: Iterable): List {
        val result = wraps.insertMany(models)
        result.forEach { onCreate(it) }
        return result
    }

    override suspend fun upsertOne(
        condition: Condition,
        modification: Modification,
        model: Model
    ): EntryChange = wraps.upsertOne(condition, modification, model).also {
        if (it.old == null) onCreate(it.new!!)
    }
}

@Deprecated("Use 'interceptDelete' instead", ReplaceWith("interceptDelete(onDelete)"))
fun  FieldCollection.preDelete(onDelete: suspend (Model) -> Unit): FieldCollection = interceptDelete(onDelete)

/**
 * Runs after an item is deleted.
 */
fun , ID : Comparable> FieldCollection.postDelete(
    onDelete: suspend (Model) -> Unit
): FieldCollection = object : FieldCollection by this@postDelete {
    override val wraps = this@postDelete
    override suspend fun deleteManyIgnoringOld(condition: Condition): Int {
        return wraps.deleteMany(condition).also { it.forEach { onDelete(it) } }.size
    }

    override suspend fun deleteOneIgnoringOld(condition: Condition, orderBy: List>): Boolean {
        return wraps.deleteOne(condition, orderBy)?.also { onDelete(it) } != null
    }

    override suspend fun deleteMany(condition: Condition): List {
        return wraps.deleteMany(condition).also { it.forEach { onDelete(it) } }
    }

    override suspend fun deleteOne(condition: Condition, orderBy: List>): Model? {
        return wraps.deleteOne(condition, orderBy)?.also { onDelete(it) }
    }
}

/**
 * Runs after an existing item is changed.
 */
fun , ID : Comparable> FieldCollection.postChange(
    changed: suspend (Model, Model) -> Unit
): FieldCollection = object : FieldCollection by this@postChange {
    override val wraps = this@postChange

    override suspend fun replaceOne(
        condition: Condition,
        model: Model,
        orderBy: List>
    ): EntryChange =
        wraps.replaceOne(condition, model, orderBy)
            .also { if (it.old != null && it.new != null) changed(it.old!!, it.new!!) }

    override suspend fun upsertOne(
        condition: Condition,
        modification: Modification,
        model: Model
    ): EntryChange =
        wraps.upsertOne(condition, modification, model)
            .also { if (it.old != null && it.new != null) changed(it.old!!, it.new!!) }

    override suspend fun updateOne(
        condition: Condition,
        modification: Modification,
        orderBy: List>
    ): EntryChange =
        wraps.updateOne(condition, modification, orderBy)
            .also { if (it.old != null && it.new != null) changed(it.old!!, it.new!!) }

    override suspend fun updateMany(
        condition: Condition,
        modification: Modification
    ): CollectionChanges = wraps.updateMany(condition, modification).also { changes ->
        changes.changes.forEach {
            if (it.old != null && it.new != null)
                changed(it.old!!, it.new!!)
        }
    }

    override suspend fun replaceOneIgnoringResult(
        condition: Condition,
        model: Model,
        orderBy: List>
    ): Boolean = replaceOne(
        condition,
        model
    ).new != null

    override suspend fun upsertOneIgnoringResult(
        condition: Condition,
        modification: Modification,
        model: Model
    ): Boolean = upsertOne(condition, modification, model).old != null

    override suspend fun updateOneIgnoringResult(
        condition: Condition,
        modification: Modification,
        orderBy: List>
    ): Boolean = updateOne(condition, modification).new != null

    override suspend fun updateManyIgnoringResult(condition: Condition, modification: Modification): Int =
        updateMany(condition, modification).changes.size
}

/**
 * Runs after any value is added or modified in the database.
 */
fun , ID : Comparable> FieldCollection.postNewValue(
    changed: suspend (Model) -> Unit
): FieldCollection = object : FieldCollection by this@postNewValue {
    override val wraps = this@postNewValue

    override suspend fun insert(models: Iterable): List {
        return wraps.insert(models).onEach { changed(it) }
    }

    override suspend fun replaceOne(
        condition: Condition,
        model: Model,
        orderBy: List>
    ): EntryChange =
        wraps.replaceOne(condition, model, orderBy).also { if (it.old != null && it.new != null) changed(it.new!!) }

    override suspend fun upsertOne(
        condition: Condition,
        modification: Modification,
        model: Model
    ): EntryChange =
        wraps.upsertOne(condition, modification, model).also { it.new?.let { changed(it) } }

    override suspend fun updateOne(
        condition: Condition,
        modification: Modification,
        orderBy: List>
    ): EntryChange =
        wraps.updateOne(condition, modification, orderBy)
            .also { if (it.old != null && it.new != null) changed(it.new!!) }

    override suspend fun updateMany(
        condition: Condition,
        modification: Modification
    ): CollectionChanges = wraps.updateMany(condition, modification).also { changes ->
        changes.changes.forEach {
            if (it.old != null && it.new != null)
                changed(it.new!!)
        }
    }

    override suspend fun replaceOneIgnoringResult(
        condition: Condition,
        model: Model,
        orderBy: List>
    ): Boolean = replaceOne(
        condition,
        model
    ).new != null

    override suspend fun upsertOneIgnoringResult(
        condition: Condition,
        modification: Modification,
        model: Model
    ): Boolean = upsertOne(condition, modification, model).old != null

    override suspend fun updateOneIgnoringResult(
        condition: Condition,
        modification: Modification,
        orderBy: List>
    ): Boolean = updateOne(condition, modification).new != null

    override suspend fun updateManyIgnoringResult(condition: Condition, modification: Modification): Int =
        updateMany(condition, modification).changes.size
}

fun , ID : Comparable> FieldCollection.postRawChanges(
    changed: suspend (List>) -> Unit
): FieldCollection = object : FieldCollection by this@postRawChanges {
    override val wraps = this@postRawChanges

    override suspend fun insert(models: Iterable): List = wraps.insert(models)
        .also { changed(it.map { EntryChange(null, it) }) }

    override suspend fun deleteMany(condition: Condition): List = wraps.deleteMany(condition)
        .also { changed(it.map { EntryChange(it, null) }) }

    override suspend fun deleteOne(condition: Condition, orderBy: List>): Model? = wraps.deleteOne(condition, orderBy)
        .also { changed(listOf(EntryChange(it, null)) ) }

    override suspend fun replaceOne(
        condition: Condition,
        model: Model,
        orderBy: List>
    ): EntryChange = wraps.replaceOne(condition, model, orderBy)
        .also { changed(listOf(it) ) }

    override suspend fun updateOne(
        condition: Condition,
        modification: Modification,
        orderBy: List>
    ): EntryChange = wraps.updateOne(condition, modification, orderBy)
        .also { changed(listOf(it) ) }

    override suspend fun upsertOne(
        condition: Condition,
        modification: Modification,
        model: Model
    ): EntryChange = wraps.upsertOne(condition, modification, model)
        .also { changed(listOf(it) ) }

    override suspend fun updateMany(
        condition: Condition,
        modification: Modification
    ): CollectionChanges = wraps.updateMany(condition, modification)
        .also { changed(it.changes) }


    override suspend fun replaceOneIgnoringResult(
        condition: Condition,
        model: Model,
        orderBy: List>
    ): Boolean = replaceOne(condition, model, orderBy).new != null

    override suspend fun upsertOneIgnoringResult(
        condition: Condition,
        modification: Modification,
        model: Model
    ): Boolean = upsertOne(condition, modification, model).old != null

    override suspend fun updateOneIgnoringResult(
        condition: Condition,
        modification: Modification,
        orderBy: List>
    ): Boolean = updateOne(condition, modification, orderBy).new != null

    override suspend fun updateManyIgnoringResult(
        condition: Condition,
        modification: Modification
    ): Int = updateMany(condition, modification).changes.size

    override suspend fun deleteOneIgnoringOld(
        condition: Condition,
        orderBy: List>
    ): Boolean = deleteOne(condition, orderBy) != null

    override suspend fun deleteManyIgnoringOld(condition: Condition): Int = deleteMany(condition).size

}

/**
 * Intercept all kinds of creates, including [FieldCollection.insert], [FieldCollection.upsertOne], and [FieldCollection.upsertOneIgnoringResult].
 * Allows you to modify the object before it is actually created.
 */
inline fun  FieldCollection.interceptCreate(crossinline interceptor: suspend (Model) -> Model): FieldCollection =
    object : FieldCollection by this {
        override val wraps = this@interceptCreate
        override suspend fun insert(models: Iterable): List =
            wraps.insertMany(models.map { interceptor(it) })

        override suspend fun upsertOne(
            condition: Condition,
            modification: Modification,
            model: Model
        ): EntryChange = wraps.upsertOne(condition, modification, interceptor(model))

        override suspend fun upsertOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            model: Model
        ): Boolean = wraps.upsertOneIgnoringResult(condition, modification, interceptor(model))
    }

/**
 * Intercepts all kinds of replace operations.
 */
inline fun  FieldCollection.interceptReplace(crossinline interceptor: suspend (Model) -> Model): FieldCollection =
    object : FieldCollection by this {
        override val wraps = this@interceptReplace

        override suspend fun upsertOne(
            condition: Condition,
            modification: Modification,
            model: Model
        ): EntryChange = if(modification is Modification.Assign)
            wraps.upsertOne(condition, Modification.Assign(interceptor(modification.value)), model)
        else
            wraps.upsertOne(condition, modification, model)

        override suspend fun upsertOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            model: Model
        ): Boolean = if(modification is Modification.Assign)
            wraps.upsertOneIgnoringResult(condition, Modification.Assign(interceptor(modification.value)), model)
        else
            wraps.upsertOneIgnoringResult(condition, modification, model)

        override suspend fun replaceOne(
            condition: Condition,
            model: Model,
            orderBy: List>
        ): EntryChange =
            wraps.replaceOne(
                condition,
                interceptor(model),
                orderBy
            )

        override suspend fun replaceOneIgnoringResult(
            condition: Condition,
            model: Model,
            orderBy: List>
        ): Boolean =
            wraps.replaceOneIgnoringResult(
                condition,
                interceptor(model),
                orderBy
            )
    }

/**
 * Intercepts all modifications sent to the database.
 */
inline fun  FieldCollection.interceptModification(crossinline interceptor: suspend (Modification) -> Modification): FieldCollection =
    object : FieldCollection by this {
        override val wraps = this@interceptModification
        override suspend fun upsertOne(
            condition: Condition,
            modification: Modification,
            model: Model
        ): EntryChange = wraps.upsertOne(condition, interceptor(modification), model)

        override suspend fun upsertOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            model: Model
        ): Boolean = wraps.upsertOneIgnoringResult(condition, interceptor(modification), model)

        override suspend fun updateOne(
            condition: Condition,
            modification: Modification,
            orderBy: List>
        ): EntryChange = wraps.updateOne(condition, interceptor(modification), orderBy)

        override suspend fun updateOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            orderBy: List>
        ): Boolean = wraps.updateOneIgnoringResult(condition, interceptor(modification), orderBy)

        override suspend fun updateMany(
            condition: Condition,
            modification: Modification
        ): CollectionChanges = wraps.updateMany(condition, interceptor(modification))

        override suspend fun updateManyIgnoringResult(
            condition: Condition,
            modification: Modification
        ): Int = wraps.updateManyIgnoringResult(condition, interceptor(modification))
    }

/**
 * Intercepts all changes sent to the database, including inserting, replacing, upserting, and updating.
 */
inline fun  FieldCollection.interceptChange(crossinline interceptor: suspend (Modification) -> Modification): FieldCollection =
    object : FieldCollection by this {
        override val wraps = this@interceptChange
        override suspend fun insert(models: Iterable): List =
            wraps.insert(models.map { interceptor(Modification.Assign(it))(it) })

        override suspend fun replaceOne(condition: Condition, model: Model, orderBy: List>): EntryChange =
            wraps.replaceOne(
                condition,
                interceptor(Modification.Assign(model))(model),
                orderBy
            )

        override suspend fun replaceOneIgnoringResult(
            condition: Condition,
            model: Model,
            orderBy: List>
        ): Boolean =
            wraps.replaceOneIgnoringResult(
                condition,
                interceptor(Modification.Assign(model))(model),
                orderBy
            )

        override suspend fun upsertOne(
            condition: Condition,
            modification: Modification,
            model: Model
        ): EntryChange = wraps.upsertOne(condition, interceptor(modification), interceptor(Modification.Assign(model))(model))

        override suspend fun upsertOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            model: Model
        ): Boolean = wraps.upsertOneIgnoringResult(condition, interceptor(modification), interceptor(Modification.Assign(model))(model))

        override suspend fun updateOne(
            condition: Condition,
            modification: Modification,
            orderBy: List>
        ): EntryChange = wraps.updateOne(condition, interceptor(modification), orderBy)

        override suspend fun updateOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            orderBy: List>
        ): Boolean = wraps.updateOneIgnoringResult(condition, interceptor(modification), orderBy)

        override suspend fun updateMany(
            condition: Condition,
            modification: Modification
        ): CollectionChanges = wraps.updateMany(condition, interceptor(modification))

        override suspend fun updateManyIgnoringResult(
            condition: Condition,
            modification: Modification
        ): Int = wraps.updateManyIgnoringResult(condition, interceptor(modification))
    }

/**
 * Intercepts all changes sent to the database, including inserting, replacing, upserting, and updating.
 * Also gives you an instance of the model that will be changed.
 * This is significantly more expensive, as we must retrieve the data before we can calculate the change.
 */
inline fun , ID: Comparable> FieldCollection.interceptChangePerInstance(
    includeMassUpdates: Boolean = true,
    crossinline interceptor: suspend (Model, Modification) -> Modification
): FieldCollection =
    object : FieldCollection by this {
        override val wraps = this@interceptChangePerInstance
        override suspend fun insert(models: Iterable): List =
            wraps.insert(models.map { interceptor(it, Modification.Assign(it))(it) })

        override suspend fun replaceOne(condition: Condition, model: Model, orderBy: List>): EntryChange {
            val current = wraps.findOne(condition) ?: return EntryChange(null, null)
            return wraps.replaceOne(
                Condition.OnField(HasId::_id, Condition.Equal(current._id)),
                interceptor(current, Modification.Assign(model))(model),
                orderBy
            )
        }

        override suspend fun replaceOneIgnoringResult(
            condition: Condition,
            model: Model,
            orderBy: List>
        ): Boolean {
            val current = wraps.findOne(condition) ?: return false
            return wraps.replaceOneIgnoringResult(
                Condition.OnField(HasId::_id, Condition.Equal(current._id)),
                interceptor(current, Modification.Assign(model))(model),
                orderBy
            )
        }
        override suspend fun upsertOne(
            condition: Condition,
            modification: Modification,
            model: Model
        ): EntryChange {
            val current = wraps.findOne(condition) ?: return wraps.upsertOne(condition, modification, model)
            val changed = interceptor(current, modification)
            return wraps.upsertOne(condition and Condition.OnField(HasId::_id, Condition.Equal(current._id)), changed, changed(model))
        }

        override suspend fun upsertOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            model: Model
        ): Boolean {
            val current = wraps.findOne(condition) ?: return wraps.upsertOneIgnoringResult(condition, modification, model)
            val changed = interceptor(current, modification)
            return wraps.upsertOneIgnoringResult(condition and Condition.OnField(HasId::_id, Condition.Equal(current._id)), changed, changed(model))
        }

        override suspend fun updateOne(
            condition: Condition,
            modification: Modification,
            orderBy: List>
        ): EntryChange {
            val current = wraps.findOne(condition) ?: return EntryChange(null, null)
            return wraps.updateOne(Condition.OnField(HasId::_id, Condition.Equal(current._id)), interceptor(current, modification), orderBy)
        }

        override suspend fun updateOneIgnoringResult(
            condition: Condition,
            modification: Modification,
            orderBy: List>
        ): Boolean {
            val current = wraps.findOne(condition) ?: return false
            return wraps.updateOneIgnoringResult(Condition.OnField(HasId::_id, Condition.Equal(current._id)), interceptor(current, modification), orderBy)
        }

        override suspend fun updateMany(
            condition: Condition,
            modification: Modification
        ): CollectionChanges {
            if(!includeMassUpdates) return wraps.updateMany(condition, modification)
            val all = ArrayList>()
            wraps.find(condition).collect {
                val altMod = interceptor(it, modification)
                all.add(wraps.updateOne(condition, altMod))
            }
            return CollectionChanges(all)
        }

        override suspend fun updateManyIgnoringResult(
            condition: Condition,
            modification: Modification
        ): Int {
            if(!includeMassUpdates) return wraps.updateManyIgnoringResult(condition, modification)
            var count = 0
            wraps.find(condition).collect {
                val altMod = interceptor(it, modification)
                if(wraps.updateOneIgnoringResult(condition, altMod)) count++
            }
            return count
        }
    }


/**
 * Runs before an item is deleted.
 */
fun  FieldCollection.interceptDelete(
    onDelete: suspend (Model) -> Unit
): FieldCollection = object : FieldCollection by this@interceptDelete {
    override val wraps = this@interceptDelete
    override suspend fun deleteOne(condition: Condition, orderBy: List>): Model? {
        wraps.find(condition, limit = 1, orderBy = orderBy).collect(FlowCollector(onDelete))
        return wraps.deleteOne(condition, orderBy)
    }

    override suspend fun deleteMany(condition: Condition): List {
        wraps.find(condition).collect(FlowCollector(onDelete))
        return wraps.deleteMany(condition)
    }

    override suspend fun deleteManyIgnoringOld(condition: Condition): Int {
        wraps.find(condition).collect(FlowCollector(onDelete))
        return wraps.deleteManyIgnoringOld(condition)
    }

    override suspend fun deleteOneIgnoringOld(condition: Condition, orderBy: List>): Boolean {
        wraps.find(condition, limit = 1, orderBy = orderBy).collect(FlowCollector(onDelete))
        return wraps.deleteOneIgnoringOld(condition, orderBy)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy