If you want to discover IRIS for Health with some samples, the best way is to install ZPM (community package manager).
More info here : https://community.intersystems.com/post/install-zpm-one-line

Then, you have access of almost all application in OpenExchange.

Let's have an example with csvgen-ui :
https://openexchange.intersystems.com/package/csvgen-ui

zpm "install csvgen-ui"

In OpenExchange you will find may example about rest API, web app, and so.

For now, it's not possible in pure python, because the select namespace is specified by the environment variable IRISNAMESPACE, and environment variable can't be change in the parent process, I have tried by reloading iris module with no success.

To achieve that, for now, as Robert says, you have to create an helper method in objectscript ... :(

Class Embedded.Utils
{

ClassMethod GetNameSpace() As %Status
{

    Return $namespace
}

ClassMethod SetNameSpace(pNameSpace) As %Status
{
    zn pNameSpace
    Return $namespace
}

}

Python :

import iris

print(iris.cls("Embedded.Utils").GetNameSpace())
try:
    print(iris.cls("Security.Users").Exists("SuperUser"))
except RuntimeError:
    print("Wrong NameSpace")

print(iris.cls("Embedded.Utils").SetNameSpace("%SYS"))
try:
    print(iris.cls("Security.Users").Exists("SuperUser"))
except RuntimeError:
    print("Wrong NameSpace")

If you don't want to create new data on the FHIR protocol, you must use the PUT verb with an ID instead of POST.

PUT creates the resource with the specified ID if the ID does not exist, otherwise it replaces the pre-existing data.

POST always creates a new resource with a new ID, that's why the ID is not mandatory when POSTing.

For automatic transformations from HL7/CDA to FHIR, there is the possibility to define the ID for some resources and thus to avoid duplication.

Below is an example of code to transform an HL7 payload to SDA by specifying the ID of the patient in order to avoid duplicating this resource, after that you can transform this SDA to FHIR with no duplication of patient.

/// This is a custom business process that transforms an HL7 message to SDA format (an internal healthcare data format for InterSystems IRIS for Health).
/// To use this class, add a business process with this class to the production and configure the target. The default target will send the SDA to a component
/// that converts the data to FHIR.
/// 
Class FHIRDemo.HL7TransformProcess Extends Ens.BusinessProcess [ ClassType = persistent ]
{

Parameter SETTINGS = "TargetConfigName:Basic:selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},TransformFile:Basic";

Property TargetConfigName As Ens.DataType.ConfigName [ InitialExpression = "HS.FHIR.DTL.Util.HC.SDA3.FHIR.Process" ];

/// Transforms an HL7 message to SDA, an internal healthcare format for InterSystems IRIS for Health.
Method OnRequest(pRequest As EnsLib.HL7.Message, Output pResponse As Ens.Response) As %Status
{
    set tSC = $$$OK
    try {
        $$$ThrowOnError(##class(HS.Gateway.HL7.HL7ToSDA3).GetSDA(pRequest,.tSDA))
        $$$LOGINFO(tSDA.Read())

        Set tQuickStream = ##class(HS.SDA3.QuickStream).%New()
        $$$ThrowOnError(tQuickStream.CopyFrom(tSDA))

        Set tResponse = ##class(HS.Message.XMLMessage).%New()
        Do tResponse.AdditionalInfo.SetAt(tQuickStream.%Id(),"QuickStreamId")
        Do tResponse.AdditionalInfo.SetAt($P(pRequest.GetValueAt("PID:3:1"),"^"),"PatientResourceId")

        Set tSC = ..SendRequestSync(..TargetConfigName,tResponse,.pResponse)
    } catch ex {
        set tSC = ex.AsStatus()
    }
    quit tSC
}

Storage Default
{
<Data name="HL7TransformProcessDefaultData">
<Subscript>"HL7TransformProcess"</Subscript>
<Value name="1">
<Value>TargetConfigName</Value>
</Value>
</Data>
<DefaultData>HL7TransformProcessDefaultData</DefaultData>
<Type>%Storage.Persistent</Type>
}

}

The difference between a stored procedure and SQL inserts is that the business logic remains on the application side and not on the database side to keep the principles (storage/logic/representation) separate.

Nevertheless, the problem doesn't seem to be at the SQL level but rather at the BPL level, so maybe it's due to the conversion of XML to object?
If it is the case, use different technique to parse the XML, like the SAX Parser which avoids to mount all the XML document in memory.
https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

Hi Eric,

First you are using &sql who is for internal SQL use : doc

If you want to do an external query to a remote database you can do it with Ensemble :

Include EnsSQLTypes
 
Class Batch.Example.SqlInsertOperation Extends Ens.BusinessOperation
{
 
Parameter ADAPTER = "EnsLib.SQL.OutboundAdapter";
 
Property Adapter As EnsLib.SQL.OutboundAdapter;
 
Parameter INVOCATION = "Queue";
 
Method SetResultSetView(pRequest As Ens.StringRequest, Output pResponse As Ens.StringResponse) As %Status
{
    set tStatus = $$$OK
    
    try{
                    
        set pResponse = ##class(Ens.StringResponse).%New()
    
        set SqlInsertView = "INSERT into ODS_Products (ID,ProductName,Date_Alimentation) values (?,?,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'))"
 
        set param(1) = 1
        set param(1,"SqlType")=$$$SqlInteger
 
        set param(2) = ##class(%PopulateUtils).Name()
        set param(2,"SqlType")=$$$SqlVarchar
            
        set param(3) = $ZDATETIME($NOW(),3)
        set param(3,"SqlType")=$$$SqlVarchar
 
        set param = 3
            
        $$$ThrowOnError(..Adapter.ExecuteUpdateBatchParamArray(.nrows,SqlInsertView,.param))
                                
    }
    catch exp
    {
        Set tStatus = exp.AsStatus()
    }
 
    Quit tStatus
}
 
XData MessageMap
{
<MapItems>
    <MapItem MessageType="Ens.StringRequest">
        <Method>SetResultSetView</Method>
    </MapItem>
</MapItems>
}
 
}

Or with the %SQLGatewayConnection :

    //Create new Gateway connection object
   set gc=##class(%SQLGatewayConnection).%New()
   If gc=$$$NULLOREF quit $$$ERROR($$$GeneralError,"Cannot create %SQLGatewayConnection.")
       
   //Make connection to target DSN
   s pDSN="Samples"
   s usr="_system"
   s pwd="SYS"
   set sc=gc.Connect(pDSN,usr,pwd,0)
   If $$$ISERR(sc) quit sc
   if gc.ConnectionHandle="" quit $$$ERROR($$$GeneralError,"Connection failed")
       
   set sc=gc.AllocateStatement(.hstmt)
   if $$$ISERR(sc) quit sc
       
   //Prepare statement for execution
   set pQuery= "select * from Sample.Person"
   set sc=gc.Prepare(hstmt,pQuery)
   if $$$ISERR(sc) quit sc
     //Execute statement
   set sc=gc.Execute(hstmt)
   if $$$ISERR(sc) quit sc

It depends on what you are looking for.

To create applications to expose data on IRIS with custom APIs and make custom applications, you can use IRIS Studio and/or VsCode with the IRIS extension.

For database administration, you can use the management portal.

For 100% SQL administration, I recommend DbBeaver.

Hi Xiong,

To convert FHIR R4 to SDA you have to use this helper class :

HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process

This class take in input a message of this kind : HS.FHIRServer.Interop.Request or HS.Message.FHIR.Request.

So if you want to convert an json FHIR file to SDA, you have to read the file from a business service cast you file to one of this message and send it to the helper class.

Here is and Business service example of reading fhir json files :

Class BS.FHIRFileService Extends Ens.BusinessService
{

Parameter ADAPTER = "EnsLib.File.InboundAdapter";

Property TargetConfigNames As %String(MAXLEN = 1000) [ InitialExpression = "BusinessProcess" ];

Parameter SETTINGS = "TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}";

Method OnProcessInput(pDocIn As %RegisteredObject, Output pDocOut As %RegisteredObject) As %Status
{
    set status = $$$OK

    try {

        set pInput = ##class(HS.FHIRServer.Interop.Request).%New()
        set tQuickStream = ##class(HS.SDA3.QuickStream).%New()
        do tQuickStream.CopyFrom(pDocIn)
        set pInput.QuickStreamId= tQuickStream.Id


        for iTarget=1:1:$L(..TargetConfigNames, ",") {
            set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")  Continue:""=tOneTarget
            $$$ThrowOnError(..SendRequestSync(tOneTarget,pInput,.pDocOut))
        }
    } catch ex {
        set status = ex.AsStatus()
    }

    Quit status
}

}

You can find more information from this documentation :

https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.c...

Hi Lucas,

A simple solution to you question can be this :

Property numDossiersMER As list Of %Integer(SQLPROJECTION = "table/column", STORAGEDEFAULT = "array");

Index numDossiersMERIdx On numDossiersMER(ELEMENTS);

With those parameters you can achieve :

  • 'As list Of %Integer' allows you to use the Insert() in ObjectScript and 'for some %element' in SQL command
  • 'SQLPROJECTION = "table/column"' allows you to display the table as a column (note, the column does not appear in a select * it must be specified : select numDossierMER, numDossiersMER from User_TestList_Data.Titre )
  • 'STORAGEDEFAULT = "array"' allows a separate table for the normalized representation
  • 'Index numDossiersMERIdx On numDossiersMER(ELEMENTS);' bring the ability to use index on values with this SQL query :
select numDossierMER, numDossiersMER from User_TestList_Data.Titre
where
for some %element(numDossiersMER) (%Value in (345))

Hi Cindy,

To deploy your services, routes and plugins to another environment you can use CI/CD with postman (newman)

Some examples here :

Another possibility is to use deck (decK helps manage Kong’s configuration in a declarative fashion) from kong

I haven't tried this one, I can't give you feedback on it.

If I understand correctly, you want to replace an HTTP Header basic auth with a bearer token.
If the bearer token is static, you can implement a solution like this:
- https://github.com/grongierisc/iam-training/tree/training#6-third-add-ou...

If it is dynamic, I think you will have to develop your own plug-in:
- https://github.com/grongierisc/iam-training/tree/training#11-plugins

A good base to start working on could be this plugin:
- https://github.com/grongierisc/kong-plugin-jwt-crafter

Hi,

What you can do is a snapshot of this ResultSet.

Then use the global of this snapshot for another Operation :

Get snapshot global :

Method OnGetSnapshot(pRequest As Ens.Request, Output pResponse As Ens.StringResponse) As %Status
{
    set tStatus = $$$OK

    try{

        set pResponse = ##class(Ens.StringResponse).%New()

        set tQuery = "SELECT *  FROM [sqlserver].[dbo].[whatever] "

        //$$$TRACE(tQuery)      
        Set pSnap = ##class(EnsLib.SQL.Snapshot).%New()

        //size of snapshot
        // -1 = Max
        set pSnap.MaxRowsToGet = -1

        $$$ThrowOnError(..Adapter.ExecuteQueryBatch(pSnap,tQuery,1000))

        $$$ThrowOnError(pSnap.%Save())


        set pResponse.StringValue = pSnap.%GblRef   

    }
    catch exp
        {
            Set tStatus = exp.AsStatus()
        }
    Quit tStatus
}

Use snapshot global :

Method UseSnapshot(pRequest As Ens.StringRequest, Output pResponse As Ens.Response) As %Status
{

    set status = $$$OK

    try {
        set pResponse = ##class(Ens.Response).%New()

        set nRow = 0
        set tSequence = 0

        //Get SnapShot
        Set tSnap = ##class(EnsLib.SQL.Snapshot).%New()
        set tSnap.%GblRef = pRequest.StringValue // use of global SnapShot
        set tSnap.%CurrentRow = 0
        set tSnap.FirstRow = 1
        set tSnap.MaxRowsToGet = -1

        $$$TRACE("MaxRowsToGet :  "_tSnap.RowCountGet())

                while tSnap.Next() {
                    try {
                            set nRow = nRow + 1
                            set tSequence = tSequence + 1

                            set i = 0

                            set i = i + 1
                            set tParam(i) = tSnap.Get("Col1")


                            set i = i + 1
                            set tParam(i) = tSnap.Get("Col2")


                            set i = i + 1
                            set tParam(i) = tSnap.Get("Col3")


                            set i = i + 1
                            set tParam(i) = tSnap.Get("ColX")

                            set tParam = i

                            set tQuery = "UPDATE Whatever  "_
                                        "SET   "_
                                        "Col1 = ?  "_
                                        ",Col2 = ?  "_
                                        ",Col3 = ?  "_
                                        " WHERE ColX = ?  " 


                            $$$ThrowOnError(..Adapter.ExecuteUpdateParmArray(.tResult,tQuery,.tParam))

                        } catch exSnap {
                            // Update exeption
                        }

        }


    } catch ex {
        set status = ex.AsStatus()
    }
    return status
}

Furthermore, If you have big table to query/insert in JDBC consider this ZPM module :
https://github.com/grongierisc/BatchSqlOutboundAdapter