The goal of this project is to provide a FHIR® Server with an internal CQL Evaluation Engine which is able to answer population wide aggregate queries in a timely manner to enable interactive, online queries over millions of patients.
- Language: Main language is Clojure with some parts written in Java.
- Build System: Clojure
tools.deps. All build steps are available viaMakefiles. - Modules: Most code is located in
modules/. Each module is structured similarly.- Frontend: A special module
modules/frontendwritten in Svelte.
- Frontend: A special module
- Server: The FHIR Server is built via the top-level
Makefile.
Rigorous adherence to these patterns is required:
- Functional Core: Blaze is primarily implemented using pure functions.
- Error Handling: Use Cognitect Anomalies for error handling. Do not use Exceptions for control flow.
- Component System:
- Use Integrant for wiring components.
- Implement
ig/init-keyandig/halt-key!multimethods. - Define
m/pre-init-specfor dependency validation.
- Specs:
- Every public function must have a spec.
- Location: Specs must never be defined inline in the implementation namespace. There are two distinct spec namespace conventions:
s/def(data/attribute specs) → dot-separated*.specnamespace (e.g.,blaze.db.node.specforblaze.db.node), in aspec.cljfile nested under the namespace directory.s/fdef(function specs) → hyphen-separated*-specnamespace (e.g.,blaze.db.node-specforblaze.db.node), as a sibling file to the implementation.
- Classpath: Public module-level specs go in
src, but inner-module public function specs should be intestto keep the production classpath small.
- Java Interop:
- Avoid reflection.
- Mandatory: Add
(set! *warn-on-reflection* true)to any namespace performing Java interop.
- Async Composition:
- Prefer the
blaze.async.comp/do-syncmacro over threading chains ofblaze.async.comp/then-applywhere feasible. - Always use
blaze.async.comp/then-apply,blaze.async.comp/then-composeand similar in conjunction with the threading macro (->), never as a standalone call.
- Prefer the
- Macros:
- Macros must always be
:refered directly so they can be used without a namespace alias prefix (e.g.,[blaze.async.comp :refer [do-sync]]).
- Macros must always be
- Reuse:
- Avoid code duplication.
- Use existing functions if possible.
- Create a function if code is used more than two times.
- Testing:
- Spec Instrumentation: Always enable spec instrumentation in tests to catch spec violations early.
- Require
[clojure.spec.test.alpha :as st]. - Call
(st/instrument)at the top level of the test namespace.
- Require
- Java Interop: Enable reflection warnings (
(set! *warn-on-reflection* true)) ONLY if the test namespace performs Java interop. - Fixtures: Use the standard test fixture in all test namespaces.
- Require
[blaze.test-util :as tu]. - Call
(test/use-fixtures :each tu/fixture).
- Require
- Assertions: Use the
givenmacro fromjuxt.iotafor asserting map values (e.g. anomalies).- Require
[juxt.iota :refer [given]]. - Example:
(given (my-fn ...) ::anom/category := ::anom/fault ::anom/message := "...") - Use
isonly for simple scalar equality checks that don't involve maps.
- Require
- Async Testing:
- To assert that a
CompletableFuturecompletes exceptionally with an anomaly, usegiven-failed-futurefromblaze.module.test-util— not the(given (ba/try-anomaly (ac/join ...)))pattern. - To obtain the value of a successfully-completed future inside a test, use
@future(Clojure'sderef).
- To assert that a
- Private Functions: Do not call private functions (via
#') from tests. If a function needs to be tested, move it to animplnamespace where it becomes part of the public API of that namespace.
- Spec Instrumentation: Always enable spec instrumentation in tests to catch spec violations early.
- Environment Variables: Every new environment variable introduced via
#blaze/cfginresources/blaze.ednmust be documented indocs/deployment/environment-variables.md, following the existing format (heading, description, default value, since badge).
When starting to work on an issue, you can use the GitHub CLI to fetch the issue details: gh issue view <issue-number>
Before finishing a task, ensure the following commands pass:
- Format:
make fmt - Lint:
make lint(Usesclj-kondo) - Test: Run tests only for the modules you changed:
make -C modules/<module> test(e.g.make -C modules/db test). Usemake testonly when changes span multiple modules or the root. - Coverage:
make test-coverage(Checks for adequate test coverage — must be ≥ 95% forms)
When adding a new module under modules/, also add it to the module matrix in .github/workflows/build.yml (the test job, sorted alphabetically) so CI picks it up.
After verification, when working on an issue:
- Create a feature branch using the GitHub CLI:
gh issue develop <issue-number> --checkout - Commit the changes:
git add .andgit commit- The commit title should be the issue title.
- The commit body should just contain:
Closes: #<issue-number>
- There should be exactly one commit per issue. Multiple changes have to be ammended to the first commit.