62 lines
2.5 KiB
Java
62 lines
2.5 KiB
Java
package tc.oc.pgm.filters;
|
|
|
|
import java.util.Optional;
|
|
import java.util.stream.Stream;
|
|
|
|
import tc.oc.pgm.filters.query.IMatchQuery;
|
|
import tc.oc.pgm.filters.query.IQuery;
|
|
|
|
/**
|
|
* An object that {@link Filter}s can be applied to.
|
|
*
|
|
* Filterables serve as {@link IQuery}s about themselves in their current state,
|
|
* and each Filterable subtype should also extend the query type given for its
|
|
* {@link Q} parameter. Unlike {@link IQuery}s in general, which may be ephemeral
|
|
* value types, Filterables have a persistent identity.
|
|
*
|
|
* Filterables are composed in a hiearchy that mirrors the type relationships
|
|
* of their {@link Q} parameters. If query type B extends query type A then
|
|
* every Filterable<B> is contained in some Filterable<A>. Aside from this,
|
|
* the types of the Filterables may not have any particular relationship.
|
|
*/
|
|
public interface Filterable<Q extends IMatchQuery> extends IMatchQuery {
|
|
|
|
/**
|
|
* The (single) Filterable that contains this one, or empty if this
|
|
* is a top-level object.
|
|
*/
|
|
Optional<? extends Filterable<? super Q>> filterableParent();
|
|
|
|
/**
|
|
* Return the enclosing Filterable of the given subtype, if any.
|
|
*
|
|
* This object is returned if it extends the given type.
|
|
*/
|
|
default <R extends Filterable<?>> Optional<R> filterableAncestor(Class<R> type) {
|
|
return type.isInstance(this) ? Optional.of((R) this)
|
|
: filterableParent().flatMap(parent -> parent.filterableAncestor(type));
|
|
}
|
|
|
|
/**
|
|
* Return all {@link Filterable} objects that this object is directly composed of.
|
|
*
|
|
* This object is NOT included in the result, nor are indirect components i.e. grandchildren, etc.
|
|
*/
|
|
Stream<? extends Filterable<? extends Q>> filterableChildren();
|
|
|
|
/**
|
|
* Return all individual objects of the given Filterable subtype that this object is composed of,
|
|
* directly or indirectly, possibly including this object itself.
|
|
*
|
|
* This method simply tests this object's type, and recurses on all {@link #filterableChildren()}.
|
|
* Subclasses should provide a more efficient implementation, if possible.
|
|
*/
|
|
default <R extends Filterable<?>> Stream<? extends R> filterableDescendants(Class<R> type) {
|
|
Stream<? extends R> result = filterableChildren().flatMap(child -> child.filterableDescendants(type));
|
|
if(type.isInstance(this)) {
|
|
result = Stream.concat(Stream.of((R) this), result);
|
|
}
|
|
return result;
|
|
}
|
|
}
|