Question
· Jul 9

Has anyone worked with <MAXSTRING> in Fhir R4 Binary deserialization (From Athena)?

I'm running into an intermittent issue with some of our Custom Operations/Processes as a result of some large FHIR R4 Binaries. Essentially we get a response from an AthenaHealth FHIR endpoint that appears to be too large to be processed using the IRIS Built In Functions for FHIR:

I've replicated it on the command line here using a file (binary.json) that has the response from the FHIR Endpoint. Not sharing full contents due to PHI concerns.

HSCUSTOM>S file=##class(%Stream.FileCharacter).%New()

HSCUSTOM>Do file.LinkToFile("/data/binary.json")

HSCUSTOM>w file.Size
4033045

HSCUSTOM>Set FhirBinary = ##class(HS.FHIR.DTL.vR4.Model.Resource.Binary).%New()

HSCUSTOM 2d1>Do FhirBinary.FromJSON(file,"vR4")

<MAXSTRING>%GetNext+12^%Iterator.Object.1

 

Looking into the Class Code:
 

/// Pure binary content defined by a format other than FHIR.
Class HS.FHIR.DTL.vR4.Model.Resource.Binary Extends HS.FHIR.DTL.vR4.Model.Base.Resource [ Not ProcedureBlock ]
{

/// code
/// <p>
/// MimeType of the binary content.
/// <p>
/// mimetypes|4.0.1 is the REQUIRED FHIR4 ValueSet for codes; 
/// you may NOT extend mimetypes|4.0.1 and you may NOT use codes from other ValueSets.
Property contentType As %String(MAXLEN = 1000000, XMLNAME = "contentType", XMLPROJECTION = "ATTRIBUTE") [ Required ];

/// Reference
/// <p>
/// Identifies another resource to use as proxy when enforcing access control.
/// <p>
/// Any FHIR4 Resource may be indicated by this Reference
Property securityContext As HS.FHIR.DTL.vR4.Model.Base.Reference(XMLNAME = "securityContext", XMLPROJECTION = "ELEMENT");

/// base64Binary
/// <p>
/// The actual content.
Property data As %Binary(XMLNAME = "data", XMLPROJECTION = "ATTRIBUTE");

It appears the data is stored as a %Binary (which is basically a %String) and hits the <MAXSTRING> error.

Sample data:
 

{

"contentType": "image/png",
"data": "<LONG Base64 Encoded Content>",
"id": "XXXXXXXXXXX",

"meta": {

"security": [

{

"code": "NOPAT",

"display": "no disclosure to patient, family or caregivers without attending provider's authorization",

"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"

}

]

},

"resourceType": "Binary"
}

 

I'm essentially trying to deserialize so I can get at the content-type, security, and id properties easily to determine if we do anything with the Base64 itself. It seems odd that productized code from IRIS wouldn't handle this, although I can't say I'm super confident the source data is complying to any standards outside of shape.

We could refactor our existing code to handle SOME of this using DynamicObjects:

HSCUSTOM>s dynObj={}.%FromJSON(file)

HSCUSTOM>w dynObj.contentType
image/png

HSCUSTOM>w $EXTRACT(dynObj.data,1,100) W $EXTRACT(dynObj.data,1,100)
^
<MAXSTRING>

That said, if I still need to access the binary content itself, I'm not sure the best way to handle that. If anyone has run into anything similar, I'd appreciate some feedback.

Thank you!
-Vic

Product version: IRIS 2023.1
$ZV: IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2023.1.1 (Build 380U) Fri Jul 7 2023 23:38:49 EDT
Discussion (1)2
Log in or sign up to continue

I don't know anything about the FhirBinary class but I do know why the %GetNext method in the %Iterator.Array or %Iterator.Object classes is giving the <MAXSTRING> signal.  Let's assume the %GetNext in question is accessing a %DynamicObject as the %DynamicArray case is identical.  A %DynamicObject (usually created by the %FromJSON method) limits it contained string elements only by the amount of memory that can be obtained from the Operating System running the IRIS instance.  Fetching a long string element from a %DynamicObject as an ObjectScript string value will signal <MAXSTRING> when the %DynamicObject string element is too long.  However, you can fetch a long string element as a %Stream.DynamicBinary or %Stream.DynamicCharacter class object.  Such a %Stream object can contain any string that will into the system memory.  Long %Stream contents longer than the ObjectScript maximum string length can be accessed by using the Read(.len,.status) method to access smaller substrings of the %Stream contents.  Also, you can copy one class of long %Stream into a different class of long %Stream if you want to move a long string out of memory and into either a a file or an ObjectScript global array.

The Class Reference documentation for the %Iterator.Object class does not directly appear in either Class Reference webpage on an IRIS instance nor in the Class Reference web page in the InterSystems IRIS network documentation.  This strikes me as a documentation bug.

Fortunately you can see the appropriate Class Reference documentation by indirectly going to the Class Reference page for the %Library.DynamicObject class (or %Library.DynamicArray class) and going to the documentation for %GetIterator method. That documentaton contains a link to the %Iterator.Object class. Click on that link and you will go the %Iterator.Object Class Reference page where you can see the documentation for the GetNext(.key,.value,.type) method.  

%GetNext method is used to iterate over the values in a %DynamicObject.  The third argument, .type, is optional.  The two argument form, %GetNext(.key,.value) will return the key index in .key and its associated ObjectScript value in .value.  If the element value cannot be converted to an ObjectScript value then you will get a <MAXSTRING> or <MAXNUMBER> signal.  However, the three argument form, %GetNext(.key,.value,.type) will not signal these errors.  In place of a <MAXSTRING> signal, the .type argument will contain "string" and the the .value argument will contain the appropriate in-memory %Stream object value.  In place of a <MAXNUMBER> signal, the .type argument will contain "number" and .value will contain a string with the decimal representation of the numeric value.

More detail of other uses for the .type argument of the %GetNext(.key,.value,.type) method call can be found on the %Iterator.Object (or %Iterator.Array) Class Reference web page.

When the Fhir.Binary class needs to iterate over the elements of a %DynamicArray/Object then it should not use the 2 argument form of %GetNext(.key,.value) but should instead use the the 3 argument form %GetNext(.key,.value,.type) and be prepared when the type of the the .value variable does not match the type specified by the .type argument.