org.javers.repository.jql.QueryBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javers-core Show documentation
Show all versions of javers-core Show documentation
JaVers - object auditing and diff framework for Java
package org.javers.repository.jql;
import org.javers.common.collections.Sets;
import org.javers.common.exception.JaversException;
import org.javers.common.exception.JaversExceptionCode;
import org.javers.common.validation.Validate;
import org.javers.core.Javers;
import org.javers.core.commit.CommitId;
import org.javers.core.metamodel.object.CdoSnapshot;
import org.javers.core.metamodel.object.SnapshotType;
import org.javers.repository.api.QueryParamsBuilder;
import org.javers.repository.jql.FilterDefinition.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.javers.repository.jql.InstanceIdDTO.instanceId;
import static java.time.LocalTime.MIDNIGHT;
import static org.javers.repository.jql.ShadowScope.*;
/**
* Fluent API for building {@link JqlQuery},
* executed with {@link Javers#findChanges(JqlQuery)} and {@link Javers#findSnapshots(JqlQuery)}
*
* @see http://javers.org/documentation/jql-examples
* @author bartosz.walacik
*/
public class QueryBuilder {
private static final int DEFAULT_LIMIT = 100;
private static final int DEFAULT_SKIP = 0;
private static final int DEFAULT_GAPS_TO_FILL_LIMIT = 10;
private static final ShadowScope DEFAULT_SHADOW_SCOPE = SHALLOW;
private final FilterDefinition filter;
private final QueryParamsBuilder queryParamsBuilder;
private ShadowScope shadowScope = DEFAULT_SHADOW_SCOPE;
private int maxGapsToFill;
private QueryBuilder(FilterDefinition filter) {
Validate.argumentIsNotNull(filter);
this.filter = filter;
queryParamsBuilder = QueryParamsBuilder
.withLimit(DEFAULT_LIMIT)
.skip(DEFAULT_SKIP);
}
/**
* Query for selecting changes (or snapshots) made on any object.
*
*
* For example, last changes committed on any object can be fetched with:
*
* javers.findChanges( QueryBuilder.anyDomainObject().build() );
*
* @since 2.0
*/
public static QueryBuilder anyDomainObject(){
return new QueryBuilder(new AnyDomainObjectFilterDefinition());
}
/**
* Query for selecting changes (or snapshots) made on
* any object (Entity or ValueObject) of given classes.
*
*
* For example, last changes on any object of MyClass.class:
*
* javers.findChanges( QueryBuilder.byClass(MyClass.class).build() );
*
*/
public static QueryBuilder byClass(Class... requiredClasses){
return new QueryBuilder(new ClassFilterDefinition(Sets.asSet(requiredClasses)));
}
/**
* Query for selecting Changes, Snapshots or Shadows for a given Entity instance.
*
*
* For example, last Changes on "bob" Person:
*
* javers.findChanges( QueryBuilder.byInstanceId("bob", Person.class).build() );
*
*
* @param localId Value of an Id-property. When an Entity has Composite-Id (more than one Id-property) —
* localId
should be Map<String, Object>
with
* Id-property name to value pairs.
* @see CompositeIdExample.groovy
*/
public static QueryBuilder byInstanceId(Object localId, Class entityClass){
Validate.argumentsAreNotNull(localId, entityClass);
return new QueryBuilder(new IdFilterDefinition(instanceId(localId, entityClass)));
}
/**
* Query for selecting Changes, Snapshots or Shadows for a given Entity instance, identified by its type name.
*
*
* For example, last Changes on "bob" Person:
*
* javers.findChanges( QueryBuilder.byInstanceId("bob", "Person").build() );
*
*
* @param localId Value of an Id-property. When an Entity has Composite-Id (more than one Id-property) —
* localId
should be Map<String, Object>
with
* Id-property name to value pairs.
* @see CompositeIdExample.groovy
*/
public static QueryBuilder byInstanceId(Object localId, String typeName){
Validate.argumentsAreNotNull(localId, typeName);
return new QueryBuilder(new IdAndTypeNameFilterDefinition(localId, typeName));
}
/**
* Query for selecting changes (or snapshots) made on a concrete Entity instance.
*
*
* For example, last changes on "bob" Person:
*
* javers.findChanges( QueryBuilder.byInstanceId(new Person("bob")).build() );
*
* @Since 2.8.0
*/
public static QueryBuilder byInstance(Object instance){
Validate.argumentsAreNotNull(instance);
return new QueryBuilder(new InstanceFilterDefinition(instance));
}
/**
* Query for selecting changes (or snapshots)
* made on all ValueObjects at given path, owned by any instance of given Entity.
*
*
* See path parameter hints in {@link #byValueObjectId(Object, Class, String)}.
*/
public static QueryBuilder byValueObject(Class ownerEntityClass, String path){
Validate.argumentsAreNotNull(ownerEntityClass, path);
return new QueryBuilder(new VoOwnerFilterDefinition(ownerEntityClass, path));
}
/**
* Query for selecting changes (or snapshots) made on a concrete ValueObject
* (so a ValueObject owned by a concrete Entity instance).
*
*
* Path parameter is a relative path from owning Entity instance to ValueObject that you are looking for.
*
*
* When ValueObject is just a property, use propertyName. For example:
*
* class Employee {
* @Id String name;
* Address primaryAddress;
* }
* ...
* javers.findChanges( QueryBuilder.byValueObjectId("bob", Employee.class, "primaryAddress").build() );
*
*
* When ValueObject is stored in a List, use propertyName and list index separated by "/", for example:
*
* class Employee {
* @Id String name;
* List<Address> addresses;
* }
* ...
* javers.findChanges( QueryBuilder.byValueObjectId("bob", Employee.class, "addresses/0").build() );
*
*
* When ValueObject is stored as a Map value, use propertyName and map key separated by "/", for example:
*
* class Employee {
* @Id String name;
* Map<String,Address> addressMap;
* }
* ...
* javers.findChanges( QueryBuilder.byValueObjectId("bob", Employee.class, "addressMap/HOME").build() );
*
*/
public static QueryBuilder byValueObjectId(Object ownerLocalId, Class ownerEntityClass, String path){
Validate.argumentsAreNotNull(ownerEntityClass, ownerLocalId, path);
return new QueryBuilder(new IdFilterDefinition(ValueObjectIdDTO.valueObjectId(ownerLocalId, ownerEntityClass, path)));
}
@Deprecated
public static QueryBuilder byGlobalId(GlobalIdDTO globalId){
Validate.argumentIsNotNull(globalId);
return new QueryBuilder(new IdFilterDefinition(globalId));
}
/**
* Only snapshots which changed a given property.
*
* @see CdoSnapshot#getChanged()
*/
public QueryBuilder withChangedProperty(String propertyName) {
Validate.argumentIsNotNull(propertyName);
queryParamsBuilder.changedProperty(propertyName);
return this;
}
/**
* See javadoc in {@link #withNewObjectChanges()}
*/
public QueryBuilder withNewObjectChanges(boolean newObjectChanges) {
queryParamsBuilder.newObjectChanges(newObjectChanges);
return this;
}
/**
* Affects changes query only.
* When switched on, additional changes are generated for the initial snapshot
* (the first commit of a given object). Off by default.
*
* It means one NewObject change for each initial snapshot
* and the full set of initial PropertyChanges with null on the left side
* and initial property value on the right.
*/
public QueryBuilder withNewObjectChanges() {
queryParamsBuilder.newObjectChanges(true);
return this;
}
/**
* Selects only snapshots with a given type: initial, update or terminal.
*
*
* Typical use case:
*
*
* javers.findSnapshots(QueryBuilder.byClass(SnapshotEntity)
* .withChangedProperty("someProperty")
* .withSnapshotTypeUpdate().build())
*
*/
public QueryBuilder withSnapshotType(SnapshotType snapshotType) {
queryParamsBuilder.withSnapshotType(snapshotType);
return this;
}
/**
* Selects only updating snapshots (without initial ones).
*/
public QueryBuilder withSnapshotTypeUpdate() {
queryParamsBuilder.withSnapshotType(SnapshotType.UPDATE);
return this;
}
/**
* Only for Snapshot and Changes queries, see {@link #withChildValueObjects()}
*
* @since 2.1
*/
public QueryBuilder withChildValueObjects(boolean aggregate) {
queryParamsBuilder.withChildValueObjects(aggregate);
return this;
}
/**
* Only for Snapshot and Changes queries.
* When enabled, selects all child ValueObjects owned by selected Entities.
*
*
* This switch has no effect on Shadow queries because Shadows
* are always loaded together with their child ValueObjects
* (see {@link ShadowScope#CHILD_VALUE_OBJECT}).
*
* @since 2.1
* @see http://javers.org/documentation/jql-examples
*/
public QueryBuilder withChildValueObjects() {
queryParamsBuilder.withChildValueObjects(true);
return this;
}
/**
* Limits number of Snapshots to be fetched from JaversRepository in a single query,
* default is 100.
*
*
* Always choose reasonable limits to improve performance of your queries.
*/
public QueryBuilder limit(int limit) {
queryParamsBuilder.limit(limit);
return this;
}
/**
* Sets the number of Snapshots to skip.
* Use skip() and limit() for paging Snapshots and Changes.
*
*
* For paging Shadows use {@link Javers#findShadowsAndStream(JqlQuery)}
* with {@link Stream#skip(long)} and {@link Stream#limit(long)}.
*
*/
public QueryBuilder skip(int skip) {
queryParamsBuilder.skip(skip);
return this;
}
/**
* Limits to snapshots created after this date or exactly at this date.
*
*
* CommitDate is local datetime
* Please remember that commitDate is persisted as LocalDateTime
* (without information about time zone and daylight saving time).
*
*
* It may affects your query results. For example,
* once a year when DST ends,
* one hour is repeated (clock goes back from 3 am to 2 am).
* Looking just on the commitDate we
* can't distinct in which iteration of the hour, given commit was made.
*
* @see #to(LocalDateTime)
*/
public QueryBuilder from(LocalDateTime from) {
queryParamsBuilder.from(from);
return this;
}
/**
* Limits to snapshots created before this date or exactly at this date.
*/
public QueryBuilder to(LocalDateTime to) {
queryParamsBuilder.to(to);
return this;
}
/**
* Only snapshots created in a given commit.
*/
public QueryBuilder withCommitId(CommitId commitId) {
Validate.argumentIsNotNull(commitId);
queryParamsBuilder.commitId(commitId);
return this;
}
/**
* Delegates to {@link #withCommitId(CommitId)}
*/
public QueryBuilder withCommitId(BigDecimal commitId) {
Validate.argumentIsNotNull(commitId);
queryParamsBuilder.commitId(CommitId.valueOf(commitId));
return this;
}
/**
* Only snapshots created in given commits.
*/
public QueryBuilder withCommitIds(Collection commitIds) {
Validate.argumentIsNotNull(commitIds);
queryParamsBuilder.commitIds(commitIds.stream().map(CommitId::valueOf).collect(Collectors.toSet()));
return this;
}
/**
* Only snapshots created before this commit or exactly in this commit.
*/
public QueryBuilder toCommitId(CommitId commitId) {
Validate.argumentIsNotNull(commitId);
queryParamsBuilder.toCommitId(commitId);
return this;
}
/**
* delegates to {@link #from(LocalDateTime)} with MIDNIGHT
*/
public QueryBuilder from(LocalDate fromDate) {
return from(fromDate.atTime(MIDNIGHT));
}
/**
* delegates to {@link #to(LocalDateTime)} with MIDNIGHT
*/
public QueryBuilder to(LocalDate toDate) {
return to(toDate.atTime(MIDNIGHT));
}
/**
* Only snapshots with a given commit property.
*
all given properties must match with persisted commit properties.
* @since 2.0
*/
public QueryBuilder withCommitProperty(String name, String value) {
Validate.argumentsAreNotNull(name, value);
queryParamsBuilder.commitProperty(name, value);
return this;
}
/**
* Only snapshots with a given version.
*/
public QueryBuilder withVersion(long version) {
Validate.argumentCheck(version > 0, "Version is not a positive number.");
queryParamsBuilder.version(version);
return this;
}
/**
* Choose between shallow, child-value-object, commit-deep or deep+ query scopes.
*
* The wider the scope, the more object shadows are loaded to the resulting graph.
*
*
* Default scope is {@link ShadowScope#SHALLOW}.
*
*
* Read more about query scopes in {@link Javers#findShadows(JqlQuery)} javadoc.
*
*
* Only for Shadow queries.
*
* @see http://javers.org/documentation/jql-examples
* @since 3.2
*/
public QueryBuilder withShadowScope(ShadowScope shadowScope){
Validate.argumentIsNotNull(shadowScope);
this.shadowScope = shadowScope;
if (shadowScope == DEEP_PLUS && maxGapsToFill == 0) {
this.maxGapsToFill = DEFAULT_GAPS_TO_FILL_LIMIT;
}
return this;
}
/**
* Selects {@link ShadowScope#COMMIT_DEEP} for Shadow queries.
*
*
* Read about query scopes in {@link Javers#findShadows(JqlQuery)} javadoc.
*
* @see http://javers.org/documentation/jql-examples
* @since 3.5
*/
public QueryBuilder withScopeCommitDeep() {
return withShadowScope(COMMIT_DEEP);
}
/**
* Selects {@link ShadowScope#DEEP_PLUS}
* with maxGapsToFill
defaulted to 10.
*
*
* Read more about query scopes in {@link Javers#findShadows(JqlQuery)} javadoc.
*
*
* Only for Shadow queries.
*
* @see http://javers.org/documentation/jql-examples
* @since 3.5
*/
public QueryBuilder withScopeDeepPlus() {
return withShadowScope(DEEP_PLUS);
}
/**
* Selects {@link ShadowScope#DEEP_PLUS} with given maxGapsToFill
.
*
*
* Read more about Shadow query scopes, profiling, and runtime statistics
* in {@link Javers#findShadows(JqlQuery)} javadoc.
*
*
* Only for Shadow queries.
*
* @param maxGapsToFill Limits the number of referenced entity Shadows to be eagerly loaded.
* The limit is global for a query. When it is exceeded,
* references to other entities are nulled. Collections of entities may not be fully loaded.
* @see http://javers.org/documentation/jql-examples
* @since 3.5
*/
public QueryBuilder withScopeDeepPlus(int maxGapsToFill) {
this.maxGapsToFill = maxGapsToFill;
return withShadowScope(DEEP_PLUS);
}
/**
* @deprecated renamed to {@link #withScopeDeepPlus()} ()}
*/
@Deprecated
public QueryBuilder withScopeCommitDeepPlus() {
return withScopeDeepPlus();
}
/**
* @deprecated renamed to {@link #withScopeDeepPlus(int)} ()}
*/
@Deprecated
public QueryBuilder withScopeCommitDeepPlus(int maxGapsToFill) {
return withScopeDeepPlus(maxGapsToFill);
}
/**
* Only snapshots committed by a given author.
* @since 2.0
*/
public QueryBuilder byAuthor(String author) {
Validate.argumentIsNotNull(author);
queryParamsBuilder.author(author);
return this;
}
public JqlQuery build() {
return new JqlQuery(filter, queryParamsBuilder.build(), new ShadowScopeDefinition(shadowScope, maxGapsToFill));
}
/**
* renamed to {@link #withScopeCommitDeep()}
* @deprecated
*/
@Deprecated
public QueryBuilder withShadowScopeDeep() {
return withShadowScope(COMMIT_DEEP);
}
/**
* renamed to {@link #withChangedProperty(String)}
* @deprecated
*/
@Deprecated
public QueryBuilder andProperty(String propertyName) {
return withChangedProperty(propertyName);
}
}