Implementation Features
| Feature | Support | Notes |
|---|
| Compartment Search | ✅ Full | Single resource type or all types (*) |
| GET Search | ✅ Full | Query string parameters |
| POST Search | ✅ Full | Form-urlencoded body |
| CompartmentDefinition Hook | ✅ Full | Automatic membership table updates |
| Temporal Boundaries | ✅ Full | startParam and endParam support |
| Multiple Parameters | ✅ Full | OR logic for membership parameters |
| Dynamic Configuration | ✅ Full | Runtime updates via CompartmentDefinition resources |
| All Search Features | ✅ Full | Includes, pagination, filters work within compartments |
Endpoints
TLQ FHIR supports the standard FHIR compartment search endpoints:
| Scope | GET | POST | Notes |
|---|
| Specific Type | /fhir/{Compartment}/{id}/{ResourceType} | /fhir/{Compartment}/{id}/{ResourceType}/_search | Search one resource type |
| All Types | /fhir/{Compartment}/{id}/* | /fhir/{Compartment}/{id}/_search | Search all compartment types |
Examples:
# Search for Observations in Patient/123's compartment
curl "http://localhost:8080/fhir/Patient/123/Observation?code=http://loinc.org|29463-7"
# Search for all resources in Patient/123's compartment
curl "http://localhost:8080/fhir/Patient/123/*"
# POST-based compartment search
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&status=final"
# All-types compartment search with type filtering
curl "http://localhost:8080/fhir/Patient/123/*?_type=Observation,Condition"
The literal * in the URL path means “all resource types in this
compartment”. For POST searches, use the /_search endpoint without the *.
How Compartments Work
Compartment Membership
Resources belong to a compartment when they reference the compartment resource through specific search parameters. For example:
- Patient Compartment: Resources with
patient, subject, or performer parameters pointing to a Patient
- Encounter Compartment: Resources with
encounter or context parameters pointing to an Encounter
- Device Compartment: Resources with
device or subject parameters pointing to a Device
CompartmentDefinition Resources
TLQ FHIR uses CompartmentDefinition resources to define compartment membership rules. When you create or update a CompartmentDefinition, the server automatically:
- Parses the compartment type (e.g., “Patient”, “Encounter”)
- Extracts resource membership rules from the
resource[] array
- Updates the
compartment_memberships database table
- Enables compartment searches for that compartment type
Example CompartmentDefinition:
{
"resourceType": "CompartmentDefinition",
"id": "patient",
"code": "Patient",
"search": true,
"resource": [
{
"code": "Patient",
"param": ["{def}"]
},
{
"code": "Observation",
"param": ["patient", "performer"]
},
{
"code": "DiagnosticReport",
"param": ["subject"]
},
{
"code": "Account",
"param": ["patient"],
"startParam": "period",
"endParam": "period"
}
]
}
Special Parameter Values
{def}: The compartment resource itself (e.g., Patient in Patient compartment)
- Multiple parameters: OR logic - resource is in compartment if ANY parameter matches
- Empty param array: Resource type is NOT in this compartment
Temporal Boundaries
Some resources have time-based membership using startParam and endParam:
{
"code": "Account",
"param": ["patient"],
"startParam": "period",
"endParam": "period"
}
This means an Account is only in the Patient compartment during its period date range.
Database Schema
TLQ FHIR stores compartment membership rules in the compartment_memberships table:
CREATE TABLE compartment_memberships (
compartment_type VARCHAR(64) NOT NULL, -- e.g., "Patient", "Encounter"
resource_type VARCHAR(64) NOT NULL, -- e.g., "Observation", "Condition"
parameter_names TEXT[] NOT NULL, -- e.g., ["patient", "subject"]
start_param VARCHAR(64), -- Optional temporal boundary
end_param VARCHAR(64), -- Optional temporal boundary
loaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (compartment_type, resource_type)
);
Search Examples
Basic Compartment Search
# Find all Observations for Patient/123
curl "http://localhost:8080/fhir/Patient/123/Observation"
# Find final lab results for Patient/123
curl "http://localhost:8080/fhir/Patient/123/Observation?category=laboratory&status=final"
# Find all resources in Patient/123's compartment
curl "http://localhost:8080/fhir/Patient/123/*"
Advanced Search Features
All standard FHIR search features work within compartments:
# Compartment search with includes
curl "http://localhost:8080/fhir/Patient/123/DiagnosticReport?_include=DiagnosticReport:result"
# Compartment search with pagination
curl "http://localhost:8080/fhir/Patient/123/Observation?_count=10"
# Compartment search with chaining
curl "http://localhost:8080/fhir/Patient/123/DiagnosticReport?result.code=http://loinc.org|33747-0"
# Compartment search with _filter
curl -G "http://localhost:8080/fhir/Patient/123/Observation" \
--data-urlencode '_filter=status eq final and category co laboratory'
# Compartment search with summary
curl "http://localhost:8080/fhir/Patient/123/Observation?_summary=count"
Type Filtering in All-Types Search
# Search specific types in compartment
curl "http://localhost:8080/fhir/Patient/123/*?_type=Observation,Condition,DiagnosticReport"
# Exclude certain types (using _filter)
curl -G "http://localhost:8080/fhir/Patient/123/*" \
--data-urlencode '_filter=not (resourceType eq AuditEvent)'
Managing CompartmentDefinitions
Creating a CompartmentDefinition
curl -X POST "http://localhost:8080/fhir/CompartmentDefinition" \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "CompartmentDefinition",
"id": "encounter",
"code": "Encounter",
"search": true,
"resource": [
{
"code": "Encounter",
"param": ["{def}"]
},
{
"code": "Observation",
"param": ["encounter", "context"]
},
{
"code": "DiagnosticReport",
"param": ["encounter", "context"]
}
]
}'
Updating Compartment Rules
When you update a CompartmentDefinition, TLQ FHIR automatically:
- Clears existing membership rules for that compartment type
- Rebuilds the rules from the updated definition
- Applies changes immediately to new searches
curl -X PUT "http://localhost:8080/fhir/CompartmentDefinition/encounter" \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "CompartmentDefinition",
"id": "encounter",
"code": "Encounter",
"search": true,
"resource": [
{
"code": "Encounter",
"param": ["{def}"]
},
{
"code": "Observation",
"param": ["encounter"]
}
]
}'
Deleting CompartmentDefinitions
Per FHIR spec, servers may continue using compartment definitions even after deletion. TLQ FHIR keeps the membership rules unless explicitly replaced:
# This deletes the CompartmentDefinition resource but keeps the compartment functional
curl -X DELETE "http://localhost:8080/fhir/CompartmentDefinition/encounter"
To fully disable a compartment, create a CompartmentDefinition with an empty resource array.
Configuration
Compartment search can be disabled in the server configuration:
fhir:
interactions:
compartment:
search: false # Disable compartment search endpoints
- Indexing: TLQ FHIR uses GIN indexes on
parameter_names for efficient membership queries
- Caching: Compartment membership rules are loaded once per search and cached
- Query Optimization: The search engine builds optimized SQL queries with proper JOINs
- Resource Types: Searching specific resource types is more efficient than all-types searches
Limitations
- Compartment Instance Validation: TLQ FHIR does not validate that the compartment resource (e.g., Patient/123) exists
- Empty Results: Non-existent compartment instances return empty search results rather than errors
- Temporal Boundaries: Currently stored but not yet fully implemented in search logic
Error Handling
# Unknown compartment type
curl "http://localhost:8080/fhir/UnknownType/123/Observation"
# Returns: 400 Bad Request - Unsupported resource type
# Unknown resource type in compartment
curl "http://localhost:8080/fhir/Patient/123/UnknownType"
# Returns: 400 Bad Request - Unsupported resource type
# Malformed compartment ID
curl "http://localhost:8080/fhir/Patient//Observation"
# Returns: 404 Not Found