22.4.1MDM Survivorship rules

 

MDM supports flexible survivorship rules that determine which attributes are replaced and which are preserved in the Golden Record after MDM operations. These rules are defined as JavaScript handler functions in the MDM survivorship rules module configuration section. Rules can be defined at four different scopes: global, operation type, resource type, and both, operation and resource type. In case multiple handlers are defined, only the most specific one will be called. Please note that the script is not intended to preserve state. Please use bindings to track any required state.

22.4.1.1Global Handler

The global handler function is applied to all MDM resources and request types, unless a more specific handler function is available.

function mdmApplySurvivorshipRules(targetRec, goldenRec, transactionContext) {
  // rule implementation goes here
}

22.4.1.2MDM operation type handler

Operation type handler is more specific than the global handler. It is run on the MDM operations regardless of the resource type provided to the operation.

Handler function should follow the convention mdmApplySurvivorshipRulesOn<OperationType>, where <OperationType> is one of the MDM operation types:

  • CreateResource
  • UpdateResource
  • SubmitResourceToMdm
  • UpdateLink (only when switching update to match)
  • MergeGoldenResources

An example handler function for all resources for MergeGoldenResources operation type is included below:

function mdmApplySurvivorshipRulesOnMergeGoldenResources(fromGoldenRec, toGoldenRec, transactionContext) { 
 // rule implementation goes here
}

22.4.1.3MDM Resource type handler

Resource type handlers apply to all requests with a given MDM resource type. Resource type handlers are considered more specific than operation type handlers. If resource type handler is available, operation type and global handlers will not be executed.

JavaScript function should be named as mdmApplySurvivorshipRulesFor<Resource>Type. <Resource> is any of the supported MDM resource types.

function mdmApplySurvivorshipRulesForPatientType(targetRec, goldenRec, transactionContext) {
 // rule implementation goes here
}

22.4.1.4MDM Operation and Resource type handler

Operation and Resource type handlers are the most specific handler that are applied to MDM requests. JavaScript function should be named using the following convention: mdmApplySurvivorshipRulesOn<OperationType>For<Resource>Type. Where <OperationType> should be one of the MDM supported operation types and <Resource> is any of the supported MDM resource types.

function mdmApplySurvivorshipRulesOnCreateResourceForPatientType(targetRec, goldenRec, transactionContext) { 
  // rule implementation goes here
}

22.4.1.5MDM survivorship bindings

22.4.1.5.1MDM Helper class

The MdmHelper object is available to the survivorship script. It can be used for copying values from the target record to the golden record. The MdmHelper supports the following methods:

Method Description
MdmHelper(Fhir.getContext(), targetRec, goldenRec, transactionContext ) Constructor that accepts FHIR context, target record to copy values from, golden record to copy values to and transaction context.
helper.mergeAll() Adds all values from the target record to the golden record. IDs, identifiers and metadata values are not merged.
helper.replaceAll() Replaces all values in the golden resource with the values in the target resource. IDs, identifiers and metadata are not replaced.
helper.merge(fieldName) Adds the values from the field identified by the fieldName from target record to the golden record.
helper.mergeFields(fieldNames) Adds values from the fields in the fieldNames array from target record to the golden record.
helper.replace(fieldName) Replaces the values from the field identified by the fieldName from target record to the golden record.
helper.replaceFields(fieldNames) Replaces the values from the fields in the fieldNames array from target record to the golden record.
helper.isGoldenResourceFieldEmpty(fieldName) Checks if the fieldName is empty on the golden resource.
helper.isTargetFieldEmpty(fieldName) Checks if the fieldName is empty on the target resource.
helper.isValidTargetResourceField(fieldName) Checks if the fieldName exists on the target resource.
helper.isValidGoldenResourceField(fieldName) Checks if the fieldName exists on the golden resource.
helper.isGoldenResourceOlderThanTarget() Checks if Golden Resource was last modified before the Target Resource (i.e. so that the values form the Target Resources are more recent and we need to modify the Golden Resource appropriately, for instance). This method will return false if timestamp is missing on either the Target or Golden Resource.

22.4.1.5.2Additional bindings

There are also additional objects available to the survivorship script that might be helpful. To learn more about them, please refer to the JavaScript Execution Environment.

Instance Description
BundleUtil Convenience object for retrieving resources with the resourceName from the provided bundle.
Converter Utility instance for converting HL7v2 time to FHIR format and decoding/encoding URL stings.
Environment Convenience object for retrieving JavaScript-related system properties.
Exceptions Convenience object for creating exception instances.
Fhir Utility object for accessing FHIR context.
FhirClientFactory Factory object for creating new FHIR client instances.
Hl7V2 Utility for creating HL7 v2 message segments.
Http Factory object for building HTTP requests.
LdapFactory Utility object for creating LDAP resources.
Log Convenience logger instance.
OAuth2Exceptions Utility object for creating authentication / authorization exceptions.
ResourceBuilder Builder object responsible for creating new FHIR resource instances
TransactionBuilder Builder object responsible for creating new transaction bundles.
Util Utility object pausing current execution.
Uuid Helper object for generating UUIDs.

22.4.1.6Sample MDM Survivorship Rules

/*
   Objects available to the survivorship script:

   * BundleUtil - Convenience object for retrieving resources with the resourceName from the provided bundle.
   * Converter - Utility instance for converting HL7v2 time to FHIR format and decoding/encoding URL stings.
   * Environment - Convenience object for retrieving JavaScript-related system properties.
   * Exceptions - Convenience object for creating exception instances.
   * Fhir - Utility object for accessing FHIR context.
   * FhirClientFactory - Factory object for creating new FHIR client instances.
   * Hl7V2 - Utility for creating HL7 v2 message segments.
   * Http - Factory object for building HTTP requests.
   * LdapFactory - Utility object for creating LDAP resources.
   * Log - Convenience logger instance.
   * OAuth2Exceptions - Utility object for creating authentication / authorization exceptions.
   * ResourceBuilder - Builder object responsible for creating new FHIR resource instances
   * TransactionBuilder - Builder object responsible for creating new transaction bundles.
   * Util - Utility object pausing current execution.
   * Uuid - Helper object for generating UUIDs.

*/

/*
   Global handler
 */
function mdmApplySurvivorshipRules(targetRec, goldenRec, transactionContext) {
   // by default replace name on the golden record, if target has it
   var helper = new MdmHelper(Fhir.getContext(), targetRec, goldenRec, transactionContext);
   if (!helper.isTargetFieldEmpty('name')) {
      helper.replace('name');
   }

   // also replace DOB and phone
   helper.replaceFields(['birthDate', 'telecom']);
}

/*
   Request Type handler
 */
function mdmApplySurvivorshipRulesOnMergeGoldenResources(fromGoldenRec, toGoldenRec, transactionContext) {
   // merge all fields by default
   var helper = new MdmHelper(Fhir.getContext(), targetRec, goldenRec, transactionContext);
   helper.mergeAll();
}

/*
   Request and resource type handlers
 */
function mdmApplySurvivorshipRulesOnMergeGoldenResourcesForPatientType(targetRec, goldenRec, transactionContext) {
   var helper = new MdmHelper(Fhir.getContext(), targetRec, goldenRec, transactionContext);
   if (helper.isGoldenResourceFieldEmpty('address')) {
      // if golden resource has no address, keep the address from the target resource
      helper.replace('address');
   } else {
      // otherwise keep all addresses
      helper.merge('address');
   }
   // re-apply global handler
   mdmApplySurvivorshipRules(targetRec, goldenRec, transactionContext);
}

22.4.1.6.1Sample Global handler that copies identifiers in golden records

/*
   Global handler, that copy identifiers in golden records.
 */
function mdmApplySurvivorshipRules(targetRec, goldenRec, txContext) {
    var helper = new MdmHelper(Fhir.getContext(), targetRec, goldenRec, txContext);
    // Replaces all values in the golden resource with the values in the target resource.
    // But IDs, identifiers and metadata are not replaced.
    helper.replaceAll();
    // Now, copy identifiers (system and value) in the golden record
    for (let i = 0; i < targetRec.getIdentifier().size(); i++) {
        let targetId = targetRec.getIdentifier().get(i);
        let goldenId = getIdentifier(goldenRec, targetId.getSystem());
        if (goldenId === null) {
            goldenRec.addIdentifier(targetId.copy());
        } else {
            goldenId.setValue(targetId.getValue());
        }
    }
}
function getIdentifier(resource, system) {
    for (let i = 0; i < resource.getIdentifier().size(); i++) {
        var id = resource.getIdentifier().get(i);
        if (id.getSystem().equals(system)) {
            return id;
        }
    }
    return null;
}

22.4.1.7MDM Survivorship Setup Guide

  1. Please follow steps 1 to 4 in the Smile CDR MDM Quickstart Guide to set up the MDM module, and make sure the module is successfully started.

  2. By now, you should already have the following suvivorship rules set up. The script contains a global handler that replaces all fields using the values from the target resource, and a Merge Golden Resources operation handler that merges all fields of the fromGoldenRec to the toGoldenRec.

    function mdmApplySurvivorshipRules(targetRec, goldenRec, transactionContext) {
       // by default replace name on the golden record, if target has it
       var helper = new MdmHelper(Fhir.getContext(), targetRec, goldenRec, transactionContext);
       helper.replaceAll();
    }
    
    function mdmApplySurvivorshipRulesOnMergeGoldenResources(fromGoldenRec, toGoldenRec, transactionContext) {
       // merge all fields by default
       var helper = new MdmHelper(Fhir.getContext(), fromGoldenRec, toGoldenRec, transactionContext);
       helper.mergeAll();
    }
    
  3. Let's send a few requests to see their effects concretely. Create a Patient resource: POST {{base_url}}/Patient

{
   "resourceType": "Patient",
   "identifier": [
      {
         "use": "usual",
         "type": {
            "coding": [
               {
                  "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
                  "code": "MR"
               }
            ]
         },
         "system": "http://my-lab-system",
         "value": "123"
      }
   ],
   "active": true,
   "name": [
      {
         "use": "official",
         "family": "Chalmers",
         "given": [
            "Peter",
            "James"
         ]
      }
   ],
   "birthDate": "1974-12-25",
   "gender": "male",
   "address": [
      {
         "use": "home",
         "type": "both",
         "text": "534 Erewhon St PeasantVille, Rainbow, Vic  3999",
         "line": [
            "534 Erewhon St"
         ],
         "city": "PleasantVille",
         "district": "Rainbow",
         "state": "Vic",
         "postalCode": "3999",
         "period": {
            "start": "1974-12-25"
         }
      }
   ]
}
  1. SmileCDR should automatically create a golden resource for the Patient:
{
   "resourceType": "Patient",
   "id": "xxxx",
   "meta": {
      "versionId": "1",
      "lastUpdated": "2023-09-15T11:45:09.705-04:00",
      "tag": [
         {
            "system": "http://hapifhir.io/fhir/NamingSystem/mdm-record-status",
            "version": "1",
            "code": "GOLDEN_RECORD",
            "display": "Golden Record",
            "userSelected": false
         },
         {
            "system": "https://hapifhir.org/NamingSystem/managing-mdm-system",
            "version": "1",
            "code": "HAPI-MDM",
            "display": "This Golden Resource can only be modified by HAPI MDM system.",
            "userSelected": false
         }
      ]
   },
   "identifier": [
      {
         "system": "http://hapifhir.io/fhir/NamingSystem/mdm-golden-resource-enterprise-id",
         "value": "11f70e3a-7988-4410-af6b-545deb50c68f"
      }
   ],
   "active": true,
   "name": [
      {
         "use": "official",
         "family": "Chalmers",
         "given": [
            "Peter",
            "James"
         ]
      }
   ],
   "gender": "male",
   "birthDate": "1974-12-25",
   "address": [
      {
         "use": "home",
         "type": "both",
         "text": "534 Erewhon St PeasantVille, Rainbow, Vic  3999",
         "line": [
            "534 Erewhon St"
         ],
         "city": "PleasantVille",
         "district": "Rainbow",
         "state": "Vic",
         "postalCode": "3999",
         "period": {
            "start": "1974-12-25"
         }
      }
   ]
}
  1. Now, let's send a new patient that will be matched to the same golden resource but with different address and gender.
{
   "resourceType": "Patient",
   "identifier": [
      {
         "use": "usual",
         "type": {
            "coding": [
               {
                  "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
                  "code": "MR"
               }
            ]
         },
         "system": "http://my-lab-system",
         "value": "123"
      }
   ],
   "active": true,
   "name": [
      {
         "use": "official",
         "family": "Chalmers",
         "given": [
            "Peter",
            "James"
         ]
      }
   ],
   "birthDate": "1974-12-25",
   "gender": "female",
   "address": [
      {
         "use": "home",
         "type": "both",
         "text": "111 University St PeasantVille, Rainbow, Vic  1111",
         "line": [
            "111 University St"
         ],
         "city": "PleasantVille",
         "district": "Rainbow",
         "state": "Vic",
         "postalCode": "1111",
         "period": {
            "start": "1974-12-25"
         }
      }
   ]
}
  1. As a result, golden resource should now have the new address and gender instead.
{
   "resourceType": "Patient",
   "id": "xxxx",
   "meta": {
      "versionId": "1",
      "lastUpdated": "2023-09-15T11:45:09.705-04:00",
      "tag": [
         {
            "system": "http://hapifhir.io/fhir/NamingSystem/mdm-record-status",
            "version": "1",
            "code": "GOLDEN_RECORD",
            "display": "Golden Record",
            "userSelected": false
         },
         {
            "system": "https://hapifhir.org/NamingSystem/managing-mdm-system",
            "version": "1",
            "code": "HAPI-MDM",
            "display": "This Golden Resource can only be modified by HAPI MDM system.",
            "userSelected": false
         }
      ]
   },
   "identifier": [
      {
         "system": "http://hapifhir.io/fhir/NamingSystem/mdm-golden-resource-enterprise-id",
         "value": "11f70e3a-7988-4410-af6b-545deb50c68f"
      }
   ],
   "active": true,
   "name": [
      {
         "use": "official",
         "family": "Chalmers",
         "given": [
            "Peter",
            "James"
         ]
      }
   ],
   "gender": "female",
   "birthDate": "1974-12-25",
   "address": [
      {
         "use": "home",
         "type": "both",
         "text": "111 University St PeasantVille, Rainbow, Vic  1111",
         "line": [
            "111 University St"
         ],
         "city": "PleasantVille",
         "district": "Rainbow",
         "state": "Vic",
         "postalCode": "1111",
         "period": {
            "start": "1974-12-25"
         }
      }
   ]
}