Skip to content

Commit

Permalink
Issue #90 Convert InsertMany to execute as a runCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
jsonking authored and alexandru-slobodcicov committed Feb 7, 2021
1 parent 0873c90 commit dedda68
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,27 @@
* #L%
*/

import com.mongodb.client.MongoCollection;
import liquibase.ext.mongodb.database.MongoConnection;
import liquibase.nosql.statement.NoSqlExecuteStatement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.bson.Document;

import java.util.ArrayList;
import java.util.List;

import static java.util.Optional.ofNullable;
import static java.util.Objects.nonNull;
import static liquibase.ext.mongodb.statement.BsonUtils.orEmptyDocument;
import static liquibase.ext.mongodb.statement.BsonUtils.orEmptyList;

/**
* Inserts many documents via the database runCommand method
* For a list of supported options see the reference page:
* https://docs.mongodb.com/manual/reference/command/insert/
*/
@Getter
@EqualsAndHashCode(callSuper = true)
public class InsertManyStatement extends AbstractCollectionStatement
implements NoSqlExecuteStatement<MongoConnection> {
public class InsertManyStatement extends AbstractRunCommandStatement {

public static final String COMMAND_NAME = "insertMany";
public static final String RUN_COMMAND_NAME = "insert";

private final List<Document> documents;
private final Document options;
Expand All @@ -49,34 +50,22 @@ public InsertManyStatement(final String collectionName, final String documents,
}

public InsertManyStatement(final String collectionName, final List<Document> documents, final Document options) {
super(collectionName);
super(BsonUtils.toCommand(RUN_COMMAND_NAME, collectionName, combine(documents, options)));
this.documents = documents;
this.options = options;
}

@Override
public String getCommandName() {
return COMMAND_NAME;
}

@Override
public String toJs() {
return
"db." +
getCollectionName() +
"." +
getCommandName() +
"(" +
ofNullable(documents).map(List::toString).orElse(null) +
", " +
ofNullable(options).map(Document::toJson).orElse(null) +
");";
private static Document combine(final List<Document> documents, final Document options) {
final Document combined = new Document(BsonUtils.DOCUMENTS, documents);
if (nonNull(options)) {
combined.putAll(options);
}
return combined;
}

@Override
public void execute(final MongoConnection connection) {
final MongoCollection<Document> collection = connection.getDatabase().getCollection(collectionName);
collection.insertMany(documents);
public String getRunCommandName() {
return RUN_COMMAND_NAME;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import lombok.Getter;
import org.bson.Document;

import static java.util.Objects.nonNull;
import static java.util.Collections.singletonList;
import static liquibase.ext.mongodb.statement.BsonUtils.orEmptyDocument;

Expand All @@ -35,34 +34,13 @@
*/
@Getter
@EqualsAndHashCode(callSuper = true)
public class InsertOneStatement extends AbstractRunCommandStatement {

public static final String RUN_COMMAND_NAME = "insert";
public class InsertOneStatement extends InsertManyStatement {

public InsertOneStatement(final String collectionName, final String document, final String options) {
this(collectionName, orEmptyDocument(document), orEmptyDocument(options));
}

public InsertOneStatement(final String collectionName, final Document document, final Document options) {
super(BsonUtils.toCommand(RUN_COMMAND_NAME, collectionName, combine(document, options)));
}

private static Document combine(final Document document, final Document options) {
final Document combined = new Document(BsonUtils.DOCUMENTS, singletonList(document));
if (nonNull(options)) {
combined.putAll(options);
}
return combined;
}

/**
* Returns the RunCommand command name.
*
* @return the run command as this is not used and not required for a generic RunCommandStatement
* @see <a href="https://docs.mongodb.com/manual/reference/command/">Database Commands</a>
*/
@Override
public String getRunCommandName() {
return RUN_COMMAND_NAME;
super(collectionName, singletonList(document), options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,51 @@
* #L%
*/

import com.mongodb.MongoException;
import com.mongodb.client.MongoDatabase;
import liquibase.ext.AbstractMongoIntegrationTest;
import lombok.SneakyThrows;
import org.bson.Document;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static liquibase.ext.mongodb.TestUtils.formatDoubleQuoted;
import static liquibase.ext.mongodb.TestUtils.COLLECTION_NAME_1;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

class InsertManyStatementIT extends AbstractMongoIntegrationTest {

private String collectionName;

@BeforeEach
public void createCollectionName() {
collectionName = COLLECTION_NAME_1 + System.nanoTime();
}

@Test
void toStringTest() {
final InsertManyStatement statement = new InsertManyStatement(COLLECTION_NAME_1, Collections.emptyList(), new Document());

String expected = formatDoubleQuoted(
"db.runCommand({'insert': '%s', " +
"'documents': [{'key1': 'value1'}, {'key1': 'value2'}], " +
"'ordered': false});", collectionName);

final InsertManyStatement statement = new InsertManyStatement(
collectionName,
Arrays.asList(
new Document("key1", "value1"),
new Document("key1", "value2")),
new Document("ordered", false));
assertThat(statement.toJs())
.isEqualTo(statement.toString())
.isEqualTo("db.collectionName.insertMany([], {});");
.isEqualTo(expected);
}

@Test
Expand All @@ -50,9 +74,9 @@ void executeForList() {
.mapToObj(id -> Collections.singletonMap("id", (Object) id))
.map(Document::new)
.collect(Collectors.toList());
new InsertManyStatement(COLLECTION_NAME_1, testObjects, new Document()).execute(connection);
new InsertManyStatement(collectionName, testObjects, new Document()).execute(connection);

assertThat(database.getCollection(COLLECTION_NAME_1).find())
assertThat(database.getCollection(collectionName).find())
.hasSize(5);
}

Expand All @@ -64,9 +88,23 @@ void executeForString() {
.map(Document::new)
.map(Document::toJson)
.collect(Collectors.joining(",", "[", "]"));
new InsertManyStatement(COLLECTION_NAME_1, testObjects, "").execute(connection);
new InsertManyStatement(collectionName, testObjects, "").execute(connection);

assertThat(database.getCollection(COLLECTION_NAME_1).find())
assertThat(database.getCollection(collectionName).find())
.hasSize(5);
}

@Test
@SneakyThrows
void cannotInsertSameDocumentsTwice() {
final List<Document> documents = Arrays.asList(new Document("_id", "x"),new Document("_id", "y"));
final Document options = new Document("ordered", false);
final InsertManyStatement statement = new InsertManyStatement(collectionName, documents, options);
statement.execute(connection);

assertThatExceptionOfType(MongoException.class)
.isThrownBy(() -> statement.execute(connection))
.withMessageStartingWith("Command failed. The full response is")
.withMessageContaining("E11000 duplicate key error collection");
}
}

0 comments on commit dedda68

Please sign in to comment.