The HS.SDA3.TimeStamp datatype class  accepts both YYYY-MM-DDT00:00:00Z and YYYY-MM-DDT00:00:00 values but truncates the additional date values if the length is more than 19 in some system methods such as IsValid, LogicalToXSD methods while performing exports. I have verified and This changes happened whenever it converts to XML. However the actual entire value is persist YYYY-MM-DDT00:00:00Z in the container object. Container object have capability to export both XML and JSON as a stream by using ToJSON() method. You can run the DTL programmatically to get the container object to verify. 

SAMPLES> write container
2@HS.SDA3.Container
SAMPLES> write container.Patient
3@HS.SDA3.Patient
SAMPLES> write container.Patient.BirthTime
1993-12-12T00:00:00Z

I used the DTL generated container object value for another DTL source to generate a FHIR discrete resource. It works. The BirthTime is same as the expected value

{
  "resourceType": "Patient",
  "birthDate": "1993-12-12T00:00:00Z"
}

Hello @Smythe Smythee 

There is no difference between ensemble and IRIS instance. In your case, the source.MemberDOB is an date( ex 01/01/2000) and the conversion is working perfectly. Can you check the input of the memberDOB before conversion and just take a quick look of the previous samples.

USER>write $ZV
IRIS for Windows (x86-64) 2023.1 (Build 229) Fri Apr 14 2023 17:36:18 EDT
USER>set DOB="01/01/1999"
 
USER>write $translate($ZDT($ZDTH(DOB),3)," ","T")_"Z"
1999-01-01T00:00:00Z

The same code is works in IRIS Interoperability DTL as well.

<assign value='$translate($ZDT($ZDTH(source.DOB),3)," ","T")_"Z"' property='target.{PID:DateTimeofBirth}' action='set' />

 

AFAIK No. There is no straightforward way to import JSON from FHIR discrete resources to SDA3 objects by %JSONImport(). Basically, there are various stages involved in converting the FHIR to HL7 and vice versa. To achieve this, Intersystems created an intermediary format called SDA. However, there are more processes involved whenever convert the bundle or discrete resource.
for example

  1. In some instances, the FHIR resource data element name (property) is not the same as the SDA property.
  2. Lots of internal DTL's are invoked or invoked at the conversion time, and an SDA object is created based on that output. Typically it's common for SDA to FHIR and vice versa. 
  3. DTL's are crucial to accomplish this conversion. Some of the data elements are not mapped in the standard FHIR to SDA or SDA to FHIR DTL transformation. HS.FHIR.DTL.vR4.SDA3.AllergyIntolerance.Allergy in this DTL the "criticality" data element is not mapped with SDA object In this case you should create your custom DTL from the already implemented DTL to convert the values to object. So If you haven't added this type of additional properties in the SDA extension class, it won't work.
  4. Metadata values and lookup tables vary from SDA to FHIR. SDA has 'A' in the lookup tables for some fields, while FHIR has 'Active'. There is a internal validation runs against every data element to verify the generated FHIR resource Every time

%JSON.Adaptor default manner is rid out the null value properties when %JSONExport method invokes. There is some default parameter are used to achieve this while exporting. You need to enable parameter in your class definition. The %JSONNULL parameter is used to export all the field and display even the property has null values. Once you have added the parameter and try export the itemdetails object

Parameter %JSONNULL As BOOLEAN = 1;
Class Samples.AllItems Extends (%JSON.Adaptor, Ens.Response)
{

Parameter %JSONNULL As BOOLEAN = 1;

Property ItemtId As %String;
Property itemName As %String(MAXLEN = 100);
Property itemStockNumber As %String(MAXLEN = 150);
Property itemType As %String;
Property itemPriority As %String;
Property itemDetailData As %String(MAXLEN = 10000);
}
{
    "ItemId": "test",
    "Item": [
        {
            "ItemtId": null,
            "itemName": null,
            "itemStockNumber": 123,
            "itemType": "test",
            "itemPriority": "High",
            "itemDetailData": null
        }
    ]
}

Hello @Hannah Sullivan 
If you need to delete the list of object while deleting the parent object. You can override the %OnDelete method and add the delete implementation refer below code logic. Once you call the ##Class(package.class).%DeleteId(id). It will trigger the %OnDelete Method and delete the list of persistent object as well.

ClassMethod %OnDelete(oid As %ObjectIdentity) As %Status [ Private, ServerOnly = 1 ]
{
    set object = ..%Open(oid,,.status)
    If $$$ISERR(status) quit status
    If $IsObject(object.Organizations) {
        set org= object.OrganizationsGetSwizzled()
        while org.GetNext(.key){
            do object.Organizations.GetAt(key).%DeleteId(key)
        }
    }
    Quit $$$OK
}

You can create these object with Parent-child relationship as well.

I'm not sure why the request class CSVtoHL7.Inputfile.Record inherits from right. All the request and response are required persistent object. This will be used to display the entire flow in the visual trace section. I have attached some sample below.

You can add a property setter method for property DOB and modify the value from MM/DD/YYYY to +$H value. This will keep the internal date format in database.

Class CSVtoHL7.Inputfile.Record Extends (Ens.Request, %XML.Adaptor, EnsLib.RecordMap.Base) [ ProcedureBlock ]
{
Property ID As %Integer;
Property LastName As %String;
Property FirstName As %String;
Property MiddleName As %String;
Property DOB As %Date;
Method DOBSet(pDate) As %Status
{
    Set i%DOB= $ZDH(pDate)
    Quit $$$OK
}
Property Gender As %String;
ClassMethod createObj() As CSVtoHL7.Inputfile.Record
{
    Set obj = ##class(CSVtoHL7.Inputfile.Record).%New()
    Set obj.DOB="12/30/2001"
    Set obj.FirstName="Test"
    Set obj.ID=12345
    Set obj.MiddleName = "middle"
    Set obj.Gender="M"
    return obj
}
}

Create a object for the request class and send to Transformation. you can use the logic $translate($ZDT(source.DOB_",0",3)," ","T")_"Z" in DTL to convert the internal date format to required output 2023-08-24T00:00:00Z. You can refer the DTL sample below

Class CSVtoHL7.DTL.Record Extends Ens.DataTransformDTL [ DependsOn = (CSVtoHL7.Inputfile.Record, EnsLib.HL7.Message) ]
{

Parameter IGNOREMISSINGSOURCE = 1;

Parameter REPORTERRORS = 1;

Parameter TREATEMPTYREPEATINGFIELDASNULL = 0;

XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='CSVtoHL7.Inputfile.Record' targetClass='EnsLib.HL7.Message' targetDocType='2.5:ADT_A01' create='new' language='objectscript' >
<assign value='source.ID' property='target.{PID:SetIDPID}' action='set' />
<assign value='source.FirstName' property='target.{PID:PatientName().FamilyName}' action='set' />
<assign value='source.MiddleName' property='target.{PID:PatientName().GivenName}' action='set' />
<assign value='source.Gender' property='target.{PID:AdministrativeSex}' action='set' />
<assign value='$translate($ZDT(source.DOB_",0",3)," ","T")_"Z"' property='target.{PID:DateTimeofBirth.Time}' action='set' />
</transform>
}

}

output

As we mentioned above the DOB should have +$H value instead of MM/DD/YYYY. However you can try the below

If DOB is date format

IRISMYDEV>set dob="12/01/1993"
IRISMYDEV>write $translate($ZDT($ZDTH(dob),3)," ","T")_"Z"
1993-12-01T00:00:00Z

If DOB is +$H value

IRISMYDEV>set dob=+$H
IRISMYDEV>write $translate($ZDT(d_",00000",3)," ","T")_"Z"
2023-08-24T00:00:00Z

Hello @Joel Solon 

  • The %ValidateObject() method is used to validate the property. Not to find out the property is modified in the opened object
IRISMYDEV>set obj = ##Class(Samples.NewClass2).%OpenId(1)
IRISMYDEV>write obj.Name
Test
IRISMYDEV>zwrite obj.%ValidateObject()
1
IRISMYDEV>set obj.Name="newname"
IRISMYDEV>zwrite obj.%ValidateObject()
1
  • m%_Property is used to verify whether the property is modified before save. Incase If we need to verify

Class Samples.NewClass2 Extends %Persistent
{
Property Name As %String;
Method modified()
{
    write "Property modifed : ",$Property(,"m%Name")
}
}
IRISMYDEV>set obj = ##Class(Samples.NewClass2).%OpenId(1)
IRISMYDEV>do obj.modified()
Property modifed : 0
IRISMYDEV>set obj.Name="test"
IRISMYDEV>do obj.modified()
Property modifed : 1
IRISMYDEV>
  • I hope, we don't have any built in method like "propertyIsModified" to verify the property is modified 

Hello Smythe,

I agree with @Robert Cemper points. The %Date datatype is for +$H which means numeric date value. Not an string. You should modify the datatype of the property or use string functions.

IRISMYDEV>s obj = ##Class(CSVtoHL7.Inputfile.Record).%New()
IRISMYDEV>s obj.DOB="12/12/1993"
IRISMYDEV>zw ##Class(%Date).IsValid(obj.DOB)
"0 "_$lb($lb(7207,"12/12/1993",,,,,,,,$lb(,"IRISMYDEV",$lb("e^IsValid+1^%Library.Date.1^1","e^^^0"))))/* ERROR #7207: Datatype value '12/12/1993' is not a valid number */
 
IRISMYDEV>w $SYSTEM.OBJ.DisplayError()
ERROR #7207: Datatype value '12/12/1993' is not a valid number1
IRISMYDEV>s obj = ##Class(CSVtoHL7.Inputfile.Record).%New()
IRISMYDEV>s obj.DOB=$ZDateH("12/12/1993")
IRISMYDEV>zw ##Class(%Date).IsValid(obj.DOB)
1

Nice article. However, there is a minor problem while setting the trailing zero values in %Set() of dynamicobject. But, It's not happening in literal constructor {} syntax. Due to objectscript not keep the trailing zeros. But json number do.

    set json = { "decimal": 12.000}
    zw json
    set json1= ##Class(%DynamicObject).%New()
    do json1.%Set("decimal", 12.000) ; this is consider as string
    do json1.%Set("decimal1", $FN(12,,2), "number")	
    zw json1
    
    #;output
    json={"decimal":12.000}  ; <DYNAMIC OBJECT>
    json1={"decimal":12,"decimal1":12}  ; <DYNAMIC OBJECT>