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

commonMain.s2.sourcing.dsl.view.ViewLoader.kt Maven / Gradle / Ivy

There is a newer version: 0.21.0
Show newest version
package s2.sourcing.dsl.view

import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.fold
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.flow.transform
import s2.dsl.automate.Evt
import s2.dsl.automate.model.WithS2Id
import s2.sourcing.dsl.Loader
import s2.sourcing.dsl.event.EventRepository

open class ViewLoader(
	private val eventRepository: EventRepository,
	private val view: View
): Loader where
EVENT: Evt,
EVENT: WithS2Id {

	override suspend fun load(id: ID & Any): ENTITY? {
		return eventRepository.load(id).let { events ->
			load(events)
		}
	}

	override suspend fun load(events: Flow): ENTITY? {
		return evolve(events, null)
	}

	override suspend fun loadAndEvolve(id: ID & Any, news: Flow): ENTITY? {
		return eventRepository.load(id).let { events ->
			load(events)
		}.let { entity ->
			evolve(news, entity)
		}
	}

	override suspend fun evolve(events: Flow, entity: ENTITY?): ENTITY? {
		return events.fold(entity) { updated, event ->
			view.evolve(event, updated)
		}
	}

	override suspend fun reloadHistory(): List = eventRepository.loadAll()
		.groupBy { event -> event.s2Id() }
		.reducePerKey(::load)
		.mapNotNull{it}
		.toList()

	// https://stackoverflow.com/a/58678049
//	private fun  Flow.groupBy(getKey: (T) -> K): Flow>> = flow {
//		val storage = mutableMapOf>()
//		try {
//			collect { t ->
//				val key = getKey(t)
//				println("Handle ${key}")
//				storage.getOrPut(key) {
//					Channel(32).also { emit(key to it.consumeAsFlow()) }
//				}.send(t)
//			}
//		} finally {
//			println("Handle groupBy finally")
//			storage.values.forEach { chan ->
//				try {
//					println("Handle groupBy finally ${chan}")
//					 chan.close()
//				} catch (e: Exception) {
//					println("Handle groupBy finally exception: ${e}")
//				}
//			}
//		}
//	}

	suspend fun  Flow.groupBy(keySelector: suspend (T) -> K): Map> {
		val resultMap = mutableMapOf>()

		transform { value ->
			val key = keySelector(value)
			val list = resultMap.getOrPut(key) { mutableListOf() }
			list.add(value)
			emit(resultMap)
		}.toList()

		return resultMap.mapValues { it.value.asFlow() }
	}

	@OptIn(FlowPreview::class)
	private fun  Map>.reducePerKey(reduce: suspend (Flow) -> R): Flow {
		return this.values.asFlow().map { flow ->
			reduce(flow)
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy