All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.csiro.pathling.terminology.TerminologyService Maven / Gradle / Ivy

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2023 Commonwealth Scientific and Industrial Research
 * Organisation (CSIRO) ABN 41 687 119 230.
 *
 * 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 au.csiro.pathling.terminology;

import au.csiro.pathling.fhir.ParametersUtils.DesignationPart;
import au.csiro.pathling.fhirpath.encoding.ImmutableCoding;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Value;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.Type;
import org.hl7.fhir.r4.model.codesystems.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome;

/**
 * Abstraction layer for the terminology related operations.
 *
 * @author Piotr Szul
 */
public interface TerminologyService {

  /**
   * Represent a single translation of a code.
   */
  @Value(staticConstructor = "of")
  class Translation implements Serializable {

    private static final long serialVersionUID = -7551505530196865478L;

    @Nonnull
    ConceptMapEquivalence equivalence;

    @Nonnull
    Coding concept;

    @Override
    public boolean equals(final Object o) {
      // We override this method because Coding does not have a sane equals method.
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }
      final Translation that = (Translation) o;
      return equivalence == that.equivalence && ImmutableCoding.of(concept)
          .equals(ImmutableCoding.of(that.concept));
    }

    @Override
    public int hashCode() {
      // We override this method because Coding does not have a sane hashCode method.
      return Objects.hash(equivalence, ImmutableCoding.of(concept));
    }

  }

  /**
   * Validates that a coded value is in a value set. Abstracts the FHIR ValueSet/$validate-code
   * operation.
   *
   * @param valueSetUrl the URL of the value set to validate against
   * @param coding the coding to test
   * @return true if the coding is a valid member of the value set
   */
  boolean validateCode(@Nonnull String valueSetUrl, @Nonnull Coding coding);

  /**
   * Translates a code from one value set to another, based on the existing concept map. Abstracts
   * the FHIR ConceptMap/$translate
   * operation.
   *
   * @param coding the code to translate.
   * @param conceptMapUrl the url of the concept map to use for translation.
   * @param reverse if this is true, then the operation should return all the codes that might be
   * mapped to this code.
   * @param target identifies the value set in which a translation is sought. If null all known
   * translations are returned.
   * @return the list of translations.
   */
  @Nonnull
  List translate(@Nonnull Coding coding,
      @Nonnull String conceptMapUrl,
      boolean reverse,
      @Nullable String target);

  /**
   * Tests the subsumption relationship between two codings given the semantics of subsumption in
   * the underlying code system. Abstracts the CodeSystem/$subsumes
   * operation.
   *
   * @param codingA the left code to be tested.
   * @param codingB the right code to be tested.
   * @return {@link ConceptSubsumptionOutcome} representing the relation between codingA (left code)
   * and codingB (right code).
   */
  @Nonnull
  ConceptSubsumptionOutcome subsumes(@Nonnull Coding codingA, @Nonnull Coding codingB);

  /**
   * Gets additional details about the concept, including designations and properties. Abstracts
   * the
   * CodeSystem/$lookup
   * operation.
   *
   * @param coding the coding to lookup.
   * @param propertyCode the code of the propertyCode to lookup. If not null only the properties
   * with matching codes are returned.
   * @return the list of properties and/or designations.
   */
  @Nonnull
  List lookup(@Nonnull Coding coding, @Nullable String propertyCode);

  /**
   * Common interface for properties and designations
   */
  interface PropertyOrDesignation extends Serializable {
    // marker interface
  }

  /**
   * The representation of the property of a concept.
   */
  @Value(staticConstructor = "of")
  class Property implements PropertyOrDesignation {

    private static final long serialVersionUID = 8827691056493768863L;

    @Nonnull
    String code;
    @Nonnull
    Type value;

    /**
     * Gets the string representation of the property value.
     *
     * @return the string representation of the property value
     */
    @Nonnull
    public String getValueAsString() {
      return value.primitiveValue();
    }

    @Override
    public int hashCode() {
      // not supported for now because it's not possible to satisfy the hashCode/equals contract
      // without some form of deepHash corresponding to equalsDeep()
      throw new UnsupportedOperationException("hashCode not implemented.");
    }

    @Override
    public boolean equals(final Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      final Property property = (Property) o;

      if (!code.equals(property.code)) {
        return false;
      }
      return value.equalsDeep(property.value);
    }

  }

  /**
   * The representation of a designation of a concept.
   */
  @Value(staticConstructor = "of")
  class Designation implements PropertyOrDesignation {

    private static final long serialVersionUID = -809107979219801186L;

    /**
     * The code of the designation properties
     */
    public static final String PROPERTY_CODE = "designation";

    @Nullable
    Coding use;

    @Nullable
    String language;

    @Nonnull
    String value;

    @Override
    public int hashCode() {
      // not supported for now because it's not possible to satisfy the hashCode/equals contract
      // without some form of deepHash corresponding to equalsDeep()
      throw new UnsupportedOperationException("hashCode not implemented.");
    }

    @Override
    public boolean equals(final Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      final Designation that = (Designation) o;

      if (use != null
          ? !use.equalsDeep(that.use)
          : that.use != null) {
        return false;
      }
      if (!Objects.equals(language, that.language)) {
        return false;
      }
      return value.equals(that.value);
    }

    @Nonnull
    public static Designation ofPart(@Nonnull final DesignationPart part) {
      return of(part.getUse(),
          Optional.ofNullable(part.getLanguage()).map(StringType::getValue).orElse(null),
          part.getValue().getValue());
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy