Form creation
To create new form you need to define Form-assembly and at least 1 layer (schemas from aidbox.sdc
) :
- Formbind all layers in one place
- SDCDocumentcontains questions with answers and other meta data
Other layers you could add as you need some special behavior:
- Form Layoutdefine fields layout and display rules
- Form Launchdefine form init parameters and prepopulate logic.
- Form Finalizedefine additional validations and extractions for form
sign
SDCDocument
Lets define some subset of the Vitals questionaire.
VitalsDocument
{:zen/tags #{zen/schema aidbox.sdc/doc aidbox.sdc/rules},
:type zen/map,
;; define source of original questionaire (optional)
:source {:code "85353-1", :system "http://loinc.org"},
;; title of your document
:zen/desc "Basic Vitals Document",
;; to validate against common document fields you need to confirms sdc/Document
;; document also has common fields: author, patient, encounter
:confirms #{aidbox.sdc/Document},
;; you also can define some rules for your document and also computed fields.
;; (lisp reference see bellow)
:sdc/rules {:bmi (when (and (get :weight) (get :height))
(* (divide (get :weight)
(get :height))
10000))},
;; all fields should be defined under :keys
;; fields are defined with zen types and confirms.
:keys {:weight {:text "Weight",
:confirms #{aidbox.sdc.fhir/quantity},
:units [{:name "kg"}]},
:height {:text "Body height",
:confirms #{aidbox.sdc.fhir/quantity}
:units [{:name "cm"}]},
:bmi {:text "BMI",
:type zen/number}}}
SDC Rules is just are lisp expressions that can be used for two things:
- store temporary value
- calculate document field
To store rule value in SDCDocument give it the same name as the field:
DepressionDocument
{...
:sdc/rules {:phq2-score (+ (get-in [...] ...)
:type zen/map
:keys {:phq2-score {:type zen/integer}} ;; phq2-score will be calculated on-fly and stored in the document
...
}
More on SDCDocument:Document DSL (deprecated) Reference
Form Layout
Form layout defines fields layout for specific SDCDocument
and layout-engine
Default Layout engine is aidbox.sdc/Hiccup
uses DSL in shape of nested objects {:type component-type :children []}
VitalsLayout
{:zen/tags #{aidbox.sdc/Layout}
;; bind form to document
:document VitalsDocument
;; set layout engine (pluggable, default: aidbox.sdc/Hiccup)
:engine aidbox.sdc/Hiccup
;; layout specified according to layout engine
:layout
{:type aidbox.sdc/col,
:children
;; {:bind [:field-name]} used to bind widget to specific field of the document
[{:bind [:loinc-29463-7]}
{:bind [:loinc-8302-2]}
{:bind [:loinc-39156-5]}]}}
More on form layout: Layout DSL (deprecated) Reference
Form Launch
Form Launch
defines parameters schema for aidbox.sdc/launch
rpc and populate logic for SDCDocument
.
If you don't specify this Layer your parameters (for aidbox.sdc/launch
rpc) will be passed as-is to SDCDocument
.
Default populate-engine - aidbox.sdc/LispPopulate
For populate you can specify what fields should be populated.
For that you can use:
- basic edn values
- lisp expressions
- you need to follow SDCDocument fields structure.
VitalsLaunch
{:zen/tags #{aidbox.sdc/Launch}
;; bind to document
:document VitalsDocument
;; specify parameters for launch
:params {:encounter-id {:type zen/string}
:tenant-id {:type zen/string}}
;; set populate engine
:populate-engine aidbox.sdc/LispPopulate
;; populate logic. Define fields in the shape of the document.
:populate {:author (get-in [:ctx :user])
:encounter {:id (get-in [:params :encounter-id])
:resourceType "Encounter"}
:patient (sql {:select [:#> :resource [:subject]]
:from :Encounter
:where [:= :id (get-in [:params :encounter-id])]})}}
More on launch: Launch DSL (deprecated) Reference
Form Finalize
Form Finalize
defines extractions that should be done after document sign
and optionally binds to custom constraint schema for validations.
Default export-engine - aidbox.sdc/LispExport
(see available commands: Lisp (deprecated) Reference)
VitalsFinalize
{:zen/tags #{aidbox.sdc/Finalize zen/schema}
;; bind to document
:document VitalsDocument
;; possible to define custom export engine
:export-engine aidbox.sdc/LispExport
;; describe which resources should be created based on form data
:create [
;; use lisp template to generate observation if field is exists
{:template aidbox.sdc/gen-observation-template
:params {:path [:bmi]} }
;; create observation resource if the field exists
(when (get :height)
{:resourceType "Observation"
:status "final"
:code {:coding [{:code "29463-7"}]}
:subject (get :patient)
:encounter (get :encounter)
:value {:Quantity (get :height)}})
;; decribe other resources to create
,,,]}
Finalize Constraints
The Form gets validated on sign
operation using the document schema. An additional validation profile can be defined within the Finalize layer.
VitalsFinalize
{:zen/tags #{aidbox.sdc/Finalize zen/schema}
;; bind to document
:document VitalsDocument
;; additional validation profile
:profile VitalsFinalizeConstraints
,,,
}
This profile can e.g. declare mandatory fields or set some limitations like min/max for numeric fields etc. The profile is defined via zen schema.
VitalsFinalizeConstraints
{:zen/tags #{zen/schema}
:type zen/map
;; list of mandatory fields
:require #{:bmi :weight :height}
:keys
{;; limit field value to the specified range
:bmi {:type zen/number :min 20, :max 220}
;; denote this field value is required
:weight {:type zen/map :require #{:value}}
;; more validation constraints
,,,
}}}
Form
Form used just to bind all DSLs to one item.
VitalsForm
{:zen/tags #{aidbox.sdc/Form}
;; form title
:title "Vitals Signs"
;; bind to Document
:document VitalsDocument
;; bind to Layout
:layout VitalsLayout
;; bind to Launch
:launch VitalsLaunch
;; bind to Finalize
:finalize VitalsFinalize}
For now you can already try to use created document via aidbox.sdc
Form API (deprecated)