Saltar al contenido

Tipos Primitivos

FHIR define un conjunto de tipos de datos primitivos que sirven como bloques de construcción para todos los campos de recursos. La biblioteca gofhir/models mapea cada tipo primitivo FHIR a un tipo de Go apropiado, usando semántica de punteros para representar la opcionalidad.

Mapeo de Tipos FHIR a Go

La siguiente tabla muestra el mapeo completo de tipos primitivos FHIR a sus representaciones en Go:

Tipo FHIRTipo GoNotas
string*stringTexto de propósito general
uri*stringReferencia URI/IRI
url*stringURL absoluta
canonical*stringURL canónica a una definición de recurso FHIR
id*stringID lógico del recurso (1-64 caracteres, [A-Za-z0-9-.])
oid*stringOID (urn:oid:…)
uuid*stringUUID (urn:uuid:…)
markdown*stringTexto con formato Markdown
code*string o enum generadop. ej., *AdministrativeGender para conjuntos de valores vinculados
boolean*booltrue o false
integer*intEntero con signo de 32 bits
integer64*Integer64Entero con signo de 64 bits, codificado como string en JSON (solo R5)
unsignedInt*uint32Entero sin signo de 32 bits (>= 0)
positiveInt*uint32Entero sin signo de 32 bits (>= 1)
decimal*DecimalTipo personalizado, preserva precisión
date*stringFecha ISO 8601 (YYYY, YYYY-MM o YYYY-MM-DD)
dateTime*stringFecha/hora ISO 8601 con zona horaria opcional
instant*stringMarca de tiempo precisa ISO 8601 con zona horaria
time*stringHora del día (HH:MM:SS)
base64Binary*stringDatos binarios codificados en Base64

Semántica de Punteros

Todos los tipos primitivos usan semántica de punteros (*T), donde un puntero nil significa que el valor está ausente del recurso. Esto es crítico para FHIR, donde la ausencia de un campo tiene un significado distinto al de que el campo esté presente con un valor por defecto o valor cero.

func ptrTo[T any](v T) *T {
    return &v
}

patient := &r4.Patient{
    Id:           ptrTo("123"),       // Present: "123"
    Active:       ptrTo(true),        // Present: true
    BirthDate:    ptrTo("1990-01-15"),// Present: "1990-01-15"
    // Gender is nil -- absent from the resource
}

Al leer campos, siempre verifica si es nil antes de desreferenciar:

if patient.Gender != nil {
    fmt.Println("Gender:", *patient.Gender)
} else {
    fmt.Println("Gender is not specified")
}

if patient.BirthDate != nil {
    fmt.Println("Birth date:", *patient.BirthDate)
}

Por Qué No Valores Cero?

Los valores cero de Go ("" para cadenas, false para booleanos, 0 para enteros) no pueden distinguir entre “ausente” y “presente con valor cero”. En FHIR:

  • Un campo booleano establecido en false es diferente de un campo booleano ausente.
  • Un campo entero establecido en 0 es diferente de un campo entero ausente.
  • Un campo cadena establecido en "" es diferente de un campo cadena ausente.

Los punteros resuelven esto de forma limpia: nil significa ausente, y ptrTo(false) significa explícitamente false.

Tipos Similares a Cadenas

FHIR define muchos tipos primitivos similares a cadenas (uri, url, canonical, id, oid, uuid, markdown) que todos se mapean a *string en Go. La información del tipo FHIR se captura en los comentarios de los campos del struct y las etiquetas JSON, pero el tipo de Go es el mismo.

type StructureDefinition struct {
    // ...
    Url         *string `json:"url,omitempty"`       // FHIR type: uri
    Version     *string `json:"version,omitempty"`   // FHIR type: string
    Name        *string `json:"name,omitempty"`      // FHIR type: string
    Description *string `json:"description,omitempty"` // FHIR type: markdown
    // ...
}

Tipos de Fecha y Hora

FHIR tiene cuatro primitivos de fecha/hora, todos mapeados a *string en Go. Los valores de cadena deben conformarse al formato ISO 8601, pero la biblioteca no realiza validación de fechas a nivel de tipo.

patient := &r4.Patient{
    BirthDate:    ptrTo("1990-01-15"),  // FHIR date: YYYY-MM-DD
}

observation := &r4.Observation{
    EffectiveDateTime: ptrTo("2024-03-15T10:30:00Z"), // FHIR dateTime
}
Tipo FHIREjemplos de Formato
date"2024", "2024-03", "2024-03-15"
dateTime"2024-03-15", "2024-03-15T10:30:00Z", "2024-03-15T10:30:00+01:00"
instant"2024-03-15T10:30:00.123Z" (requiere precisión completa con zona horaria)
time"10:30:00", "10:30:00.123"

Tipos Numéricos

Tipos Enteros

FHIR define cuatro tipos enteros con diferentes mapeos en Go. integer64 es el caso particular: los números JSON solo transportan 53 bits de precisión de forma fiable, así que la especificación exige que viaje como string en JSON. Por eso se mapea a un tipo con nombre y no a int64:

// integer64 -> *Integer64, serializado como "1024"
attachment := r5.Attachment{Size: r5.Ptr(r5.Integer64(1024))}
data, _ := r5.Marshal(attachment)  // {"size":"1024"}

size := attachment.Size.Int64()    // 1024, como int64 normal

Integer64 también acepta un número JSON desnudo al leer, porque es lo que produce un encoder ingenuo, pero siempre escribe la forma string. En XML es un atributo value= normal.

Los otros tres:

// integer -> *int
type Dosage struct {
    Sequence *int `json:"sequence,omitempty"`
}

// unsignedInt -> *uint32
type Attachment struct {
    Size *uint32 `json:"size,omitempty"`
}

// positiveInt -> *uint32
type ContactPoint struct {
    Rank *uint32 `json:"rank,omitempty"`
}

Decimal

El tipo decimal de FHIR se mapea al tipo personalizado *Decimal en lugar de *float64, para preservar la precisión. Consulta la página de Precisión Decimal para todos los detalles.

type Quantity struct {
    Value *Decimal `json:"value,omitempty"`
    // ...
}

// Create a quantity with precise decimal value
q := r4.Quantity{
    Value: r4.MustDecimal("72.50"),
    Unit:  ptrTo("kg"),
}

Tipos de Código

Cuando un campo FHIR está vinculado a un conjunto de valores requerido, la biblioteca genera un enum con seguridad de tipos en lugar de usar *string. Consulta la página de Sistemas de Códigos para más detalles.

// Gender uses a generated enum type
type Patient struct {
    Gender *AdministrativeGender `json:"gender,omitempty"`
    // ...
}

// Status uses a generated enum type
type Observation struct {
    Status *ObservationStatus `json:"status,omitempty"`
    // ...
}

Elementos de Extensión

Cada campo primitivo en un recurso FHIR tiene un elemento de extensión correspondiente que puede llevar el id del elemento y cualquier extensión sobre el valor primitivo. En los structs de Go, estos aparecen como campos *Element con una etiqueta JSON prefijada con guion bajo.

type Patient struct {
    // The date of birth for the individual
    BirthDate    *string  `json:"birthDate,omitempty"`
    // Extension for BirthDate
    BirthDateExt *Element `json:"_birthDate,omitempty"`

    // Whether this patient's record is in active use
    Active    *bool    `json:"active,omitempty"`
    // Extension for Active
    ActiveExt *Element `json:"_active,omitempty"`
    // ...
}

El struct Element contiene un Id opcional y un slice de valores Extension:

type Element struct {
    Id        *string     `json:"id,omitempty"`
    Extension []Extension `json:"extension,omitempty"`
}

Consulta la página de Extensiones para ejemplos detallados del uso de extensiones de primitivos.

Primitivos Repetidos

Cuando un campo primitivo puede repetirse (cardinalidad 0..*), usa un slice de Go del tipo base en lugar de un puntero:

type HumanName struct {
    Given     []string  `json:"given,omitempty"`     // Repeating string
    GivenExt  []Element `json:"_given,omitempty"`    // Per-element extensions
    Prefix    []string  `json:"prefix,omitempty"`    // Repeating string
    PrefixExt []Element `json:"_prefix,omitempty"`   // Per-element extensions
    // ...
}

Un slice vacío o nil significa “no hay valores presentes”. Cada elemento en el slice de extensiones corresponde posicionalmente al elemento en el mismo índice en el slice de valores.

La biblioteca no realiza validación FHIR sobre valores primitivos. Por ejemplo, los campos *string para tipos date aceptan cualquier cadena, y los campos *uint32 para positiveInt aceptan cero aunque FHIR requiere valores positivos. La validación debe manejarse en una capa superior.
Última actualización