go to post Jeffrey Drumm · Feb 8, 2021 As is USER> w $system.Util.InstallDirectory()_"lib" There's also a LibPath entry in IRIS.cpf, but I'm not sure it's the same. But you can get it: %SYS> do ##class(Config.config).Get(.props) %SYS> write props("LibPath") Unfortunately on the IRIS server I'm working with it's empty ...
go to post Jeffrey Drumm · Jan 20, 2021 What class did you use for the inbound service? I created a small batch of HL7 messages using nothing but newlines (newline is \n ... carriage return is actually \r). I consumed that file using a service based on EnsLib.HL7.Service.FileService and they were processed correctly. If you used one of the HL7 service classes, what did you select for Framing? Finally, is it possible that the messages you're testing with contain an actual backslash (\) character followed by the letter 'n' separating the segments? I've seen this happen before, believe it or not ...
go to post Jeffrey Drumm · Jan 20, 2021 I'm assuming you're working with Ensemble (or Interoperability as it's known in the most recent IRIS-based versions) ... If you create a class that extends Ens.Rule.FunctionSet, not only will you be able to call its methods/functions from the DTL editor, they will appear as selectable functions in the drop-down list.
go to post Jeffrey Drumm · Jan 15, 2021 Nevermind. Ugh. Been a rough week. HL7.{PID.7} Contains CurrentDateTime("YYYYMMDD") Close, but not quite:
go to post Jeffrey Drumm · Jan 15, 2021 This question is more than 2 1/2 years old now, but I guess I missed it when it was posted. Regardless, the issue is that "?" is the match operator that "Matches" represents, and is not part of the pattern itself. Your match pattern should not include the "?" character.
go to post Jeffrey Drumm · Jan 14, 2021 Your syntax for the match argument is wrong. You need quantifiers for the literal strings: 1P4N1":F"5N1"R"1P. This is not obvious from the documentation ... I only discovered it through experimentation. It appears as though the expression editor expects the pattern to be a quoted string, so you'll probably need to follow the syntax for quoting strings that contain quote characters: "1P4N1"":F""5N1""R""1P"
go to post Jeffrey Drumm · Dec 24, 2020 I'm thinking that the value you provided for ElementName in the service's configuration is incorrect. Your class definition also needs to match the structure of the repeating element, not the entire XML document. Here's an example XML structure: <Persons> <Person> <LastName>Drumm</LastName> <FirstName>Jeff</FirstName> <FavoriteColor>Red</FavoriteColor> </Person> <Person> <LastName>Herlick</LastName> <FirstName>Blakely</FirstName> <FavoriteColor>Teal</FavoriteColor> </Person></Persons> The classname you'd create would be something like User.Custom.Person, with properties FirstName, LastName and FavoriteColor. In the service's ElementName field, you'd enter Person. When the file is read, each Person element from the XML would end up in a separate message. You can then filter in the routing rule by using the variables Document.FirstName, Document.LastName, etc. and transform it in the DTL by selecting the Persistent Class User.Custom.Person as the source and your HL7 schema as the target. Make sense?
go to post Jeffrey Drumm · Dec 24, 2020 Hi Blake, Can you provide a bit more detail? If you need to create an individual HL7 message for each repeating element in the XML document, my answer here is probably the easiest way to get there. If there's a "master/detail" relationship within the XML, though, you'll need to handle that in a BPL, and perhaps still "chunk" the XML before handing it off to the BPL if there are multiple elements with master/detail relationships. You'd do that with the XML Object file service mentioned in the link (assuming you're getting these XML documents as local files ... there's also an FTP version of the service). There are tutorials on BPLs in ISC's Learning library.
go to post Jeffrey Drumm · Oct 25, 2020 That works, thanks! So the method is now doing everything I need. In its previous incarnation I was just returning a %String, and although it got me into trouble with messages larger than MAXSTRING, it was a LOT faster ... easily 3x to 5x faster.
go to post Jeffrey Drumm · Oct 25, 2020 Ok ... so this actually works: ClassMethod GetHL7Msg(pId As %String) As %Stream.GlobalCharacter [ SqlName = GetMsg, SqlProc ] { Set tHl7 = ##class(EnsLib.HL7.Message).%OpenId(pId,,.tSC) Throw:$$$ISERR(tSC) ..GetErr(-400, "HL7 Message with ID "_pId_" Not Found.") Set tMsg = ##class(%Stream.GlobalCharacter).%New() Set tSC = tHl7.OutputToLibraryStream(.tMsg) Do tHl7.%Close() If tSC Set tSC=tMsg.%Save() Throw:$$$ISERR(tSC) ..GetErr(-400, $system.Status.GetErrorText(tSC)) Return tMsg."%%OID" } I'm concerned that I'm using a persisted object. Does it automatically get killed once I leave the scope of the function (I'm assuming not, see the last paragraph)? Is there a way to force it to temp storage? It's also very slow, but 1) I'm currently connecting to the database over a VPN connection, and 2) the average message size is around 30KB, with some messages up to 3MB. It took 5 minutes to return 1000 rows. Looks like ^CacheStream is currently using almost 600MB.
go to post Jeffrey Drumm · Oct 25, 2020 No errors running the query from $system.SQL.Shell(), but I get the stream OREF rather than the message in the query result: ID SourceConfigName TargetConfigName Message 191344 InEpicMdm_Router OutOptumMdm 23@%Stream.GlobalCharacter 191348 InEpicMdm_Router OutOptumMdm 25@%Stream.GlobalCharacter 191352 InEpicMdm_Router OutOptumMdm 9@%Stream.GlobalCharacter 191356 InEpicMdm_Router OutOptumMdm 23@%Stream.GlobalCharacter 191360 InEpicMdm_Router OutOptumMdm 25@%Stream.GlobalCharacter 191364 InEpicMdm_Router OutOptumMdm 9@%Stream.GlobalCharacter 191368 InEpicMdm_Router OutOptumMdm 23@%Stream.GlobalCharacter 191372 InEpicMdm_Router OutOptumMdm 25@%Stream.GlobalCharacter 191376 InEpicMdm_Router OutOptumMdm 9@%Stream.GlobalCharacter 191380 InEpicMdm_Router OutOptumMdm 23@%Stream.GlobalCharacter ODBC seems to be doing a little magic in the background to return the stream data, but it's not good magic at the moment. EDIT: Turns out the ODBC wrangler needs a persistent object's "%%OID" rather than an OREF to fetch the stream. See the eventual working method here.
go to post Jeffrey Drumm · Oct 25, 2020 Hi Eduard, I'm having a bit of trouble applying your solution to my problem. I have only one method in EnsLib.HL7.Message that seems to populate a %Stream.TmpCharacter data type, and it doesn't allow me to "chunk" the data. In the code I posted, I should be returning a %Stream.TmpCharacter object functionally identical to yours. I think I am, but suspect that the ODBC handler in IRIS isn't finding the stream.
go to post Jeffrey Drumm · Oct 24, 2020 Also, I should add that although I had said that I wasn't seeing any errors on the client side (aside from not getting the entire result set), that's not exactly true. No errors were displayed in the client application's GUI, but it was logging them to its log file. In examining that log file I found what appears to be a stream-related entry in the connection string: StreamPrefetch=0. I can't find any documentation on it other than it being mentioned (without a description) in the Using .NET and the ADO.NET Managed Provider with Cache section. I'm assuming it takes a number of bytes(?) as an argument, since all the other boolean entries take True/False as values ...
go to post Jeffrey Drumm · Oct 24, 2020 I'll give that a try, but I'm not optimistic. The data is there; the stream object is getting populated because I can Read() it and return the data as a %String ...
go to post Jeffrey Drumm · Oct 24, 2020 Hi Robert, Same result ... a single row and the same error in the IRIS xDBC log: 2020-10-24 01:35:59 [SQLCODE: <-412>:<General stream error>] [Error: <<INVALID OREF>PrepareStream+6^%SYS.SQLStreamSRV>] [Location: <ReadStreamODBC::PrepareStream>] [Client info: <Username: Jeff, Node Name: WIN10X64-VM01, IP Address: 10.208.8.90, Executable Name: HL7Spy.exe, Internal Function: AS>] [%protocol: <59>] $Id: //adhocs-iris/2020.1.0.217.1/HICG_LLC_001/kernel/common/src/aclass.c#1 $ 21256 11 The method works fine if I define the return type as %String, but only until the query fetches a row with a message larger than MAXSTRING in size. I of course have to Return tMsg.Read() to get the output. When it hits a message that's too large, I get a <MAXSTRING> error in the IRIS xDBC log, but no error is set for the ODBC (actually ADO) client.
go to post Jeffrey Drumm · Oct 23, 2020 Hi Robert, Yes, I get the exact same error whether I use %Stream.GlobalCharacter or %Stream.TmpCharacter.
go to post Jeffrey Drumm · Oct 14, 2020 Hi Nora! Long time Something like this should do the trick, assuming the file to be appended to is named "spoo.txt" and the file from which you're appending is named "fleem.txt": Set tOut = ##class(%File).%New() Set tIn = ##class(%File).%New() Set tSC = 1 Set tOut.Name = "spoo.txt" Set tIn.Name = "fleem.txt" Set sc = tOut.Open("WA") Set:$$$ISERR(sc) tSC=$$$ADDSC(tSC,sc) Set sc = tIn.Open() Set:$$$ISERR(sc) tSC=$$$ADDSC(tSC,sc) Quit:$$$ISERR(tSC) tSC While 'tIn.AtEnd { Set sc=tOut.Write(tIn.Read()) Return:$$$ISERR(sc) sc } Do tIn.Close() Do tOut.Close() Return $$$OK
go to post Jeffrey Drumm · Sep 8, 2020 I'm not finding any significant differences in the supporting classes between HS and I4H 2020.1. You might want to open an incident with the WRC to see why you're successful in I4H and not HS. I'm also thinking that you might be better off developing your NACK logic in a BPL, though. Routing Rules aren't really designed for this sort of thing.
go to post Jeffrey Drumm · Sep 3, 2020 I guess that depends on what you want to do if you get an invalid date. Here's a method you can add to the class I referenced above: ClassMethod IsValidBirthDate(pDate As %String) As %Boolean { Try { Set tHDate = $ZDATEH(pDate) } Catch ex { Return 0 } Return 1 } And you'd use it something like this: