0

I'm looking for:

  1. Interface of a mutable collection akin to key-value map that will somehow retain previous states for individual elements, i.e. it's possible to get all previous and current states of an element knowning its key.
  2. Implementation of such interface, preferably backed in some sort of database or some other persistent storage.

Slick database accessing kit indeed allows to access SQL databases as if they were regular Scala collections, however, it doesn't cover accessing any historical states of an entry in a collection. You can do, for example:

suppliers(42)     // => gets current state of a supplier with ID=42
suppliers.get(42) // => gets current state or None if not found

but you can't get a list of all previous states, neither you can get a particular historical state by some sort of history ID. I've browsed through Scala collection overview and it seems that neither of them provides such an API. Everything that conforms to Map[T] interface returns only a single (latest, current) value of T when getting an element.

This concept is implemented in several database backends, for example:

There are quite a few ready-made solutions in other languages, for example:

Community
  • 1
  • 1
GreyCat
  • 16,622
  • 18
  • 74
  • 112

1 Answers1

1

It sounds like you have a simple library in mind, but especially since you mention having persistence to a database, I think you're going to need something a bit more heavyweight than a standard library data structure.

I recommend looking into Akka Persistence. It would take me a while to code up an example, but basically you start an ActorSystem, launch your persistent history map actor, and then use the ask pattern to query the your actor. Akka Persistence is easily configurable to persist its journal to the datastore of your choice.

If you don't really need persistence built in, you can just extend the mutable map trait. The following hasn't been tested, but it should act like a basic mutable map, while storing a history internally. Not sure what the semantics of -= should be with respect to that history, so just made an assumption. Here you go:

class MutableHistoryMap[K, V] extends scala.collection.mutable.Map[K, V] {
  // Invariant: if a key exists, the sequence it maps to has at least one item
  val internalMap = scala.collection.mutable.Map[K, Seq[V]]()

  def +=(kv: (K, V)): MutableHistoryMap.this.type = {
    val (key, newValue) = kv
    val oldValues = internalMap.get(key).getOrElse(Seq())
    internalMap.update(key, newValue +: oldValues)
    this
  }

  def -=(key: K): MutableHistoryMap.this.type = {
    internalMap.get(key) match {
      case Some(values) if values.size > 1=> 
        internalMap.update(key, values.tail)
      case _ =>
        internalMap -= key
    }
    this
  }

  def get(key: K): Option[V] = 
    internalMap.get(key).flatMap(_.headOption)

  def iterator: Iterator[(K, V)] = 
    internalMap.iterator.map {
      case (key, values) => (key, values.head)
    }

  // then whatever methods for modifying your history
}
acjay
  • 34,571
  • 6
  • 57
  • 100