Pesquisar

Article
· 4 hr ago 5m read

API nativa para Demos ObjectScript

A demo é baseada nas descrições brutas das classes.
As classes de dados utilizadas são Address, Person, Employee e Company.
Para uma demonstração mais atraente, foi adicionado um método JSONtoString por ID.

Após a instalação com o ZPM, basta executar pelo Terminal

USER>do ##class(ONAPI.demo).Run()
Adjust Parameters
host[127.0.0.1]:
port[1972]:
namespace[USER]:
user[_SYSTEM]:
pwd[SYS]:
timeout[5]:
****** connected ********

Em seguida, você recebe uma lista de possíveis ações de demonstração.
Nenhuma entrada significa nenhuma ação.
O menu fica em loop até você sair.

Populate Person by:100
     100
Populate Company by:10
     10
Populate Employee by:50
     50
Show Person by ID:3
{
  "Name":"O'Donnell,Mark I.",
  "SSN":"871-87-4555",
  "DOB":"1934-05-24",
  "Home":{
    "Street":"3012 Elm Drive",
    "City":"Ukiah",
    "State":"IN",
    "Zip":"11758"
  },
  "Office":{
    "Street":"1326 Maple Street",
    "City":"Jackson",
    "State":"MD",
    "Zip":"61987"
  },
  "FavoriteColors":[
    "Green"
  ],
  "Age":91
}
Show Company by ID:3
{
  "Name":"TeleData Gmbh.",
  "Mission":"Experts in innovative nano-connectivity for social networks.",
  "TaxID":"E4116",
  "Revenue":33297336,
  "Employees":[
    {
      "Name":"Larson,Dave G.",
      "SSN":"761-57-3123",
      "DOB":"2011-09-28",
      "Home":{
        "Street":"6346 Second Street",
        "City":"Chicago",
        "State":"NJ",
        "Zip":"16814"
      },
      "Office":{
        "Street":"6702 Clinton Drive",
        "City":"Tampa",
        "State":"CT",
        "Zip":"91275"
      },
      "Spouse":{
        "Name":"Willeke,Rhonda A.",
        "SSN":"434-63-3541",
        "DOB":"1974-02-15",
        "Home":{
          "Street":"1910 Oak Blvd",
          "City":"St Louis",
          "State":"ND",
          "Zip":"62884"
        },
        "Office":{
          "Street":"5148 Ash Court",
          "City":"St Louis",
          "State":"DE",
          "Zip":"36764"
        },
        "FavoriteColors":[
          "White",
          "Yellow"
        ],
        "Age":51
      },
      "FavoriteColors":[
        "Black"
      ],
      "Age":14,
      "Title":"Product Specialist",
      "Salary":28870
    },
    {
      "Name":"Quincy,Mo V.",
      "SSN":"345-36-6735",
      "DOB":"1945-05-14",
      "Home":{
        "Street":"399 Oak Court",
        "City":"Youngstown",
        "State":"LA",
        "Zip":"75634"
      },
      "Office":{
        "Street":"6307 Clinton Avenue",
        "City":"Oak Creek",
        "State":"NH",
        "Zip":"85911"
      },
      "Spouse":{
        "Name":"Iacobelli,Barb E.",
        "SSN":"951-91-9488",
        "DOB":"2020-09-04",
        "Home":{
          "Street":"8413 Elm Blvd",
          "City":"Denver",
          "State":"ID",
          "Zip":"91025"
        },
        "Office":{
          "Street":"4276 Oak Court",
          "City":"Oak Creek",
          "State":"ID",
          "Zip":"20879"
        },
        "Age":5
      },
      "FavoriteColors":[
        "Blue"
      ],
      "Age":80,
      "Title":"Global Sales Rep.",
      "Salary":89381
    }
  ]
}
Show Employee by ID:103
{
  "Name":"Larson,Dave G.",
  "SSN":"761-57-3123",
  "DOB":"2011-09-28",
  "Home":{
    "Street":"6346 Second Street",
    "City":"Chicago",
    "State":"NJ",
    "Zip":"16814"
  },
  "Office":{
    "Street":"6702 Clinton Drive",
    "City":"Tampa",
    "State":"CT",
    "Zip":"91275"
  },
  "Spouse":{
    "Name":"Willeke,Rhonda A.",
    "SSN":"434-63-3541",
    "DOB":"1974-02-15",
    "Home":{
      "Street":"1910 Oak Blvd",
      "City":"St Louis",
      "State":"ND",
      "Zip":"62884"
    },
    "Office":{
      "Street":"5148 Ash Court",
      "City":"St Louis",
      "State":"DE",
      "Zip":"36764"
    },
    "FavoriteColors":[
      "White",
      "Yellow"
    ],
    "Age":51
  },
  "FavoriteColors":[
    "Black"
  ],
  "Age":14,
  "Title":"Product Specialist",
  "Salary":28870
}
Show Global PersonD by ID:4
     $Data()=1
     Value=$lb("","Eastman,Mary C.","887-18-3730",44711,$lb("3889 Ash Blvd","Washington","TX",67862),$lb("5709 Oak Blvd","Chicago","IL",30845),"","")

Index list for Person & Employee (n,y):y
     $Employee
     $Person
     NameIDX
     SSNKey
     ZipCode
Exit Demo (n,y,*):y
****** done ********
 
USER>

GitHub

Discussion (0)1
Log in or sign up to continue
Article
· 4 hr ago 3m read

Como encontrar um texto específico em ObjectScript

Você provavelmente conhece essa situação:

Algum tempo atrás, você encontrou uma função $ZU muito especial para um tipo de problema bem específico. Uma espécie de fórmula mística. Ela se tornou popular e foi usada por muitos desenvolvedores em todo o seu código e em todas as suas instalações.

Depois de várias versões e atualizações, você é informado pela ISC de que seu $ZU místico está obsoleto (deprecated) e não é mais suportado. Você é aconselhado a substituí-lo por um novo $something().

Então, como encontrar e documentar o uso desse código misterioso?
Ele pode estar localizado em classes, em código MAC, INT ou INC.
Também pode estar espalhado por vários namespaces.
No passado, o Studio ainda não estava completo: era pouco adequado, lento e impreciso.

Já me deparei com essa situação mais de uma vez em diferentes instalações.
O controle de versão (Source Control) não estava disponível na época e só passou a ser usado raramente quando foi finalmente introduzido.

Como ObjectScript era a única escolha possível para enfrentar esse desafio, escrevi meu próprio utilitário.
Minha solução evoluiu ao longo dos anos e, quando a migração para o IRIS foi planejada, verifiquei mais uma vez o quanto ela ainda era útil.
E, por ter sido escrita inteiramente em ObjectScript puro, ela funcionou no IRIS sem que fosse necessário alterar um único caractere.

Como você já deve saber, o problema de procurar um trecho específico de texto em ObjectScript não mudou.

Meus objetivos pessoais para esse utilitário foram:

  • apenas ObjectScript
  • nada de construções sofisticadas, milagrosas ou frágeis
  • o menor uso possível de funções $avançadas
  • priorizar legibilidade em vez de elegância, pensando na manutenção futura
  • exibir o número de ocorrências encontradas por namespace e por elemento de código
  • para classes, também distinguir entre:
    • parâmetros
    • propriedades (se calculadas)
    • métodos
    • índices
  • uma opção para mostrar a linha que contém a ocorrência
  • nenhuma preocupação com a listagem de saída:
    • qualquer programa de terminal pode gravar um log
    • o bash tem o STDOUT exatamente para isso

Esse utilitário, portanto, está disponível para você no Open Exchange e no GitHub.
Também criei um video para demonstrar a ferramenta em funcionamento.
Ela também está disponível no Demo Server.

Basta iniciá-la pelo terminal:
user>DO ^rcc.find

  • qual texto você está procurando?
  • Verbose?
  • você quer ver cada linha completa que contém o texto?
    • aviso: isso pode gerar uma listagem muito grande
    • um teste recente encontrou mais de 90.000 ocorrências
    • com verbose=1, você terá mais de 90.000 linhas
  • Apenas maiúsculas (Uppercase only)?
    • isso resolve o problema de funções escritas
      em maiúsculas, minúsculas ou em formato misto
    • Uppercase=1 garante que você não perca nenhuma ocorrência
  • Qual tipo de código você deseja examinar? (CLS, MAC, INT, INC, ALL)
  • Qual namespace você deseja pesquisar?
    • um namespace específico da sua lista ou ALL
    • para ALL, você obtém uma lista condensada de namespaces e tipos
      (não visível no vídeo)

Selecionar o namespace inicia a varredura.

Vamos dançar! 

USER> do ^rcc.find
----------------

enter search string [$ZU] <blank> to exit: RCC
          Verbose? (0,1) [0]:
          Force UpperCase? (1,0) [1]:

enter code type (CLS,MAC,INT,INC,ALL) [ALL]: CLS

select namespace (ALL,%SYS,DOCBOOK,ENSDEMO,ENSEMBLE,SAMPLES,USER) [USER]:

** Scan Namespace: USER **

** CLS **
** 2      User.ConLoad
** 15     User.Main
** 3      csp.form
** 3      csp.winner
** 2      dc.rcc.Contest
** 37     dc.rcc.Main
** 1      dc.rcc.Prize
** 63 CLS **
----------------

Espero que você tenha gostado da minha história.
Tentei evitar listagens de código entediantes, é para isso que servem o Open Exchange e o GitHub.

Discussion (0)1
Log in or sign up to continue
Question
· 5 hr ago

Accessing %Collection.ListOfObj within .NET using the Native SDK

I am migrating from HealthShare 2015 to Health Connect 2025 as part of an infrastructure upgrade. We have several C# .NET Razor web apps that interact with HealthShare using the InterSystems.Data.CacheClient assembly, and the Cache Object Binding Wizard for .NET to build the C# proxy classes. This has worked flawlessly for about 6 years.

I am now switching to using the Native SDK with the InterSystems.Data.IRISClient assembly and using the C# IRISReference and IRISObject. I have been able to rewrite nearly all the code in our web apps to use the new mechanism, with the exception of lists of objects.

As an example, I have the following Caché classes:

Class TestClasses.Entries Extends %RegisteredObject
{
Property Entries As list Of TestClasses.Entry;
}

Class TestClasses.Entry Extends %RegisteredObject
{
Property Domain As %String;
Property Username As %String;
}

A classmethod has an output parameter of TestClasses.Entries, with a return type of %Status.

Class TestClass
{
ClassMethod Method1(output pReturn As TestClasses.Entries) As %Status
{
    Set pReturn = ##class(TestClasses.Entries).%New()
    Set tObject1 = ##class(TestClasses.Entry).%New()
    Set tObject1.Username = "user1"
    Do pReturn.Entries.Insert(tObject1)
    Set tObject2 = ##class(TestClasses.Entry).%New()
    Set tObject2.Username = "user2"
    Do pReturn.Entries.Insert(tObject2)
    Quit $$$OK
}
}

Within C# I can get the Entries object and can see the type and OREF of the Entries property.

IRISReference irisReference = new(0);
iris.ClassMethodStatusCode("TestClass", "Method1", irisReference);
IRISObject irisObject = (IRISObject)irisReference.value;
Console.WriteLine(irisObject.GetOREF())
// prints: 5@TestClasses.Entries

IRISObject irisObject2 = (IRISObject)irisObject.GetObject("Entries");
Console.WriteLine(irisObject2.GetType())
// prints: InterSystems.Data.IRISClient.ADO.IRISObject
Console.WriteLine(irisObject2.GetOREF())
// prints: 8@%Collection.ListOfObj

IRISList irisList = irisObject.GetIRISList("Entries");
Console.WriteLine(irisList.ToString());
// prints: $lb()
Console.WriteLine(irisList.GetType());
// prints: InterSystems.Data.IRISClient.ADO.IRISList

But I cannot find any way to interact with the list of Entry objects or their properties. I've tried pretty much every combination of the various IRIS C# methods that I can see and have looked through the SDK documentation. The example above is a simple version of what some of our clinical web apps do; other methods have multiple input and output parameters with large objects with nested lists of objects.

Is %Collection.ListOfObj not supported via the Native SDK, or am I just doing it wrong/missing something obvious?

2 new Comments
Discussion (2)1
Log in or sign up to continue
Article
· 8 hr ago 5m read

