How to combine class cases? - scala

I am using play framework and slick, play framework uses a case map in the form validation but there are values that I don't need validated as they are not inputed by the user, e.g. the ID & Date which is done is provided on the backend.
By the end I would like to have a class case like this, to provide to Slick and use with my Table.
case class Order(id: Long, order: String, date: Date)
For Play's Form validation I would provide a seperate case class:
case Class inputableOrder(order: String)
Can I then create the Order class that will grab the variables from inputableOrder and added it the Order class?
case class Order(id: Long, date: Date) // <- some way to add the variable from inputableOrder?
I'm just trying to prevent repetition but I still need two different case classes (one for form validation and another for working with the database).
Is there a way to modify an existing case Class , remove a variable or modify a variable type?

I think you have several options here:
Make InputableOrder a part of Order:
case class InputableOrder(order: String) // ...
case class Order(input: InputableOrder, id: Long, date: Date) // ..
This is probably the most idiomatic solution. But it can be inflexible if you later realize that InputableOrder needs something that shouldn't be in Order.
Make Order a subclass of InputableOrder. In this case there is some code repetition when passing arguments to the superclass, and the superclass can't be a case class, so you have to declare it as a regular class and create an extractor yourself:
class InputableOrder(val order: String) // ...
object InputableOrder {
def unapply(o: InputableOrder): Option[String] = Some(o.order);
// if you have more than one constructor arguments, return
// a tuple like Option[(String,String)] etc.
}
case class Order(override val order: String, id: Long, date: Date)
extends InputableOrder(order) // ...
Again, the same problems can arise as with the previous point.
Make the classes distinct and create helper methods to convert between them. The choice depends on your design, but I find this solution to be most flexible:
case class InputableOrder(order: String);
case class Order(order: String, id: Long, date: java.util.Date) {
// An additional constructor to use when converting from Inputable:
def this(other: InputableOrder, id: Long, date: java.util.Date) =
this(other.order, id, date);
// Update this instance with `other`:
def this(that: Order, other: InputableOrder) =
this(other, that.id, that.date);
def toInput = InputableOrder(order);
}
This way you can create an Order from an InputableOrder just by supplying the missing fields and vice versa. You need to write these helper methods/constructors once, but using them is then easy.
You can also use implicit methods such as
implicit def toInput(other: InputableOrder): Order = other.toInput;
to make things even easier.

Related

Same case class different validation

What I'm trying to do in Scala 2.11 and akka is have one case class but two different validations based on which route is being hit.
For example, let's consider the case class below
case class User(_id: String, name: String, age: Int, address: String)
Now while the /create route is hit, I don't need _id but I need all the other fields.
But while /update route is hit, I need the _id and the fields that are to be updated (which could be one or all three)
Only declaring Option doesn't serve the purpose because then my /create route goes for a toss.
Even extending case classes doesn't really work seamlessly (there's too much code duplicity).
I would love if something like this was possible
case class User(_id: String, name: String, age: Int, address: String)
case class SaveUser() extends User {
require(name.nonEmpty)
require(age.nonEmpty)
require(address.nonEmpty)
}
case class UpdateUser() extends User {
require(_id.nonEmpty)
}
Is there an elegant solution to this? Or do I have to create two identical case classes?
My suggestion would be to encode different case classes for different requirements, but if you insist you must share code between these two cases a possible solution would be to parameterize the case class
case class User[Id[_], Param[_]](_id: Id[String], name: Param[String], age: Param[Int], address: Param[String])
Then you define an alias for the Identity type constructor and your two uses of the case class
type Identity[T] = T
type SaveUser = User[Option, Identity]
type UpdateUser = User[Identity, Option]

Where to put complex logic of Scala case class default value

I am new to Scala and i want to understand, where to put the complex logic for default values of Case Classes.
case class Job (name: String, timeStamp: Long = <something more complex>) {
...
}
Where should i put the more complex logic? (For example not just assigning a value)
Do I need to overwrite the apply method, or create a companion object?
Simply add an additional apply method to the companion object:
case class Job(name: String, timeStamp: Long)
object Job {
def apply(name: String): Job = new Job(name, System.currentTimeMillis)
}
val j1 = Job("foo", 345678L)
val j2 = Job("bar")
Now, inside the apply, you have the freedom to make arbitrarily complex computations that can depend on name too, without requiring multiple argument lists.

Common Case Class Variables

Does anyone have any thoughts/better way to handle common fields that cross multiple case classes...for example I have the following case class;
case class Customer(
name: String,
refId: String = ReferenceIdGenerator.generateRefId("CUSTOMER"),
createdAt: DateTime = DateTime.now,
updatedAt: DateTime = DateTime.now,
id: Option[Long] = None)
The last four variables are repeated in every "model/domain" case class in my example application. Is there a better way to remove that common boilerplate code?
One thought would be to create a "common" case class and at least the boilerplate code is limited, for example;
case class CommonFields(refId: String...etc)
case class Customer(name: String, common: CommonFields)
Thoughts?
One thought would be to create a "common" case class and at least the boilerplate code is limited, for example
Yes, this is the correct solution, assuming this works well with whatever you use to interact with the database. If you are using Slick, see also Extending SLICK Tables in a DRY manner.

How can I make a scala class implement ==?

I have a non-case class that I'm trying to test for equality. It has > 22 fields so I can't use a case class in Scala 2.10.x:
class Row(
val date: String,
val time: String,
val orderId: String,
val id: String) extends Serializable {
override def toString: String = {
ToStringBuilder.reflectionToString(this);
}
}
What's the simplest way of me implementing an == or equals function so I can test row1 == row2?
You have no choice but to implement your own equals and therefore hashcode method (not easy) since you cannot implement a case class. This article should help you: object equality. These are the factors you need to bear in mind:
Take care with the type signature of the equals method
Override the hashCode()
Avoid dependencies on mutable state
Should implement and use a canEqual method if the class is non-final
In your example, Row is not a case class. It is a standard class, and thus checked for equality in the standard Java way.
Try this:
case class Row(date: String,
time: String,
orderId: String,
id: String)
Another option (though, since Row isn't a case class, still involves writing field-by-field comparison code) would be to provide an instance of the Scalaz Equal typeclass. This has the advantage of being type-safe. For more information, check out the Learning Scalaz series. (The "typeclasses 102" section has an example of providing an Equal instance for a type).

Scala case class inheritance

I have an application based on Squeryl. I define my models as case classes, mostly since I find convenient to have copy methods.
I have two models that are strictly related. The fields are the same, many operations are in common, and they are to be stored in the same DB table. But there is some behaviour that only makes sense in one of the two cases, or that makes sense in both cases but is different.
Until now I only have used a single case class, with a flag that distinguishes the type of the model, and all methods that differ based on the type of the model start with an if. This is annoying and not quite type safe.
What I would like to do is factor the common behaviour and fields in an ancestor case class and have the two actual models inherit from it. But, as far as I understand, inheriting from case classes is frowned upon in Scala, and is even prohibited if the subclass is itself a case class (not my case).
What are the problems and pitfalls I should be aware in inheriting from a case class? Does it make sense in my case to do so?
My preferred way of avoiding case class inheritance without code duplication is somewhat obvious: create a common (abstract) base class:
abstract class Person {
def name: String
def age: Int
// address and other properties
// methods (ideally only accessors since it is a case class)
}
case class Employer(val name: String, val age: Int, val taxno: Int)
extends Person
case class Employee(val name: String, val age: Int, val salary: Int)
extends Person
If you want to be more fine-grained, group the properties into individual traits:
trait Identifiable { def name: String }
trait Locatable { def address: String }
// trait Ages { def age: Int }
case class Employer(val name: String, val address: String, val taxno: Int)
extends Identifiable
with Locatable
case class Employee(val name: String, val address: String, val salary: Int)
extends Identifiable
with Locatable
Since this is an interesting topic to many, let me shed some light here.
You could go with the following approach:
// You can mark it as 'sealed'. Explained later.
sealed trait Person {
def name: String
}
case class Employee(
override val name: String,
salary: Int
) extends Person
case class Tourist(
override val name: String,
bored: Boolean
) extends Person
Yes, you have to duplicate the fields. If you don't, it simply would not be possible to implement correct equality among other problems.
However, you don't need to duplicate methods/functions.
If the duplication of a few properties is that much of an importance to you, then use regular classes, but remember that they don't fit FP well.
Alternatively, you could use composition instead of inheritance:
case class Employee(
person: Person,
salary: Int
)
// In code:
val employee = ...
println(employee.person.name)
Composition is a valid and a sound strategy that you should consider as well.
And in case you wonder what a sealed trait means — it is something that can be extended only in the same file. That is, the two case classes above have to be in the same file. This allows for exhaustive compiler checks:
val x = Employee(name = "Jack", salary = 50000)
x match {
case Employee(name) => println(s"I'm $name!")
}
Gives an error:
warning: match is not exhaustive!
missing combination Tourist
Which is really useful. Now you won't forget to deal with the other types of Persons (people). This is essentially what the Option class in Scala does.
If that does not matter to you, then you could make it non-sealed and throw the case classes into their own files. And perhaps go with composition.
case classes are perfect for value objects, i.e. objects that don't change any properties and can be compared with equals.
But implementing equals in the presence of inheritance is rather complicated. Consider a two classes:
class Point(x : Int, y : Int)
and
class ColoredPoint( x : Int, y : Int, c : Color) extends Point
So according to the definition the ColorPoint(1,4,red) should be equal to the Point(1,4) they are the same Point after all. So ColorPoint(1,4,blue) should also be equal to Point(1,4), right? But of course ColorPoint(1,4,red) should not equal ColorPoint(1,4,blue), because they have different colors. There you go, one basic property of the equality relation is broken.
update
You can use inheritance from traits solving lots of problems as described in another answer. An even more flexible alternative is often to use type classes. See What are type classes in Scala useful for? or http://www.youtube.com/watch?v=sVMES4RZF-8
In these situations I tend to use composition instead of inheritance i.e.
sealed trait IVehicle // tagging trait
case class Vehicle(color: String) extends IVehicle
case class Car(vehicle: Vehicle, doors: Int) extends IVehicle
val vehicle: IVehicle = ...
vehicle match {
case Car(Vehicle(color), doors) => println(s"$color car with $doors doors")
case Vehicle(color) => println(s"$color vehicle")
}
Obviously you can use a more sophisticated hierarchy and matches but hopefully this gives you an idea. The key is to take advantage of the nested extractors that case classes provide