Missing implicit in Phantom Cassandra - scala

Phantom 2.14.5
Scala 2.12.1
I'm experiencing: could not find implicit value for parameter sg: com.outworkers.phantom.macros.SingleGeneric.Aux[User,Repr,HL,Out]
when I try to implement an insert using the generated save. Here are my definitions.
case class User(
id: UUID,
email: String,
firstName: String,
lastName: String,
passwordHash: String,
createdAt: DateTime,
updatedAt: DateTime
)
abstract class Users extends Table[Users, User] {
object id extends UUIDColumn with PartitionKey
object email extends StringColumn
object first_name extends StringColumn
object last_name extends StringColumn
object password_hash extends StringColumn
object created_at extends DateTimeColumn
object updated_at extends DateTimeColumn
def getById(id: UUID): Future[Option[User]] = {
select.where(_.id eqs id).one()
}
def add(user: User): Future[UUID] = {
store(user)
.consistencyLevel_=(ConsistencyLevel.ALL)
.future()
.map(_ => user.id)
}
}
class AppDatabase(override val connector: CassandraConnection)
extends Database[AppDatabase](connector) {
object users extends Users with Connector
}
object Database extends AppDatabase(connector)
Any insight is appreciated! Thanks!

Related

scala error: class type required but T found

I'm trying to create a generic abstract class table and create a generic TableQuery using it with slick
The generic Table:
trait TaskRow {
def dvProjectId: Int
def timestamp: Long
def status: String
}
abstract class TaskTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
def id: Rep[Int] = column[Int]("Id")
def status: Rep[String] = column[String]("Status")
}
Usage:
case class ATaskRow(id: Int, status: String) extends TaskRow
class ATaskTable(tag: Tag) extends TaskTable[ATaskRow](tag, "A") {
def * : ProvenShape[ATaskRow] = (id, status) <> (ATaskRow.tupled, ATaskRow.unapply)
}
class Repo[T <: TaskTable[R], R <: TaskRow] #Inject()(db: DB) {
...
private def table: TableQuery[T] = TableQuery[T]
}
this line gives an error - class type required but T found:
private def table: TableQuery[T] = TableQuery[T]
There's a way I can fix it?
So I solved this.
class ARepo #Inject()(db: DB)
extends Repo[ATaskTable, ATaskRow](db, (tag: Tag) => new ATaskTable(tag))
class Repo[T <: TaskTable[R], R <: TaskRow] (db: DB, cons: Tag => T) {
...
private def table: TableQuery[T] = TableQuery(cons)
}

Sangria: How to handle custom types

