Search... (alt + k)

FHIR-профилирование на Zen-lang

updated

2022-09-30

zen.fhir - это пространство имен языка zen-lang, которое используется во всех пакетах, сгенерированных инструментом zen-fhir.

zen.fhir расширяет zen/schema, давая возможность описывать специфичные для FHIR вещи, такие как привязки, ссылки, расширения.

В этой секции приведены примеры описания ограничений FHIR на zen.

В примерах используется это пространство имен:

{:ns fhir
 :alias hl7-fhir-r4-core}

Это пространство имен вводит псевдонимы для определений FHIR R4 как просто fhir, что позволит позже заменить этот псевдоним на hl7-fhir-r4b-core или на hl7-fhir-r5-core и, таким образом, перенести свои профили на более новую версию FHIR.

Другой распространенной вещью является свойство :zen.fhir/version схем. Оно определяет, какую версию синтаксиса zen.fhir будет использовать ваша схема. В настоящее время указание версии в схемах является обязательным, текущая версия — :zen.fhir/version "0.5.0". В будущем это свойство может быть объявлено устаревшим с соблюдением обратной совместимости.

Создайте схему с тегом zen.fhir/profile-schema. Эта схема должна содержать :zen.fhir/profileUri, по которому на него будут ссылаться ресурсы в атрибуте meta.profile. Вот пример профиля на тип ресурса Patient:

{:ns MyProfiles
 :import #{zen.fhir fhir}

 MyPatientProfile
 {:zen/tags #{zen/schema zen.fhir/profile-schema}
  :zen.fhir/version "0.5.0"
  :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
  :confirms #{fhir/Patient}}}

Обратите внимание на часть :confirms #{fhir/Patient}, она означает, что данные, которые будут валидироваться на соответствие вашей схеме, также будут проверены на соответствие базовому типу ресурса Patient.

Профиль создается таким же способом, как и на существующий тип ресурса, однако в элементе :confirms необходимо указать схему профиля вместо схемы базового типа ресурса.

MyPatientProfileOnAProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfileOnAProfile"
 :confirms #{MyPatientProfile}}

Если у схемы есть тег zen.fhir/profile-schema, то в ней можно описывать огарничения. Следует понимать, что свойство :confirms не являлется наследованием. Ваша схема не получает неявно никаких свойств из схем, указанных в :confirms. В результате, для описания ограничения вам необходимо явно описать типы и структуру данных. Следующий пример проиллюстрирует это.

В zen-lang, чтобы требовать наличие ключа, вам нужно установить свойство :require. Вот обновленный пример профиля для типа ресурса Patient с обязательными ключами :active и :name:

MyPatientProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
 :confirms #{fhir/Patient}
 :type zen/map
 :require #{:active :name}}

Обратите внимание, что нам пришлось описать :type zen/map, чтобы использовать свойство :require. Ваша схема не наследует неявно :type zen/map от :confirms #{fhir/Patient}. И поскольку :require является свойством типа zen/map, вам необходимо явно указать тип в вашей схеме.

В настоящее время нет возможности запретить использование элемента в zen-lang. Вот ссылка на задачу, чтобы отслеживать её статус.

:type zen/vector предоставляет свойства :minItems и :maxItems. Пример ограничения Patient.name ровно одним элементом:

MyPatientProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
 :confirms #{fhir/Patient}
 :type zen/map
 :require #{:name}
 :keys {:name {:type zen/vector
               :minItems 1
               :maxItems 1}}}

Указание того, что zen/vector имеет минимум 1 элемент, не делает ключ, который хранит это значение, обязательным для присутствия. Нам нужно явно указать, что ключ также требуется.

В профилях FHIR pattern[x] чаще всего используется в срезах. Свойство :match из zen/schema позволяет описать сопоставление с образцом.

Ниже приведен пример определения шаблона для элемента Observation.code, шаблон описывает, что в массиве :coding должен быть хотя бы один объект с ~:system “my-system”~ и ~:code “my-code”~:

MyObservationProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyObservationProfile"
 :confirms #{fhir/Observation}
 :type zen/map
 :keys {:code {:match {:coding #{{:system "my-system", :code "my-code"}}}}}}

Синтаксис сопоставления шаблонов :match представляет собой рекурсивную структуру данных, состоящую из нескольких частей:

  • {} содержит ключи и их шаблоны, примененные к объекту, каждый ключ из {} должен присутствовать в объекте и соответствовать шаблону. Объект может содержать любые дополнительные ключи, не упомянутые в шаблоне.
  • #{} содержит шаблоны, применяемые к массивам, для каждого шаблона из #{} должно быть хотя бы одно совпадение в массиве данных. Массив может содержать любые другие элементы, не соответствующие шаблону.
  • любое другое примитивное значение означает, что данные должны быть постоянным значением

Разбивка приведенного выше примера:

  1. The pattern is {:coding #{{:system "my-system", :code "my-code"}}};
  2. Top level of the pattern is {:coding ...}, it expects data to be an object containing key :coding;
  3. To a value of the key :coding the pattern #{{:system ...}} is applied;
  4. The #{} syntax expects the data to be an array containing at least one match to the pattern {:system "my-system", :code "my-code"};
  5. {:system "my-system", :code "my-code"} expects data to be an object containing keys :system and :code with values “my-system” and “my-code” respectively.

Чтобы определить фиксированное значение, используйте свойство :const из zen/schema, позволяющее описать постоянное значение. Так же, как и шаблоны, value[x] в большинстве случаев используется в срезах, а также для установки URL-адреса расширения. Вместо этого Zen FHIR предлагает расширения первого класса, если вы хотите определить расширение, обратитесь к примеру расширения. Вот пример установки значения элемента Observation.status, которое всегда будет иметь значение final, если оно присутствует:

MyObservationProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyObservationProfile"
 :confirms #{fhir/Observation}
 :type zen/map
 :keys {:status {:const {:value "final"}}}}

Можно сделать слайсинг в схеме с помощью своейства :slicing, которое позволяет валидировать оперделенные элементы массива, используя отдельные схемы для каждой категории элементов. Чтобы указать правила проверки отдельного среза, опишите его в свойстве :slices. Обратите внимание, что каждый слайс должен иметь свойство :filter, которое должно содержать свойство :match. Элемент становится частью определенного слайса, если указанные данные в свойстве :match совпадают с данными элемента.

MyObservation
{:zen/tags #{zen.fhir/profile-schema zen/schema},
 :zen.fhir/profileUri "urn:fhir:Observation"
 :zen.fhir/version "0.5.0"
 :confirms #{fhir/Observation}
 :type zen/map
 :keys {:code {:confirms #{fhir/CodeableConcept}
        :type zen/map
        :keys {:coding
                {:slicing
                 {:type zen/vector
                  :every {:confirms #{fhir/Coding}
                          :slices {"HeartRateCode"
                                   {:schema {:type zen/vector
                                             :minItems 1  
                                             :maxItems 1
                                             :every {:type zen/map
                                                     :keys {:system {:const {:value "http://loinc.org"}
                                                                     :confirms #{fhir/uri}}
                                                            :code   {:const {:value "8867-4"}
                                                                     :confirms #{fhir/code}}
                                                            :require #{:system :code}}}}
                                    :filter {:engine  :match,
                                             :match   {:code "8867-4", :system "http://loinc.org"}}}}}}}}}}}

Если у вас есть схема с тегом zen.fhir/profile-schema, вы можете указать набор значений. Используйте свойство zen.fhir/value-set и укажите существующее имя набора значений в свойстве :symbol. Вам также необходимо указать степень привязки к набору значений в свойстве :strength. Поддерживаемые степени привязки:

  • :required - концепция в этом элементе ДОЛЖНА быть из указанного набора значений.
  • :extensible - понятие в этом элементе ДОЛЖНО быть из указанного набора значений, если любой из кодов в пределах набора значений может применяться к передаваемому концепту. Если набор значений не охватывает концепцию (на основе проверки человеком), вместо этого могут быть включены альтернативные коды (или, если позволяет тип данных, текст).
  • :preferred - поощряется использовать указанные коды для целей взаимодействия, но не обязательно делать это, чтобы считаться соответствующими стандарту.
  • :example - не ожидается и даже не поощряется использование кодов из указанного набора значений. Набор значений просто предоставляет примеры типов понятий, которые должны быть включены.
MyPatientProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
 :confirms #{fhir/Patient}
 :type zen/map
 :keys {:gender {:confirms #{fhir/code},
                 :zen.fhir/value-set {:symbol fhir/administrative-gender,
                                      :strength :required}}

Как было сказано ранее, в zen-lang нет наследования, поэтому для описания ограничения вложенного элемента необходимо описать структуру, содержащую этот элемент. В следующем примере требуется, чтобы Patient.name.given присутствовал и содержал хотя бы один элемент:

MyPatientProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
 :confirms #{fhir/Patient}
 :type zen/map
 :require #{:name}
 :keys {:name {:type zen/vector
               :minItems 1
               :every {:type zen/map
                       :require #{:given}
                       :keys {:given {:type zen/vector
                                      :minItems 1}}}}}}

Zen FHIR предлагает другой подход к расширениям как к первому классу вместо обычного способа FHIR через срезы. Расширения первого класса описываются так же, как и любые другие атрибуты и ограничения, но с добавлением URL-адреса расширения. В следующем примере описывается расширение первого класса us-core-race прямо внутри профиля:

MyPatientProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
 :confirms #{fhir/Patient}
 :type zen/map
 :keys {:race
        {:type zen/map
         :zen/desc "US Core Race Extension",
         :fhir/extensionUri "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race"
         :require #{:text}
         :keys {:ombCategory {:type zen/vector
                              :maxItems 5
                              :every {:confirms #{fhir/Coding}
                                      :zen/desc "American Indian or Alaska Native|Asian|Black or African American|Native Hawaiian or Other Pacific Islander|White"
                                      :zen.fhir/value-set {:symbol omb-race-category-value-set
                                                           :strength :required}}}
                :detailed {:type zen/vector
                           :every {:confirms #{fhir/Coding}
                                   :zen/desc "Extended race codes"
                                   :zen.fhir/value-set {:symbol detailed-race-value-set
                                                        :strength :required}}}
                :text {:confirms #{fhir/string}
                       :zen/desc "Race Text"}}}}}

Обратите внимание, что элементы расширения имеют свойство :confirms для указанного примитивного или сложного типа данных FHIR. Ранее они указывались в схеме базового профиля. Эти :confirms и :fhir/extensionUri необходимы для преобразования формата zen FHIR <-> FHIR.

Структура, определяемая этой схемой, описывает данные такой формы:

resourceType: Patient
id: sample-pt
race:
  category:
  - {system: 'urn:oid:2.16.840.1.113883.6.238', code: 2028-9, display: Asian}
  detailed:
  - {system: 'urn:oid:2.16.840.1.113883.6.238', code: 2029-7, display: Asian Indian}
  text: Asian Indian

Затем его можно преобразовать в формат FHIR, что приведет к следующему результату:

resourceType: Patient
id: sample-pt
extension:
- url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-race
  extension:
  - url: ombCategory
    valueCoding: {system: 'urn:oid:2.16.840.1.113883.6.238', code: 2028-9, display: Asian}
  - url: detailed
    valueCoding: {system: 'urn:oid:2.16.840.1.113883.6.238', code: 2029-7, display: Asian Indian}
  - url: text
    valueString: Asian Indian

Расширения можно помещать в отдельную схему, если вы собираетесь повторно использовать их в разных профилях. Вот профиль us-core-race, обновленный таким образом:

us-core-race
{:zen/tags #{zen/schema zen.fhir/structure-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race"
 :type zen/map
 :require #{:text}
 :keys {:ombCategory {:type zen/vector
                      :maxItems 5
                      :every {:confirms #{fhir/Coding}
                              :zen/desc "American Indian or Alaska Native|Asian|Black or African American|Native Hawaiian or Other Pacific Islander|White"
                              :zen.fhir/value-set {:symbol omb-race-category-value-set
                                                   :strength :required}}}
        :detailed {:type zen/vector
                   :every {:confirms #{fhir/Coding}
                           :zen/desc "Extended race codes"
                           :zen.fhir/value-set {:symbol detailed-race-value-set
                                                :strength :required}}}
        :text {:confirms #{fhir/string}
               :zen/desc "Race Text"}}}

MyPatientProfile
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen.fhir/version "0.5.0"
 :zen.fhir/profileUri "urn:fhir:extension:MyPatientProfile"
 :confirms #{fhir/Patient}
 :type zen/map
 :keys {:race {:confirms #{us-core-race}
               :zen/desc "US Core Race Extension"
               :fhir/extensionUri "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race"}}}

Более сложный пример расширения:

MyPatient
{:zen/tags #{zen/schema zen.fhir/profile-schema}
 :zen/desc "Patient resource schema with first-class extension definition examples"
 :zen.fhir/version "0.5.20"
 :confirms #{zen.fhir/Resource}
 :zen.fhir/type "Patient"
 :zen.fhir/profileUri "urn:profile:MyPatientProfile"
 :type zen/map
 :keys {:meta {:type zen/map
               :keys {:tenant-id
                      {:confirms #{fhir/string}
                       :zen/desc "Patient.meta.tenant-id first-class extension"
                       :fhir/extensionUri "http://tenant-id-extension-url"}}}

        :form {:type zen/vector
               :zen/desc "Patient.form.[*] array first-class extension"
               :every {:confirms #{fhir/uri}
                       :fhir/extensionUri "http://patient-form-url"}}

        :info {:type zen/map
               :zen/desc "Patient.info nested first-class extension"
               :fhir/extensionUri "http://patient-info"
               :keys {:registration {:confirms #{fhir/dateTime}
                                     :zen/desc "Patient.info.registration
                                                extension.url deduced from key"}

                      :referral {:confirms #{fhir/uri}
                                 :fhir/extensionUri "http://patient-info-referral"
                                 :zen/desc "Patient.info.referral
                                            extension.url is specified"}}}}}
Наверх