Hello IRIS community,
InterSystems Certification is developing a certification exam for InterSystems IRIS Developer professionals, and if you match the exam candidate description given below, we would like you to beta test the exam.
InterSystems ObjectScript is a scripting language to operate with data using any data model of InterSystems Data Platform (Objects, Relational, Key-Value, Document, Globals) and to develop business logic for serverside applications on InterSystems Data Platform.
Hello IRIS community,
InterSystems Certification is developing a certification exam for InterSystems IRIS Developer professionals, and if you match the exam candidate description given below, we would like you to beta test the exam.
I have an IRIS persistent class with a %Stream property whose value is a JSON object. I'd like to use a SQL trigger to pull some value out of the JSON and persist it in another property, for easy querying and indexing. See below for a minimal example:
ClassExtends%PersistentAsinsertintoContentsHowever, the SQL insert fails in the trigger with a JSON parsing message like this:
<THROW>InsertRow+9^PAB.DebugStream.1 *%Exception.SQL -415 -415 InsertRow+9^PAB.DebugStream.1 Error occurring during INSERT in table 'PAB.DebugStream': $ZE=<THROW>%FromJSON+22^%Library.DynamicAbstractObject.1 *%Exception.General Parsing error 3 Line 1 Offset 1
I think I found my solution but I'm trying to understand better why it works. Forgive me as my descriptions here may be scattered but I'm trying to piece the puzzle together.
Scenario: I've found there are times when I make a request using a %Net.HttpRequest object and as I'm debugging and stepping through via the debugger in VSCode, if I try to access an object in the 'variables' menu, sometimes when I click that little expand button it will just spin and never load what's in the object to the viewer.
I was wondering if someone could help me. In the past I have been able to call external Stored Procedures through a SQL Outbound Connection and have them return me the EnsLib.SQL.Snapshot to use within a BPL to extract data.
But this time instead of using a SQL Outbound BO to make the Stored Procedure call, I decided to create a Linked Stored Procedure through the %JDBC_Server to point to the Stored Procedure out on MS SQL.
However, I am struggling to get the code just right to return the Column value from the Linked Stored Procedure.
set##classAfter upgrading from 2024 to 2025 Im not able to compile any class.
I was using ZPM and git-source-control.
Now Im getting
Compilation started on 04190.209I disabled SourceControl in Management portal and nothing happen.
I added extra OBX segments and I need to renumber OBX 4 so they are sequential.
.png)
Say I have an ObjectScript object called Book. It has 2 properties title and author. It extends JSON.%Adaptor, so I can call book.
If you're solving complex problems in ObjectScript, you probably have a lot of code that works with %Status values. If you have interacted with persistent classes from an object perspective (%Save, %OpenId, etc.), you have almost certainly seen them. A %Status provides a wrapper around a localizable error message in InterSystems' platforms. An OK status ($$$OK) is just equal to 1, whereas a bad status ($$$ERROR(errorcode,arguments...)) is represented as a 0 followed by a space followed by a $ListBuild list with structured information about the error. $System.Status (see class reference) provides several handy APIs for working with %Status values; the class reference is helpful and I won't bother duplicating it here. There have been a few other useful articles/questions on the topic as well (see links at the end). My focus in this article will be on a few debugging tricks techniques rather than coding best practices (again, if you're looking for those, see links at the end).
Hello Community,
The subroutine ^routine is not executed while the queue is being processed in WorkMgr. However, it works when defined as a function. Is it mandatory to define subroutine^routine as a function for it to execute properly?
testwqm.mac
set##classThanks!
Hey everyone.
I'm currently looking at a process where we're utilising the Class Ens.StreamContainer, and was looking to do some deletions outside of any purge routines.
Having been burned before, I wanted to make sure that deleting the container also deletes the contents within.
From looking in the class, the %OnDelete ClassMethod appears to be removing an index from a search table and nothing more.
Am I looking in the right place, or is there a extended class for Ens.StreamContainer that does in fact delete the %Stream.Object
contained within the Ens.StreamContainer?
I need to add an extra blank OBX segment after a segment containing text, Total Cost:
I get the OBX segment but it is in incorrect location.
It should be after the line containing Total Cost:
It needs to contain:
OBX|1|TX|2000.02^REASON FOR REQUEST^AS4|
code:
//Do pOutput.SetValueAt(tOBXText_"~~","ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX:5","set") //
If (tOBXText[ "Total Cost:") {
Set tSegmentOBX = ##class(EnsLib.HL7.Segment).%New()
Set tSegmentOBX.SegType = "2.3:OBX"
Set tSC = tSegmentOBX.SetValueAt("OBX", 0, "set")
Set tSC = pOutput.
I'm exploring this right now: given a bunch of types defined as Pydantic models, how can I come up with an equivalent %RegisteredObject/%SerialObject and convert to/from (e.g., to support persistence and match validation as much as possible)?
People who know Python better than I do (e.g., your average undergraduate from this decade): is this a stupid idea or a cool idea? Has anyone else done this before?
To VSCode experts - see the screenshot. When right-click on a method with intentions to proceed to the source code:

I am always confused about what to choose: declaration or definition. What is the difference?
Is there a way to use a property of the type %Persistent class in a %ZEN.Component.page class?
Example:
// Data classClassExtendsClass
The problem is that when using it the described in the example.
The property can be set in a Method like this:
Method DoStuff()
But when reading the property in an other Method the content of it is not set:
Is it generally possible to work like this?
Or have I overlooked a special handling?
Is there a generic process for "walking" the structure of a virtual document - eg an HL7 message (EnsLib.HL7.Message) or an XML document (EnsLib.EDI.XML.Document).
At least we'd want to be able to visit all "nodes" (HL7 fields or sub-fields, XML nodes) in the virtual document and be able to work out/generate the Property Path (so we could call "GetValueAt").
We can just about come up with something generic for HL7, since it only nests down to 4 levels within each segment, though we're using numeric Property Path's at that point rather than symbolic ones (MSH:1.3 etc).
Hello again IRIS community,
We have officially released our InterSystems IRIS Developer Professional certification exam for beta testing. The beta test will be available until April 20, 2025. As a beta tester, you have the chance to earn the certification for free!
Interested in beta testing? See the InterSystems IRIS Developer Professional Beta Test Developer Community post for exam details, recommended preparation, and instructions on how to schedule and take the beta exam.
Thank you!
I was using VSCode to edit a DTL because it seemed easier to copy/paste code from parts of the DTL I was editing. I tried to add <sql> tag and code to call a SELECT statement, but when I compiled I got the following error...
ERROR <Ens>ErrInvalidDTL: Invalid DTL
> ERROR #5490: Error running generator for method 'GetSourceDocType:osuwmc.Epic.MFN.DTL.EpicMFN949002Normalization'
ERROR: Ens.DataTransformDTL.cls(GetSourceDocType) of generated code compiling subclass 'osuwmc.Epic.MFN.DTL.EpicMFN949002Normalization'
> ERROR #5030: An error occurred while compiling class 'osuwmc.Epic.MFN.
This can be done with TRY-CATCH:
#dimAsIf you use ^%ETN, call it from the BACK entry (BACK^%ETN).
Please also take a look at the related article: How to get application errors (^ERRORS) using a command
Perhaps this is an issue that has long been discussed somewhere. I have searched for it but still could not find the solution anywhere. In our environment, we send a container of SDA objects to UCR from HealthConnect. To populate the container we do a SQL query on a source system and then populate the appropriate SDA objects. Sometimes it happens that I want to do an update of a field and I want to empty the corresponding SDA field. In other words, send an empty string. The Alert.toTime field of the object in question is filled with the date '2022-11-29Z13:00:00'.
I have the need to query an external database and write the result set/snapshot to an internal %Persistent [ DdlAllowed ] table that I built. I have built inbound SQL Services before and write them externally to replace SSIS jobs, but how would querying a database via a Service and writing the data to an internal table work?
Can I just take the inbound query structure and write it to the class file of the internal table in a DTL? If so, what would be the Target? Or does this need to be done within a BPL as a Code block?
For programmers new to ObjectScript, one question will inevitably arise: “What is the difference between methods and class methods?” A typical answer would be: “A class method applies to a class, but a method applies to an instance of that class.” While that answer is correct, it lacks important information on how these methods differ, and how they are used in ObjectScript. Many things could be written as either. For instance, suppose we had a class called “User.Person” with a property called “Name”.
A REST API (Representational State Transfer) is an interface that allows different applications to communicate with each other through the HTTP protocol, using standard operations such as GET, POST, PUT, and DELETE. REST APIs are widely used in software development to expose services accessible by other applications, enabling integration between different systems.
However, to ensure that APIs are easy to understand and use, good documentation is essential. This is where OpenAPI comes in.
OpenAPI is a standard for describing RESTful APIs.
My query that I am running on my Custom SQL Inbound Service has columns that are larger than the typical string length. How do I enlarge the SQL Snapshot Column limitations
ClassExtends%PersistentAsAsI want to append items to the list inside a for loop
Example:
set$ListBuildforThe output should be:
mylist = The code snippet written above is not working, looking for correct way to do it.
In the process of trying to get more familiar with Objectscript I decided to try to build a general priority queue since I wasn't able to find an implementation anywhere. My though process for implementing this followed this general path.
My first though to try to make this work quickly was to implement a binary heap and my first attempt at this used a multidimensional to build it. This version was relatively efficient, worked for strings/numbers natively, and worked for objects be letting the user override the comparitor.
Class pqueue.Queue Extends %RegisteredObject
{
Property Data As %Any [ MultiDimensional ];
Property Size As %Integer [ InitialExpression = 0 ];
Property Comparitor As %String [ InitialExpression = "(a,b) return a < b" ];
Method Swap(i As %Integer, j As %Integer) As %Status [ Private ]
{
set temp = ..Data(i)
set ..Data(i) = ..Data(j)
set ..Data(j) = temp
}
Method Comp(x As %Any, y As %Any) As %Boolean [ Private ]
{
return $XECUTE(..Comparitor, x, y)
}
Method PercolateUp(idx As %Integer) [ Private ]
{
while idx > 0 {
set newidx = (idx-1)\2
if ..Comp( ..Data(idx), ..Data(newidx) ) do ..Swap( idx, newidx )
else Quit
set idx = newidx
}
}
Method PercolateDown() [ Private ]
{
set idx = 0
while ((idx+1)*2) < ..Size {
if ..Comp( ..Data(idx*2+2), ..Data(idx*2+1) ) set newidx = idx*2+2
else set newidx = idx*2+1
if ..Comp( ..Data(idx), ..Data(newidx) ) Quit
do ..Swap( idx, newidx )
set idx = newidx
}
if ( (idx*2+1 < ..Size) && ..Comp( ..Data(idx*2+1), ..Data(idx) ) ) do ..Swap( idx, idx*2+1 )
}
Method IsEmpty() As %Boolean
{
return ..Size = 0
}
Method Top() As %Any
{
if ..IsEmpty() return ""
return ..Data(0)
}
Method Put(inp As %Any) As %Status
{
set sts = $$$OK
set ..Data( ..Size ) = inp
do ..PercolateUp( ..Size )
set ..Size = ..Size + 1
return sts
}
Method Get(Output obj As %Any) As %Status
{
set sts = $$$OK
if ..IsEmpty() {
set obj = ""
return $$$ERROR( "Cannot Get() from empty Queue" )
}
set obj = ..Data( 0 )
set ..Size = ..Size - 1
set ..Data( 0 ) = ..Data( ..Size )
do ..PercolateDown()
kill ..Data( ..Size )
return sts
}
Method GenerateComparitor(operator As %String = "<", transform As %String = "") As %Status
{
set ..Comparitor = "(a,b) return a" _ transform _ " " _ operator _ " b" _ transform
return $$$OK
}
}
After getting this working I wanted to try out different internal arrays since I assumed multidimensional arrays must be slower than a simple integer indexed array. So I modified the above code to use
* `Property Data As list Of %Any;` : This works OK but it is about 3-4 times slower than using a multidimensional making it pointless.
* `Property Data As %DynamicArray;` : I assumed this would be relatively fast but proved to be slow to the point of absurdity. When the amount of data stored in the queue is small it is around as fast as the `list of %Any`, but as the data grows the time it takes to make inserts and gets grows linearly which makes it pointless to build a heap on top of.
## Using the Multidimensional Array's Self-sorting
On its face this idea seems pretty simple, use the fact that the multidimensional array is always sorted to grab the lowest cost (highest priority) item. A problem with this are that indexing by an object simply uses the string representation of that object which isn't useful. To handle this a customer `evaluator` function is needed to return the integer or string evaluation of an object which is then sorted, it is then stored as `data( evaluation, obj_str_rep ) = object` which ensures that objects are correctly sorted even when two objects evaluate to the same value.
Class pqueue.SparseQueue Extends %RegisteredObject
{
// Parameter Comp(a,b) As $XECUTE(..Comparitor, a, b);
Property Data As %Any [ MultiDimensional ];
Property Size As %Integer [ InitialExpression = 0 ];
Property Evaluator As %String [ InitialExpression = "(a) return a" ];
Method IsEmpty() As %Boolean
{
return ..Size = 0
}
Method Top() As %Any
{
if ..IsEmpty() return ""
return $Order( ..Data("") )
}
Method Put(inp As %Any) As %Status
{
set sts = $$$OK
set ..Data( $XECUTE(..Evaluator, inp), inp ) = inp
set ..Size = ..Size + 1
return sts
}
Method Get(Output obj As %Any) As %Status
{
set sts = $$$OK
if ..IsEmpty() {
set obj = ""
return $$$ERROR( "Cannot Get() from empty Queue" )
}
set loc = $ORDER( ..Data("") )
set obj = ..Data(loc, $ORDER( ..Data(loc, "")))
set ..Size = ..Size - 1
kill ..Data( loc, obj )
return sts
}
Method GenerateEvaluator(transform As %String = "") As %Status
{
set ..Evaluator = "(a) return a" _ transform
return $$$OK
}
}
This method proved to be by far the fastest. It has some slight disadvantages in that it can be harder to write an evaluator than a comparitor and, in the form given above, it cannot hold the same object at the same value twice (this is a rare case but could theoretically be a problem or a benefit).
## Speed Test
To test these out I wrote a simple script that generates a large randomized weighted directed graph and runs [Dijkstra's shortest path algorithm](https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/) using a given queue object. Using a graph with `150000` vertices where each has `10` neighbors, the output is printed below. Here while the algorithm is running an update is printed every `10000` edges checked, where the time since the last 10 thousand and size of the priority queue is printed, with some final stats at the end. The order they are run in is
* Self-sorting Multidimensional
* Heap Multidimensional
* Heap Dynamic Array
* Heap List of Object
> Generated Random Graph
Hello, dear colleagues.
I need to connect to a remote JavaGateway from an Ensemble service.
I am trying to use the EnsLib.JavaGateway.Service with a remote host where the JVM is running.
I can successfully ping the remote Java Gateway from EnsLib.JavaGateway.Service, and Ensemble reports that the service status is OK.
There are no network issues, and all necessary ports are accessible.
My requests work without any problems when I specify localhost in EnsLib.JavaGateway.Service.
Hi colleagues!
Yet another time I figured that there is no super-simple way to display error from %Status variable, but I need it relatively often in a terminal.
Yes, I know about $$$ Macro, but they are not superhelpful in a terminal.
My usual behavior is to try to remember by heart or copy from somewhere the formula:
USER>w $System.Status.DisplayError(st)
I have created a class file that I want to execute daily to gather Metrics (Message Header, Space Available, etc..) and write the data into a Cache table. Now that I have written the class I want to add it to the Task Scheduler within Ensemble to run every morning. How do I go about getting the class file created as a Task within the Task Scheduler? The Documentation isn't as clear cut for creating custom tasks as one would expect.
I already mentioned in a Previous post I am trying to build a list from a repeatable field within a HL7 message. I figured out how to build the list by using a context list string variable within the Business Process (BPL) and doing a
dowhen I am looping through the field. I want to do it one step farther though... I want to search the list to see if the value exists before I do the insert. I only want to insert if the value is different than what is in the list already.
IF$LF##classI tried using $LF or $LISTFIND, but I keep getting the same error...
I have a repeatable field within HL7 that I want to create a List from. Do I have to initialize the List by using $LB, or can I just use $LI to keep adding on to the end of the list as it is looping through the field?