-Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
-(person, visit_occurrence, condition_occurrence, drug_exposure,
-procedure_occurrence, measurement, observation).
-
-Resource support is intentionally limited to the OMOP tables returned by
-this endpoint:
-- `Patient` -> `person`
+Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+grouped by destination table in `tables`.
+
+Current resource coverage:
+- `Patient` -> `person`; `deceased[x]` can also produce `death`, and the
+ first address can produce `location`
+- `observation_period` -> one derived row per person with dated visit,
+ clinical, or death rows, spanning those dates
+- `Location` -> `location` and `care_site`
+- `Organization` -> `care_site`; its first address can produce `location`
+- `HealthcareService` -> `care_site`
+- `Practitioner` and `PractitionerRole` -> `provider`
- `Encounter` -> `visit_occurrence`
- `Condition` -> `condition_occurrence`
- `Procedure` -> `procedure_occurrence`
- `MedicationRequest`, `MedicationStatement`, and
`MedicationAdministration` -> `drug_exposure`
- `Immunization` -> `drug_exposure`
-- `Observation` with a numeric `valueQuantity`, `valueInteger`, or
- numeric-looking `valueString` (for example `"<2"`) -> `measurement`
-- non-numeric `Observation` -> `observation`
+- `Observation` -> `measurement` or `observation`. For coded
+ Observations, the resolved OMOP concept domain selects the table; value
+ form only breaks ties. For text-only Observations, numeric values route
+ to `measurement` and nonnumeric values to `observation`.
- `AllergyIntolerance` -> `observation`
-`Medication` is supported only as reference data for medication
-resources; it is not emitted as its own row because OMOP CDM has no
-Medication table. Other reference/admin resources such as `Practitioner`,
-`Organization`, `Location`, `Coverage`, and `Claim`, and clinical
-workflow/document resources such as `DiagnosticReport`, `ServiceRequest`,
-`CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and
-`DeviceUseStatement`, are currently accepted in a Bundle but are not
-shaped into OMOP rows. Unsupported resource types are ignored rather than
-listed under `dropped`; `dropped` is reserved for supported resource types
-that were missing the subject/patient, code, or medication reference data
-needed to produce a valid row.
-
-Each resource's primary clinical coding is resolved to a standard OMOP
-`concept_id`. Alongside the OMOP rows grouped by table (`tables`), the
-response carries `mappings` (how each source coding resolved, linked back
-to the row it produced), `dropped` (resources that could not be shaped
-into a row), `vocab_version` (the OMOP vocabulary release codes were
-resolved against), and a small `summary` of the resolution outcomes.
+`Medication` is reference data for medication resources; it does not
+create its own row because OMOP CDM has no Medication table. Administrative
+linkages (provider, care site, and location) are best-effort and limited to
+references supplied in the request. Their supporting concepts, including
+provider specialty, country, and place of service, are not mapped.
+
+`DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,
+`Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and
+other unsupported resource types are accepted in a Bundle but ignored: they
+create no row and no `dropped` entry. `dropped` is reserved for supported
+row-producing resources that could not be shaped because the subject/patient,
+clinical code/text, or medication data was not usable. A single-Patient
+Bundle can attribute a supported clinical resource with a missing or
+unresolvable subject to that sole person; in a multi-Patient Bundle, that
+resource is dropped instead.
+
+Coded Observation routing is selected from the resolved OMOP concept
+domain. Numeric and nonnumeric `value[x]` forms establish the preferred
+target only when the code is valid for both tables. A text-only
+Observation has no resolver target, so numeric values route to
+`measurement` and nonnumeric values to `observation`. Numeric values
+populate `value_as_number` in the selected row; nonnumeric values
+populate `value_as_string` for an `observation` or `value_source_value`
+for a `measurement`. `valueCodeableConcept` remains source text and does
+not populate `value_as_concept_id`; other unsupported `value[x]` forms
+and Observation components do not populate separate converted values. A
+numeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a
+measurement's `operator_concept_id`; units remain source text and have
+`unit_concept_id` of `0`.
+
+A single standard OMOP `concept_id` is selected for each clinical row
+after considering all of the resource's supplied codings. Alongside the
+OMOP rows grouped by table (`tables`), the response carries `mappings`
+(an entry for every source coding, linked back to the row it produced),
+`dropped` (resources that could not be shaped into a row),
+`vocab_version` (the OMOP vocabulary release codes were resolved
+against), and a small `summary` of the resolution outcomes.
A `concept_id` of `0` is reported, not omitted (OMOP "no matching
concept" semantics): it covers both a coding with no standard match
(`UNMAPPED`) and an unverified suggestion for a text-only resource
-(`UNCHECKED`). Only the primary clinical coding is resolved, so
-`gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are
-always `0`; the one populated non-resolved concept is measurement
+(`UNCHECKED`). Demographic, visit, categorical-value, and unit concept
+fields currently remain `0`; the one populated non-resolved concept is
+measurement
`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)
-rather than the resolver. Each `*_source_value` carries the verbatim FHIR
-coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).
+rather than terminology resolution. Clinical `*_source_value` fields
+preserve the selected FHIR coding (`system#code`, or `code` when no
+system is supplied), falling back to source text for text-only resources.
+Other `*_source_value` fields preserve row-specific raw source values,
+such as resource identifiers, names, units, or status codes, and
+`*_type_concept_id` is set to `32817` (EHR).
Medication codes are resolved whether they appear inline
(`medicationCodeableConcept`) or via a `medicationReference` to a contained,
@@ -3254,8 +3283,18 @@ relative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource.
Resources that cannot be shaped into a row — a medication with no usable
code, resolvable reference, or display, or any clinical resource whose
subject/patient reference cannot be tied to a person — are reported under
-`dropped` rather than emitted as blank rows. The
-bundle must contain at least one Patient resource.
+`dropped` rather than emitted as blank rows. The Bundle must contain at
+least one Patient resource.
+
+All row IDs start at `1` for each request and are not stable or global.
+For clinical conversion rows whose resource supplies an `id`, `mappings`
+associates each row with that source FHIR resource ID. A `person` row
+retains the Patient ID or its first identifier value in
+`person_source_value`, when present; other reference and derived rows do
+not uniformly carry a FHIR resource ID. Input resources without those
+source identifiers cannot be correlated across responses from the
+returned rows alone. Consumers combining responses need to establish
+their own stable keys and remap every primary and foreign key together.
@@ -3347,11 +3386,12 @@ client.fhir2Omop().create(
FHIR resources (single resource or Bundle). Must contain at least one
Patient resource. Supported row-producing resources are Patient,
-Encounter, Condition, Procedure, MedicationRequest,
+Location, Organization, HealthcareService, Practitioner,
+PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
MedicationStatement, MedicationAdministration, Immunization,
Observation, and AllergyIntolerance. Standalone Medication resources
are consumed by medication references rather than mapped to their own
-table. Other resource types are accepted but ignored.
+table. Unsupported resource types are accepted in a Bundle but ignored.
@@ -4023,11 +4063,9 @@ client.implementationGuides().implementationGuides().update(
-Deletes the stored metadata for an implementation guide — its
-profile_context and timestamps. Member profiles keep their
-implementation_guide assignment, so a guide still referenced by at least
-one profile continues to appear in listings, just without context or
-timestamps.
+Deletes the stored name-level metadata and any exact canonical package
+versions beneath the guide. Legacy member profile assignments are not
+changed.
+
+Publishes an exact package beneath this guide family. PR 2 temporarily
+permits one exact package version per guide family; publishing another
+version returns `409 Conflict` until multi-version package support lands.
+
+
+**version:** `String` — The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+
+
+
+
+
+
@@ -4129,7 +4310,7 @@ client.lang2Fhir().create(
-**resource:** `CreateRequestResource` — Type of FHIR resource to create. Use 'auto' for automatic resource type detection, or specify a supported US Core profile. Recommended to use the supported US Core Profiles for validated results but you can also use any custom profile you've uploaded (if you're a develop or launch customer)
+**resource:** `CreateRequestResource` — Type of FHIR resource to create. Use 'auto' for automatic resource type detection, or specify a supported profile. The default profile set includes US Core profiles and selected base R4 resources; you can also use any custom profile you've uploaded (if you're a develop or launch customer).
-**implementationGuide:** `Optional` — Custom Implementation Guide name. When specified, profiles from this IG are included alongside US Core profiles during resource detection. US Core is always the base layer; custom IG profiles are additive.
+**implementationGuide:** `Optional` — Custom Implementation Guide name. When specified, profiles from this IG are included alongside the default profiles during resource detection. Default profiles are always the base layer; custom IG profiles are additive.
-Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.
+Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.
**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.
@@ -4455,7 +4644,7 @@ client.lang2Fhir().document(
.builder()
.version("R4")
.resource("questionnaire")
- .content("JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)")
+ .content("JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)")
.build()
);
```
@@ -4491,8 +4680,11 @@ client.lang2Fhir().document(
**content:** `String`
Base64 encoded file content.
-Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
@@ -4524,7 +4716,7 @@ File type is auto-detected from content magic bytes.
-Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,
+Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,
returned as a transaction Bundle. Combines document text extraction with multi-resource detection.
Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.
Resources are linked with proper references (e.g., Conditions reference the Patient).
@@ -4550,7 +4742,7 @@ client.lang2Fhir().documentMulti(
DocumentMultiRequest
.builder()
.version("R4")
- .content("JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)")
+ .content("JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)")
.provider("medplum")
.config(
DocumentConfig
@@ -4602,8 +4794,11 @@ client.lang2Fhir().documentMulti(
**content:** `String`
Base64 encoded file content.
-Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
@@ -4619,7 +4814,15 @@ File type is auto-detected from content magic bytes.
+
+**patientReference:** `Optional` — Deprecated compatibility alias for primary_patient.identifier. Cannot be combined with primary_patient.
@@ -4627,7 +4830,7 @@ File type is auto-detected from content magic bytes.
-**implementationGuide:** `Optional` — Custom Implementation Guide name. When specified, profiles from this IG are included alongside US Core profiles during resource detection. US Core is always the base layer; custom IG profiles are additive.
+**implementationGuide:** `Optional` — Custom Implementation Guide name. When specified, profiles from this IG are included alongside the default profiles during resource detection. Default profiles are always the base layer; custom IG profiles are additive.
@@ -4663,8 +4866,8 @@ File type is auto-detected from content magic bytes.
-## Profiles
-client.profiles.profiles.list() -> ProfileListResponse
+## Lang2FhirBatch
+client.lang2FhirBatch.list() -> JobListResponse
@@ -4676,14 +4879,10 @@ File type is auto-detected from content magic bytes.
-Returns metadata for every custom (uploaded) FHIR profile on this
-instance, across all implementation guides. The full StructureDefinition
-JSON is omitted from each entry; fetch a single profile by id to retrieve it.
-
-The `url` query parameter filters by canonical URL. The canonical URL is the
-stable key other platform features use to reference a profile (FHIR's
-`meta.profile`, `baseDefinition`), since StructureDefinition ids are only
-unique within a package. A non-matching filter returns an empty list, not a 404.
+Returns a page of the instance's batch jobs, newest first, without
+per-job counts. Jobs are shared across the instance's credentials, so
+this lists every batch job on the instance, not just the calling
+credential's.
@@ -4698,10 +4897,11 @@ unique within a package. A non-matching filter returns an empty list, not a 404.
-**url:** `Optional` — Filter by canonical URL. Accepts the FHIR pinned form `url|version` (split on the last `|`); the bare form matches the current version.
+**cursor:** `Optional` — Opaque pagination cursor from a previous page's next_cursor.
+
+
+
+
+
+
+
+**limit:** `Optional` — Page size. Defaults to 20; values above 100 are clamped to 100.
-Creates a custom profile from a FHIR StructureDefinition supplied as a JSON
-object. Metadata such as version, resource type, and url is read from the
-StructureDefinition; the lowercase StructureDefinition id becomes the
-profile's lookup key. When id is omitted, a random UUID is assigned. Code
-system configuration is auto-extracted from the snapshot. Optionally group
-the profile under a named implementation guide.
+Opens an empty batch job. Items arrive on later upload calls and the set
+is sealed at finalize.
+
+Supplying `request_id` makes the create idempotent on that token: a
+retried submit whose response was lost returns the original job rather
+than opening a second one. This dedupe is scoped to the calling
+credential. A `request_id` whose job was canceled or failed before it
+finalized is released for a fresh replay; once a job is finalized, its
+`request_id` keeps resolving to it even after cancellation.
+
+There is no limit on how many jobs an instance may hold at once; how many
+items run in parallel is a property of the instance, not of the job count.
@@ -4762,14 +4976,10 @@ the profile under a named implementation guide.
-**request:** `ProfileUploadRequest`
+**requestId:** `Optional`
+
+Optional client idempotency token (at most 256 UTF-8 bytes). A
+retried create with the same token returns the original job instead
+of opening a second one.
-Returns a single custom profile by id, including its full StructureDefinition JSON.
+Stores one item of a job from a multipart upload. A batch's items arrive
+one per request. The item carries **either** a `document` extraction
+(whose input file rides as raw bytes in the `file` part) **or** a
+`create` extraction (JSON only, no file).
+
+The upload enforces these rules:
+- Set **exactly one** of `document` or `create`. Setting both, or
+ neither, is a `400`.
+- When `document` is set, `file` is **required** — it supplies the
+ document's file content (PDF, image, RTF, or XML/C-CDA).
+- When `create` is set, `file` is **forbidden** — a create item carries
+ no file.
+- `document` and `create` must each be a JSON **object**.
+
+Only the item's structure is checked here: the fields inside `document`
+or `create` are not validated at upload. A body that is well-formed JSON
+but not a valid request for its endpoint is still accepted with `202`
+and fails later during processing, recorded as an item `error`. A
+wrong-typed field the endpoint cannot decode fails as `invalid_input`; a
+body that decodes but the pipeline rejects (for example, a missing
+required field) fails as `processing_failed`.
+
+Supplying `request_id` makes the upload idempotent on that token. A
+re-upload under the same token overwrites the same item rather than
+adding a second, so a client that lost an upload's response can safely
+re-send it. The response's `deduplicated` is `true` only when the
+re-uploaded payload matches the one already stored; a same-token upload
+with a changed payload overwrites in place and returns `false`.
+
+Set a `request_id` on **every** upload: re-sending under the same token
+is the only way to repair a lost or incomplete upload, including the one
+a finalize `409` reports. Without one, a re-send adds a new item instead
+of replacing the missing one, and the job cannot be finalized.
+
+Uploads are rejected once the job has been finalized (`409`), once it
+holds its 500-item limit (`409`), or when the item is too large (`413` —
+see the raw-file limit in the API description).
@@ -4825,7 +5075,13 @@ Returns a single custom profile by id, including its full StructureDefinition JS
-Replaces an existing custom profile with a new StructureDefinition. The
-`id` path parameter is authoritative: if the StructureDefinition includes
-an `id` it must match the path parameter, and if it omits one the path
-parameter is used. The FHIR resource type of the profile cannot change.
-Code system configuration is
-re-derived from the new StructureDefinition. When `implementation_guide` is
-omitted, the profile keeps its existing implementation guide. The instance
-stores a single version per canonical URL, so this replaces it in place.
+Seals the job's item set and starts processing. Takes no request body.
+Finalize is idempotent: a retried finalize succeeds again.
+
+If a previous upload did not complete, finalize returns a `409`; re-send
+the missing upload (with the same `request_id`), then finalize.
+Finalizing a job with no items is a `400`.
@@ -4886,17 +5140,7 @@ stores a single version per canonical URL, so this replaces it in place.
-Permanently deletes a custom profile by id.
+Drives a job to the terminal `canceled` state on request. Takes no
+request body.
+
+Cancel does not delete the job: the job record and any results already
+produced are preserved for the normal retention window, the same as a
+`completed` or `failed` job. Items stop being processed and keep the state
+they held at cancellation, so a canceled job's `counts` may show
+unfinished items that never resolve.
+
+Cancel is idempotent: canceling an already-`canceled` job returns `200`
+with the job. Canceling a job that has already `completed` or `failed` is
+a `409`.
@@ -4958,7 +5205,7 @@ Permanently deletes a custom profile by id.
+
+Returns a job's record, its per-status item counts, and one page of
+per-item statuses.
+
+Items are listed in a stable order that is not upload order and is the
+same across pages. Match each entry to your own records by its `id`
+(your correlation label) or `item_id` (from the upload response),
+never by position.
+
+
+A lighter status page. Returns the same per-item status entries as
+`GET /lang2fhir/batch/{job_id}`, but without the job record or counts,
+and the entries carry `result_size` rather than any result content. Use
+each entry's `item_id` to fetch that item's result from
+`GET /lang2fhir/batch/{job_id}/results/{item_id}`.
+
+Entries are listed in a stable order that is not upload order and is
+the same across pages. Match each entry to your own records by its `id`
+(your correlation label) or `item_id` (from the upload response),
+never by position.
+
+
+Streams one item's stored result bytes verbatim as `application/json`.
+The body is the response the item's synchronous multi endpoint would have
+returned — a `DocumentMultiResponse` for a document item or a
+`CreateMultiResponse` for a create item.
+
+Only a succeeded item has a result: an item that has not succeeded
+(pending, processing, or failed) is a `409`, and a result that has
+expired is a `404`.
+
+
+Returns metadata for every custom (uploaded) FHIR profile on this
+instance, across all implementation guides. The full StructureDefinition
+JSON is omitted from each entry; fetch a single profile by id to retrieve it.
+
+The `url` query parameter filters by canonical URL. The canonical URL is the
+stable key other platform features use to reference a profile (FHIR's
+`meta.profile`, `baseDefinition`), since StructureDefinition ids are only
+unique within a package. An unpinned `url` filter returns metadata for
+the profile's current StructureDefinition. Pinned `url|version` filters
+resolve a retained version when present; otherwise they can fall back to
+the profile's current StructureDefinition, whose content can change
+through the profile update endpoint. A non-matching filter returns an
+empty list, not a 404.
+
+
+**url:** `Optional` — Filter by canonical URL. Accepts the FHIR pinned form `url|version`; without a version pin, returns the profile's current StructureDefinition metadata.
+
+
+
+Creates a custom profile from a FHIR StructureDefinition supplied as a JSON
+object. Metadata such as version, resource type, and url is read from the
+StructureDefinition; the lowercase StructureDefinition id becomes the
+profile's lookup key. When id is omitted, a random UUID is assigned.
+Optionally group the profile under a named implementation guide.
+
+
+Replaces an existing custom profile with a new StructureDefinition. The
+`id` path parameter is authoritative: if the StructureDefinition includes
+an `id` it must match the path parameter, and if it omits one the path
+parameter is used. The FHIR resource type of the profile cannot change.
+When `implementation_guide` is omitted, the profile keeps its existing
+implementation guide. A retained version string is allowed only when
+re-submitting the profile's current version with an unchanged
+StructureDefinition; otherwise it returns a conflict. While the profile
+has retained versions, its
+canonical URL cannot be changed.
+
+
+**id:** `String` — The lowercase StructureDefinition id of the custom profile.
+
+
+
+
+
+
+
+**request:** `ProfileUploadRequest`
+
+
+
+
+
+
+
+
+
+
+
+client.profiles.profiles.delete(id)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Permanently deletes a custom profile by id. This also deletes all retained
+versions for that profile so the canonical URL can be reused by a later
+upload.
+
+
+Adds an immutable StructureDefinition version to a custom profile. If
+the profile does not exist, it is created from the submitted version.
+The StructureDefinition must include a non-empty `version`; its
+canonical URL and resource type must match the profile when one already
+exists. If it includes an `id`, that id must match the path parameter;
+if it omits `id`, the path parameter is used. Profiles created through
+this endpoint are grouped under `custom`. Posting the profile's current
+StructureDefinition unchanged retains it as a version.
+Version strings may contain letters, numbers, and the punctuation
+characters `.`, `_`, `~`, `+`, and `-`; they cannot be exactly `.` or
+`..`. Each profile can retain up to 250 versions; delete old
+versions before adding more.
+
+
+Returns metadata and the full StructureDefinition for one retained
+version. The returned StructureDefinition's id is the profile id. The
+path version is the authored `StructureDefinition.version` value.
+
+
+**id:** `String` — The lowercase StructureDefinition id of the custom profile.
+
+
+
+
+
+
+
+**version:** `String` — The authored StructureDefinition.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+
+
+**id:** `String` — The lowercase StructureDefinition id of the custom profile.
+
+
+
+
+
+
+
+**version:** `String` — The authored StructureDefinition.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
diff --git a/src/main/java/com/phenoml/api/AsyncPhenomlClient.java b/src/main/java/com/phenoml/api/AsyncPhenomlClient.java
index 68d40177..513815c4 100644
--- a/src/main/java/com/phenoml/api/AsyncPhenomlClient.java
+++ b/src/main/java/com/phenoml/api/AsyncPhenomlClient.java
@@ -14,6 +14,7 @@
import com.phenoml.api.resources.fhirprovider.AsyncFhirProviderClient;
import com.phenoml.api.resources.implementationguides.AsyncImplementationGuidesClient;
import com.phenoml.api.resources.lang2fhir.AsyncLang2FhirClient;
+import com.phenoml.api.resources.lang2fhirbatch.AsyncLang2FhirBatchClient;
import com.phenoml.api.resources.profiles.AsyncProfilesClient;
import com.phenoml.api.resources.summary.AsyncSummaryClient;
import com.phenoml.api.resources.tools.AsyncToolsClient;
@@ -42,6 +43,8 @@ public class AsyncPhenomlClient {
protected final Supplier lang2FhirClient;
+ protected final Supplier lang2FhirBatchClient;
+
protected final Supplier profilesClient;
protected final Supplier summaryClient;
@@ -63,6 +66,7 @@ public AsyncPhenomlClient(ClientOptions clientOptions) {
this.fhirProviderClient = Suppliers.memoize(() -> new AsyncFhirProviderClient(clientOptions));
this.implementationGuidesClient = Suppliers.memoize(() -> new AsyncImplementationGuidesClient(clientOptions));
this.lang2FhirClient = Suppliers.memoize(() -> new AsyncLang2FhirClient(clientOptions));
+ this.lang2FhirBatchClient = Suppliers.memoize(() -> new AsyncLang2FhirBatchClient(clientOptions));
this.profilesClient = Suppliers.memoize(() -> new AsyncProfilesClient(clientOptions));
this.summaryClient = Suppliers.memoize(() -> new AsyncSummaryClient(clientOptions));
this.toolsClient = Suppliers.memoize(() -> new AsyncToolsClient(clientOptions));
@@ -106,6 +110,10 @@ public AsyncLang2FhirClient lang2Fhir() {
return this.lang2FhirClient.get();
}
+ public AsyncLang2FhirBatchClient lang2FhirBatch() {
+ return this.lang2FhirBatchClient.get();
+ }
+
public AsyncProfilesClient profiles() {
return this.profilesClient.get();
}
diff --git a/src/main/java/com/phenoml/api/AsyncPhenomlClientBuilder.java b/src/main/java/com/phenoml/api/AsyncPhenomlClientBuilder.java
index 6ef67046..d6d4fc9c 100644
--- a/src/main/java/com/phenoml/api/AsyncPhenomlClientBuilder.java
+++ b/src/main/java/com/phenoml/api/AsyncPhenomlClientBuilder.java
@@ -176,7 +176,15 @@ protected ClientOptions buildClientOptions() {
protected void setEnvironment(ClientOptions.Builder builder) {
if (this.instanceUrl != null) {
String _instanceUrl = this.instanceUrl != null ? this.instanceUrl : "experiment.app.pheno.ml";
- this.environment = Environment.custom("https://{instanceUrl}".replace("{instanceUrl}", _instanceUrl));
+ String _urlTemplate = null;
+ if (this.environment == null) {
+ _urlTemplate = "https://{instanceUrl}";
+ } else if (this.environment.equals(Environment.DEFAULT)) {
+ _urlTemplate = "https://{instanceUrl}";
+ }
+ if (_urlTemplate != null) {
+ this.environment = Environment.custom(_urlTemplate.replace("{instanceUrl}", _instanceUrl));
+ }
}
builder.environment(this.environment);
}
@@ -314,30 +322,18 @@ public static final class _CredentialsAuth extends AsyncPhenomlClientBuilder {
private final String clientSecret;
- private Optional grantType = Optional.empty();
-
_CredentialsAuth(String clientId, String clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
}
- public _CredentialsAuth grantType(Optional grantType) {
- this.grantType = grantType;
- return this;
- }
-
- public _CredentialsAuth grantType(String grantType) {
- this.grantType = Optional.ofNullable(grantType);
- return this;
- }
-
@Override
public AsyncPhenomlClient build() {
validateConfiguration();
ClientOptions baseOptions = buildClientOptions();
AuthtokenClient authClient = new AuthtokenClient(baseOptions);
OAuthTokenSupplier oAuthTokenSupplier =
- new OAuthTokenSupplier(this.clientId, this.clientSecret, this.grantType, authClient);
+ new OAuthTokenSupplier(this.clientId, this.clientSecret, authClient);
ClientOptions finalOptions = ClientOptions.Builder.from(baseOptions)
.addHeader("Authorization", oAuthTokenSupplier)
.build();
diff --git a/src/main/java/com/phenoml/api/PhenomlClient.java b/src/main/java/com/phenoml/api/PhenomlClient.java
index 8a12aeb9..c96e61bc 100644
--- a/src/main/java/com/phenoml/api/PhenomlClient.java
+++ b/src/main/java/com/phenoml/api/PhenomlClient.java
@@ -14,6 +14,7 @@
import com.phenoml.api.resources.fhirprovider.FhirProviderClient;
import com.phenoml.api.resources.implementationguides.ImplementationGuidesClient;
import com.phenoml.api.resources.lang2fhir.Lang2FhirClient;
+import com.phenoml.api.resources.lang2fhirbatch.Lang2FhirBatchClient;
import com.phenoml.api.resources.profiles.ProfilesClient;
import com.phenoml.api.resources.summary.SummaryClient;
import com.phenoml.api.resources.tools.ToolsClient;
@@ -42,6 +43,8 @@ public class PhenomlClient {
protected final Supplier lang2FhirClient;
+ protected final Supplier lang2FhirBatchClient;
+
protected final Supplier profilesClient;
protected final Supplier summaryClient;
@@ -63,6 +66,7 @@ public PhenomlClient(ClientOptions clientOptions) {
this.fhirProviderClient = Suppliers.memoize(() -> new FhirProviderClient(clientOptions));
this.implementationGuidesClient = Suppliers.memoize(() -> new ImplementationGuidesClient(clientOptions));
this.lang2FhirClient = Suppliers.memoize(() -> new Lang2FhirClient(clientOptions));
+ this.lang2FhirBatchClient = Suppliers.memoize(() -> new Lang2FhirBatchClient(clientOptions));
this.profilesClient = Suppliers.memoize(() -> new ProfilesClient(clientOptions));
this.summaryClient = Suppliers.memoize(() -> new SummaryClient(clientOptions));
this.toolsClient = Suppliers.memoize(() -> new ToolsClient(clientOptions));
@@ -106,6 +110,10 @@ public Lang2FhirClient lang2Fhir() {
return this.lang2FhirClient.get();
}
+ public Lang2FhirBatchClient lang2FhirBatch() {
+ return this.lang2FhirBatchClient.get();
+ }
+
public ProfilesClient profiles() {
return this.profilesClient.get();
}
diff --git a/src/main/java/com/phenoml/api/PhenomlClientBuilder.java b/src/main/java/com/phenoml/api/PhenomlClientBuilder.java
index 00d898be..42b2db88 100644
--- a/src/main/java/com/phenoml/api/PhenomlClientBuilder.java
+++ b/src/main/java/com/phenoml/api/PhenomlClientBuilder.java
@@ -176,7 +176,15 @@ protected ClientOptions buildClientOptions() {
protected void setEnvironment(ClientOptions.Builder builder) {
if (this.instanceUrl != null) {
String _instanceUrl = this.instanceUrl != null ? this.instanceUrl : "experiment.app.pheno.ml";
- this.environment = Environment.custom("https://{instanceUrl}".replace("{instanceUrl}", _instanceUrl));
+ String _urlTemplate = null;
+ if (this.environment == null) {
+ _urlTemplate = "https://{instanceUrl}";
+ } else if (this.environment.equals(Environment.DEFAULT)) {
+ _urlTemplate = "https://{instanceUrl}";
+ }
+ if (_urlTemplate != null) {
+ this.environment = Environment.custom(_urlTemplate.replace("{instanceUrl}", _instanceUrl));
+ }
}
builder.environment(this.environment);
}
@@ -314,30 +322,18 @@ public static final class _CredentialsAuth extends PhenomlClientBuilder {
private final String clientSecret;
- private Optional grantType = Optional.empty();
-
_CredentialsAuth(String clientId, String clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
}
- public _CredentialsAuth grantType(Optional grantType) {
- this.grantType = grantType;
- return this;
- }
-
- public _CredentialsAuth grantType(String grantType) {
- this.grantType = Optional.ofNullable(grantType);
- return this;
- }
-
@Override
public PhenomlClient build() {
validateConfiguration();
ClientOptions baseOptions = buildClientOptions();
AuthtokenClient authClient = new AuthtokenClient(baseOptions);
OAuthTokenSupplier oAuthTokenSupplier =
- new OAuthTokenSupplier(this.clientId, this.clientSecret, this.grantType, authClient);
+ new OAuthTokenSupplier(this.clientId, this.clientSecret, authClient);
ClientOptions finalOptions = ClientOptions.Builder.from(baseOptions)
.addHeader("Authorization", oAuthTokenSupplier)
.build();
diff --git a/src/main/java/com/phenoml/api/core/ClientOptions.java b/src/main/java/com/phenoml/api/core/ClientOptions.java
index c7a9705f..b12427d2 100644
--- a/src/main/java/com/phenoml/api/core/ClientOptions.java
+++ b/src/main/java/com/phenoml/api/core/ClientOptions.java
@@ -47,10 +47,10 @@ private ClientOptions(
this.headers.putAll(headers);
this.headers.putAll(new HashMap() {
{
- put("User-Agent", "com.phenoml.maven.phenoml-java-sdk/17.13.0");
+ put("User-Agent", "com.phenoml.maven.phenoml-java-sdk/17.13.1");
put("X-Fern-Language", "JAVA");
- put("X-Fern-SDK-Name", "com.phenoml.fern:api-sdk");
- put("X-Fern-SDK-Version", "17.13.0");
+ put("X-Fern-SDK-Name", "com.phenoml.maven:phenoml-java-sdk");
+ put("X-Fern-SDK-Version", "17.13.1");
}
});
this.headerSuppliers = headerSuppliers;
@@ -153,7 +153,9 @@ public Builder environment(Environment environment) {
}
public Builder addHeader(String key, String value) {
- this.headers.put(key, value);
+ if (value != null) {
+ this.headers.put(key, value);
+ }
return this;
}
diff --git a/src/main/java/com/phenoml/api/core/ConsoleLogger.java b/src/main/java/com/phenoml/api/core/ConsoleLogger.java
index 92f79a63..d502dc13 100644
--- a/src/main/java/com/phenoml/api/core/ConsoleLogger.java
+++ b/src/main/java/com/phenoml/api/core/ConsoleLogger.java
@@ -23,6 +23,7 @@ public String format(java.util.logging.LogRecord record) {
return record.getLevel() + " - " + record.getMessage() + System.lineSeparator();
}
});
+ handler.setLevel(Level.ALL);
logger.addHandler(handler);
logger.setUseParentHandlers(false);
logger.setLevel(Level.ALL);
diff --git a/src/main/java/com/phenoml/api/core/OAuthTokenSupplier.java b/src/main/java/com/phenoml/api/core/OAuthTokenSupplier.java
index a293397a..cc79cc17 100644
--- a/src/main/java/com/phenoml/api/core/OAuthTokenSupplier.java
+++ b/src/main/java/com/phenoml/api/core/OAuthTokenSupplier.java
@@ -8,7 +8,6 @@
import com.phenoml.api.resources.authtoken.types.TokenResponse;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
-import java.util.Optional;
import java.util.function.Supplier;
public final class OAuthTokenSupplier implements Supplier {
@@ -18,8 +17,6 @@ public final class OAuthTokenSupplier implements Supplier {
private final String clientSecret;
- private final Optional grantType;
-
private final AuthtokenClient authClient;
private final Object tokenLock = new Object();
@@ -28,11 +25,9 @@ public final class OAuthTokenSupplier implements Supplier {
private volatile Instant expiresAt;
- public OAuthTokenSupplier(
- String clientId, String clientSecret, Optional grantType, AuthtokenClient authClient) {
+ public OAuthTokenSupplier(String clientId, String clientSecret, AuthtokenClient authClient) {
this.clientId = clientId;
this.clientSecret = clientSecret;
- this.grantType = grantType;
this.authClient = authClient;
this.expiresAt = Instant.now();
}
@@ -41,7 +36,7 @@ public TokenResponse fetchToken() {
ClientCredentialsRequest getTokenRequest = ClientCredentialsRequest.builder()
.clientId(clientId)
.clientSecret(clientSecret)
- .grantType(grantType)
+ .grantType("client_credentials")
.build();
return authClient.getToken(getTokenRequest);
}
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncFhir2OmopClient.java b/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncFhir2OmopClient.java
index 509fc772..76ec7878 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncFhir2OmopClient.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncFhir2OmopClient.java
@@ -27,116 +27,188 @@ public AsyncRawFhir2OmopClient withRawResponse() {
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public CompletableFuture create(CreateOmopRequest request) {
return this.rawClient.create(request).thenApply(response -> response.body());
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public CompletableFuture create(CreateOmopRequest request, RequestOptions requestOptions) {
return this.rawClient.create(request, requestOptions).thenApply(response -> response.body());
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncRawFhir2OmopClient.java b/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncRawFhir2OmopClient.java
index 3f362908..b0a23deb 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncRawFhir2OmopClient.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/AsyncRawFhir2OmopClient.java
@@ -39,116 +39,188 @@ public AsyncRawFhir2OmopClient(ClientOptions clientOptions) {
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public CompletableFuture> create(CreateOmopRequest request) {
return create(request, null);
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public CompletableFuture> create(
CreateOmopRequest request, RequestOptions requestOptions) {
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/Fhir2OmopClient.java b/src/main/java/com/phenoml/api/resources/fhir2omop/Fhir2OmopClient.java
index 5def4f52..99d605a4 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/Fhir2OmopClient.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/Fhir2OmopClient.java
@@ -26,116 +26,188 @@ public RawFhir2OmopClient withRawResponse() {
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public CreateOmopResponse create(CreateOmopRequest request) {
return this.rawClient.create(request).body();
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public CreateOmopResponse create(CreateOmopRequest request, RequestOptions requestOptions) {
return this.rawClient.create(request, requestOptions).body();
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/RawFhir2OmopClient.java b/src/main/java/com/phenoml/api/resources/fhir2omop/RawFhir2OmopClient.java
index f4f4e265..f1e28a07 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/RawFhir2OmopClient.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/RawFhir2OmopClient.java
@@ -35,116 +35,188 @@ public RawFhir2OmopClient(ClientOptions clientOptions) {
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public PhenomlClientHttpResponse create(CreateOmopRequest request) {
return create(request, null);
}
/**
- * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- * (person, visit_occurrence, condition_occurrence, drug_exposure,
- * procedure_occurrence, measurement, observation).
- *
Resource support is intentionally limited to the OMOP tables returned by
- * this endpoint:
+ * Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ * grouped by destination table in tables.
+ *
Current resource coverage:
*
- *
Patient -> person
+ *
Patient -> person; deceased[x] can also produce death, and the
+ * first address can produce location
+ *
observation_period -> one derived row per person with dated visit,
+ * clinical, or death rows, spanning those dates
+ *
Location -> location and care_site
+ *
Organization -> care_site; its first address can produce location
+ *
HealthcareService -> care_site
+ *
Practitioner and PractitionerRole -> provider
*
Encounter -> visit_occurrence
*
Condition -> condition_occurrence
*
Procedure -> procedure_occurrence
*
MedicationRequest, MedicationStatement, and
* MedicationAdministration -> drug_exposure
*
Immunization -> drug_exposure
- *
Observation with a numeric valueQuantity, valueInteger, or
- * numeric-looking valueString (for example "<2") -> measurement
- *
non-numeric Observation -> observation
+ *
Observation -> measurement or observation. For coded
+ * Observations, the resolved OMOP concept domain selects the table; value
+ * form only breaks ties. For text-only Observations, numeric values route
+ * to measurement and nonnumeric values to observation.
*
AllergyIntolerance -> observation
*
- *
Medication is supported only as reference data for medication
- * resources; it is not emitted as its own row because OMOP CDM has no
- * Medication table. Other reference/admin resources such as Practitioner,
- * Organization, Location, Coverage, and Claim, and clinical
- * workflow/document resources such as DiagnosticReport, ServiceRequest,
- * CarePlan, DocumentReference, Composition, Specimen, and
- * DeviceUseStatement, are currently accepted in a Bundle but are not
- * shaped into OMOP rows. Unsupported resource types are ignored rather than
- * listed under dropped; dropped is reserved for supported resource types
- * that were missing the subject/patient, code, or medication reference data
- * needed to produce a valid row.
- *
Each resource's primary clinical coding is resolved to a standard OMOP
- * concept_id. Alongside the OMOP rows grouped by table (tables), the
- * response carries mappings (how each source coding resolved, linked back
- * to the row it produced), dropped (resources that could not be shaped
- * into a row), vocab_version (the OMOP vocabulary release codes were
- * resolved against), and a small summary of the resolution outcomes.
+ *
Medication is reference data for medication resources; it does not
+ * create its own row because OMOP CDM has no Medication table. Administrative
+ * linkages (provider, care site, and location) are best-effort and limited to
+ * references supplied in the request. Their supporting concepts, including
+ * provider specialty, country, and place of service, are not mapped.
+ *
DiagnosticReport, ServiceRequest, CarePlan, DocumentReference,
+ * Composition, Specimen, DeviceUseStatement, Coverage, Claim, and
+ * other unsupported resource types are accepted in a Bundle but ignored: they
+ * create no row and no dropped entry. dropped is reserved for supported
+ * row-producing resources that could not be shaped because the subject/patient,
+ * clinical code/text, or medication data was not usable. A single-Patient
+ * Bundle can attribute a supported clinical resource with a missing or
+ * unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ * resource is dropped instead.
+ *
Coded Observation routing is selected from the resolved OMOP concept
+ * domain. Numeric and nonnumeric value[x] forms establish the preferred
+ * target only when the code is valid for both tables. A text-only
+ * Observation has no resolver target, so numeric values route to
+ * measurement and nonnumeric values to observation. Numeric values
+ * populate value_as_number in the selected row; nonnumeric values
+ * populate value_as_string for an observation or value_source_value
+ * for a measurement. valueCodeableConcept remains source text and does
+ * not populate value_as_concept_id; other unsupported value[x] forms
+ * and Observation components do not populate separate converted values. A
+ * numeric comparator (<, <=, >, >=) is represented only by a
+ * measurement's operator_concept_id; units remain source text and have
+ * unit_concept_id of 0.
+ *
A single standard OMOP concept_id is selected for each clinical row
+ * after considering all of the resource's supplied codings. Alongside the
+ * OMOP rows grouped by table (tables), the response carries mappings
+ * (an entry for every source coding, linked back to the row it produced),
+ * dropped (resources that could not be shaped into a row),
+ * vocab_version (the OMOP vocabulary release codes were resolved
+ * against), and a small summary of the resolution outcomes.
*
A concept_id of 0 is reported, not omitted (OMOP "no matching
* concept" semantics): it covers both a coding with no standard match
* (UNMAPPED) and an unverified suggestion for a text-only resource
- * (UNCHECKED). Only the primary clinical coding is resolved, so
- * gender/race/ethnicity/visit/value/unitconcept_ids are
- * always 0; the one populated non-resolved concept is measurement
+ * (UNCHECKED). Demographic, visit, categorical-value, and unit concept
+ * fields currently remain 0; the one populated non-resolved concept is
+ * measurement
* operator_concept_id, set from a value comparator (<, <=, >, >=)
- * rather than the resolver. Each *_source_value carries the verbatim FHIR
- * coding (system#code), and *_type_concept_id is set to 32817 (EHR).
+ * rather than terminology resolution. Clinical *_source_value fields
+ * preserve the selected FHIR coding (system#code, or code when no
+ * system is supplied), falling back to source text for text-only resources.
+ * Other *_source_value fields preserve row-specific raw source values,
+ * such as resource identifiers, names, units, or status codes, and
+ * *_type_concept_id is set to 32817 (EHR).
*
Medication codes are resolved whether they appear inline
* (medicationCodeableConcept) or via a medicationReference to a contained,
* relative (Type/id), or bundle-entry (urn:uuid) Medication resource.
* Resources that cannot be shaped into a row — a medication with no usable
* code, resolvable reference, or display, or any clinical resource whose
* subject/patient reference cannot be tied to a person — are reported under
- * dropped rather than emitted as blank rows. The
- * bundle must contain at least one Patient resource.
+ * dropped rather than emitted as blank rows. The Bundle must contain at
+ * least one Patient resource.
+ *
All row IDs start at 1 for each request and are not stable or global.
+ * For clinical conversion rows whose resource supplies an id, mappings
+ * associates each row with that source FHIR resource ID. A person row
+ * retains the Patient ID or its first identifier value in
+ * person_source_value, when present; other reference and derived rows do
+ * not uniformly carry a FHIR resource ID. Input resources without those
+ * source identifiers cannot be correlated across responses from the
+ * returned rows alone. Consumers combining responses need to establish
+ * their own stable keys and remap every primary and foreign key together.
*/
public PhenomlClientHttpResponse create(
CreateOmopRequest request, RequestOptions requestOptions) {
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/requests/CreateOmopRequest.java b/src/main/java/com/phenoml/api/resources/fhir2omop/requests/CreateOmopRequest.java
index 34b8f6da..13327997 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/requests/CreateOmopRequest.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/requests/CreateOmopRequest.java
@@ -32,11 +32,12 @@ private CreateOmopRequest(Map fhirResources, Map
/**
* @return FHIR resources (single resource or Bundle). Must contain at least one
* Patient resource. Supported row-producing resources are Patient,
- * Encounter, Condition, Procedure, MedicationRequest,
+ * Location, Organization, HealthcareService, Practitioner,
+ * PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
* MedicationStatement, MedicationAdministration, Immunization,
* Observation, and AllergyIntolerance. Standalone Medication resources
* are consumed by medication references rather than mapped to their own
- * table. Other resource types are accepted but ignored.
+ * table. Unsupported resource types are accepted in a Bundle but ignored.
*/
@JsonProperty("fhir_resources")
public Map getFhirResources() {
@@ -89,11 +90,12 @@ public Builder from(CreateOmopRequest other) {
/**
*
FHIR resources (single resource or Bundle). Must contain at least one
* Patient resource. Supported row-producing resources are Patient,
- * Encounter, Condition, Procedure, MedicationRequest,
+ * Location, Organization, HealthcareService, Practitioner,
+ * PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
* MedicationStatement, MedicationAdministration, Immunization,
* Observation, and AllergyIntolerance. Standalone Medication resources
* are consumed by medication references rather than mapped to their own
- * table. Other resource types are accepted but ignored.
+ * table. Unsupported resource types are accepted in a Bundle but ignored.
*/
@JsonSetter(value = "fhir_resources", nulls = Nulls.SKIP)
public Builder fhirResources(Map fhirResources) {
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/types/CreateOmopResponse.java b/src/main/java/com/phenoml/api/resources/fhir2omop/types/CreateOmopResponse.java
index e365995f..3dad063f 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/types/CreateOmopResponse.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/types/CreateOmopResponse.java
@@ -91,9 +91,9 @@ public Optional> getDropped() {
}
/**
- * @return The OMOP vocabulary release the clinical codes were resolved against
- * (e.g. "v20240229"), for reproducibility. Present when at least one
- * coded concept was resolved.
+ * @return The OMOP vocabulary release returned for coded concept resolution
+ * (for example, "v20240229"), for reproducibility. It is generally
+ * absent for requests containing only text-only resources.
*/
@JsonProperty("vocab_version")
public Optional getVocabVersion() {
@@ -238,9 +238,9 @@ public Builder dropped(List dropped) {
}
/**
- *
The OMOP vocabulary release the clinical codes were resolved against
- * (e.g. "v20240229"), for reproducibility. Present when at least one
- * coded concept was resolved.
+ *
The OMOP vocabulary release returned for coded concept resolution
+ * (for example, "v20240229"), for reproducibility. It is generally
+ * absent for requests containing only text-only resources.
*/
@JsonSetter(value = "vocab_version", nulls = Nulls.SKIP)
public Builder vocabVersion(Optional vocabVersion) {
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntry.java b/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntry.java
index 73bbb33f..ba7a725a 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntry.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntry.java
@@ -40,7 +40,7 @@ public final class MappingEntry {
private final Optional targetName;
- private final Optional mappingStatus;
+ private final Optional mappingStatus;
private final Optional note;
@@ -57,7 +57,7 @@ private MappingEntry(
Optional targetVocabulary,
Optional targetCode,
Optional targetName,
- Optional mappingStatus,
+ Optional mappingStatus,
Optional note,
Map additionalProperties) {
this.resourceType = resourceType;
@@ -144,7 +144,7 @@ public Optional getTargetName() {
* UNMAPPED (no standard concept found).
*/
@JsonProperty("mapping_status")
- public Optional getMappingStatus() {
+ public Optional getMappingStatus() {
return mappingStatus;
}
@@ -227,7 +227,7 @@ public static final class Builder {
private Optional targetName = Optional.empty();
- private Optional mappingStatus = Optional.empty();
+ private Optional mappingStatus = Optional.empty();
private Optional note = Optional.empty();
@@ -381,12 +381,12 @@ public Builder targetName(String targetName) {
* UNMAPPED (no standard concept found).
*/
@JsonSetter(value = "mapping_status", nulls = Nulls.SKIP)
- public Builder mappingStatus(Optional mappingStatus) {
+ public Builder mappingStatus(Optional mappingStatus) {
this.mappingStatus = mappingStatus;
return this;
}
- public Builder mappingStatus(String mappingStatus) {
+ public Builder mappingStatus(MappingEntryMappingStatus mappingStatus) {
this.mappingStatus = Optional.ofNullable(mappingStatus);
return this;
}
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntryMappingStatus.java b/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntryMappingStatus.java
new file mode 100644
index 00000000..c3b619f1
--- /dev/null
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/types/MappingEntryMappingStatus.java
@@ -0,0 +1,106 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.phenoml.api.resources.fhir2omop.types;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public final class MappingEntryMappingStatus {
+ public static final MappingEntryMappingStatus ALREADY_STANDARD =
+ new MappingEntryMappingStatus(Value.ALREADY_STANDARD, "ALREADY_STANDARD");
+
+ public static final MappingEntryMappingStatus MAPPED = new MappingEntryMappingStatus(Value.MAPPED, "MAPPED");
+
+ public static final MappingEntryMappingStatus UNCHECKED =
+ new MappingEntryMappingStatus(Value.UNCHECKED, "UNCHECKED");
+
+ public static final MappingEntryMappingStatus UNMAPPED = new MappingEntryMappingStatus(Value.UNMAPPED, "UNMAPPED");
+
+ private final Value value;
+
+ private final String string;
+
+ MappingEntryMappingStatus(Value value, String string) {
+ this.value = value;
+ this.string = string;
+ }
+
+ public Value getEnumValue() {
+ return value;
+ }
+
+ @java.lang.Override
+ @JsonValue
+ public String toString() {
+ return this.string;
+ }
+
+ @java.lang.Override
+ public boolean equals(Object other) {
+ return (this == other)
+ || (other instanceof MappingEntryMappingStatus
+ && this.string.equals(((MappingEntryMappingStatus) other).string));
+ }
+
+ @java.lang.Override
+ public int hashCode() {
+ return this.string.hashCode();
+ }
+
+ public T visit(Visitor visitor) {
+ switch (value) {
+ case ALREADY_STANDARD:
+ return visitor.visitAlreadyStandard();
+ case MAPPED:
+ return visitor.visitMapped();
+ case UNCHECKED:
+ return visitor.visitUnchecked();
+ case UNMAPPED:
+ return visitor.visitUnmapped();
+ case UNKNOWN:
+ default:
+ return visitor.visitUnknown(string);
+ }
+ }
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static MappingEntryMappingStatus valueOf(String value) {
+ switch (value) {
+ case "ALREADY_STANDARD":
+ return ALREADY_STANDARD;
+ case "MAPPED":
+ return MAPPED;
+ case "UNCHECKED":
+ return UNCHECKED;
+ case "UNMAPPED":
+ return UNMAPPED;
+ default:
+ return new MappingEntryMappingStatus(Value.UNKNOWN, value);
+ }
+ }
+
+ public enum Value {
+ ALREADY_STANDARD,
+
+ MAPPED,
+
+ UNCHECKED,
+
+ UNMAPPED,
+
+ UNKNOWN
+ }
+
+ public interface Visitor {
+ T visitAlreadyStandard();
+
+ T visitMapped();
+
+ T visitUnchecked();
+
+ T visitUnmapped();
+
+ T visitUnknown(String unknownType);
+ }
+}
diff --git a/src/main/java/com/phenoml/api/resources/fhir2omop/types/Summary.java b/src/main/java/com/phenoml/api/resources/fhir2omop/types/Summary.java
index 5f018ef5..73f1875b 100644
--- a/src/main/java/com/phenoml/api/resources/fhir2omop/types/Summary.java
+++ b/src/main/java/com/phenoml/api/resources/fhir2omop/types/Summary.java
@@ -44,7 +44,7 @@ private Summary(
}
/**
- * @return Coded concepts already a standard OMOP concept (ALREADY_STANDARD).
+ * @return Resolution outcomes already a standard OMOP concept (ALREADY_STANDARD).
*/
@JsonProperty("codes_already_standard")
public Optional getCodesAlreadyStandard() {
@@ -52,7 +52,7 @@ public Optional getCodesAlreadyStandard() {
}
/**
- * @return Coded concepts mapped or suggested to a standard concept (MAPPED or UNCHECKED).
+ * @return Resolution outcomes mapped or suggested to a standard concept (MAPPED or UNCHECKED).
*/
@JsonProperty("codes_normalized")
public Optional getCodesNormalized() {
@@ -60,7 +60,7 @@ public Optional getCodesNormalized() {
}
/**
- * @return Coded concepts with no standard concept found (UNMAPPED).
+ * @return Resolution outcomes with no standard concept found (UNMAPPED).
*/
@JsonProperty("codes_unmapped")
public Optional getCodesUnmapped() {
@@ -68,7 +68,7 @@ public Optional getCodesUnmapped() {
}
/**
- * @return Share of coded concepts not already standard ((normalized + unmapped) / total).
+ * @return Share of resolution outcomes not already standard ((normalized + unmapped) / total).
*/
@JsonProperty("off_vocab_rate")
public Optional getOffVocabRate() {
@@ -131,7 +131,7 @@ public Builder from(Summary other) {
}
/**
- *
Coded concepts already a standard OMOP concept (ALREADY_STANDARD).
+ *
Resolution outcomes already a standard OMOP concept (ALREADY_STANDARD).
Present only for guides that have stored metadata (a profile_context has been set). Omitted for guides that exist solely because a profile references them.
*/
@@ -256,7 +325,15 @@ public Builder profiles(List profiles) {
public ImplementationGuideDetail build() {
return new ImplementationGuideDetail(
- name, profileContext, profileCount, createdAt, updatedAt, profiles, additionalProperties);
+ name,
+ profileContext,
+ profileCount,
+ canonicalUrl,
+ versionCount,
+ createdAt,
+ updatedAt,
+ profiles,
+ additionalProperties);
}
public Builder additionalProperty(String key, Object value) {
diff --git a/src/main/java/com/phenoml/api/resources/implementationguides/types/ImplementationGuideSummary.java b/src/main/java/com/phenoml/api/resources/implementationguides/types/ImplementationGuideSummary.java
index 33197052..38652ac1 100644
--- a/src/main/java/com/phenoml/api/resources/implementationguides/types/ImplementationGuideSummary.java
+++ b/src/main/java/com/phenoml/api/resources/implementationguides/types/ImplementationGuideSummary.java
@@ -27,6 +27,10 @@ public final class ImplementationGuideSummary implements IImplementationGuideSum
private final Optional profileCount;
+ private final Optional canonicalUrl;
+
+ private final Optional versionCount;
+
private final Optional createdAt;
private final Optional updatedAt;
@@ -37,12 +41,16 @@ private ImplementationGuideSummary(
Optional name,
Optional profileContext,
Optional profileCount,
+ Optional canonicalUrl,
+ Optional versionCount,
Optional createdAt,
Optional updatedAt,
Map additionalProperties) {
this.name = name;
this.profileContext = profileContext;
this.profileCount = profileCount;
+ this.canonicalUrl = canonicalUrl;
+ this.versionCount = versionCount;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
this.additionalProperties = additionalProperties;
@@ -75,6 +83,24 @@ public Optional getProfileCount() {
return profileCount;
}
+ /**
+ * @return Canonical FHIR ImplementationGuide URL, when the family has an exact package.
+ */
+ @JsonProperty("canonical_url")
+ @java.lang.Override
+ public Optional getCanonicalUrl() {
+ return canonicalUrl;
+ }
+
+ /**
+ * @return Number of retained exact package versions.
+ */
+ @JsonProperty("version_count")
+ @java.lang.Override
+ public Optional getVersionCount() {
+ return versionCount;
+ }
+
/**
* @return Present only for guides that have stored metadata (a profile_context has been set). Omitted for guides that exist solely because a profile references them.
*/
@@ -108,13 +134,22 @@ private boolean equalTo(ImplementationGuideSummary other) {
return name.equals(other.name)
&& profileContext.equals(other.profileContext)
&& profileCount.equals(other.profileCount)
+ && canonicalUrl.equals(other.canonicalUrl)
+ && versionCount.equals(other.versionCount)
&& createdAt.equals(other.createdAt)
&& updatedAt.equals(other.updatedAt);
}
@java.lang.Override
public int hashCode() {
- return Objects.hash(this.name, this.profileContext, this.profileCount, this.createdAt, this.updatedAt);
+ return Objects.hash(
+ this.name,
+ this.profileContext,
+ this.profileCount,
+ this.canonicalUrl,
+ this.versionCount,
+ this.createdAt,
+ this.updatedAt);
}
@java.lang.Override
@@ -134,6 +169,10 @@ public static final class Builder {
private Optional profileCount = Optional.empty();
+ private Optional canonicalUrl = Optional.empty();
+
+ private Optional versionCount = Optional.empty();
+
private Optional createdAt = Optional.empty();
private Optional updatedAt = Optional.empty();
@@ -147,6 +186,8 @@ public Builder from(ImplementationGuideSummary other) {
name(other.getName());
profileContext(other.getProfileContext());
profileCount(other.getProfileCount());
+ canonicalUrl(other.getCanonicalUrl());
+ versionCount(other.getVersionCount());
createdAt(other.getCreatedAt());
updatedAt(other.getUpdatedAt());
return this;
@@ -194,6 +235,34 @@ public Builder profileCount(Integer profileCount) {
return this;
}
+ /**
+ *
Canonical FHIR ImplementationGuide URL, when the family has an exact package.
Present only for guides that have stored metadata (a profile_context has been set). Omitted for guides that exist solely because a profile references them.
Patient identifier handling. When generating a patient (or patient-canvas) resource, US Core requires Patient.identifier (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with system: "urn:phenoml:lang2fhir-generated-id" and a UUID value so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.