Skip to content

Instantly share code, notes, and snippets.

@ConnorDoyle
Last active August 29, 2015 13:56
Show Gist options
  • Save ConnorDoyle/9147037 to your computer and use it in GitHub Desktop.
Save ConnorDoyle/9147037 to your computer and use it in GitHub Desktop.
Versioned
// Versioned
import scala.math.{ Ordered, Ordering }
import scala.collection.{ SortedSet, SortedSetLike }
trait Versioned[V <: Ordered[V]] {
val version: V
}
object Versioned {
/**
* Returns an ordering on type `T` derived from the natural ordering of
* `T`'s version type.
*/
def versionOrdering[T <: Versioned[V], V <: Ordered[V]](): Ordering[T] =
Ordering.by { (item: T) => item.version }
}
// History
/**
* A sorted set of like-typed versioned elements.
*
* The natural ordering of this collection is derived from the orderedness
* of the elements' versions.
*
* @tparam T the type of the elements of this collection
* @tparam V the type of T's versions
*/
class History[T <: Versioned[V], V <: Ordered[V]] protected (
underlying: SortedSet[T]
) extends SortedSet[T] {
def this() =
this(SortedSet[T]()(Versioned.versionOrdering[T, V]))
def this(elems: Seq[T]) =
this(SortedSet[T](elems: _*)(Versioned.versionOrdering[T, V]))
def +(elem: T): History[T, V] = new History(underlying + elem)
def -(elem: T): History[T, V] = new History(underlying - elem)
def contains(elem: T): Boolean = underlying contains elem
def iterator: Iterator[T] = underlying.iterator
implicit def ordering: Ordering[T] = History.versionOrdering[T, V]
def rangeImpl(from: Option[T], until: Option[T]): History[T, V] =
new History(underlying.rangeImpl(from, until))
}
object History {
def apply[T <: Versioned[V], V <: Ordered[V]](): History[T, V] =
new History[T, V]()
def apply[T <: Versioned[V], V <: Ordered[V]](elems: T*): History[T, V] =
new History[T, V](elems)
def versionOrdering[T <: Versioned[V], V <: Ordered[V]](): Ordering[T] =
Ordering.by { (item: T) => item.version }
}
// Usage
case class Timestamp(time: Long) extends Ordered[Timestamp] {
def compare(that: Timestamp) = this.time compare that.time
}
object Timestamp {
def now(): Timestamp = Timestamp(System.currentTimeMillis)
}
trait Timestamped extends Versioned[Timestamp]
case class Person(
name: String,
age: Int,
version: Timestamp = Timestamp.now
) extends Timestamped
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment