com.eventsourcing.index.EntityQueryFactory Maven / Gradle / Ivy
Show all versions of eventsourcing-core Show documentation
/**
* Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.eventsourcing.index;
import com.eventsourcing.Entity;
import com.eventsourcing.EntityHandle;
import com.googlecode.cqengine.IndexedCollection;
import com.googlecode.cqengine.attribute.Attribute;
import com.googlecode.cqengine.attribute.*;
import com.googlecode.cqengine.query.Query;
import com.googlecode.cqengine.query.logical.And;
import com.googlecode.cqengine.query.logical.Not;
import com.googlecode.cqengine.query.logical.Or;
import com.googlecode.cqengine.query.option.*;
import com.googlecode.cqengine.query.simple.*;
import java.util.*;
import java.util.regex.Pattern;
/**
* Static factory for creating {@link Query} objects for {@link Entity}
*/
public interface EntityQueryFactory {
/**
* Creates an {@link Equal} query which asserts that an attribute equals a certain value.
*
* @param entityIndex The index to which the query refers
* @param attributeValue The value to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link Equal} query
*/
static Equal, A> equal(EntityIndex entityIndex, A attributeValue) {
return new Equal<>(entityIndex.getAttribute(), attributeValue);
}
/**
* Creates a {@link LessThan} query which asserts that an attribute is less than or equal to an upper bound
* (i.e. less than, inclusive).
*
* @param entityIndex The index to which the query refers
* @param attributeValue The upper bound to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return A {@link LessThan} query
*/
static > LessThan, A>
lessThanOrEqualTo(EntityIndex entityIndex, A attributeValue) {
return new LessThan<>(entityIndex.getAttribute(), attributeValue, true);
}
/**
* Creates a {@link LessThan} query which asserts that an attribute is less than (but not equal to) an upper
* bound (i.e. less than, exclusive).
*
* @param entityIndex The index to which the query refers
* @param attributeValue The upper bound to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return A {@link LessThan} query
*/
static > LessThan, A>
lessThan(EntityIndex entityIndex, A attributeValue) {
return new LessThan<>(entityIndex.getAttribute(), attributeValue, false);
}
/**
* Creates a {@link GreaterThan} query which asserts that an attribute is greater than or equal to a lower
* bound (i.e. greater than, inclusive).
*
* @param entityIndex The index to which the query refers
* @param attributeValue The lower bound to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return A {@link GreaterThan} query
*/
static > GreaterThan, A>
greaterThanOrEqualTo(EntityIndex entityIndex, A attributeValue) {
return new GreaterThan<>(entityIndex.getAttribute(), attributeValue, true);
}
/**
* Creates a {@link LessThan} query which asserts that an attribute is greater than (but not equal to) a lower
* bound (i.e. greater than, exclusive).
*
* @param entityIndex The index to which the query refers
* @param attributeValue The lower bound to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return A {@link GreaterThan} query
*/
static > GreaterThan, A>
greaterThan(EntityIndex entityIndex, A attributeValue) {
return new GreaterThan<>(entityIndex.getAttribute(), attributeValue, false);
}
/**
* Creates a {@link Between} query which asserts that an attribute is between a lower and an upper bound.
*
* @param entityIndex The index to which the query refers
* @param lowerValue The lower bound to be asserted by the query
* @param lowerInclusive Whether the lower bound is inclusive or not (true for "greater than or equal to")
* @param upperValue The upper bound to be asserted by the query
* @param upperInclusive Whether the upper bound is inclusive or not (true for "less than or equal to")
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return A {@link GreaterThan} query
*/
static > Between, A> between(EntityIndex entityIndex, A lowerValue, boolean lowerInclusive, A upperValue, boolean upperInclusive) {
return new Between<>(entityIndex.getAttribute(), lowerValue, lowerInclusive, upperValue, upperInclusive);
}
/**
* Creates a {@link Between} query which asserts that an attribute is between a lower and an upper bound,
* inclusive.
*
* @param entityIndex The index to which the query refers
* @param lowerValue The lower bound to be asserted by the query
* @param upperValue The upper bound to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return A {@link GreaterThan} query
*/
static > Between, A> between(EntityIndex entityIndex, A lowerValue, A upperValue) {
return new Between<>(entityIndex.getAttribute(), lowerValue, true, upperValue, true);
}
/**
* Creates a {@link In} query which asserts that an attribute has at least one value matching any value in a set of values.
*
If the given attribute is a {@link com.googlecode.cqengine.attribute.SimpleAttribute}, this method will set a hint in the query to
* indicate that results for the child queries will inherently be disjoint and so will not require deduplication.
*
* @param entityIndex The index to which the query refers
* @param attributeValues The set of values to match
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link In} query
*/
static Query> in(EntityIndex entityIndex, A... attributeValues) {
return in(entityIndex, Arrays.asList(attributeValues));
}
/**
* Creates a {@link In} query which asserts that an attribute has at least one value matching any value in a set of values.
*
If the given attribute is a {@link com.googlecode.cqengine.attribute.SimpleAttribute}, this method will set a hint in the query to
* indicate that results for the child queries will inherently be disjoint and so will not require deduplication.
*
* @param entityIndex The index to which the query refers
* @param attributeValues TThe set of values to match
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link In} query
*/
static Query> in(EntityIndex entityIndex, Collection attributeValues) {
return in(entityIndex, entityIndex instanceof SimpleIndex, attributeValues);
}
/**
* Creates a {@link In} query which asserts that an attribute has at least one value matching any value in a set of values.
*
Note that this can result in more efficient queries than several {@link Equal} queries "OR"ed together using other means.
*
* @param entityIndex The index to which the query refers
* @param disjoint Set it to {@code true} if deduplication is not necessary because the results are disjoint. Set it to {@code false} deduplication is needed
* @param attributeValues The set of values to match
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link In} query
*/
static Query> in(EntityIndex entityIndex, boolean disjoint, Collection
attributeValues) {
int n = attributeValues.size();
switch (n) {
case 0:
return none(entityIndex.getAttribute().getEffectiveObjectType());
case 1:
A singleValue = attributeValues.iterator().next();
return equal(entityIndex, singleValue);
default:
// Copy the values into a Set if necessary...
Set values = (attributeValues instanceof Set ? (Set)attributeValues : new HashSet(attributeValues));
return new In<>(entityIndex.getAttribute(), disjoint, values);
}
}
/**
* Creates a {@link StringStartsWith} query which asserts that an attribute starts with a certain string fragment.
*
* @param entityIndex The index to which the query refers
* @param attributeValue The value to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link StringStartsWith} query
*/
static StringStartsWith, A> startsWith(EntityIndex entityIndex, A attributeValue) {
return new StringStartsWith<>(entityIndex.getAttribute(), attributeValue);
}
/**
* Creates a {@link StringEndsWith} query which asserts that an attribute ends with a certain string fragment.
*
* @param entityIndex The index to which the query refers
* @param attributeValue The value to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link StringEndsWith} query
*/
static StringEndsWith, A> endsWith(EntityIndex entityIndex, A attributeValue) {
return new StringEndsWith<>(entityIndex.getAttribute(), attributeValue);
}
/**
* Creates a {@link StringContains} query which asserts that an attribute contains with a certain string fragment.
*
* @param entityIndex The index to which the query refers
* @param attributeValue The value to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link StringContains} query
*/
static StringContains, A> contains(EntityIndex entityIndex, A attributeValue) {
return new StringContains<>(entityIndex.getAttribute(), attributeValue);
}
/**
* Creates a {@link StringIsContainedIn} query which asserts that an attribute is contained in a certain string
* fragment.
*
* @param entityIndex The index to which the query refers
* @param attributeValue The value to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link StringStartsWith} query
*/
static StringIsContainedIn, A> isContainedIn(EntityIndex entityIndex, A attributeValue) {
return new StringIsContainedIn<>(entityIndex.getAttribute(), attributeValue);
}
/**
* Creates a {@link StringMatchesRegex} query which asserts that an attribute's value matches a regular expression.
*
* To accelerate {@code matchesRegex(...)} queries, add a Standing Query Index on {@code matchesRegex(...)}.
*
* @param entityIndex The index to which the query refers
* @param regexPattern The regular expression pattern to be asserted by the query
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link StringStartsWith} query
*/
static StringMatchesRegex, A> matchesRegex(EntityIndex entityIndex, Pattern regexPattern) {
return new StringMatchesRegex<>(entityIndex.getAttribute(), regexPattern);
}
/**
* Creates a {@link StringMatchesRegex} query which asserts that an attribute's value matches a regular expression.
*
* To accelerate {@code matchesRegex(...)} queries, add a Standing Query Index on {@code matchesRegex(...)}.
*
* @param entityIndex The index to which the query refers
* @param regex The regular expression to be asserted by the query (this will be compiled via {@link Pattern#compile(String)})
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link StringStartsWith} query
*/
static StringMatchesRegex, A> matchesRegex(EntityIndex entityIndex, String regex) {
return new StringMatchesRegex<>(entityIndex.getAttribute(), Pattern.compile(regex));
}
/**
* Creates an {@link Has} query which asserts that an attribute has a value (is not null).
*
* To accelerate {@code has(...)} queries, add a Standing Query Index on {@code has(...)}.
*
* To assert that an attribute does not have a value (is null), use not(has(...))
.
*
* To accelerate not(has(...))
queries, add a Standing Query Index on not(has(...))
.
*
* @param entityIndex The index to which the query refers
* @param The type of the attribute
* @param The type of the object containing the attribute
* @return An {@link Has} query
*/
static Has, A> has(EntityIndex entityIndex) {
return new Has<>(entityIndex.getAttribute());
}
/**
* Creates an {@link And} query, representing a logical AND on child queries, which when evaluated yields the
* set intersection of the result sets from child queries.
*
* @param query1 The first child query to be connected via a logical AND
* @param query2 The second child query to be connected via a logical AND
* @param The type of the object containing attributes to which child queries refer
* @return An {@link And} query, representing a logical AND on child queries
*/
static And> and(Query> query1, Query> query2) {
@SuppressWarnings({"unchecked"})
Collection>> queries = Arrays.asList(query1, query2);
return new And<>(queries);
}
/**
* Creates an {@link And} query, representing a logical AND on child queries, which when evaluated yields the
* set intersection of the result sets from child queries.
*
* @param query1 The first child query to be connected via a logical AND
* @param query2 The second child query to be connected via a logical AND
* @param additionalQueries Additional child queries to be connected via a logical AND
* @param The type of the object containing attributes to which child queries refer
* @return An {@link And} query, representing a logical AND on child queries
*/
static And> and(Query> query1, Query> query2,
Query>...
additionalQueries) {
Collection>> queries = new ArrayList<>(2 + additionalQueries.length);
queries.add(query1);
queries.add(query2);
Collections.addAll(queries, additionalQueries);
return new And>(queries);
}
/**
* Creates an {@link And} query, representing a logical AND on child queries, which when evaluated yields the
* set intersection of the result sets from child queries.
*
* @param query1 The first child query to be connected via a logical AND
* @param query2 The second child query to be connected via a logical AND
* @param additionalQueries Additional child queries to be connected via a logical AND
* @param The type of the object containing attributes to which child queries refer
* @return An {@link And} query, representing a logical AND on child queries
*/
static And> and(Query> query1, Query> query2, Collection>> additionalQueries) {
Collection>> queries = new ArrayList<>(2 + additionalQueries.size());
queries.add(query1);
queries.add(query2);
queries.addAll(additionalQueries);
return new And<>(queries);
}
/**
* Creates an {@link Or} query, representing a logical OR on child queries, which when evaluated yields the
* set union of the result sets from child queries.
*
* @param query1 The first child query to be connected via a logical OR
* @param query2 The second child query to be connected via a logical OR
* @param The type of the object containing attributes to which child queries refer
* @return An {@link Or} query, representing a logical OR on child queries
*/
static Or> or(Query> query1, Query> query2) {
@SuppressWarnings({"unchecked"})
Collection>> queries = Arrays.asList(query1, query2);
return new Or<>(queries);
}
/**
* Creates an {@link Or} query, representing a logical OR on child queries, which when evaluated yields the
* set union of the result sets from child queries.
*
* @param query1 The first child query to be connected via a logical OR
* @param query2 The second child query to be connected via a logical OR
* @param additionalQueries Additional child queries to be connected via a logical OR
* @param The type of the object containing attributes to which child queries refer
* @return An {@link Or} query, representing a logical OR on child queries
*/
static Or> or(Query> query1, Query> query2, Query>... additionalQueries) {
Collection>> queries = new ArrayList<>(2 + additionalQueries.length);
queries.add(query1);
queries.add(query2);
Collections.addAll(queries, additionalQueries);
return new Or<>(queries);
}
/**
* Creates an {@link Or} query, representing a logical OR on child queries, which when evaluated yields the
* set union of the result sets from child queries.
*
* @param query1 The first child query to be connected via a logical OR
* @param query2 The second child query to be connected via a logical OR
* @param additionalQueries Additional child queries to be connected via a logical OR
* @param The type of the object containing attributes to which child queries refer
* @return An {@link Or} query, representing a logical OR on child queries
*/
static Or> or(Query> query1, Query> query2, Collection>> additionalQueries) {
Collection>> queries = new ArrayList<>(2 + additionalQueries.size());
queries.add(query1);
queries.add(query2);
queries.addAll(additionalQueries);
return new Or<>(queries);
}
/**
* Creates a {@link Not} query, representing a logical negation of a child query, which when evaluated
* yields the set complement of the result set from the child query.
*
* @param query The child query to be logically negated
* @param The type of the object containing attributes to which child queries refer
* @return A {@link Not} query, representing a logical negation of a child query
*/
static Not> not(Query> query) {
return new Not<>(query);
}
/**
* Creates a query supporting the equivalent of SQL EXISTS
.
*
* Asserts that objects in a local {@code IndexedCollection} match objects in a foreign collection,
* based on a key attribute of local objects being equal to a key attribute of the foreign objects.
* This query can be performed on the local collection, supplying the foreign collection and the
* relevant attributes, as arguments to the query.
*
* This supports the SQL equivalent of:
*
* SELECT * From LocalCollection
* WHERE EXISTS (
* SELECT * FROM ForeignCollection
* WHERE LocalCollection.localAttribute = ForeignCollection.foreignAttribute
* )
*
*
* @param foreignCollection The collection of foreign objects
* @param localKeyAttribute An attribute of the local object
* @param foreignKeyAttribute An attribute of objects in the foreign collection
* @param The type of the local object
* @param The type of the foreign objects
* @param The type of the common attributes
* @return A query which checks if the local object matches any objects in the foreign collection based on the given
* key attributes being equal
*/
static Query>
existsIn(final IndexedCollection> foreignCollection,
final EntityIndex localKeyAttribute,
final EntityIndex foreignKeyAttribute) {
return new ExistsIn<>(foreignCollection, localKeyAttribute.getAttribute(),
foreignKeyAttribute.getAttribute());
}
/**
* Creates a query supporting the equivalent of SQL EXISTS
,
* with some additional restrictions on foreign objects.
*
* Asserts that objects in a local {@code IndexedCollection} match objects in a foreign collection,
* based on a key attribute of local objects being equal to a key attribute of the foreign objects,
* AND objects in the foreign collection matching some additional criteria.
* This query can be performed on the local collection, supplying the foreign collection and the
* relevant attributes, as arguments to the query.
*
* This supports the SQL equivalent of:
*
* SELECT * From LocalCollection
* WHERE EXISTS (
* SELECT * FROM ForeignCollection
* WHERE LocalCollection.localAttribute = ForeignCollection.foreignAttribute
* AND ([AND|OR|NOT](ForeignCollection.someOtherAttribute = x) ...)
* )
*
* @param foreignCollection The collection of foreign objects
* @param localKeyAttribute An attribute of the local object
* @param foreignKeyAttribute An attribute of objects in the foreign collection
* @param foreignRestrictions A query specifying additional restrictions on foreign objects
* @param The type of the local object
* @param The type of the foreign objects
* @param The type of the common attributes
* @return A query which checks if the local object matches any objects in the foreign collection based on the given
* key attributes being equal
*/
static Query>
existsIn(final IndexedCollection> foreignCollection,
final EntityIndex localKeyAttribute, final EntityIndex foreignKeyAttribute,
final Query> foreignRestrictions) {
return new ExistsIn<>(foreignCollection, localKeyAttribute.getAttribute(), foreignKeyAttribute.getAttribute(),
foreignRestrictions);
}
/**
* Creates an {@link OrderByOption} query option, encapsulating the given list of {@link AttributeOrder} objects
* which pair an attribute with a preference to sort results by that attribute in either ascending or descending
* order.
*
* @param attributeOrders The list of attribute orders by which objects should be sorted
* @param The type of the object containing the attributes
* @return An {@link OrderByOption} query option, requests results to be sorted in the given order
*/
static OrderByOption orderBy(List> attributeOrders) {
return new OrderByOption<>(attributeOrders);
}
/**
* Creates an {@link OrderByOption} query option, encapsulating the given list of {@link AttributeOrder} objects
* which pair an attribute with a preference to sort results by that attribute in either ascending or descending
* order.
*
* @param attributeOrders The list of attribute orders by which objects should be sorted
* @param The type of the object containing the attributes
* @return An {@link OrderByOption} query option, requests results to be sorted in the given order
*/
static OrderByOption orderBy(AttributeOrder... attributeOrders) {
return new OrderByOption<>(Arrays.asList(attributeOrders));
}
/**
* Creates an {@link AttributeOrder} object which pairs an attribute with a preference to sort results by that
* attribute in ascending order. These {@code AttributeOrder} objects can then be passed to the
* {@link #orderBy(com.googlecode.cqengine.query.option.AttributeOrder[])} method to create a query option which
* sorts results by the indicated attributes and ascending/descending preferences.
*
* @param entityIndex An attribute to sort by
* @param The type of the object containing the attributes
* @return An {@link AttributeOrder} object, encapsulating the attribute and a preference to sort results by it
* in ascending order
*/
static AttributeOrder> ascending(EntityIndex
entityIndex) {
return new AttributeOrder<>(entityIndex.getAttribute(), false);
}
/**
* Creates an {@link AttributeOrder} object which pairs an attribute with a preference to sort results by that
* attribute in descending order. These {@code AttributeOrder} objects can then be passed to the
* {@link #orderBy(com.googlecode.cqengine.query.option.AttributeOrder[])} method to create a query option which
* sorts results by the indicated attributes and ascending/descending preferences.
*
* @param entityIndex An attribute to sort by
* @param The type of the object containing the attributes
* @return An {@link AttributeOrder} object, encapsulating the attribute and a preference to sort results by it
* in descending order
*/
static AttributeOrder> descending(EntityIndex
entityIndex) {
return new AttributeOrder<>(entityIndex.getAttribute(), true);
}
/**
* Creates a {@link DeduplicationOption} query option, encapsulating a given {@link DeduplicationStrategy}, which
* when supplied to the query engine requests it to eliminate duplicates objects from the results returned using
* the strategy indicated.
*
* @param deduplicationStrategy The deduplication strategy the query engine should use
* @return A {@link DeduplicationOption} query option, requests duplicate objects to be eliminated from results
*/
static DeduplicationOption deduplicate(DeduplicationStrategy deduplicationStrategy) {
return new DeduplicationOption(deduplicationStrategy);
}
/**
* Creates a {@link IsolationOption} query option, encapsulating a given {@link IsolationLevel}, which
* when supplied to the query engine requests that level of transaction isolation.
*
* @param isolationLevel The transaction isolation level to request
* @return An {@link IsolationOption} query option
*/
static IsolationOption isolationLevel(IsolationLevel isolationLevel) {
return new IsolationOption(isolationLevel);
}
/**
* Creates an {@link ArgumentValidationOption} query option, encapsulating a given
* {@link ArgumentValidationStrategy}, which when supplied to the query engine requests that some argument
* validation may be disabled (or enabled) for performance or reliability reasons.
*
* @param strategy The argument validation strategy to request
* @return An {@link ArgumentValidationOption} query option
*/
static ArgumentValidationOption argumentValidation(ArgumentValidationStrategy strategy) {
return new ArgumentValidationOption(strategy);
}
/**
* A convenience method to encapsulate several objects together as {@link com.googlecode.cqengine.query.option.QueryOptions},
* where the class of the object will become its key in the QueryOptions map.
*
* @param queryOptions The objects to encapsulate as QueryOptions
* @return A {@link QueryOptions} object
*/
static QueryOptions queryOptions(Object... queryOptions) {
return queryOptions(Arrays.asList(queryOptions));
}
/**
* A convenience method to encapsulate a collection of objects as {@link com.googlecode.cqengine.query.option.QueryOptions},
* where the class of the object will become its key in the QueryOptions map.
*
* @param queryOptions The objects to encapsulate as QueryOptions
* @return A {@link QueryOptions} object
*/
static QueryOptions queryOptions(Collection