private void addOrdering(InterpretationContext context, ObjectOrdering ordering)
      throws QueryException {

    ItemPath orderByPath = ordering.getOrderBy();

    // TODO if we'd like to have order-by extension properties, we'd need to provide itemDefinition
    // for them
    ProperDataSearchResult<JpaDataNodeDefinition> result =
        context
            .getItemPathResolver()
            .findProperDataDefinition(
                context.getRootEntityDefinition(), orderByPath, null, JpaDataNodeDefinition.class);
    if (result == null) {
      LOGGER.error(
          "Unknown path '"
              + orderByPath
              + "', couldn't find definition for it, "
              + "list will not be ordered by it.");
      return;
    }
    JpaDataNodeDefinition targetDefinition = result.getLinkDefinition().getTargetDefinition();
    if (targetDefinition instanceof JpaAnyContainerDefinition) {
      throw new QueryException(
          "Sorting based on extension item or attribute is not supported yet: " + orderByPath);
    } else if (targetDefinition instanceof JpaReferenceDefinition) {
      throw new QueryException("Sorting based on reference is not supported: " + orderByPath);
    } else if (result.getLinkDefinition().isMultivalued()) {
      throw new QueryException(
          "Sorting based on multi-valued item is not supported: " + orderByPath);
    } else if (targetDefinition instanceof JpaEntityDefinition) {
      throw new QueryException("Sorting based on entity is not supported: " + orderByPath);
    } else if (!(targetDefinition instanceof JpaPropertyDefinition)) {
      throw new IllegalStateException("Unknown item definition type: " + result.getClass());
    }

    JpaEntityDefinition baseEntityDefinition = result.getEntityDefinition();
    JpaPropertyDefinition orderByDefinition = (JpaPropertyDefinition) targetDefinition;
    String hqlPropertyPath =
        context
            .getItemPathResolver()
            .resolveItemPath(
                orderByPath, null, context.getPrimaryEntityAlias(), baseEntityDefinition, true)
            .getHqlPath();
    if (RPolyString.class.equals(orderByDefinition.getJpaClass())) {
      hqlPropertyPath += ".orig";
    }

    RootHibernateQuery hibernateQuery = context.getHibernateQuery();
    if (ordering.getDirection() != null) {
      switch (ordering.getDirection()) {
        case ASCENDING:
          hibernateQuery.addOrdering(hqlPropertyPath, OrderDirection.ASCENDING);
          break;
        case DESCENDING:
          hibernateQuery.addOrdering(hqlPropertyPath, OrderDirection.DESCENDING);
          break;
      }
    } else {
      hibernateQuery.addOrdering(hqlPropertyPath, OrderDirection.ASCENDING);
    }
  }
  private <T extends ObjectFilter> Restriction findAndCreateRestrictionInternal(
      T filter,
      InterpretationContext context,
      Restriction parent,
      ItemPathResolver resolver,
      JpaEntityDefinition baseEntityDefinition)
      throws QueryException {

    // the order of processing restrictions can be important, so we do the selection via handwritten
    // code

    if (filter instanceof AndFilter) {
      return new AndRestriction(context, (AndFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof OrFilter) {
      return new OrRestriction(context, (OrFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof NotFilter) {
      return new NotRestriction(context, (NotFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof InOidFilter) {
      return new InOidRestriction(context, (InOidFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof OrgFilter) {
      return new OrgRestriction(context, (OrgFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof TypeFilter) {
      TypeFilter typeFilter = (TypeFilter) filter;
      JpaEntityDefinition refinedEntityDefinition =
          resolver.findRestrictedEntityDefinition(baseEntityDefinition, typeFilter.getType());
      return new TypeRestriction(context, typeFilter, refinedEntityDefinition, parent);
    } else if (filter instanceof ExistsFilter) {
      ExistsFilter existsFilter = (ExistsFilter) filter;
      ItemPath path = existsFilter.getFullPath();
      ItemDefinition definition = existsFilter.getDefinition();
      ProperDataSearchResult<JpaEntityDefinition> searchResult =
          resolver.findProperDataDefinition(
              baseEntityDefinition, path, definition, JpaEntityDefinition.class);
      if (searchResult == null) {
        throw new QueryException(
            "Path for ExistsFilter ("
                + path
                + ") doesn't point to a hibernate entity within "
                + baseEntityDefinition);
      }
      return new ExistsRestriction(
          context, existsFilter, searchResult.getEntityDefinition(), parent);
    } else if (filter instanceof RefFilter) {
      RefFilter refFilter = (RefFilter) filter;
      ItemPath path = refFilter.getFullPath();
      ItemDefinition definition = refFilter.getDefinition();
      ProperDataSearchResult<JpaReferenceDefinition> searchResult =
          resolver.findProperDataDefinition(
              baseEntityDefinition, path, definition, JpaReferenceDefinition.class);
      if (searchResult == null) {
        throw new QueryException(
            "Path for RefFilter ("
                + path
                + ") doesn't point to a reference item within "
                + baseEntityDefinition);
      }
      return new ReferenceRestriction(
          context,
          refFilter,
          searchResult.getEntityDefinition(),
          parent,
          searchResult.getLinkDefinition());
    } else if (filter instanceof PropertyValueFilter) {
      PropertyValueFilter valFilter = (PropertyValueFilter) filter;
      ItemPath path = valFilter.getFullPath();
      ItemDefinition definition = valFilter.getDefinition();

      ProperDataSearchResult<JpaPropertyDefinition> propDefRes =
          resolver.findProperDataDefinition(
              baseEntityDefinition, path, definition, JpaPropertyDefinition.class);
      if (propDefRes == null) {
        throw new QueryException(
            "Couldn't find a proper restriction for a ValueFilter: " + valFilter.debugDump());
      }
      // TODO can't be unified?
      if (propDefRes.getTargetDefinition() instanceof JpaAnyPropertyDefinition) {
        return new AnyPropertyRestriction(
            context,
            valFilter,
            propDefRes.getEntityDefinition(),
            parent,
            propDefRes.getLinkDefinition());
      } else {
        return new PropertyRestriction(
            context,
            valFilter,
            propDefRes.getEntityDefinition(),
            parent,
            propDefRes.getLinkDefinition());
      }
    } else if (filter instanceof NoneFilter
        || filter instanceof AllFilter
        || filter instanceof UndefinedFilter) {
      // these should be filtered out by the client
      throw new IllegalStateException(
          "Trivial filters are not supported by QueryInterpreter: " + filter.debugDump());
    } else {
      throw new IllegalStateException("Unknown filter: " + filter.debugDump());
    }
  }