Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for IPS Export/Summary #419

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a5eba79
make sure tokens support modifiers during query
AnalogJ Feb 20, 2024
6885954
adding tests to ensure that the same field with multiple modifiers is…
AnalogJ Feb 20, 2024
0af00e0
reorganize tests
AnalogJ Feb 20, 2024
43dc56c
fixing tests.
AnalogJ Feb 20, 2024
21d12dd
trying to fix permissions error when pulling docker images without auth.
AnalogJ Feb 21, 2024
bf446a0
generate basic IPS summary bundle. Still missing lots of important fu…
AnalogJ Feb 21, 2024
9466d2b
move all IPS/narrative code into utils.
AnalogJ Feb 23, 2024
c3184fa
adding ability to generate slices of fhir resources.
AnalogJ Feb 23, 2024
dd78494
generate IPS bundle and composition
AnalogJ Feb 23, 2024
0664f20
generating IPS render test.
AnalogJ Feb 24, 2024
907c9be
working on rendering resources
AnalogJ Feb 24, 2024
55509c9
expand export summary.
AnalogJ Feb 24, 2024
da8e9e5
updated IPS generation.
AnalogJ Feb 24, 2024
7c9d59c
fixed IPS generation.
AnalogJ Feb 24, 2024
492fc27
better date extraction during PopulateAndExtractSearchParameters
AnalogJ Feb 25, 2024
4255fa6
removed the unnecessary/unused default "type" column. Correctly allow…
AnalogJ Feb 25, 2024
30149c4
working on care plan tests.
AnalogJ Feb 25, 2024
2e5b84d
working IPS export open in new window.
AnalogJ Feb 25, 2024
9608e07
working IPS export using github markdown.
AnalogJ Feb 25, 2024
7900ccf
better Observation value export & unit export - centralized in single…
AnalogJ Mar 3, 2024
0f6e735
update inteface{} usage in query with `any` for clarity.
AnalogJ Mar 3, 2024
441c8ab
when querying vital signs, use vital-signs category to find a list of…
AnalogJ Mar 3, 2024
83d6cde
correctly handle complex Observations (ComponentValueQuantity - used …
AnalogJ Mar 3, 2024
08f8722
working Observation components with/without units.
AnalogJ Mar 3, 2024
99317bc
safer handling of componentValueQuantity.
AnalogJ Mar 3, 2024
182d56f
correctly extract existing Text field data.
AnalogJ Mar 5, 2024
af1c033
working Patient record merge. Fixing IPS Export Data model for more f…
AnalogJ Mar 8, 2024
d700a1e
make sure the patient summary is exported in a specific order.
AnalogJ Mar 20, 2024
d99da60
update logos
AnalogJ Mar 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ jobs:
type=raw,value=${{ matrix.flavor }},enable=${{ github.ref_name == 'main' }}
# if this is a (non main) branch build, tag it with the flavor and branch name (eg. main-branch and sandbox-branch)
type=ref,event=branch,prefix=${{ matrix.flavor }}-,enable=${{ github.ref_name != 'main' }}
labels: |
maintainer=AnalogJ
org.opencontainers.image.title=Fasten Health - ${{ matrix.flavor }}
org.opencontainers.image.authors=Jason Kulatunga - [email protected]
org.opencontainers.image.description=An open-source personal medical record that never leaves the patients hands without their consent
org.opencontainers.image.vendor=Fasten Health, Inc.
org.opencontainers.image.source=https://github.com/fastenhealth/fasten-onprem/
org.opencontainers.image.revision=${{ github.sha }}
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
Expand Down
62 changes: 62 additions & 0 deletions backend/pkg/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ type DatabaseRepositoryType string
type InstallationVerificationStatus string
type InstallationQuotaStatus string

type IPSSections string
type IPSSectionGroups string

const (
ResourceListPageSize int = 20

Expand Down Expand Up @@ -50,4 +53,63 @@ const (
InstallationVerificationStatusVerified InstallationVerificationStatus = "VERIFIED" //email has been verified
InstallationQuotaStatusActive InstallationQuotaStatus = "ACTIVE"
InstallationQuotaStatusConsumed InstallationQuotaStatus = "CONSUMED"

IPSSectionsMedicationSummary IPSSections = "medication_summary"
IPSSectionsAllergiesIntolerances IPSSections = "allergies_intolerances"
IPSSectionsProblemList IPSSections = "problem_list"
IPSSectionsImmunizations IPSSections = "immunizations"
IPSSectionsHistoryOfProcedures IPSSections = "history_of_procedures"
IPSSectionsMedicalDevices IPSSections = "medical_devices"
IPSSectionsDiagnosticResults IPSSections = "diagnostic_results"
IPSSectionsVitalSigns IPSSections = "vital_signs"
IPSSectionsHistoryOfIllness IPSSections = "history_of_illness"
IPSSectionsPregnancy IPSSections = "pregnancy"
IPSSectionsSocialHistory IPSSections = "social_history"
IPSSectionsPlanOfCare IPSSections = "plan_of_care"
IPSSectionsFunctionalStatus IPSSections = "functional_status"
IPSSectionsAdvanceDirectives IPSSections = "advance_directives"

IPSSectionGroupsRequired IPSSectionGroups = "required"
IPSSectionGroupsRecommended IPSSectionGroups = "recommended"
IPSSectionGroupsOptional IPSSectionGroups = "optional"
)

var IPSSectionsList = []IPSSections{
IPSSectionsMedicationSummary,
IPSSectionsAllergiesIntolerances,
IPSSectionsProblemList,
IPSSectionsImmunizations,
IPSSectionsHistoryOfProcedures,
IPSSectionsMedicalDevices,
IPSSectionsDiagnosticResults,
IPSSectionsVitalSigns,
IPSSectionsHistoryOfIllness,
IPSSectionsPregnancy,
IPSSectionsSocialHistory,
IPSSectionsPlanOfCare,
IPSSectionsFunctionalStatus,
IPSSectionsAdvanceDirectives,
}

var IPSSectionGroupsOrdered = map[IPSSectionGroups][]IPSSections{
IPSSectionGroupsRequired: []IPSSections{
IPSSectionsMedicationSummary,
IPSSectionsAllergiesIntolerances,
IPSSectionsProblemList,
},
IPSSectionGroupsRecommended: []IPSSections{
IPSSectionsImmunizations,
IPSSectionsHistoryOfProcedures,
IPSSectionsMedicalDevices,
IPSSectionsDiagnosticResults,
},
IPSSectionGroupsOptional: []IPSSections{
IPSSectionsVitalSigns,
IPSSectionsHistoryOfIllness,
IPSSectionsPregnancy,
IPSSectionsSocialHistory,
IPSSectionsPlanOfCare,
IPSSectionsFunctionalStatus,
IPSSectionsAdvanceDirectives,
},
}
104 changes: 67 additions & 37 deletions backend/pkg/database/gorm_repository_query.go

Large diffs are not rendered by default.

228 changes: 228 additions & 0 deletions backend/pkg/database/gorm_repository_query_sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,3 +520,231 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenGroupByNoMo
"00000000-0000-0000-0000-000000000000",
})
}

func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenWithNotModifier() {
//setup
sqliteRepo := suite.TestRepository.(*GormRepository)
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})

//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")

sqlQuery, err := sqliteRepo.sqlQueryResources(authContext, models.QueryResource{
Select: []string{},
Where: map[string]interface{}{
"code:not": "test_code",
},
From: "Observation",
})
require.NoError(suite.T(), err)
var results []map[string]interface{}
statement := sqlQuery.Find(&results).Statement
sqlString := statement.SQL.String()
sqlParams := statement.Vars

//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(),
strings.Join([]string{
"SELECT fhir.*",
"FROM fhir_observation as fhir, json_each(fhir.code) as codeJson",
"WHERE ((codeJson.value ->> '$.code' <> ?)) AND (user_id = ?)",
"GROUP BY `fhir`.`id`",
"ORDER BY fhir.sort_date DESC",
}, " "),
sqlString)
require.Equal(suite.T(), sqlParams, []interface{}{
"test_code", "00000000-0000-0000-0000-000000000000",
})
}

func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenMultipleANDValuesWithNotModifier() {
//setup
sqliteRepo := suite.TestRepository.(*GormRepository)
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})

//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")

sqlQuery, err := sqliteRepo.sqlQueryResources(authContext, models.QueryResource{
Select: []string{},
Where: map[string]interface{}{
"code:not": []string{"test_code", "test_code2"}, //AND condition
},
From: "Observation",
})
require.NoError(suite.T(), err)
var results []map[string]interface{}
statement := sqlQuery.Find(&results).Statement
sqlString := statement.SQL.String()
sqlParams := statement.Vars

//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(),
strings.Join([]string{
"SELECT fhir.*",
"FROM fhir_observation as fhir, json_each(fhir.code) as codeJson",
"WHERE ((codeJson.value ->> '$.code' <> ?)) AND ((codeJson.value ->> '$.code' <> ?)) AND (user_id = ?)",
"GROUP BY `fhir`.`id`",
"ORDER BY fhir.sort_date DESC",
}, " "),
sqlString)
require.Equal(suite.T(), sqlParams, []interface{}{
"test_code", "test_code2", "00000000-0000-0000-0000-000000000000",
})
}

func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenMultipleORValues() {
//setup
sqliteRepo := suite.TestRepository.(*GormRepository)
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})

//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")

sqlQuery, err := sqliteRepo.sqlQueryResources(authContext, models.QueryResource{
Select: []string{},
Where: map[string]interface{}{
"code": "test_code,test_code2", //OR condition
},
From: "Observation",
})
require.NoError(suite.T(), err)
var results []map[string]interface{}
statement := sqlQuery.Find(&results).Statement
sqlString := statement.SQL.String()
sqlParams := statement.Vars

//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(),
strings.Join([]string{
"SELECT fhir.*",
"FROM fhir_observation as fhir, json_each(fhir.code) as codeJson",
"WHERE ((codeJson.value ->> '$.code' = ?) OR (codeJson.value ->> '$.code' = ?)) AND (user_id = ?)",
"GROUP BY `fhir`.`id`",
"ORDER BY fhir.sort_date DESC",
}, " "),
sqlString)
require.Equal(suite.T(), sqlParams, []interface{}{
"test_code", "test_code2", "00000000-0000-0000-0000-000000000000",
})
}

func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenMultipleORANDValues() {
//setup
sqliteRepo := suite.TestRepository.(*GormRepository)
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})

//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")

sqlQuery, err := sqliteRepo.sqlQueryResources(authContext, models.QueryResource{
Select: []string{},
Where: map[string]interface{}{
"code": []string{"test_code,test_code2", "test_code3,test_code4"}, //OR-AND condition
},
From: "Observation",
})
require.NoError(suite.T(), err)
var results []map[string]interface{}
statement := sqlQuery.Find(&results).Statement
sqlString := statement.SQL.String()
sqlParams := statement.Vars

//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(),
strings.Join([]string{
"SELECT fhir.*",
"FROM fhir_observation as fhir, json_each(fhir.code) as codeJson",
"WHERE ((codeJson.value ->> '$.code' = ?) OR (codeJson.value ->> '$.code' = ?)) AND ((codeJson.value ->> '$.code' = ?) OR (codeJson.value ->> '$.code' = ?)) AND (user_id = ?)",
"GROUP BY `fhir`.`id`",
"ORDER BY fhir.sort_date DESC",
}, " "),
sqlString)
require.Equal(suite.T(), sqlParams, []interface{}{
"test_code", "test_code2", "test_code3", "test_code4", "00000000-0000-0000-0000-000000000000",
})
}

func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenMultipleModifiersMultipleANDORValues() {
//setup
sqliteRepo := suite.TestRepository.(*GormRepository)
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})

//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")

sqlQuery, err := sqliteRepo.sqlQueryResources(authContext, models.QueryResource{
Select: []string{},
Where: map[string]interface{}{
"code:not": []string{"test_code", "test_code2,test_code3"}, //AND-OR condition
"code": "test_code4,test_code5,test_code6", //OR condition
},
From: "Observation",
})
require.NoError(suite.T(), err)
var results []map[string]interface{}
statement := sqlQuery.Find(&results).Statement
sqlString := statement.SQL.String()
sqlParams := statement.Vars

//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(),
strings.Join([]string{
"SELECT fhir.*",
"FROM fhir_observation as fhir, json_each(fhir.code) as codeJson",
"WHERE ((codeJson.value ->> '$.code' <> ?)) AND ((codeJson.value ->> '$.code' <> ?) OR (codeJson.value ->> '$.code' <> ?)) AND ((codeJson.value ->> '$.code' = ?) OR (codeJson.value ->> '$.code' = ?) OR (codeJson.value ->> '$.code' = ?)) AND (user_id = ?)",
"GROUP BY `fhir`.`id`",
"ORDER BY fhir.sort_date DESC",
}, " "),
sqlString)
require.Equal(suite.T(), sqlParams, []interface{}{
"test_code", "test_code2", "test_code3", "test_code4", "test_code5", "test_code6", "00000000-0000-0000-0000-000000000000",
})
}

// Section Vital Signs Codes Lookup

func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_SectionVitalSigns_WithTokenGroupByNoModifier() {
//setup
sqliteRepo := suite.TestRepository.(*GormRepository)
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})

//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")

sqlQuery, err := sqliteRepo.sqlQueryResources(authContext, models.QueryResource{
Select: []string{},
Where: map[string]interface{}{
"category": "vital-signs",
},
From: "Observation",
Aggregations: &models.QueryResourceAggregations{
GroupBy: &models.QueryResourceAggregation{Field: "code:code"},
},
})
require.NoError(suite.T(), err)
var results []map[string]interface{}
statement := sqlQuery.Find(&results).Statement
sqlString := statement.SQL.String()
sqlParams := statement.Vars

//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(),
strings.Join([]string{
"SELECT (codeJson.value ->> '$.code') as label, count(*) as value",
"FROM fhir_observation as fhir, json_each(fhir.category) as categoryJson, json_each(fhir.code) as codeJson",
"WHERE ((categoryJson.value ->> '$.code' = ?)) AND (user_id = ?)",
"GROUP BY (codeJson.value ->> '$.code')",
"ORDER BY count(*) DESC",
}, " "), sqlString)
require.Equal(suite.T(), sqlParams, []interface{}{
"vital-signs",
"00000000-0000-0000-0000-000000000000",
})
}
14 changes: 9 additions & 5 deletions backend/pkg/database/gorm_repository_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ func TestProcessSearchParameter(t *testing.T) {
{"url:below", map[string]string{"url": "string"}, SearchParameter{Type: "string", Name: "url", Modifier: "below"}, false},
{"url:above", map[string]string{"url": "string"}, SearchParameter{Type: "string", Name: "url", Modifier: "above"}, false},

{"display:text", map[string]string{"display": "token"}, SearchParameter{}, true},
{"display", map[string]string{"display": "token"}, SearchParameter{Type: "token", Name: "display", Modifier: ""}, false},
{"display:not", map[string]string{"display": "token"}, SearchParameter{Type: "token", Name: "display", Modifier: "not"}, false},
{"display:unsupported", map[string]string{"display": "token"}, SearchParameter{}, true},
}

//test && assert
Expand Down Expand Up @@ -147,10 +149,10 @@ func TestSearchCodeToWhereClause(t *testing.T) {
{SearchParameter{Type: "date", Name: "issueDate", Modifier: ""}, SearchParameterValue{Value: time.Date(2013, time.January, 14, 10, 0, 0, 0, time.UTC), Prefix: "lt", SecondaryValues: map[string]interface{}{}}, "1_1", "(issueDate < @issueDate_1_1)", map[string]interface{}{"issueDate_1_1": time.Date(2013, time.January, 14, 10, 0, 0, 0, time.UTC)}, false},

{SearchParameter{Type: "string", Name: "given", Modifier: ""}, SearchParameterValue{Value: "eve", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(givenJson.value LIKE @given_0_0)", map[string]interface{}{"given_0_0": "eve%"}, false},
{SearchParameter{Type: "string", Name: "given", Modifier: "contains"}, SearchParameterValue{Value: "eve", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(givenJson.value LIKE @given_0_0)", map[string]interface{}{"given_0_0": "%eve%"}, false},
{SearchParameter{Type: "string", Name: "given", Modifier: "exact"}, SearchParameterValue{Value: "eve", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(givenJson.value = @given_0_0)", map[string]interface{}{"given_0_0": "eve"}, false},
{SearchParameter{Type: "string", Name: "given", Modifier: "contains"}, SearchParameterValue{Value: "eve", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(givenJson.value LIKE @given_contains_0_0)", map[string]interface{}{"given_contains_0_0": "%eve%"}, false},
{SearchParameter{Type: "string", Name: "given", Modifier: "exact"}, SearchParameterValue{Value: "eve", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(givenJson.value = @given_exact_0_0)", map[string]interface{}{"given_exact_0_0": "eve"}, false},

{SearchParameter{Type: "uri", Name: "url", Modifier: "below"}, SearchParameterValue{Value: "http://acme.org/fhir/", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(url LIKE @url_0_0)", map[string]interface{}{"url_0_0": "http://acme.org/fhir/%"}, false},
{SearchParameter{Type: "uri", Name: "url", Modifier: "below"}, SearchParameterValue{Value: "http://acme.org/fhir/", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(url LIKE @url_below_0_0)", map[string]interface{}{"url_below_0_0": "http://acme.org/fhir/%"}, false},
{SearchParameter{Type: "uri", Name: "url", Modifier: "above"}, SearchParameterValue{Value: "http://acme.org/fhir/", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "", map[string]interface{}{}, true}, //above modifier not supported

{SearchParameter{Type: "quantity", Name: "valueQuantity", Modifier: ""}, SearchParameterValue{Value: float64(5.4), Prefix: "", SecondaryValues: map[string]interface{}{"valueQuantityCode": "mg"}}, "0_0", "(valueQuantityJson.value ->> '$.value' = @valueQuantity_0_0 AND valueQuantityJson.value ->> '$.code' = @valueQuantityCode_0_0)", map[string]interface{}{"valueQuantity_0_0": float64(5.4), "valueQuantityCode_0_0": "mg"}, false},
Expand All @@ -161,7 +163,9 @@ func TestSearchCodeToWhereClause(t *testing.T) {

{SearchParameter{Type: "token", Name: "code", Modifier: ""}, SearchParameterValue{Value: "ha125", Prefix: "", SecondaryValues: map[string]interface{}{"codeSystem": "http://acme.org/conditions/codes"}}, "0_0", "(codeJson.value ->> '$.code' = @code_0_0 AND codeJson.value ->> '$.system' = @codeSystem_0_0)", map[string]interface{}{"code_0_0": "ha125", "codeSystem_0_0": "http://acme.org/conditions/codes"}, false},
{SearchParameter{Type: "token", Name: "code", Modifier: ""}, SearchParameterValue{Value: "ha125", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(codeJson.value ->> '$.code' = @code_0_0)", map[string]interface{}{"code_0_0": "ha125"}, false},
{SearchParameter{Type: "token", Name: "identifier", Modifier: "otype"}, SearchParameterValue{Value: "MR|446053", Prefix: "", SecondaryValues: map[string]interface{}{"identifierSystem": "http://terminology.hl7.org/CodeSystem/v2-0203"}}, "0_0", "(identifierJson.value ->> '$.code' = @identifier_0_0 AND identifierJson.value ->> '$.system' = @identifierSystem_0_0)", map[string]interface{}{"identifier_0_0": "MR|446053", "identifierSystem_0_0": "http://terminology.hl7.org/CodeSystem/v2-0203"}, false},
{SearchParameter{Type: "token", Name: "identifier", Modifier: ""}, SearchParameterValue{Value: "MR|446053", Prefix: "", SecondaryValues: map[string]interface{}{"identifierSystem": "http://terminology.hl7.org/CodeSystem/v2-0203"}}, "0_0", "(identifierJson.value ->> '$.code' = @identifier_0_0 AND identifierJson.value ->> '$.system' = @identifierSystem_0_0)", map[string]interface{}{"identifier_0_0": "MR|446053", "identifierSystem_0_0": "http://terminology.hl7.org/CodeSystem/v2-0203"}, false},
{SearchParameter{Type: "token", Name: "gender", Modifier: ""}, SearchParameterValue{Value: "male", Prefix: "", SecondaryValues: map[string]interface{}{"genderSystem": "http://terminology.hl7.org/CodeSystem/v2-0203"}}, "0_0", "(genderJson.value ->> '$.code' = @gender_0_0 AND genderJson.value ->> '$.system' = @genderSystem_0_0)", map[string]interface{}{"gender_0_0": "male", "genderSystem_0_0": "http://terminology.hl7.org/CodeSystem/v2-0203"}, false},
{SearchParameter{Type: "token", Name: "gender", Modifier: "not"}, SearchParameterValue{Value: "male", Prefix: "", SecondaryValues: map[string]interface{}{"genderSystem": "http://terminology.hl7.org/CodeSystem/v2-0203"}}, "0_0", "(genderJson.value ->> '$.code' <> @gender_not_0_0 AND genderJson.value ->> '$.system' = @genderSystem_not_0_0)", map[string]interface{}{"gender_not_0_0": "male", "genderSystem_not_0_0": "http://terminology.hl7.org/CodeSystem/v2-0203"}, false},

{SearchParameter{Type: "keyword", Name: "id", Modifier: ""}, SearchParameterValue{Value: "1234", Prefix: "", SecondaryValues: map[string]interface{}{}}, "0_0", "(id = @id_0_0)", map[string]interface{}{"id_0_0": "1234"}, false},
}
Expand Down
Loading
Loading