code snippets are trivialized, sampled, for the purpose of this post.
case class Person(firstName:String,lstName:String)
This person class has been used all over the place in a codebase. Now later requirements changed and deciding to add phoneNumber in the person case class
e.g.
case class Person(firstName:String,lstName:String,phoneNumber:String)
again, examples are extremely simplified in the post. In reality there are more interesting things are happening. Note that phoneNumber is not an Option but a required field. Generally one would go and update all the code that's using Person class, to cater new field lastName. which is quite tedious when you have 100 references of it.
Can shapeless help in creating more flexible HList from get go vs case class?
The easiest way to go about it would be to provide a default value for phoneNumber:
case class Person(firstName: String, lastName: String, phoneNumber: String = "")
Alternatively, you could create a companion object and implement an apply() method for both cases, i.e. with and without phoneNumber. If you decide to take this approach, and you're using the case class in pattern matches, you might also want to implement the corresponding unapply() methods.
Related
I'm building the following api for Users in play scala:
case class User(_id: BSONObjectId, username: String)
The issue is that when the client sends a request in order to store/create a new user the _id is not present.
One viable solution seemed to be:
case class User(_id: Option[BSONObjectId], username: String)
However, it seemed a bit annoying to check for the option field not only for inserting the user, but for the other CRUD operations.
One suggestions that I got was to have two types:
case class User(name: String) ; type UserWithId = (Id, User)
or
case class User[A](id: A, name: String); type UserWithId = User[BSONObjectId]
type UserWithoutId = User[Unit]
I chose the latter implementation as it seemed appropiate.
I created the proper Json Formats to deal with both cases insertion and the other operations:
object User {
lazy val userWithIdFormat: OFormat[UserWithId] = Json.format[UserWithId]
lazy val userWithoutIdFormat: OFormat[UserWithoutId] = Json.format[UserWithoutId]
}
However, now I faced an issue when Inserting, how to convert elegantly from UserWithoutId => UserwithId after the Id has been generated
So the next step was to create this method:
case class User[A](_id: A, username: String)
{
def map[B](f: A => B): User[B] = ???
}
Is this some type of Monad that I need to implement? (Just learning category theory now)
I guess the easiest way is to just add an "initialized/empty" state where the case Class is required to always have an Id, and only when it's persisted it will have username.
Something like val initalizedUser = User(BSONObjectId.generate(), "")
What is the best approach here?
Are using Types would improve performance wise and make the domain more rich, or just adding a state will make it more approachable for future colleagues
What would be the implementation for map, is this something I should extract and have my own Monad implementation to be applied for all future collections?
Is it better to reach for a functional library to solve this issue or not yet?
In my opinion using complex types seems unnecessary here: it won't improve performance and may confuse some colleagues who are not familiar with the concepts.
My favorite approach here is to have two case classes, one for user creation and one to represent the created entity:
case class CreateUser(username: String)
case class User(id: BSONObjectId, username: String)
This has several advantages:
expresses the user intents
you can have different fields in both entities and more complex validation on the CreateUser case class
will be more future proof
The downsize is that it requires to write one more case class, but it's quite easy in scala
I have case classes which have Option[java.sql.Timestamp] field.
case class BooRow(id:Int, createdTs: Option[java.sql.Timestamp])
case class FooRow(id: Int, name:String, deptId:Int,createdTs:Option[java.sql.Timestamp])
case class BarRow(id:Int,name:String)
looking for a generic solution which is also compile time safe to observe incoming case class instance and if it finds createdTs:Option[java.sql.Timestamp] in it then populate it.
Originally thought started with looking at shapless and had posted this question. Gabriele 's answer is right in the context of that previous question but may be I wasn't clear enough in the question so not sure how to "catch" "implicit not found error for that shapeless solution" (for the case class which doesn't have createdTs field) somehow. Generic function should populate createdTs if found in a case class instance it was passed, if it doesn't find createdTs in an instance of a case class then do nothing.
I have tagged slick for this question because these are slick generated case classes (not the reason for tagging) but I assume this can be a common need (generically populating such timestamp columns) when dealing with slick/databases in general. To clarify, I am not looking for db based solutions (like triggers etc) but something at an application level also without using structural types.
Edit: Providing default value to createdTs in case class declaration is not a desired solution. That will stamp wrong timestamp when case class instance is created for an "update" query.
Depending on how you are expecting to arrive at instances of you case classes, one option might be to ensure the createdTs parameter is given a default value on creation:
case class BooRow(id:Int, createdTs: Option[java.sql.Timestamp] = Some(new java.sql.Timestamp((new java.util.Date).getTime)))
However, it isn't clear from your question if this can cover your particular use case.
I have several objects that closely (but not perfectly) mirror other objects in Scala. For example, I have a PackagedPerson that has all of the same fields as the PersonModel object, plus some. (The PackagedPerson adds in several fields from other entities, things that are not on the PersonModel object).
Generally, the PackagedPerson is used for transmitting a "package" of person-related things over REST, or receiving changes back (again over REST).
When preparing these transactions, I have a pack method, such as:
def pack(p: PersonModel): PackagedPerson
After all the preamble is out of the way (for instance, loading optional, extra objects that will be included in the package), I create a PackagedPerson from the PersonModel and "everything else:"
new PackagedPerson(p.id, p.name, // these (and more) from the model object
x.profilePicture, y.etc // these from elsewhere
)
In many cases, the model object has quite a few fields. My question is, how can I minimize repetitive code.
In a way it's like unapply and apply except that there are "extra" parameters, so what I really want is something like this:
new PackagePerson(p.unapply(), x.profilePicture, y.etc)
But obviously that won't work. Any ideas? What other approaches have you taken for this? I very much want to keep my REST-compatible "transport objects" separate from the model objects. Sometimes this "packaging" is not necessary, but sometimes there is too much delta between what goes over the wire, and what gets stored in the database. Trying to use a single object for both gets messy fast.
You could use LabelledGeneric from shapeless.
You can convert between a case class and its a generic representation.
case class Person(id: Int, name: String)
case class PackagedPerson(id: Int, name: String, age: Int)
def packagePerson(person: Person, age: Int) : PackagedPerson = {
val personGen = LabelledGeneric[Person]
val packPersonGen = LabelledGeneric[PackagedPerson]
// turn a Person into a generic representation
val rec = personGen.to(person)
// add the age field to the record
// and turn the updated record into a PackagedPerson
packPersonGen.from(rec + ('age ->> age))
}
Probably the order of the fields of your two case classes won't correspond as nice as my simple example. If this is the case shapeless can reorder your fields using Align. Look at this brilliant answer on another question.
You can try Java/Scala reflection. Create a method that accepts a person model, all other models and model-free parameters:
def pack(p: PersonModel, others: Seq[Model], freeParams: (String, Any)*): PackedPerson
In the method, you reflectively obtain PackedPerson's constructor, see what arguments go there. Then you (reflectively) iterate over the fields of PersonModel, other models and free args: if there's a field the name and type of which are same as one of the cunstructor params, you save it. Then you invoke the PackedPerson constructor reflectively using saved args.
Keep in mind though, that a case class can contain only up to 22 constructor params.
I'm new to Scala and trying to understand how I should be modeling these objects.
The goal here is to have an object that will be stored into a database. The data to store will come from a POST. The post does not contain all of the data that will be persisted.
The OO side of me says to make a base class with the common fields. Extend it represent the data that is posted, and extend that to represent the object that is persisted. However, it seems that case classes are used for this sort of thing, and case class inheritance is discouraged/deprecated/buggy, so I'm not quite sure what I should be doing.
Also, the repetition feels very... wrong.
I am hoping someone a bit more experienced can offer some insight on how to approach this.
abstract class TestBase(val someField: String)
case class TestPost(override val someField: String) extends TestBase(someField)
case class Test(testId: String, override val someField: String) extends TestBase(someField)
Also, if I did continue with this approach, how would you copy fields from a TestPost instance to a Test instance?
although you are doing OOP and you can in Scala you should also be pressing on the functional way of doing things, functional programming states your objects should be immutable and case classes that's what they are for, they represent the value object pattern built right in the language. My advice would be to use composition instead.
case class A(field : Field)
case class B(a : A, moreFields : Fields)
I am not sure how you are trying to persist things to a database.
In my web application authorized user has at least 4 "facets": http session related data, persistent data, facebook data, runtime business data.
I've decided to go with case class composition instead of traits for at least two reasons:
traits mixing can cause name clashes
i want the free case class goodies like pattern matching and copy method
I'd like to know experienced scalaists opinions on this subject. It looks like traits and/or cake pattern should be suitable for such tasks but as i've mentioned above there are problems... Its obvious that not only i want to implement it fast and easy but also to understand it in depth for using in future.
So does my decision have any flaws and misunderstanding or is it right?
Related code looks like this:
case class FacebookUserInfo(name: String, friends: List[Long])
case class HttpUserInfo(sessionId: String, lastInteractionTime: Long, reconnect: Boolean)
case class RuntimeQuizUserInfo(recentScore: Int)
trait UserState {
def db: User
def http: HttpUserInfo
}
case class ConnectingUser(db: User, http: HttpUserInfo) extends UserState
case class DisconnectedUser(db: User, http: HttpUserInfo, facebook: Option[FacebookUserInfo]) extends UserState
case class AuthorizedUser(db: User, http: HttpUserInfo, facebook: FacebookUserInfo,
quiz: RuntimeQuizUserInfo) extends UserState
I think the answer is easy: Go with inheritance, as long as everything really "belongs" to your object, as long as everything is in the same "problem domain".
The intention of the cake pattern is to factor out parts of the object that are somehow required, but are not really part of it, e.g. a strategy, a decoration, a configuration, a context etc. Logging would be a typical example. Generally we're talking about situations you don't want to "hard-wire" things, e.g. cases you would consider to use a DI framework (like Guice or Spring) in Java. See http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html for a good example.
A question that often helps to decide what to do is: "How could I test the object behavior?". If you find it difficult to set up a proper test environment, chances are that you should decouple things, and that means DI, which can be often realized conveniently with the cake pattern.
The third option is to use implicit converters aka "pimp my library," which probably is not necessary since you have the control of the code.
It all depends on how opaque (or transparent) you want to be about certain aspect of your object. You can pretend its a plain old case class to the rest of the world, but internally make it do extra work by using implicits. The use of case class to hold data is appropriate but I also feel that it's awkward to represent the same object using three classes (ConnectingUser, DisconnectedUser, AuthenticatedUser) depending on her state of authentication.
For the UserState, you could provide an extractor so it behaves like a case class:
object UserState {
def unapply(state: UserState) = Some(state.db, state.http)
}
this can be used in a match state as follows:
val user = ConnectingUser(User(), HttpUserInfo("foo", 0, false))
user match {
case UserState(db, http) => println(http)
}