diff --git a/open-api/swagger.yaml b/open-api/swagger.yaml index ff6637471a..f957be25e7 100644 --- a/open-api/swagger.yaml +++ b/open-api/swagger.yaml @@ -1876,6 +1876,32 @@ paths: description: > No concept exists with the concept code, or the user does not have access to the concept. + '/v2/concepts/{conceptCode}/modifiers': + get: + description: > + Gets the modifiers associated with a particular concept code if it exists + and the user has access to it. + tags: + - v2 + parameters: + - name: conceptCode + required: true + in: path + description: Concept code of the concept. + schema: + type: string + responses: + '200': + description: | + Returns a list of modifier names associated with the given concept. + content: + '*/*': + schema: + $ref: '#/components/schemas/ConceptModifiers' + '404': + description: > + No concept exists with the concept code, or the user does not have + access to the concept. /v2/tree_nodes: get: @@ -3383,6 +3409,14 @@ components: name: type: string + ConceptModifiers: + type: object + properties: + modifiers: + type: array + items: + type: string + VariableMetadata: type: object properties: diff --git a/transmart-core-api/src/main/groovy/org/transmartproject/core/concept/ConceptsResource.groovy b/transmart-core-api/src/main/groovy/org/transmartproject/core/concept/ConceptsResource.groovy index ddbcde18da..0485902d8c 100644 --- a/transmart-core-api/src/main/groovy/org/transmartproject/core/concept/ConceptsResource.groovy +++ b/transmart-core-api/src/main/groovy/org/transmartproject/core/concept/ConceptsResource.groovy @@ -49,4 +49,5 @@ interface ConceptsResource { */ String getConceptCodeByConceptPath(String conceptPath) throws NoSuchResourceException + List getModifiersByConceptCode(String conceptCode, User user) throws NoSuchResourceException } diff --git a/transmart-core-api/src/main/groovy/org/transmartproject/core/multidimquery/MultiDimensionalDataResource.groovy b/transmart-core-api/src/main/groovy/org/transmartproject/core/multidimquery/MultiDimensionalDataResource.groovy index 68820fcc42..48d6c554f6 100644 --- a/transmart-core-api/src/main/groovy/org/transmartproject/core/multidimquery/MultiDimensionalDataResource.groovy +++ b/transmart-core-api/src/main/groovy/org/transmartproject/core/multidimquery/MultiDimensionalDataResource.groovy @@ -69,4 +69,5 @@ interface MultiDimensionalDataResource { Iterable getSupportedDimensions(Constraint constraint) + List getModifiersForConcept(String conceptCode) } diff --git a/transmart-core-db/grails-app/services/org/transmartproject/db/clinical/MultidimensionalDataResourceService.groovy b/transmart-core-db/grails-app/services/org/transmartproject/db/clinical/MultidimensionalDataResourceService.groovy index d924b838a2..72970155c9 100644 --- a/transmart-core-db/grails-app/services/org/transmartproject/db/clinical/MultidimensionalDataResourceService.groovy +++ b/transmart-core-db/grails-app/services/org/transmartproject/db/clinical/MultidimensionalDataResourceService.groovy @@ -18,6 +18,7 @@ import org.hibernate.criterion.Restrictions import org.hibernate.criterion.Subqueries import org.hibernate.internal.CriteriaImpl import org.hibernate.internal.StatelessSessionImpl +import org.hibernate.transform.Transformers import org.springframework.beans.factory.annotation.Autowired import org.transmartproject.core.IterableResult import org.transmartproject.core.multidimquery.datatable.PaginationParameters @@ -179,6 +180,21 @@ class MultidimensionalDataResourceService extends AbstractDataResourceService im getAvailableDimensions(getConstraintStudies(constraint)) } + @CompileDynamic + List getModifiersForConcept(String conceptCode) { + def session = (StatelessSessionImpl) sessionFactory.openStatelessSession() + session.connection().autoCommit = false + def results = (List)session.createSQLQuery("SELECT DISTINCT of.concept_cd, of.modifier_cd, mod.name_char " + \ + "FROM i2b2demodata.observation_fact as of " + \ + "INNER JOIN i2b2demodata.modifier_dimension as mod ON of.modifier_cd = mod.modifier_cd " + \ + "WHERE of.concept_cd = :conceptCode") + .setString("conceptCode", conceptCode) + .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP) + .list() + session.close() + results.collect{ Map result -> (String)result.get('name_char') } + } + // FIXME: Enable static compilation @CompileDynamic private Query buildCriteria(Set dimensions, ImmutableMap orderDims) { diff --git a/transmart-core-db/grails-app/services/org/transmartproject/db/concept/ConceptsService.groovy b/transmart-core-db/grails-app/services/org/transmartproject/db/concept/ConceptsService.groovy index 009fb69e37..a231257a71 100644 --- a/transmart-core-db/grails-app/services/org/transmartproject/db/concept/ConceptsService.groovy +++ b/transmart-core-db/grails-app/services/org/transmartproject/db/concept/ConceptsService.groovy @@ -12,10 +12,16 @@ import org.transmartproject.core.exceptions.NoSuchResourceException import org.transmartproject.core.concept.Concept import org.transmartproject.core.concept.ConceptsResource import org.transmartproject.core.multidimquery.MultiDimensionalDataResource +import org.transmartproject.core.multidimquery.query.AndConstraint +import org.transmartproject.core.multidimquery.query.Constraint +import org.transmartproject.core.multidimquery.query.Field +import org.transmartproject.core.multidimquery.query.FieldConstraint +import org.transmartproject.core.multidimquery.query.Operator import org.transmartproject.core.users.User import org.transmartproject.db.i2b2data.ConceptDimension import org.transmartproject.core.multidimquery.query.ConceptConstraint import org.transmartproject.core.multidimquery.query.TrueConstraint +import org.transmartproject.db.i2b2data.ObservationFact import java.util.concurrent.ConcurrentHashMap @@ -122,4 +128,9 @@ class ConceptsService implements ConceptsResource, ApplicationRunner { code } + @Override + List getModifiersByConceptCode(String conceptCode, User user) throws NoSuchResourceException { + getConceptByConceptCodeForUser(conceptCode, user) + multiDimService.getModifiersForConcept(conceptCode) + } } diff --git a/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/ConceptController.groovy b/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/ConceptController.groovy index 99ef142a03..da307ab5e1 100644 --- a/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/ConceptController.groovy +++ b/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/ConceptController.groovy @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestParam import org.transmartproject.core.concept.Concept import org.transmartproject.core.concept.ConceptsResource +import org.transmartproject.rest.marshallers.ConceptModifiersWrapper import org.transmartproject.rest.marshallers.ConceptWrapper import org.transmartproject.rest.marshallers.ContainerResponseWrapper @@ -43,6 +44,13 @@ class ConceptController extends AbstractQueryController { ) } + def getModifiers(@RequestParam('api_version') String apiVersion, @PathVariable('conceptCode') String conceptCode) { + checkForUnsupportedParams(params, ['conceptCode']) + respond new ConceptModifiersWrapper( + modifiers: conceptsResource.getModifiersByConceptCode(conceptCode, authContext.user) + ) + } + private static wrapConcepts(String apiVersion, Collection source) { new ContainerResponseWrapper( key: 'concepts', diff --git a/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/RestApiUrlMappings.groovy b/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/RestApiUrlMappings.groovy index 3c67f7d4eb..d9f1dcdb5d 100644 --- a/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/RestApiUrlMappings.groovy +++ b/transmart-rest-api/grails-app/controllers/org/transmartproject/rest/RestApiUrlMappings.groovy @@ -122,6 +122,9 @@ class RestApiUrlMappings { "/concepts/${conceptCode}"(method: 'GET', controller: 'concept', action: 'show') { apiVersion = 'v2' } + "/concepts/${conceptCode}/modifiers"(method: 'GET', controller: 'concept', action: 'getModifiers') { + apiVersion = 'v2' + } "/tree_nodes"(method: 'GET', controller: 'tree', action: 'index') { apiVersion = 'v2' } diff --git a/transmart-rest-api/src/main/groovy/org/transmartproject/rest/marshallers/ConceptModifiersSerializationHelper.groovy b/transmart-rest-api/src/main/groovy/org/transmartproject/rest/marshallers/ConceptModifiersSerializationHelper.groovy new file mode 100644 index 0000000000..8643d6bb40 --- /dev/null +++ b/transmart-rest-api/src/main/groovy/org/transmartproject/rest/marshallers/ConceptModifiersSerializationHelper.groovy @@ -0,0 +1,17 @@ +package org.transmartproject.rest.marshallers + +import grails.rest.Link + +import static grails.rest.render.util.AbstractLinkingRenderer.RELATIONSHIP_SELF + +class ConceptModifiersSerializationHelper extends AbstractHalOrJsonSerializationHelper { + + final Class targetType = ConceptModifiersWrapper + + final String collectionName = 'modifiers' + + @Override + Map convertToMap(ConceptModifiersWrapper object) { + [modifiers: object.modifiers] + } +} diff --git a/transmart-rest-api/src/main/groovy/org/transmartproject/rest/marshallers/ConceptModifiersWrapper.groovy b/transmart-rest-api/src/main/groovy/org/transmartproject/rest/marshallers/ConceptModifiersWrapper.groovy new file mode 100644 index 0000000000..aa4ad825bc --- /dev/null +++ b/transmart-rest-api/src/main/groovy/org/transmartproject/rest/marshallers/ConceptModifiersWrapper.groovy @@ -0,0 +1,5 @@ +package org.transmartproject.rest.marshallers + +class ConceptModifiersWrapper { + List modifiers +}