GH-2493 - Unwrap MapValueWrapper for list parameters, too.
This fixes #2493.
This commit is contained in:
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -66,13 +68,45 @@ final class NamedParameters {
|
||||
|
||||
if (Constants.NAME_OF_PROPERTIES_PARAM.equals(name) && value != null) {
|
||||
this.parameters.put(name, unwrapMapValueWrapper((Map<String, Object>) value));
|
||||
} else if (Constants.NAME_OF_ENTITY_LIST_PARAM.equals(name) && value != null) {
|
||||
this.parameters.put(name, unwrapMapValueWrapperInListOfEntities((List<Map<String, Object>>) value));
|
||||
} else {
|
||||
this.parameters.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Map<String, Object>> unwrapMapValueWrapperInListOfEntities(List<Map<String, Object>> entityList) {
|
||||
boolean requiresChange = entityList.stream().anyMatch(
|
||||
entity ->
|
||||
entity.containsKey(Constants.NAME_OF_PROPERTIES_PARAM) &&
|
||||
((Map<String, Object>) entity.get(Constants.NAME_OF_PROPERTIES_PARAM)).values().stream()
|
||||
.anyMatch(MapValueWrapper.class::isInstance)
|
||||
);
|
||||
|
||||
if (!requiresChange) {
|
||||
return entityList;
|
||||
}
|
||||
|
||||
List<Map<String, Object>> newEntityList = new ArrayList<>(entityList.size());
|
||||
for (Map<String, Object> entity : entityList) {
|
||||
if (entity.containsKey(Constants.NAME_OF_PROPERTIES_PARAM)) {
|
||||
Map<String, Object> newEntity = new HashMap<>(entity);
|
||||
newEntity.put(Constants.NAME_OF_PROPERTIES_PARAM, unwrapMapValueWrapper((Map<String, Object>) entity.get(Constants.NAME_OF_PROPERTIES_PARAM)));
|
||||
newEntityList.add(newEntity);
|
||||
} else {
|
||||
newEntityList.add(entity);
|
||||
}
|
||||
}
|
||||
return newEntityList;
|
||||
}
|
||||
|
||||
private static Map<String, Object> unwrapMapValueWrapper(Map<String, Object> properties) {
|
||||
|
||||
if (properties.values().stream().noneMatch(MapValueWrapper.class::isInstance)) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
Map<String, Object> newProperties = new HashMap<>(properties.size());
|
||||
properties.forEach((k, v) -> {
|
||||
if (v instanceof MapValueWrapper) {
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2011-2022 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.neo4j.integration.issues.gh2493;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.driver.Session;
|
||||
import org.neo4j.driver.Transaction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.config.AbstractNeo4jConfig;
|
||||
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
|
||||
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
|
||||
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
|
||||
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.test.BookmarkCapture;
|
||||
import org.springframework.data.neo4j.test.Neo4jExtension;
|
||||
import org.springframework.data.neo4j.test.Neo4jIntegrationTest;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Neo4jIntegrationTest
|
||||
public class Gh2493IT {
|
||||
|
||||
protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport;
|
||||
|
||||
@BeforeAll
|
||||
protected static void setupData(@Autowired BookmarkCapture bookmarkCapture) {
|
||||
|
||||
try (Session session = neo4jConnectionSupport.getDriver().session(bookmarkCapture.createSessionConfig());
|
||||
Transaction transaction = session.beginTransaction();
|
||||
) {
|
||||
transaction.run("MATCH (n) DETACH DELETE n").consume();
|
||||
transaction.commit();
|
||||
bookmarkCapture.seedWith(session.lastBookmark());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveOneShouldWork(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture,
|
||||
@Autowired TestObjectRepository repository) {
|
||||
|
||||
TestObject testObject = new TestObject(new TestData(4711, "Foobar"));
|
||||
testObject = repository.save(testObject);
|
||||
|
||||
assertThat(testObject.getId()).isNotNull();
|
||||
assertThatTestObjectHasBeenCreated(driver, bookmarkCapture, testObject);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveAllShouldWork(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture,
|
||||
@Autowired TestObjectRepository repository) {
|
||||
|
||||
TestObject testObject = new TestObject(new TestData(4711, "Foobar"));
|
||||
testObject = repository.saveAll(Collections.singletonList(testObject)).get(0);
|
||||
|
||||
assertThat(testObject.getId()).isNotNull();
|
||||
assertThatTestObjectHasBeenCreated(driver, bookmarkCapture, testObject);
|
||||
}
|
||||
|
||||
private static void assertThatTestObjectHasBeenCreated(Driver driver, BookmarkCapture bookmarkCapture,
|
||||
TestObject testObject) {
|
||||
try (Session session = driver.session(bookmarkCapture.createSessionConfig())) {
|
||||
Map<String, Object> arguments = new HashMap<>();
|
||||
arguments.put("id", testObject.getId());
|
||||
arguments.put("num", testObject.getData().getNum());
|
||||
arguments.put("string", testObject.getData().getString());
|
||||
long cnt = session.run(
|
||||
"MATCH (n:TestObject) WHERE n.id = $id AND n.dataNum = $num AND n.dataString = $string RETURN count(n)",
|
||||
arguments)
|
||||
.single().get(0).asLong();
|
||||
assertThat(cnt).isOne();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableNeo4jRepositories
|
||||
static class Config extends AbstractNeo4jConfig {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BookmarkCapture bookmarkCapture() {
|
||||
return new BookmarkCapture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformTransactionManager transactionManager(Driver driver,
|
||||
DatabaseSelectionProvider databaseNameProvider) {
|
||||
|
||||
BookmarkCapture bookmarkCapture = bookmarkCapture();
|
||||
return new Neo4jTransactionManager(driver, databaseNameProvider,
|
||||
Neo4jBookmarkManager.create(bookmarkCapture));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2011-2022 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.neo4j.integration.issues.gh2493;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.neo4j.driver.Value;
|
||||
import org.neo4j.driver.Values;
|
||||
import org.springframework.data.neo4j.core.convert.Neo4jConversionService;
|
||||
import org.springframework.data.neo4j.core.convert.Neo4jPersistentPropertyToMapConverter;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
public class TestConverter implements Neo4jPersistentPropertyToMapConverter<String, TestData> {
|
||||
|
||||
static final String NUM = "Num";
|
||||
static final String STRING = "String";
|
||||
|
||||
@Override
|
||||
public Map<String, Value> decompose(TestData property,
|
||||
Neo4jConversionService neo4jConversionService) {
|
||||
|
||||
if (property == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, Value> result = new HashMap<>();
|
||||
result.put(NUM, Values.value(property.getNum()));
|
||||
result.put(STRING, Values.value(property.getString()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestData compose(Map<String, Value> source,
|
||||
Neo4jConversionService neo4jConversionService) {
|
||||
TestData data = new TestData();
|
||||
if (source.get(NUM) != null) {
|
||||
data.setNum(source.get(NUM).asInt());
|
||||
}
|
||||
if (source.get(STRING) != null) {
|
||||
data.setString(source.get(STRING).asString());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2011-2022 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.neo4j.integration.issues.gh2493;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestData {
|
||||
|
||||
private int num;
|
||||
private String string;
|
||||
|
||||
public TestData() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TestData(int num, String string) {
|
||||
this.num = num;
|
||||
this.string = string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2011-2022 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.neo4j.integration.issues.gh2493;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.springframework.data.neo4j.core.schema.CompositeProperty;
|
||||
import org.springframework.data.neo4j.core.schema.GeneratedValue;
|
||||
import org.springframework.data.neo4j.core.schema.Id;
|
||||
import org.springframework.data.neo4j.core.schema.Node;
|
||||
import org.springframework.data.neo4j.core.schema.Property;
|
||||
import org.springframework.data.neo4j.core.support.UUIDStringGenerator;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Node
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestObject {
|
||||
|
||||
@Id
|
||||
@Property(name = "id")
|
||||
@GeneratedValue(value = UUIDStringGenerator.class)
|
||||
protected String id;
|
||||
|
||||
@JsonIgnore
|
||||
@CompositeProperty(delimiter = "", converter = TestConverter.class)
|
||||
private TestData data;
|
||||
|
||||
public TestObject(TestData aData) {
|
||||
super();
|
||||
data = aData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2011-2022 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.neo4j.integration.issues.gh2493;
|
||||
|
||||
import org.springframework.data.neo4j.repository.Neo4jRepository;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
public interface TestObjectRepository extends Neo4jRepository<TestObject, String> {
|
||||
}
|
||||
Reference in New Issue
Block a user