On 30 April 2014 15:06, William Burns <mudokonman(a)gmail.com> wrote:
Was wondering if anyone had any opinions on the API for this.
These are a few options that Dan and I mulled over:
Note the CloseableIterable inteface mentioned is just an interface
that extends both Closeable and Iterable.
1. The API that is very similar to previously proposed in this list
but slightly changed:
Methods on AdvancedCache
CloseableIterable<CacheEntry<K, V>> entryIterable(KeyValueFilter<?
super K, ? super V> filter);
<C> CloseableIterable<CacheEntry<K, C>>
entryIterable(KeyValueFilter<?
super K, ? super V> filter, Converter<? super K, ? super V, C>
converter);
Note the difference here is that it would return an Iterable instead
of Iterator, which would allow for it being used in a for loop.
Example usage would be (types omitted)
for (CacheEntry entry : cache.entryIterable(someFilter, someConverter)) {
// Do something
}
If it's important to close the Iterable, this example highlights a
problem of the API.
Ideally I think you might want to drop the need for the #close()
method, but I'm guessing that's not an option so I'd avoid the
Iterable API in that case.
You could think of an intermediary place-holder to still allow for
natural iteration:
try ( CacheEntryIteratorContext ctx = cache.entryIterable(someFilter,
someConverter) ) {
for (CacheEntry entry : ctx.asIterable()) {
// Do something
}
}
But I'm not liking the names I used above, as I would expect to be
able to reuse the same iterator for multiple invocations of
iterable(), and have each to restart the iteration from the beginning.
Can this be solved with better name choices?
2. An API that returns a new type EntryIterable for example that can
chain methods to provide a filter and converter.
on AdvancedCache
EntryIterable<K, V> entryIterable();
where EntryIterable is defined as:
public interface EntryIterable<K, V> extends
CloseableIterable<CacheEntry<K, V>> {
public EntryIterable<K, V> filter(KeyValueFilter<? super K, ? super
V> filter);
public EntryIterable<K, V> converter(Converter<? super K, ? super
V, ? extends V> converter);
public <C> CloseableIterable<CacheEntry<K, C>>
projection(Converter<? super K, ? super V, C> converter);
}
Note that there are 2 methods that take a Converter, this is to
preserve the typing, since the method would return a different
EntryIterable instance. However I can also see removing one of the
converter method and just rename projection to converter instead.
This API would allow for providing optional fields more cleanly or not
if all if desired.
Example usage would be (types omitted)
for (CacheEntry entry :
cache.entryIterable().filter(someFilter).converter(someConverter)) {
// Do something
}
This looks very nice, assuming you fix the missing close(). Am I
missing a catch?
Also it's quite trivial for the user to do his own filtering and
conversion in the "do something block", so I'm wondering if there is a
reason beyond API shugar to expose this.
It would be lovely if for example certain filters could affect loading
from CacheStores - narrowing down a relational database select for
example - and I guess the same concept could apply to the converted if
you'd allow to select a subset of fields.
I don't think these optimisations need to be coded right now, but it
would be nice to keep the option open for future enhancement.
3. An API that requires the filter up front in the AdvancedCache
method. This also brings up the point should we require a filter to
always be provided? Unfortuantely this doesn't prevent a user from
querying every entry as they can just use a filter that accepts all
key/value pairs.
Why is that unfortunate?
on AdvancedCache
EntryIterable<K, V> entryIterable(Filter<? super K, ? super V> filter)
where EntryIterable is defined as:
public interface EntryIterable<K, V> extends
CloseableIterable<CacheEntry<K, V>> {
public <C> CloseableIterable<CacheEntry<K, C>>
converter(Converter<? super K, ? super V, C> converter);
}
The usage would be identical to #2 except the filter is always provided.
I wouldn't mandate it, but in case you overload the method it probably
is a good idea to internally apply an accept-all filter so you have a
single implementation. Could be a singleton, which also implies an
efficient Externalizer.
Let me know what you guys think or if you have any other suggestions.
Thanks,
- Will
_______________________________________________
infinispan-dev mailing list
infinispan-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/infinispan-dev