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

s2.spring.sourcing.data.r2dbc.R2dbcEventRepository.kt Maven / Gradle / Ivy

There is a newer version: 0.22.0
Show newest version
package s2.spring.sourcing.data.r2dbc

import java.util.UUID
import kotlin.reflect.KClass
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.reactive.awaitFirstOrNull
import kotlinx.coroutines.reactor.awaitSingle
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.data.r2dbc.core.flow
import org.springframework.data.relational.core.query.Criteria
import org.springframework.data.relational.core.query.Query
import org.springframework.r2dbc.core.DatabaseClient
import reactor.core.publisher.Mono
import s2.dsl.automate.Evt
import s2.dsl.automate.model.WithS2Id
import s2.sourcing.dsl.event.EventRepository
import s2.spring.sourcing.data.event.EventSourcing

class R2dbcEventRepository(
	private val json: Json,
	private val databaseClient: DatabaseClient,
	private val r2dbcEntityTemplate: R2dbcEntityTemplate,
	private val eventType: KClass,
	private val tableName: String = "s2_event_sourcing_${eventType.simpleName!!}".lowercase()
) : EventRepository where
EVENT: Evt,
EVENT: WithS2Id
{

	fun delete(id: Long?): Mono {
		return r2dbcEntityTemplate.delete(EventSourcing::class.java)
			.from(tableName)
			.matching(Query.query(Criteria.where("id").`is`(id!!)))
			.all()
			.then()
	}

	override suspend fun load(id: ID): Flow {
		return r2dbcEntityTemplate.select(EventSourcing::class.java)
			.from(tableName)
			.matching(Query.query(Criteria.where("obj_id").`is`(id!!)))
			.flow().toEvents()
	}

	override suspend fun loadAll(): Flow {
		return r2dbcEntityTemplate.select(EventSourcing::class.java)
			.from(tableName)
			.flow().toEvents()
	}

	@OptIn(InternalSerializationApi::class)
	override suspend fun persistFlow(events: Flow): Flow {
		return events.map { event ->
			val encoded =  json.encodeToString(eventType.serializer(), event)
			r2dbcEntityTemplate.insert(EventSourcing::class.java)
				.into(tableName)
				.using(EventSourcing(
					id = UUID.randomUUID().toString(),
					objId = event.s2Id(),
					event = encoded
				)).toEvent().awaitSingle()
		}

	}

	override suspend fun createTable() {
		val createScript = """
			CREATE TABLE IF NOT EXISTS ${tableName} (
			      id VARCHAR(255) PRIMARY KEY,
			      obj_id VARCHAR(255) NOT NULL,
			      event text NOT NULL,
			      created_by VARCHAR(255),
			      created_date TIMESTAMP,
			      last_modified_by VARCHAR(255),
			      last_modified_date TIMESTAMP,
			      version INTEGER
			);

		""".trimIndent()

		databaseClient.sql(createScript)
			.then().awaitFirstOrNull()
	}

	@OptIn(InternalSerializationApi::class)
	override suspend fun persist(event: EVENT): EVENT {
		val encoded =  json.encodeToString(eventType.serializer(), event)
		return r2dbcEntityTemplate.insert(EventSourcing::class.java)
			.into(tableName)
			.using(EventSourcing(
				id = UUID.randomUUID().toString(),
				objId = event.s2Id(),
				event = encoded
			)).toEvent().awaitSingle()
	}

	@OptIn(InternalSerializationApi::class)
	private fun Flow>.toEvents(): Flow = map {
		json.decodeFromString(eventType.serializer(), it.event)
	}

	@OptIn(InternalSerializationApi::class)
	private fun Mono>.toEvent(): Mono = map {
		json.decodeFromString(eventType.serializer(), it.event)
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy