@Override
  public PaginationInfo<IRelation> paginate(
      int page, int entriesPerPage, Map<String, Object> filters) {
    // avoid NPEs
    if (filters == null) filters = new HashMap<>();

    // aggregate filters
    List<String> constraints = new LinkedList<>();
    // search term
    if (filters.containsKey("search")) {
      // constraints.add(createSearchTermFullText((String) filters.get("search")));
      // TODO: implement this one day
    }

    // location
    // TODO search locations and contain

    // period
    // Long minJD = null, maxJD = null;
    // get periods from session - not needed, since we always calculate from min/maxEntries
    // if (filters.containsKey("minJD")) minJD = (Long)filters.get("minJD");
    // if (filters.containsKey("maxJD")) maxJD = (Long)filters.get("maxJD");
    // parse periods from input
    if (filters.containsKey("minEntry")) { // parse from input
      FlexibleDateParser parser = new FlexibleDateParser();
      Long minJD = parser.inputToJd((String) filters.get("minEntry"), "G", false);
      if (minJD > Long.MIN_VALUE) constraints.add("minJD >= " + minJD);
    }
    if (filters.containsKey("maxEntry")) { // parse from input
      FlexibleDateParser parser = new FlexibleDateParser();
      Long maxJD = parser.inputToJd((String) filters.get("maxEntry"), "G", true);
      if (maxJD < Long.MAX_VALUE) constraints.add("maxJD <= " + maxJD);
    }

    // tags
    String tagSQL =
        buildTagFilterSQL(
            (String[]) filters.get("tags"),
            filters.containsKey("withSubTags") && (boolean) filters.get("withSubTags"),
            false);
    if (!tagSQL.isEmpty()) constraints.add(tagSQL);

    // location type uid
    if (filters.containsKey("relationTypeUid")) {
      // convert to id
      String id =
          AbstractSegradaEntity.convertUidToOrientId((String) filters.get("relationTypeUid"));
      if (id != null) {
        constraints.add("relationType = " + id);
      }
      // TODO: test
    }
    // node uid
    if (filters.containsKey("nodeUid")) {
      // convert to id
      String id = AbstractSegradaEntity.convertUidToOrientId((String) filters.get("nodeUid"));
      if (id != null) {
        constraints.add("(relationLink.in = " + id + " OR relationLink.out = " + id + ")");
      }
      // TODO: test
    }

    // sorting
    String customOrder = null;
    if (filters.get("sort") != null) {
      String field = (String) filters.get("sort");
      if (allowedSorts.contains(field)) { // sanity check
        String dir = getDirectionFromString(filters.get("dir"));
        if (dir != null) customOrder = field.concat(dir);
      }
    }

    // let helper do most of the work
    return super.paginate(page, entriesPerPage, constraints, customOrder);
  }