Skip to content

Commit 59ef714

Browse files
authored
[DE-842] fixed tests of entities with non-string ids (#316)
* fixed tests of entities with non-string ids * fixed mapping of entities with non-string ids in repository methods * fixed mapping of entities with non-string ids in template methods
1 parent 003c911 commit 59ef714

32 files changed

+621
-206
lines changed

src/main/java/com/arangodb/springframework/core/ArangoOperations.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,35 @@ <T> MultiDocumentEntity<DocumentDeleteEntity<T>> deleteAll(
145145
*/
146146
MultiDocumentEntity<DocumentDeleteEntity<?>> deleteAll(Iterable<?> values, Class<?> entityClass) throws DataAccessException;
147147

148+
/**
149+
* Deletes multiple documents with the given IDs from a collection.
150+
*
151+
* @param ids
152+
* The keys of the documents
153+
* @param entityClass
154+
* The entity class which represents the collection
155+
* @param options
156+
* Additional options, can be null
157+
* @return information about the documents
158+
* @throws DataAccessException
159+
*/
160+
<T> MultiDocumentEntity<DocumentDeleteEntity<T>> deleteAllById(
161+
Iterable<?> ids,
162+
DocumentDeleteOptions options,
163+
Class<T> entityClass) throws DataAccessException;
164+
165+
/**
166+
* Deletes multiple documents with the given IDs from a collection.
167+
*
168+
* @param ids
169+
* The keys of the documents
170+
* @param entityClass
171+
* The entity class which represents the collection
172+
* @return information about the documents
173+
* @throws DataAccessException
174+
*/
175+
MultiDocumentEntity<DocumentDeleteEntity<?>> deleteAllById(Iterable<?> ids, Class<?> entityClass) throws DataAccessException;
176+
148177
/**
149178
* Deletes the document with the given {@code id} from a collection.
150179
*

src/main/java/com/arangodb/springframework/core/convert/ArangoConverter.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020

2121
package com.arangodb.springframework.core.convert;
2222

23+
import com.fasterxml.jackson.databind.JsonNode;
2324
import org.springframework.core.convert.ConversionService;
25+
import org.springframework.data.mapping.PersistentPropertyAccessor;
2426
import org.springframework.data.mapping.context.MappingContext;
2527

2628
import com.arangodb.springframework.core.mapping.ArangoPersistentEntity;
@@ -33,6 +35,13 @@
3335
*/
3436
public interface ArangoConverter extends ArangoEntityReader, ArangoEntityWriter {
3537

38+
void readProperty(
39+
ArangoPersistentEntity<?> entity,
40+
PersistentPropertyAccessor<?> accessor,
41+
JsonNode source,
42+
ArangoPersistentProperty property
43+
);
44+
3645
boolean isCollectionType(Class<?> type);
3746

3847
boolean isEntityType(Class<?> type);

src/main/java/com/arangodb/springframework/core/convert/DefaultArangoConverter.java

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,16 @@ public <R> R read(final Class<R> type, final JsonNode source) {
120120
return (R) readInternal(TypeInformation.of(type), source);
121121
}
122122

123+
@Override
124+
public void readProperty(
125+
final ArangoPersistentEntity<?> entity,
126+
final PersistentPropertyAccessor<?> accessor,
127+
final JsonNode source,
128+
final ArangoPersistentProperty property
129+
) {
130+
readProperty(entity, null, accessor, source, property);
131+
}
132+
123133
private Object readInternal(final TypeInformation<?> type, final JsonNode source) {
124134
if (source == null) {
125135
return null;
@@ -161,8 +171,8 @@ private Object readInternal(final TypeInformation<?> type, final JsonNode source
161171
return readMap(typeToUse, source);
162172
}
163173

164-
if (!source.isArray() && (TypeInformation.OBJECT.equals(typeToUse) || rawTypeToUse.equals(Object.class))) {
165-
return readMap(TypeInformation.MAP, source);
174+
if (!source.isArray() && (TypeInformation.OBJECT.equals(typeToUse) || rawTypeToUse.equals(Object.class))) {
175+
return readMap(TypeInformation.MAP, source);
166176
}
167177

168178
if (typeToUse.getType().isArray()) {
@@ -173,8 +183,8 @@ private Object readInternal(final TypeInformation<?> type, final JsonNode source
173183
return readCollection(typeToUse, source);
174184
}
175185

176-
if (TypeInformation.OBJECT.equals(typeToUse) || rawTypeToUse.equals(Object.class)) {
177-
return readCollection(TypeInformation.COLLECTION, source);
186+
if (TypeInformation.OBJECT.equals(typeToUse) || rawTypeToUse.equals(Object.class)) {
187+
return readCollection(TypeInformation.COLLECTION, source);
178188
}
179189

180190
ArangoPersistentEntity<?> entity = context.getRequiredPersistentEntity(rawTypeToUse);
@@ -331,11 +341,11 @@ private Optional<Object> readReference(
331341
final ArangoPersistentProperty property,
332342
final Annotation annotation
333343
) {
334-
if (source.isMissingNode() || source.isNull()) {
335-
return Optional.empty();
336-
}
344+
if (source.isMissingNode() || source.isNull()) {
345+
return Optional.empty();
346+
}
337347

338-
Optional<ReferenceResolver<Annotation>> resolver = resolverFactory.getReferenceResolver(annotation);
348+
Optional<ReferenceResolver<Annotation>> resolver = resolverFactory.getReferenceResolver(annotation);
339349

340350
if (resolver.isEmpty()) {
341351
return Optional.empty();
@@ -349,9 +359,9 @@ private Optional<Object> readReference(
349359

350360
return resolver.map(res -> res.resolveMultiple(ids, property.getTypeInformation(), annotation));
351361
} else if (source.isObject()) {
352-
// source contains target
353-
return Optional.of(readInternal(property.getTypeInformation(), source));
354-
} else {
362+
// source contains target
363+
return Optional.of(readInternal(property.getTypeInformation(), source));
364+
} else {
355365
if (!source.isTextual()) {
356366
throw new MappingException(
357367
String.format("A reference must be of type String, but got type %s!", source.getNodeType()));
@@ -446,7 +456,7 @@ private Object readSimple(final Class<?> type, final JsonNode source) {
446456
Enum<?> e = Enum.valueOf((Class<? extends Enum>) type, value);
447457
return e;
448458
} else if (byte[].class.isAssignableFrom(type)) {
449-
return Base64.getDecoder().decode(value);
459+
return Base64.getDecoder().decode(value);
450460
} else if (java.sql.Date.class.isAssignableFrom(type)) {
451461
return new java.sql.Date(parseDate(value).getTime());
452462
} else if (Timestamp.class.isAssignableFrom(type)) {
@@ -778,16 +788,16 @@ private Optional<String> getRefId(final Object source, final ArangoPersistentEnt
778788
}
779789

780790
return Optional.ofNullable(entity.getIdentifierAccessor(source).getIdentifier())
781-
.map(key -> {
782-
if (annotation != null) {
783-
return resolverFactory.getReferenceResolver(annotation)
784-
.map(resolver -> resolver.write(source, entity, convertId(key)))
785-
.orElseThrow(() -> new IllegalArgumentException("Missing reference resolver for " + annotation));
786-
} else {
787-
return MetadataUtils.createIdFromCollectionAndKey(entity.getCollection(), convertId(key));
788-
}
789-
})
790-
.or(() -> Optional.ofNullable((String) entity.getArangoIdAccessor(source).getIdentifier()));
791+
.map(key -> {
792+
if (annotation != null) {
793+
return resolverFactory.getReferenceResolver(annotation)
794+
.map(resolver -> resolver.write(source, entity, convertId(key)))
795+
.orElseThrow(() -> new IllegalArgumentException("Missing reference resolver for " + annotation));
796+
} else {
797+
return MetadataUtils.createIdFromCollectionAndKey(entity.getCollection(), convertId(key));
798+
}
799+
})
800+
.or(() -> Optional.ofNullable((String) entity.getArangoIdAccessor(source).getIdentifier()));
791801
}
792802

793803
private static Collection<?> asCollection(final Object source) {
@@ -846,8 +856,6 @@ private boolean isValidId(final Object key) {
846856
return false;
847857
} else if (JsonNode.class.isAssignableFrom(type)) {
848858
return false;
849-
} else if (type.isArray() && type.getComponentType() != byte.class) {
850-
return false;
851859
} else if (isSimpleType(type)) {
852860
return true;
853861
} else {

src/main/java/com/arangodb/springframework/core/template/ArangoTemplate.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.arangodb.springframework.core.template.DefaultUserOperation.CollectionCallback;
3939
import com.arangodb.springframework.core.util.ArangoExceptionTranslator;
4040
import com.arangodb.springframework.core.util.MetadataUtils;
41+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
4142
import org.springframework.beans.BeansException;
4243
import org.springframework.context.ApplicationContext;
4344
import org.springframework.context.ApplicationContextAware;
@@ -324,6 +325,21 @@ public MultiDocumentEntity<DocumentDeleteEntity<?>> deleteAll(
324325
return deleteAll(values, new DocumentDeleteOptions(), (Class) entityClass);
325326
}
326327

328+
@Override
329+
public <T> MultiDocumentEntity<DocumentDeleteEntity<T>> deleteAllById(Iterable<?> ids, DocumentDeleteOptions options, Class<T> entityClass) throws DataAccessException {
330+
ArrayList<String> convertedIds = new ArrayList<>();
331+
for (Object id : ids) {
332+
convertedIds.add(converter.convertId(id));
333+
}
334+
return deleteAll(convertedIds, options, entityClass);
335+
}
336+
337+
@Override
338+
@SuppressWarnings({"unchecked", "rawtypes"})
339+
public MultiDocumentEntity<DocumentDeleteEntity<?>> deleteAllById(Iterable<?> ids, Class<?> entityClass) throws DataAccessException {
340+
return deleteAllById(ids, new DocumentDeleteOptions(), (Class) entityClass);
341+
}
342+
327343
@Override
328344
public <T> DocumentDeleteEntity<T> delete(final Object id, final DocumentDeleteOptions options, final Class<T> entityClass)
329345
throws DataAccessException {
@@ -665,7 +681,7 @@ private void updateDBFields(final Object value, final DocumentEntity documentEnt
665681
final PersistentPropertyAccessor<?> accessor = entity.getPropertyAccessor(value);
666682
final ArangoPersistentProperty idProperty = entity.getIdProperty();
667683
if (idProperty != null && !idProperty.isImmutable()) {
668-
accessor.setProperty(idProperty, documentEntity.getKey());
684+
converter.readProperty(entity, accessor, JsonNodeFactory.instance.textNode(documentEntity.getKey()), idProperty);
669685
}
670686
entity.getArangoIdProperty().filter(arangoId -> !arangoId.isImmutable())
671687
.ifPresent(arangoId -> accessor.setProperty(arangoId, documentEntity.getId()));

src/main/java/com/arangodb/springframework/repository/SimpleArangoRepository.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public void deleteById(final ID id) {
171171
*/
172172
@Override
173173
public void delete(final T entity) {
174-
String id = (String) arangoOperations.getConverter().getMappingContext()
174+
Object id = arangoOperations.getConverter().getMappingContext()
175175
.getRequiredPersistentEntity(domainClass).getIdentifierAccessor(entity).getRequiredIdentifier();
176176
arangoOperations.delete(id, domainClass);
177177
}
@@ -181,7 +181,7 @@ public void delete(final T entity) {
181181
* @implNote do not add @Override annotation to keep backwards compatibility with spring-data-commons 2.4
182182
*/
183183
public void deleteAllById(Iterable<? extends ID> ids) {
184-
arangoOperations.deleteAll(ids, domainClass);
184+
arangoOperations.deleteAllById(ids, domainClass);
185185
}
186186

187187
/**

src/test/java/com/arangodb/springframework/core/mapping/MultiTenancyDBLevelRepositoryTest.java

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
import java.util.Optional;
2727

28+
import com.arangodb.springframework.repository.StringIdTestEntity;
29+
import com.arangodb.springframework.repository.StringIdTestRepository;
2830
import org.junit.jupiter.api.AfterEach;
2931
import org.junit.jupiter.api.BeforeEach;
3032
import org.junit.jupiter.api.Test;
@@ -37,53 +39,50 @@
3739
import com.arangodb.springframework.ArangoMultiTenancyRepositoryTestConfiguration;
3840
import com.arangodb.springframework.component.TenantProvider;
3941
import com.arangodb.springframework.core.ArangoOperations;
40-
import com.arangodb.springframework.repository.IdTestRepository;
41-
import com.arangodb.springframework.testdata.IdTestEntity;
4242

4343
/**
4444
* @author Paulo Ferreira
45-
*
4645
*/
4746
@ExtendWith(SpringExtension.class)
48-
@ContextConfiguration(classes = { ArangoMultiTenancyRepositoryTestConfiguration.class })
47+
@ContextConfiguration(classes = {ArangoMultiTenancyRepositoryTestConfiguration.class})
4948
public class MultiTenancyDBLevelRepositoryTest {
5049

51-
private static final String TENANT00 = "tenant00";
50+
private static final String TENANT00 = "tenant00";
51+
52+
@Autowired
53+
protected ArangoOperations template;
5254

53-
@Autowired
54-
protected ArangoOperations template;
55+
@Autowired
56+
TenantProvider tenantProvider;
5557

56-
@Autowired
57-
TenantProvider tenantProvider;
58+
@Autowired
59+
StringIdTestRepository idTestRepository;
5860

59-
@Autowired
60-
IdTestRepository<String> idTestRepository;
61-
62-
/*
63-
* For some reason, findAll already creates the collection by itself
64-
*/
61+
/*
62+
* For some reason, findAll already creates the collection by itself
63+
*/
6564

66-
@Test
67-
public void dbFindAll() {
68-
tenantProvider.setId(TENANT00);
69-
assertThat(idTestRepository.findAll().iterator().hasNext(), is(false));
70-
}
65+
@Test
66+
public void dbFindAll() {
67+
tenantProvider.setId(TENANT00);
68+
assertThat(idTestRepository.findAll().iterator().hasNext(), is(false));
69+
}
7170

72-
@Test
73-
public void dbFindOne() {
74-
tenantProvider.setId(TENANT00);
75-
IdTestEntity<String> entity = new IdTestEntity<>();
76-
entity.setId("MyId");
77-
Example<IdTestEntity<String>> example = Example.of(entity);
78-
Optional<IdTestEntity<String>> result = idTestRepository.findOne(example);
79-
assertThat(result.isPresent(), is(false));
80-
}
71+
@Test
72+
public void dbFindOne() {
73+
tenantProvider.setId(TENANT00);
74+
StringIdTestEntity entity = new StringIdTestEntity();
75+
entity.setId("MyId");
76+
Example<StringIdTestEntity> example = Example.of(entity);
77+
Optional<StringIdTestEntity> result = idTestRepository.findOne(example);
78+
assertThat(result.isPresent(), is(false));
79+
}
8180

82-
@BeforeEach
83-
@AfterEach
84-
public void cleanup() {
85-
tenantProvider.setId(TENANT00);
86-
template.dropDatabase();
87-
}
81+
@BeforeEach
82+
@AfterEach
83+
public void cleanup() {
84+
tenantProvider.setId(TENANT00);
85+
template.dropDatabase();
86+
}
8887

8988
}

src/test/java/com/arangodb/springframework/core/mapping/RefMappingTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Optional;
3434
import java.util.stream.Collectors;
3535

36+
import lombok.Data;
3637
import org.junit.jupiter.api.Test;
3738
import org.springframework.data.annotation.Id;
3839

@@ -66,6 +67,28 @@ public void singleRef() {
6667
assertThat(document.entity.id, is(e1.id));
6768
}
6869

70+
@Data
71+
@Document
72+
public static class NumericReferenceTestEntity {
73+
@Id
74+
public Integer id;
75+
@Ref
76+
private NumericReferenceTestEntity entity;
77+
}
78+
79+
@Test
80+
public void refNumeric() {
81+
final NumericReferenceTestEntity e1 = new NumericReferenceTestEntity();
82+
template.insert(e1);
83+
final NumericReferenceTestEntity e0 = new NumericReferenceTestEntity();
84+
e0.entity = e1;
85+
template.insert(e0);
86+
final NumericReferenceTestEntity document = template.find(e0.id, NumericReferenceTestEntity.class).get();
87+
assertThat(document, is(notNullValue()));
88+
assertThat(document.entity, is(notNullValue()));
89+
assertThat(document.entity.id, is(e1.id));
90+
}
91+
6992
public static class SingleReferenceLazyTestEntity extends BasicTestEntity {
7093
@Ref(lazy = true)
7194
private BasicTestEntity entity;

0 commit comments

Comments
 (0)