Scala Slick - Infinite recursion (StackOverflowError) on query results - scala

I am playing around with Slick on top of a Twitter Finatra application. Finally I thought I made it but now, when I want to process a result, I always get an recursion error. I looked around but I did not find anything helpful for this particular problem. The code I have is actually quite simple:
Map the Database class to a custom Type:
package com.configurationManagement.library
package object Types {
type SlickDatabase = slick.driver.MySQLDriver.api.Database
}
Model:
package com.configurationManagement.app.domain
import slick.lifted.Tag
import slick.driver.MySQLDriver.api._
import slick.profile.SqlProfile.ColumnOption.NotNull
case class ConfigurationTemplate(id: Option[Int], name: String)
class ConfigurationTemplates(tag: Tag) extends Table[ConfigurationTemplate](tag: Tag, "configuration_template") {
def id = column[Int]("id", O.AutoInc, O.PrimaryKey)
def name = column[String]("name", NotNull)
def uniqueNameIndex = index("unique_name", name, unique = true)
def * = (id.?, name) <> (ConfigurationTemplate.tupled, ConfigurationTemplate.unapply)
}
Controller:
package com.configurationManagement.app.controller
import com.google.inject.{Inject, Singleton}
import com.configurationManagement.app.domain.ConfigurationTemplates
import com.configurationManagement.app.dto.request.RequestConfigurationTemplateDto
import com.configurationManagement.library.Types._
import com.twitter.finatra.http.Controller
import com.twitter.inject.Logging
import slick.driver.MySQLDriver.api._
#Singleton
class ConfigurationTemplateController #Inject()(database: SlickDatabase)
extends Controller with Logging with FutureConverter {
post("/configurations/templates") { dto: RequestConfigurationTemplateDto =>
val templates = TableQuery[ConfigurationTemplates]
val query = templates.filter(_.id === 1)
response.ok(query.map(_.name))
}
}
And here comes the error
Infinite recursion (StackOverflowError) (through reference chain: com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast.TableNode["driver_table"]->com.configurationManagement.app.domain.ConfigurationTemplates["table_node"]->slick.ast
Obvisously this line causes the error:
query.map(_.name)

Two things I see, first you need to add .result to the query to transform it into a FixedSqlStreamingAction, second you need a database to run that query on:
private[this] val database: slick.driver.MySQLDriver.backend.DatabaseDef = Database.forDataSource(...)
database.run(templates.filter(_.id === 1).map(_.name).result)
Which returns a Future[Seq[String]], this probably is the expected type from response.ok.

Related

Could not find implicit value for parameter write eror, yet I defined the handler using the macro

I have the following:
Account.scala
package modules.accounts
import java.time.Instant
import reactivemongo.api.bson._
case class Account(id: String, name: String)
object Account {
type ID = String
implicit val accountHandler: BSONDocumentHandler[Account] = Macros.handler[Account]
// implicit def accountWriter: BSONDocumentWriter[Account] = Macros.writer[Account]
// implicit def accountReader: BSONDocumentReader[Account] = Macros.reader[Account]
}
AccountRepo.scala
package modules.accounts
import java.time.Instant
import reactivemongo.api.collections.bson.BSONCollection
import scala.concurrent.ExecutionContext
final class AccountRepo(
val coll: BSONCollection
)(implicit ec: ExecutionContext) {
import Account.{ accountHandler, ID }
def insertTest() = {
val doc = Account(s"account123", "accountName") //, Instant.now)
coll.insert.one(doc)
}
}
The error I am getting is:
could not find implicit value for parameter writer: AccountRepo.this.coll.pack.Writer[modules.accounts.Account]
[error] coll.insert.one(doc)
From what I understand the implicit handler that is generated by the macro should be enough and create the Writer. What am I doing wrong?
Reference: http://reactivemongo.org/releases/1.0/documentation/bson/typeclasses.html
The code is mismixing different versions.
The macro generated handler is using the new BSON API, as it can be seen with the import reactivemongo.api.bson, whereas the collection is using an old driver, as it can be seen as it uses reactivemongo.api.collections.bson instead of reactivemongo.api.bson.collection.
It's recommended to have a look at the documentation, and not mixing incompatible versions of related libraries.

Slick PostgreSQL Integration

I'm new to scala and I'm trying to integrate a PostgreSQL database to a Lagom application written in scala.I'm trying to utilise the persistence API of Lagom. Lagom has inbuilt support for slick.
My table has 3 fields id of type int, name of type string, data of type jsonb
Since Slick doesn't support json format I'm trying to use slick-pg .
Below is my implementation
My custom profile class
import com.github.tminglei.slickpg.{ExPostgresProfile, PgPlayJsonSupport}
import play.api.libs.json.JsValue
import slick.basic.Capability
import slick.jdbc.{JdbcCapabilities, PostgresProfile}
trait CustomPostgresProfile extends ExPostgresProfile with PgPlayJsonSupport {
def pgjson = "jsonb"
override protected def computeCapabilities: Set[Capability] =
super.computeCapabilities + JdbcCapabilities.insertOrUpdate
override val api = PostgresJsonSupportAPI
object PostgresJsonSupportAPI extends API with JsonImplicits {}
}
object CustomPostgresProfile extends PostgresProfile
My table definition
import com.custom.persistence.profile.CustomPostgresProfile.api._
import play.api.libs.json._
case class CustomDataEntity(id:int,name: String, data: JsValue)
object CustomDataTableDef {
val data = TableQuery[CustomDataTableDef]
}
class CustomDataTableDef(tag: Tag) extends Table[CustomDataEntity](tag, "custom"){
def id = column[Int]("id", O.PrimaryKey)
def name = column[String]("name")
def data = column[JsValue]("data")
override def * =
(id,name,data) <> (CustomDataEntity.tupled,CustomDataEntity.unapply(_))
}
when I'm trying to compile the code, I get the below 2 errors
could not find implicit value for parameter tt: slick.ast.TypedType[play.api.libs.json.JsValue]
[error] def data = column[JsValue]("data")
Cannot resolve symbol <>
Please help me to resolve this
Your object CustomPostgresProfile extends PostgresProfile instead of CustomPostgresProfile. If you fix that, it works.

Play Framework Anorm withConnection Error

I have the following case class and class in Play Framework 2.5. Since the DB object has been deprecated I'm trying to use the new dependency inject methodology but not understanding why my code does not compile. The old method works fine, the new method has compilation error.
missing parameter type on the implicit connection =>
package models
import javax.inject.{Inject, Singleton}
import play.db._
import anorm.SqlParser._
import anorm._
import play.api.db.DB
import play.api.Play.current
case class Department(id: Int,
name: String)
#Singleton
class DepartmentDao #Inject() (dBApi: DBApi) {
private val db = dBApi.getDatabase("default")
val simple = {
get[Int]("department.id") ~
get[String]("department.name") map {
case id ~ name => Department(id, name)
}
}
def getDepartments = DB.withConnection { implicit connection =>
SQL("SELECT * FROM DEPARTMENT")
}
def getDepartmentsNew = db.withConnection { implicit connection =>
SQL("SELECT * FROM DEPARMTMENT")
}
}
UPDATE:
I've placed what the code looked like before was I was originally trying to get it working. Unless I am missing something this code should run. It is identical to code I've seen in multiple sample projects.
#Singleton
class DepartmentDao #Inject() (dBApi: DBApi) {
private val db = dBApi.getDatabase("default")
val simple = {
get[Int]("department.id") ~
get[String]("department.name") map {
case id ~ name => Department(id, name)
}
}
def getDepartments: Seq[Department] = db.withConnection { implicit connection =>
SQL("SELECT * FROM DEPARMTMENT").as(simple.*)
}
}

Deleting is not working with Play! 2.4, Slick 3 and PostgreSQL

I have read this SO post: Play 2.4 - Slick 3.0.0 - DELETE not working
but it seems not to work in my case.
I manage to insert or get some data from my PostgreSQL (9.1) database in my Play! 2.4 application, but I don't manage to perform some deletions.
Here is the very simple code of my controller:
package controllers
import javax.inject.Inject
import play.api.db.slick.DatabaseConfigProvider
import play.api.mvc._
import slick.driver.JdbcProfile
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import slick.driver.PostgresDriver.api._
import models.Address
class Application #Inject()(dbConfigProvider: DatabaseConfigProvider) extends Controller {
val dbConfig = dbConfigProvider.get[JdbcProfile]
import dbConfig._
import dbConfig.driver.api._
def index = Action.async {
db.run(addresses.filter(_.id === 1L).delete) map { res =>
Ok(Json.toJson(res))
}
}
}
and my model Address:
case class Address(id: Option[Long], city: String)
object Address {
class Addresses(tag: Tag) extends Table[Address](tag, "addresses") {
def id = column[Long]("addressid", O.PrimaryKey, O.AutoInc)
def city = column[String]("city")
def * = (id.?, city) <>
((Address.apply _).tupled, Address.unapply)
}
lazy val addresses = TableQuery[Addresses]
}
The compilation error I get is: value delete is not a member of slick.lifted.Query[models.Address.Addresses,models.Address.Addresses#TableElementType,Seq]
I suspect that it comes from the imports, but I tried a lot of things without any improvement.
I suspect that the problem is that you are importing the implicits needed for the delete function twice, thus generating an ambiguity and causing the compiler to give up on that:
import slick.driver.PostgresDriver.api._
import dbConfig.driver.api._
You don't probably need one of the two anyway, if you are trying to be generic (e.g. because you want to run tests over H2) try removing the PostgresDriver import. If that doesn't work try removing the inner import and leave PostgresDriver as the SO post you linked seemed to suggest that delete was (is?) not in the common API.

reactivemongo, could not find implicit value for parameter reader

I'm doing tests with reactivemongo
In my controller I have this:
package controllers
import models._
import models.JsonFormats._
import play.modules.reactivemongo.MongoController
import scala.concurrent.Future
import reactivemongo.api.Cursor
import org.slf4j.{LoggerFactory, Logger}
import javax.inject.Singleton
import play.api.mvc._
import reactivemongo.api.collections.default.BSONCollection
import reactivemongo.bson._
#Singleton
class Users extends Controller with MongoController {
private final val logger: Logger = LoggerFactory.getLogger(classOf[Users])
val collection = db[BSONCollection]("users")
// list all articles and sort them
def list = Action.async { implicit request =>
// get a sort document (see getSort method for more information)
val sort = getSort(request)
// build a selection document with an empty query and a sort subdocument ('$orderby')
val query = BSONDocument(
"$orderby" -> sort,
"$query" -> BSONDocument())
val activeSort = request.queryString.get("sort").flatMap(_.headOption).getOrElse("none")
// the cursor of documents
val found = collection.find(query).cursor[User]
// build (asynchronously) a list containing all the articles
found.collect[List]().map { users =>
Ok(views.html.admin.list(users, activeSort))
}.recover {
case e =>
e.printStackTrace()
BadRequest(e.getMessage())
}
}
...........
}
and in my model i have this:
package models
import reactivemongo.bson._
case class User(
nickName: String,
email: String,
password: String,
active: Boolean
)
object JsonFormats {
import play.api.libs.json.Json
// Generates Writes and Reads for Feed and User thanks to Json Macros
implicit val userFormat = Json.format[User]
}
When I compile the project returns the following error:
could not find implicit value for parameter reader: reactivemongo.bson.BSONDocumentReader[models.User]
in this line is the problem:
val found = collection.find(query).cursor[User]
Can anyone tell me where I'm wrong or what I'm missing please?
You have no implicit handler defined to map your model class to a BSONDocument. You can implement it yourself, or, just like you did for the JsonFormats, you could use the macros provided by ReactiveMongo.
object BsonFormats {
import reactivemongo.bson.Macros
implicit val userFormat = Macros.handler[User]
}
Alternatively, instead of the BSONCollection, you could use the JSONCollection provided by Play-ReactiveMongo to perform your mapping using the JSON format that you have already defined.
For me, I still get the error even after I have declared the implicits for both bson and json format. What I need to do is just import this:
import reactivemongo.api.commands.bson.BSONCountCommandImplicits._