From 0d968980646322e5c3513afda66f11299fbc1203 Mon Sep 17 00:00:00 2001
From: Roi Menashe <33356310+roimenashe@users.noreply.github.com>
Date: Sun, 9 May 2021 12:52:03 +0300
Subject: [PATCH 1/5] Remove deprecated CustomConversions class. (#212)
* instead use org.springframework.data.aerospike.convert.AerospikeCustomConversions
---
.../aerospike/convert/CustomConversions.java | 46 -------------------
1 file changed, 46 deletions(-)
delete mode 100644 src/main/java/org/springframework/data/aerospike/convert/CustomConversions.java
diff --git a/src/main/java/org/springframework/data/aerospike/convert/CustomConversions.java b/src/main/java/org/springframework/data/aerospike/convert/CustomConversions.java
deleted file mode 100644
index 3d1a5c594..000000000
--- a/src/main/java/org/springframework/data/aerospike/convert/CustomConversions.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2012-2020 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.aerospike.convert;
-
-import org.springframework.data.mapping.model.SimpleTypeHolder;
-
-import java.util.List;
-
-/**
- * Value object to capture custom conversion.
- *
- * Types that can be mapped directly onto JSON are considered simple ones, because they neither need deeper
- * inspection nor nested conversion.
- *
- * @author Michael Nitschinger
- * @author Oliver Gierke
- * @author Mark Paluch
- * @deprecated instead use {@link org.springframework.data.aerospike.convert.AerospikeCustomConversions}
- */
-@Deprecated
-public class CustomConversions extends AerospikeCustomConversions {
-
- /**
- * Instead use the other constructor.
- */
- @Deprecated
- public CustomConversions(final List> converters, SimpleTypeHolder simpleTypeHolder) {
- super(converters);
- }
-
-
-}
From b130e04d871c56f835f0a55b1585ccca75fd13d0 Mon Sep 17 00:00:00 2001
From: mrozk
Date: Tue, 18 May 2021 14:23:02 +0300
Subject: [PATCH 2/5] Add multientities batch to aerospike template (#162)
---
.../aerospike/core/AerospikeOperations.java | 4 +
.../aerospike/core/AerospikeTemplate.java | 56 ++++-
.../aerospike/core/BaseAerospikeTemplate.java | 38 ++++
.../data/aerospike/core/EntitiesKeys.java | 48 ++++
.../core/ReactiveAerospikeOperations.java | 4 +
.../core/ReactiveAerospikeTemplate.java | 37 +++-
.../aerospike/core/model/GroupedEntities.java | 66 ++++++
.../aerospike/core/model/GroupedKeys.java | 46 ++++
.../core/AbstractFindByEntitiesTest.java | 206 ++++++++++++++++++
.../AerospikeTemplateFindByEntitiesTests.java | 18 ++
.../core/model/GroupedEntitiesTest.java | 38 ++++
.../aerospike/core/model/GroupedKeysTest.java | 32 +++
...veAerospikeTemplateFindByEntitiesTest.java | 24 ++
13 files changed, 613 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/org/springframework/data/aerospike/core/EntitiesKeys.java
create mode 100644 src/main/java/org/springframework/data/aerospike/core/model/GroupedEntities.java
create mode 100644 src/main/java/org/springframework/data/aerospike/core/model/GroupedKeys.java
create mode 100644 src/test/java/org/springframework/data/aerospike/core/AbstractFindByEntitiesTest.java
create mode 100644 src/test/java/org/springframework/data/aerospike/core/AerospikeTemplateFindByEntitiesTests.java
create mode 100644 src/test/java/org/springframework/data/aerospike/core/model/GroupedEntitiesTest.java
create mode 100644 src/test/java/org/springframework/data/aerospike/core/model/GroupedKeysTest.java
create mode 100644 src/test/java/org/springframework/data/aerospike/core/reactive/ReactiveAerospikeTemplateFindByEntitiesTest.java
diff --git a/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java b/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java
index 9ed2ab60f..fd40422e4 100644
--- a/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java
+++ b/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java
@@ -22,6 +22,8 @@
import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;
import org.springframework.data.aerospike.IndexAlreadyExistsException;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
import org.springframework.data.aerospike.repository.query.Query;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.context.MappingContext;
@@ -109,6 +111,8 @@ public interface AerospikeOperations {
List findByIds(Iterable> ids, Class entityClass);
+ GroupedEntities findByIds(GroupedKeys groupedKeys);
+
T add(T objectToAddTo, Map values);
T add(T objectToAddTo, String binName, long value);
diff --git a/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java b/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java
index 96156b46b..2a68e9af8 100644
--- a/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java
+++ b/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java
@@ -15,17 +15,31 @@
*/
package org.springframework.data.aerospike.core;
+import com.aerospike.client.AerospikeException;
+import com.aerospike.client.Bin;
+import com.aerospike.client.IAerospikeClient;
+import com.aerospike.client.Info;
+import com.aerospike.client.Key;
+import com.aerospike.client.Operation;
import com.aerospike.client.Record;
-import com.aerospike.client.*;
+import com.aerospike.client.ResultCode;
+import com.aerospike.client.Value;
import com.aerospike.client.cluster.Node;
import com.aerospike.client.policy.RecordExistsAction;
import com.aerospike.client.policy.WritePolicy;
-import com.aerospike.client.query.*;
+import com.aerospike.client.query.Filter;
+import com.aerospike.client.query.IndexCollectionType;
+import com.aerospike.client.query.IndexType;
+import com.aerospike.client.query.KeyRecord;
+import com.aerospike.client.query.ResultSet;
+import com.aerospike.client.query.Statement;
import com.aerospike.client.task.IndexTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.aerospike.convert.AerospikeWriteData;
import org.springframework.data.aerospike.convert.MappingAerospikeConverter;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
import org.springframework.data.aerospike.mapping.AerospikeMappingContext;
import org.springframework.data.aerospike.mapping.AerospikePersistentEntity;
import org.springframework.data.aerospike.query.KeyRecordIterator;
@@ -39,7 +53,14 @@
import org.springframework.data.util.StreamUtils;
import org.springframework.util.Assert;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -334,6 +355,35 @@ private List findByIdsInternal(Collection> ids, Class entityClass) {
}
}
+
+ /**
+ * Executes a single batch request to get results for several entities.
+ *
+ * Aerospike provides functionality to get records from different sets in 1 batch
+ * request. The methods allows to put grouped keys by entity type as parameter and
+ * get result as spring data aerospike entities grouped by entity type.
+ *
+ * @param groupedKeys will never be {@literal null}.
+ * @return GroupedEntities grouped entities
+ */
+ @Override
+ public GroupedEntities findByIds(GroupedKeys groupedKeys) {
+ Assert.notNull(groupedKeys, "Grouped keys must not be null!");
+
+ if (groupedKeys.getEntitiesKeys().isEmpty()) {
+ return GroupedEntities.builder().build();
+ }
+
+ return findEntitiesByIdsInternal(groupedKeys);
+ }
+
+ private GroupedEntities findEntitiesByIdsInternal(GroupedKeys groupedKeys) {
+ EntitiesKeys entitiesKeys = EntitiesKeys.of(toEntitiesKeyMap(groupedKeys));
+ Record[] records = client.get(null, entitiesKeys.getKeys());
+
+ return toGroupedEntities(entitiesKeys, records);
+ }
+
@SuppressWarnings("unchecked")
@Override
public Iterable aggregate(Filter filter, Class entityClass,
diff --git a/src/main/java/org/springframework/data/aerospike/core/BaseAerospikeTemplate.java b/src/main/java/org/springframework/data/aerospike/core/BaseAerospikeTemplate.java
index 40c6473ec..e2b092499 100644
--- a/src/main/java/org/springframework/data/aerospike/core/BaseAerospikeTemplate.java
+++ b/src/main/java/org/springframework/data/aerospike/core/BaseAerospikeTemplate.java
@@ -34,6 +34,8 @@
import org.springframework.data.aerospike.convert.AerospikeTypeAliasAccessor;
import org.springframework.data.aerospike.convert.AerospikeWriteData;
import org.springframework.data.aerospike.convert.MappingAerospikeConverter;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
import org.springframework.data.aerospike.mapping.AerospikeMappingContext;
import org.springframework.data.aerospike.mapping.AerospikePersistentEntity;
import org.springframework.data.aerospike.mapping.AerospikePersistentProperty;
@@ -41,13 +43,20 @@
import org.springframework.data.aerospike.repository.query.Query;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.domain.Sort;
+import org.springframework.data.keyvalue.core.IterableConverter;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.util.Assert;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Base class for creation Aerospike templates
@@ -232,6 +241,35 @@ Key getKey(Object id, AerospikePersistentEntity> entity) {
return new Key(this.namespace, entity.getSetName(), userKey);
}
+ GroupedEntities toGroupedEntities(EntitiesKeys entitiesKeys, Record[] records) {
+ GroupedEntities.GroupedEntitiesBuilder builder = GroupedEntities.builder();
+
+ IntStream.range(0, entitiesKeys.getKeys().length)
+ .filter(index -> records[index] != null)
+ .mapToObj(index -> mapToEntity(entitiesKeys.getKeys()[index], entitiesKeys.getEntityClasses()[index], records[index]))
+ .filter(Objects::nonNull)
+ .forEach(entity -> builder.entity(getEntityClass(entity), entity));
+
+ return builder.build();
+ }
+
+ Map, List> toEntitiesKeyMap(GroupedKeys groupedKeys) {
+ return groupedKeys.getEntitiesKeys().entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, entry -> toKeysList(entry.getKey(), entry.getValue())));
+ }
+
+ private List toKeysList(Class entityClass, Collection> ids) {
+ Assert.notNull(entityClass, "Entity class must not be null!");
+ Assert.notNull(ids, "List of ids must not be null!");
+
+ AerospikePersistentEntity> entity = mappingContext.getRequiredPersistentEntity(entityClass);
+ List> idsList = IterableConverter.toList(ids);
+
+ return idsList.stream()
+ .map(id -> getKey(id, entity))
+ .collect(Collectors.toList());
+ }
+
@SuppressWarnings("unchecked")
private S convertIfNecessary(Object source, Class type) {
return type.isAssignableFrom(source.getClass()) ? (S) source : converter.getConversionService().convert(source, type);
diff --git a/src/main/java/org/springframework/data/aerospike/core/EntitiesKeys.java b/src/main/java/org/springframework/data/aerospike/core/EntitiesKeys.java
new file mode 100644
index 000000000..cf2206c7b
--- /dev/null
+++ b/src/main/java/org/springframework/data/aerospike/core/EntitiesKeys.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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.aerospike.core;
+
+import com.aerospike.client.Key;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Value;
+
+import java.util.List;
+import java.util.Map;
+
+@Value
+@Builder
+@Getter
+class EntitiesKeys {
+
+ Class>[] entityClasses;
+ Key[] keys;
+
+ public static EntitiesKeys of(Map, List> entitiesKeys) {
+ Class>[] entityClasses = entitiesKeys.entrySet().stream()
+ .flatMap(entry -> entry.getValue().stream().map(item -> entry.getKey()))
+ .toArray(Class>[]::new);
+
+ Key[] keys = entitiesKeys.entrySet().stream()
+ .flatMap(entry -> entry.getValue().stream())
+ .toArray(Key[]::new);
+
+ return EntitiesKeys.builder()
+ .entityClasses(entityClasses)
+ .keys(keys)
+ .build();
+ }
+}
diff --git a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java
index c2cb64f2b..50a57da73 100644
--- a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java
+++ b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java
@@ -18,6 +18,8 @@
import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;
import com.aerospike.client.reactor.IAerospikeReactorClient;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
import org.springframework.data.aerospike.repository.query.Query;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.context.MappingContext;
@@ -61,6 +63,8 @@ public interface ReactiveAerospikeOperations {
Flux findByIds(Iterable> ids, Class entityClass);
+ Mono findByIds(GroupedKeys groupedKeys);
+
Flux find(Query query, Class entityClass);
Flux findInRange(long offset, long limit, Sort sort, Class entityClass);
diff --git a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java
index c85f8ce1c..4f5f23e2e 100644
--- a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java
+++ b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java
@@ -15,8 +15,12 @@
*/
package org.springframework.data.aerospike.core;
+import com.aerospike.client.AerospikeException;
+import com.aerospike.client.Bin;
+import com.aerospike.client.Key;
+import com.aerospike.client.Operation;
import com.aerospike.client.Record;
-import com.aerospike.client.*;
+import com.aerospike.client.Value;
import com.aerospike.client.policy.RecordExistsAction;
import com.aerospike.client.policy.WritePolicy;
import com.aerospike.client.query.Filter;
@@ -28,6 +32,8 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.aerospike.convert.AerospikeWriteData;
import org.springframework.data.aerospike.convert.MappingAerospikeConverter;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
import org.springframework.data.aerospike.mapping.AerospikeMappingContext;
import org.springframework.data.aerospike.mapping.AerospikePersistentEntity;
import org.springframework.data.aerospike.query.Qualifier;
@@ -257,6 +263,35 @@ public Flux findByIds(Iterable> ids, Class entityClass) {
.map(keyRecord -> mapToEntity(keyRecord.key, entityClass, keyRecord.record));
}
+ /**
+ * Executes a single batch request to get results for several entities.
+ *
+ * Aerospike provides functionality to get records from different sets in 1 batch
+ * request. The methods allows to put grouped keys by entity type as parameter and
+ * get result as spring data aerospike entities grouped by entity type.
+ *
+ * @param groupedKeys
+ * @return Mono
+ */
+ @Override
+ public Mono findByIds(GroupedKeys groupedKeys) {
+ Assert.notNull(groupedKeys, "Grouped keys must not be null!");
+
+ if (groupedKeys.getEntitiesKeys().isEmpty()) {
+ return Mono.just(GroupedEntities.builder().build());
+ }
+
+ return findEntitiesByIdsInternal(groupedKeys);
+ }
+
+ private Mono findEntitiesByIdsInternal(GroupedKeys groupedKeys) {
+ EntitiesKeys entitiesKeys = EntitiesKeys.of(toEntitiesKeyMap(groupedKeys));
+
+ return reactorClient.get(null, entitiesKeys.getKeys())
+ .map(item -> toGroupedEntities(entitiesKeys, item.records))
+ .onErrorMap(this::translateError);
+ }
+
@Override
public Flux find(Query query, Class entityClass) {
Assert.notNull(query, "Query must not be null!");
diff --git a/src/main/java/org/springframework/data/aerospike/core/model/GroupedEntities.java b/src/main/java/org/springframework/data/aerospike/core/model/GroupedEntities.java
new file mode 100644
index 000000000..49de590e0
--- /dev/null
+++ b/src/main/java/org/springframework/data/aerospike/core/model/GroupedEntities.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 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.aerospike.core.model;
+
+
+import lombok.Builder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+@Builder
+public class GroupedEntities {
+
+ private final Map, List>> entitiesResults;
+
+ @SuppressWarnings("unchecked")
+ public List getEntitiesByClass(Class entityClass) {
+ return (List) entitiesResults.getOrDefault(entityClass, emptyList());
+ }
+
+ public boolean containsEntities() {
+ return entitiesResults.entrySet().stream().anyMatch(entry -> !entry.getValue().isEmpty());
+ }
+
+ public static class GroupedEntitiesBuilder {
+
+ private Map, List>> entitiesResults = new HashMap<>();
+
+ @SuppressWarnings("unchecked")
+ public GroupedEntities.GroupedEntitiesBuilder entity(Class key, T entity) {
+ entitiesResults.compute(key, (k,v) -> {
+ if (v == null) {
+ return new ArrayList<>(singletonList(entity));
+ }
+
+ ((List)v).add(entity);
+ return v;
+ });
+
+ return this;
+ }
+
+ private GroupedEntities.GroupedEntitiesBuilder entitiesResults(Map, List>> keysMap) {
+ this.entitiesResults = keysMap;
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/springframework/data/aerospike/core/model/GroupedKeys.java b/src/main/java/org/springframework/data/aerospike/core/model/GroupedKeys.java
new file mode 100644
index 000000000..b67e3575d
--- /dev/null
+++ b/src/main/java/org/springframework/data/aerospike/core/model/GroupedKeys.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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.aerospike.core.model;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+@Builder
+public class GroupedKeys {
+
+ private final Map, Collection>> entitiesKeys;
+
+ public static class GroupedKeysBuilder {
+
+ private Map, Collection>> entitiesKeys = new HashMap<>();
+
+ public GroupedKeys.GroupedKeysBuilder entityKeys(Class key, Collection value) {
+ entitiesKeys.put(key, value);
+
+ return this;
+ }
+
+ private GroupedKeys.GroupedKeysBuilder entitiesKeys(Map, Collection>> keys) {
+ this.entitiesKeys = keys;
+ return this;
+ }
+ }
+}
diff --git a/src/test/java/org/springframework/data/aerospike/core/AbstractFindByEntitiesTest.java b/src/test/java/org/springframework/data/aerospike/core/AbstractFindByEntitiesTest.java
new file mode 100644
index 000000000..8587afd91
--- /dev/null
+++ b/src/test/java/org/springframework/data/aerospike/core/AbstractFindByEntitiesTest.java
@@ -0,0 +1,206 @@
+package org.springframework.data.aerospike.core;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.core.convert.ConverterNotFoundException;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
+import org.springframework.data.aerospike.sample.Customer;
+import org.springframework.data.aerospike.sample.Person;
+import org.springframework.data.mapping.MappingException;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.data.aerospike.utility.AerospikeUniqueId.nextId;
+
+public interface AbstractFindByEntitiesTest {
+
+ @Test
+ default void shouldFindAllRequestedEntities() {
+ List persons = generatePersons(5);
+ List customers = generateCustomers(3);
+
+ GroupedKeys groupedKeys = getGroupedKeys(persons, customers);
+ GroupedEntities byIds = findByIds(groupedKeys);
+
+ assertThat(byIds.getEntitiesByClass(Person.class)).containsExactlyInAnyOrderElementsOf(persons);
+ assertThat(byIds.getEntitiesByClass(Customer.class)).containsExactlyInAnyOrderElementsOf(customers);
+ }
+
+ @Test
+ default void shouldReturnAnEmptyResultIfKeysWhereSetToWrongEntities() {
+ List persons = generatePersons(5);
+ List customers = generateCustomers(3);
+
+ Set requestedPersonsIds = persons.stream()
+ .map(Person::getId)
+ .collect(Collectors.toSet());
+ Set requestedCustomerIds = customers.stream().map(Customer::getId)
+ .collect(Collectors.toSet());
+
+ GroupedKeys groupedKeys = GroupedKeys.builder()
+ .entityKeys(Person.class, requestedCustomerIds)
+ .entityKeys(Customer.class, requestedPersonsIds)
+ .build();
+
+ GroupedEntities byIds = findByIds(groupedKeys);
+
+ assertThat(byIds.containsEntities()).isFalse();
+ }
+
+ @Test
+ default void shouldFindSomeOfIdsOfRequestedEntities() {
+ List persons = generatePersons(2);
+ List customers = generateCustomers(3);
+
+ GroupedKeys requestMapWithRandomExtraIds = getGroupedEntitiesKeysWithRandomExtraIds(persons, customers);
+ GroupedEntities results = findByIds(requestMapWithRandomExtraIds);
+
+ assertThat(results.getEntitiesByClass(Person.class)).containsExactlyInAnyOrderElementsOf(persons);
+ assertThat(results.getEntitiesByClass(Customer.class)).containsExactlyInAnyOrderElementsOf(customers);
+ }
+
+ @Test
+ default void shouldFindResultsOfOneOfRequestedEntity() {
+ List persons = generatePersons(3);
+
+ GroupedKeys groupedKeysWithRandomExtraIds = getGroupedEntitiesKeysWithRandomExtraIds(persons, emptyList());
+ GroupedEntities results = findByIds(groupedKeysWithRandomExtraIds);
+
+ assertThat(results.getEntitiesByClass(Person.class)).containsExactlyInAnyOrderElementsOf(persons);
+ assertThat(results.getEntitiesByClass(Customer.class)).containsExactlyInAnyOrderElementsOf(emptyList());
+ }
+
+ @Test
+ default void shouldFindForOneEntityIfAnotherContainsEmptyRequestList() {
+ List persons = generatePersons(3);
+
+ GroupedKeys groupedKeys = getGroupedKeys(persons, emptyList());
+ GroupedEntities batchGroupedEntities = findByIds(groupedKeys);
+
+ assertThat(batchGroupedEntities.getEntitiesByClass(Person.class)).containsExactlyInAnyOrderElementsOf(persons);
+ assertThat(batchGroupedEntities.getEntitiesByClass(Customer.class)).containsExactlyInAnyOrderElementsOf(emptyList());
+ }
+
+ @Test
+ default void shouldReturnMapWithEmptyResultsOnEmptyRequest() {
+ GroupedKeys groupedKeys = GroupedKeys.builder()
+ .entityKeys(Person.class, emptyList())
+ .entityKeys(Customer.class, emptyList())
+ .build();
+
+
+ GroupedEntities batchGroupedEntities = findByIds(groupedKeys);
+
+ assertThat(batchGroupedEntities.getEntitiesByClass(Person.class))
+ .containsExactlyInAnyOrderElementsOf(emptyList());
+ assertThat(batchGroupedEntities.getEntitiesByClass(Customer.class))
+ .containsExactlyInAnyOrderElementsOf(emptyList());
+ }
+
+ @Test
+ default void shouldReturnMapWithEmptyResultsIfNoEntitiesWhereFound() {
+ GroupedKeys groupedKeys = GroupedKeys.builder()
+ .entityKeys(Person.class, singletonList(nextId()))
+ .entityKeys(Customer.class, singletonList(nextId()))
+ .build();
+
+ GroupedEntities batchGroupedEntities = findByIds(groupedKeys);
+
+ assertThat(batchGroupedEntities.getEntitiesByClass(Person.class))
+ .containsExactlyInAnyOrderElementsOf(emptyList());
+ assertThat(batchGroupedEntities.getEntitiesByClass(Customer.class))
+ .containsExactlyInAnyOrderElementsOf(emptyList());
+ }
+
+ @Test
+ default void shouldThrowMappingExceptionOnNonAerospikeEntityClass() {
+ List persons = generatePersons(2);
+ Set personIds = persons.stream()
+ .map(Person::getId)
+ .collect(Collectors.toSet());
+
+ GroupedKeys groupedKeys = GroupedKeys.builder()
+ .entityKeys(Person.class, personIds)
+ .entityKeys(String.class, singletonList(1L))
+ .build();
+
+ assertThatThrownBy(() -> findByIds(groupedKeys))
+ .isInstanceOf(MappingException.class)
+ .hasMessage("Couldn't find PersistentEntity for type class java.lang.String!");
+ }
+
+ @Test
+ default void shouldReturnAnEmptyResultOnEmptyRequestMap() {
+ GroupedKeys groupedKeys = GroupedKeys.builder().build();
+ GroupedEntities byIds = findByIds(groupedKeys);
+ assertThat(byIds.getEntitiesByClass(Person.class)).isEmpty();
+ }
+
+ @Test
+ default void shouldThrowConverterNotFoundExceptionOnClassWithoutConverter() {
+ GroupedKeys groupedKeys = GroupedKeys.builder()
+ .entityKeys(Person.class, singletonList(Person.builder().id("id").build()))
+ .build();
+
+ assertThatThrownBy(() -> findByIds(groupedKeys))
+ .isInstanceOf(ConverterNotFoundException.class)
+ .hasMessageContaining("No converter found capable of converting from type");
+ }
+
+ default GroupedKeys getGroupedKeys(Collection persons, Collection customers) {
+ Set requestedPersonsIds = persons.stream()
+ .map(Person::getId)
+ .collect(Collectors.toSet());
+ Set requestedCustomerIds = customers.stream().map(Customer::getId)
+ .collect(Collectors.toSet());
+
+ return GroupedKeys.builder()
+ .entityKeys(Person.class, requestedPersonsIds)
+ .entityKeys(Customer.class, requestedCustomerIds)
+ .build();
+ }
+
+ default GroupedKeys getGroupedEntitiesKeysWithRandomExtraIds(Collection persons, Collection customers) {
+ Set requestedPersonsIds = Stream.concat(persons.stream().map(Person::getId), Stream.of(nextId(), nextId()))
+ .collect(Collectors.toSet());
+ Set requestedCustomerIds = Stream.concat(customers.stream().map(Customer::getId), Stream.of(nextId(), nextId()))
+ .collect(Collectors.toSet());
+
+ return GroupedKeys.builder()
+ .entityKeys(Person.class, requestedPersonsIds)
+ .entityKeys(Customer.class, requestedCustomerIds)
+ .build();
+ }
+
+ default List generateCustomers(int count) {
+ return IntStream.range(0, count)
+ .mapToObj(i -> Customer.builder().id(nextId())
+ .firstname("firstName" + i)
+ .lastname("Smith")
+ .build())
+ .peek(this::save)
+ .collect(Collectors.toList());
+ }
+
+ default List generatePersons(int count) {
+ return IntStream.range(0, count)
+ .mapToObj(i -> Person.builder().id(nextId())
+ .firstName("firstName" + i)
+ .emailAddress("gmail.com")
+ .build())
+ .peek(this::save)
+ .collect(Collectors.toList());
+ }
+
+ void save(T obj);
+ GroupedEntities findByIds(GroupedKeys groupedKeys);
+}
diff --git a/src/test/java/org/springframework/data/aerospike/core/AerospikeTemplateFindByEntitiesTests.java b/src/test/java/org/springframework/data/aerospike/core/AerospikeTemplateFindByEntitiesTests.java
new file mode 100644
index 000000000..04e79f681
--- /dev/null
+++ b/src/test/java/org/springframework/data/aerospike/core/AerospikeTemplateFindByEntitiesTests.java
@@ -0,0 +1,18 @@
+package org.springframework.data.aerospike.core;
+
+import org.springframework.data.aerospike.BaseBlockingIntegrationTests;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
+
+public class AerospikeTemplateFindByEntitiesTests extends BaseBlockingIntegrationTests implements AbstractFindByEntitiesTest {
+
+ @Override
+ public void save(T obj) {
+ template.save(obj);
+ }
+
+ @Override
+ public GroupedEntities findByIds(GroupedKeys groupedKeys) {
+ return template.findByIds(groupedKeys);
+ }
+}
diff --git a/src/test/java/org/springframework/data/aerospike/core/model/GroupedEntitiesTest.java b/src/test/java/org/springframework/data/aerospike/core/model/GroupedEntitiesTest.java
new file mode 100644
index 000000000..986363d0e
--- /dev/null
+++ b/src/test/java/org/springframework/data/aerospike/core/model/GroupedEntitiesTest.java
@@ -0,0 +1,38 @@
+package org.springframework.data.aerospike.core.model;
+
+
+import org.junit.Test;
+import org.springframework.data.aerospike.sample.Customer;
+import org.springframework.data.aerospike.sample.Person;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class GroupedEntitiesTest {
+
+ private static final GroupedEntities TEST_GROUPED_ENTITIES = GroupedEntities.builder()
+ .entity(Person.class, Person.builder().id("22").build())
+ .entity(Customer.class, Customer.builder().id("33").build())
+ .build();
+ @Test
+ public void shouldGetEntitiesByClass() {
+ Person expectedResult = Person.builder().id("22").build();
+ assertThat(TEST_GROUPED_ENTITIES.getEntitiesByClass(Person.class))
+ .containsExactlyInAnyOrder(expectedResult);
+ }
+
+ @Test
+ public void shouldReturnAnEmptyResultIfGroupedEntitiesDoesNotContainResult() {
+ assertThat(TEST_GROUPED_ENTITIES.getEntitiesByClass(String.class)).isEmpty();
+ }
+
+ @Test
+ public void shouldContainEntities() {
+ assertThat(TEST_GROUPED_ENTITIES.containsEntities()).isTrue();
+ }
+
+ @Test
+ public void shouldNotContainEntities() {
+ GroupedEntities groupedEntities = GroupedEntities.builder().build();
+ assertThat(groupedEntities.containsEntities()).isFalse();
+ }
+}
diff --git a/src/test/java/org/springframework/data/aerospike/core/model/GroupedKeysTest.java b/src/test/java/org/springframework/data/aerospike/core/model/GroupedKeysTest.java
new file mode 100644
index 000000000..4ca51f9a6
--- /dev/null
+++ b/src/test/java/org/springframework/data/aerospike/core/model/GroupedKeysTest.java
@@ -0,0 +1,32 @@
+package org.springframework.data.aerospike.core.model;
+
+
+import org.junit.Test;
+import org.springframework.data.aerospike.sample.Person;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class GroupedKeysTest {
+
+ @Test
+ public void shouldGetEntitiesKeys() {
+ Set keys = new HashSet<>();
+ keys.add("p22");
+
+ GroupedKeys groupedKeys = GroupedKeys.builder()
+ .entityKeys(Person.class, keys)
+ .build();
+
+ Map, Collection>> expectedResult =
+ new HashMap<>();
+ expectedResult.put(Person.class, keys);
+
+ assertThat(groupedKeys.getEntitiesKeys()).containsAllEntriesOf(expectedResult);
+ }
+}
diff --git a/src/test/java/org/springframework/data/aerospike/core/reactive/ReactiveAerospikeTemplateFindByEntitiesTest.java b/src/test/java/org/springframework/data/aerospike/core/reactive/ReactiveAerospikeTemplateFindByEntitiesTest.java
new file mode 100644
index 000000000..b0bd48fb1
--- /dev/null
+++ b/src/test/java/org/springframework/data/aerospike/core/reactive/ReactiveAerospikeTemplateFindByEntitiesTest.java
@@ -0,0 +1,24 @@
+package org.springframework.data.aerospike.core.reactive;
+
+import org.springframework.data.aerospike.BaseReactiveIntegrationTests;
+import org.springframework.data.aerospike.core.AbstractFindByEntitiesTest;
+import org.springframework.data.aerospike.core.model.GroupedEntities;
+import org.springframework.data.aerospike.core.model.GroupedKeys;
+import reactor.core.scheduler.Schedulers;
+
+public class ReactiveAerospikeTemplateFindByEntitiesTest extends BaseReactiveIntegrationTests implements AbstractFindByEntitiesTest {
+
+ @Override
+ public void save(T obj) {
+ reactiveTemplate.save(obj)
+ .subscribeOn(Schedulers.parallel())
+ .block();
+ }
+
+ @Override
+ public GroupedEntities findByIds(GroupedKeys groupedKeys) {
+ return reactiveTemplate.findByIds(groupedKeys)
+ .subscribeOn(Schedulers.parallel())
+ .block();
+ }
+}
From 7ba21f50365947ca48f9f5eba134fdb391ca3045 Mon Sep 17 00:00:00 2001
From: Roi Menashe <33356310+roimenashe@users.noreply.github.com>
Date: Tue, 18 May 2021 14:47:12 +0300
Subject: [PATCH 3/5] Upgrade Aerospike clients dependencies + remove
deprecations. (#221)
1. Remove deprecated usages:
a. ScanPolicy: scanPercent and failOnClusterChange properties.
b. Policy: priority property.
2. Upgrade both reactive and non-reactive Aerospike java clients.
---
pom.xml | 4 ++--
.../aerospike/config/ReadPolicyFactoryBean.java | 10 ----------
.../aerospike/config/ScanPolicyFactoryBean.java | 17 -----------------
3 files changed, 2 insertions(+), 29 deletions(-)
diff --git a/pom.xml b/pom.xml
index c5ae6cb4e..ecb973319 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,8 +21,8 @@
1.8
- 5.0.5
- 5.0.3
+ 5.1.2
+ 5.0.7
2.4.6
2.4.6
diff --git a/src/main/java/org/springframework/data/aerospike/config/ReadPolicyFactoryBean.java b/src/main/java/org/springframework/data/aerospike/config/ReadPolicyFactoryBean.java
index ef587de10..3836ed1d9 100644
--- a/src/main/java/org/springframework/data/aerospike/config/ReadPolicyFactoryBean.java
+++ b/src/main/java/org/springframework/data/aerospike/config/ReadPolicyFactoryBean.java
@@ -18,7 +18,6 @@
import org.springframework.beans.factory.FactoryBean;
import com.aerospike.client.policy.Policy;
-import com.aerospike.client.policy.Priority;
/**
* A {@link FactoryBean} implementation that exposes the setters necessary to configure a read policy via XML.
@@ -73,15 +72,6 @@ public void setSleepBetweenRetries(int sleepBetweenRetries){
this.policy.sleepBetweenRetries = sleepBetweenRetries;
}
- /**
- * Configures the priority of request relative to other transactions.
- * Currently, only used for scans.
- * @param priority The priority configuration value.
- */
- public void setPriority(Priority priority){
- this.policy.priority = priority;
- }
-
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
diff --git a/src/main/java/org/springframework/data/aerospike/config/ScanPolicyFactoryBean.java b/src/main/java/org/springframework/data/aerospike/config/ScanPolicyFactoryBean.java
index 033645701..97a8621c7 100644
--- a/src/main/java/org/springframework/data/aerospike/config/ScanPolicyFactoryBean.java
+++ b/src/main/java/org/springframework/data/aerospike/config/ScanPolicyFactoryBean.java
@@ -43,14 +43,6 @@ public void setConcurrentNodes(boolean concurrentNodes){
this.policy.concurrentNodes = concurrentNodes;
}
- /**
- * Configures termination of scan if cluster in fluctuating state.
- * @param failOnClusterChange The failOnClusterChange configuration value.
- */
- public void setFailOnClusterChange(boolean failOnClusterChange){
- this.policy.failOnClusterChange = failOnClusterChange;
- }
-
/**
* Indicates if bin data is retrieved. If false, only record digests are retrieved.
* @param includeBinData The includeBinData configuration value.
@@ -72,15 +64,6 @@ public void setIncludeBinData(boolean includeBinData){
public void setMaxConcurrentNodes(int maxConcurrentNodes){
this.policy.maxConcurrentNodes = maxConcurrentNodes;
}
-
- /**
- * Configure the percent of data to scan. Valid integer range is 1 to 100.
- * Default is 100.
- * @param scanPercent The scanPercent configuration value.
- */
- public void setScanPercent(int scanPercent){
- this.policy.scanPercent = scanPercent;
- }
/*
* (non-Javadoc)
From 3a2ad37b8860d5ec64567acc0bae324607ec6bb0 Mon Sep 17 00:00:00 2001
From: Roi Menashe <33356310+roimenashe@users.noreply.github.com>
Date: Wed, 19 May 2021 11:37:53 +0300
Subject: [PATCH 4/5] Bump dependencies versions + support new operation
deleteAllById() (#232)
* Bump dependencies versions:
spring-data-parent from 2.4.6 to 2.5.1.
spring-data-commons from 2.4.6 to 2.5.1.
spring-data-keyvalue from 2.4.6 to 2.5.1.
spring-boot-starter-test from 2.4.4 to 2.4.5.
embedded-aerospike from 2.0.3 to 2.0.8.
awaitility from 4.0.3 to 4.1.0.
blockhound from 1.0.4.RELEASE to 1.0.6.RELEASE.
lombok from 1.18.18 to 1.18.20.
* Support deleteAllById() new operation both in the reactive repository and in the non-reactive repository.
---
pom.xml | 18 +++++++++---------
.../support/SimpleAerospikeRepository.java | 6 ++++++
.../SimpleReactiveAerospikeRepository.java | 8 ++++++++
...eAerospikeRepositoryDeleteRelatedTests.java | 8 ++++++++
.../support/SimpleAerospikeRepositoryTest.java | 12 ++++++++++++
5 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/pom.xml b/pom.xml
index ecb973319..ebce2a910 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
org.springframework.data.build
spring-data-parent
- 2.4.6
+ 2.5.1
@@ -24,17 +24,17 @@
5.1.2
5.0.7
- 2.4.6
- 2.4.6
+ 2.5.1
+ 2.5.1
DATAAERO
UTF-8
- 2.4.4
+ 2.4.5
3.0.2
- 2.0.3
- 4.0.3
- 1.0.4.RELEASE
- 1.18.18
+ 2.0.8
+ 4.1.0
+ 1.0.6.RELEASE
+ 1.18.20
@@ -311,7 +311,7 @@
org.apache.maven.plugins
maven-gpg-plugin
- 1.6
+ 3.0.1
sign-artifacts
diff --git a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java
index 41043df13..296c38ab1 100644
--- a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java
+++ b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java
@@ -71,6 +71,12 @@ public void delete(T entity) {
operations.delete(entity);
}
+ @Override
+ public void deleteAllById(Iterable extends ID> iterable) {
+ Assert.notNull(iterable, "The given Iterable must not be null!");
+ iterable.forEach(this::deleteById);
+ }
+
@Override
public Iterable findAll(Sort sort) {
return operations.findAll(sort, entityInformation.getJavaType());
diff --git a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java
index 3c67b8104..01659559a 100644
--- a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java
+++ b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java
@@ -118,6 +118,14 @@ public Mono delete(T entity) {
return operations.delete(entity).then();
}
+ @Override
+ public Mono deleteAllById(Iterable extends ID> iterable) {
+ Assert.notNull(iterable, "The given Iterable must not be null!");
+ iterable.forEach(id ->
+ Assert.notNull(id, "The given Iterable of entities must not contain null!"));
+ return Flux.fromIterable(iterable).flatMap(this::deleteById).then();
+ }
+
@Override
public Mono deleteAll(Iterable extends T> entities) {
Assert.notNull(entities, "The given Iterable of entities must not be null!");
diff --git a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java
index fa9d3aeeb..706035268 100644
--- a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java
+++ b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java
@@ -145,4 +145,12 @@ public void deleteAllPublisher_ShouldSkipNonexistent() {
StepVerifier.create(customerRepo.findById(customer1.getId())).expectNextCount(0).verifyComplete();
StepVerifier.create(customerRepo.findById(customer2.getId())).expectNextCount(0).verifyComplete();
}
+
+ @Test
+ public void deleteAllById_ShouldDelete() {
+ customerRepo.deleteAllById(asList(customer1.getId(), customer2.getId())).subscribeOn(Schedulers.parallel()).block();
+
+ StepVerifier.create(customerRepo.findById(customer1.getId())).expectNextCount(0).verifyComplete();
+ StepVerifier.create(customerRepo.findById(customer2.getId())).expectNextCount(0).verifyComplete();
+ }
}
\ No newline at end of file
diff --git a/src/test/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepositoryTest.java b/src/test/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepositoryTest.java
index b28034bd0..f9ffbc477 100644
--- a/src/test/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepositoryTest.java
+++ b/src/test/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepositoryTest.java
@@ -164,6 +164,18 @@ public void deleteID() {
verify(operations).delete("one", Person.class);
}
+ @Test
+ public void deleteAllById() {
+ List personIds = testPersons.stream()
+ .map(Person::getId)
+ .collect(toList());
+ aerospikeRepository.deleteAllById(personIds);
+
+ verify(operations).delete("one", Person.class);
+ verify(operations).delete("two", Person.class);
+ verify(operations).delete("three", Person.class);
+ }
+
@Test
public void deleteIterableOfQExtendsT() {
aerospikeRepository.deleteAll(testPersons);
From 528be068e011b269c47166352f3b3e0b2d2d4f8a Mon Sep 17 00:00:00 2001
From: Roi Menashe <33356310+roimenashe@users.noreply.github.com>
Date: Wed, 19 May 2021 12:18:39 +0300
Subject: [PATCH 5/5] 1. Prepare for 3.0.0 release. (#234)
1. Update compatibility table (README.md).
2. Set Spring Data Aerospike version to 3.0.0.
---
README.md | 18 ++++++++++--------
pom.xml | 2 +-
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index f584512ae..0c6e21512 100644
--- a/README.md
+++ b/README.md
@@ -22,14 +22,16 @@ The Spring Data Aerospike project aims to provide a familiar and consistent Spri
3. [Basic error handling in spring-data-aerospike](https://medium.com/aerospike-developer-blog/basic-error-handling-in-spring-data-aerospike-5edd580d77d9?source=friends_link&sk=cff71ea1539b36e5a89b2c3411b58a06)
4. [How to create secondary index in Spring Data Aerospike](https://medium.com/aerospike-developer-blog/how-to-create-secondary-index-in-spring-data-aerospike-e19d7e343d7c?source=friends_link&sk=413619a568f9aac51ed2f2611ee70aba)
-## Spring Boot compatibility
+## Spring Data Aerospike compatibility
-|`spring-data-aerospike` Version | Spring Boot Version
-| :----------- | :----: |
-|2.4.2.RELEASE | 2.3.x
-|2.3.5.RELEASE | 2.2.x
-|2.1.1.RELEASE | 2.1.x, 2.0.x
-|1.2.1.RELEASE | 1.5.x
+|`spring-data-aerospike` Version | Spring Boot Version | Aerospike Client | Aerospike Reactor Client
+| :----------- | :----: | :----------- | :-----------
+|3.0.0 | 2.5.X | 5.1.x | 5.0.x
+|2.5.0 | 2.5.X | 4.4.x | 4.4.x
+|2.4.2.RELEASE | 2.3.x | 4.4.x | 4.4.x
+|2.3.5.RELEASE | 2.2.x | 4.4.x | 4.4.x
+|2.1.1.RELEASE | 2.1.x, 2.0.x | 4.4.x | 3.2.x
+|1.2.1.RELEASE | 1.5.x | 4.1.x |
## Quick Start
@@ -41,7 +43,7 @@ Add the Maven dependency:
com.aerospike
spring-data-aerospike
- 2.4.2.RELEASE
+ 3.0.0
```
diff --git a/pom.xml b/pom.xml
index ebce2a910..6d7ccd3dc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.aerospike
spring-data-aerospike
- 2.4.2.RELEASE
+ 3.0.0
Spring Data Aerospike
Aerospike Inc.