trying work with Sangria and Slick. New to both of them.
I have bunch of tables which share a list of common fields. Slick's representation of this is below:
case class CommonFields(created_by: Int = 0, is_deleted: Boolean = false)
trait CommonModel {
def commonFields: CommonFields
def created_by = commonFields.created_by
def is_deleted = commonFields.is_deleted
}
case class User(id: Int,
name: String,
commonFields: CommonFields = CommonFields()) extends CommonModel
Slick tables:
abstract class CommonTable [Model <: CommonModel] (tag: Tag, tableName: String) extends Table[Model](tag, tableName) {
def created_by = column[Int]("created_by")
def is_deleted = column[Boolean]("is_deleted")
}
case class CommonColumns(created_by: Rep[Int], is_deleted: Rep[Boolean])
implicit object CommonShape extends CaseClassShape(
CommonColumns.tupled, CommonFields.tupled
)
class UsersTable(tag: Tag) extends CommonTable[User](tag, "USERS") {
def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
def name = column[String]("NAME")
def * = (id,
name,
CommonColumns(created_by, is_deleted)) <> (User.tupled, User.unapply)
}
val Users = TableQuery[UsersTable]
The problem is with Graphql:
lazy val UserType: ObjectType[Unit, User] = deriveObjectType[Unit, User]()
When I try to create UserType using derivedObjectType Macro, it complains that
Can't find suitable GraphQL output type for .CommonFields. If you have defined it already, please consider making it implicit and ensure that it's available in the scope.
[error] lazy val UserType: ObjectType[Unit, User] = deriveObjectType[Unit, User](
How do I tell Sangria/Graphql how to handle this nested list of fields (from CommonFields) ?
Please help.
You are deriving the Type for User but user also has CommonFields which you have not derived. So it's not able to find Type information for CommonFields. Derive both and make the derivation implicit for CommonFields.
implicit val CommonFieldsType: ObjectType[Unit, CommonFields] = deriveObjectType[Unit, CommonFields]
implicit val UserType: ObjectType[Unit, User] = deriveObjectType[Unit, User]

Play-Slick Repository Pattern

I am trying to implement a simple Repository in a PlayFramework app with the play-slick plugin.
I am new to scala, new to slick, new to play.
When trying to compile my code, i get the following error:
type mismatch;
found : slick.lifted.TableQuery[UserRepository.this.UserTable]
required: UserRepository.this.profile.api.TableQuery[UserRepository.this.BaseTable]
(which expands to) slick.lifted.TableQuery[UserRepository.this.BaseTable]
Note: UserRepository.this.UserTable <: UserRepository.this.BaseTable, but class TableQuery is invariant in type E.
You may wish to define E as +E instead. (SLS 4.5)
Here is my code:
trait BaseEntity {
def id: Long
def createdAt: LocalDateTime
def updatedAt: LocalDateTime
def deletedAt: LocalDateTime
}
case class User (id: Long, firstname: String, lastname: String, password: String, createdAt: LocalDateTime, updatedAt: LocalDateTime, deletedAt: LocalDateTime) extends BaseEntity
abstract class BaseRepository[E <: BaseEntity](protected val dbConfigProvider: DatabaseConfigProvider, executionContext: ExecutionContext) extends HasDatabaseConfigProvider[JdbcProfile] {
import profile.api._
implicit val localDateTimeToTimestamp: BaseColumnType[LocalDateTime] = MappedColumnType.base[LocalDateTime, Timestamp](
l => Timestamp.valueOf(l),
t => t.toLocalDateTime
)
protected abstract class BaseTable(tag: Tag, tableName: String) extends Table[E](tag, tableName) {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def createdAt = column[LocalDateTime]("created_at")
def updatedAt = column[LocalDateTime]("updated_at")
def deletedAt = column[LocalDateTime]("deleted_at")
}
protected val query: TableQuery[BaseTable]
def all(): Future[Seq[E]] = db.run(query.result)
}
class UserRepository #Inject()(#NamedDatabase("effective-potato-play") override protected val dbConfigProvider: DatabaseConfigProvider)(implicit executionContext: ExecutionContext) extends BaseRepository[User](dbConfigProvider, executionContext) {
import profile.api._
protected class UserTable(tag: Tag) extends BaseTable(tag, "user") {
def firstname = column[String]("firstname")
def lastname = column[String]("lastname")
def password = column[String]("password")
def * = (id, firstname, lastname, password, createdAt, updatedAt, deletedAt) <> (User.tupled, User.unapply)
}
protected val query = TableQuery[UserTable]
}
pamus comment led me in the right directions.
I solved the following by moving the inner Table-Class to an own class and giving the query for the repository as constructor argument.
abstract class BaseRepository[E <: BaseEntity, T <: BaseTable[E]](val dbConfigProvider: DatabaseConfigProvider, executionContext: ExecutionContext, query: TableQuery[T]) extends HasDatabaseConfigProvider[JdbcProfile] {
def all(): Future[Seq[E]] = db.run(query.result)
def find(id: Long): Future[Option[E]] = db.run(query.filter(_.id === id).result.headOption)
}
class UserRepository #Inject()(dbConfigProvider: DatabaseConfigProvider)(implicit executionContext: ExecutionContext) extends BaseRepository[User, UserTable](dbConfigProvider, executionContext, TableQuery[UserTable]) {
}
abstract class BaseTable[E <: BaseEntity](tag: Tag, tableName: String) extends Table[E](tag, tableName) {
implicit val localDateTimeToTimestamp: BaseColumnType[LocalDateTime] = MappedColumnType.base[LocalDateTime, Timestamp](
l => Timestamp.valueOf(l),
t => t.toLocalDateTime
)
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def createdAt = column[LocalDateTime]("created_at")
def updatedAt = column[LocalDateTime]("updated_at")
def deletedAt = column[Option[LocalDateTime]]("deleted_at", O.Default(null))
}
class UserTable(tag: Tag) extends BaseTable[User](tag, "user") {
def firstname = column[String]("firstname")
def lastname = column[String]("lastname")
def password = column[String]("password")
def * = (id, firstname, lastname, password, createdAt, updatedAt, deletedAt) <> (User.tupled, User.unapply)
}
I can then use the queries from the BaseRepository like so
userRepository.find(1).map { user =>
Ok(Json.toJson(user))
}

Cassandra Phantom - could not find implicit value for parameter helper: com.outworkers.phantom.macros.TableHelper[Users, User]

I am using Cassandra Phantom driver to build an application with Scala and Cassandra. My code looks like this:
case class User(id: UUID, name:String)
abstract class Users extends CassandraTable[Users, User] with RootConnector {
object id extends UUIDColumn(this) with PartitionKey
object name extends StringColumn(this)
def save(user: User): Future[ResultSet] = {
insert
.value(_.id, user.id)
.value(_.name, user.name)
.consistencyLevel_=(ConsistencyLevel.ALL)
.future()
}
def getById(id: UUID): Future[Option[User]] = {
select.where(_.id eqs id).one()
}
}
But when I try to compile the code it gives me following error:
could not find implicit value for parameter helper: com.outworkers.phantom.macros.TableHelper[Users, User]
I am not able to understand why this error is occurring when I am following documentation.
Phantom Version: 2.7.6
Scala: 2.11.2
case class User(id: UUID, name:String)
abstract class Users extends Table[Users, User] with RootConnector {
object id extends UUIDColumn(this) with PartitionKey
object name extends StringColumn(this)
def save(user: User): Future[ResultSet] = {
store(user)
.consistencyLevel_=(ConsistencyLevel.ALL)
.future()
}
def getById(id: UUID): Future[Option[User]] = {
select.where(_.id eqs id).one()
}
}
I have just compiled this with 2.7.6, you also don't need to manually implement an insert as it is generated for you.

