private QueryCriteria queryCriteriaCase(
        AttributeQueryCriteria criteria, List<AttributeReference.Key> arg) {
      final AttributeReference basicAttRef;
      if (arg.isEmpty()) {
        basicAttRef = criteria.getAttributeReference();
      } else {
        basicAttRef = criteria.getAttributeReference().prepend(arg);
      }

      DisjunctionBuilder disjunctionBuilder = new DisjunctionBuilder();

      disjunctionBuilder.add(criteria);

      for (int i = 0; i < basicAttRef.getKeys().size(); i++) {
        AttributeReference existsAttRef = basicAttRef.subReference(0, i + 1);

        List<AttributeReference.Key> newArg =
            basicAttRef.getKeys().subList(i + 1, basicAttRef.getKeys().size());

        QueryCriteria plainNewBody = criteria.accept(QUERY_CRITERIA_FACTORY, newArg);

        QueryCriteria newBody =
            plainNewBody.accept(this, Collections.<AttributeReference.Key>emptyList());

        disjunctionBuilder.add(new ExistsQueryCriteria(existsAttRef, newBody));
      }

      return disjunctionBuilder.build();
    }
    @Override
    public QueryCriteria visit(NotQueryCriteria criteria, List<AttributeReference.Key> arg) {
      QueryCriteria subQuery = criteria.getSubQueryCriteria().accept(this, arg);

      if (subQuery.equals(criteria.getSubQueryCriteria())) {
        return criteria;
      }
      return new NotQueryCriteria(subQuery);
    }
    @Override
    public QueryCriteria visit(NotQueryCriteria criteria, Void arg) {
      QueryCriteria subQuery = criteria.getSubQueryCriteria().accept(this, null);

      if (subQuery.equals(criteria.getSubQueryCriteria())) {
        return criteria;
      }

      return new NotQueryCriteria(subQuery);
    }
    @Override
    public QueryCriteria visit(OrQueryCriteria criteria, List<AttributeReference.Key> arg) {
      QueryCriteria subQuery1 = criteria.getSubQueryCriteria1().accept(this, arg);
      QueryCriteria subQuery2 = criteria.getSubQueryCriteria2().accept(this, arg);

      if (subQuery1.equals(criteria.getSubQueryCriteria1())
          && subQuery2.equals(criteria.getSubQueryCriteria2())) {
        return criteria;
      }

      return new OrQueryCriteria(subQuery1, subQuery2);
    }
    @Override
    public QueryCriteria visit(OrQueryCriteria criteria, Void arg) {
      QueryCriteria subQuery1 = criteria.getSubQueryCriteria1().accept(this, null);
      QueryCriteria subQuery2 = criteria.getSubQueryCriteria2().accept(this, null);

      if (subQuery1.equals(criteria.getSubQueryCriteria1())
          && subQuery2.equals(criteria.getSubQueryCriteria2())) {
        return criteria;
      }

      return new OrQueryCriteria(subQuery1, subQuery2);
    }
  public static QueryCriteria translate(QueryCriteria queryCriteria) {
    QueryCriteria withArrayAlternative = queryCriteria.accept(ARRAY_REFERENCE_CREATOR, null);

    return withArrayAlternative.accept(
        OR_EXISTS_CREATOR, Collections.<AttributeReference.Key>emptyList());
  }