io.helidon.dbclient.mongodb.MongoDbStatement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of helidon-dbclient-mongodb Show documentation
Show all versions of helidon-dbclient-mongodb Show documentation
Helidon Database Client MongoDB Support
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.dbclient.mongodb;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.json.Json;
import javax.json.JsonReaderFactory;
import io.helidon.dbclient.DbStatement;
import io.helidon.dbclient.DbStatementType;
import io.helidon.dbclient.common.AbstractStatement;
import io.helidon.dbclient.common.DbStatementContext;
import io.helidon.dbclient.mongodb.MongoDbTransaction.TransactionManager;
import com.mongodb.reactivestreams.client.MongoDatabase;
import org.bson.Document;
/**
* Common MongoDB statement builder.
*
* @param MongoDB statement type
* @param Statement execution result type
*/
abstract class MongoDbStatement, R> extends AbstractStatement {
/**
* Empty JSON object.
*/
static final Document EMPTY = Document.parse(Json.createObjectBuilder().build().toString());
/**
* Operation JSON parameter name.
*/
protected static final String JSON_OPERATION = "operation";
/**
* Collection JSON parameter name.
*/
protected static final String JSON_COLLECTION = "collection";
/**
* Query JSON parameter name.
*/
protected static final String JSON_QUERY = "query";
/**
* Value JSON parameter name.
*/
protected static final String JSON_VALUE = "value";
/**
* Projection JSON parameter name: Defines projection to restrict returned fields.
*/
protected static final String JSON_PROJECTION = "projection";
/**
* JSON reader factory.
*/
protected static final JsonReaderFactory READER_FACTORY = Json.createReaderFactory(Collections.emptyMap());
/** MongoDB database. */
private final MongoDatabase db;
/** MongoDB transaction manager. Set to {@code null} when not running in transaction. */
private TransactionManager txManager;
/**
* Creates an instance of MongoDB statement builder.
*
* @param db mongo database handler
* @param statementContext configuration of statement
*/
MongoDbStatement(MongoDatabase db, DbStatementContext statementContext) {
super(statementContext);
this.db = db;
this.txManager = null;
}
/**
* Set target transaction for this statement.
*
* @param tx MongoDB transaction session
* @return MongoDB statement builder
*/
@SuppressWarnings("unchecked")
B inTransaction(TransactionManager tx) {
this.txManager = tx;
this.txManager.addStatement(this);
return (B) this;
}
String build() {
switch (paramType()) {
// Statement shall not contain any parameters, no conversion is needed.
case UNKNOWN:
return statement();
case INDEXED:
return StatementParsers.indexedParser(statement(), indexedParams()).convert();
// Replace parameter identifiers with values from name to value map
case NAMED:
return StatementParsers.namedParser(statement(), namedParams()).convert();
default:
throw new IllegalStateException("Unknown SQL statement type: " + paramType());
}
}
/**
* Statement name.
*
* @return name of this statement (never null, may be generated)
*/
@Override
public String statementName() {
return super.statementName();
}
MongoDatabase db() {
return db;
}
boolean noTx() {
return txManager == null;
}
TransactionManager txManager() {
return txManager;
}
@Override
protected String dbType() {
return MongoDbClientProvider.DB_TYPE;
}
/**
* Mongo operation enumeration.
*/
enum MongoOperation {
QUERY("query", "find", "select"),
INSERT("insert"),
UPDATE("update"),
DELETE("delete"),
// Database command not related to a specific collection
// Only executable using generic statement
COMMAND("command");
private static final Map NAME_TO_OPERATION = new HashMap<>();
static {
for (MongoOperation value : MongoOperation.values()) {
for (String name : value.names) {
NAME_TO_OPERATION.put(name.toLowerCase(), value);
}
}
}
static MongoOperation operationByName(String name) {
if (name == null) {
return null;
}
return NAME_TO_OPERATION.get(name.toLowerCase());
}
private final String[] names;
MongoOperation(String... names) {
this.names = names;
}
}
static class MongoStatement {
private final String preparedStmt;
private static Document/*JsonObject*/ readStmt(JsonReaderFactory jrf, String preparedStmt) {
return Document.parse(preparedStmt);
}
private final Document/*JsonObject*/ jsonStmt;
private final MongoOperation operation;
private final String collection;
private final Document query;
private final Document value;
private final Document projection;
MongoStatement(DbStatementType dbStatementType, JsonReaderFactory jrf, String preparedStmt) {
this.preparedStmt = preparedStmt;
this.jsonStmt = readStmt(jrf, preparedStmt);
MongoOperation operation;
if (jsonStmt.containsKey(JSON_OPERATION)) {
operation = MongoOperation.operationByName(jsonStmt.getString(JSON_OPERATION));
// make sure we have alignment between statement type and operation
switch (dbStatementType) {
case QUERY:
case GET:
validateOperation(dbStatementType, operation, MongoOperation.QUERY);
break;
case INSERT:
validateOperation(dbStatementType, operation, MongoOperation.INSERT);
break;
case UPDATE:
validateOperation(dbStatementType, operation, MongoOperation.UPDATE);
break;
case DELETE:
validateOperation(dbStatementType, operation, MongoOperation.DELETE);
break;
case DML:
validateOperation(dbStatementType, operation, MongoOperation.INSERT,
MongoOperation.UPDATE, MongoOperation.DELETE);
break;
case COMMAND:
validateOperation(dbStatementType, operation, MongoOperation.COMMAND);
break;
default:
throw new IllegalStateException(
"Operation type is not defined in statement, and cannot be inferred from statement type: "
+ dbStatementType);
}
} else {
switch (dbStatementType) {
case QUERY:
operation = MongoOperation.QUERY;
break;
case GET:
operation = MongoOperation.QUERY;
break;
case INSERT:
operation = MongoOperation.INSERT;
break;
case UPDATE:
operation = MongoOperation.UPDATE;
break;
case DELETE:
operation = MongoOperation.DELETE;
break;
case COMMAND:
operation = MongoOperation.COMMAND;
break;
case DML:
default:
throw new IllegalStateException(
"Operation type is not defined in statement, and cannot be inferred from statement type: "
+ dbStatementType);
}
}
this.operation = operation;
this.collection = jsonStmt.getString(JSON_COLLECTION);
this.value = jsonStmt.get(JSON_VALUE, Document.class);
this.query = jsonStmt.get(JSON_QUERY, Document.class);
this.projection = jsonStmt.get(JSON_PROJECTION, Document.class);
}
private static void validateOperation(DbStatementType dbStatementType,
MongoOperation actual,
MongoOperation... expected) {
// PERF: time complexity of this check is terrible
for (MongoOperation operation : expected) {
if (actual == operation) {
return;
}
}
throw new IllegalStateException("Statement type is "
+ dbStatementType
+ ", yet operation in statement is: "
+ actual);
}
Document/*JsonObject*/ getJsonStmt() {
return jsonStmt;
}
MongoOperation getOperation() {
return operation;
}
String getCollection() {
return collection;
}
Document getQuery() {
return query != null ? query : EMPTY;
}
Document getValue() {
return value;
}
Document getProjection() {
return projection;
}
@Override
public String toString() {
return preparedStmt;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy