Skip to main content

Implementation Features

FeatureSupportNotes
System-level Search✅ FullRequires _type parameter
Type-level Search✅ FullPrimary search form
Compartment Search✅ FullSupports specific type or all types (*)
GET Search✅ FullQuery string parameters
POST Search✅ FullForm-urlencoded body
Parameter Types✅ Fullstring, token, date, number, quantity, reference, uri, text, content
Value Prefixes✅ Fulleq ne gt lt ge le sa eb ap for date/number/quantity/_lastUpdated
Modifiers⚠️ PartialImplemented subset; validated per type + SearchParameter metadata
Special Parameters✅ Full_id, _lastUpdated, _in, _list, _text, _content
Chaining✅ Single-levelsubject.name=peter, subject:Patient.name=peter
Reverse chaining (_has)✅ Full_has:Observation:subject:code=...
Membership Search✅ Full_in and _list parameters
_include / _revinclude✅ FullWildcards (*, Resource:*), :iterate (depth-limited)
_filter (R5-style)✅ FullExpression-based filtering with multiple operators
Pagination✅ Cursor-basedKeyset pagination with _cursor and _cursor_direction
Totals✅ Full_total=accurate, _total=estimate, _total=none
Summary Modes✅ Full_summary=count, _summary=text, _summary=data, _summary=true
_elements✅ FullElement filtering (when _summary not specified)
Sorting⚠️ LimitedOnly _id and _lastUpdated supported
Unknown Parameters✅ LenientIgnored by default; strict mode via Prefer: handling=strict
Composite Parameters❌ Not SupportedFuture work

Endpoints TLQ FHIR implements

ScopeGETPOSTNotes
System-level/fhir/?_type=A,B/fhir/_search_type is required
Type-level/fhir/{resourceType}?…/fhir/{resourceType}/_searchPrimary search form
Compartment/fhir/{Compartment}/{id}/{type}/fhir/{Compartment}/{id}/{type}/_search“All types” uses literal *
Examples:
# Type-level search (GET)
curl "http://localhost:8080/fhir/Patient?name=Doe"

# Type-level search (POST)
curl -X POST "http://localhost:8080/fhir/Patient/_search" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "name=Doe"

# System-level search (GET)
curl "http://localhost:8080/fhir/?_type=Patient,Observation&_count=10"

# System-level search (POST)
curl -X POST "http://localhost:8080/fhir/_search" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "_type=Patient,Observation&_count=10"

# Compartment search (GET) - specific type
curl "http://localhost:8080/fhir/Patient/123/Observation?code=http://loinc.org|29463-7"

# Compartment search (GET) - all types
curl "http://localhost:8080/fhir/Patient/123/*?_type=Observation,Condition"

# Compartment search (POST)
curl -X POST "http://localhost:8080/fhir/Patient/123/Observation/_search" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "code=http://loinc.org|29463-7"
POST-based search must use Content-Type: application/x-www-form-urlencoded. TLQ FHIR merges query string parameters and body parameters into one ordered parameter list.

Parameter occurrence semantics (AND/OR)

TLQ FHIR preserves parameter occurrences in request order (no lossy map parsing):
  • Repeating a parameter is AND: name=John&name=Smith
  • Comma-separated values are OR: name=John,Smith
Examples:
# AND logic: name contains "John" AND name contains "Smith"
curl "http://localhost:8080/fhir/Patient?name=John&name=Smith"

# OR logic: name equals "John" OR "Smith"
curl "http://localhost:8080/fhir/Patient?name=John,Smith"

# Combined: (name=John OR name=Jane) AND gender=male
curl "http://localhost:8080/fhir/Patient?name=John,Jane&gender=male"

Search syntax (modifiers, prefixes, chaining)

Parameter name forms

Most resource parameters follow:
{code}[:{modifier}][.{chain}]=...
  • :{modifier} is case-insensitive (except reference type modifiers like :Patient)
  • .{chain} is single-level chaining (see below)
Want to see which search parameters exist for a resource type? Check the server’s CapabilityStatement: GET /fhir/metadata.

Value prefixes

TLQ supports the standard FHIR prefixes when they appear at the start of the value. Applies to: date, number, quantity, and _lastUpdated.
PrefixMeaning (FHIR-style)Examples
eqequal (default if omitted)birthdate=eq1990-01-01
nenot equalvalue=ne5
gtgreater thanvalue=gt5
gegreater or equaldate=ge2024-01-01
ltless thandate=lt2024-02
leless or equalvalue=le10
sastarts afterdate=sa2024-01-01
ebends beforedate=eb2024-01-01
apapproximately (±10%, min 1 day for dates)date=ap2024-01, value=ap100.0
Notes:
  • Date precision is range-based (2024 matches any date in 2024; 2024-01 matches any date in Jan 2024).
  • For number/quantity, eq/ne respect implied precision (FHIR-style decimal ranges).

