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

commonMain.tech.skot.model.SKData.kt Maven / Gradle / Ivy

package tech.skot.model

import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.map
import kotlin.math.min

interface SKData {


    val flow: Flow?>
    val defaultValidity: Long
    val _current: DatedData?

    suspend fun update(): D
    suspend fun fallBackValue(): D?

    open suspend fun get(validity: Long? = null): D {
        val datedCurrentValue = _current
        val usedValidity = validity ?: defaultValidity
        return if (datedCurrentValue == null || usedValidity == 0L || ((datedCurrentValue.timestamp + usedValidity) > 0 && currentTimeMillis() > (datedCurrentValue.timestamp + usedValidity))) {
            update()
        } else {
            datedCurrentValue.data
        }
    }

    suspend fun getDirect() = _current?.data ?: get(validity = Long.MAX_VALUE)

}

interface SKPaginatedData:SKData> {
    suspend fun oneMorePage()
    val mayHaveAnotherPage:Boolean
}

fun  SKData.map(transform: (d: D) -> O): SKData {
    return object : SKData {
        override val defaultValidity = [email protected]
        override val flow = [email protected] {
            it?.let { transformDatedData(it) }
        }
        override val _current
            get() = this@map._current?.let { transformDatedData(it) }

        private fun transformDatedData(datedData: DatedData) =
            transform(datedData.data).let { transformedValue ->
                DatedData(
                    data = transformedValue,
                    timestamp = datedData.timestamp
                )
            }

        override suspend fun update(): O {
            return transform([email protected]())
        }

        override suspend fun get(validity: Long?): O {
            return transform([email protected](validity))
        }

        override suspend fun fallBackValue(): O? {
            return [email protected]()?.let(transform)
        }
    }
}

fun  SKData.mapSuspend(transform: suspend (d: D) -> O): SKData {
    return object : SKData {
        override val defaultValidity = [email protected]
        override val flow = [email protected] {
            it?.let { transformDatedData(it) }
        }

        private var trueCurrent: DatedData? = null
        private var transformedCurrent: DatedData? = null
        override val _current: DatedData?
            get() {
                return if (transformedCurrent == this@mapSuspend._current) {
                    trueCurrent
                } else {
                    null
                }
            }


        private suspend fun transformDatedData(datedData: DatedData) =
            transform(datedData.data).let { transformedValue ->
                DatedData(
                    data = transformedValue,
                    timestamp = datedData.timestamp
                ).also {
                    trueCurrent = it
                    transformedCurrent = datedData
                }
            }

        override suspend fun update(): O {
            val originUpdate = [email protected]()
            return transform(originUpdate).also {
                trueCurrent = DatedData(it)
                transformedCurrent = DatedData(
                    originUpdate,
                    this@mapSuspend._current?.timestamp ?: currentTimeMillis()
                )
            }
        }

        override suspend fun fallBackValue(): O? {
            return [email protected]()?.let {
                transform(it)
            }
        }
    }
}


fun  SKData.combine(other: SKData) = combineSKData(this, other)

fun  combineSKData(
    data1: SKData,
    data2: SKData
): SKData> {
    return object : SKData> {

        override val defaultValidity: Long by lazy {
            min(data1.defaultValidity, data2.defaultValidity)
        }
        override val _current: DatedData>?
            get() = buildPair(data1._current, data2._current)


        private fun buildPair(
            datedData1: DatedData?,
            datedData2: DatedData?
        ): DatedData>? =
            if (datedData1 != null && datedData2 != null) {
                DatedData(
                    data = Pair(datedData1.data, datedData2.data),
                    timestamp = min(datedData1.timestamp, datedData2.timestamp)
                )
            } else {
                null
            }

        override val flow: Flow>?> by lazy {
            combineTransform(
                data1.flow,
                data2.flow
            ) { datedDataFlow1, datedDataFlow2 ->
                buildPair(datedDataFlow1, datedDataFlow2)?.let { emit(it) }
            }
        }

        override suspend fun update(): Pair {
            return coroutineScope {
                val updatedData1 =
                    async {
                        data1.update()
                    }
                val updatedData2 =
                    async {
                        data2.update()
                    }
                Pair(updatedData1.await(), updatedData2.await())
            }
        }

        override suspend fun get(validity: Long?): Pair {
            return coroutineScope {
                val gettedData1 = async {
                    data1.get(validity)
                }

                val gettedData2 = async {
                    data2.get(validity)
                }
                Pair(gettedData1.await(), gettedData2.await())
            }
        }

        override suspend fun fallBackValue(): Pair? {
            val data1FallBackValue = data1.fallBackValue()
            val data2FallBackValue = data2.fallBackValue()
            return if (data1FallBackValue != null && data2FallBackValue != null) {
                Pair(data1FallBackValue, data2FallBackValue)
            } else {
                null
            }
        }
    }
}


fun  combineSKData(
    data1: SKData,
    data2: SKData,
    data3: SKData
): SKData> {
    return object : SKData> {

        override val defaultValidity by lazy {
            min(min(data1.defaultValidity, data2.defaultValidity), data3.defaultValidity)
        }

        override val _current: DatedData>?
            get() = buildTriple(data1._current, data2._current, data3._current)


        private fun buildTriple(
            datedData1: DatedData?,
            datedData2: DatedData?,
            datedData3: DatedData?
        ): DatedData>? =
            if (datedData1 != null && datedData2 != null && datedData3 != null) {
                DatedData(
                    data = Triple(datedData1.data, datedData2.data, datedData3.data),
                    timestamp = min(
                        min(datedData1.timestamp, datedData2.timestamp),
                        datedData3.timestamp
                    )
                )
            } else {
                null
            }

        override val flow: Flow>?> by lazy {
            combineTransform(
                data1.flow,
                data2.flow,
                data3.flow
            ) { datedDataFlow1, datedDataFlow2, datedDataFlow3 ->
                buildTriple(datedDataFlow1, datedDataFlow2, datedDataFlow3)?.let { emit(it) }

            }
        }

        override suspend fun update(): Triple {
            return coroutineScope {
                val updatedData1 =
                    async {
                        data1.update()
                    }
                val updatedData2 =
                    async {
                        data2.update()
                    }
                val updatedData3 =
                    async {
                        data3.update()
                    }
                Triple(updatedData1.await(), updatedData2.await(), updatedData3.await())
            }
        }

        override suspend fun get(validity: Long?): Triple {
            return coroutineScope {
                val gettedData1 = async {
                    data1.get(validity)
                }

                val gettedData2 = async {
                    data2.get(validity)
                }
                val gettedData3 = async {
                    data3.get(validity)
                }
                Triple(gettedData1.await(), gettedData2.await(), gettedData3.await())
            }
        }

        override suspend fun fallBackValue(): Triple? {
            val data1FallBackValue = data1.fallBackValue()
            val data2FallBackValue = data2.fallBackValue()
            val data3FallBackValue = data3.fallBackValue()
            return if (data1FallBackValue != null && data2FallBackValue != null && data3FallBackValue != null) {
                Triple(data1FallBackValue, data2FallBackValue, data3FallBackValue)
            } else {
                null
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy