Encontrar

Artículo
· 28 abr, 2025 Lectura de 9 min

Gerando uma Classe ObjectScript a partir de uma Resposta JSON Usando o ChatGPT.

Tenho um novo projeto para armazenar informações de respostas REST em um banco de dados IRIS. Precisarei sincronizar informações de pelo menos duas dúzias de endpoints REST separados, o que significa criar quase essa quantidade de classes ObjectScript para armazenar os resultados desses endpoints.

Poderia usar o ChatGPT para ter uma vantagem inicial na criação dessas classes? A resposta é "Sim", o que é ótimo, já que esta é minha primeira tentativa de usar IA generativa para algo útil. Gerar fotos de girafas tomando sopa estava ficando meio batido...

Aqui está o que eu fiz:

  • Obter alguma saída de chamada REST JSON de amostra usando "curl" para consultar o endpoint.
  • Visitar o ChatGPT (a InterSystems fornece uma licença para toda a empresa para os funcionários)
  • Tenha o seguinte diálogo com o ChatGPT.

Coloquei o seguinte pedido no prompt "Message ChatGPT":

Eu: Gere uma classe ObjectScript que armazenará dados do seguinte JSON:

Apertei "Enter" antes de inserir o JSON, então o ChatGPT me direcionou da seguinte forma:

ChatGPT: Por favor, forneça a estrutura JSON para a qual você gostaria que eu gerasse a classe ObjectScript. Se você tiver um objeto JSON de exemplo, cole-o aqui e eu criarei a classe InterSystems ObjectScript correspondente para você.

Eu inseri o seguinte no prompt:

{
  "id": 335818632,
  "appId": 113,
  "appName": "Batch",
  "contentId": 182455380233,
  "subject": "Test Subject",
  "name": "Test email campaign name",
  "counters": {
    "processed": 3910,
    "deferred": 86,
    "unsubscribed": 17,
    "statuschange": 17,
    "bounce": 153,
    "mta_dropped": 8,
    "dropped": 299,
    "delivered": 3749,
    "sent": 3903,
    "click": 16,
    "open": 323
  },
  "lastProcessingFinishedAt": 1733232499000,
  "lastProcessingStartedAt": 1733232303000,
  "lastProcessingStateChangeAt": 1733232499000,
  "numIncluded": 4201,
  "processingState": "DONE",
  "scheduledAt": 1733232300000,
  "type": "BATCH_EMAIL"
}

Resposta do ChatGPT:

Aqui está a classe InterSystems ObjectScript que mapeia a estrutura JSON fornecida:

Class MyNamespace.MyJSONData Extends (%Persistent, %JSON.Adaptor)
{
Property id As %Integer;
Property appId As %Integer;
Property appName As %String;
Property contentId As %Integer;
Property subject As %String;
Property name As %String;
Property counters As MyNamespace.Counters;
Property lastProcessingFinishedAt As %BigInt;
Property lastProcessingStartedAt As %BigInt;
Property lastProcessingStateChangeAt As %BigInt;
Property numIncluded As %Integer;
Property processingState As %String;
Property scheduledAt As %BigInt;
Property type As %String;
ClassMethod %OnJSONImport(jsonObject As %Object, instance As MyNamespace.MyJSONData) As %Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyNamespace.Counters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As %Integer;
Property deferred As %Integer;
Property unsubscribed As %Integer;
Property statuschange As %Integer;
Property bounce As %Integer;
Property mta_dropped As %Integer;
Property dropped As %Integer;
Property delivered As %Integer;
Property sent As %Integer;
Property click As %Integer;
Property open As %Integer;
}

Junto com uma explicação:

 

Explicação:

  1. Mynamespace.MyJSONData: A principal classe representando o objeto JSON.
    • As propriedades mapeiam diretamente para os campos no JSON.
    • Ela estende tanto %Persistent quanto %JSON.Adaptor para persistência e compatibilidade com JSON.
  2. Mynamespace.Counters: Uma classe aninhada para representar o objeto counters no JSON.
    • Esta classe é definida como um %SerialObject, pois faz parte do objeto principal e não precisa de persistência independente.
  3. Manipulação de JSON:
    • O %JSON.Adaptor lida automaticamente com a serialização e desserialização de/para o formato JSON.
    • O método %OnJSONImport permite a personalização da importação JSON, embora o método padrão %JSONImport seja suficiente para esse mapeamento direto.

Você pode salvar esse código em um arquivo de classe e usá-lo para analisar ou armazenar dados JSON. Avise se quiser recursos adicionais ou mais personalizações!

 

Este código é um ótimo começo, mas eu gostaria que ele se encaixasse no meu pacote chamadoMyPkge desse o nome "EmailCampaign" para a classe. Além disso, usando um pouco de NI (Network Intelligence), sei que os valores que geraram as propriedades "%BigInt" são, na verdade, tempos Linux e as propriedades deveriam ser "%Library.PosixTime".

Faço o seguinte pedido (não tenho certeza por que estou dizendo "por favor" para uma máquina; acho que meus pais fizeram um bom trabalho):

Eu: Podemos recriar a classe novamente, renomeando o pacote para "MyPkg" e a Classe como "EmailCampaign"? Além disso, por favor, altere os tipos das propriedades de %BigInt para %Library.PosixTime.

Resposta do ChatGPT:

Aqui está a classe ObjectScript atualizada com o nome do pacote e o nome da classe especificados, e as propriedades de timestamp atualizadas para usar %Library.PosixTime:

Class MyPkg.EmailCampaign Extends (%Persistent, %JSON.Adaptor)
{
Property id As %Integer;
Property appId As %Integer;
Property appName As %String;
Property contentId As %Integer;
Property subject As %String;
Property name As %String;
Property counters As MyPkg.Counters;
Property lastProcessingFinishedAt As %Library.PosixTime;
Property lastProcessingStartedAt As %Library.PosixTime;
Property lastProcessingStateChangeAt As %Library.PosixTime;
Property numIncluded As %Integer;
Property processingState As %String;
Property scheduledAt As %Library.PosixTime;
Property type As %String;
ClassMethod %OnJSONImport(jsonObject As %Object, instance As MyPkg.EmailCampaign) As %Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyPkg.Counters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As %Integer;
Property deferred As %Integer;
Property unsubscribed As %Integer;
Property statuschange As %Integer;
Property bounce As %Integer;
Property mta_dropped As %Integer;
Property dropped As %Integer;
Property delivered As %Integer;
Property sent As %Integer;
Property click As %Integer;
Property open As %Integer;
}

Junto com esta explicação:

Alterações Feitas:

  1. Nome do Pacote e da Classe:
    • O pacote agora é CRMBI.
    • A classe principal foi renomeada para EmailCampaign.
  2. Propriedades de Timestamp:
    • lastProcessingFinishedAt, lastProcessingStartedAt, lastProcessingStateChangeAt e scheduledAt agora utilizam %Library.PosixTime.
    • %Library.PosixTime é apropriado para propriedades que armazenam timestamps no formato UNIX.
  3. Outras Propriedades:
    • Todos os outros campos permanecem inalterados e seguem a estrutura original do JSON.

Esta classe está pronta para lidar com a serialização/desserialização JSON e fornece o mapeamento correto para o objeto aninhado counters. Me avise se precisar de mais ajustes ou tiver novos requisitos!

Depois de copiar o código "como está" para o VSCode, problemas de sintaxe com as chaves foram destacados. Classes ObjectScript não habilitam definições de classe internas.

Pedir ao ChatGPT para corrigir o problema das "chaves" movendo a classe interna MyPkg.Counters para uma classe separada é uma "não-operação"; um humano precisará mover essa classe para outro arquivo. O ChatGPT renomeou essa classe após o seguinte pedido:

Eu: A classe como está escrita não compila. Podemos mover a classe interna chamada MyPkg.Counters para fora da classe principal para sua própria classe e renomeá-la para MyPkg.CampaignCounters?

Resposta do ChatGPT:

Aqui está o código ObjectScript atualizado com a classe MyPkg.CampaignCounters movida para fora como sua própria classe:

Class MyPkg.EmailCampaign Extends (%Persistent, %JSON.Adaptor)
{
Property id As %Integer;
Property appId As %Integer;
Property appName As %String;
Property contentId As %Integer;
Property subject As %String;
Property name As %String;
Property counters As MyPkg.CampaignCounters;
Property lastProcessingFinishedAt As %Library.PosixTime;
Property lastProcessingStartedAt As %Library.PosixTime;
Property lastProcessingStateChangeAt As %Library.PosixTime;
Property numIncluded As %Integer;
Property processingState As %String;
Property scheduledAt As %Library.PosixTime;
Property type As %String;
ClassMethod %OnJSONImport(jsonObject As %Object, instance As MyPkg.EmailCampaign) As %Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyPkg.CampaignCounters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As %Integer;
Property deferred As %Integer;
Property unsubscribed As %Integer;
Property statuschange As %Integer;
Property bounce As %Integer;
Property mta_dropped As %Integer;
Property dropped As %Integer;
Property delivered As %Integer;
Property sent As %Integer;
Property click As %Integer;
Property open As %Integer;
}

Depois de colar o código acima no VSCode e compilá-lo, o compilador relatou que o tipo chamado "%Object" não existe em ObjectScript. De acordo com a documentação do IRIS, a propriedade para o primeiro parâmetro do método %JSONImport() de %JSON.Adaptor é flexível:

O argumento de entrada é JSON como uma string ou stream, ou uma subclasse de %DynamicAbstractObject.

Depois de remover a propriedade "As %Object" para o primeiro parâmetro de %OnJSONImport() na primeira classe e separar as duas classes em arquivos separados, a classe MyPkg.EmailCampaign compilou com sucesso. No entanto, a MyPkg.CampaignCounters não compilou; o ChatGPT não sabe (ainda?) que o sublinhado é um caractere especial em ObjectScript (o operador de concatenação de strings)

