Skip to content

Commit 1eb8977

Browse files
committed
support mapping of computed values (DE-604)
1 parent dfeb275 commit 1eb8977

File tree

8 files changed

+158
-36
lines changed

8 files changed

+158
-36
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* DISCLAIMER
3+
*
4+
* Copyright 2017 ArangoDB GmbH, Cologne, Germany
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
*/
20+
21+
package com.arangodb.springframework.annotation;
22+
23+
import java.lang.annotation.ElementType;
24+
import java.lang.annotation.Retention;
25+
import java.lang.annotation.RetentionPolicy;
26+
import java.lang.annotation.Target;
27+
28+
/**
29+
* Annotation to mark a field to represent an ArangoDB computed value.
30+
*
31+
* @see <a href="https://docs.arangodb.com/stable/concepts/data-structure/documents/computed-values">Reference Doc</a>
32+
*/
33+
@Retention(RetentionPolicy.RUNTIME)
34+
@Target({ElementType.FIELD})
35+
public @interface ComputedValue {
36+
37+
}

src/main/java/com/arangodb/springframework/core/mapping/ArangoPersistentEntity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package com.arangodb.springframework.core.mapping;
2222

2323
import java.util.Collection;
24+
import java.util.Map;
2425
import java.util.Optional;
2526

2627
import com.arangodb.springframework.annotation.TtlIndex;
@@ -58,6 +59,8 @@ public interface ArangoPersistentEntity<T>
5859

5960
Optional<TtlIndex> getTtlIndex();
6061

62+
Map<String, ArangoPersistentProperty> getComputedValuesProperties();
63+
6164
Collection<ArangoPersistentProperty> getPersistentIndexedProperties();
6265

6366
Collection<ArangoPersistentProperty> getGeoIndexedProperties();

src/main/java/com/arangodb/springframework/core/mapping/ArangoPersistentProperty.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,9 @@
2222

2323
import java.util.Optional;
2424

25+
import com.arangodb.springframework.annotation.*;
2526
import org.springframework.data.mapping.PersistentProperty;
2627

