How do I search from multiple tables with DAO? - kotlin

Say I have tables like this:
object Leagues : IntIdTable() {
val name = varchar("name", 50).uniqueIndex()
}
object Matches: IntIdTable() {
val game = reference("game", Games)
}
object Users: IntIdTable() {
val name = varchar("name", 50).uniqueIndex()
}
object Bets: IntIdTable() {
val match = reference("match", Matches)
val user = reference("user", Users)
}
Daos are in the lines of:
class Bet(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Bet>(Bets)
var match by Bets.match
var user by Bets.user
}
How do I write the dao or the query for the Bets class so I can query "give me all bets player X has made in league Y". Bet.find { (user eq X) and (/* what here to get the leagues table ? */) }

val bets = Bet.wrapRows(
Bets.innerJoin(Matches).innerJoin(Leagues).select {
Bets.user eq X.id and (Leagues.name eq "Y"
}
).toList()

Related

Kotlin Exposed: Proper way to create a One To Many Relationship?

I want to create an One-To-Many Relationship from the Order Entity to the OrderProductAmount Entity.
I need this, because for each Order I need to know which Product's it contains and what the amount of each Product in the Order is, as one order can contain multiple products.
When I fetch Order Entities from the database, I want to be able to access all rows from OrderProductAmount that contain the corresponding orderId from it.
But whenever I access order.products from the result of findOrder I get null as the result.
I suppose there is some mistake in my setup of the entities or I am not inserting the entities into the database in the right way.
Order Entity
class Order(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Order>(Orders)
var orderStatus by Orders.orderStatus
val products by OrderProductAmount referrersOn OrderProductAmounts.order
}
object Orders : IntIdTable() {
var orderStatus = enumeration("orderStatus", OrderStatus::class)
}
OrderProductAmount Entity
class OrderProductAmount(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<OrderProductAmount>(OrderProductAmounts)
var order by Order referencedOn OrderProductAmounts.order
var product by OrderProductAmounts.product
var amount by OrderProductAmounts.amount
}
object OrderProductAmounts : IntIdTable() {
var order = reference("order", Orders)
var product = integer("product")
var amount = integer("amount")
}
Product Entity
class Product(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Product>(Products)
var name by Products.name
var price by Products.price
}
object Products : IntIdTable() {
val name = varchar("name", length = 256)
val price = decimal("price", precision = 10, scale = 2)
}
Inserting new entities ...
override suspend fun addOrder(productIdToAmount: Map<Int, Int>) = dbQuery {
val orderId = Orders.insertAndGetId {
it[Orders.orderStatus] = OrderStatus.CREATED
}
productIdToAmount.entries.forEach { (productId, amount) ->
val product = productDAO.findProduct(productId)!!
OrderProductAmounts.insert {
it[OrderProductAmounts.order] = orderId.value
it[OrderProductAmounts.product] = product.id.value
it[OrderProductAmounts.amount] = amount
}
}
}
Fetching an order from the database ...
override suspend fun findOrder(id: Int): Order? = dbQuery {
Orders.select { Orders.id eq id }.map { Order.wrapRow(it) }.singleOrNull()
}
It seems that your mapping for products is a bit off.
It should be:
val products by Product via OrderProductAmounts
First comes the type of the collection, then the connection table.

Cannot 'find' on mutableListOf

The mytable object contains the columns variable (the CollectionColumns class) and the list variable is declared in this class, which contains objects of the Column class.
I try to search in this list by the variable name and don't find it (returns null).
val myTable = Table()
myTable.columns.add("Date")
myTable.columns.add("Name")
myTable.columns.add("Summ")
val find = myTable.columns.find("Summ")
println(find)
result: null
Does anyone know why ?
class Table() {
var columns: CollectionColumns
var rows: CollectionRows
init {
columns = CollectionColumns()
rows = CollectionRows()
}
inner class CollectionColumns() {
var list = mutableListOf<Column>()
fun add(_name: String): Table.Column{
val newColumn = Column(_name)
columns.list.add(newColumn)
for (row in rows.list) {
row.data.put(newColumn.name, null)
}
return newColumn
}
fun find(_name: String): Column?{
val findColumn = columns.list.find { it.name == _name }
return findColumn
}
}
class Column(_name: String) {
val name = _name
}
inner class CollectionRows() {
var list = mutableListOf<Row>()
fun add() : Table.Row {
val newRow = Row()
for (column in columns.list) {
newRow.data.put(column.name, null)
}
rows.list.add(newRow)
return newRow
}
}
class Row() {
var data = mutableMapOf<String, Any?>()
}
}

can you join two tables and result with an obj (from first table) containing a list of obj(from the second table)

First of all my code:
Table 1:
object Company : Table() {
val name = varchar("pk_name", 250)
override val primaryKey = PrimaryKey(name, name = "pk_company_constraint")
}
Table 2&3:
object Sector : IntIdTable() {
val name = varchar("fk_name", 50).references(MainSector.name)
val alias = varchar("alias", 50).nullable()
val companyName = varchar("fk_company_name", 250).references(Company.name, onDelete = ReferenceOption.CASCADE)
}
object MainSector : Table() {
val name = varchar("pk_name", 50)
override val primaryKey = PrimaryKey(name, name = "pk_main_sector_constraint")
}
My Problem:
I need to parse the result into a DTO that looks like this:
data class CompanyDTO (
val companyName: String,
val sectorList: List<SectorDTO>
)
data class SectorDTO (
val mainSectorName: String,
val sectorAlias: String
)
I am able to get a Company with the first Sector from the database, but i have no idea how to get a list of them.
My try:
override fun retrieveCompanies(vararg names: String): List<CompanyDTO> {
var retlist: List<CompanyDTO> = emptyList()
if (names.isEmpty()){
retlist = transaction {
(Company innerJoin Sector)
.select{Company.name eq Sector.companyName}
.map { CompanyDTO(it[Company.name], listOf(
SectorDTO(it[Sector.name], it[Sector.alias]?: "")
)) }
}
} else {
//return specific
}
return retlist
}
If no arguments are given i want to return all companies from the database, if arguments are given i want to return only companies with given name.
I canĀ“t find anything about this topic in the official documentation, please send help
If Company could not have any Sector you need to use leftJoin and then your code could be like:
Company.leftJoin.Sector.selectAll().map {
val companyName = it[Company.name]
val sector = it.tryGet(Sector.name)?.let { name ->
SectorDTO(name, it[Sector.alias].orEmpty())
}
companyName to sector
}.groupBy({ it.first }, { it.second }).map { (companyName, sectors) ->
CompanyDTO(companyName, sectors.filterNotNull())
}

Kotlin Exposed Many-to-Many Jackson Infinite recursion (StackOverflowError)

I have done the many-to-many reference in ExposedBD (kotlin) as follows in the wiki:
https://github.com/JetBrains/Exposed/wiki/DAO#many-to-many-reference
However, there is a problem of Infinite Recursion (Jackson) when I am trying to return a list of objects in my API (Javalin).
So, I would like to know how to put the annotation #jsonIgnore or if there are other alternative solutions in this case. Here is the mapping:
// many-to-many Actor--StarWarsFilms
// Actor Entity
object Actors: IntIdTable() {
val firstname = varchar("firstname", 50)
val lastname = varchar("lastname", 50)
}
class Actor(id: EntityID<Int>): IntEntity(id) {
companion object : IntEntityClass<Actor>(Actors)
var firstname by Actors.firstname
var lastname by Actors.lastname
}
// StarWarFilm Entity
object StarWarsFilms : IntIdTable() {
val sequelId = integer("sequel_id").uniqueIndex()
val name = varchar("name", 50)
val director = varchar("director", 50)
}
class StarWarsFilm(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<StarWarsFilm>(StarWarsFilms)
var sequelId by StarWarsFilms.sequelId
var name by StarWarsFilms.name
var director by StarWarsFilms.director
var actors by Actor via StarWarsFilmActors
}
// Intermediate table
object StarWarsFilmActors : Table() {
val starWarsFilm = reference("starWarsFilm", StarWarsFilms).primaryKey(0)
val actor = reference("actor", Actors).primaryKey(1)
}

type-safe builder example kotlin

I want to have following person object in Kotlin :
var p = person {
age = 22
gender = "male"
name {
first = "Ali"
last = "Rezaei"
}
}
I have following code to build it :
data class Person(var age: Int? = null, var gender: String? = null
, var name : Name? = null) {
}
fun name(init: Name.() -> Unit): Name {
val n = Name()
n.init()
return n
}
data class Name(var first: String? = null, var last : String? = null)
fun person(init: Person.() -> Unit): Person {
val p = Person()
p.init()
return p
}
But when I print it, the result is following :
Person(age=22, gender="male", name=null)
What is wrong with my code?
You could make name an extension function on Person that assigns the Name to the Person instead of returning it:
fun Person.name(init: Name.() -> Unit) {
val n = Name()
n.init()
this.name = n
}
You could even consider a more concise syntax for the same, like this:
fun Person.name(init: Name.() -> Unit) {
this.name = Name().apply(init)
}
Shameless plug for my repository discussing DSL design and containing examples.
You need to assign to name. This ended up working for me...
var p = person {
age = 22
gender = "male"
name = name {
first = "Ali"
last = "Rezaei"
}
}