From 893fe01f082f1a5968b5f6804aa2502dc0b9ebbc Mon Sep 17 00:00:00 2001 From: oleg-odysseus Date: Wed, 9 Oct 2024 22:24:36 +0200 Subject: [PATCH 1/4] Batch operation for fetching related standard concepts with reverse mappings --- .../webapi/service/VocabularyService.java | 64 ++++++++++++++- .../vocabulary/MappedRelatedConcept.java | 12 +++ ...dard_concepts_permission_if_not_exists.sql | 18 +++++ .../sql/getRelatedStandardMappedConcepts.sql | 78 +++++++++++++++++++ 4 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/ohdsi/webapi/vocabulary/MappedRelatedConcept.java create mode 100644 src/main/resources/db/migration/postgresql/V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql create mode 100644 src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql diff --git a/src/main/java/org/ohdsi/webapi/service/VocabularyService.java b/src/main/java/org/ohdsi/webapi/service/VocabularyService.java index e034fb41c2..c741742693 100644 --- a/src/main/java/org/ohdsi/webapi/service/VocabularyService.java +++ b/src/main/java/org/ohdsi/webapi/service/VocabularyService.java @@ -71,6 +71,7 @@ import org.springframework.jdbc.core.RowCallbackHandler; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; +import org.ohdsi.webapi.vocabulary.MappedRelatedConcept; /** * Provides REST services for working with @@ -783,7 +784,68 @@ public Collection getRelatedConcepts(@PathParam("sourceKey") Str return concepts.values(); } - /** + @POST + @Path("{sourceKey}/related-standard") + @Produces(MediaType.APPLICATION_JSON) + public Collection getRelatedStandardMappedConcepts(@PathParam("sourceKey") String sourceKey, List conceptIds) { + Source source = getSourceRepository().findBySourceKey(sourceKey); + String sqlPath = "/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql"; + String tableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Vocabulary); + + String[] searchStrings = {"CDM_schema"}; + String[] replacementStrings = {tableQualifier}; + + String[] varNames = {"conceptIdList"}; + Object[] varValues = {conceptIds.toArray()}; + + PreparedStatementRenderer psr = new PreparedStatementRenderer(source, sqlPath, searchStrings, replacementStrings, varNames, varValues); + + final Map concepts = new HashMap<>(); + getSourceJdbcTemplate(source).query(psr.getSql(), psr.getSetter(), (RowMapper) (resultSet, arg1) -> { + addMappedRelationships(concepts, resultSet); + return null; + }); + return concepts.values(); + } + private void addMappedRelationships(final Map concepts, final ResultSet resultSet) throws SQLException { + final Long concept_id = resultSet.getLong("CONCEPT_ID"); + if (!concepts.containsKey(concept_id)) { + final MappedRelatedConcept concept = new MappedRelatedConcept(); + concept.conceptId = concept_id; + concept.conceptCode = resultSet.getString("CONCEPT_CODE"); + concept.conceptName = resultSet.getString("CONCEPT_NAME"); + concept.standardConcept = resultSet.getString("STANDARD_CONCEPT"); + concept.invalidReason = resultSet.getString("INVALID_REASON"); + concept.vocabularyId = resultSet.getString("VOCABULARY_ID"); + concept.validStartDate = resultSet.getDate("VALID_START_DATE"); + concept.validEndDate = resultSet.getDate("VALID_END_DATE"); + concept.conceptClassId = resultSet.getString("CONCEPT_CLASS_ID"); + concept.domainId = resultSet.getString("DOMAIN_ID"); + + final ConceptRelationship relationship = new ConceptRelationship(); + relationship.relationshipName = resultSet.getString("RELATIONSHIP_NAME"); + relationship.relationshipDistance = resultSet.getInt("RELATIONSHIP_DISTANCE"); + concept.relationships.add(relationship); + + concept.mappedFromIds = extractMappedFromIds(resultSet); + concepts.put(concept_id, concept); + } else { + final ConceptRelationship relationship = new ConceptRelationship(); + relationship.relationshipName = resultSet.getString("RELATIONSHIP_NAME"); + relationship.relationshipDistance = resultSet.getInt("RELATIONSHIP_DISTANCE"); + concepts.get(concept_id).relationships.add(relationship); + concepts.get(concept_id).mappedFromIds.addAll(extractMappedFromIds(resultSet)); + } + } + private Set extractMappedFromIds(ResultSet resultSet) throws SQLException { + String mappedFromIds = resultSet.getString("mapped_from"); + return Arrays.stream(mappedFromIds.split(",")) + .map(Long::parseLong) + .collect(Collectors.toSet()); + } + + + /** * Get ancestor and descendant concepts for the selected concept identifier * from a source. * diff --git a/src/main/java/org/ohdsi/webapi/vocabulary/MappedRelatedConcept.java b/src/main/java/org/ohdsi/webapi/vocabulary/MappedRelatedConcept.java new file mode 100644 index 0000000000..1d7cb2e0cc --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/vocabulary/MappedRelatedConcept.java @@ -0,0 +1,12 @@ +package org.ohdsi.webapi.vocabulary; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Set; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class MappedRelatedConcept extends RelatedConcept { + @JsonProperty("mapped_from") + public Set mappedFromIds; +} diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql b/src/main/resources/db/migration/postgresql/V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql new file mode 100644 index 0000000000..c106df2543 --- /dev/null +++ b/src/main/resources/db/migration/postgresql/V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql @@ -0,0 +1,18 @@ +INSERT INTO ${ohdsiSchema}.sec_permission (id, value, description) +SELECT nextval('${ohdsiSchema}.sec_permission_id_seq'), 'vocabulary:*:related-standard:post', 'Access related mapped standard concepts resource' +WHERE NOT EXISTS ( + SELECT NULL FROM ${ohdsiSchema}.sec_permission + WHERE value = 'vocabulary:*:related-standard:post' +); + +INSERT INTO ${ohdsiSchema}.sec_role_permission(id, role_id, permission_id) +SELECT nextval('${ohdsiSchema}.sec_role_permission_sequence'), sr.id, sp.id +FROM ${ohdsiSchema}.sec_permission SP, ${ohdsiSchema}.sec_role sr +WHERE sp.value IN ( + 'vocabulary:*:related-standard:post' + ) AND sr.name IN ('Atlas users') + AND NOT EXISTS ( + SELECT NULL FROM ${ohdsiSchema}.sec_role_permission + WHERE permission_id = sp.id and role_id = sr.id); + + diff --git a/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql b/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql new file mode 100644 index 0000000000..5c727c31e1 --- /dev/null +++ b/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql @@ -0,0 +1,78 @@ +SELECT + c.CONCEPT_ID, + c.CONCEPT_NAME, + COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, + COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, + c.CONCEPT_CODE, + c.CONCEPT_CLASS_ID, + c.DOMAIN_ID, + c.VOCABULARY_ID, + c.VALID_START_DATE, + c.VALID_END_DATE, + c.RELATIONSHIP_NAME, + c.RELATIONSHIP_DISTANCE, + STRING_AGG(DISTINCT c.mapped_from_id, ',') AS mapped_from +FROM ( + SELECT + c.CONCEPT_ID, CONCEPT_NAME, COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, + c.CONCEPT_CODE, c.CONCEPT_CLASS_ID, c.DOMAIN_ID, c.VOCABULARY_ID, c.VALID_START_DATE, c.VALID_END_DATE, + r.RELATIONSHIP_NAME, 1 as RELATIONSHIP_DISTANCE, + CAST(cr.CONCEPT_ID_1 AS VARCHAR) as mapped_from_id + FROM + @CDM_schema.concept_relationship cr + JOIN + @CDM_schema.concept c ON cr.CONCEPT_ID_2 = c.CONCEPT_ID + JOIN + @CDM_schema.relationship r ON cr.RELATIONSHIP_ID = r.RELATIONSHIP_ID + WHERE + cr.CONCEPT_ID_1 IN (@conceptIdList) + AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') + AND cr.INVALID_REASON IS NULL + + UNION ALL + + SELECT + ca.ANCESTOR_CONCEPT_ID as CONCEPT_ID, c.CONCEPT_NAME, COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, + c.CONCEPT_CODE, c.CONCEPT_CLASS_ID, c.DOMAIN_ID, c.VOCABULARY_ID, c.VALID_START_DATE, c.VALID_END_DATE, + 'Has ancestor of' as RELATIONSHIP_NAME, MIN_LEVELS_OF_SEPARATION as RELATIONSHIP_DISTANCE, + CAST(ca.DESCENDANT_CONCEPT_ID AS VARCHAR) as mapped_from_id + FROM + @CDM_schema.concept_ancestor ca + JOIN + @CDM_schema.concept c ON c.CONCEPT_ID = ca.ANCESTOR_CONCEPT_ID + WHERE + ca.DESCENDANT_CONCEPT_ID IN (@conceptIdList) + AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') + AND ca.ANCESTOR_CONCEPT_ID NOT IN (@conceptIdList) + + UNION ALL + + SELECT + ca.DESCENDANT_CONCEPT_ID as CONCEPT_ID, c.CONCEPT_NAME, COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, + c.CONCEPT_CODE, c.CONCEPT_CLASS_ID, c.DOMAIN_ID, c.VOCABULARY_ID, c.VALID_START_DATE, c.VALID_END_DATE, + 'Has descendant of' as RELATIONSHIP_NAME, MIN_LEVELS_OF_SEPARATION as RELATIONSHIP_DISTANCE, + CAST(ca.ANCESTOR_CONCEPT_ID AS VARCHAR) as mapped_from_id + FROM + @CDM_schema.concept_ancestor ca + JOIN + @CDM_schema.concept c ON c.CONCEPT_ID = ca.DESCENDANT_CONCEPT_ID + WHERE + ca.ANCESTOR_CONCEPT_ID IN (@conceptIdList) + AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') + AND ca.DESCENDANT_CONCEPT_ID NOT IN (@conceptIdList) +) c +GROUP BY + c.CONCEPT_ID, + c.CONCEPT_NAME, + c.STANDARD_CONCEPT, + c.INVALID_REASON, + c.CONCEPT_CODE, + c.CONCEPT_CLASS_ID, + c.DOMAIN_ID, + c.VOCABULARY_ID, + c.VALID_START_DATE, + c.VALID_END_DATE, + c.RELATIONSHIP_NAME, + c.RELATIONSHIP_DISTANCE +ORDER BY + c.RELATIONSHIP_DISTANCE ASC; \ No newline at end of file From 932b733409abc9293732bb858ee79cec6acf65ce Mon Sep 17 00:00:00 2001 From: oleg-odysseus Date: Wed, 6 Nov 2024 12:45:57 +0100 Subject: [PATCH 2/4] Optimized SQL for fetching related standard concepts, eliminated vendor-specific string aggregating function --- .../webapi/service/VocabularyService.java | 100 ++++++++++-------- .../sql/getRelatedStandardMappedConcepts.sql | 38 +------ ...tandardMappedConcepts_getMappedFromIds.sql | 20 ++++ 3 files changed, 78 insertions(+), 80 deletions(-) create mode 100644 src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts_getMappedFromIds.sql diff --git a/src/main/java/org/ohdsi/webapi/service/VocabularyService.java b/src/main/java/org/ohdsi/webapi/service/VocabularyService.java index c741742693..9de8432a22 100644 --- a/src/main/java/org/ohdsi/webapi/service/VocabularyService.java +++ b/src/main/java/org/ohdsi/webapi/service/VocabularyService.java @@ -3,6 +3,8 @@ import static org.ohdsi.webapi.service.cscompare.ConceptSetCompareService.CONCEPT_SET_COMPARISON_ROW_MAPPER; import static org.ohdsi.webapi.util.SecurityUtils.whitelist; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -97,7 +99,10 @@ public class VocabularyService extends AbstractDaoService { @Autowired private ConceptSetCompareService conceptSetCompareService; - + + @Autowired + private ObjectMapper objectMapper; + @Value("${datasource.driverClassName}") private String driver; @@ -787,63 +792,70 @@ public Collection getRelatedConcepts(@PathParam("sourceKey") Str @POST @Path("{sourceKey}/related-standard") @Produces(MediaType.APPLICATION_JSON) - public Collection getRelatedStandardMappedConcepts(@PathParam("sourceKey") String sourceKey, List conceptIds) { + public Collection getRelatedStandardMappedConcepts(@PathParam("sourceKey") String sourceKey, List allConceptIds) { Source source = getSourceRepository().findBySourceKey(sourceKey); - String sqlPath = "/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql"; + String relatedConceptsSQLPath = "/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql"; + String relatedMappedFromIdsSQLPath = "/resources/vocabulary/sql/getRelatedStandardMappedConcepts_getMappedFromIds.sql"; String tableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Vocabulary); String[] searchStrings = {"CDM_schema"}; String[] replacementStrings = {tableQualifier}; String[] varNames = {"conceptIdList"}; - Object[] varValues = {conceptIds.toArray()}; - - PreparedStatementRenderer psr = new PreparedStatementRenderer(source, sqlPath, searchStrings, replacementStrings, varNames, varValues); - final Map concepts = new HashMap<>(); - getSourceJdbcTemplate(source).query(psr.getSql(), psr.getSetter(), (RowMapper) (resultSet, arg1) -> { - addMappedRelationships(concepts, resultSet); - return null; - }); - return concepts.values(); + final Map resultCombinedMappedConcepts = new HashMap<>(); + final Map relatedStandardConcepts = new HashMap<>(); + for(final List conceptIdsBatch: Lists.partition(allConceptIds, PreparedSqlRender.getParameterLimit(source))) { + Object[] varValues = {conceptIdsBatch.toArray()}; + PreparedStatementRenderer relatedConceptsRenderer = new PreparedStatementRenderer(source, relatedConceptsSQLPath, searchStrings, replacementStrings, varNames, varValues); + getSourceJdbcTemplate(source).query(relatedConceptsRenderer.getSql(), relatedConceptsRenderer.getSetter(), (RowMapper) (resultSet, arg1) -> { + addRelationships(relatedStandardConcepts, resultSet); + return null; + }); + + final Map> relatedNonStandardConceptIdsByStandardId = new HashMap<>(); + + PreparedStatementRenderer mappedFromConceptsRenderer = new PreparedStatementRenderer(source, relatedMappedFromIdsSQLPath, searchStrings, replacementStrings, varNames, varValues); + getSourceJdbcTemplate(source).query(mappedFromConceptsRenderer.getSql(), mappedFromConceptsRenderer.getSetter(), (RowMapper) (resultSet, arg1) -> { + populateRelatedConceptIds(relatedNonStandardConceptIdsByStandardId, resultSet); + return null; + }); + + enrichResultCombinedMappedConcepts(resultCombinedMappedConcepts, relatedStandardConcepts, relatedNonStandardConceptIdsByStandardId); + } + return resultCombinedMappedConcepts.values(); } - private void addMappedRelationships(final Map concepts, final ResultSet resultSet) throws SQLException { + + private void populateRelatedConceptIds(final Map> mappedConceptsIds, final ResultSet resultSet) throws SQLException { final Long concept_id = resultSet.getLong("CONCEPT_ID"); - if (!concepts.containsKey(concept_id)) { - final MappedRelatedConcept concept = new MappedRelatedConcept(); - concept.conceptId = concept_id; - concept.conceptCode = resultSet.getString("CONCEPT_CODE"); - concept.conceptName = resultSet.getString("CONCEPT_NAME"); - concept.standardConcept = resultSet.getString("STANDARD_CONCEPT"); - concept.invalidReason = resultSet.getString("INVALID_REASON"); - concept.vocabularyId = resultSet.getString("VOCABULARY_ID"); - concept.validStartDate = resultSet.getDate("VALID_START_DATE"); - concept.validEndDate = resultSet.getDate("VALID_END_DATE"); - concept.conceptClassId = resultSet.getString("CONCEPT_CLASS_ID"); - concept.domainId = resultSet.getString("DOMAIN_ID"); - - final ConceptRelationship relationship = new ConceptRelationship(); - relationship.relationshipName = resultSet.getString("RELATIONSHIP_NAME"); - relationship.relationshipDistance = resultSet.getInt("RELATIONSHIP_DISTANCE"); - concept.relationships.add(relationship); - - concept.mappedFromIds = extractMappedFromIds(resultSet); - concepts.put(concept_id, concept); + if (!mappedConceptsIds.containsKey(concept_id)) { + Set mappedIds = new HashSet<>(); + mappedIds.add(resultSet.getLong("MAPPED_FROM_ID")); + mappedConceptsIds.put(concept_id,mappedIds); } else { - final ConceptRelationship relationship = new ConceptRelationship(); - relationship.relationshipName = resultSet.getString("RELATIONSHIP_NAME"); - relationship.relationshipDistance = resultSet.getInt("RELATIONSHIP_DISTANCE"); - concepts.get(concept_id).relationships.add(relationship); - concepts.get(concept_id).mappedFromIds.addAll(extractMappedFromIds(resultSet)); + mappedConceptsIds.get(concept_id).add(resultSet.getLong("MAPPED_FROM_ID")); } } - private Set extractMappedFromIds(ResultSet resultSet) throws SQLException { - String mappedFromIds = resultSet.getString("mapped_from"); - return Arrays.stream(mappedFromIds.split(",")) - .map(Long::parseLong) - .collect(Collectors.toSet()); - } + void enrichResultCombinedMappedConcepts(Map resultCombinedMappedConcepts, + Map relatedStandardConcepts, + Map> relatedNonStandardConceptIdsByStandardId) { + relatedNonStandardConceptIdsByStandardId.forEach((standardConceptId, mappedFromIds)->{ + if(resultCombinedMappedConcepts.containsKey(standardConceptId)){ + resultCombinedMappedConcepts.get(standardConceptId).mappedFromIds.addAll(mappedFromIds); + } else { + MappedRelatedConcept mappedRelatedConcept; + try { + mappedRelatedConcept = objectMapper.readValue(objectMapper.writeValueAsString(relatedStandardConcepts.get(standardConceptId)), MappedRelatedConcept.class); + mappedRelatedConcept.mappedFromIds=mappedFromIds; + resultCombinedMappedConcepts.put(standardConceptId,mappedRelatedConcept); + } catch (JsonProcessingException e) { + log.error("Could not convert RelatedConcept to MappedRelatedConcept", e); + throw new WebApplicationException(e); + } + } + }); + } /** * Get ancestor and descendant concepts for the selected concept identifier diff --git a/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql b/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql index 5c727c31e1..fae14064de 100644 --- a/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql +++ b/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts.sql @@ -10,14 +10,12 @@ SELECT c.VALID_START_DATE, c.VALID_END_DATE, c.RELATIONSHIP_NAME, - c.RELATIONSHIP_DISTANCE, - STRING_AGG(DISTINCT c.mapped_from_id, ',') AS mapped_from + c.RELATIONSHIP_DISTANCE FROM ( SELECT c.CONCEPT_ID, CONCEPT_NAME, COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, c.CONCEPT_CODE, c.CONCEPT_CLASS_ID, c.DOMAIN_ID, c.VOCABULARY_ID, c.VALID_START_DATE, c.VALID_END_DATE, - r.RELATIONSHIP_NAME, 1 as RELATIONSHIP_DISTANCE, - CAST(cr.CONCEPT_ID_1 AS VARCHAR) as mapped_from_id + r.RELATIONSHIP_NAME, 1 as RELATIONSHIP_DISTANCE FROM @CDM_schema.concept_relationship cr JOIN @@ -28,38 +26,6 @@ FROM ( cr.CONCEPT_ID_1 IN (@conceptIdList) AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') AND cr.INVALID_REASON IS NULL - - UNION ALL - - SELECT - ca.ANCESTOR_CONCEPT_ID as CONCEPT_ID, c.CONCEPT_NAME, COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, - c.CONCEPT_CODE, c.CONCEPT_CLASS_ID, c.DOMAIN_ID, c.VOCABULARY_ID, c.VALID_START_DATE, c.VALID_END_DATE, - 'Has ancestor of' as RELATIONSHIP_NAME, MIN_LEVELS_OF_SEPARATION as RELATIONSHIP_DISTANCE, - CAST(ca.DESCENDANT_CONCEPT_ID AS VARCHAR) as mapped_from_id - FROM - @CDM_schema.concept_ancestor ca - JOIN - @CDM_schema.concept c ON c.CONCEPT_ID = ca.ANCESTOR_CONCEPT_ID - WHERE - ca.DESCENDANT_CONCEPT_ID IN (@conceptIdList) - AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') - AND ca.ANCESTOR_CONCEPT_ID NOT IN (@conceptIdList) - - UNION ALL - - SELECT - ca.DESCENDANT_CONCEPT_ID as CONCEPT_ID, c.CONCEPT_NAME, COALESCE(c.STANDARD_CONCEPT, 'N') as STANDARD_CONCEPT, COALESCE(c.INVALID_REASON, 'V') as INVALID_REASON, - c.CONCEPT_CODE, c.CONCEPT_CLASS_ID, c.DOMAIN_ID, c.VOCABULARY_ID, c.VALID_START_DATE, c.VALID_END_DATE, - 'Has descendant of' as RELATIONSHIP_NAME, MIN_LEVELS_OF_SEPARATION as RELATIONSHIP_DISTANCE, - CAST(ca.ANCESTOR_CONCEPT_ID AS VARCHAR) as mapped_from_id - FROM - @CDM_schema.concept_ancestor ca - JOIN - @CDM_schema.concept c ON c.CONCEPT_ID = ca.DESCENDANT_CONCEPT_ID - WHERE - ca.ANCESTOR_CONCEPT_ID IN (@conceptIdList) - AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') - AND ca.DESCENDANT_CONCEPT_ID NOT IN (@conceptIdList) ) c GROUP BY c.CONCEPT_ID, diff --git a/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts_getMappedFromIds.sql b/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts_getMappedFromIds.sql new file mode 100644 index 0000000000..a1db504bed --- /dev/null +++ b/src/main/resources/resources/vocabulary/sql/getRelatedStandardMappedConcepts_getMappedFromIds.sql @@ -0,0 +1,20 @@ +SELECT + c.CONCEPT_ID, + c.MAPPED_FROM_ID +FROM ( + SELECT DISTINCT + c.CONCEPT_ID, + CAST(cr.CONCEPT_ID_1 AS VARCHAR) as MAPPED_FROM_ID + FROM + @CDM_schema.concept_relationship cr + JOIN + @CDM_schema.concept c ON cr.CONCEPT_ID_2 = c.CONCEPT_ID + JOIN + @CDM_schema.relationship r ON cr.RELATIONSHIP_ID = r.RELATIONSHIP_ID + WHERE + cr.CONCEPT_ID_1 IN (@conceptIdList) + AND COALESCE(c.STANDARD_CONCEPT, 'N') IN ('S', 'C') + AND cr.INVALID_REASON IS NULL +) c +ORDER BY + c.CONCEPT_ID; \ No newline at end of file From 49cef233f143b10b0206039ec4c8859b1600bdba Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Tue, 12 Nov 2024 13:57:55 +0100 Subject: [PATCH 3/4] Renaming the migration script --- ...1__add_related_standard_concepts_permission_if_not_exists.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/db/migration/postgresql/{V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql => V2.15.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql} (100%) diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql b/src/main/resources/db/migration/postgresql/V2.15.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql similarity index 100% rename from src/main/resources/db/migration/postgresql/V2.14.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql rename to src/main/resources/db/migration/postgresql/V2.15.0.20241009000001__add_related_standard_concepts_permission_if_not_exists.sql From defec06735729ad21207f144e75931f4b4a32419 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Tue, 18 Feb 2025 11:57:19 -0500 Subject: [PATCH 4/4] Update git actions to use cache@v4. --- .github/workflows/ci.yaml | 4 ++-- .github/workflows/release.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 21492840f4..57a6318cf5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -30,7 +30,7 @@ jobs: java-version: 8 - name: Maven cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: # Cache gradle directories path: ~/.m2 @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v2 - name: Cache Docker layers - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a9624b5e1b..5c029bac62 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -26,7 +26,7 @@ jobs: java-version: 8 - name: Maven cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: # Cache gradle directories path: ~/.m2