Ayfri
05/26/2023, 8:33 PMUser(id: Int), Game(id: Int), UserGame(gameId: Int, userId: Int)
I want to use the association API to be able to do like users.games()
and game.members()
, but I don't quite understand the docs about this
How can I do this ? I currently only created two data classes for my 2 tables, but none for the association table.Toshihiro Nakamura
05/26/2023, 10:33 PM@KomapperEntity
@KomapperOneToMany(UserGame::class)
@KomapperAggregateRoot("users")
data class User(@KomapperId val id: Int)
@KomapperEntity
@KomapperManyToOne(User::class)
@KomapperManyToOne(Game::class)
data class UserGame(
@KomapperId val gameId: Int,
@KomapperId val userId: Int
)
@KomapperEntity
@KomapperOneToMany(UserGame::class)
data class Game(@KomapperId val id: Int)
If you want to hide access to the association table from your application, you need to define extension functions:
context(org.komapper.core.dsl.query.EntityStoreContext)
fun User.gemes(): Set<Game> {
return this.userGame().mapNotNull { it.game() }.toSet()
}
context(org.komapper.core.dsl.query.EntityStoreContext)
fun Game.members(): Set<User> {
return this.userGame().mapNotNull { it.user() }.toSet()
}
Now you can achieve what you want:
val store: EntityStore = db.runQuery(...)
with(store.asContext()) {
val users: Set<User> = store.users()
for (user in users) {
val games: Set<Game> = user.gemes()
for (game in games) {
val memabers: Set<User> = game.members()
}
}
}
Ayfri
05/26/2023, 10:45 PMstore: EntityStore
and with(store.asContext())
etc
A more direct
val user = db.runQuery(...)
val userGames = user.games()
API would be very cool !!Ayfri
05/26/2023, 10:51 PMToshihiro Nakamura
05/27/2023, 2:56 AMIs it planned to simplify the usage of this API also ?If we can simplify it, that would be great. Do you have any ideas? From my point of view, using Context Receiver to get association data is a simpler way than using Lazy Loading.
Or even just extension val properties if it’s not doing any transaction internallyWhat does this mean? Let me hear a little more.
Ayfri
05/27/2023, 2:59 AM.games
of .games()
, as in Kotlin we rarely use methods for returning a value except when it does some internal computing
But I don't know what it currently does in the current API :)Ayfri
05/27/2023, 3:08 AMUser().insert()
, and User.select { where { it.id greaterThan 5 } }.first()
etc
I know it's pretty far from the current API, but it's just how I would design and love to use it
As I said, I don't know the capabilities of KSP and if it's possible at all
If I had to be closer to the current API, I would write instead
QueryDSL.insert(User).values(User(), User())
QueryDSL.select(User).where { ... }.first()
You could only use @KomapperEntity
to QueryDSL methodsAyfri
05/27/2023, 3:18 AMval users = QueryDSL.from(...) // List<User>
val games = users.games // List<Game>
users.first().userGames.first().delete()
val latestGame = games.last().also { it.userGames += UserGame(it.id, 2) }
I've written List
, but I think a custom implementation should be used, so that it can perform easily the SQL request, like when using +=Ayfri
05/27/2023, 3:22 AM.delete()
and other operationsToshihiro Nakamura
05/27/2023, 4:38 AMJust usingThe reason Komapper uses extended functions rather than extended properties is to avoid conflicts with user-defined properties.of.games
, as in Kotlin we rarely use methods for returning a value except when it does some internal computing.games()
Toshihiro Nakamura
05/27/2023, 5:26 AMQueryDSL.insert(User)
.
For the Association API, we need to resolve how to hold and propagate association entities. In the current API, EntityStoreContext and Context Receivers play those roles.Ayfri
05/27/2023, 11:01 AMToshihiro Nakamura
05/28/2023, 2:51 AMdata class User(val id: Int) {
companion object: EntityMetadamodel<User, Int, Companion> {
...
}
}
If KSP allows bytecode enhancement and can generate a comanion object as described above, we can write something like QueryDSL.insert(User)
.
But KSP can only generate source code and can not generate a companion object. I think it is not a blocking, but an appropriate constraint.
Komapper’s current API allows us to write QueryDsl.insert(Meta.user)
, which is not much different than writing QueryDSL.insert(User)
.Ayfri
05/28/2023, 11:13 AM