I added extra OBX segments and I need to renumber OBX 4 so they are sequential.
.png)
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.
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?
I was thinking about how to create a new parameter in a method, similar to Output or ByRef...
What documentation can I read to learn more about this?
I want to create a parameter customized.
I have been trying to get to grips with the new dot Net Gateway used in IRIS as the import of the DLL to construct proxy classes is no longer supported in IRIS I have a third party DLL that when I try to instantiate throws an error complaining about the class not instantiated as it does not support parameterless constructor .I am using this new
set$systemdoHi - Recently I have been investigating an annoying situation whilst editing ObjectScript classes or routines in VSCode.
What was happening to me was, as I was typing in lines of code into my class (for example, adding a new Method, or changing the Class signature, or a block of code), this would quickly get syntax checked, re-formatted, and compiled - inevitably, (since I would be mid-way through my typing), this would generate compilation errors.
.png)
The question is straight forward. Is there a way to do that? I've searched docs but no result
Hello, I try to develop a REST interface where I need to interact with legacy MUMPS routines. How can I pass in input to a Read without modifying the legacy code?
I think in linux I can execute command < inputfile to read from file, but how does it work in ObjectScript?