Rechercher

Discussion (0)2
Connectez-vous ou inscrivez-vous pour continuer
Annonce
· Oct 6

Vuelve a ver el webinar "De los datos al conocimiento: Sacando provecho a la Información Clínica con InterSystems e IA"

Hola! 

¿Qué tal se presenta la semana? 🚀 El jueves tuvimos un webinar fantástico con @Rodrigo Barahona. A parte de unas reflexiones sobre el sector sanitario y la posibilidades de la IA, nos mostró su aplicación práctica a través de un agente creado con inteligencia artificial. También, @David Reche nos adelantó que en unos pocos meses volveremos a vernos en Madrid ¡lo estamos deseando! 😶 No queremos revelar demasiado aún... pero estad atentos  

 

Hubo varias dudas, comentarios y en general ¡os gustó mucho! Normal, Rodrigo es un maestro de esto. Agradecemos su participación, humor y dinamismo en la explicación. 

➡ ¿Qué? ¿Os lo perdisteis? Tranquilos... Podéis volver a verlo en la plataforma donde se emitió, a máxima calidad, o en nuestro canal de YouTube.

¡Buena semana a todos! 🙌

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Résumé
· Oct 6
Article
· Oct 5 3m de lecture

GORM Meets InterSystems IRIS: Introducing gorm-iris

If you thought native Go support for IRIS was exciting, wait until you see what happens when GORM enters the mix.


Just recently, we welcomed native GoLang support for InterSystems IRIS with the release of go-irisnative. That was just the beginning. Now, we’re kicking things up a notch with the launch of gorm-iris — a GORM driver designed to bring the power of Object Relational Mapping (ORM) to your IRIS + Go stack.

Why GORM?

GORM is one of the most popular ORM libraries in the Go ecosystem. It makes it easy to interact with databases using Go structs instead of writing raw SQL. With features like auto migrations, associations, and query building, GORM simplifies backend development significantly.

So naturally, the next step after enabling Go to talk natively with IRIS was to make GORM work seamlessly with it. That’s exactly what gorm-iris does.


What Is gorm-iris?

gorm-iris is a custom GORM driver for InterSystems IRIS built on top of go-irisnative. It acts as a bridge, allowing developers to use the familiar GORM syntax and patterns to interact with an IRIS database — while all the heavy lifting behind the scenes is handled via native IRIS calls.

Think of it as the best of both worlds:

  • Native performance and data access via go-irisnative
  • Developer-friendly ORM features via GORM

Key Features

Here’s what you can expect from gorm-iris:

✅ Seamless integration between GORM and IRIS
✅ Use of native Go structs to model your IRIS data
✅ Basic CRUD operations out of the box
✅ Customizable behavior through Go interfaces

And of course, it’s all open source.


Quick Start Example

Want to get started? Here’s a minimal setup to show how things work:

package main

import (
	"fmt"

	iris "github.com/caretdev/gorm-iris"
	"gorm.io/gorm"
)

type User struct {
  ID    int
  Name  string
  Email string
}

func main() {
  dsn := "iris://_SYSTEM:SYS@localhost:1972/USER"
  db, err := gorm.Open(iris.Open(dsn), &gorm.Config{})
  if err != nil {
    panic("failed to connect to IRIS")
  }

	// Auto-migrate schema
  db.AutoMigrate(&User{})

  // Create
  db.Create(&[]User{
		{Name: "Johh", Email: "john@example.com"},
		{Name: "Johh1", Email: "john1@example.com"},
		{Name: "John2", Email: "john2@example.com"},
	})

  // Read
  var user User
  db.First(&user, "email = ?", "john1@example.com")
	fmt.Printf("Found: ID: %d; Name: %s\n", user.ID, user.Name)
}

Yes — that’s really it.


What’s Under the Hood?

The gorm-iris driver translates GORM operations into native calls through go-irisnative. This means you still get the speed and efficiency of direct IRIS access, but with a higher-level abstraction for everyday use cases.

It's ideal for developers who:

  • Want to build Go applications with IRIS as the backend
  • Prefer ORM-style development over direct query construction
  • Are looking to prototype or build full-scale apps with clean, readable Go code

Where It’s Headed

This is just version 0.1.1 — we’re actively working on improving feature coverage, performance tuning, and handling more complex GORM features.

If you’re using it and have feedback or feature requests — issues and PRs are welcome!

👉 Check out the repo: https://github.com/caretdev/gorm-iris


Final Thoughts

With go-irisnative, we opened the door for GoLang developers to talk to InterSystems IRIS. With gorm-iris, we’re inviting them to stay for dinner.

This library is all about making IRIS feel like home in your Go development workflow. It’s clean, expressive, and leverages the tools Go developers already love.

So go ahead — try it out, build something cool, and let us know what you think.

4 Comments
Discussion (4)2
Connectez-vous ou inscrivez-vous pour continuer
Article
· Oct 5 12m de lecture

Implementando um projeto FHIR - ÚNICAS

Boas-vindas, estimados membros da Comunidade!


Neste artigo, apresentaremos um exemplo de um projeto que implementa uma solução baseada em FHIR. Este projeto se baseará no projeto nacional (espanhol), conhecido como ÚNICA

O que é ÚNICAS?

Em suas próprias palavras:

Um projeto cujo objetivo é criar um ecossistema de colaborações para melhorar a atenção à saúde de pacientes pediátricos com Doenças Raras Complexas (DRCs). Este projeto está sendo implementado por meio da rede dentro do Sistema Nacional de Saúde (SNS) para melhorar o diagnóstico e o cuidado de pacientes com doenças raras.

Características Técnicas de ÚNICAS

Em resumo, a arquitetura projetada para este projeto é composta por:

Nó Central 

O objetivo é permitir o compartilhamento de dados clínicos de pacientes afetados por essas doenças raras. Esses dados clínicos serão encontrados nos nós regionais.

Nó Autônomo

Cada comunidade autônoma terá seu próprio nó (ou mais de um, dependendo do volume de dados). Esses nós serão responsáveis por obter as informações clínicas dos pacientes das diversas fontes de dados disponíveis e fornecê-las ao nó central.

Modelo de Interoperabilidade

O modelo de interoperabilidade escolhido para este caso é o FHIR (R5), que fornece um conjunto de recursos padronizados para a troca de dados clínicos.

Cada comunidade autônoma é livre para escolher como implementar este modelo, seja implantando um repositório FHIR no qual carregar os dados clínicos para posterior compartilhamento, ou utilizando uma fachada FHIR (FHIR facade) que transformará a informação clínica em recursos FHIR quando um pedido de partilha for processado.

Recursos FHIR em ÚNICAS

Visto que este projeto tem objetivos muito específicos, ele definiu um conjunto de recursos FHIR a serem utilizados:

Mensajería estandardizada en ÚNICAS en FHIR

Enquanto para relatórios:

Mensajería existente de informes en HL7 CDA

Implementando ÚNICAS com Health Connect

Após revisar os aspectos técnicos do projeto ÚNICAS, é hora de examinar como ele se encaixa com o Health Connect e quais possíveis adaptações seriam necessárias para facilitar a implementação.

Modelo FHIR R5 

Para implementar o modelo de interoperabilidade em FHIR R5, o cliente tem duas opções:

  • FHIR Facade.
  • FHIR Repository.

FHIR Facade

O FHIR facade implantará os componentes de negócio necessários para uma API REST dentro de nossa instância do Health Connect que nos permitirá receber chamadas de sistemas de terceiros com os vários recursos FHIR. Com esta opção, podemos extrair os recursos no formato %DynamicObject e transformá-los em nosso formato específico de dados clínicos.

As consultas recebidas contra a fachada FHIR devem ser construídas manualmente, uma vez que não há um repositório FHIR vinculado abaixo, então devemos implementar cada recurso nós mesmos. Para o ÚNICAS, esta não seria a melhor opção, visto que os requisitos em nível de consulta nos exigiriam implementar a funcionalidade que já temos no repositório FHIR.

FHIR Repository

O Health Connect permite (consultar condições de licença) implantar um repositório FHIR R5 de uma forma simples a partir de um namespace com a opção de interoperabilidade habilitada a partir do menu Health -> FHIR Server Management

Ao clicar na opção de adicionar novo servidor, será mostrada uma tela com as diversas opções de configuração:

Como você pode ver, temos a opção de importar Pacotes (Packages) em nossa configuração. Isso será útil para importar os Conjuntos de Valores (ValueSets) e Perfis (Profiles) definidos pela ÚNICAS IG. Podemos fazer essa importação a qualquer momento rodando o seguinte comando:

// Rutas a modificar por el usuario
do ##class(HS.FHIRMeta.Load.NpmLoader).importPackages($lb("/iris-shared/packages/hl7.terminology.r5-6.5.0/package", "/iris-shared/packages/hl7.fhir.uv.extensions.r5-5.2.0/package","/iris-shared/packages/full-ig/package"))

 

No ÚNICAS IG, existe uma pequena discrepância acerca das dependências definidas para o full-IG (IG completo). As seguintes dependências estão listadas no pacote:

"dependencies" : {
    "hl7.terminology.r5" : "6.5.0",
    "hl7.fhir.uv.extensions.r5" : "5.2.0",
    "hl7.fhir.uv.ips" : "1.1.0"
  }

A versão 1.1.0 de hl7.fhir.uv.ips é suportada apenas no FHIR R4, e tentar importá-la para um servidor R5 resultará em um erro, pois também possui várias dependências R4 que causarão incompatibilidades. Para nossa implementação, vamos removê-la da lista de dependências e importar apenas aquelas relacionadas ao R5... e que Deus cuide disso.

Adaptando o repositório FHIR ao ÚNICAS

Uma das características mais interessantes do repositório FHIR no Health Connect é a capacidade de usar o motor de interoperabilidade para capturar e transformar cada interação com o repositório FHIR para adaptá-la às nossas necessidades. Para fazer isso, só precisamos incluir o business service HS.FHIRServer.Interop.Service e a business operation HS.FHIRServer.Interop.Operation do ambiente de produção vinculado ao namespace onde implantamos o repositório FHIR. Esta será a aparência do ambiente de produção para o namespace que contém nosso repositório:

Com estes componentes em nossa produção, podemos especificar em nossa configuração de repositório que todas as chamadas usando a API REST passarão por este serviço:

Perfeito! Nosso repositório FHIR R5 está pronto para começar a implantar nosso nó autônomo ÚNICAS. Vamos ver um exemplo de como podemos aproveitar as capacidades de interoperabilidade para transformar mensagens HL7 v2.5.1 em recursos FHIR R5.

Convertendo HL7 para FHIR

Um caso típico a ser resolvido para qualquer implementador de repositório FHIR é a conversão de mensagens HL7 (v2 ou v3) em recursos FHIR. Esta conversão não é nada direta por duas razões:

  1. Não há equivalência direta entre recursos FHIR e eventos HL7. Enquanto o FHIR é usado para a troca de conceitos clínicos na forma de recursos, o HL7 representa eventos, que contêm informações que podem ou não ser equivalentes a um conceito clínico.
  2. A implementação de mensagens HL7 v2 ou v3 está longe de ser uniforme. Cada organização adapta as mensagens às suas necessidades, e o mesmo evento em diferentes organizações pode conter dados completamente diferentes.

Que ferramentas o Health Connect nos fornece?

O Health Connect possui uma série de transformações predefinidas que utilizam o modelo de dados SDA3 como gateway, muito semelhante aos CDAs. Estas transformações estão atualmente desenvolvidas para a versão R4, mas não é muito complicado adaptá-las para transformar recursos R4 gerados na versão R5.

Portanto, os passos a seguir serão HL7 v2.5.1 -> SDA3 -> FHIR R4 -> FHIR R5. 

Transformação HL7 v2.5.1 -> SDA3

Para este primeiro passo, usaremos a classe HS.Gateway.HL7.HL7ToSDA3 e seu método GetSDA (você pode ver um exemplo na documentação aqui ). Esta classe transformará nossa mensagem HL7 em um bom SDA.

Transformação SDA3 -> FHIR R4

Uma vez obtido nosso SDA com as informações clínicas extraídas da mensagem HL7, usaremos a classe HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR e seu método TransformStream, que transformará o SDA3 em formato Stream obtido na etapa anterior em um %DynamicObject com um recurso FHIR R4 Bundle (mais informações
 aqui ).

Abaixo você pode ver um exemplo do código necessário para transformar uma mensagem HL7 em um bundle FHIR R4 no formato %DynamicObject:

 do ##class(HS.Gateway.HL7.HL7ToSDA3).GetSDA(request, .SDAMessageTemp)
 set SDAToFHIR = #class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformStream(SDAMessageTemp,"HS.SDA3.Container","R4")

E quanto ao meu FHIR R5?

Até agora vimos que o Health Connect permite uma conversão muito simples de HL7 para FHIR R4 (a conversão pode não se adequar 100% às suas necessidades, mas será mais fácil editar um recurso do que construí-lo do zero), ótimo, mas... ONDE ESTÁ O MEU RECURSO R5?

Não se preocupe, porque... a Comunidade de Desenvolvedores está vindo ao resgate!

Você verá que anexado a este artigo está um aplicativo OpenExchange associado. Este aplicativo contém o código necessário para transformar recursos FHIR R4 nos recursos R5 usados no projeto ÚNICAS. Para instalar este código, você pode usar o IPM:

set version="latest" s r=##class(%Net.HttpRequest).%New(),r.Server="pm.community.intersystems.com",r.SSLConfiguration="ISC.FeatureTracker.SSL.Config" d r.Get("/packages/zpm/"_version_"/installer"),$system.OBJ.LoadStream(r.HttpResponse.Data,"c")
zpm "enable -community"
zpm "install spain-unicas"

Uma vez instalado, você verá um pacote chamado Spain aparecer no namespace onde você o instalou. O que você pode encontrar neste pacote?

  • Spain.BPBPL com exemplo de transformação HL7 -> SDA -> FHIR R4 -> FHIR R5.
  • Spain.FHIR.DTL.vR4Transformações de R4 para R5 dos recursos usados pelo ÚNICAS.
  • Spain.FHIR.DTL.vR5: Classes ObjectScript que modelam recursos ÚNICAS R5.
  • Spain.Gateway.HL7: Pequena correção para transformação HL7 para SDA3.

Transformando R4 para R5

Com as ferramentas disponíveis no pacote Spain, agora podemos transformar nossos recursos R4 em recursos R5. Para fazer isso, usaremos as transformações para cada tipo de recurso da seguinte forma:

set obj = ##class(HS.FHIR.DTL.vR4.Model.Resource.Bundle).FromJSONHelper(context.FHIRMessage, "vR4")

for i=1:1:obj.entry.Count() {
    set item = obj.entry.GetAt(i)
    if ($CLASSNAME(item.resource) = "HS.FHIR.DTL.vR4.Model.Resource.Immunization")
    {
      Set status = ##class(Spain.FHIR.DTL.vR4.vR5.Immunization).Transform(item.resource, .immunizationR5)            
      Set item.resource = immunizationR5
      Do obj.entry.SetAt(item, i)            
    }
    elseif ($CLASSNAME(item.resource) = "HS.FHIR.DTL.vR4.Model.Resource.AllergyIntolerance")
    {
      Set status = ##class(Spain.FHIR.DTL.vR4.vR5.Allergy.AllergyIntolerance).Transform(item.resource, .allergyIntoleranceR5)            
      Set item.resource = allergyIntoleranceR5
      Do obj.entry.SetAt(item, i)            
    }
    ...
 }

Lembre-se de que tínhamos um %DynamicObject com um bundle de recursos R4, o primeiro passo que daremos será mapear dito %DynamicObject para uma classe HS.FHIR.DTL.vR4.Model.Resource.Bundle usando o método FromJSONHelper, o objetivo desta transformação é poder posteriormente reconhecer o tipo de recurso presente no bundle pelo nome de sua classe.

Com o bundle mapeado para sua classe ObjectScript, simplesmente percorreremos cada entrada, identificando o recurso. Se corresponder a um dos recursos utilizados no ÚNICAS, procedemos a invocar uma DTL específica para realizar a transformação de R4 para R5.

Com o recurso já transformado, o reintroduzimos no Bundle substituindo o recurso R4 anterior.

Finalmente, só teremos que transformar o Bundle em um Stream (neste caso chamado QuickStream) e enviá-lo dentro de uma mensagem do tipo HS.FHIRServer.Interop.Request para a business operation HS.FHIRServer.Interop.Operation

 Set context.FHIRRequest.Request.RequestMethod = "POST"
 Set context.FHIRRequest.Request.RequestPath = ""
 Set context.FHIRRequest.Request.RequestFormatCode= "JSON"
 Set context.FHIRRequest.Request.SessionApplication = "/csp/healthshare/fhirserver/fhir/r5"
 Set context.FHIRRequest.Request.IsRecursive = 0
 set qs=##class(HS.SDA3.QuickStream).%New()
 set context.FHIRRequest.QuickStreamId = qs.%Id()
 do qs.CopyFrom(context.FHIRStream)
 

Aqui teríamos a chamada:

Bem, é isso! Agora temos nosso pequeno exemplo de conversões de HL7 para R5 e seu registro em nosso repositório Health Connect. Vejamos em ação.

Exemplo de transformação de HL7 para R5

Vamos começar com uma mensagem HL7 v2.5.1

MSH|^~\&|CLINIC_SYS|HOSPITAL123|EHR_SYSTEM|REGION1|20250826143000||ADT^A08^ADT_A01|MSG00002|P|2.5.1
EVN|A08|20250826143000
PID|1||123456^^^HOSPITAL123^MR||GOMEZ^MARIA^LUISA||19750523|F|||AVDA UNIVERSIDAD 45^^MADRID^^28040^ESP||(555)1234567|||S||12345678Z^^^ESP^NI
AL1|1|DA|70618^Penicillin^RXNORM|SV|Rash|20200115|Clinician noted severe rash after administration
AL1|2|FA|256349002^Peanut protein^SCT|SE|Anaphylaxis|20181201|Reported after accidental exposure
AL1|3|MA|300916003^Latex^SCT|MO|Skin irritation|20191010|Observed during procedure with latex gloves

Aqui temos um simples ADT_A08 com informações relacionadas a um paciente e suas alergias, como implementadores diligentes que somos, sabemos que esta mensagem conterá (pelo menos) um recurso do tipo Patient (Paciente) e 3 do tipo AllergyIntolerance (Alergia e Intolerância).

Introduzimos um serviço de negócio em nossa produção para capturar arquivos HL7 e enviá-los ao nosso BPL:

Uma vez capturado, transformamos nosso HL7 para R4 através de SDA, vamos dar uma olhada no recurso AllergyIntolerance gerado em R4:

{
                                                              
	"request": {
		"method": "POST",
		"url": "AllergyIntolerance"
	},
	"fullUrl": "urn:uuid:4b9f7b2e-9dd0-11f0-870e-c6b593068383",
	"resource": {
		"resourceType": "AllergyIntolerance",
		"category": [
			"food"
		],
		"clinicalStatus": {
			"coding": [
				{
					"code": "active",
					"system": "http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical"
				}
			]
		},
		"code": {
			"coding": [
				{
					"code": "256349002",
					"display": "Peanut protein",
					"system": "http://snomed.info/sct"
				}
			]
		},
		"extension": [
			{
				"url": "http://intersystems.com/fhir/extn/sda3/lib/allergy-discovery-time",
				"valueDateTime": "2018-12-01T00:00:00+00:00"
			},
			{
				"url": "http://intersystems.com/fhir/extn/sda3/lib/allergy-entered-at",
				"valueReference": {
					"reference": "urn:uuid:4b9e97f6-9dd0-11f0-870e-c6b593068383"
				}
			}
		],
		"onsetDateTime": "2018-12-01T00:00:00+00:00",
		"patient": {
			"reference": "urn:uuid:4b9edb58-9dd0-11f0-870e-c6b593068383"
		},
		"reaction": [
			{
				"extension": [
					{
						"url": "http://intersystems.com/fhir/extn/sda3/lib/allergy-severity",
						"valueCodeableConcept": {
							"coding": [
								{
									"code": "SE"
								}
							]
						}
					}
				],
				"manifestation": [
					{
			
						"coding": [
							{
								"code": "Anaphylaxis"
							}
						]
 
					}
				]
			}
		]
	}
}

E agora o mesmo recurso, mas adaptado à versão R5:

{
	"fullUrl": "urn:uuid:4b9f7b2e-9dd0-11f0-870e-c6b593068383",
	"request": {
		"method": "POST",
		"url": "AllergyIntolerance"
	},
													  
	"resource": {
		"resourceType": "AllergyIntolerance",
		"category": [
			"food"
		],
		"clinicalStatus": {
			"coding": [
				{
					"code": "active",
					"system": "http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical"
				}
			]
		},
		"code": {
			"coding": [
				{
					"code": "256349002",
					"display": "Peanut protein",
					"system": "http://snomed.info/sct"
				}
			]
		},
		"extension": [
			{
				"url": "http://intersystems.com/fhir/extn/sda3/lib/allergy-discovery-time",
				"valueDateTime": "2018-12-01T00:00:00+00:00"
			},
			{
				"url": "http://intersystems.com/fhir/extn/sda3/lib/allergy-entered-at",
				"valueReference": {
					"reference": "urn:uuid:4b9e97f6-9dd0-11f0-870e-c6b593068383"
				}
			}
		],
		"onsetDateTime": "2018-12-01T00:00:00+00:00",
		"patient": {
			"reference": "urn:uuid:4b9edb58-9dd0-11f0-870e-c6b593068383"
		},
		"reaction": [
			{
				"extension": [
					{
						"url": "http://intersystems.com/fhir/extn/sda3/lib/allergy-severity",
						"valueCodeableConcept": {
							"coding": [
								{
									"code": "SE"
								}
							]
						}
					}
				],
				"manifestation": [
					{
						"concept": {
							"coding": [
								{
									"code": "Anaphylaxis"
								}
							]
						}
					}
				]
			}
		]
	}
}

Como você pode ver, a propriedade reaction foi modificada, adaptando-a à definição R5:

Conclusão

Como você viu, o Health Connect oferece infinitas possibilidades para se adaptar aos diversos projetos baseados em FHIR que podemos encontrar. Com o motor de interoperabilidade, podemos adaptar nossos dados da forma que precisarmos, levando em conta quaisquer requisitos que se desviem do comportamento padrão.

Espero que você ache útil!

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer