Just wondering <@U01SP2GJYAU>, maybe since we alre...
# komapper
d
Just wondering @Toshihiro Nakamura, maybe since we already got so far having aggregate roots and relationship annotations, could it be feasible to generate
EntityStore
subclasses for each aggregate root, and have it store the the root by itself type safely and the relations already in the form they need to be?
t
What are the advantages of subclassing? Who creates an instance of that subclass? What kind of API do you want?
d
Sorry, I mean implementations, and KSP could maybe generate them?
Maybe includeTyped could resolve and return them?
Then store.departements would return a stored version of aa list of departments instead of looking them up in a map, and one to many would be stored in the store directly as a list of that thing...
So using those extension functions wouldn't cost anything, but just be accessing data already cached in the right way, and casting wouldn't be needed.
Truth is, if includeTyped or includeFromAggragate Root is used, it might not even need to be derived from entitystore and just return a filled up typed store from the generated implementation with the requested data
t
Thanks for your explanation. But can you show me the concept code so I can understand it better?
d
From here: https://github.com/komapper/komapper/blob/aba3e2946d2b4d8a1128b91c4f17da684df331cc[…]egration-test-core/src/main/kotlin/integration/core/Entities.kt Department is an aggregateroot, so you could generate:
Copy code
class DepartmentEntityStore(
   val departments: List<Department>,
   val employees: Map<Department, List<Employee>>
)
// Maybe having some kind of wrapper for things that weren't requested in the query like employees being nullable?

///
val store: DepartmentEntityStore = db.runQuery(...includeAllTyped<Departement>())

// Still have extension functions, but with almost no cost to resuse them many times:
val employees = store.departments.first().employees
For non-aggregateroots, there could still be the
include()
api with the EntityStore, and this generation of the extra store could be opt-in by indicating it in the AggregateRoot annotation...
Does this sound possible/good?
t
Thank you for sharing your code. I think I understand what you are trying to achieve. However, we can accomplish much the same with our current implementation, and I don’t see any performance issues. The current implementation is more straightforward.
d
Every time you call
employees
you go through this with the current implementation:
Copy code
private fun <T : Any, S : Any> createOneToMany(
        first: EntityMetamodel<T, *, *>,
        second: EntityMetamodel<S, *, *>,
    ): Map<T, Set<S>> {
        if (!contains(first, second)) {
            return emptyMap()
        }
        val oneToMany = mutableMapOf<T, MutableSet<S>>()
        for (row in rows) {
            val entity1 = row[first]
            val entity2 = row[second]
            if (entity1 != null) {
                val key = first.klass().cast(entity1)
                val values = oneToMany.computeIfAbsent(key) { mutableSetOf() }
                if (entity2 != null) {
                    val value = second.klass().cast(entity2)
                    values.add(value)
                }
            }
        }
        return oneToMany
    }
So one needs to make sure to call it only once, and just use it's result... but usually a
val
indicates that there's not some kind of expensive operation being done... so maybe the current implementation IS
employees()
. But it could still be nice to avoid the intermediate structures being saved to and caching already when using
runQuery
...
I'm not saying that the current implementation is so bad -- and thanks a lot for having worked on it 😃, I'm happy even with it! I'm just pondering if things might be even better (maybe later on, the current implementation IS experimental...).
t
Please let me release it this weekend with the current implementation. I would be happy to have you use it once and send me feedback again.
d
Oh... that's already much better... the intermediate structure still can't be avoided yet, but at least calling it again isn't as costly! Thanks again for all the nice work!