/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.mongodb.query.impl;
import static org.hibernate.ogm.datastore.mongodb.query.impl.MongoDBQueryDescriptor.Operation.FINDANDMODIFY;
import static org.hibernate.ogm.datastore.mongodb.query.impl.MongoDBQueryDescriptor.Operation.INSERT;
import static org.hibernate.ogm.datastore.mongodb.query.impl.MongoDBQueryDescriptor.Operation.REMOVE;
import static org.hibernate.ogm.datastore.mongodb.query.impl.MongoDBQueryDescriptor.Operation.UPDATE;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import org.bson.Document;
import com.mongodb.client.model.Collation;
/**
* Describes a query to be executed against MongoDB.
*
* @author Gunnar Morling
* @author Davide D'Alto
* @author Thorsten Möller
*/
public class MongoDBQueryDescriptor implements Serializable {
/**
* Enum with operations
* @see <a href="https://docs.mongodb.com/manual/reference/method/js-collection/">list of operations in mongo shell</a>
*/
public enum Operation {
FIND,
FINDONE,
FINDANDMODIFY,
INSERT,
INSERTONE,
INSERTMANY,
REMOVE,
UPDATE,
UPDATEONE,
UPDATEMANY,
REPLACEONE,
COUNT,
/**
* This is used by the query parser when the parsed query requires an aggregation, usually for embedded collections.
*/
AGGREGATE,
/**
* This is used for native queries, when the user wants to execute a generic aggregation query.
*/
AGGREGATE_PIPELINE,
DISTINCT;
}
private final String collectionName;
private final Operation operation;
private final Document criteria; // Overloaded to be the 'document' for a FINDANDMODIFY query (which is a kind of criteria),
private final Document projection;
/**
* Distinct query will use this field name
*/
private final String distinctFieldName;
/**
* Collation object will be used for Distinct Operation
*/
private final Collation collation; // As of now only applicable to distinct queries
/**
* The "update" (new values to apply) in case this is an UPDATE query or values to insert in case this is an INSERT query.
*/
private final Document updateOrInsertOne;
private final List<Document> updateOrInsertMany;
private final Document orderBy;
/**
* Optional query options in case this is an UPDATE, INSERT or REMOVE. Will have the following structure:
* <ul>
* <li>{ upsert: boolean, multi: boolean, writeConcern: document } for an UPDATE query</li>
* <li>{ ordered: boolean, writeConcern: document } argument for an INSERT query</li>
* <li>{ justOne: boolean, writeConcern: document } argument for a REMOVE query</li>
* </ul>
*/
private final Document options;
private final List<String> unwinds;
private final List<Document> pipeline;
public MongoDBQueryDescriptor(String collectionName, Operation operation, Document criteria, Collation collation, String distinctFieldName) {
this.collectionName = collectionName;
this.operation = operation;
this.criteria = criteria;
this.projection = null;
this.orderBy = null;
this.options = null;
this.updateOrInsertOne = null;
this.updateOrInsertMany = null;
this.unwinds = null;
this.pipeline = Collections.<Document>emptyList();
this.distinctFieldName = distinctFieldName;
this.collation = collation;
}
public MongoDBQueryDescriptor(String collectionName, Operation operation, List<Document> pipeline) {
this.collectionName = collectionName;
this.operation = operation;
this.criteria = null;
this.projection = null;
this.orderBy = null;
this.options = null;
this.updateOrInsertOne = null;
this.updateOrInsertMany = null;
this.unwinds = null;
this.pipeline = pipeline == null ? Collections.<Document>emptyList() : pipeline;
this.distinctFieldName = null;
this.collation = null;
}
public MongoDBQueryDescriptor(String collectionName,Operation operation,Document criteria, Document projection, Document orderBy, Document options, Document updateOrInsertOne, List<Document> updateOrInsertMany, List<String> unwinds) {
this.collectionName = collectionName;
this.operation = operation;
this.criteria = criteria;
this.projection = projection;
this.orderBy = orderBy;
this.options = options;
this.updateOrInsertOne = updateOrInsertOne;
this.updateOrInsertMany = updateOrInsertMany;
this.unwinds = unwinds;
this.pipeline = Collections.<Document>emptyList();
this.distinctFieldName = null;
this.collation = null;
}
public List<Document> getPipeline() {
return pipeline;
}
/**
* The name of the collection to select from.
*
* @return the collection name
*/
public String getCollectionName() {
return collectionName;
}
public Operation getOperation() {
return operation;
}
/**
* Criteria describing the records to apply this query to.
*
* @return the {@link Document} representing the criteria
*/
public Document getCriteria() {
return criteria;
}
/**
* The fields to be selected, if this query doesn't return all fields of the entity. Passed to the {@code keys}
* parameter of the MongoDB find API.
*
* @return the {@link Document} representing the projection
*/
public Document getProjection() {
return projection;
}
/**
* Get the order criteria of the result of the query.
*
* @return the {@link Document} representing the order to apply the results of the query
*/
public Document getOrderBy() {
return orderBy;
}
/**
* Returns (optional) query options if this is a INSERT, UPDATE or REMOVE query.
*/
public Document getOptions() {
return options;
}
/**
* Returns the update (new values to apply) in case this is an UPDATE query or values to insert in case this is an
* INSERT query.
*/
public Document getUpdateOrInsertOne() {
return updateOrInsertOne;
}
public List<Document> getUpdateOrInsertMany() {
return updateOrInsertMany;
}
public List<String> getUnwinds() {
return unwinds;
}
/**
* Name of field on which distinct query will be performed
*/
public String getDistinctFieldName() {
return distinctFieldName;
}
/**
* Returns collation document which will be used in DISTINCT operation
*
*/
public Collation getCollation() {
return collation;
}
@Override
public String toString() {
return String.format( "MongoDBQueryDescriptor [collectionName=%s, %s=%s, %s=%s, %s%s]",
collectionName,
operation == FINDANDMODIFY ? "document" : operation == INSERT ? "document(s)" : "where", criteria,
operation == UPDATE ? "update" : operation == INSERT ? "insert" : operation == REMOVE ? "remove" : "projection", projection,
operation == UPDATE || operation == INSERT || operation == REMOVE ? "" : "options=", options );
}
}