How to align case objects with scalafmt? - scala

I would like to align case objects extending some class with scalafmt:
sealed abstract class AClass(id: String)
object AClass {
case object Abc extends AClass("1")
case object De extends AClass("2")
case object Fghi extends AClass("3")
}
I have tried the following with in .scalafmt.conf with no success:
align.tokens=[
{ code = "extends", owner = "case object" }
]
What options should I use?

Related

Tapir Custom Codec

I am stuck at a place, I am using scala, tapir and circe.
sealed abstract class S1Error extends Product with Serializable
object S1Error {
final case class SError(error: SMError) extends S1Error
}
sealed abstract class SMError(message: String)
object SMError {
final case class SVError(message: String) extends SMError(message)
}
For tapir errorOut I am using this
val schemaVersionError: EndpointOutput.StatusMapping[SError] = statusMappingValueMatcher(
StatusCode.BadRequest,
jsonBody[SError]
.description("XXXX.")
) {
case SMError(SVError(_)) => true
case _ => false
}
Now because of this structure, the API result I get is
{
"error": {
"SVError": {
"message": "XXXXG"
}
}
}
where as ideally I would want a response as
"message": "XXXXG"
I can not change the error structure.
Is there a way to wrap this error using a custom codec to get the result as required.
Tapir codec is derived from Circe's decoder and encoder.
What you see is the default way of encoding case classes by circe.
Circe provides the possibility to encode case classes the way you described with deriveUnwrappedEncoder from circe-generic-extras. Unfortunately, it doesn't compile for SMError (probably derivation mechanism gets confused by your abstract class hierarchy).
What you can do is just creating encoder manually:
sealed abstract class S1Error extends Product with Serializable
object S1Error {
final case class SError(error: SMError) extends S1Error
implicit val encoder: Encoder[SError] = Encoder[SMError].contramap(_.error)
// or you can use deriveUnwrappedEncoder from circe-generic-extras:
// implicit val encoder: Encoder[SError] = deriveUnwrappedEncoder
}
//I also needed to make message a field in SMError
sealed abstract class SMError(val message: String)
object SMError {
final case class SVError(override val message: String) extends SMError(message)
implicit val encoder: Encoder[SMError] = Encoder.encodeJsonObject.contramap{s => JsonObject("message" -> s.message.asJson)}
}
Response now looks like:
{
message": "XXXXG"
}

How to handle the return type of a method that sometimes return a case class object and sometimes returns a Future of that case class

Let's say I have 4 Objects that share the same method called getParentName().
two of the object getParentName() returns Info, which is just a case class
object Jack extends Person {
override def getParentName(): Info = {...}
}
object Mila extends Person {
override def getParentName(): Info = {...}
}
and the other two returns a Future[Info] :
object Mike #Inject() (wsclient: WSClient) extends Person {
override def getParentName(): Future[Info] = {...}
}
object Amy #Inject() (wsclient: WSClient) extends Person {
override def getParentName(): Future[Info] = {...}
}
and now I want to have PeopleManager class that is iterating on those objects list and getting getParentName() results:
class PeopleManager {
def getParentsNames ():??? = {
listOfPeople.map(person => person.getParentName)
}
}
but im not sure what is the right way to handle getParentsNames() return type...
the controller will use PeopleManager in an Action the to release a GET method for getting parents names. what will be a good way to handle this situation?
thanks!

scala ADTs via sealed traits - is there a way to deserialize from string in a generic fashion

Let's say I have the following trait
trait Named {
def name: String
}
and the following Algebraic Data Type
sealed trait Animal extends Named
case object Dog extends Animal {
override val name: String = "dog man"
}
case object Cat extends Animal {
override val name: String = "cat man"
}
case object Owl extends Animal {
override val name: String = "I am an owl left in the dark"
}
Now, I can deserialize an instance of string into my Animal ADT with the following method.
object Animal {
def apply(name: String): Animal = name match {
case Dog.name => Dog
case Cat.name => Cat
}
}
#oxbow_lakes mentions at the end of his answer that:
Can't instantiate easily from persisted value. This is also true but,
except in the case of huge enumerations (for example, all currencies),
this doesn't present a huge overhead.
I find that the fact that when you add a new value it needs to be added to the deserialization code explicitly as error prone (I thought that the compiler would warn me of an in-exhaustive match, but take a look at Owl above and the apply method - there was no warning issued...)
Is there no better way? (If not with the standard scala toolset, a third party one?)
This problem already solved by enumeratum library:
https://github.com/lloydmeta/enumeratum
Your code could be written like this:
import enumeratum._
import enumeratum.EnumEntry.Lowercase
sealed trait Animal extends EnumEntry with Lowercase
object Animal extends Enum[Animal] {
val values = findValues
case object Dog extends Animal
case object Cat extends Animal
case object Owl extends Animal
}
val dogName = Animal.Dog.entryName
val dog = Animal.withNameInsensitive(dogName)
One thing you could try is to use reflection to obtain the set of types that extend Animal, then use that to create a Map[String,Animal] using name to lookup object values, then use the map in your Animal.apply function.
Refer to this question for more information on obtaining the Animal subclasses.

WIth Squeryl (using Lift), how can I make two model classes a subclass of the same class?

Using Lift with Squeryl, how can I make two classes a subclass of the same class?
My classes look like the following:
class SubClass1 extends Record[SubClass1] with KeyedRecord[SubClass1] with CreatedUpdated[SubClass1] {
val id = ...
val field1a = StringField(...)
...
}
class SubClass2 extends Record[SubClass2] with KeyedRecord[SubClass2] with CreatedUpdated[SubClass2] {
val id = ...
val field2a = StringField(...)
}
I want SubClass1 and SubClass2 each to be a child class of some other class, say MyParentClass. So I would think that I would have to do something like this:
abstract class MyParentClass extends Record[MyParentClass] with KeyedRecord[MyParentClass] with CreatedUpdated[MyParentClass] {}
and then
class SubClass1 extends MyParentClass {
val id = ...
val field1a = StringField(...)
...
}
class SubClass2 extends MyParentClass {
val id = ...
val field2a = StringField(...)
...
}
This gives me errors, such as the fields (StringField) etc. not conforming to the right type. Any suggestions on how to do this?
Thanks,
You abstract superclass can't define a concrete type parameter, since it needs to be overriden by the subclasses. Try:
abstract class MyParentClass[A <: MyParentClass]
extends Record[A] with KeyedRecord[A] with CreatedUpdated[A]
Then:
class SubClass extends MyParentClass[SubClass]

using Enum in traits in scala

i have a trait named UserT and a class DirectUserT extending the trait
i want to add enum in the trait so that child classes can use it
i have made a scala Object UserStatus which extends Enumeration
now i want to have this enum in my trait so that child classes can use it but i dont know how should i do is ?
my enum object
package testlogic
object UserStatus extends Enumeration{
type UserStatus = Value
val ACTIVE , INACTIVE , BLOCKED , DELETED = Value
}
here is my code for UserT
package testlogic
import testlogic.UserStatus._
trait UserT {
var name : String = ""
def setName( aName: String)= {
name = aName
}
def getName : String = {
name
}
}
DirectUserT.scala
package testlogic
class DirectuserT extends UserT {
var currentStatus =BLOCKED
//println(currentStatus)
}
eclipse shows error on BLOCKED
Please help
You need to add
import testlogic.UserStatus._
to you class DirectUserT.scala
Or add it within your trait:
trait UserT {
import testlogic.UserStatus._
}