Modifiers

TLQ recognizes and validates a subset of FHIR modifiers. A modifier must:
  1. Be valid for the parameter type, and
  2. Be allowed by the underlying SearchParameter metadata (when provided)
Common patterns: | Modifier | Applies to | What it does in TLQ | | ------------------: | --------------------------------- | ----------------------------------------------------------- | -------- | ------------ | | :missing | most indexed parameter types | existence check (true = missing, false = present) | | :exact | string, _text, _content | exact match / phrase search | | :contains | string, uri, some reference | substring match (string/uri); hierarchy closure (reference) | | :text | string, token, reference | text match against human text fields (value/display) | | :code-text | token, reference | match code/id-like parts (case-insensitive starts-with) | | :text-advanced | token, reference | PostgreSQL full-text (websearch_to_tsquery) on display | | :not | token, _in, _list | negation (token set semantics; membership exclusion) | | :identifier | reference | token-style match against Reference.identifier | | :above / :below | reference, uri | hierarchy traversal (reference) / URL path ancestry | | :of-type | token | Identifier triple typeSystem | typeCode | value match | | :{ResourceType} | reference | reference type restriction (e.g. subject:Patient=123) | Examples:
# Existence
curl "http://localhost:8080/fhir/Patient?birthdate:missing=true"

# String modifiers
curl "http://localhost:8080/fhir/Patient?name:exact=John%20Doe"
curl "http://localhost:8080/fhir/Patient?name:contains=doe"

# Token modifiers
curl "http://localhost:8080/fhir/Observation?status:not=final"
curl "http://localhost:8080/fhir/Patient?identifier:of-type=http://hl7.org/fhir/v2/0203|MR|12345"

# Reference modifiers (including type modifier)
curl "http://localhost:8080/fhir/DiagnosticReport?subject:Patient=123"
curl "http://localhost:8080/fhir/DiagnosticReport?subject:identifier=http://acme.example/mrn|123"

# URI hierarchy
curl "http://localhost:8080/fhir/NamingSystem?value:below=http://example.com/system"
Token modifiers :in, :not-in, :above, and :below are rejected (terminology-backed behavior is not implemented yet).

Chaining (single-level)

TLQ supports single-level chaining on reference parameters:
  • Basic chaining: subject.name=peter
  • Type-restricted chaining: subject:Patient.name=peter
Examples:
curl "http://localhost:8080/fhir/DiagnosticReport?subject.name=peter"
curl "http://localhost:8080/fhir/DiagnosticReport?subject:Patient.birthdate=ge1990"

Reverse chaining (_has)

TLQ supports _has (reverse chaining) with the form:
_has:{referringResource}:{referringParam}:{filterParam}={value}
Example:
# Patients that have at least one final Observation with the given LOINC code
curl "http://localhost:8080/fhir/Patient?_has:Observation:subject:code=http://loinc.org|29463-7&_has:Observation:subject:status=final"

What is searchable?

Resources become searchable through SearchParameter resources that define:
  • What to index: FHIRPath expressions extract values from resources
  • How to search: Parameter types determine search semantics
  • Where to store: Each type maps to a dedicated database table

Parameter types and tables

TypeDatabase TableExample Values
stringsearch_stringname=John, name:contains=doe
tokensearch_tokenstatus=active, code=12345
datesearch_datebirthdate=2020-01-01, date=ge2020
numbersearch_numbervalue=5.0, value=lt5.1
quantitysearch_quantityheight=170, height=ge170
referencesearch_referencesubject=Patient/123, subject.name=peter
urisearch_uriurl=http://example.com, url:below=...
textsearch_text_text=diabetes
contentsearch_content_content=diabetes
compositesearch_compositeNot yet supported
Token and quantity parameters also support pipe-delimited forms: system|code (token), and number||code / number|system|code (quantity).
# Token: system|code
curl "http://localhost:8080/fhir/Observation?code=http://loinc.org|29463-7"

# Quantity: number||code (no system)
curl "http://localhost:8080/fhir/Observation?value-quantity=ge5||mg"

# Quantity: number|system|code
curl "http://localhost:8080/fhir/Observation?value-quantity=ge5|http://unitsofmeasure.org|mg"

Unknown or unsupported parameters

By default, TLQ FHIR follows the common “lenient” behavior and ignores unknown/unsupported search parameters. If you want strict validation, use Prefer: handling=strict:
curl -H "Prefer: handling=strict" \
  "http://localhost:8080/fhir/Patient?definitely-not-a-param=1"
This returns an error listing the unknown/unsupported parameters for that resource context.

Advanced search features supported

_include / _revinclude

TLQ FHIR supports _include and _revinclude including:
  • Wildcards (*, Resource:*)
  • :iterate (depth-limited to prevent infinite recursion)
  • Deduplication of included resources
Examples:
# Include related resources
curl "http://localhost:8080/fhir/DiagnosticReport?subject=Patient/123&_include=DiagnosticReport:subject"

# Include with wildcard
curl "http://localhost:8080/fhir/Patient/123?_include=*"

# Reverse include (find resources that reference this one)
curl "http://localhost:8080/fhir/Patient/123?_revinclude=Observation:subject"

# Include with iteration (limited depth)
curl "http://localhost:8080/fhir/DiagnosticReport?subject=Patient/123&_include=DiagnosticReport:subject:iterate"

Membership search: _in and _list

TLQ FHIR supports membership searches (e.g. “resources in Group/List”):
# Find patients in a Group
curl "http://localhost:8080/fhir/Patient?_in=Group/104"

# Exclude patients in a Group
curl "http://localhost:8080/fhir/Patient?_in:not=Group/104"

# Find observations for patients in a Group (chained)
curl "http://localhost:8080/fhir/Observation?subject._in=Group/104"

# Find patients in a List
curl "http://localhost:8080/fhir/Patient?_list=List/105"

_filter (FHIR R5-style expression filter)

TLQ FHIR supports _filter expressions for type-level search (and for system search when a single type is implied). Operators supported include: eq, ne, co, sw, ew, re, gt, lt, ge, le, sa, eb, ap, pr, in, ni, ss, sb. Example (use --data-urlencode so spaces and quotes are encoded correctly):
curl -G "http://localhost:8080/fhir/Patient" \
  --data-urlencode '_filter=name co "doe" and gender eq male'
_filter does not support modifiers (_filter:...) and should not be combined with multi-type system searches. Prefer a type-level search when using _filter.

Pagination (cursor-based)

TLQ FHIR uses keyset/cursor pagination for stable paging over a changing dataset.
  • Control page size with _count
  • Follow Bundle.link URLs (next, prev, first, last) returned by the server
  • Paging links use TLQ FHIR’s internal parameters:
    • _cursor: base64url-encoded lastUpdated,id
    • _cursor_direction: next, prev, or last
Example:
# First page
curl "http://localhost:8080/fhir/Patient?_count=10"

# Next page (use the cursor from Bundle.link[].url in the response)
curl "http://localhost:8080/fhir/Patient?_count=10&_cursor=eyJsYXN0VXBkYXRlZCI6IjIwMjQtMDEtMDEiLCJpZCI6IjEyMyJ9&_cursor_direction=next"
TLQ FHIR parses _offset but does not use it for paging. Pagination links will not include _offset.

Totals and response shaping

_total

TLQ FHIR calculates totals when requested via _total:
  • _total=accurate: compute an exact Bundle.total
  • _total=estimate: allow faster, estimated totals (where possible)
  • _total=none: omit totals entirely
Examples:
curl "http://localhost:8080/fhir/Patient?name=Doe&_total=accurate"
curl "http://localhost:8080/fhir/Patient?name=Doe&_total=estimate"
curl "http://localhost:8080/fhir/Patient?name=Doe&_total=none"

_summary and _elements

TLQ FHIR applies _summary / _elements filtering to Bundle.entry[].resource:
  • _summary=count short-circuits fetching resources and returns only the count bundle
  • _summary takes precedence over _elements
  • Includes are suppressed for _summary=text (common server behavior)
Examples:
curl "http://localhost:8080/fhir/Patient?name=Doe&_summary=count"
curl "http://localhost:8080/fhir/Patient?name=Doe&_summary=text"
curl "http://localhost:8080/fhir/Patient?name=Doe&_elements=id,name,birthdate"
curl "http://localhost:8080/fhir/Patient?name=Doe&_summary=data"
_count=0 is treated as _summary=count (per FHIR search result parameter rules).

Limits and configuration knobs

Search limits are configurable under fhir.search:
  • max_count (default 1000): maximum allowed _count
  • max_total_results (default 10000): maximum allowed _maxresults
  • max_includes (default 10): maximum number of _include + _revinclude
  • max_include_depth (default 3): maximum :iterate depth
  • enable_text / enable_content: enable _text / _content full-text search parameters

Known gaps

Current limitations in TLQ FHIR’s search engine:
  • Recursive chaining (e.g. subject.organization.name) is not supported (single-level only)
  • Composite search parameters are not supported