Mongodb scala driver codec for trait and inherited classes - mongodb

Using the following mongo-driver. I want to insert and get structures (see below) from MongoDB.
trait A {
def id: ObjectId
}
case class B(id: ObjectId) extends A
case class C(id: ObjectId, name: String) extends A
I find a solution with using sealed classes, but I want to use traits.
I want to find a solution with Codecs or something else.

I had the same concern just a few days ago but didn't find anything in the documentation regarding sealed traits for modeling ADT in MongoDB.
In the end, I used sealed class as suggested in the official scala driver github repo.
If you really want to use traits (due to the definition of abstract methods) you can do something like this:
package example.model
import example.model.adt._
import org.mongodb.scala.bson.ObjectId
import org.mongodb.scala.bson.codecs.Macros._
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries}
trait MongoModel {
def _id: ObjectId
}
object MongoModel {
val codecRegistery = fromRegisteries(fromProviders(classOf[A]), DEFAULT_CODEC_REGISTRY)
}
Now you can have your ADT for A defined with sealed class.
package example.model.adt
import example.model.MongoModel
import org.mongodb.scala.bson.ObjectId
sealed class A
final case class B(_id: ObjectId) extends A with MongoModel
final case class C(_id: ObjectId) extends A with MongoModel
This answer doesn't solve the question directly but provides a feasible workaround. Note that this code is just an example. For a more complete implementation, you can see this github repo.

Since release 2.7, the mongodriver is now able to serialize sealed traits.
It works exactly like serializing a sealed classes.

Related

Akka Typed and having base class for MessageAdapters

