s_mach.datadiff is an open-source data difference engine for Scala. Implementations of the DataDiff type-class are provided which can compute the difference between all data types, Option, Set, Seq, Map and all tuple types. A DataDiff implementation for any case class (or other type that has matching apply/unapply) can be generated at compile-time by the DataDiff.forProductType macro method. The difference between any two instances is stored as a patch type, which can be user-defined per type. Patches can be applied to instances of the original type to propagate computed changes. All provided DataDiff implementations are 100% strongly-typed and use absolutely no runtime reflection.
-
Add to build.sbt
libraryDependencies += "net.s_mach" %% "datadiff" % "1.1.1"
Notes_mach.datadiff is cross compiled for Scala 2.11/JDK6 and 2.12/JDK8
s_mach.datadiff uses semantic versioning (http://semver.org/). s_mach.datadiff does not use the package private modifier. Instead, all code files outside of the s_mach.datadiff.impl package form the public interface and are governed by the rules of semantic versioning. Code files inside the s_mach.datadiff.impl package may be used by downstream applications and libraries. However, no guarantees are made as to the stability or interface of code in the s_mach.datadiff.impl package between versions.
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_72).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
import s_mach.datadiff._
case class Name(
first: String,
middle: Option[String],
last: String
)
case class NamePatch(
first: StringPatch,
middle: OptionPatch[String, StringPatch],
last: StringPatch
)
object Name {
implicit val dataDiff_Name = DataDiff.forProductType[Name,NamePatch]
}
case class Person(
name: Name,
age: Int
)
case class PersonPatch(
name: NamePatch,
age: IntPatch
)
object Person {
implicit val dataDiff_Person = DataDiff.forProductType[Person,PersonPatch]
}
val p1 = Person(Name("Gary",None,"Oldman"),56)
val p2 = Person(Name("Gary",Some("Freakn'"),"Oldman"),57)
// Exiting paste mode, now interpreting.
import s_mach.datadiff._
defined class Name
defined class NamePatch
defined object Name
defined class Person
defined class PersonPatch
defined object Person
p1: Person = Person(Name(Gary,None,Oldman),56)
p2: Person = Person(Name(Gary,Some(Freakn'),Oldman),57)
scala> val patch1 = p1 calcDiff p2
patch1: PersonPatch = PersonPatch(NamePatch(None,SetValue(Freakn'),None),1)
scala> patch1 == patchFor[Person].noChange
res0: Boolean = false
scala> val patch2 = p1 calcDiff p1
patch2: PersonPatch = PersonPatch(NamePatch(None,NoChange,None),0)
scala> patch2 == patchFor[Person].noChange
res1: Boolean = true
scala> val p3 = p1 applyPatch patch1
p3: Person = Person(Name(Gary,Some(Freakn'),Oldman),57)
scala> p3 == p2
res2: Boolean = true
scala> val p4 = p1 applyPatch patch2
p4: Person = Person(Name(Gary,None,Oldman),56)
scala> p4 == p1
res3: Boolean = true
