Skip to content

Commit

Permalink
Merge pull request #1068 from b2ihealthcare/issue/SO-5535-MRCM_applic…
Browse files Browse the repository at this point in the history
…able_predicates

SO-5535: MRCM evaluations
  • Loading branch information
cmark authored Dec 7, 2022
2 parents 78c65c6 + d5914a9 commit fea71e2
Show file tree
Hide file tree
Showing 16 changed files with 886 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ private Concepts() { }
// MRCM Attribute Range
public static final String ATTRIBUTE_TYPE_RANGE_CONSTRAINT = "723575003";
public static final String ATTRIBUTE_TYPE_ATTRIBUTE_RULE = "723576002";
public static final String ALL_PRECOORDINATED_CONTENT = "723594008";

// MRCM Module Scope
public static final String ATTRIBUTE_TYPE_RULE_REFSET = "723577006";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright 2022 B2i Healthcare Pte Ltd, http://b2i.sg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.b2international.snowowl.snomed.core.request;

import static com.b2international.snowowl.snomed.common.SnomedConstants.Concepts.SUBSTANCE;
import static com.b2international.snowowl.snomed.common.SnomedRf2Headers.FIELD_MRCM_RANGE_CONSTRAINT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.junit.Test;

import com.b2international.snowowl.snomed.common.SnomedConstants.Concepts;
import com.b2international.snowowl.snomed.core.MrcmAttributeType;
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSetMember;
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSetMembers;
import com.b2international.snowowl.snomed.datastore.request.SnomedRequests;
import com.b2international.snowowl.test.commons.Services;
import com.google.common.base.Objects;

/**
* @since 8.8.0
*/
public class SnomedMrcmTest {

private static final String CODESYSTEM = "SNOMEDCT";

@Test
public void applicableTypesTest() {
final String isAModificationOf = "738774007";
final String hasDisposition = "726542003";

SnomedReferenceSetMembers substanceDataTypes = SnomedRequests.prepareGetMrcmTypeRules()
.setAttributeType(MrcmAttributeType.DATA)
.setModuleIds(List.of(Concepts.MODULE_SCT_CORE))
.setParentIds(Set.of(SUBSTANCE))
.build(CODESYSTEM)
.execute(Services.bus())
.getSync(1, TimeUnit.MINUTES);
assertEquals(0, substanceDataTypes.getTotal());

Collection<String> substanceObjectTypes = SnomedRequests.prepareGetMrcmTypeRules()
.setAttributeType(MrcmAttributeType.OBJECT)
.setModuleIds(List.of(Concepts.MODULE_SCT_CORE))
.setParentIds(Set.of(SUBSTANCE))
.build(CODESYSTEM)
.execute(Services.bus())
.getSync(1, TimeUnit.MINUTES)
.stream()
.map(SnomedReferenceSetMember::getReferencedComponentId)
.collect(Collectors.toSet());

assertEquals(2, substanceObjectTypes.size());
assertTrue(substanceObjectTypes.containsAll(List.of(isAModificationOf, hasDisposition)));
}

@Test
public void applicableRangeTest() {
SnomedReferenceSetMembers substanceDataTypeRanges = SnomedRequests.prepareGetMrcmRangeRules()
.setAttributeType(MrcmAttributeType.DATA)
.setModuleIds(List.of(Concepts.MODULE_SCT_CORE))
.setParentIds(Set.of(SUBSTANCE))
.build(CODESYSTEM)
.execute(Services.bus())
.getSync(1, TimeUnit.MINUTES);
assertEquals(0, substanceDataTypeRanges.getTotal());

SnomedReferenceSetMembers substanceObjectTypeRanges = SnomedRequests.prepareGetMrcmRangeRules()
.setAttributeType(MrcmAttributeType.OBJECT)
.setModuleIds(List.of(Concepts.MODULE_SCT_CORE))
.setParentIds(Set.of(SUBSTANCE))
.build(CODESYSTEM)
.execute(Services.bus())
.getSync(1, TimeUnit.MINUTES);
assertEquals(2, substanceObjectTypeRanges.getTotal());
Map<String, String> ranges = Map.of("738774007", "<< 105590001 |Substance (substance)|", //Is A Modification Of
"726542003", "<< 726711005 |Disposition (disposition)|"); //Has Disposition
substanceObjectTypeRanges.forEach(member -> {
final String expectedRange = ranges.get(member.getReferencedComponentId());
final String actualRange = (String) member.getProperties().get(FIELD_MRCM_RANGE_CONSTRAINT);
assertTrue(String.format("Expected range (%s) does not match actual range (%s)", expectedRange, actualRange), Objects.equal(expectedRange, actualRange));
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
SnomedReferenceSetDeletionPerformanceTest.class,
SnomedConceptCreatePerformanceTest.class,
SnomedMergePerformanceTest.class,
SnomedMrcmTest.class
})
public class AllSnomedApiTests {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright 2022 B2i Healthcare Pte Ltd, http://b2i.sg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.b2international.snowowl.snomed.core.rest;

import java.util.List;
import java.util.Set;

import org.springframework.web.bind.annotation.*;

import com.b2international.snowowl.core.events.util.Promise;
import com.b2international.snowowl.core.rest.AbstractRestService;
import com.b2international.snowowl.snomed.core.MrcmAttributeType;
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSetMembers;
import com.b2international.snowowl.snomed.datastore.request.SnomedRequests;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

/**
* @since 8.8.0
*/
@Tag(description="MRCM Rules", name = "mrcm")
@RestController
public class SnomedMrcmRestService extends AbstractRestService {

@Operation(
summary="Retrieve MRCM attribute domain type refset members filtered by domain and attribute type",
description="Retrieve MRCM relationship type rules ")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "Bad Request"),
@ApiResponse(responseCode = "404", description = "Not found"),
})
@GetMapping(value = "/{path:**}/mrcm/types", produces = { AbstractRestService.JSON_MEDIA_TYPE })
public @ResponseBody Promise<SnomedReferenceSetMembers> getApplicableTypes(
@Parameter(description = "The resource path", required = true)
@PathVariable(name ="path")
final String path,

@Parameter(description = "The attribute types to include in the results", schema = @Schema(allowableValues = "all,object,data", defaultValue = "all"))
@RequestParam(name = "attributeType", defaultValue = "all")
final String attributeType,

@Parameter(name = "selfIds", description = "Set of concept ids that might form the domain of the rule", required = false)
@RequestParam(name = "selfIds", required = false)
final Set<String> selfIds,

@Parameter(name = "parentIds", description = "Set of parent/ancestor ids that might form the domain of the rule", required = false)
@RequestParam(name = "parentIds", required = false)
final Set<String> parentIds,

@Parameter(name = "refsetIds", description = "Set of reference set ids that might form the domain of the rule", required = false)
@RequestParam(name = "refsetIds", required = false)
final Set<String> refsetIds,

@Parameter(name = "moduleIds", description = "List of applicable modules refining the scope of returned rules", required = false)
@RequestParam(name = "moduleIds", required = false)
final List<String> moduleIds,

@RequestParam(name = "searchAfter", required = false)
@Parameter(name = "searchAfter", description = "The search key to use for retrieving the next page of results")
final String searchAfter,

@RequestParam(name = "limit", required = false, defaultValue = "50")
@Parameter(name = "limit",description = "The maximum number of items to return")
int limit) {

return SnomedRequests.prepareGetMrcmTypeRules()
.setAttributeType(MrcmAttributeType.getByNameIgnoreCase(attributeType))
.setModuleIds(moduleIds)
.setParentIds(parentIds)
.setRefSetIds(refsetIds)
.setSelfIds(selfIds)
.setLimit(limit)
.setSearchAfter(searchAfter)
.build(path)
.execute(getBus());
}

@Operation(
summary="Retrieve MRCM attribute domain range refset members filtered by domain and attribute type",
description="Retrieve MRCM relationship range rules ")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "Bad Request"),
@ApiResponse(responseCode = "404", description = "Not found"),
})
@GetMapping(value = "/{path:**}/mrcm/ranges", produces = { AbstractRestService.JSON_MEDIA_TYPE })
public @ResponseBody Promise<SnomedReferenceSetMembers> getApplicableRanges(
@Parameter(description = "The resource path", required = true)
@PathVariable(name ="path")
final String path,

@Parameter(description = "The attribute types to include in the results", schema = @Schema(allowableValues = "all,object,data", defaultValue = "all"))
@RequestParam(name = "attributeType", defaultValue = "all")
final String attributeType,

@Parameter(name = "selfIds", description = "Set of concept ids that might form the domain of the rule", required = false)
@RequestParam(name = "selfIds", required = false)
final Set<String> selfIds,

@Parameter(name = "parentIds", description = "Set of parent/ancestor ids that might form the domain of the rule", required = false)
@RequestParam(name = "parentIds", required = false)
final Set<String> parentIds,

@Parameter(name = "refsetIds", description = "Set of reference set ids that might form the domain of the rule", required = false)
@RequestParam(name = "refsetIds", required = false)
final Set<String> refsetIds,

@Parameter(name = "moduleIds", description = "List of applicable modules refining the scope of returned rules", required = false)
@RequestParam(name = "moduleIds", required = false)
final List<String> moduleIds,

@RequestParam(name = "searchAfter", required = false)
@Parameter(name = "searchAfter", description = "The search key to use for retrieving the next page of results")
final String searchAfter,

@RequestParam(name = "limit", required = false, defaultValue = "50")
@Parameter(name = "limit",description = "The maximum number of items to return")
int limit) {

return SnomedRequests.prepareGetMrcmRangeRules()
.setAttributeType(MrcmAttributeType.getByNameIgnoreCase(attributeType))
.setModuleIds(moduleIds)
.setParentIds(parentIds)
.setRefSetIds(refsetIds)
.setSelfIds(selfIds)
.setLimit(limit)
.setSearchAfter(searchAfter)
.build(path)
.execute(getBus());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2022 B2i Healthcare Pte Ltd, http://b2i.sg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.b2international.snowowl.snomed.core;

import static com.google.common.base.Strings.nullToEmpty;

import com.b2international.commons.exceptions.BadRequestException;

/**
* @since 8.8.0
*/
public enum MrcmAttributeType {

DATA,
OBJECT,
ALL;

public static MrcmAttributeType getByNameIgnoreCase(String name) {
for (final MrcmAttributeType type : values()) {
if (nullToEmpty(name).equalsIgnoreCase(type.toString())) {
return type;
}
}
throw new BadRequestException("Unknown attribute type: '%s'", name);
}

}
Loading

0 comments on commit fea71e2

Please sign in to comment.