Phantom 1.25.4 with Cassandra

I need help with implementing a model of a notification using phantom and cassandra. What I have done till now:
import java.util.UUID
import com.websudos.phantom.dsl._
import com.websudos.phantom.connectors.Connector
import org.joda.time.DateTime
import scala.concurrent.Future
case class Notification(
id: UUID,
userId: UUID,
timestamp: DateTime,
read: Boolean,
actionUser: List[String],
verb: String,
itemId: UUID,
collectionId: String
)
sealed class NotificationTable extends CassandraTable[NotificationTable, Notification] {
object id extends UUIDColumn(this) with ClusteringOrder[UUID] with Ascending
object userId extends StringColumn(this) with PartitionKey[String]
object timestamp extends DateTimeColumn(this) with ClusteringOrder[DateTime] with Descending
object read extends BooleanColumn(this)
object actionUser extends ListColumn[NotificationTable, Notification, String](this)
object verb extends StringColumn(this)
object itemId extends UUIDColumn(this)
object collectionId extends StringColumn(this)
def fromRow(row: Row): Notification =
Notification(
id(row),
userId(row),
timestamp(row),
read(row),
actionUser(row),
verb(row),
itemId(row),
collectionId(row)
)
}
object NotificationTable extends NotificationTable with Connector {
override def keySpace: String = "test"
implicit val keyspace: com.websudos.phantom.connectors.KeySpace = com.websudos.phantom.connectors.KeySpace("test")
def insertItem(item: Notification): Future[ResultSet] =
insert
.value(_.id, item.id)
.value(_.userId, item.userId)
.value(_.timestamp, item.timestamp)
.value(_.read, item.read)
.value(_.actionUser, item.actionUser)
.value(_.verb, item.verb)
.value(_.itemId, item.itemId)
.value(_.collectionId, item.collectionId)
.future()
}
Somehow, I have to define two keyspaces, one for RootConnector and one for the insert statement. This is close enough to: this example,. Yet, my code does not compile. I know that they are using an abstract class there and hence it compiles.
My question is how would I go about using that abstract class?? I want to just call the insert statement from another scala source.
You are missing the fact that you are meant to use RootConnector instead of a random Connector trait there. The reason why that class is abstract is because it should only be instantiated inside of a Database object.
Have a look at this tutorial for more details, but in short, notice the RootConnector mixin here:
abstract class ConcreteNotificationTable extends
NotificationTable with RootConnector
And then:
class MyDatabase(val connector: KeySpaceDef) extends Database(connector) {
// And here you inject the real session and keyspace in the table
object notifications extends ConcreteNotificationsTable with connector.Connector
}
Then you do something like this:
object MyDatabase extends MyDatabase(ContactPoint.local.keySpace("my_app"))
And from every other source file:
val notification = Notification(id, //etc...)
MyDatabase.notifications.insertItem(someNotification)
And even better seperation of concern, as available in the tutorial:
trait DbProvider extends DatabaseProvider {
def database: MyDatabase
}
trait ProductionDbProvider extends DbProvider {
// this would now point to your object
override val database = MyDatabase
}
Then every single place which needs a database would need to mixin either DbProvider or directly ProductionDbProvider. Read the tutorial for more details, this is not a super trivial topic and all the details are already there.
Try:
import java.util.UUID
import com.websudos.phantom.dsl._
import com.websudos.phantom.connectors.Connector
import org.joda.time.DateTime
import scala.concurrent.Future
case class Notification(
id: UUID,
userId: UUID,
timestamp: DateTime,
read: Boolean,
actionUser: List[String],
verb: String,
itemId: UUID,
collectionId: String
)
//use normal class
class NotificationTable extends CassandraTable[NotificationTable, Notification] {
object id extends UUIDColumn(this) with ClusteringOrder[UUID] with Ascending
object userId extends StringColumn(this) with PartitionKey[String]
object timestamp extends DateTimeColumn(this) with ClusteringOrder[DateTime] with Descending
object read extends BooleanColumn(this)
object actionUser extends ListColumn[NotificationTable, Notification, String](this)
object verb extends StringColumn(this)
object itemId extends UUIDColumn(this)
object collectionId extends StringColumn(this)
def fromRow(row: Row): Notification =
Notification(
id(row),
userId(row),
timestamp(row),
read(row),
actionUser(row),
verb(row),
itemId(row),
collectionId(row)
)
}
//use abstract
abstract class NotificationTable extends NotificationTable with Connector {
def insertItem(item: Notification): Future[ResultSet] =
insert
.value(_.id, item.id)
.value(_.userId, item.userId)
.value(_.timestamp, item.timestamp)
.value(_.read, item.read)
.value(_.actionUser, item.actionUser)
.value(_.verb, item.verb)
.value(_.itemId, item.itemId)
.value(_.collectionId, item.collectionId)
.future()
}