I'm currently using Scala with the Play Framework and Anorm to access my database. I've been mostly a Ruby developer and still have to get used to the new concepts like dependency injection which Play uses out of the box.
I'll use a simplified example to show my problem.
Currently I have my models and persistency structured like this:
User.scala:
case class User (
val id: Long
val name: String
)
object User (
val idColumn = "id"
val nameColumn = "name"
)
UserRepository.scala:
sealed trait UserRepository {
def findAll: List[User]
}
class DatabaseUserRepository @Inject() (db: Database) extends UserRepository {
val parser: RowParser[User] = Macro.parser[User](
User.idColumn,
User.nameColumn
)
def findById(id: Long): List[User] = {
db.withConnection { implicit c =>
SQL(
"""
SELECT * FROM users;
"""
).as(parser.*)
}
}
}
Now I have to add another model which is related to users. Let's say comments. But I struggle how to add the relation most elegantly while still using Dependency Injection.
Adding a method to the User class sounds horrible because I would always have to have an injected persistency object at the point where I call the method:
case class User (
...
) {
def comments(repo: CommentRepository): List[Comment] = {
repo.findByUserId(this.id)
}
}
The next solution I came up with is as well far from ideal:
case class User (
...
) {
var comments: List[Comment] = List()
}
class DatabaseUserRepository @Inject() (db: Database, commentRepo: CommentRepository) extends UserRepository {
...
def findById(id: Long): List[User] = {
val users = db.withConnection { implicit c =>
SQL(
"""
SELECT * FROM users;
"""
).as(parser.*)
}
users.map { u => u.comments = commentRepo.findByUserId(u.id) }
}
}
This way I would always fetch the comments and not when I need them AND generally the idea of using an empty var comments list and later filling it feels wrong.
How would it look like to structure relations between models while preserving immutable state and dependency injection? Are there some examples anywhere?
Thanks!