@Override
  public Object executeIndexQuery(
      OCommandContext iContext,
      OIndex<?> index,
      final INDEX_OPERATION_TYPE iOperationType,
      List<Object> keyParams,
      int fetchLimit) {
    final OIndexDefinition indexDefinition = index.getDefinition();

    final OIndexInternal<?> internalIndex = index.getInternal();
    if (!internalIndex.canBeUsedInEqualityOperators()) return null;

    final Object result;

    if (indexDefinition.getParamCount() == 1) {
      final Object key;
      if (indexDefinition instanceof OIndexDefinitionMultiValue)
        key = ((OIndexDefinitionMultiValue) indexDefinition).createSingleValue(keyParams.get(0));
      else key = indexDefinition.createValue(keyParams);

      if (key == null) return null;

      final Object indexResult;
      if (iOperationType == INDEX_OPERATION_TYPE.GET) indexResult = index.get(key);
      else indexResult = index.count(key);

      result = convertIndexResult(indexResult);
    } else {
      // in case of composite keys several items can be returned in case of we perform search
      // using part of composite key stored in index.

      final OCompositeIndexDefinition compositeIndexDefinition =
          (OCompositeIndexDefinition) indexDefinition;

      final Object keyOne = compositeIndexDefinition.createSingleValue(keyParams);

      if (keyOne == null) return null;

      final Object keyTwo = compositeIndexDefinition.createSingleValue(keyParams);

      if (internalIndex.hasRangeQuerySupport()) {
        if (INDEX_OPERATION_TYPE.COUNT.equals(iOperationType)) {
          result = index.count(keyOne, true, keyTwo, true, fetchLimit);
        } else if (fetchLimit > -1)
          result = index.getValuesBetween(keyOne, true, keyTwo, true, fetchLimit);
        else result = index.getValuesBetween(keyOne, true, keyTwo, true);
      } else {
        if (indexDefinition.getParamCount() == keyParams.size()) {
          final Object indexResult;
          if (iOperationType == INDEX_OPERATION_TYPE.GET) indexResult = index.get(keyOne);
          else indexResult = index.count(keyOne);

          result = convertIndexResult(indexResult);
        } else return null;
      }
    }

    updateProfiler(iContext, index, keyParams, indexDefinition);
    return result;
  }
 @Override
 protected void handleObject(OIndex<?> object) {
   indexName = object.getName();
   OIndexDefinition indexDefinition = object.getDefinition();
   if (indexDefinition != null) {
     String className = indexDefinition.getClassName();
     if (className != null) classModel = new OClassModel(className);
   }
 }
 /**
  * Make type conversion of keys for specific index.
  *
  * @param index - index for which keys prepared for.
  * @param keys - which should be prepared.
  * @return keys converted to necessary type.
  */
 private Set<Comparable> prepareKeys(OIndex<?> index, Object keys) {
   final OIndexDefinition indexDefinition = index.getDefinition();
   if (keys instanceof Collection) {
     final Set<Comparable> newKeys = new TreeSet<Comparable>();
     for (Object o : ((Collection) keys)) {
       newKeys.add((Comparable) indexDefinition.createValue(o));
     }
     return newKeys;
   } else {
     return Collections.singleton((Comparable) indexDefinition.createValue(keys));
   }
 }