Saltar al contenido

API del Builder

Cada tipo de recurso en gofhir/models proporciona un builder fluido, generado automáticamente para todos los recursos en R4, R4B y R5.

Patron Builder Fluido

El patron builder proporciona una API encadenable para construir recursos paso a paso.

Estructura

Para cada tipo de recurso <Resource>, la biblioteca genera:

ExportacionTipoDescripcion
<Resource>BuilderstructLa struct del builder que contiene el recurso en construccion
New<Resource>Builder()*<Resource>BuilderConstructor que crea un nuevo builder con un recurso de valor cero
Set<Field>(v T)*<Resource>BuilderEstablece un campo singular (puntero o escalar)
Add<Field>(v T)*<Resource>BuilderAgrega a un campo repetido (slice)
Build()*<Resource>Devuelve el recurso construido

Convencion de Nomenclatura

  • Set se usa para campos singulares – campos con una cardinalidad maxima de 1 (por ejemplo, Id, Gender, BirthDate, Status).
  • Add se usa para campos repetidos – campos con una cardinalidad maxima mayor a 1 (por ejemplo, Name, Identifier, Telecom, Extension).

Ejemplo con Patient

import "github.com/gofhir/models/r4/v2"

patient := r4.NewPatientBuilder().
    SetId("patient-123").
    SetActive(true).
    SetGender(r4.AdministrativeGenderMale).
    SetBirthDate("1990-05-15").
    AddName(r4.HumanName{
        Family: ptrTo("Doe"),
        Given:  r4.PtrSlice("John", "Michael"),
    }).
    AddIdentifier(r4.Identifier{
        System: ptrTo("http://hospital.example.org/mrn"),
        Value:  ptrTo("MRN-12345"),
    }).
    AddTelecom(r4.ContactPoint{
        System: ptrTo(r4.ContactPointSystemPhone),
        Value:  ptrTo("+1-555-0100"),
        Use:    ptrTo(r4.ContactPointUseHome),
    }).
    AddAddress(r4.Address{
        Use:        ptrTo(r4.AddressUseHome),
        Line:       r4.PtrSlice("123 Main St"),
        City:       ptrTo("Springfield"),
        State:      ptrTo("IL"),
        PostalCode: ptrTo("62701"),
        Country:    ptrTo("US"),
    }).
    Build()

// Funcion auxiliar para crear punteros a strings
func ptrTo[T any](v T) *T {
    return &v
}

Ejemplo con Observation

import "github.com/gofhir/models/r4/v2"

status := r4.ObservationStatusFinal
observation := r4.NewObservationBuilder().
    SetId("obs-001").
    SetStatus(status).
    SetCode(r4.CodeableConcept{
        Coding: []r4.Coding{{
            System:  ptrTo("http://loinc.org"),
            Code:    ptrTo("29463-7"),
            Display: ptrTo("Body weight"),
        }},
        Text: ptrTo("Body Weight"),
    }).
    SetSubject(r4.Reference{
        Reference: ptrTo("Patient/patient-123"),
    }).
    SetEffectiveDateTime("2024-01-15T10:30:00Z").
    SetValueQuantity(r4.Quantity{
        Value:  r4.NewDecimalFromFloat64(72.5),
        Unit:   ptrTo("kg"),
        System: ptrTo("http://unitsofmeasure.org"),
        Code:   ptrTo("kg"),
    }).
    AddCategory(r4.CodeableConcept{
        Coding: []r4.Coding{{
            System:  ptrTo("http://terminology.hl7.org/CodeSystem/observation-category"),
            Code:    ptrTo("vital-signs"),
            Display: ptrTo("Vital Signs"),
        }},
    }).
    Build()

Elegir entre Patrones

CriterioBuilder FluidoLiteral de Struct
Encadenamiento de métodosSíNo
Construcción incrementalEncaja de forma naturalNo es posible
Campos condicionalesAñadir tras crear el builderRequiere un if antes del literal
Envoltura de punterosLa hacen Set*/Add*Usa Ptr
Todo conocido de antemanoFuncionaEs lo más corto

Cuando Usar el Builder

El builder es adecuado cuando necesitas construir un recurso de forma incremental, especialmente cuando algunos campos dependen de condiciones:

builder := r4.NewPatientBuilder().
    SetId(id).
    SetActive(true)

if hasName {
    builder.AddName(name)
}
if hasAddress {
    builder.AddAddress(address)
}

patient := builder.Build()

Cuándo Usar Literales de Struct

Para un recurso que ya tienes completo, un literal de struct es más corto que cualquiera de los dos y no necesita builder:

patient := &r4.Patient{
    Id:     r4.Ptr(id),
    Active: r4.Ptr(true),
    Name:   []r4.HumanName{name},
}

Ambos estilos producen la misma salida —el builder solo asigna campos en el mismo struct—, así que elige el que se lea mejor donde estés.

Las opciones funcionales eran el tercer estilo, y desaparecen en la v2. Cada With<Recurso><Campo> tenía un método de builder con firma y comportamiento idénticos, así que la v1.6.0 marcó las 11.952 como Deprecated nombrando su reemplazo, y la v2 las eliminó: Set* para los campos simples, Add* para los repetibles.

Si vienes de la v1, staticcheck sobre tu build de v1.6.0 o posterior te lista cada llamada con su reemplazo. Consulta la guía de migración de v1 a v2.

Literales de Struct

Siempre puedes construir recursos directamente usando literales de struct de Go. Esto proporciona el mayor control y es el patron Go mas familiar:

patient := &r4.Patient{
    Id:           ptrTo("patient-789"),
    Active:       ptrTo(true),
    Gender:       ptrTo(r4.AdministrativeGenderMale),
    Name: []r4.HumanName{{
        Family: ptrTo("Johnson"),
        Given:  r4.PtrSlice("Robert"),
    }},
}

resourceType no requiere atención en ninguno de los dos estilos: es un marcador de tamaño cero en el struct, así que un simple r4.Patient{} ya se serializa con el valor correcto. Léelo con GetResourceType().

Última actualización