org.springframework.data.relational.core.conversion.BatchedActions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-data-relational Show documentation
Show all versions of spring-data-relational Show documentation
Spring Data Relational support
/*
* Copyright 2022-2023 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.relational.core.conversion;
import static java.util.Collections.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
/**
* Collects actions of a certain type and allows to consume them in a batched fashion, i.e. "similar" actions get
* combined into a batched action variant.
*
* @param type of the singular action.
* @param type of the batched action.
* @param type of the container used for gathering singular actions.
* @author Jens Schauder
* @since 3.0
*/
class BatchedActions {
private static final Comparator> PATH_LENGTH_COMPARATOR = //
Comparator.comparing(PersistentPropertyPath::getLength);
private static final Comparator> REVERSE_PATH_LENGTH_COMPARATOR = //
PATH_LENGTH_COMPARATOR.reversed();
private final Map, C> actionMap = new HashMap<>();
private final Combiner combiner;
private final Comparator> sorting;
static BatchedActions> batchedDeletes() {
return new BatchedActions<>(DeleteCombiner.INSTANCE, REVERSE_PATH_LENGTH_COMPARATOR);
}
static BatchedActions>> batchedInserts() {
return new BatchedActions<>(InsertCombiner.INSTANCE, PATH_LENGTH_COMPARATOR);
}
private BatchedActions(Combiner combiner,
Comparator> sorting) {
this.combiner = combiner;
this.sorting = sorting;
}
/**
* Adds an action that might get combined with other actions into a batch.
*
* @param action the action to combine with other actions.
*/
void add(S action) {
combiner.merge(actionMap, action.getPropertyPath(), action);
}
void forEach(Consumer consumer) {
combiner.forEach( //
actionMap.entrySet().stream() //
.sorted(Map.Entry.comparingByKey(sorting)), //
consumer);
}
interface Combiner {
/**
* Merges an additional entry into the map of actions, which groups the actions by property path.
*
* @param actionMap the map of actions into which the new action is to be merged.
* @param propertyPath the property map under which to add the action.
* @param action the action to be merged.
*/
void merge(Map, C> actionMap,
PersistentPropertyPath propertyPath, S action);
/**
* Invokes the consumer for the actions in the sorted stream. Before passed to the consumer compatible actions will
* get combined into batched actions.
*
* @param sorted
* @param consumer
*/
void forEach(Stream, C>> sorted,
Consumer consumer);
}
enum DeleteCombiner implements Combiner, DbAction.BatchDelete> {
INSTANCE;
@Override
public void merge(Map, List> actionMap,
PersistentPropertyPath propertyPath, DbAction.Delete action) {
actionMap.merge( //
propertyPath, //
new ArrayList<>(singletonList(action)), //
(actions, defaultValue) -> {
actions.add(action);
return actions;
});
}
@Override
public void forEach(
Stream, List>> sorted,
Consumer consumer) {
sorted.forEach((entry) -> {
List actions = entry.getValue();
if (actions.size() > 1) {
singletonList(new DbAction.BatchDelete(actions)).forEach(consumer);
} else {
actions.forEach(consumer);
}
});
}
}
enum InsertCombiner
implements Combiner>, DbAction.BatchInsert> {
INSTANCE;
@Override
public void merge(
Map, Map>> actionMap,
PersistentPropertyPath propertyPath, DbAction.Insert action) {
actionMap.merge( //
propertyPath, //
new HashMap<>(singletonMap(action.getIdValueSource(), new ArrayList<>(singletonList(action)))), //
(map, mapDefaultValue) -> {
map.merge(action.getIdValueSource(), new ArrayList<>(singletonList(action)),
(actions, listDefaultValue) -> {
actions.add(action);
return actions;
});
return map;
});
}
@Override
public void forEach(
Stream, Map>>> sorted,
Consumer consumer) {
sorted.forEach((entry) -> entry.getValue() //
.forEach((idValueSource, inserts) -> consumer.accept(new DbAction.BatchInsert(inserts))));
}
}
}