From 2faf81ece15b59d74285ecfb2c33c03deffc7fff Mon Sep 17 00:00:00 2001 From: Michael Lifshits Date: Sat, 22 Oct 2022 06:35:44 -0400 Subject: [PATCH] Implementing AggregateDsl --- .../capsa/it/aggregate/AggregateDSL.kt | 111 -------------- .../capsa/it/aggregate/AggregateDsl.kt | 139 ++++++++++++++++++ 2 files changed, 139 insertions(+), 111 deletions(-) delete mode 100644 capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDSL.kt create mode 100644 capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDsl.kt diff --git a/capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDSL.kt b/capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDSL.kt deleted file mode 100644 index 6783092..0000000 --- a/capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDSL.kt +++ /dev/null @@ -1,111 +0,0 @@ -package digital.capsa.it.aggregate - -import digital.capsa.core.logger -import digital.capsa.it.TestContext -import java.util.* -import kotlin.reflect.KClass -import kotlin.reflect.KVisibility -import kotlin.reflect.full.declaredMemberProperties - -interface Aggregate { - var key: Key? - - var id: UUID? - - var parent: Aggregate? - - val children: List - - var randomSeed: Long - - fun create(context: TestContext) - - fun onCreate() - - fun toString(builder: StringBuilder, nesting: Int) - - fun getChildCount(kClass: KClass): Int - - fun construct() -} - -inline fun Aggregate.getChild(i: Int): T { - return children.filter { it is T }[i] as T -} - -inline fun Aggregate.getChild(key: Key): T { - return children.filter { it is T && key == it.key }[0] as T -} - -@DslMarker -annotation class AggregateMarker - -data class Key(var value: String) - -@AggregateMarker -abstract class AbstractAggregate(private val aggregateName: String) : Aggregate { - - lateinit var context: TestContext - - override var key: Key? = null - - override var id: UUID? = null - - override var parent: Aggregate? = null - - override val children = arrayListOf() - - override var randomSeed: Long = 0 - - protected fun initAggregate(aggregate: T, init: T.() -> Unit): T { - aggregate.parent = this - aggregate.construct() - children.add(aggregate) - aggregate.init() - return aggregate - } - - override fun create(context: TestContext) { - this.context = context - if (parent == null) { - logger.info("Aggregate Tree:\n $this") - } - onCreate() - for (c in children) { - c.create(context) - } - } - - override fun toString(builder: StringBuilder, nesting: Int) { - builder.append("".padStart(nesting * 4) + "$aggregateName ${getAttributes()}\n") - for (c in children) { - c.toString(builder, nesting + 1) - } - } - - override fun toString(): String { - val builder = StringBuilder() - toString(builder, 0) - return builder.toString() - } - - open fun getAttributes(): String { - return this::class.declaredMemberProperties.filter { it.visibility == KVisibility.PUBLIC } - .joinToString(prefix = "[", postfix = "]") { "${it.name}=${it.getter.call(this)}" } - } - - override fun getChildCount(kClass: KClass): Int { - return children.count { kClass.isInstance(it) } - } - - operator fun Key.unaryPlus() { - key = this - } - - fun nextRandomInt(seed: Int, bound: Int): Int { - return Random(31 * randomSeed + seed).nextInt(bound) - } - -} - - diff --git a/capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDsl.kt b/capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDsl.kt new file mode 100644 index 0000000..26a5c2e --- /dev/null +++ b/capsa-it/src/main/kotlin/digital/capsa/it/aggregate/AggregateDsl.kt @@ -0,0 +1,139 @@ +package digital.capsa.it.aggregate + +import digital.capsa.core.logger +import java.util.* +import kotlin.reflect.KClass +import kotlin.reflect.KVisibility +import kotlin.reflect.full.declaredMemberProperties + +@DslMarker +annotation class AggregateMarker + +data class Key(var value: String) + +@AggregateMarker +abstract class Aggregate(private val aggregateName: String) { + + enum class Pass { + First, Second + } + + var key: Key? = null + + var id: UUID? = null + + var parent: Aggregate? = null + + val children = arrayListOf() + + var randomSeed: Long = 0 + + abstract fun onConstruct() + + abstract fun onCreate(pass: Pass) + + protected fun initAggregate(aggregate: T, init: T.() -> Unit): T { + aggregate.parent = this + children.add(aggregate) + aggregate.init() + return aggregate + } + + open fun create(pass: Pass = Pass.First) { + if (pass == Pass.First && parent == null) { + logger.info("Aggregate Tree:\n $this") + } + onCreate(pass) + for (c in children) { + c.create(pass) + } + } + + private fun toString(builder: StringBuilder, nesting: Int) { + builder.append("".padStart(nesting * 4) + "$aggregateName${key?.let { " key=${it.value}" } ?: ""} ${getAttributes()}\n") + for (c in children) { + c.toString(builder, nesting + 1) + } + } + + override fun toString(): String { + val builder = StringBuilder() + toString(builder, 0) + return builder.toString() + } + + open fun getPath(): String { + return (parent?.getPath() ?: "") + "/${aggregateName}" + (parent?.let { "(${it.getChildIndex(this)})" } ?: "") + } + + open fun getAttributes(): String { + return this::class.declaredMemberProperties.filter { it.visibility == KVisibility.PUBLIC } + .joinToString(prefix = "[", postfix = "]") { "${it.name}=${it.getter.call(this)}" } + } + + inline fun getChild(i: Int): T { + return children.filter { it is T }[i] as T + } + + inline fun getChild(key: Key): T { + return children.filter { it is T && key == it.key }[0] as T + } + + open fun getChildIndex(aggregate: Aggregate): Int { + return children.subList(0, children.indexOf(aggregate)).count { aggregate::class.isInstance(it) } + } + + open fun getChildCount(kClass: KClass): Int { + return children.count { kClass.isInstance(it) } + } + + open fun getDescendantCount(kClass: KClass): Int { + fun count(aggregate: Aggregate, kClass: KClass): Int { + return getChildCount(kClass) + aggregate.children.sumOf { it.getDescendantCount(kClass) } + } + return count(this, kClass) + } + + inline fun getDescendant(key: Key): T { + return getRecursiveDescendant(aggregate = this, kClass = T::class, key = key) + ?: throw Error("Descendant with key = ${key.value} not found") + } + + fun getRecursiveDescendant(aggregate: Aggregate, kClass: KClass, key: Key): T? { + val children = aggregate.children.filter { it::class == kClass && key == it.key } + return if (children.isNotEmpty()) { + children[0] as T + } else { + var child: T? = null + for (item in aggregate.children) { + child = getRecursiveDescendant(aggregate = item, kClass = kClass, key = key) + if (child != null) { + break + } + } + child + } + } + + inline fun getAncestor(): T { + return getRecursiveAncestor(this, T::class) + } + + fun getRecursiveAncestor(aggregate: Aggregate, kClass: KClass): T { + return if (aggregate.parent == null) { + throw Error("Ancestor with class = $kClass not found") + } else if (aggregate.parent!!::class == kClass) { + aggregate.parent!! as T + } else { + getRecursiveAncestor(aggregate.parent!!, kClass) + } + } + + operator fun Key.unaryPlus() { + key = this + } + + fun nextRandomInt(seed: Int, bound: Int): Int { + return Random(31 * randomSeed + seed).nextInt(bound) + } +}