@Override
  public Bson visit(Call call) {
    final Operator op = call.operator();
    final List<Expression> args = call.arguments();


    if (op == OptionalOperators.IS_ABSENT || op == OptionalOperators.IS_PRESENT) {
      Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
      final String field = naming.name(Visitors.toPath(args.get(0)));
      Bson filter;
      if (op == OptionalOperators.IS_PRESENT) {
        filter = Filters.and(Filters.exists(field), Filters.ne(field, null));
      } else {
        // absent fields means null or missing
        filter = Filters.or(Filters.exists(field, false), Filters.eq(field, null));
      }
      return filter;
    }

    if (op == Operators.AND || op == Operators.OR) {
      final List<Bson> list = call.arguments().stream()
              .map(a -> a.accept(this))
              .collect(Collectors.toList());

      return op == Operators.AND ? Filters.and(list) : Filters.or(list);
    }

    if (op == Operators.NOT) {
      return negate(args.get(0));
    }

    if (op == IterableOperators.IS_EMPTY || op == IterableOperators.NOT_EMPTY) {
      Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
      final String field = naming.name(Visitors.toPath(args.get(0)));
      return op == IterableOperators.IS_EMPTY ? Filters.eq(field, Collections.emptyList())
              : Filters.and(Filters.exists(field), Filters.ne(field, null), Filters.ne(field, Collections.emptyList()));
    }
    
    if (op == IterableOperators.ANY) {
      Call rightCall = call;
      Path path = null;

      while (rightCall.operator() == IterableOperators.ANY) {
        Preconditions.checkArgument(rightCall.arguments().size() == 2, "Expected two arguments for %s got %s", rightCall, rightCall.arguments().size());
        Preconditions.checkArgument(rightCall.arguments().get(0) instanceof Path, "%s is not a path", rightCall.arguments().get(0));
        Preconditions.checkArgument(rightCall.arguments().get(1) instanceof Call, "%s is not a call", rightCall.arguments().get(1));

        path = Path.combine(path, (Path) rightCall.arguments().get(0));
        rightCall = (Call) rightCall.arguments().get(1);
      }

      Operator operator;
      if (rightCall.operator() == Operators.NOT) {
        Preconditions.checkArgument(rightCall.arguments().get(0) instanceof Call, "%s is not a call", rightCall.arguments().get(0));

        rightCall = (Call) rightCall.arguments().get(0);
        operator = negateOperator(rightCall.operator());
      } else {
        operator = rightCall.operator();
      }

      Preconditions.checkArgument(rightCall.arguments().get(0) instanceof Path,"%s is not a path", rightCall.arguments().get(0));

      Path currentPath = Visitors.toPath(rightCall.arguments().get(0));
      List<Path> paths = new ArrayList<>();
      while (currentPath.parent().isPresent()) {
        paths.add(currentPath);
        currentPath = currentPath.parent().get();
      }
      Collections.reverse(paths);
      for (Path tmpPath : paths) {
        path = Path.combine(path, tmpPath);
      }

      if (rightCall.operator().arity() == Operator.Arity.UNARY) {
        return visit(Expressions.unaryCall(rightCall.operator(), path));
      } else {
        return binaryCall(Expressions.binaryCall(operator, path, rightCall.arguments().get(1)));
      }
    }

    if (op.arity() == Operator.Arity.BINARY) {
      return binaryCall(call);
    }


    throw new UnsupportedOperationException(String.format("Not yet supported (%s): %s", call.operator(), call));
  }
Converts find expression to Mongo BSON format
@see <a href="https://docs.mongodb.com/manual/tutorial/query-documents/">Query Documents</a>
criteria/mongo/src/org/immutables/criteria/mongo/FindVisitor.java