Skip to content

Commit 6cf8f4c

Browse files
authored
Merge pull request #499 from IBM/issue-317
Issue #317 - Composite Search
2 parents fc0ae7a + 99ecd8d commit 6cf8f4c

91 files changed

Lines changed: 4658 additions & 2332 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/src/pages/Conformance.md

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ permalink: /conformance/
77
---
88

99
# Conformance to the HL7 FHIR Specification
10-
The IBM FHIR Server aims to be a conformant implementation of the HL7 FHIR specification, version 4.0.0 (R4). However, the FHIR specification is very broad and not all implementations are expected to implement every feature. We prioritize performance and configurability over spec coverage.
10+
The IBM FHIR Server aims to be a conformant implementation of the HL7 FHIR specification, version 4.0.1 (R4). However, the FHIR specification is very broad and not all implementations are expected to implement every feature. We prioritize performance and configurability over spec coverage.
1111

1212
## Capability statement
1313
The HL7 FHIR specification defines [an interaction](https://www.hl7.org/fhir/R4/http.html#capabilities) for retrieving a machine-readable description of the server's capabilities via the `[base]/metadata` endpoint. The IBM FHIR Server implements this interaction and generates a `CapabilityStatement` resource based on the current server configuration. While the `CapabilityStatement` resource is ideal for certain uses, this markdown document provides a human-readable summary of important details, with a special focus on limitations of the current implementation and deviations from the specification.
1414

15-
The IBM FHIR Server supports only version 4.0.0 of the specification and presently has no support for the MIME-type parameter `fhirVersion`.
15+
The IBM FHIR Server supports only version 4.0.1 of the specification and presently has no support for the MIME-type parameter `fhirVersion`.
1616

1717
## FHIR HTTP API
1818
The HL7 FHIR specification is more than just a data format. It defines an [HTTP API](https://www.hl7.org/fhir/R4/http.html) for creating, reading, updating, deleting, and searching over FHIR resources. The IBM FHIR Server implements almost the full API for every resource defined in the specification, with the following exceptions:
@@ -24,17 +24,21 @@ The IBM FHIR Server implements a linear versioning scheme for resources and full
2424
### General parameters
2525
The `_format` parameter is supported and provides a useful mechanism for requesting a specific format (`XML` or `JSON`) in requests made from a browser. In the absence of either an `Accept` header or a `_format` query parameter, the server defaults to `application/fhir+json`.
2626

27-
The `_pretty` parameter is also supported.
27+
The `_pretty` parameter is also supported.
2828

2929
The `_summary` and `_elements` parameters are supported on the search interaction as documented.
3030

3131
## Search
32-
The IBM FHIR Server supports search parameters of type `Number`, `Date/DateTime`, `String`, `Token`, `Reference`, `Quantity`, and `URI`.
33-
34-
Search parameters of type [Composite](https://www.hl7.org/fhir/R4/search.html#composite) and [Special](https://www.hl7.org/fhir/R4/search.html#special) are not currently supported.
35-
36-
For all other types, the IBM FHIR Server supports the parameters defined in the
37-
specification and allows for the configuration of additional ones.
32+
The IBM FHIR Server supports all search parameter types defined in the specification:
33+
* `Number`
34+
* `Date/DateTime`
35+
* `String`
36+
* `Token`
37+
* `Reference`
38+
* `Composite`
39+
* `Quantity`
40+
* `URI`
41+
* `Special` (Location-near)
3842

3943
### Search parameters
4044
Search parameters defined in the specification can be found by browsing the R4 FHIR specification by resource type. For example, to find the search parameters for the Patient resource, navigate to https://www.hl7.org/fhir/R4/patient.html and scroll to the Search Parameters section near the end of the page.
@@ -46,10 +50,14 @@ In addition, the following search parameters are supported on all resources:
4650
* `_profile`
4751
* `_security`
4852
* `_source`
53+
* `_type`
4954

50-
The `_text`, `_content`, `_list`, `_has`, `_type`, `_query`, and `_filter` parameters are not supported at this time.
55+
These parameters can be used while searching any single resource type or while searching across resource types (whole system search).
56+
The `_type` parameter is special in that it is only applicable for whole system search.
5157

52-
Finally, the specification defines a set of <q>Search result parameters</q> for controlling the search behavior. The IBM FHIR Server supports the following:
58+
The `_text`, `_content`, `_list`, `_has`, `_query`, and `_filter` parameters are not supported at this time.
59+
60+
Finally, the specification defines a set of "Search result parameters" for controlling the search behavior. The IBM FHIR Server supports the following:
5361
* `_sort`
5462
* `_count`
5563
* `_include`
@@ -71,24 +79,24 @@ For information on how to specify custom search parameters, see [FHIRSearchConfi
7179
### Search modifiers
7280
FHIR search modifiers are described at https://www.hl7.org/fhir/R4/search.html#modifiers and vary by search parameter type. The IBM FHIR Server implements a subset of the spec-defined search modifiers that is defined in the following table:
7381

74-
|FHIR Search Parameter Type|Supported Modifiers|"Default" search behavior when no Modifier is present|
82+
|FHIR Search Parameter Type|Supported Modifiers|"Default" search behavior when no Modifier or Prefix is present|
7583
|--------------------------|-------------------|-----------------------------------------------------|
76-
|String |`:exact`,`:contains`,`:missing` |Performs a "starts with" search that is case-insensitive and accent-insensitive|
77-
|Reference |`:[type]`,`:missing` |Performs an exact match search|
78-
|URI |`:below`,`:above`,`:missing` |Performs a "starts with" search (issue #273), component based search for the path in the URL (issue #448)|
79-
|Token |`:below`,`:not`,`:missing` |Performs an exact match search|
80-
|Number |`:missing` |Honors prefix if present, otherwise performs an exact match search|
81-
|Date |`:missing` |Honors prefix if present, otherwise performs an exact match search|
82-
|Quantity |`:missing` |Honors prefix if present, otherwise performs an exact match search|
84+
|String |`:exact`,`:contains`,`:missing` |"starts with" search that is case-insensitive and accent-insensitive|
85+
|Reference |`:[type]`,`:missing` |exact match search|
86+
|URI |`:below`,`:above`,`:missing` |exact match search|
87+
|Token |`:below`,`:not`,`:missing` |exact match search|
88+
|Number |`:missing` |exact match search|
89+
|Date |`:missing` |exact match search|
90+
|Quantity |`:missing` |implicit range search (see http://hl7.org/fhir/R4/search.html#quantity)|
91+
|Composite |`:missing` |processes each parameter component according to its type|
92+
|Special (near) | none |searches a bounding area according to the value of the `fhirServer/search/useBoundingRadius` property|
8393

84-
Note that the default IBM FHIR Server behavior for URI search parameters differs from the behavior defined at https://www.hl7.org/fhir/R4/search.html#uri.
94+
Due to performance implications, the `:exact` modifier should be used for String searches where possible.
8595

8696
At present, modifiers cannot be used with chained parameters. For example, a search with query string like `subject:Basic.date:missing` will result in an `OperationOutcome` explaining that the search parameter could not be processed.
8797

8898
The `:text` modifier is not supported in this version of the FHIR server and use of this modifier will results in an HTTP 400 error with an `OperationOutcome` that describes the failure.
8999

90-
Due to performance implications, the `:exact` modifier should be used for String searches where possible.
91-
92100
### Search prefixes
93101
FHIR search prefixes are described at https://www.hl7.org/fhir/R4/search.html#prefix.
94102

@@ -147,20 +155,24 @@ For search parameters of type token that are defined on data fields of type `Con
147155
Searching string values via a token search parameter is not currently supported.
148156

149157
### Searching on Number
150-
For fields of type `decimal`, the IBM FHIR Server does not compute an implicit range for search. Search query values must match to the same precision, or greater precision, as the value in the resource.
158+
For fields of type `decimal`, the IBM FHIR Server computes an implicit range when the query parameter value has a prefix of `eq` (the default), `ne`, or `ap`. The computed range is based on the number of significant figures passed in the query string and further information can be found at https://www.hl7.org/fhir/R4/search.html#number.
159+
For searches with the `ap` prefix, we use the range `[implicitLowerBound - searchQueryValue * .1, implicitUpperBound + searchQueryValue * .1)` to ensure that the `ap` range is broader than the implicit range of `eq`.
151160

152161
### Searching on Quantity
153-
Quantity elements are not indexed unless they include either a valid `system` **and** `code` for their unit **or** a human-readable `unit` field. Quantities that don't include a `value` element are also skipped.
162+
Quantity elements are not indexed unless they include either a valid `system` **and** `code` for their unit **or** a human-readable `unit` field.
163+
If a Quantity element contains both a coded unit **and** a display unit, then both will be indexed. Quantities that don't include a `value` element are also skipped.
164+
165+
The FHIR server does not perform any unit conversion or unit manipulation at this time. Quantity values should be searched using the same unit `code` that is included in the original resource.
154166

155-
The FHIR server does not perform any unit conversion or unit manipulation at this time. Quantity values **must** be searched using the same unit `code` that is included in the original resource. If, and only if, a coded unit is not present on a resource, then the FHIR server indexes the human-readable `unit` field, which can then be searched by omitting the `system` in the search query.
167+
Similar to Numeric searches, the FHIR Server computes an implicit range for search query values with no range prefix (e.g. `eq`, `ne`, `ap`) based on the number of significant figures passed in the query string.
168+
For searches with the `ap` prefix, we use the range `[implicitLowerBound - searchQueryValue * .1, implicitUpperBound + searchQueryValue * .1)` to ensure that the `ap` range is broader than the implicit range of `eq`.
156169

157170
The IBM FHIR Server does not consider the `Quantity.comparator` field as part of search processing at this time.
158-
Similar to Numeric searches, the FHIR Server does not compute an implicit range for quantity values...the precise number given in the resource is required for retrieval via standard search (i.e. searches with either no prefix or the `eq` prefix).
159171

160172
### Searching on URI
161-
URI searches on the IBM FHIR Server are case-insensitive, similar to the default behavior of searching on string values.
173+
URI searches on the IBM FHIR Server are case-sensitive with "exact-match" semantics. The `above` and `below` prefixes can be used to perform path-based matching that is based on the `/` delimiter.
162174

163-
## HL7 FHIR R4 (v4.0.0) errata
175+
## HL7 FHIR R4 (v4.0.1) errata
164176
We add information here as we find issues with the artifacts provided with this version of the specification.
165177

166-
FHIR® is the registered trademark of HL7 and is used with the permission of HL7.
178+
FHIR® is the registered trademark of HL7 and is used with the permission of HL7.

fhir-database-utils/src/main/java/com/ibm/fhir/database/utils/api/IDatabaseAdapter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.function.Supplier;
1212

1313
import com.ibm.fhir.database.utils.model.ColumnBase;
14+
import com.ibm.fhir.database.utils.model.IdentityDef;
1415
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
1516
import com.ibm.fhir.database.utils.model.Privilege;
1617
import com.ibm.fhir.database.utils.model.Table;
@@ -71,10 +72,11 @@ public interface IDatabaseAdapter {
7172
* @param tenantColumnName optional column name to enable multi-tenancy
7273
* @param columns
7374
* @param primaryKey
75+
* @param identity
7476
* @param tablespaceName
7577
*/
7678
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns,
77-
PrimaryKeyDef primaryKey, String tablespaceName);
79+
PrimaryKeyDef primaryKey, IdentityDef identity, String tablespaceName);
7880

7981
/**
8082
* Create ROW type used for passing values to stored procedures e.g.:

fhir-database-utils/src/main/java/com/ibm/fhir/database/utils/common/CommonDatabaseAdapter.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.ibm.fhir.database.utils.api.TenantStatus;
2828
import com.ibm.fhir.database.utils.api.UndefinedNameException;
2929
import com.ibm.fhir.database.utils.model.ColumnBase;
30+
import com.ibm.fhir.database.utils.model.IdentityDef;
3031
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
3132
import com.ibm.fhir.database.utils.model.Privilege;
3233
import com.ibm.fhir.database.utils.model.Tenant;
@@ -82,10 +83,8 @@ public IDatabaseTranslator getTranslator() {
8283

8384
/**
8485
* Build the list of columns in the create table statement
85-
* @param columns
86-
* @return
8786
*/
88-
protected String buildColumns(List<ColumnBase> columns) {
87+
protected String buildColumns(List<ColumnBase> columns, IdentityDef identity) {
8988
StringBuilder result = new StringBuilder();
9089
for (ColumnBase column: columns) {
9190
if (result.length() > 0) {
@@ -95,7 +94,10 @@ protected String buildColumns(List<ColumnBase> columns) {
9594
result.append(column.getName());
9695
result.append(" ");
9796
result.append(column.getTypeInfo(this));
98-
if (!column.isNullable()) {
97+
if (identity != null && column.getName().equals(identity.getColumnName())) {
98+
result.append(" GENERATED " + identity.getGenerated() + " AS IDENTITY");
99+
} // AS IDENTITY implies NOT NULL so this can be and else if
100+
else if (!column.isNullable()) {
99101
result.append(" NOT NULL");
100102
}
101103
}
@@ -114,12 +116,12 @@ protected String buildColumns(List<ColumnBase> columns) {
114116
* @param tablespaceName
115117
* @return
116118
*/
117-
protected String buildCreateTableStatement(String schema, String name, List<ColumnBase> columns, PrimaryKeyDef pkDef, String tablespaceName) {
119+
protected String buildCreateTableStatement(String schema, String name, List<ColumnBase> columns, PrimaryKeyDef pkDef, IdentityDef identity, String tablespaceName) {
118120
StringBuilder result = new StringBuilder();
119121
result.append("CREATE TABLE ");
120122
result.append(getQualifiedName(schema, name));
121-
result.append("(");
122-
result.append(buildColumns(columns));
123+
result.append('(');
124+
result.append(buildColumns(columns, identity));
123125

124126
// Add the primary key definition after the columns
125127
if (pkDef != null) {
@@ -136,9 +138,9 @@ protected String buildCreateTableStatement(String schema, String name, List<Colu
136138
}
137139

138140
result.append(cols);
139-
result.append(")");
141+
result.append(')');
140142
}
141-
result.append(")");
143+
result.append(')');
142144

143145
if (tablespaceName != null) {
144146
DataDefinitionUtil.assertValidName(tablespaceName);

fhir-database-utils/src/main/java/com/ibm/fhir/database/utils/db2/Db2Adapter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.ibm.fhir.database.utils.common.CommonDatabaseAdapter;
2929
import com.ibm.fhir.database.utils.common.DataDefinitionUtil;
3030
import com.ibm.fhir.database.utils.model.ColumnBase;
31+
import com.ibm.fhir.database.utils.model.IdentityDef;
3132
import com.ibm.fhir.database.utils.model.IntColumn;
3233
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
3334
import com.ibm.fhir.database.utils.model.Table;
@@ -54,7 +55,7 @@ public Db2Adapter(IConnectionProvider cp) {
5455

5556
@Override
5657
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns, PrimaryKeyDef primaryKey,
57-
String tablespaceName) {
58+
IdentityDef identity, String tablespaceName) {
5859

5960
// With DB2 we can implement support for multi-tenancy, which we do by injecting a MT_ID column
6061
// to the definition and partitioning on that column
@@ -78,7 +79,7 @@ public void createTable(String schemaName, String name, String tenantColumnName,
7879
// Now append all the actual columns we want in the table
7980
cols.addAll(columns);
8081

81-
String ddl = buildCreateTableStatement(schemaName, name, cols, primaryKey, tablespaceName);
82+
String ddl = buildCreateTableStatement(schemaName, name, cols, primaryKey, identity, tablespaceName);
8283

8384
// Our multi-tenant tables are range-partitioned as part of our data isolation strategy
8485
// We reserve partition 0. Real tenant partitions start at 1...

fhir-database-utils/src/main/java/com/ibm/fhir/database/utils/derby/DerbyAdapter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.ibm.fhir.database.utils.common.CommonDatabaseAdapter;
1919
import com.ibm.fhir.database.utils.common.DataDefinitionUtil;
2020
import com.ibm.fhir.database.utils.model.ColumnBase;
21+
import com.ibm.fhir.database.utils.model.IdentityDef;
2122
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
2223
import com.ibm.fhir.database.utils.model.Table;
2324

@@ -59,15 +60,15 @@ public void warnOnce(MessageKey messageKey, String msg) {
5960

6061
@Override
6162
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns, PrimaryKeyDef primaryKey,
62-
String tablespaceName) {
63+
IdentityDef identity, String tablespaceName) {
6364

6465
// Derby doesn't support partitioning, so we ignore tenantColumnName
6566
if (tenantColumnName != null) {
6667
warnOnce(MessageKey.MULTITENANCY, "Derby does support not multi-tenancy: " + name);
6768
}
6869

6970
// We also ignore tablespace for Derby
70-
String ddl = buildCreateTableStatement(schemaName, name, columns, primaryKey, null);
71+
String ddl = buildCreateTableStatement(schemaName, name, columns, primaryKey, identity, null);
7172

7273

7374
runStatement(ddl);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* (C) Copyright IBM Corp. 2019
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package com.ibm.fhir.database.utils.model;
8+
9+
/**
10+
* When to generate a value for an identity column.
11+
*/
12+
public enum Generated {
13+
ALWAYS, BY_DEFAULT;
14+
15+
/**
16+
* @return the SQL keyword or phrase for this Generated option
17+
*/
18+
@Override
19+
public String toString() {
20+
switch (this) {
21+
case BY_DEFAULT:
22+
return "BY DEFAULT";
23+
default:
24+
return this.name();
25+
}
26+
}
27+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* (C) Copyright IBM Corp. 2019
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package com.ibm.fhir.database.utils.model;
8+
9+
/**
10+
* Represents the definition of a primary key constraint on a table
11+
*/
12+
public class IdentityDef {
13+
14+
// The name of the column to be the identity
15+
public final String column;
16+
17+
// The list of columns comprising the primary key
18+
public final Generated generated;
19+
20+
public IdentityDef(String columnName, Generated generatedPref) {
21+
this.column = columnName;
22+
this.generated = generatedPref;
23+
}
24+
25+
/**
26+
* Getter for the name of the identity column
27+
*/
28+
public String getColumnName() {
29+
return this.column;
30+
}
31+
32+
/**
33+
* Getter for the generation preference
34+
*/
35+
public Generated getGenerated() {
36+
return this.generated;
37+
}
38+
}

fhir-database-utils/src/main/java/com/ibm/fhir/database/utils/model/IndexDef.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ public void apply(String schemaName, String tableName, String tenantColumnName,
6767
target.createUniqueIndex(schemaName, tableName, indexName, tenantColumnName, indexColumns, includeColumns);
6868
}
6969
else if (unique) {
70-
target.createUniqueIndex(schemaName, tableName, indexName, tenantColumnName, indexColumns);
70+
target.createUniqueIndex(schemaName, tableName, indexName, tenantColumnName, indexColumns);
7171
}
7272
else {
73-
target.createIndex(schemaName, tableName, indexName, tenantColumnName, indexColumns);
73+
target.createIndex(schemaName, tableName, indexName, tenantColumnName, indexColumns);
7474
}
7575
}
7676
}

0 commit comments

Comments
 (0)