Mise à jour du code legacy vers les versions actuelles - Trucs et astuces

Il vous faudra inévitablement passer votre code d'une version antérieure d'IRIS ou de Cache à la version la plus récente d'IRIS. Voici quelques étapes à suivre pour réussir cette transition.

Discussion (0)0
Log in or sign up to continue
Article
· 14 hr ago 4m read

Using Postman for testing the OAuth2.0 of the InterSystems FHIR repository - Part1

Hi all, it's me again for sharing what I am studying recently.😓

 

Recently, I am studying how to setup OAuth2 authentication for the InterSystems FHIR repository. And I found the following articles are very good and easy to follow.😁

SMART on FHIR EHR Launch with IRIS for Health

Building an FHIR Repository + OAuth2 Authorization Server/Resource Server Configuration on IRIS for Health Part 2

 

For me, as a user who do not have much knowledge about OAuth2.0. I think it quite difficult to understand how to setup the whole OAuth2.0 environment before knowing how's it look like (what is it? what are the parameters I need? What is the expecting output?) from a pure user point of view. 🤔 Here, I try to reverse the sequence a little bit, we try to talk about OAuth2.0 from the client side 1st. And , here, we use Postman as a client.😁

If you want to have a test environment for OAuth, you may try the following dockers

workshop-iris-oauth2 or the docker in this article Building an FHIR Repository + OAuth2 Authorization Server/Resource Server Configuration on IRIS for Health Part 1

In this article, I setup an InterSystems FHIR repository with HTTPS support on my local machine. (Base on my observation, correct me if I am wrong, for making the InterSystems OAuth working, the resource server should support HTTPS😑😐)

 


So let's start from something simple. 😀

Case 1: Basic Authentication 

 Information we need are

URL {hostname}/{path}/{Resources}?{parameters}
Body (optional)
Username  
Password  

 

While testing in Postman is simple, it looks like the following

In general, basic authentication is simple, because all you need is the URL of the resources you would like to get and provide the corresponding credential. 1 step and can obtain the data you want.😁✌

 


Case 2: OAuth Authentication 

The concept is a little bit different from basic authentication. From my understanding, the key difference is the concept of session and token. Maybe before we really jump into OAuth2.0, let's talk about something we familiar.

Let's consider the following scenario, you would like to visit an Art Museum for a special event "The Miracle Moment". As this event is so popular, the Art Museum decided to setup the flow control, divide the opening time into 8 sessions, for each session is 1 hour, and visitor must book their own session in the Ticketing Centre before visiting. In the other word, the visitor must present a valid ticket (token) at the correct time slot (session) to the Art Museum for the event "The Miracle Moment".

 

From the scenario above, we can summarize as following, from a OAuth2.0 client point of view, in order to access the resources we want, we need to 

Step1: get a token from the Authentication Server (Get a ticket from Ticket Service Centre)

Step2: present the token to the Resource Server (Present the ticket to the Art Museum)

For getting the token, you need to let the Authentication Server know

1. Who you are? (one of the most simple way, provide client_id and client_secret, of course there are some other way, but i just want to keep it simple here😁)

2. What is the Resource Server you want to access? (Which museum? Which venue?), you may provide it in the audience.

3. What is the scope of your access? (Which program? Which event?), you can provide it in the Scope, and this scope should be defined between the Authentication Server and the Resource Server.

 

So...now ... it's time for being a client

with the information below, and get the token from Postman

Auth Type OAuth2.0
Grant type Client Credentials
Access Token URL

https://{authentication server hostname}/oauth2/token?aud={resource server hostname}/path

For example,

https://authenticationserver.com/oauth2/token?aud=https://resourceserver...

Scope user/*.read user/*.write
Client Authentication Send as Basic Auth header

After the authentication complete, click use the token

 

Yeah!! now we got a valid token here,😁😂 and it will expired within an hour 😶🤐

 

Now use the token for getting the resource we want

 

Now try to get the Patient Resource

URL {resource server hostname}/{path}/Patient
Method GET
Token the one we got from Step 1

 

 

 

Yeah!! looks good.😁

Thank you for reading.

Discussion (0)1
Log in or sign up to continue