27-
import com.arangodb.springframework.annotation.From;
28-
import com.arangodb.springframework.annotation.FulltextIndexed;
29-
import com.arangodb.springframework.annotation.GeoIndexed;
30-
import com.arangodb.springframework.annotation.PersistentIndexed;
31-
import com.arangodb.springframework.annotation.Ref;
32-
import com.arangodb.springframework.annotation.Relations;
33-
import com.arangodb.springframework.annotation.To;
34-
import com.arangodb.springframework.annotation.TtlIndexed;
35-
3628
/**
3729
* @author Mark Vollmary
3830
*
@@ -56,6 +48,8 @@ public interface ArangoPersistentProperty extends PersistentProperty<ArangoPersi
5648

5749
Optional<To> getTo();
5850

51+
Optional<ComputedValue> getComputedValue();
52+
5953
Optional<PersistentIndexed> getPersistentIndexed();
6054

6155
Optional<GeoIndexed> getGeoIndexed();

src/main/java/com/arangodb/springframework/core/mapping/DefaultArangoPersistentEntity.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public class DefaultArangoPersistentEntity<T> extends BasicPersistentEntity<T, A
7676
private ArangoPersistentProperty arangoIdProperty;
7777
private ArangoPersistentProperty revProperty;
7878
private ArangoPersistentProperty ttlIndexedProperty;
79+
private final Map<String, ArangoPersistentProperty> computedValueProperties;
7980
private final Collection<ArangoPersistentProperty> persistentIndexedProperties;
8081
private final Collection<ArangoPersistentProperty> geoIndexedProperties;
8182
private final Collection<ArangoPersistentProperty> fulltextIndexedProperties;
@@ -88,6 +89,7 @@ public DefaultArangoPersistentEntity(final TypeInformation<T> information) {
8889
super(information);
8990
collection = StringUtils.uncapitalize(information.getType().getSimpleName());
9091
context = new StandardEvaluationContext();
92+
computedValueProperties = new HashMap<>();
9193
persistentIndexedProperties = new ArrayList<>();
9294
geoIndexedProperties = new ArrayList<>();
9395
fulltextIndexedProperties = new ArrayList<>();
@@ -185,6 +187,7 @@ public void addPersistentProperty(final ArangoPersistentProperty property) {
185187
}
186188
ttlIndexedProperty = property;
187189
}
190+
property.getComputedValue().ifPresent(i -> computedValueProperties.put(property.getName(), property));
188191
property.getPersistentIndexed().ifPresent(i -> persistentIndexedProperties.add(property));
189192
property.getGeoIndexed().ifPresent(i -> geoIndexedProperties.add(property));
190193
property.getFulltextIndexed().ifPresent(i -> fulltextIndexedProperties.add(property));
@@ -243,6 +246,11 @@ public <A extends Annotation> Collection<A> getIndexes(final Class<A> annotation
243246
.map(annotation::cast).collect(Collectors.toList());
244247
}
245248

249+
@Override
250+
public Map<String, ArangoPersistentProperty> getComputedValuesProperties() {
251+
return computedValueProperties;
252+
}
253+
246254
@Override
247255
public Collection<ArangoPersistentProperty> getPersistentIndexedProperties() {
248256
return persistentIndexedProperties;

src/main/java/com/arangodb/springframework/core/mapping/DefaultArangoPersistentProperty.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Optional;
2424

2525
import com.arangodb.entity.CollectionType;
26+
import com.arangodb.springframework.annotation.*;
2627
import org.springframework.data.mapping.Association;
2728
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
2829
import org.springframework.data.mapping.model.FieldNamingStrategy;
@@ -31,18 +32,6 @@
3132
import org.springframework.data.mapping.model.SimpleTypeHolder;
3233
import org.springframework.util.StringUtils;
3334

34-
import com.arangodb.springframework.annotation.ArangoId;
35-
import com.arangodb.springframework.annotation.Field;
36-
import com.arangodb.springframework.annotation.From;
37-
import com.arangodb.springframework.annotation.FulltextIndexed;
38-
import com.arangodb.springframework.annotation.GeoIndexed;
39-
import com.arangodb.springframework.annotation.PersistentIndexed;
40-
import com.arangodb.springframework.annotation.Ref;
41-
import com.arangodb.springframework.annotation.Relations;
42-
import com.arangodb.springframework.annotation.Rev;
43-
import com.arangodb.springframework.annotation.To;
44-
import com.arangodb.springframework.annotation.TtlIndexed;
45-
4635
/**
4736
* @author Mark Vollmary
4837
*
@@ -124,6 +113,11 @@ private Optional<String> getAnnotatedFieldName() {
124113
.map(f -> StringUtils.hasText(f.value()) ? f.value() : null);
125114
}
126115

116+
@Override
117+
public Optional<ComputedValue> getComputedValue() {
118+
return Optional.ofNullable(findAnnotation(ComputedValue.class));
119+
}
120+
127121
@Override
128122
public Optional<PersistentIndexed> getPersistentIndexed() {
129123
return Optional.ofNullable(findAnnotation(PersistentIndexed.class));

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,13 @@ private void updateDBFieldsFromObject(final Object toModify, final Object toRead
631631
entityToModify.getRevProperty().filter(rev -> !rev.isImmutable())
632632
.ifPresent(rev -> accessorToWrite.setProperty(rev, accessorToRead.getProperty(revPropertyToRead)));
633633
}
634+
635+
for (ArangoPersistentProperty propRead : entityToRead.getComputedValuesProperties().values()) {
636+
ArangoPersistentProperty propWrite = entityToModify.getComputedValuesProperties().get(propRead.getName());
637+
if (propWrite != null && !propWrite.isImmutable()) {
638+
accessorToWrite.setProperty(propWrite, accessorToRead.getProperty(propRead));
639+
}
640+
}
634641
}
635642

636643
private <T> void updateDBFields(final Iterable<T> values, final MultiDocumentEntity<? extends DocumentEntity> res) {

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

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@
2020

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

23+
import com.arangodb.ArangoDatabase;
2324
import com.arangodb.entity.DocumentEntity;
2425
import com.arangodb.model.AqlQueryOptions;
26+
import com.arangodb.model.CollectionCreateOptions;
2527
import com.arangodb.springframework.AbstractArangoTest;
2628
import com.arangodb.springframework.ArangoTestConfiguration;
2729
import com.arangodb.springframework.AuditorProvider;
28-
import com.arangodb.springframework.annotation.ArangoId;
29-
import com.arangodb.springframework.annotation.Document;
30-
import com.arangodb.springframework.annotation.Field;
31-
import com.arangodb.springframework.annotation.Ref;
30+
import com.arangodb.springframework.annotation.*;
3231
import com.arangodb.springframework.core.convert.ArangoConverter;
3332
import com.arangodb.springframework.core.geo.*;
3433
import com.arangodb.springframework.core.mapping.testdata.BasicTestEntity;
@@ -536,6 +535,86 @@ public void arangoIdAndId() {
536535
assertThat(template.find(entity.arangoId, ArangoIdAndIdTestEntity.class).isPresent(), is(true));
537536
}
538537

538+
private static final String COMPUTED_VALUE_COLL = "compValues";
539+
540+
@Document(COMPUTED_VALUE_COLL)
541+
static class ComputedValueMutable {
542+
@Id
543+
private String id;
544+
545+
@ComputedValue
546+
private String value;
547+
}
548+
549+
@Test
550+
public void computedValueMutableProp() {
551+
ArangoDatabase db = template.driver().db(ArangoTestConfiguration.DB);
552+
db.createCollection(COMPUTED_VALUE_COLL, new CollectionCreateOptions().computedValues(
553+
new com.arangodb.model.ComputedValue()
554+
.name("value")
555+
.computeOn(
556+
com.arangodb.model.ComputedValue.ComputeOn.update,
557+
com.arangodb.model.ComputedValue.ComputeOn.replace,
558+
com.arangodb.model.ComputedValue.ComputeOn.insert
559+
)
560+
.expression("RETURN \"foo\"")
561+
.overwrite(true)
562+
));
563+
564+
final ComputedValueMutable entity = new ComputedValueMutable();
565+
ComputedValueMutable saved;
566+
567+
saved = template.repsert(entity);
568+
assertThat(entity.id, is(notNullValue()));
569+
assertThat(saved.id, is(entity.id));
570+
assertThat(entity.value, is("foo"));
571+
assertThat(saved.value, is(entity.value));
572+
573+
entity.value = "bar";
574+
saved = template.repsert(entity);
575+
assertThat(entity.value, is("foo"));
576+
assertThat(saved.value, is(entity.value));
577+
578+
db.collection(COMPUTED_VALUE_COLL).drop();
579+
}
580+
581+
private static final String COMPUTED_VALUE_COLL_REC = "compValuesRec";
582+
583+
@Document(COMPUTED_VALUE_COLL_REC)
584+
record ComputedValueImmutable(
585+
@Id
586+
String id,
587+
588+
@ComputedValue
589+
String value
590+
) {
591+
}
592+
593+
@Test
594+
public void computedValueImmutableProp() {
595+
ArangoDatabase db = template.driver().db(ArangoTestConfiguration.DB);
596+
db.createCollection(COMPUTED_VALUE_COLL_REC, new CollectionCreateOptions().computedValues(
597+
new com.arangodb.model.ComputedValue()
598+
.name("value")
599+
.computeOn(
600+
com.arangodb.model.ComputedValue.ComputeOn.update,
601+
com.arangodb.model.ComputedValue.ComputeOn.replace,
602+
com.arangodb.model.ComputedValue.ComputeOn.insert
603+
)
604+
.expression("RETURN \"foo\"")
605+
.overwrite(true)
606+
));
607+
608+
ComputedValueImmutable entity = new ComputedValueImmutable(null, "bar");
609+
ComputedValueImmutable saved = template.repsert(entity);
610+
assertThat(entity.id, is(nullValue()));
611+
assertThat(saved.id, is(notNullValue()));
612+
assertThat(entity.value, is("bar"));
613+
assertThat(saved.value, is("foo"));
614+
615+
db.collection(COMPUTED_VALUE_COLL_REC).drop();
616+
}
617+
539618
@Document
540619
static class AuditingTestEntity {
541620
@Id
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<configuration>
22

3-
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
4-
<!-- encoders are assigned the type
5-
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
6-
<encoder>
7-
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
8-
</encoder>
9-
</appender>
3+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
4+
<!-- encoders are assigned the type
5+
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
6+
<encoder>
7+
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
8+
</encoder>
9+
</appender>
1010

11-
<root level="info">
12-
<appender-ref ref="STDOUT" />
13-
</root>
11+
<root level="info">
12+
<appender-ref ref="STDOUT"/>
13+
</root>
1414

15-
<!-- <logger name="com.arangodb.http.HttpCommunication" level="debug" />-->
15+
<!-- <logger name="com.arangodb.internal.net.Communication" level="debug"/>-->
1616

1717
</configuration>

0 commit comments

Comments
 (0)