public static <T> BatchingVisitableView<T> singleton(final T t) { return BatchingVisitableView.of(new BatchingVisitable<T>() { @Override public <K extends Exception> boolean batchAccept(int batchSize, AbortingVisitor<? super List<T>, K> v) throws K { return v.visit(ImmutableList.of(t)); } }); }
public static <T> BatchingVisitableView<T> emptyBatchingVisitable() { return BatchingVisitableView.of(new BatchingVisitable<T>() { @Override public <K extends Exception> boolean batchAccept(int batchSize, AbortingVisitor<? super List<T>, K> v) throws K { return true; } }); }
public static <F, T> BatchingVisitableView<T> transformBatch(final BatchingVisitable<F> visitable, final Function<? super List<F>, ? extends List<T>> f) { Preconditions.checkNotNull(visitable); Preconditions.checkNotNull(f); return BatchingVisitableView.of(new AbstractBatchingVisitable<T>() { @Override protected <K extends Exception> void batchAcceptSizeHint(int batchSizeHint, final ConsistentVisitor<T, K> v) throws K { visitable.batchAccept(batchSizeHint, batch -> v.visit(f.apply(batch))); } }); }
public static <T> BatchingVisitableView<T> concat(final Iterable<? extends BatchingVisitable<? extends T>> inputs) { Preconditions.checkNotNull(inputs); return BatchingVisitableView.of(new AbstractBatchingVisitable<T>() { @Override protected <K extends Exception> void batchAcceptSizeHint(int batchSizeHint, ConsistentVisitor<T, K> v) throws K { for (BatchingVisitable<? extends T> bv : inputs) { // This is safe because cast is never passed to anything and it's function // batchAccept is covariant @SuppressWarnings("unchecked") BatchingVisitable<T> cast = (BatchingVisitable<T>) bv; if (!cast.batchAccept(batchSizeHint, v)) { return; } } } }); }
/** * This method will wrap the passed visitable so it is called with the passed pageSize when it is called. * <p> * This can be used to make the performance of batching visitables better. One example of where this is useful * is if I just visit the results one at a time, but I know that I will visit 100 results, then I can save * a lot of potential round trips by hinting a page size of 100. */ public static <T> BatchingVisitableView<T> hintPageSize(final BatchingVisitable<T> bv, final int pageSize) { Preconditions.checkArgument(pageSize > 0); return BatchingVisitableView.of(new AbstractBatchingVisitable<T>() { @Override protected <K extends Exception> void batchAcceptSizeHint(int batchSizeHint, ConsistentVisitor<T, K> v) throws K { bv.batchAccept(pageSize, v); } }); }
public static <T> List<T> copyToList(BatchingVisitable<T> v) { return BatchingVisitableView.of(v).immutableCopy(); }
public static <T, TOKEN> TokenBackedBasicResultsPage<T, TOKEN> getFirstPage(BatchingVisitable<T> v, int numToVisitArg, Function<T, TOKEN> tokenExtractor) { Preconditions.checkArgument(numToVisitArg >= 0, "numToVisit cannot be negative. Value was: %d", numToVisitArg); if (numToVisitArg == Integer.MAX_VALUE) { // prevent issue with overflow numToVisitArg--; } final int numToVisit = numToVisitArg + 1; ImmutableList<T> list = BatchingVisitableView.of(v).limit(numToVisit).immutableCopy(); Preconditions.checkState(list.size() <= numToVisit); if (list.size() >= numToVisit) { TOKEN token = tokenExtractor.apply(list.get(list.size() - 1)); list = list.subList(0, numToVisit-1); return new SimpleTokenBackedResultsPage<T, TOKEN>(token, list, true); } return new SimpleTokenBackedResultsPage<T, TOKEN>(null, list, false); }
public static <T> List<T> take(BatchingVisitable<T> v, final int howMany, final boolean includeFirst) { BatchingVisitableView<T> visitable = BatchingVisitableView.of(v); if (!includeFirst) { visitable = visitable.skip(1); } return visitable.limit(howMany).immutableCopy(); }
@Test public void testImmutableCopyWithDefaultBatchSize() throws Exception { AbstractBatchingVisitable bv = mock(AbstractBatchingVisitable.class); BatchingVisitableView bvv = BatchingVisitableView.of(bv); bvv.immutableCopy(); verify(bv).batchAcceptSizeHint(eq(BatchingVisitables.DEFAULT_BATCH_SIZE), any()); }
@Test public void testImmutableCopyRespectsCustomBatchSize() throws Exception { AbstractBatchingVisitable bv = mock(AbstractBatchingVisitable.class); BatchingVisitableView bvv = BatchingVisitableView.of(bv); bvv.hintBatchSize(2).immutableCopy(); verify(bv).batchAcceptSizeHint(eq(2), any()); }
@Test public void testSkip() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L)); ImmutableList<Long> copy = BatchingVisitableView.of(visitor).skip(5).immutableCopy(); assertEquals("unexpected list remnants after skipping", ImmutableList.of(5L, 6L, 7L), copy); }
@Test public void testUnique() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList( 0L, 1L, 1L, 2L, 2L, 2L, 3L, 4L, 5L, 5L, 6L, 7L, 7L)); BatchingVisitableView<Long> bv = BatchingVisitableView.of(visitor); assertEquals("unexpected result for unique view", ImmutableList.of(0L, 1L, 2L, 3L), bv.unique().limit(4).immutableCopy()); }
@Test public void testBatchWrap2() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L)); final Mutable<Boolean> hasTripped = Mutables.newMutable(); AbortingVisitor<List<? extends Long>, RuntimeException> bv = item -> { hasTripped.set(true); assertEquals("batched item had wrong size", 8, item.size()); return false; }; AbortingVisitor<List<Long>, RuntimeException> wrap = AbortingVisitors.wrapBatching(bv); BatchingVisitableView.of(visitor).batchAccept(1000, wrap); assertTrue("should have been tripped!", hasTripped.get()); }
@Test public void testBatchWrap() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L)); final Mutable<Boolean> hasTripped = Mutables.newMutable(); AbortingVisitor<List<Object>, RuntimeException> bv = item -> { hasTripped.set(true); assertEquals("batched item had wrong size", 8, item.size()); return false; }; AbortingVisitor<List<Long>, RuntimeException> wrap = AbortingVisitors.wrapBatching(bv); BatchingVisitableView.of(visitor).batchAccept(1000, wrap); assertTrue("should have been tripped!", hasTripped.get()); }
@Test public void testVisitWhile() { List<Long> longList = Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L); BatchingVisitable<Long> visitable = ListVisitor.create(longList); BatchingVisitableView<Long> view = BatchingVisitables.visitWhile( BatchingVisitableView.of(visitable), (input) -> input.longValue() < 5L); assertEquals("visitWhile visited the wrong number of elements", 5L, view.size()); assertEquals("visitWhile visited the wrong element first", 0L, view.getFirst().longValue()); assertEquals("visitWhile visited the wrong element last", 4L, view.getLast().longValue()); assertTrue("visitWhile visited the wrong elements", view.immutableCopy().containsAll(ImmutableSet.of(0L, 1L, 2L, 3L, 4L))); visitable = ListVisitor.create(Lists.reverse(longList)); view = BatchingVisitables.visitWhile( BatchingVisitableView.of(visitable), (input) -> input.longValue() >= 5L); assertEquals("visitWhile visited the wrong number of elements", 5L, view.size()); assertEquals("visitWhile visited the wrong element first", 9L, view.getFirst().longValue()); assertEquals("visitWhile visited the wrong element last", 5L, view.getLast().longValue()); assertTrue("visitWhile visited the wrong elements", view.immutableCopy().containsAll(ImmutableSet.of(5L, 6L, 7L, 8L, 9L))); }
@Test public void testAnyAndAllForNonEmptyLists() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L)); BatchingVisitableView<Long> bv = BatchingVisitableView.of(visitor); assertTrue("any(true) should be true", bv.any(Predicates.alwaysTrue())); assertTrue("all(true) should be true", bv.all(Predicates.alwaysTrue())); assertFalse("any(false) should be false", bv.any(Predicates.alwaysFalse())); assertFalse("all(false) should be false", bv.all(Predicates.alwaysFalse())); }
@Test public void testBatchHints() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L)); Function<List<Long>, List<String>> trans = (input) -> { assertEquals("batched item had wrong size", 2, input.size()); return Lists.transform(input, Functions.toStringFunction()); }; BatchingVisitableView<String> visitable = BatchingVisitableView.of(visitor).transformBatch(trans) .hintBatchSize(2); final Mutable<Boolean> hasTripped = Mutables.newMutable(); visitable.batchAccept(10000, item -> { hasTripped.set(true); assertEquals("batched item had wrong size", 8, item.size()); return false; }); assertTrue("should have been tripped!", hasTripped.get()); }
@Test public void testConcat() { BatchingVisitable<Long> visitor = ListVisitor.create(Lists.newArrayList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L)); BatchingVisitableView<Long> limited = BatchingVisitableView.of(visitor).limit(3); BatchingVisitableView<Long> concat = BatchingVisitables.concat(limited, visitor); assertTrue("concatenated batchAccept should be true", concat.batchAccept(2, AbortingVisitors .batching(AbortingVisitors.alwaysTrue()))); }
@Test public void testAnyAndAllForEmptyLists() { BatchingVisitable<Long> visitor = BatchingVisitables.emptyBatchingVisitable(); BatchingVisitableView<Long> bv = BatchingVisitableView.of(visitor); assertFalse("any(empty-set-of-trues) should be false", bv.any(Predicates.alwaysTrue())); assertTrue("all(empty-set-of-trues) should be true", bv.all(Predicates.alwaysTrue())); assertFalse("any(empty-set-of-falses) should be false", bv.any(Predicates.alwaysFalse())); assertTrue("all(empty-set-of-falses) should be true", bv.all(Predicates.alwaysFalse())); }
@Test public void testHintPageSize() { InfiniteVisitable infinite = new InfiniteVisitable(); BatchingVisitableView<Long> bv = BatchingVisitableView.of(infinite); long first = bv.filter(new TakeEvery<>(100)).getFirst(); assertEquals("first element returned was wrong", 99L, first); assertEquals("count of InfiniteVisitable didn't match", 100L, infinite.count); first = bv.filter(new TakeEvery<>(100)).hintBatchSize(100).getFirst(); assertEquals("first element returned was wrong", 199L, first); assertEquals("count of InfiniteVisitable didn't match", 200L, infinite.count); }