FHIR Chat · Snapshot versus Differential in FSH · shorthand

Stream: shorthand

Topic: Snapshot versus Differential in FSH


view this post on Zulip Hank Lenzi (Jan 19 2022 at 22:20):

Say I have a full spec (see below, for an Immunization profile template). The question is: is I define the whole spec (by which I mean: all the elements composing the Immunization Resource), then do I have a Snapshot? And if I only define some, then is is what I have a Differential?

// Following the tutorial:  https://www.youtube.com/watch?v=gPt_ZSpZlCc&t=425s
// https://simplifier.net/DevDaysImmunization/ImmunizationProfile/~overview
// Modifies: https://www.hl7.org/fhir/immunization.html
// It seems sushiconfig.yaml already defines a lot of stuff, so how much should we put of metadata here???
// AAAAAHHHH → what sushi-yaml defines are IMPLEMENTATION GUIDE PROPERTIES. IT SAYS SO IN THE FILE ITSELF
// THE AUTHOR OF THE TUTORIAL IS USING ANOTHER TOOL - WE'LL DO AS HE SAYS
Profile: ImmunizationProfile  // Name
Parent: Immunization
Id: immunization-profile
Title: "Immunization profile"
Description: "This profile represents the contraints applied to the RESOURCE Immunization as determined by the medical regulatory authorities"
// metadata: https://www.hl7.org/fhir/structuredefinition.html#metadata

* ^meta.lastUpdated = "2022-02-18T19:37:00.003+00:00"
* ^language = #pt-BR
* ^url = "http://hank.lenzi.55/fhir/StructureDefinition/Immunization"
* ^version = "202201A"
* ^status = #draft // draft | active | retired | unknown See: https://www.hl7.org/fhir/valueset-publication-status.html
* ^experimental = true // SD was drafted for education purposes
* ^date = "2020-03-11T18:20:06.3399184+00:00"
* ^publisher = "Hank Lenzi"
* ^purpose = "Learn FHIR through FSH"
// content = #complete
// contact
// useContext 0..
// jurisdiction 0..
// keyword 0..
// copyright 0..1
// fhirVersion 0..1
// mapping 0..
// kind 1..1 (primitive-type | complex-type | resource | logical)  Type: StructureDefinitionKind // It's implicitely a Resource, becasue the Parent is the RESOURCE  Immunization. This ain't JSON!
// type data Type is a "uri". If it were JSON, you wold say: "type": "Immunization". This is implicit in FSH.
// context 0.. IF AN EXTENSION. This is a PROFILE
// contextInvariant 0..
// derivation - if this were JSON: "derivation": "contraint",
// description (markdown)
// ---------------------------------- END OF COMMON PART FOR STRUCTURE DEFINTIONS --------------------------------------------//
// ---------------------------------------------------------------------------------------------------------------------------//
// NOTE: WHAT YOU HAVE TO MATCH FROM HERE DOWN IS THE "IMMUNIZATION" RESOURCE https://www.hl7.org/fhir/immunization.html
// NOTE: The first item on the Resource Immunization structure is the DomainResource - which is the very Immunization resource.
// NOTE: The Resource Immunization page also duments the TERMINOLOGY BINDINGS for it: https://www.hl7.org/fhir/immunization.html#tx
// NOTE: The following Terminology bindings apply:
// Immunization.status  A set of codes indicating the current status of an Immunization.    Required    ImmunizationStatusCodes
// Immunization.statusReason    The reason why a vaccine was not administered.  Example ImmunizationStatusReasonCodes
// Immunization.vaccineCode The code for vaccine product administered.  Example VaccineAdministeredValueSet
// Immunization.reportOrigin    The source of the data for a record which is not from a primary source. Example ImmunizationOriginCodes
// Immunization.site    The site at which the vaccine was administered. Example CodesForImmunizationSiteOfAdministration
// Immunization.route   The route by which the vaccine was administered.    Example ImmunizationRouteCodes
// Immunization.performer.function  The role a practitioner or organization plays in the immunization event.    Extensible  ImmunizationFunctionCodes
// Immunization.reasonCode  The reason why a vaccine was administered.  Example ImmunizationReasonCodes
// Immunization.subpotentReason The reason why a dose is considered to be subpotent.    Example ImmunizationSubpotentReason
// Immunization.programEligibility  The patient's eligibility for a vaccation program.  Example ImmunizationProgramEligibility
// Immunization.fundingSource   The source of funding used to purchase the vaccine administered.    Example ImmunizationFundingSource
// Immunization.protocolApplied.targetDisease   The vaccine preventable disease the dose is being administered for. Example ImmunizationTargetDiseaseCodes
// EXAMPLE (INSTANCE): See below.
// We just go to the page for the Resource Immunization and copy stuff here
// identifier 0..
// -------------------------------------------- MANDATORY --------------------------------------------------------/
// status 1..1 ?!(←isMOdifier) (completed | entered-in-error | not-done) Type: code Immunization Status Codes
status 1..1
// --------------------------------------------------------------------------------------------------------------/

// statusReason 0..1 Type: CodeableConcept Immunization Status Reason Codes

// -------------------------------------------- MANDATORY --------------------------------------------------------/
// vaccineCode 1..1 Type: CodeableConcept Vaccine Administered Value Set
vaccineCode 1..1
// --------------------------------------------------------------------------------------------------------------/

// -------------------------------------------- MANDATORY --------------------------------------------------------/
// patient 1..1 Type: Reference(Patient)
patient 1..1
// --------------------------------------------------------------------------------------------------------------/

// encounter 0..1 Type: Reference(Encounter)

// -------------------------------------------- MANDATORY --------------------------------------------------------/
// occurrence[x] 1..1
//      +---------------> occurrenceDateTime Type: dateTime
//      +---------------> occurrenceString   Type: string
occurrence[x]
// --------------------------------------------------------------------------------------------------------------/

// recorded 0..1  Type: dateTime
// primarySource 0..1 Type: boolean
// reportOrigin 0..1 CodeableConcept
// location 0..1 Reference(Location)
// manufacturer 0..1 Reference(Organization)
// lotNumber 0..1 Type: string
// expirationDate 0..1 Type: date
// site 0..1 Type: CodeableConcept Codes for Immunization Site of Administration
// route 0..1 Type: CodeableConcept Immunization Route Codes
// doseQuantity 0..1 Type: SimpleQuantity

// ------------------------------    PART OF THE PROFILING SPECIFICATION ----------------------------------------/
// performer 0.. Type: BackboneElement
//      +--------------> function 0..1 Type: CodeableConcept Immunization Function Codes (Extensible)
//      +--------------> actor 1..1 Type: Reference(Practitioner | PractitionerRole | Organization)
* performer 1..1  // there must be a performer
* performer.function 0..1
* performer.actor only Reference(PractitionerRole)  // the performer must be played by the PratictionerRole
// --------------------------------------------------------------------------------------------------------------/

// note 0.. Type: Annotation
// reasonCode 0.. Type: CodeableConcept Immunization Reason Codes
// subpotentReason 0.. CodeableConcept Immunization Subpotent Reason

// ------------------------------    PART OF THE PROFILING SPECIFICATION ----------------------------------------/
// education 0.. Type: BackboneElement
//      +--------------> documentType 0..1 Type: string
//      +--------------> reference 0..1 Type: uri
//      +--------------> publicationDate 0..1 Type: dateTime
//      +--------------> presentationDate 0..1 Type: dateTime
* education 0..0
// --------------------------------------------------------------------------------------------------------------/

// programEligibility 0.. CodeableConcept Immunization Program Eligibility
// fundingSource 0..1 //      +--------------> Type: CodeableConcept Immunization Funding Source

// ------------------------------    PART OF THE PROFILING SPECIFICATION ----------------------------------------/
// reaction     0..*    BackboneElement
//      +-------------->  data      0..1    dateTime
//      +-------------->  detail    0..1    Reference(Observation)
//      +-------------->  reported  0..1    boolean
// --------------------------------------------------------------------------------------------------------------/

// protocolApplied  0..*    BackboneElement
//      +--------------> series         0..1    string
//      +--------------> authority      0..1    Reference(Organization)
//      +--------------> targetDisease  0..*    CodeableConcept Immunization Target Disease Codes
//      +--------------> doseNumber[x] 1..1
//                             +--------------> doseNumberPositiveInt   positiveInt
//                             +--------------> doseNumberString        string
//      +--------------> seriesDoses[x] 0..1
//                             +--------------> seriesDosesPositiveInt positiveInt
//                             +--------------> seriesDosesString string
//

Thanks.
-- Hank

view this post on Zulip Chris Moesel (Jan 19 2022 at 23:23):

Hi @Hank Lenzi. I'm not sure if I fully understood your question, but basically:

The differential should contain only those things that are different from the parent. For example, if you change a cardinality from 0..1 to 1..1 then the differential will contain that element (by id and path) with the new min value of 1. It does not need to contain anything else. Some authors/tools may put unchanged data in the differential, but this is generally not necessary (except in some very limited edge cases where the IG Publisher needs it).

The snapshot contains every element in the structure with all the properties that were defined on each element. It also reflects any of the changed values (from the differential) alongside all the unchanged values. The snapshot is helpful for tooling that wants the whole picture.

So, in FSH, when you define profiles, you're usually specifying only what goes in the differential (w/ the exception of top-level properties like ^publisher, ^purpose, etc. that sit outside of the snapshot and differential). When you run SUSHI, it will generate only the differential elements by default. And then when you run the IG Publisher, it will generate the snapshot elements by merging the differential elements into the parent definition. Does that help?

view this post on Zulip Hank Lenzi (Jan 20 2022 at 11:45):

Gotcha! Thanks!


Last updated: Apr 12 2022 at 19:14 UTC