/* Ċ Ġ* ĠCopyright Ġ 2 0 2 1 ĠGoogle ĠLLC Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġcom . google . android . fhir . db . impl . dao Ċ Ċ import Ġca . u hn . fhir . parser . I Parser Ċ import Ġcom . fasterxml . jackson . databind . JsonNode Ċ import Ġcom . fasterxml . jackson . databind . ObjectMapper Ċ import Ġcom . github . f ge . json patch . Json Patch Ċ import Ġcom . github . f ge . json patch . diff . Json Diff Ċ import Ġcom . google . android . fhir . db . impl . entities . Local Change Entity Ċ import Ġorg . hl 7 . fhir . r 4 . model . Resource Ċ import Ġorg . json . JSONArray Ċ import Ġorg . json . JSONObject Ċ Ċ internal Ġobject ĠLocal Change Utils Ġ{ ĊĊĠ Ġ/** ĠS qu ash Ġthe Ġchanges Ġby Ġmerging Ġthem Ġtwo Ġat Ġa Ġtime . Ġ*/ ĊĠ Ġfun Ġsqu ash ( local Change Entities : ĠList < Local Change Entity >): ĠLocal Change Entity Ġ= ĊĠĠĠ Ġlocal Change Entities . reduce Ġ{ Ġfirst , Ġsecond Ġ-> Ġmerge Local Changes ( first , Ġsecond ) Ġ} ĊĊĠ Ġfun Ġmerge Local Changes ( first : ĠLocal Change Entity , Ġsecond : ĠLocal Change Entity ): ĠLocal Change Entity Ġ{ ĊĠĠĠ Ġ// ĠTODO Ġ( maybe Ġthis Ġshould Ġthrow Ġexception Ġwhen Ġtwo Ġentities Ġdon 't Ġhave Ġthe Ġsame Ġversion ID ) ĊĠĠĠ Ġval Ġtype : ĠLocal Change Entity . Type ĊĠĠĠ Ġval Ġpayload : ĠString ĊĠĠĠ Ġwhen Ġ( second . type ) Ġ{ ĊĠĠĠĠĠ ĠLocal Change Entity . Type . UPDATE Ġ-> ĊĠĠĠĠĠĠĠ Ġwhen Ġ( first . type ) Ġ{ ĊĠĠĠĠĠĠĠĠĠ ĠLocal Change Entity . Type . UPDATE Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtype Ġ= ĠLocal Change Entity . Type . UPDATE ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpayload Ġ= Ġmerge Pat ches ( first . payload , Ġsecond . payload ) ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠ ĠLocal Change Entity . Type . INSERT Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtype Ġ= ĠLocal Change Entity . Type . INSERT ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpayload Ġ= Ġapply Patch ( first . payload , Ġsecond . payload ) ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalArgumentException ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Cannot Ġmerge Ġlocal Ġchanges Ġwith Ġtype Ġ${ first . type } Ġand Ġ${ second . type } ." ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ ĠLocal Change Entity . Type . DELETE Ġ-> Ġ{ ĊĠĠĠĠĠĠĠ Ġtype Ġ= ĠLocal Change Entity . Type . DELETE ĊĠĠĠĠĠĠĠ Ġpayload Ġ= Ġ"" ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ ĠLocal Change Entity . Type . INSERT Ġ-> Ġ{ ĊĠĠĠĠĠĠĠ Ġtype Ġ= ĠLocal Change Entity . Type . INSERT ĊĠĠĠĠĠĠĠ Ġpayload Ġ= Ġsecond . payload ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn ĠLocal Change Entity ( ĊĠĠĠĠĠ Ġid Ġ= Ġ 0 , ĊĠĠĠĠĠ Ġresource Id Ġ= Ġsecond . resourceId , ĊĠĠĠĠĠ Ġresource Type Ġ= Ġsecond . resourceType , ĊĠĠĠĠĠ Ġtype Ġ= Ġtype , ĊĠĠĠĠĠ Ġpayload Ġ= Ġpayload , ĊĠĠĠĠĠ Ġversion Id Ġ= Ġsecond . version Id ĊĠĠĠ Ġ) ĊĠ Ġ} ĊĊĠ Ġ/** ĠUpdate Ġa ĠJSON Ġobject Ġwith Ġa ĠJSON Ġpatch Ġ( RFC Ġ 6 9 0 2 ). Ġ*/ ĊĠ Ġprivate Ġfun Ġapply Patch ( resource String : ĠString , Ġpatch String : ĠString ): ĠString Ġ{ ĊĠĠĠ Ġval ĠobjectMapper Ġ= ĠObjectMapper () ĊĠĠĠ Ġval Ġresource Json Ġ= ĠobjectMapper . readValue ( resource String , ĠJsonNode :: class . java ) ĊĠĠĠ Ġval Ġpatch Json Ġ= ĠobjectMapper . readValue ( patch String , ĠJson Patch :: class . java ) ĊĠĠĠ Ġreturn Ġpatch Json . apply ( resource Json ). toString () ĊĠ Ġ} ĊĊĠ Ġ/** ĠMerge Ġtwo ĠJSON Ġpatch Ġstrings Ġby Ġconcaten ating Ġtheir Ġelements Ġinto Ġa Ġnew ĠJSON Ġarray . Ġ*/ ĊĠ Ġprivate Ġfun Ġmerge Pat ches ( first Patch : ĠString , Ġsecond Patch : ĠString ): ĠString Ġ{ ĊĠĠĠ Ġ// ĠTODO : Ġvalidate Ġpatches Ġare ĠRFC Ġ 6 9 0 2 Ġcompliant ĠJSON Ġpatches ĊĠĠĠ Ġval Ġfirst Map Ġ= ĠJSONArray ( first Patch ). patch Merge Map () ĊĠĠĠ Ġval Ġsecond Map Ġ= ĠJSONArray ( second Patch ). patch Merge Map () ĊĠĠĠ Ġfirst Map . put All ( second Map ) ĊĠĠĠ Ġreturn ĠJSONArray ( first Map . values ). toString () ĊĠ Ġ} ĊĊĠ Ġ/** ĠCalculates Ġthe ĠJSON Ġpatch Ġbetween Ġtwo Ġ[ Resource ] Ġs . Ġ*/ ĊĠ Ġinternal Ġfun Ġdiff ( parser : ĠI Parser , Ġsource : ĠResource , Ġtarget : ĠResource ): ĠJSONArray Ġ{ ĊĠĠĠ Ġval ĠobjectMapper Ġ= ĠObjectMapper () ĊĠĠĠ Ġreturn Ġget Filtered JSONArray ( ĊĠĠĠĠĠ ĠJson Diff . as Json ( ĊĠĠĠĠĠĠĠ ĠobjectMapper . readValue ( parser . encode Resource ToString ( source ), ĠJsonNode :: class . java ), ĊĠĠĠĠĠĠĠ ĠobjectMapper . readValue ( parser . encode Resource ToString ( target ), ĠJsonNode :: class . java ) ĊĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ) ĊĠ Ġ} ĊĊĠ Ġ/** ĊĠĠ Ġ* ĠCreates Ġa Ġmutable Ġmap Ġfrom Ġoperation Ġtype Ġ( e . g . Ġadd / remove ) Ġ+ Ġproperty Ġpath Ġto Ġthe Ġentire ĊĠĠ Ġ* Ġoperation Ġcontaining Ġthe Ġupdated Ġvalue . ĠTwo Ġsuch Ġmaps Ġcan Ġbe Ġmerged Ġusing Ġ` Map . put All ()` Ġto ĊĠĠ Ġ* Ġyield Ġa Ġminimal Ġset Ġof Ġoperations Ġequivalent Ġto Ġindividual Ġpatches . ĊĠĠ Ġ*/ ĊĠ Ġprivate Ġfun ĠJSONArray . patch Merge Map (): ĠMutable Map < Pair < String , ĠString >, ĠJSONObject > Ġ{ ĊĠĠĠ Ġreturn Ġ( 0 Ġuntil Ġthis . length ()) ĊĠĠĠĠĠ Ġ. map Ġ{ Ġthis . opt JSONObject ( it ) Ġ} ĊĠĠĠĠĠ Ġ. associate By Ġ{ Ġit . opt String (" op ") Ġto Ġit . opt String (" path ") Ġ} ĊĠĠĠĠĠ Ġ. to Mutable Map () ĊĠ Ġ} ĊĊĠ Ġ/** ĊĠĠ Ġ* ĠThis Ġfunction Ġreturns Ġthe Ġjson Ġdiff Ġas Ġa Ġjson Ġarray Ġof Ġoperation Ġobjects . ĠWe Ġremove Ġthe Ġ"/ meta " ĊĠĠ Ġ* Ġand Ġ"/ text " Ġpaths Ġas Ġthey Ġcause Ġpath Ġnot Ġfound Ġissue Ġwhen Ġwe Ġupdate Ġthe Ġresource . ĠThey Ġare ĊĠĠ Ġ* Ġusually Ġpresent Ġin Ġthe Ġdownloaded Ġresource Ġobject Ġbut Ġare Ġmissing Ġin Ġthe Ġedited Ġobject Ġas Ġthese ĊĠĠ Ġ* Ġaren 't Ġsupposed Ġto Ġbe Ġedited . ĠThus , Ġthe ĠJson Ġdiff Ġcreates Ġa ĠDELETE - ĠOP Ġfor Ġ"/ meta " Ġand Ġ"/ text " ĊĠĠ Ġ* Ġand Ġcauses Ġthe Ġissue Ġwith Ġserver Ġupdate . ĊĠĠ Ġ* ĊĠĠ Ġ* ĠAn Ġun filtered ĠJSON ĠArray Ġfor Ġfamily Ġname Ġupdate Ġlooks Ġlike ĊĠĠ Ġ* Ġ``` ĊĠĠ Ġ* Ġ[{" op ":" remove "," path ":"/ meta "}, Ġ{" op ":" remove "," path ":"/ text "}, ĊĠĠ Ġ* Ġ{" op ":" replace "," path ":"/ name / 0 / family "," value ":" N ucleus "}] ĊĠĠ Ġ* Ġ``` ĊĠĠ Ġ* ĊĠĠ Ġ* ĠA Ġfiltered ĠJSON ĠArray Ġfor Ġfamily Ġname Ġupdate Ġlooks Ġlike ĊĠĠ Ġ* Ġ``` ĊĠĠ Ġ* Ġ[{" op ":" replace "," path ":"/ name / 0 / family "," value ":" N ucleus "}] ĊĠĠ Ġ* Ġ``` ĊĠĠ Ġ*/ ĊĠ Ġprivate Ġfun Ġget Filtered JSONArray ( json Diff : ĠJsonNode ) Ġ= ĊĠĠĠ Ġwith ( JSONArray ( json Diff . toString ())) Ġ{ ĊĠĠĠĠĠ Ġval Ġignore Paths Ġ= Ġset Of ("/ meta ", Ġ"/ text ") ĊĠĠĠĠĠ Ġreturn @ with ĠJSONArray ( ĊĠĠĠĠĠĠĠ Ġ( 0 Ġuntil Ġlength ()). map Ġ{ Ġopt JSONObject ( it ) Ġ}. filter Not Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġignore Paths . contains ( it . opt String (" path ")) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ data Ġclass ĠLocal Change Token ( val Ġids : ĠList < Long >) Ċ Ċ data Ġclass ĠS qu ashed Local Change ( val Ġtoken : ĠLocal Change Token , Ġval Ġlocal Change : ĠLocal Change Entity ) Ċ