Vamos tentar ensiná-lo.

Eu: O caractere sublinhado "_" é um caractere especial em ObjectScript. Por favor, altere as propriedades com um sublinhado em seus nomes para nomes em camel case e remova o sublinhado.

Resposta do ChatGPT:

Aqui está o código atualizado com as propriedades que tinham sublinhados em seus nomes convertidas para camel case:

Class MyPkg.EmailCampaign Extends (%Persistent, %JSON.Adaptor)
{
Property id As %Integer;
Property appId As %Integer;
Property appName As %String;
Property contentId As %Integer;
Property subject As %String;
Property name As %String;
Property counters As MyPkg.CampaignCounters;
Property lastProcessingFinishedAt As %Library.PosixTime;
Property lastProcessingStartedAt As %Library.PosixTime;
Property lastProcessingStateChangeAt As %Library.PosixTime;
Property numIncluded As %Integer;
Property processingState As %String;
Property scheduledAt As %Library.PosixTime;
Property type As %String;
ClassMethod %OnJSONImport(jsonObject As %Object, instance As MyPkg.EmailCampaign) As %Status
{
    Quit ..%JSONImport(jsonObject, .instance)
}
}

Class MyPkg.CampaignCounters Extends (%SerialObject, %JSON.Adaptor)
{
Property processed As %Integer;
Property deferred As %Integer;
Property unsubscribed As %Integer;
Property statusChange As %Integer;
Property bounce As %Integer;
Property mtaDropped As %Integer;
Property dropped As %Integer;
Property delivered As %Integer;
Property sent As %Integer;
Property click As %Integer;
Property open As %Integer;
}

Junto com esta explicação:

Mudanças Realizadas:

1. Conversão para Camel Case:

  • Propriedades em CampaignCounters com underscores agora são escritas em camel case:
    • statuschangestatusChange
    • mta_droppedmtaDropped

2. Nomes de Propriedades em JSON:

  • ObjectScript irá mapear automaticamente nomes de propriedades em camel case para seus correspondentes com underscore no JSON usando o %JSON.Adaptor.

Este código atualizado compila corretamente e preserva a funcionalidade para serialização/desserialização JSON! Avise-me se precisar de mais ajustes!

 

O ChatGPT foi além e alterou outra propriedade, uma nomeada com duas palavras separadas, para camel case também (statuschange); estou mantendo essa alteração, já que outras propriedades com nomes semelhantes na classe principal estão todas em camel case.

Com o código gerado mais recente em dois arquivos separados (e removendo a definição "As %Object" na definição do método %OnJSONImport()), todo o código compila com sucesso.

Essas classes geradas são um excelente ponto de partida para o que preciso e repetirei o processo para as outras fontes de dados REST para este projeto, me poupando muita digitação desnecessária.

Comentarios (0)1
Inicie sesión o regístrese para continuar
Resumen
· 28 abr, 2025

Publications des développeurs d'InterSystems, semaine Avril 21 - 27, 2025, Résumé

Resumen
· 28 abr, 2025

Nuevas publicaciones en la Comunidad de InterSystems, 21-27 abril

21-27 abrilWeek at a GlanceInterSystems Developer Community
Comentarios (2)3
Inicie sesión o regístrese para continuar
Comentarios
· 28 abr, 2025

Let's talk about the new UI for Interoperability and Data Transformations editor

It's been a while since the new UI for Productions and DTL was published as a preview and I would like to know your opinions about it.

WARNING: This is a personal opinion, totally personal and not related with InterSystems Corporation.

I'm going to start with the Interoperabilty screen:

Production screen:

The style is sober and without frills, following the line of cloud services design, I like it.

But, always a but...or maybe two:

In my opinion there is too much information, the left menu is superfluous, it's true that you can collapse it, but I don't want to do it each time that I use the screen. I don't need to see all the time all the productions in my NAMESPACE, the Production Items, Rule Sets and Data Transformations. I feel that the designers have suffered a case of "horror vacui"

About these menus, looks like the options are too close:

And displaying Rule and Data Transformations editors in the same screen for small screens like a laptop it's a scrolling nightmare:

 A pop-up window with the editors would be more "clean" for the common user. A positive point is that we can select how we want to open the editors.:

But maybe we have too much options.

DTL Editor:

Well, I like it, the design is simple and clear, maybe, as in the Production screen, the lines are too close together and we have lost the drag and drop to link fields.

Conclusion:

The design has been modernized and looks nice, but in my opinion as a former web developer "less is more". I would like to work with simpler screens   with a well defined behaviour, I don't need to access from the same screen to all the interoperability functionalities.

My two cents, we need to balance functionalities and a friendly and modern user interface, the new design seems to go in that direction. Thank you to all the team involved in the development!

6 comentarios
Comentarios (6)5
Inicie sesión o regístrese para continuar