Storing case object with squeryl - scala

How do I store user case objects with squeryl? I have an Account object with a permission field of type Permission (defined as a sealed trait). I also have 2 case objects (Administrator and NormalUser) extending from Permission. How can I persist the Account class using Squeryl. Example code below:
sealed trait Permission
case object Administrator extends Permission
case object NormalUser extends Permission
case class Account(
id: Long,
email: String,
permission: Permission
) extends KeyedEntity[Long]

Expanding on my comment, if you use a custom type to retrieve the permission type, such that it persists to the database as an integer (in the example below 1 and 0), you can override the unapply method to lookup the case object and pattern matching should work fine. I imagine something like the following should work:
class Permission(identifier:Int) extends org.squeryl.customtypes.IntField(identifier) {
self: CustomType[Int] =>
private lazy val permissions =
List(Administrator, NormalUser).
map(p => p.value -> p).
toMap
def unapply = permissions.get(value)
}
case object Administrator extends Permission(1)
case object NormalUser extends Permission(0)
Then you should be able to store the permission directly in your code, using your entity definition:
case class Account(
id: Long,
email: String,
permission: Permission
) extends KeyedEntity[Long]
you can set the permission field directly as Administrator or NormalUser and you should also be able to pattern match like:
account.permission match {
case Administrator => ..
case NormalUser => ..
}

You need to define schema:
object Library extends Schema {
val authors = table[Author]("AUTHORS")
}
and then insert entity:
authors.insert(new Author("Herby Hancock"))
http://squeryl.org/schema-definition.html
http://squeryl.org/inserts-updates-delete.html
In order to store Permission it must inherit one of the subtypes of CustomType in the package
org.squeryl.customtypes, and import the org.squeryl.customtypes.CustomTypesMode._
into the scope where statements are defined. For details read section Custom Types here: http://squeryl.org/schema-definition.html

Related

Creating a type-sensitive function without changing the parent trait or case classes

Suppose I have two classes, Person and Business, that are extended by the trait Entity.
trait Entity
case class Person(name: String) extends Entity
case class Business(id: String) extends Entity
Assuming I cannot change Entity, Person and Business (they are in a different file and not to be changed) how can I define a function, say a printEntity, that prints the field name or id, depending on the entity? For example, given instances of Person and Business, how can I do something like this:
object Main extends App {
val person1: Person = Person("Aaaa Bbbb")
val business1: Business = Business("0001")
// How can I do something like this?
person1.printEntity // would call a function that executes println(id)
business1.printEntity // would call a function that executes println(name)
}
Any ideas are appreciated! Sorry for the lack of context, I am still learning!
This is done via so called "extension methods". In scala 2 this is achieved using implicit wrapper class:
trait Entity
case class Person(name: String) extends Entity
case class Business(id: String) extends Entity
implicit class PersonWrapper(val p: Person) extends AnyVal {
def printEntity(): Unit = {
println(p.name)
}
}
implicit class BusinessWrapper(val b: Business) extends AnyVal {
def printEntity(): Unit = {
println(b.id)
}
}
val person1: Person = Person("Aaaa Bbbb")
val business1: Business = Business("0001")
person1.printEntity()
business1.printEntity()
// prints:
//Aaaa Bbbb
//0001
Note, x.printEntity can be called without parentheses, but, by convention, methods with Unit result type and side effects should be called with explicit empty parentheses.
UPD: As #DmytroMitin pointed out, you should extend implicit wrapper classes from AnyVal. This allows the compiler to avoid actually allocating wrapper class instances at runtime, improving performance.

Scala using Implicit with Self Types

I have a implicit class which requires a user database. I want to use self-type in implicit class so I can switch implementation of database in testing scope to the mocked version. How do I mix-in database provider in this case? For example, I want user of RuchUser to not worry about having to mix-in UserDatabaseProvider by providing default mix-in. So user can just do User("name").userContext and do the same at testing scope where I will provide default mix-in to use mocked database provider?
case class User(name: String)
object User {
implicit class RichUser(self: User) { this: UserDatabaseProvider =>
def userContext: String = this.getUserContext(self.name)
}
}
// Usage of Rich user should be below as I want to provide already mixed-in implicit
import User._
val context = User("name").uerContext
I think you are overcomplicating quite a bit.
case class User(name: String) {
def context()(implicit db: UserDatabaseProvider): UserContext = {
db.getUserContext(name)
}
}
I would go to further suggest the cake pattern may be more applicable here than using implicits.
class UserService extends UserDatabaseProvider {
def context(user: User): UserContext = getUserContext(user.name)
}
class TestUserService extends UserService with TestDatabase
Let "right-most wins" diamond resolution in Scala do the job for you.

Case class without parameters alternative

During some simple scala coding exercise I ran into ideological problem of case classes without parameters and constructor parameters duplication.
It all started with the following two quite simple classes:
trait Namespace
case class Reply[T](namespace: Namespace, correlation: String, data: Try[T])
abstract class Request(val namespace: Namespace, val id: String = UUID.randomUUID().toString) {
def success[T](data: T) = Reply(namespace, id, Try(data))
def failure(msg: String) = Reply(namespace, id, Failure(new RuntimeException(msg)))
}
Now let's assume i have an entity Post and I want to add All class as a command to query all records of type Post. In my current set up it would be easier to actually write the following:
case class All extends Request(Posts)
However in this case I get compiler warning that case classes without parameters are deprecated. So one might suggest to rewrite it into the following:
case object All extends Request(Posts)
However in this case object All will be instantiated only once along with its id field which would like to avoid having unique id for each request.
Could you please suggest a better way of representing All command so that it would not be required to duplicate constructor arguments?
Thanks in advance?
The actual warning is that
case classes without a parameter list are not allowed; use either case
objects or case classes with an explicit `()' as a parameter list.
So give this class an empty parameter list, just as suggested by the compiler:
case class All() extends Requests(Posts)
Don't use a case class or case object, just use a companion apply instead. You don't really want an object here anyway, if you need a unique ID for every request.
class All extends Requests(Posts)
object All {
def apply(): All = new All()
}
getPosts(All())

How to model enum types in phantom dsl?

My case class contains enum parameter like as follows:
case class User(role: UserRole.UserRole, name: String)
object UserRole extends Enumeration {
type UserRole = Value
val ADMIN, USER = Value
}
How to model this case as in this example?
Any code samples provided will be helpful.
You need to use EnumColumn, which is created for this very reason. If you want to use the enum as a key, then you also need to create a primitive using the default helper methods.
You can use both flavours of defining an enum.
object Records extends Enumeration {
type Records = Value
val TypeOne, TypeTwo, TypeThree = Value
}
object NamedRecords extends Enumeration {
type NamedRecords = Value
val One = Value("one")
val Two = Value("two")
}
object enum extends EnumColumn[Records.type](this, Records)
In your case this would be:
object role extends EnumColumn[UserRole.type](this, UserRole)
To use this as an index, you will need:
implicit val userRolePrimitive = Primitive(UserRole)
Update As of Phantom 2.0.0+
object role extends EnumColumn[UserRole](this)
You don't need to define any additional implicits, Enums are now natively suported as indexes.

What are the correct apply and unapply methods to avoid this java.lang.ClassCastException error in a Scala Play app?

I'm building a Scala Play app where events and data are persisted in Json format, and I'm trying to model users and the roles they're assigned. My thinking has been to model Roles as case objects, as each standard role only needs defining once for all users in the application, and I'd like to pattern match on the type of role a particular user has been assigned. So far, I have this;
package models
abstract class User {
def displayName: String
def role: Role
}
case class GuestUser(displayName: String, role: Role) extends User {
}
case class RegisteredUser(displayName: String, role: Role) extends User {
}
trait Role { // have tried abstract class too - but like idea of developing stackable traits for role permissions
}
object Role {
implicit val RoleTypeFormat: Format[Role] = Json.format[Role]
def apply(className: String): Role = Class.forName(className: String).asInstanceOf[Role]
def unapply(role: Role): Option[String] = Option(this.getClass.getName) // have also tried .getSimpleName
}
case object GuestUserRole extends Role {
}
case object RegisteredUserRole extends Role {
}
If I don't define an apply and unapply method in object Role, and rely only on the implicit value that uses Json.format[Role], I get a 'no apply function found' or 'no unapply function found' error - so I added them, to try and get rid of this error.
I couldn't get it to compile without adding .asInstanceOf[Role] to the Role apply method. It now compiles, but when I try to set the role: Role parameter of a new RegisteredUser instance using,
val role: Role = RegisteredUserRole
a new RegisteredUser instance is created, where the role property gets serialized to Json as;
"role":{"className":"models.Role$”}
But when I try to deserialize it, I get Exception in thread "pool-4868-thread-1" java.lang.ClassCastException: java.lang.Class cannot be cast to models.Role
My aim is to end up with the same RegisteredUser instance (or GuestUser instance), so I can do pattern matching in the view controllers, along the lines of;
def isAuthorized: Boolean = {
role match {
case RegisteredUserRole => true
case GuestUserRole => false
// etc
}
}
Any help and advice on this would be very much appreciated. I'm not yet skilled and knowledgeable enough in Scala and Play to know whether I'm even on the right track with modelling Users and Roles.
As #lmm suggested, it would be better to provide a custom Format[Role] rather than trying to create instances in a weird way.
Something like this:
implicit val fmt = new Format[Role] {
def reads(js: JsValue): JsResult[Role] = {
js.validate[String] fold (
error => JsError(error),
role => role match {
case "GuestUserRole" => JsSuccess(GuestUserRole)
case "RegisteredUserRole" => JsSuccess(RegisteredUserRole)
case _ => JsError(Nil) // Should probably contain some sort of `ValidationError`
}
)
}
def writes(r: Role): JsValue = JsString(r.toString)
}