BulkBuilderSupport.java
/*
* Copyright 2026-present the original author or authors.
*
* 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
*
* https://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 org.springframework.data.mongodb.core.bulk;
import java.util.List;
import org.springframework.data.mongodb.core.bulk.Bulk.BulkBuilder;
import org.springframework.data.mongodb.core.bulk.BulkOperation.RemoveFirst;
import org.springframework.data.mongodb.core.bulk.BulkOperation.UpdateFirst;
import org.springframework.data.mongodb.core.bulk.BulkOperationContext.TypedNamespace;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
/**
* Default implementation of {@link BulkBuilder} and {@link TypedBulkBuilder} that tracks the current collection
* (namespace) and builds a list of {@link BulkOperation bulk operations} for execution. Supports bulk writes across
* multiple collections as in MongoDB's bulk write model.
*
* @author Christoph Strobl
* @since 5.1
*/
abstract class BulkBuilderSupport implements Bulk.BulkSpec {
final List<BulkOperation> bulkOperations;
public BulkBuilderSupport(List<BulkOperation> bulkOperations) {
this.bulkOperations = bulkOperations;
}
abstract TypedNamespace getNamespace();
@Override
public Bulk.BulkSpec insert(Object object) {
bulkOperations.add(new BulkInsert(object, getNamespace()));
return this;
}
@Override
public Bulk.BulkSpec insertAll(Iterable<? extends Object> objects) {
objects.forEach(this::insert);
return this;
}
@Override
public Bulk.BulkSpec updateOne(Query filter, UpdateDefinition update) {
bulkOperations.add(new BulkUpdateFirst(filter, update, false, getNamespace()));
return this;
}
@Override
public Bulk.BulkSpec updateMulti(Query filter, UpdateDefinition update) {
bulkOperations.add(new BulkUpdate(filter, update, false, getNamespace()));
return this;
}
@Override
public Bulk.BulkSpec upsert(Query filter, UpdateDefinition update) {
bulkOperations.add(new BulkUpdate(filter, update, true, getNamespace()));
return this;
}
@Override
public Bulk.BulkSpec remove(Query filter) {
bulkOperations.add(new BulkRemove(filter, getNamespace()));
return this;
}
@Override
public Bulk.BulkSpec replaceOne(Query filter, Object replacement) {
bulkOperations.add(new BulkReplace(filter, replacement, true, getNamespace()));
return this;
}
@Override
public Bulk.BulkSpec replaceIfExists(Query filter, Object replacement) {
bulkOperations.add(new BulkReplace(filter, replacement, false, getNamespace()));
return this;
}
private static class ContextAware {
protected final BulkOperationContext context;
public ContextAware(TypedNamespace namespace) {
this(new DefaultBulkOperationContext(namespace));
}
public ContextAware(BulkOperationContext context) {
this.context = context;
}
public BulkOperationContext context() {
return context;
}
}
private static class DefaultBulkOperationContext implements BulkOperationContext {
TypedNamespace namespace;
public DefaultBulkOperationContext(TypedNamespace namespace) {
this.namespace = namespace;
}
@Override
public TypedNamespace namespace() {
return namespace;
}
}
static class BulkInsert extends ContextAware implements BulkOperation.Insert {
private final Object value;
public BulkInsert(Object value, TypedNamespace namespace) {
super(namespace);
this.value = value;
}
@Override
public Object value() {
return value;
}
}
static class BulkUpdate extends ContextAware implements BulkOperation.Update {
private final Query query;
private final UpdateDefinition update;
private final boolean upsert;
public BulkUpdate(Query query, UpdateDefinition update, boolean upsert, TypedNamespace namespace) {
super(namespace);
this.query = query;
this.update = update;
this.upsert = upsert;
}
@Override
public UpdateDefinition update() {
return update;
}
@Override
public Query query() {
return query;
}
@Override
public boolean upsert() {
return upsert;
}
}
static class BulkUpdateFirst extends BulkUpdate implements UpdateFirst {
public BulkUpdateFirst(Query query, UpdateDefinition update, boolean upsert, TypedNamespace namespace) {
super(query, update, upsert, namespace);
}
}
static class BulkRemove extends ContextAware implements BulkOperation.Remove {
private final Query query;
public BulkRemove(Query query, TypedNamespace namespace) {
super(namespace);
this.query = query;
}
@Override
public Query query() {
return query;
}
}
static class BulkRemoveFirst extends BulkRemove implements RemoveFirst {
public BulkRemoveFirst(Query query, TypedNamespace namespace) {
super(query, namespace);
}
}
static class BulkReplace extends ContextAware implements BulkOperation.Replace {
private final Query query;
private final Object replacement;
private final boolean upsert;
BulkReplace(Query query, Object replacement, boolean upsert, TypedNamespace namespace) {
super(namespace);
this.query = query;
this.replacement = replacement;
this.upsert = upsert;
}
@Override
public Query query() {
return query;
}
@Override
public Object replacement() {
return replacement;
}
@Override
public boolean upsert() {
return upsert;
}
}
}