I am trying something with Akka Typed and Scala, actually something very simple as concept but I could not make it work so may be you can help me.
All my Actors will have one common Signal, so I try to place it to a base class and let my all Actors share it but it the compiler refuse it in the MessageAdapter....
So my code looks like following....
object ContractActor {
sealed trait ContractEvent extends BaseEvent
final case class onApprove(payload: Payload) extends ContractEvent
}
class ContractActor(ctx: ActorContext[ContractEvent]) extends BaseActor {
val listingAdapter = : ActorRef[Receptionist.Listing] = ctx.
messageAdapter(
listing => onAddRelatedEvent(listing)
}
and base actor
object BaseActor {
trait BaseEvent;
final case class onAddRelatedEvent(listing: Receptionist.Listing) extends BaseEvent
}
The compiler complains about onAddRelatedEvent is not known on ContractEvent which surprise me because ContractEvent extends BaseEvent....
What am I missing here....
Class ContractActor extending BaseActor does not automatically bring BaseActor's companion object into scope. To bring it into scope, just import it inside class ContractActor:
import BaseActor._
Alternatively, you could move the inner trait/case class into BaseActor's companion class.

Can you import user-defined scala classes into proto?

I have been tasked to create a general case class that would cover different kinds of config (existing already in the system).
Here's a sample of the configs:
package ngage.sdk.configs
...
object Config {
case class TokenConfig(expiry: FiniteDuration)
case class SagaConfig(timeOut: FiniteDuration, watcherTimeout: FiniteDuration)
case class ElasticConfig(connectionString: String, deletePerPage: Int)
case class S3Config(bucket: String)
case class RedisConfig(host: String, port: Int)
...
I looked to protobuf for a solution, but I don't know how to import the case classes as mentioned above.
Here's how I started:
syntax = "proto3";
package ngage.sdk.distributedmemory.config;
import "scalapb/scalapb.proto";
import "pboptions.proto";
import "google/protobuf/duration.proto";
import "ngage.sdk.configs.Config"; //this became red
option (scalapb.options) = {
flat_package: true
single_file: true
};
message ShardMemoryConfig {
option (ngage.type_id) = 791;
int32 size = 1;
oneof config { //everything inside oneof is red
ngage.sdk.configs.RedisConfig redis = 100002;
ngage.sdk.configs.ElasticConfig elastic = 100003;
ngage.sdk.configs.S3Config s3 = 100004;
}
}
Is it even possible to import user-defined scala classes to protobuf?
You'd need a library which generates .proto files from case class definitions, I don't know if one exists (but I would expect not). PBDirect lets you write/read case classes directly, but then your ShardMemoryConfig should also be a case class using RedisConfig etc.

Purpose of pattern where object extends trait of the same name - object Live extends Live

I am trying ZIO.
I do not understand why Live is added as Trait, and then an object is provided, like:
object Live extends Live
This pattern is found in different places, for example zio.console.Console.
Is there a reason, or are there cases where this makes sense?
What you see in ZIO is the usage of a pattern called Selfless Trait.
To implement the selfless trait pattern you simply provide a companion object for a trait that itself mixes in the trait.
trait Greeting {
def greet() { println("hi there") }
}
object Greeting extends Greeting
Then the user of the library has the choice to either mix-in Greeting:
object MixinExample extends Application with Greeting {
greet()
}
or to import the members of the Greeting companion object, like this:
import Greeting._
object ImportExample extends Application {
greet()
}
Just as an addition to Krzysztof Atłasik answer.
As mentioned in jq170727 comment you find these two cases here:
introduce-a-database-module
Object:
In the worst case, if we are pressed for time and need to ship code
today, maybe we choose to provide the production database wherever we
call inviteFriends.
inviteFriends(userId).provide(DatabaseLive)
In this case, instead of using the DefaultRuntime that ships with ZIO,
we can define our own Runtime, which provides the production database
module):
val myRuntime = Runtime(DatabaseLive, PlatformLive)
Trait:
When you have multiple Runtimes.
val myRuntime =
Runtime(
new DatabaseLive
with SocialLive
with EmailLive, PlatformLive)

What's wrong with CollectionColumn?

I'm trying out phantom from outworkers following the laidout tut on the wiki.
I'm using a test model:
case class User (id: String, name: String, friends: List[String])
with:
import com.websudos.phantom.dsl._
class Users extends CassandraTable[Users, User] {
object id extends StringColumn(this) with PartitionKey[String]
object name extends StringCoumn(this)
object friends extends ListColumn[String](this)
}
The ListColumn[String]() argument this is marked as an error which I presume I shouldnt even bother to build. Expected CassandraTable[String, User] instead of this.
I'm using version 1.29.6
Am I using a different version from the wiki example? Or missing something else?
This is an InteliJ highlightining problem. ListColumn is defined as a type alias inside Cassandra table, and for all type aliases that take constructor arguments, InteliJ is not capable of seeing through them.
That aside, I would really upgrade to phantom 2.0.0+, just because of all the new improvements made in 2.0.0. There is quite a bit of work that's gone into fixing errors and reducing how much code you need to type:
import com.outworkers.phantom.dsl._
class Users extends CassandraTable[Users, User] {
object id extends StringColumn(this) with PartitionKey
object name extends StringCoumn(this)
object friends extends ListColumn[String](this)
}
In more recent versions of phantom, 2.9.x+, the this argument is no longer required using the new compact DSL.
import com.outworkers.phantom.dsl._
abtract class Users extends Table[Users, User] {
object id extends StringColumn with PartitionKey
object name extends StringColumn
object friends extends ListColumn[String]
}

Scala class with Publisher and Subscriber traits

Using import scala.collection.mutable.{Publisher, Subscriber} I'm trying to implement a class that subscribes to events and publishes events. For example, this class may receive raw data, operate on it, then publish the result to other subscribers.
A basic class that extends Subscriber:
scala> class Sub[Evt, Pub]() extends Subscriber[Evt, Pub]{
def notify(pub: Pub, evt: Evt){
}
}
defined class Sub
A basic class that extends Publisher:
scala> class Pub[Evt]() extends Publisher[Evt]{}
defined class Pub
Now, I want to combine the two:
scala> class PubSub[Evt, Pub] extends Subscriber[Evt, Pub] with Publisher[Evt]{
def notify(pub: Pub, evt: Evt){
}
}
<console>:26: error: class PubSub needs to be abstract, since method notify in
trait Subscriber of type (pub: Pub,event: Evt)Unit is not defined class
PubSub[Evt,Pub] extends Subscriber[Evt, Pub] with Publisher[Evt]{
The notify method is defined so perhaps the error is misleading.
I'm not sure how to define the type parameters for the PubSub class which might be part of the problem.
The problem is that the class Publisher defines a type Pub which shadows the generic Pub argument.
Just rename it to something else:
class PubSub[Evt, Pub2] extends Subscriber[Evt, Pub2] with Publisher[Evt]{
def notify(pub: Pub2, evt: Evt){
}
}
You should take a look at the paper Deprecating the Observer Pattern I believe. scala.react package described there isn't released as a part of the standard distribution, but some snapshot is available on the author's homepage. If you are not planning to use it in production systems right now this project can give a sufficient playground.