@Override
  public Iterable<Object> call() throws Exception {

    Query query = operation.query();
    Oql oql = session.oqlGenerator().generate(query);

    if (GeodeBackend.logger.isLoggable(Level.FINE)) {
      GeodeBackend.logger.log(Level.FINE, "Querying Geode with {0}", oql);
    }

    // fast-path for "region.getAll" use-case. ie get values for list of keys
    // assumes no projections / aggregations / sort / count etc.
    // plain get by key lookup
    // also assumes idProperty is resolved (see IdResolver)
    boolean maybeGetById = query.filter().isPresent()
            && !query.hasAggregations()
            && !query.hasProjections()
            && !query.count()
            && query.collations().isEmpty();

    if (maybeGetById) {
      KeyLookupAnalyzer.Result result = session.keyLookupAnalyzer.analyze(query.filter().get());
      if (result.isOptimizable()) {
        return new SyncGetByKey(session, result.values()).call();
      }
    }

    // for projections use tuple function
    Function<Object, Object> tupleFn;
    if (query.count()) {
      // geode will return integer for count(*)
      tupleFn = x -> Geodes.convert(x, Long.class);
    } else if (query.hasProjections()) {
      tupleFn =  x -> Geodes.castNumbers(toTuple(query, x));
    } else {
      tupleFn = Function.identity();
    }

    // convert existing collections to JDK-only implementations (eg. ImmutableList -> ArrayList)
    Object[] variables = oql.variables().stream().map(BIND_VARIABLE_CONVERTER).toArray(Object[]::new);
    Iterable<Object> result = (Iterable<Object>) session.queryService.newQuery(oql.oql()).execute(variables);
    // lazy transform
    return Iterables.transform(result, tupleFn::apply);
  }
Convert Geode specific {@link QueryService#UNDEFINED} value to null
criteria/geode/src/org/immutables/criteria/geode/SyncSelect.java