com.lightningkite.lightningdb.simpleSignals.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of server-core Show documentation
Show all versions of server-core Show documentation
A set of tools to fill in/replace what Ktor is lacking in.
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)
}
}