Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #90 Convert InsertMany to execute as a runCommand #92

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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");
}
}