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