T1.4: Uses Complex Structures

Knowledge Review - InterSystems ObjectScript Specialist

1. Crea objetos/arrays dinámicos (JSON) - %DynamicObject, %DynamicArray, %FromJSON, %ToJSON

Puntos Clave

  • %DynamicObject crea estructuras clave-valor similares a objetos JSON
  • %DynamicArray crea listas ordenadas similares a arrays JSON
  • %FromJSON() analiza una cadena JSON en un %DynamicObject o %DynamicArray
  • %ToJSON() serializa un objeto/array dinámico de vuelta a una cadena JSON
  • Las llaves `{}` y corchetes `[]` literales crean objetos y arrays dinámicos en línea
  • Los objetos dinámicos no tienen esquema: no se requiere definición de clase

Notas Detalladas

Descripción general

InterSystems IRIS proporciona soporte nativo de JSON a través de %DynamicObject y %DynamicArray. Estas clases permiten crear, manipular y serializar datos JSON sin definir esquemas de clase formales. Son esenciales para construir APIs REST, procesar datos externos e intercambiar datos estructurados con otros sistemas.

Creación de Objetos Dinámicos

Usando el constructor %New():

Set obj = ##class(%DynamicObject).%New()
Do obj.%Set("name", "John Smith")
Do obj.%Set("age", 35, "number")
Do obj.%Set("active", 1, "boolean")
Write obj.%ToJSON()
// Output: {"name":"John Smith","age":35,"active":true}

Usando la sintaxis literal {} (preferida para casos simples):

Set obj = {"name": "John Smith", "age": 35, "active": true}
Write obj.%ToJSON()
// Output: {"name":"John Smith","age":35,"active":true}

Acceso a Propiedades

Set obj = {"name": "John", "age": 35}

// Dot syntax for simple property names
Write obj.name, !          // John
Write obj.age, !           // 35

// %Get() method for dynamic access
Set key = "name"
Write obj.%Get(key), !     // John

Modificación de Objetos Dinámicos

Set obj = {"name": "John"}

// Add/modify properties
Set obj.age = 35
Do obj.%Set("email", "john@example.com")

// Remove a property
Do obj.%Remove("email")

// Check if property exists
Write obj.%IsDefined("name")   // 1
Write obj.%IsDefined("email")  // 0

Creación de Arrays Dinámicos

Usando %New():

Set arr = ##class(%DynamicArray).%New()
Do arr.%Push("apple")
Do arr.%Push("banana")
Do arr.%Push("cherry")
Write arr.%ToJSON()
// Output: ["apple","banana","cherry"]

Usando la sintaxis literal []:

Set arr = ["apple", "banana", "cherry"]
Write arr.%ToJSON()

Operaciones con Arrays

Set arr = ["a", "b", "c", "d"]

// Access by index (0-based)
Write arr.%Get(0), !      // a
Write arr.%Get(2), !      // c

// Get array size
Write arr.%Size(), !       // 4

// Push to the end
Do arr.%Push("e")

// Pop from the end
Set last = arr.%Pop()      // "e"

// Remove at index
Do arr.%Remove(1)          // removes "b"

Análisis de JSON con %FromJSON()

Set jsonString = "{""name"":""Alice"",""scores"":[95,87,92]}"
Set obj = ##class(%DynamicAbstractObject).%FromJSON(jsonString)
// or equivalently:
Set obj = {}.%FromJSON(jsonString)

Write obj.name, !                  // Alice
Write obj.scores.%Get(0), !       // 95
Write obj.scores.%Size(), !       // 3

Desde un stream:

Set stream = ##class(%Stream.GlobalCharacter).%New()
Do stream.Write("{""key"":""value""}")
Do stream.Rewind()
Set obj = ##class(%DynamicAbstractObject).%FromJSON(stream)
Write obj.key, !   // value

Estructuras Anidadas

Set person = {
    "name": "Bob",
    "address": {
        "street": "123 Main St",
        "city": "Springfield",
        "state": "IL"
    },
    "phones": [
        {"type": "home", "number": "555-1234"},
        {"type": "work", "number": "555-5678"}
    ]
}

Write person.address.city, !                      // Springfield
Write person.phones.%Get(0).number, !             // 555-1234
Write person.%ToJSON(), !                          // Full JSON string

Iteración sobre Objetos Dinámicos

Set obj = {"name": "Alice", "age": 30, "city": "Boston"}
Set iter = obj.%GetIterator()
While iter.%GetNext(.key, .value) {
    Write key, " = ", value, !
}
// Output:
// name = Alice
// age = 30
// city = Boston

Iteración sobre Arrays Dinámicos

Set arr = ["red", "green", "blue"]
Set iter = arr.%GetIterator()
While iter.%GetNext(.idx, .value) {
    Write idx, ": ", value, !
}
// Output:
// 0: red
// 1: green
// 2: blue

Control de Tipo con %Set()

El tercer argumento de %Set() controla el tipo JSON:

Set obj = ##class(%DynamicObject).%New()
Do obj.%Set("count", 42, "number")       // JSON number
Do obj.%Set("label", "42", "string")      // JSON string "42"
Do obj.%Set("active", 1, "boolean")       // JSON true
Do obj.%Set("deleted", 0, "boolean")      // JSON false
Do obj.%Set("notes", "", "null")          // JSON null
Write obj.%ToJSON()
// {"count":42,"label":"42","active":true,"deleted":false,"notes":null}

Verificación de Tipos de Valor

Set obj = {"name": "Test", "count": 5, "active": true, "data": null}
Write obj.%GetTypeOf("name"), !      // string
Write obj.%GetTypeOf("count"), !     // number
Write obj.%GetTypeOf("active"), !    // boolean
Write obj.%GetTypeOf("data"), !      // null
Write obj.%GetTypeOf("missing"), !   // unassigned

Referencias de Documentación

2. Usa objetos stream del tipo apropiado (%Stream.GlobalCharacter, %Stream.GlobalBinary, %Stream.FileCharacter, %Stream.FileBinary, Write(), Read(), Rewind())

Puntos Clave

  • Los streams manejan datos demasiado grandes para variables de cadena (máx ~3.6M caracteres)
  • Los streams de globals almacenan datos en globals de la base de datos (portátiles, respaldados con la base de datos)
  • Los streams de archivos almacenan datos en archivos externos en el sistema de archivos
  • Los streams de caracteres manejan datos de texto con soporte de codificación de caracteres
  • Los streams binarios manejan datos binarios crudos (imágenes, PDFs, ejecutables)
  • Operaciones principales: Write(), Read(), Rewind(), CopyFrom(), Clear()

Notas Detalladas

Descripción general

Los objetos stream proporcionan acceso secuencial a datos grandes. A diferencia de las propiedades de cadena que se cargan completamente en memoria, los streams pueden leerse y escribirse en fragmentos, haciéndolos adecuados para archivos, documentos y contenido binario de cualquier tamaño.

Guía de Selección de Tipo de Stream

NecesidadClase de StreamAlmacenamiento
Texto grande en base de datos%Stream.GlobalCharacterGlobals
Datos binarios en base de datos%Stream.GlobalBinaryGlobals
Archivos de texto en disco%Stream.FileCharacterSistema de archivos
Archivos binarios en disco%Stream.FileBinarySistema de archivos

%Stream.GlobalCharacter - Texto en Base de Datos

// Create and write
Set stream = ##class(%Stream.GlobalCharacter).%New()
Do stream.Write("Line 1 of the document. ")
Do stream.WriteLine("Line 2 with newline.")
Do stream.Write("Line 3 continues.")

// Read back
Do stream.Rewind()
While 'stream.AtEnd {
    Set chunk = stream.Read(1000)
    Write chunk
}

Cuando se usa como propiedad en una clase persistente, los datos del stream se guardan automáticamente con el objeto:

Class Sample.Document Extends %Persistent
{
    Property Title As %String(MAXLEN = 200);
    Property Body As %Stream.GlobalCharacter;

    ClassMethod CreateDoc(title As %String, text As %String) As %Status
    {
        Set doc = ##class(Sample.Document).%New()
        Set doc.Title = title
        Do doc.Body.Write(text)
        Return doc.%Save()
    }
}

%Stream.GlobalBinary - Binario en Base de Datos

Class Sample.Attachment Extends %Persistent
{
    Property Filename As %String;
    Property Content As %Stream.GlobalBinary;
    Property ContentType As %String;
}

// Store binary data
Set att = ##class(Sample.Attachment).%New()
Set att.Filename = "report.pdf"
Set att.ContentType = "application/pdf"

// Read from a file stream and copy to global stream
Set fileStream = ##class(%Stream.FileBinary).%New()
Set fileStream.Filename = "/path/to/report.pdf"
Do att.Content.CopyFrom(fileStream)
Set sc = att.%Save()

%Stream.FileCharacter - Texto en Sistema de Archivos

// Write to an external file
Set stream = ##class(%Stream.FileCharacter).%New()
Set stream.Filename = "/tmp/output.csv"
Do stream.Write("Name,Age,City")
Do stream.WriteLine("")
Do stream.Write("Alice,30,Boston")
Do stream.WriteLine("")
Set sc = stream.%Save()

// Read from an external file
Set stream = ##class(%Stream.FileCharacter).%New()
Set stream.Filename = "/tmp/output.csv"
Do stream.Rewind()
While 'stream.AtEnd {
    Set line = stream.ReadLine()
    Write line, !
}

%Stream.FileBinary - Binario en Sistema de Archivos

