olon.json.Merge.scala Maven / Gradle / Ivy
The newest version!
package olon
package json
/** Use fundep encoding to improve return type of merge function (see:
* http://www.chuusai.com/2011/07/16/fundeps-in-scala/)
*
* JObject merge JObject = JObject JArray merge JArray = JArray _ merge _ =
* JValue
*/
private[json] trait MergeDep[A <: JValue, B <: JValue, R <: JValue] {
def apply(val1: A, val2: B): R
}
private[json] trait LowPriorityMergeDep {
implicit def jjj[A <: JValue, B <: JValue]: MergeDep[A, B, JValue] =
new MergeDep[A, B, JValue] {
def apply(val1: A, val2: B): JValue = merge(val1, val2)
private def merge(val1: JValue, val2: JValue): JValue =
(val1, val2) match {
case (JObject(xs), JObject(ys)) => JObject(Merge.mergeFields(xs, ys))
case (JArray(xs), JArray(ys)) => JArray(Merge.mergeVals(xs, ys))
case (JNothing, x) => x
case (x, JNothing) => x
case (_, y) => y
}
}
}
private[json] trait MergeDeps extends LowPriorityMergeDep {
implicit object ooo extends MergeDep[JObject, JObject, JObject] {
def apply(val1: JObject, val2: JObject): JObject = JObject(
Merge.mergeFields(val1.obj, val2.obj)
)
}
implicit object aaa extends MergeDep[JArray, JArray, JArray] {
def apply(val1: JArray, val2: JArray): JArray = JArray(
Merge.mergeVals(val1.arr, val2.arr)
)
}
}
/** Function to merge two JSONs.
*/
object Merge {
/** Return merged JSON. Example:
val m = ("name", "joe") ~ ("age",
* 10) merge ("name", "joe") ~ ("iq", 105) m:
* JObject(List((name,JString(joe)), (age,JInt(10)), (iq,JInt(105))))
*/
def merge[A <: JValue, B <: JValue, R <: JValue](val1: A, val2: B)(implicit
instance: MergeDep[A, B, R]
): R = instance(val1, val2)
private[json] def mergeFields(
vs1: List[JField],
vs2: List[JField]
): List[JField] = {
def mergeRec(xleft: List[JField], yleft: List[JField]): List[JField] =
xleft match {
case Nil => yleft
case JField(xn, xv) :: xs =>
yleft find (_.name == xn) match {
case Some(y @ JField(_, yv)) =>
JField(xn, merge(xv, yv)) :: mergeRec(
xs,
yleft filterNot (_ == y)
)
case None => JField(xn, xv) :: mergeRec(xs, yleft)
}
}
mergeRec(vs1, vs2)
}
private[json] def mergeVals(
vs1: List[JValue],
vs2: List[JValue]
): List[JValue] = {
def mergeRec(xleft: List[JValue], yleft: List[JValue]): List[JValue] =
xleft match {
case Nil => yleft
case x :: xs =>
yleft find (_ == x) match {
case Some(y) =>
merge(x, y) :: mergeRec(xs, yleft filterNot (_ == y))
case None => x :: mergeRec(xs, yleft)
}
}
mergeRec(vs1, vs2)
}
private[json] trait Mergeable extends MergeDeps {
implicit class MergeSyntax[A <: JValue](val json: A) {
/** Return merged JSON.
* @see
* olon.json.Merge#merge
*/
def merge[B <: JValue, R <: JValue](other: B)(implicit
instance: MergeDep[A, B, R]
): R =
Merge.merge(json, other)(instance)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy