/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.torodb.mongodb.commands.signatures.admin;
import com.eightkdata.mongowp.bson.BsonArray;
import com.eightkdata.mongowp.bson.BsonDocument;
import com.eightkdata.mongowp.bson.BsonValue;
import com.eightkdata.mongowp.exceptions.BadValueException;
import com.eightkdata.mongowp.exceptions.NoSuchKeyException;
import com.eightkdata.mongowp.exceptions.TypesMismatchException;
import com.eightkdata.mongowp.fields.ArrayField;
import com.eightkdata.mongowp.fields.BooleanField;
import com.eightkdata.mongowp.fields.IntField;
import com.eightkdata.mongowp.fields.StringField;
import com.eightkdata.mongowp.server.api.impl.AbstractNotAliasableCommand;
import com.eightkdata.mongowp.utils.BsonDocumentBuilder;
import com.eightkdata.mongowp.utils.BsonReaderTool;
import com.google.common.collect.Lists;
import com.torodb.mongodb.commands.pojos.index.IndexOptions;
import com.torodb.mongodb.commands.signatures.admin.CreateIndexesCommand.CreateIndexesArgument;
import com.torodb.mongodb.commands.signatures.admin.CreateIndexesCommand.CreateIndexesResult;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
/**
*
*/
public class CreateIndexesCommand
extends AbstractNotAliasableCommand<CreateIndexesArgument, CreateIndexesResult> {
private static final String COMMAND_NAME = "createIndexes";
public static final CreateIndexesCommand INSTANCE = new CreateIndexesCommand();
public CreateIndexesCommand() {
super(COMMAND_NAME);
}
@Override
public Class<? extends CreateIndexesArgument> getArgClass() {
return CreateIndexesArgument.class;
}
@Override
public CreateIndexesArgument unmarshallArg(BsonDocument requestDoc)
throws TypesMismatchException, NoSuchKeyException, BadValueException {
return CreateIndexesArgument.unmarshall(requestDoc);
}
public CreateIndexesArgument unmarshallArgFromInsert(BsonDocument requestDoc)
throws TypesMismatchException, NoSuchKeyException, BadValueException {
return CreateIndexesArgument.unmarshallFromInsert(requestDoc);
}
@Override
public BsonDocument marshallArg(CreateIndexesArgument request) {
return request.marshall();
}
@Override
public Class<? extends CreateIndexesResult> getResultClass() {
return CreateIndexesResult.class;
}
@Override
public BsonDocument marshallResult(CreateIndexesResult reply) {
return reply.marshall();
}
@Override
public CreateIndexesResult unmarshallResult(BsonDocument replyDoc) throws TypesMismatchException,
NoSuchKeyException {
return CreateIndexesResult.unmarshall(replyDoc);
}
public static class CreateIndexesArgument {
private static final StringField COLLECTION_FIELD = new StringField(COMMAND_NAME);
private static final ArrayField INDEXES_FIELD = new ArrayField("indexes");
private static final StringField NS_FIELD = new StringField("ns");
private final String collection;
private final List<IndexOptions> indexesToCreate;
public CreateIndexesArgument(String collection, List<IndexOptions> indexesToCreate) {
this.collection = collection;
this.indexesToCreate = indexesToCreate;
}
public String getCollection() {
return collection;
}
public List<IndexOptions> getIndexesToCreate() {
return Collections.unmodifiableList(indexesToCreate);
}
private BsonDocument marshall() {
List<BsonValue<?>> list = new ArrayList<>(indexesToCreate.size());
for (IndexOptions indexToCreate : indexesToCreate) {
list.add(indexToCreate.marshall());
}
return new BsonDocumentBuilder()
.append(COLLECTION_FIELD, collection)
.append(INDEXES_FIELD, list)
.build();
}
private static CreateIndexesArgument unmarshall(BsonDocument requestDoc)
throws TypesMismatchException, NoSuchKeyException, BadValueException {
String collection = BsonReaderTool.getString(requestDoc, COLLECTION_FIELD);
BsonArray optionsArray = BsonReaderTool.getArray(requestDoc, INDEXES_FIELD);
List<IndexOptions> indexes = Lists.newArrayListWithCapacity(optionsArray.size());
for (BsonValue element : optionsArray) {
if (!element.isDocument()) {
throw new BadValueException("The element " + element
+ " inside " + INDEXES_FIELD + " array is not a document");
}
IndexOptions options = IndexOptions.unmarshall(element.asDocument());
indexes.add(options);
}
return new CreateIndexesArgument(collection, indexes);
}
private static CreateIndexesArgument unmarshallFromInsert(BsonDocument requestDoc)
throws TypesMismatchException, NoSuchKeyException, BadValueException {
String collection = BsonReaderTool.getString(requestDoc, NS_FIELD);
BsonArray optionsArray = BsonReaderTool.getArray(requestDoc, INDEXES_FIELD);
List<IndexOptions> indexes = Lists.newArrayListWithCapacity(optionsArray.size());
for (BsonValue element : optionsArray) {
if (!element.isDocument()) {
throw new BadValueException("The element " + element
+ " inside " + INDEXES_FIELD + " array is not a document");
}
IndexOptions options = IndexOptions.unmarshall(element.asDocument());
indexes.add(options);
}
return new CreateIndexesArgument(collection, indexes);
}
}
public static class CreateIndexesResult {
private static final IntField INDEX_BEFORE_FIELD = new IntField("numIndexesBefore");
private static final IntField INDEX_AFTER_FIELD = new IntField("numIndexesAfter");
private static final StringField NOTE_FIELD = new StringField("note");
private static final BooleanField CREATED_COLLECTION_FIELD = new BooleanField(
"createdCollectionAutomatically");
private final int numIndexesBefore;
private final int numIndexesAfter;
@Nullable
private final String note;
private final boolean createdCollectionAutomatically;
public CreateIndexesResult(
int numIndexesBefore,
int numIndexesAfter,
@Nullable String note,
boolean createdCollectionAutomatically) {
this.numIndexesBefore = numIndexesBefore;
this.numIndexesAfter = numIndexesAfter;
this.note = note;
this.createdCollectionAutomatically = createdCollectionAutomatically;
}
public int getNumIndexesBefore() {
return numIndexesBefore;
}
public int getNumIndexesAfter() {
return numIndexesAfter;
}
public int getNumNewIndexes() {
return numIndexesAfter - numIndexesBefore;
}
@Nullable
public String getNote() {
return note;
}
public boolean isCreatedCollectionAutomatically() {
return createdCollectionAutomatically;
}
private static CreateIndexesResult unmarshall(BsonDocument replyDoc) throws
TypesMismatchException, NoSuchKeyException {
boolean createdCollecion = BsonReaderTool.getBooleanOrNumeric(replyDoc,
CREATED_COLLECTION_FIELD, false);
int indexesBefore = BsonReaderTool.getInteger(replyDoc, INDEX_BEFORE_FIELD);
int indexesAfter = BsonReaderTool.getInteger(replyDoc, INDEX_AFTER_FIELD);
String note = BsonReaderTool.getString(replyDoc, NOTE_FIELD, null);
return new CreateIndexesResult(indexesBefore, indexesAfter, note, createdCollecion);
}
private BsonDocument marshall() {
BsonDocumentBuilder builder = new BsonDocumentBuilder();
if (createdCollectionAutomatically) {
builder.append(CREATED_COLLECTION_FIELD, true);
}
builder.append(INDEX_BEFORE_FIELD, numIndexesBefore)
.append(INDEX_AFTER_FIELD, numIndexesAfter);
if (note != null) {
builder.append(NOTE_FIELD, note);
}
return builder.build();
}
}
}