// Read a binary file
Set stream = ##class(%Stream.FileBinary).%New()
Set stream.Filename = "/path/to/image.png"
Write "File size: ", stream.Size, " bytes", !

// Copy to another location
Set target = ##class(%Stream.FileBinary).%New()
Set target.Filename = "/path/to/copy.png"
Do target.CopyFrom(stream)
Set sc = target.%Save()

Referencia de Métodos Principales de Streams

Método/PropiedadDescripción
Write(data)Agrega datos en la posición actual
WriteLine(data)Agrega datos seguidos de un terminador de línea de plataforma
Read(len)Lee hasta len caracteres/bytes desde la posición actual
ReadLine(len, .sc, .eol)Lee una línea (hasta len caracteres)
Rewind()Reinicia la posición al principio del stream
MoveToEnd()Mueve la posición al final (para agregar)
Clear()Elimina todo el contenido del stream
CopyFrom(source)Copia todo el contenido desde otro stream
SizeDevuelve el tamaño total en caracteres/bytes
AtEndDevuelve 1 si está al final del stream, 0 en caso contrario

Patrones de Procesamiento de Streams

Lectura en fragmentos de tamaño fijo (para streams grandes):

Set chunkSize = 32000
Do stream.Rewind()
While 'stream.AtEnd {
    Set chunk = stream.Read(chunkSize)
    // Process chunk
}

Lectura línea por línea (para streams de texto):

Do stream.Rewind()
While 'stream.AtEnd {
    Set line = stream.ReadLine()
    // Process each line
}

Agregar a un stream existente:

// Position at the end before writing more data
Do stream.MoveToEnd()
Do stream.Write("Additional content appended.")
Set sc = stream.%Save()

Codificación de Caracteres con Streams de Archivo

Los streams de caracteres de archivo soportan la propiedad TranslateTable para codificación de caracteres:

Set stream = ##class(%Stream.FileCharacter).%New()
Set stream.Filename = "/tmp/utf8file.txt"
Set stream.TranslateTable = "UTF8"
Do stream.Write("Content with special characters: accents, symbols")
Set sc = stream.%Save()

Comparación de Streams

// Check if two streams have identical content
Set same = stream1.%ConstructClone().Equals(stream2)

// Or use SizeGet for a quick size comparison first
If stream1.Size '= stream2.Size {
    Write "Streams differ (different sizes)", !
}

Referencias de Documentación

Resumen de Preparación para el Examen

Conceptos Críticos a Dominar:

  1. `{}` crea un %DynamicObject; `[]` crea un %DynamicArray (sintaxis literal)
  2. %FromJSON() analiza cadenas JSON o streams en objetos/arrays dinámicos
  3. %ToJSON() serializa objetos/arrays dinámicos de vuelta a cadenas JSON
  4. Los arrays dinámicos tienen índice basado en 0; usar %Get(index), %Push(), %Pop(), %Size()
  5. %GetIterator() es la forma correcta de iterar sobre objetos y arrays dinámicos
  6. %Set() con un tercer argumento controla el tipo JSON (number, string, boolean, null)
  7. Cuatro tipos de stream: GlobalCharacter, GlobalBinary, FileCharacter, FileBinary
  8. Los streams usan el patrón Write/Read/Rewind (no asignación directa de propiedad)
  9. CopyFrom() copia contenido entre cualesquier dos streams
  10. La propiedad AtEnd controla los bucles de lectura; Rewind() reinicia al principio
  11. Los streams de globals se almacenan en la base de datos; los streams de archivos en el sistema de archivos externo
  12. Los streams de caracteres manejan texto con codificación; los streams binarios manejan bytes crudos

Escenarios Comunes en el Examen:

  • Crear una respuesta JSON desde datos ObjectScript usando %DynamicObject
  • Analizar JSON entrante en un objeto dinámico y acceder a valores anidados
  • Elegir el tipo de stream correcto para un caso de uso dado (texto vs binario, base de datos vs archivo)
  • Escribir código para leer un stream fragmento por fragmento o línea por línea
  • Convertir entre tipos de stream usando CopyFrom()
  • Identificar el método correcto para verificar tipos de valor JSON (%GetTypeOf)

Recomendaciones de Práctica:

  • Construir estructuras JSON anidadas usando tanto la sintaxis literal como los métodos %Set/%Push
  • Analizar cadenas JSON de ejemplo con %FromJSON() y navegar la estructura resultante
  • Crear cada uno de los cuatro tipos de stream, escribir datos y leerlos de vuelta
  • Practicar CopyFrom() para transferir datos entre streams de globals y de archivos
  • Usar %GetIterator() para iterar sobre objetos y arrays dinámicos
  • Construir un manejador REST simple que acepte y devuelva JSON usando objetos dinámicos

Report an Issue