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

org.molgenis.data.index.IndexDependencyModel Maven / Gradle / Ivy

There is a newer version: 8.4.5
Show newest version
package org.molgenis.data.index;

import static com.google.common.collect.Maps.uniqueIndex;
import static com.google.common.collect.Streams.stream;
import static java.util.Collections.emptySet;
import static org.molgenis.data.meta.model.EntityTypeMetadata.ATTRIBUTES;
import static org.molgenis.data.meta.model.EntityTypeMetadata.EXTENDS;
import static org.molgenis.data.meta.model.EntityTypeMetadata.ID;
import static org.molgenis.data.meta.model.EntityTypeMetadata.INDEXING_DEPTH;
import static org.molgenis.data.meta.model.EntityTypeMetadata.IS_ABSTRACT;

import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import org.molgenis.data.Fetch;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.AttributeMetadata;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.util.GenericDependencyResolver;

/**
 * Models the dependencies between {@link EntityType}s for the purpose of indexing. These
 * dependencies depend on the indexing depth of the entity types.
 */
class IndexDependencyModel {
  private final Map entityTypes;
  private final GenericDependencyResolver genericDependencyResolver =
      new GenericDependencyResolver();

  /** The fetch to use when retrieving the {@link EntityType}s fed to this DependencyModel. */
  static final Fetch ENTITY_TYPE_FETCH =
      new Fetch()
          .field(ID)
          .field(IS_ABSTRACT)
          .field(INDEXING_DEPTH)
          .field(EXTENDS, new Fetch().field(ID))
          .field(
              ATTRIBUTES,
              new Fetch()
                  .field(AttributeMetadata.ID)
                  .field(AttributeMetadata.NAME)
                  .field(AttributeMetadata.TYPE)
                  .field(AttributeMetadata.REF_ENTITY_TYPE, new Fetch().field(ID)));

  /**
   * Creates an IndexDependencyModel for a list of EntityTypes.
   *
   * @param entityTypes the EntityTypes for which the DependencyModel is created
   */
  IndexDependencyModel(List entityTypes) {
    this.entityTypes = uniqueIndex(entityTypes, EntityType::getId);
  }

  private Set getReferencingEntities(String entityTypeId) {
    ImmutableSet.Builder result = ImmutableSet.builder();
    EntityType entityType = entityTypes.get(entityTypeId);
    if (entityType == null) {
      return emptySet();
    }
    for (Map.Entry candidate : entityTypes.entrySet()) {
      EntityType candidateEntityType = candidate.getValue();
      if (hasAttributeThatReferences(candidateEntityType, entityTypeId)) {
        if (candidateEntityType.isAbstract()) {
          result.addAll(getDescendants(candidate.getKey()));
        } else {
          result.add(candidate.getKey());
        }
      }
    }
    return result.build();
  }

  private Set getDescendants(String entityTypeId) {
    ImmutableSet.Builder result = ImmutableSet.builder();
    for (Map.Entry candidate : entityTypes.entrySet()) {
      EntityType candidateEntityType = candidate.getValue();
      if (extendsFrom(candidateEntityType, entityTypeId)) {
        if (candidateEntityType.isAbstract()) {
          result.addAll(getDescendants(candidate.getKey()));
        } else {
          result.add(candidate.getKey());
        }
      }
    }
    return result.build();
  }

  @SuppressWarnings("squid:S2259") // getExtends() doesn't return null here
  private boolean extendsFrom(EntityType candidateEntityType, String entityTypeId) {
    return candidateEntityType.getExtends() != null
        && entityTypeId.equals(candidateEntityType.getExtends().getId());
  }

  /**
   * Determines if an entityType has an attribute that references another entity
   *
   * @param candidate the EntityType that is examined
   * @param entityTypeId the ID of the entity that may be referenced
   * @return indication if candidate references entityTypeID
   */
  private boolean hasAttributeThatReferences(EntityType candidate, String entityTypeId) {
    Iterable attributes = candidate.getOwnAtomicAttributes();
    return stream(attributes)
        .filter(Attribute::hasRefEntity)
        .map(attribute -> attribute.getRefEntity().getId())
        .anyMatch(entityTypeId::equals);
  }

  Stream getEntityTypesDependentOn(String entityTypeId) {
    return genericDependencyResolver
        .getAllDependants(
            entityTypeId,
            id -> entityTypes.get(id).getIndexingDepth(),
            this::getReferencingEntities)
        .stream();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy