diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFilter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFilter.java index bf174b0b7..e4341a24d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFilter.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFilter.java @@ -16,8 +16,8 @@ package org.springframework.data.neo4j.repository.query.derived; import org.neo4j.ogm.cypher.BooleanOperator; import org.neo4j.ogm.cypher.ComparisonOperator; import org.neo4j.ogm.cypher.Filter; -import org.neo4j.ogm.cypher.function.FilterFunction; -import org.neo4j.ogm.cypher.function.PropertyComparison; +import org.springframework.data.neo4j.repository.query.derived.filter.FunctionAdapter; +import org.springframework.data.neo4j.repository.query.derived.filter.PropertyComparisonAdapter; /** * A representation of a Neo4j-OGM Filter that contains no parameter/property values and only holds metadata @@ -35,7 +35,7 @@ public class CypherFilter { BooleanOperator booleanOperator; Class nestedPropertyType; String nestedPropertyName; - FilterFunction function; + FunctionAdapter functionAdapter = new PropertyComparisonAdapter(this); public Integer getPropertyPosition() { return propertyPosition; @@ -101,9 +101,9 @@ public class CypherFilter { this.nestedPropertyName = nestedPropertyName; } - public FilterFunction getFunction() { return function; } + public FunctionAdapter getFunctionAdapter() { return functionAdapter; } - public void setFunction(FilterFunction function) { this.function = function; } + public void setFunctionAdapter(FunctionAdapter functionAdapter) { this.functionAdapter = functionAdapter; } Filter toFilter() { Filter filter = new Filter(); @@ -115,9 +115,8 @@ public class CypherFilter { filter.setBooleanOperator(booleanOperator); filter.setNestedPropertyType(nestedPropertyType); filter.setNestedPropertyName(nestedPropertyName); - if (function != null) { - filter.setFunction(function); - } + filter.setFunction(functionAdapter.filterFunction()); + return filter; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFinderQuery.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFinderQuery.java index 932368aa5..28f9cfa79 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFinderQuery.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/CypherFinderQuery.java @@ -12,14 +12,11 @@ */ package org.springframework.data.neo4j.repository.query.derived; -import static org.springframework.data.repository.query.parser.Part.Type.*; - import java.util.ArrayList; import java.util.List; import org.neo4j.ogm.cypher.BooleanOperator; -import org.neo4j.ogm.cypher.ComparisonOperator; -import org.neo4j.ogm.cypher.function.DistanceComparison; +import org.springframework.data.neo4j.repository.query.derived.builder.*; import org.springframework.data.repository.query.parser.Part; /** @@ -30,68 +27,54 @@ import org.springframework.data.repository.query.parser.Part; */ public class CypherFinderQuery implements DerivedQueryDefinition { - private Class entityType; - private Part basePart; - private List cypherFilters = new ArrayList<>(); - private int paramPosition = 0; + private Class entityType; + private Part basePart; + private List cypherFilters = new ArrayList<>(); + private int paramPosition = 0; - public CypherFinderQuery(Class entityType, Part basePart) { - this.entityType = entityType; - this.basePart = basePart; - } + public CypherFinderQuery(Class entityType, Part basePart) { + this.entityType = entityType; + this.basePart = basePart; + } - @Override - public Part getBasePart() { //because the OR is handled in a weird way. Luanne, explain better - return basePart; - } + @Override + public Part getBasePart() { //because the OR is handled in a weird way. Luanne, explain better + return basePart; + } - @Override - public List getCypherFilters() { - return cypherFilters; - } + @Override + public List getCypherFilters() { + return cypherFilters; + } - @Override - public void addPart(Part part, BooleanOperator booleanOperator) { - String property = part.getProperty().getSegment(); - CypherFilter parameter = new CypherFilter(); - parameter.setPropertyPosition(paramPosition++); - parameter.setPropertyName(property); - parameter.setOwnerEntityType(entityType); - parameter.setComparisonOperator(convertToComparisonOperator(part.getType())); - parameter.setNegated(part.getType().name().startsWith("NOT")); - parameter.setBooleanOperator(booleanOperator); + @Override + public void addPart(Part part, BooleanOperator booleanOperator) { - if (part.getType() == NEAR) { - parameter.setFunction(new DistanceComparison()); - parameter.setComparisonOperator(ComparisonOperator.LESS_THAN); - paramPosition++; - } - - if (part.getProperty().next() != null) { - parameter.setOwnerEntityType(part.getProperty().getOwningType().getType()); - parameter.setNestedPropertyType(part.getProperty().getType()); - parameter.setPropertyName(part.getProperty().getLeafProperty().getSegment()); - parameter.setNestedPropertyName(part.getProperty().getSegment()); - } - cypherFilters.add(parameter); - - } - - private ComparisonOperator convertToComparisonOperator(Part.Type type) { - switch (type) { - case GREATER_THAN: - return ComparisonOperator.GREATER_THAN; - case LESS_THAN: - return ComparisonOperator.LESS_THAN; - case REGEX: - return ComparisonOperator.MATCHES; - case LIKE: - return ComparisonOperator.LIKE; - case NOT_LIKE: - return ComparisonOperator.LIKE; - default: - return ComparisonOperator.EQUALS; - } - } + List filters = builderForPart(part, booleanOperator).build(); + for (CypherFilter filter : filters) { + filter.setPropertyPosition(paramPosition); + cypherFilters.add(filter); + paramPosition += filter.functionAdapter.parameterCount(); + } + } + //TODO: Should we inject singleton instances of these? + private CypherFilterBuilder builderForPart(Part part, BooleanOperator booleanOperator) { + switch (part.getType()) { + case NEAR: + return new DistanceComparisonBuilder(part, booleanOperator, entityType); + case BETWEEN: + return new BetweenComparisonBuilder(part, booleanOperator, entityType); + case IS_NULL: + case IS_NOT_NULL: + return new IsNullFilterBuilder(part, booleanOperator, entityType); + case EXISTS: + return new ExistsFilterBuilder(part, booleanOperator, entityType); + case TRUE: + case FALSE: + return new BooleanComparisonBuilder(part, booleanOperator, entityType); + default: + return new PropertyComparisonBuilder(part, booleanOperator, entityType); + } + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/DerivedGraphRepositoryQuery.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/DerivedGraphRepositoryQuery.java index c4b680db5..54db08d4c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/DerivedGraphRepositoryQuery.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/DerivedGraphRepositoryQuery.java @@ -233,48 +233,13 @@ public class DerivedGraphRepositoryQuery implements RepositoryQuery { List cypherFilters = queryDefinition.getCypherFilters(); Filters queryParams = new Filters(); for (CypherFilter cypherFilter : cypherFilters) { - Filter filter = cypherFilter.toFilter(); - - FilterFunction function = filter.getFunction(); - Object functionValue = function instanceof DistanceComparison ? - extractDistanceArgs(params, cypherFilter.getPropertyPosition()) : - params.get(cypherFilter.getPropertyPosition()); - function.setValue(functionValue); - queryParams.add(filter); + cypherFilter.functionAdapter.setValueFromArgs(params); + queryParams.add(cypherFilter.toFilter()); } return queryParams; } - private DistanceFromPoint extractDistanceArgs(Map params, int startIndex) { - Object firstArg = params.get(startIndex); - Object secondArg = params.get(startIndex + 1); - - Distance distance; - Point point; - - if (firstArg instanceof Distance && secondArg instanceof Point) { - distance = (Distance) firstArg; - point = (Point) secondArg; - } else if (secondArg instanceof Distance && firstArg instanceof Point) { - distance = (Distance) secondArg; - point = (Point) firstArg; - } else { - throw new IllegalArgumentException("findNear requires an argument of type Distance and an argument of type Point"); - } - - double meters; - if (distance.getMetric() == Metrics.KILOMETERS) { - meters = distance.getValue() * 1000.0d; - } else if (distance.getMetric() == Metrics.MILES) { - meters = distance.getValue() / 0.00062137d; - } else { - meters = distance.getValue(); - } - - return new DistanceFromPoint(point.getX(), point.getY(), distance.getValue() * meters); - } - protected Object createPage(GraphQueryMethod graphQueryMethod, List resultList, Pageable pageable) { if (pageable == null) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/BetweenComparisonBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/BetweenComparisonBuilder.java new file mode 100644 index 000000000..e07e20240 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/BetweenComparisonBuilder.java @@ -0,0 +1,44 @@ +package org.springframework.data.neo4j.repository.query.derived.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.neo4j.ogm.cypher.ComparisonOperator; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public class BetweenComparisonBuilder extends CypherFilterBuilder { + + public BetweenComparisonBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + super(part, booleanOperator, entityType); + } + + @Override + public List build() { + List filters = new ArrayList<>(); + + CypherFilter greaterThan = new CypherFilter(); + greaterThan.setPropertyName(propertyName()); + greaterThan.setOwnerEntityType(entityType); + greaterThan.setBooleanOperator(booleanOperator); + greaterThan.setNegated(isNegated()); + greaterThan.setComparisonOperator(ComparisonOperator.GREATER_THAN); + setNestedAttributes(part, greaterThan); + filters.add(greaterThan); + + CypherFilter lessThan = new CypherFilter(); + lessThan.setPropertyName(propertyName()); + lessThan.setOwnerEntityType(entityType); + lessThan.setBooleanOperator(BooleanOperator.AND); + lessThan.setNegated(isNegated()); + lessThan.setComparisonOperator(ComparisonOperator.LESS_THAN); + setNestedAttributes(part, lessThan); + filters.add(lessThan); + + return filters; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/BooleanComparisonBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/BooleanComparisonBuilder.java new file mode 100644 index 000000000..1b59c7fbd --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/BooleanComparisonBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + + +package org.springframework.data.neo4j.repository.query.derived.builder; + +import static org.springframework.data.repository.query.parser.Part.Type.*; + +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.neo4j.ogm.cypher.ComparisonOperator; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public class BooleanComparisonBuilder extends CypherFilterBuilder { + + public BooleanComparisonBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + super(part, booleanOperator, entityType); + } + + @Override + public List build() { + List filters = new ArrayList<>(); + + CypherFilter filter = new CypherFilter(); + filter.setPropertyName(propertyName()); + filter.setOwnerEntityType(entityType); + filter.setBooleanOperator(booleanOperator); + filter.setNegated(isNegated() || part.getType() == FALSE); + filter.setComparisonOperator(ComparisonOperator.IS_TRUE); + setNestedAttributes(part, filter); + + filters.add(filter); + + return filters; + } + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/CypherFilterBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/CypherFilterBuilder.java new file mode 100644 index 000000000..afc8f5de9 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/CypherFilterBuilder.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + +package org.springframework.data.neo4j.repository.query.derived.builder; + +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public abstract class CypherFilterBuilder { + + protected Part part; + protected BooleanOperator booleanOperator; + protected Class entityType; + + public CypherFilterBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + this.part = part; + this.booleanOperator = booleanOperator; + this.entityType = entityType; + } + + public abstract List build(); + + protected boolean isNegated() { + return part.getType().name().startsWith("NOT"); + } + + protected String propertyName() { + return part.getProperty().getSegment(); + } + + protected void setNestedAttributes(Part part, CypherFilter filter) { + if (part.getProperty().next() != null) { + filter.setOwnerEntityType(part.getProperty().getOwningType().getType()); + filter.setNestedPropertyType(part.getProperty().getType()); + filter.setPropertyName(part.getProperty().getLeafProperty().getSegment()); + filter.setNestedPropertyName(part.getProperty().getSegment()); + } + } + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/DistanceComparisonBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/DistanceComparisonBuilder.java new file mode 100644 index 000000000..21b3da516 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/DistanceComparisonBuilder.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + + +package org.springframework.data.neo4j.repository.query.derived.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.neo4j.ogm.cypher.ComparisonOperator; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.neo4j.repository.query.derived.filter.DistanceComparisonAdapter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public class DistanceComparisonBuilder extends CypherFilterBuilder { + + public DistanceComparisonBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + super(part, booleanOperator, entityType); + } + + @Override + public List build() { + List filters = new ArrayList<>(); + + CypherFilter filter = new CypherFilter(); + filter.setPropertyName(propertyName()); + filter.setOwnerEntityType(entityType); + filter.setBooleanOperator(booleanOperator); + filter.setNegated(isNegated()); + filter.setFunctionAdapter(new DistanceComparisonAdapter(filter)); + filter.setComparisonOperator(ComparisonOperator.LESS_THAN); + setNestedAttributes(part, filter); + filters.add(filter); + + return filters; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/ExistsFilterBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/ExistsFilterBuilder.java new file mode 100644 index 000000000..d5091a7db --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/ExistsFilterBuilder.java @@ -0,0 +1,39 @@ +package org.springframework.data.neo4j.repository.query.derived.builder; + +import static org.springframework.data.repository.query.parser.Part.Type.IS_NOT_NULL; + +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.neo4j.ogm.cypher.ComparisonOperator; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public class ExistsFilterBuilder extends CypherFilterBuilder { + + public ExistsFilterBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + super(part, booleanOperator, entityType); + } + + @Override + public List build() { + List filters = new ArrayList<>(); + + CypherFilter filter = new CypherFilter(); + filter.setPropertyName(propertyName()); + filter.setOwnerEntityType(entityType); + filter.setBooleanOperator(booleanOperator); + filter.setNegated(isNegated()); + filter.setComparisonOperator(ComparisonOperator.EXISTS); + setNestedAttributes(part, filter); + + filters.add(filter); + + return filters; + } + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/IsNullFilterBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/IsNullFilterBuilder.java new file mode 100644 index 000000000..d43618ba7 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/IsNullFilterBuilder.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + + +package org.springframework.data.neo4j.repository.query.derived.builder; + +import static org.springframework.data.repository.query.parser.Part.Type.IS_NOT_NULL; + +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.neo4j.ogm.cypher.ComparisonOperator; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public class IsNullFilterBuilder extends CypherFilterBuilder { + + public IsNullFilterBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + super(part, booleanOperator, entityType); + } + + @Override + public List build() { + + if (part.getProperty().getSegment().contains("similarRestaurants")) { + System.out.println("here"); + } + + List filters = new ArrayList<>(); + + CypherFilter filter = new CypherFilter(); + filter.setPropertyName(propertyName()); + filter.setOwnerEntityType(entityType); + filter.setBooleanOperator(booleanOperator); + filter.setNegated(isNegated() || part.getType() == IS_NOT_NULL); + filter.setComparisonOperator(ComparisonOperator.IS_NULL); + setNestedAttributes(part, filter); + + filters.add(filter); + + return filters; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/PropertyComparisonBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/PropertyComparisonBuilder.java new file mode 100644 index 000000000..fe2d35704 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/builder/PropertyComparisonBuilder.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + +package org.springframework.data.neo4j.repository.query.derived.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.ogm.cypher.BooleanOperator; +import org.neo4j.ogm.cypher.ComparisonOperator; +import org.springframework.data.mapping.PropertyPath; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; +import org.springframework.data.repository.query.parser.Part; + +/** + * @author Jasper Blues + */ +public class PropertyComparisonBuilder extends CypherFilterBuilder { + + public PropertyComparisonBuilder(Part part, BooleanOperator booleanOperator, Class entityType) { + super(part, booleanOperator, entityType); + } + + @Override + public List build() { + + if (part.getProperty().getSegment().contains("visited")) { + System.out.println("here"); + } + + List filters = new ArrayList<>(); + + CypherFilter filter = new CypherFilter(); + filter.setPropertyName(propertyName()); + filter.setOwnerEntityType(entityType); + filter.setBooleanOperator(booleanOperator); + filter.setNegated(isNegated()); + filter.setComparisonOperator(convertToComparisonOperator(part.getType())); + setNestedAttributes(part, filter); + + filters.add(filter); + + return filters; + } + + + private ComparisonOperator convertToComparisonOperator(Part.Type type) { + switch (type) { + case AFTER: + case GREATER_THAN: + return ComparisonOperator.GREATER_THAN; + case GREATER_THAN_EQUAL: + return ComparisonOperator.GREATER_THAN_EQUAL; + case BEFORE: + case LESS_THAN: + return ComparisonOperator.LESS_THAN; + case LESS_THAN_EQUAL: + return ComparisonOperator.LESS_THAN_EQUAL; + case REGEX: + return ComparisonOperator.MATCHES; + case LIKE: + case NOT_LIKE: + return ComparisonOperator.LIKE; + case STARTING_WITH: + return ComparisonOperator.STARTING_WITH; + case ENDING_WITH: + return ComparisonOperator.ENDING_WITH; + case CONTAINING: + case NOT_CONTAINING: + return ComparisonOperator.CONTAINING; + case IN: + case NOT_IN: + return ComparisonOperator.IN; + case SIMPLE_PROPERTY: + return ComparisonOperator.EQUALS; + default: + throw new IllegalArgumentException("No ComparisonOperator for Part.Type " + type); + } + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/DistanceComparisonAdapter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/DistanceComparisonAdapter.java new file mode 100644 index 000000000..0fa5427e1 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/DistanceComparisonAdapter.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + +package org.springframework.data.neo4j.repository.query.derived.filter; + +import java.util.Map; + +import org.neo4j.ogm.cypher.function.DistanceComparison; +import org.neo4j.ogm.cypher.function.DistanceFromPoint; +import org.neo4j.ogm.cypher.function.FilterFunction; +import org.springframework.data.geo.Distance; +import org.springframework.data.geo.Metrics; +import org.springframework.data.geo.Point; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; + +/** + * Adapter to the OGM FilterFunction interface for a PropertyComparison. + * + * @author Jasper Blues + */ +public class DistanceComparisonAdapter implements FunctionAdapter { + + private CypherFilter cypherFilter; + private DistanceComparison distanceComparison; + + public DistanceComparisonAdapter(CypherFilter cypherFilter) { + this.distanceComparison = new DistanceComparison(); + this.cypherFilter = cypherFilter; + } + + public DistanceComparisonAdapter() { + this(null); + } + + @Override + public CypherFilter cypherFilter() { + return cypherFilter; + } + + @Override + public FilterFunction filterFunction() { + return distanceComparison; + } + + @Override + public int parameterCount() { + return 2; + } + + @Override + public void setValueFromArgs(Map params) { + if (cypherFilter == null) { + throw new IllegalStateException("Can't set value from args when cypherFilter is null."); + } + + Object firstArg = params.get(cypherFilter().getPropertyPosition()); + Object secondArg = params.get(cypherFilter().getPropertyPosition() + 1); + + Distance distance; + Point point; + + if (firstArg instanceof Distance && secondArg instanceof Point) { + distance = (Distance) firstArg; + point = (Point) secondArg; + } else if (secondArg instanceof Distance && firstArg instanceof Point) { + distance = (Distance) secondArg; + point = (Point) firstArg; + } else { + throw new IllegalArgumentException("findNear requires an argument of type Distance and an argument of type Point"); + } + + double meters; + if (distance.getMetric() == Metrics.KILOMETERS) { + meters = distance.getValue() * 1000.0d; + } else if (distance.getMetric() == Metrics.MILES) { + meters = distance.getValue() / 0.00062137d; + } else { + meters = distance.getValue(); + } + + distanceComparison.setValue(new DistanceFromPoint(point.getX(), point.getY(), distance.getValue() * meters)); + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/FunctionAdapter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/FunctionAdapter.java new file mode 100644 index 000000000..0ba68b2f5 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/FunctionAdapter.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + +package org.springframework.data.neo4j.repository.query.derived.filter; + +import java.util.Map; + +import org.neo4j.ogm.cypher.function.FilterFunction; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; + +/** + * Adapter to the OGM FilterFunction interface. Adds the derived finder parameter count, and the ability to set the + * function value from the derived finder argument structure. + * + * @author Jasper Blues + */ +public interface FunctionAdapter { + + CypherFilter cypherFilter(); + + FilterFunction filterFunction(); + + int parameterCount(); + + void setValueFromArgs(Map params); + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/PropertyComparisonAdapter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/PropertyComparisonAdapter.java new file mode 100644 index 000000000..f48278a3b --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/query/derived/filter/PropertyComparisonAdapter.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2011-2016] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with + * separate copyright notices and license terms. Your use of the source + * code for these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + * + */ + +package org.springframework.data.neo4j.repository.query.derived.filter; + +import java.util.Map; + +import org.neo4j.ogm.cypher.function.FilterFunction; +import org.neo4j.ogm.cypher.function.PropertyComparison; +import org.springframework.data.neo4j.repository.query.derived.CypherFilter; + +/** + * Adapter to the OGM FilterFunction interface for a PropertyComparison. + * + * @author Jasper Blues + * @see FunctionAdapter + */ +public class PropertyComparisonAdapter implements FunctionAdapter { + + private CypherFilter cypherFilter; + private PropertyComparison propertyComparison; + + public PropertyComparisonAdapter(CypherFilter cypherFilter) { + this.cypherFilter = cypherFilter; + this.propertyComparison = new PropertyComparison(); + } + + public PropertyComparisonAdapter() { + this(null); + } + + public CypherFilter getCypherFilter() { + return cypherFilter; + } + + public void setCypherFilter(CypherFilter cypherFilter) { + this.cypherFilter = cypherFilter; + } + + @Override + public CypherFilter cypherFilter() { + return null; + } + + @Override + public FilterFunction filterFunction() { + return propertyComparison; + } + + @Override + public int parameterCount() { + return 1; + } + + @Override + public void setValueFromArgs(Map params) { + if (cypherFilter == null) { + throw new IllegalStateException("Can't set value from args when cypherFilter is null."); + } + propertyComparison.setValue(params.get(cypherFilter.getPropertyPosition())); + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/movies/MoviesIntegrationIT.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/movies/MoviesIntegrationIT.java index 502ec873d..b6abe598d 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/movies/MoviesIntegrationIT.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/movies/MoviesIntegrationIT.java @@ -15,12 +15,14 @@ package org.springframework.data.neo4j.examples.movies; import static org.junit.Assert.*; import static org.neo4j.ogm.testutil.GraphTestUtils.*; +import static org.springframework.data.repository.query.parser.Part.Type.*; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.apache.commons.lang.ArrayUtils; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/RestaurantIT.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/RestaurantIT.java index befe5fcfb..0b41e3a32 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/RestaurantIT.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/RestaurantIT.java @@ -17,8 +17,9 @@ package org.springframework.data.neo4j.examples.restaurants; import static org.apache.webbeans.util.Asserts.assertNotNull; import static org.junit.Assert.*; -import java.util.ArrayList; -import java.util.Collection; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; import java.util.List; import org.junit.After; @@ -32,6 +33,7 @@ import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; import org.springframework.data.neo4j.examples.restaurants.context.RestaurantContext; +import org.springframework.data.neo4j.examples.restaurants.domain.Diner; import org.springframework.data.neo4j.examples.restaurants.domain.Restaurant; import org.springframework.data.neo4j.examples.restaurants.repo.RestaurantRepository; import org.springframework.test.annotation.DirtiesContext; @@ -43,6 +45,9 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @DirtiesContext /** + * + * Tests that we support each kind of keyword specified by Part.Type + * * @author Jasper Blues */ public class RestaurantIT extends MultiDriverTestClass { @@ -51,13 +56,16 @@ public class RestaurantIT extends MultiDriverTestClass { private RestaurantRepository restaurantRepository; @After - public void tearDown() - { + public void tearDown() { restaurantRepository.deleteAll(); } /** + * This test, as the below one does, asserts that the parameter index for each query part is set correctly. Most + * query parts are associated with one parameter, while certain kinds, such as NEAR, require more. + + * * @see DATAGRAPH-561 */ @Test @@ -80,6 +88,10 @@ public class RestaurantIT extends MultiDriverTestClass { } /** + * + * This test, as the above one does, asserts that the parameter index for each query part is set correctly. Most + * query parts are associated with one parameter, while certain kinds, such as NEAR, require more. + * * @see DATAGRAPH-561 */ @Test @@ -100,4 +112,436 @@ public class RestaurantIT extends MultiDriverTestClass { assertEquals(37.61649, found.getLocation().getX(), 0); assertEquals(-122.38681, found.getLocation().getY(), 0); } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindRestaurantsWithScoreBetween() { + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + Restaurant cyma = new Restaurant("Cyma", 80.6); + restaurantRepository.save(cyma); + + Restaurant awful = new Restaurant("Awful", 20.0); + restaurantRepository.save(awful); + + List results = restaurantRepository.findByScoreBetween(70.0, 80.0); + assertNotNull(results); + assertEquals(1, results.size()); + + List shouldBeEmpty = restaurantRepository.findByScoreBetween(30.0, 40.0); + assertNotNull(shouldBeEmpty); + assertEquals(0, shouldBeEmpty.size()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByPropertyIsNull() { + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", + new Point(37.61649, -122.38681), 94128); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", "Mostly Ramen"); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByDescriptionIsNull(); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByPropertyIsNotNull() { + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", + new Point(37.61649, -122.38681), 94128); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", "Mostly Ramen"); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByDescriptionIsNotNull(); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindBNestedProperty_different_entity_type_IsNull() { + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", + new Point(37.61649, -122.38681), 94128); + + Diner diner = new Diner("Jasper", null); + restaurant.addRegularDiner(diner); + + restaurantRepository.save(restaurant); + + List results = restaurantRepository.findByRegularDinersLastNameIsNull(); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindBNestedProperty_same_entity_type_IsNull() { + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", + new Point(37.61649, -122.38681), 94128); + + Diner diner = new Diner("Jasper", null); + restaurant.addRegularDiner(diner); + + Restaurant kuroda = new Restaurant("Kuroda", null); + restaurant.addSimilarRestaurant(kuroda); + + restaurantRepository.save(restaurant); + + List results = restaurantRepository.findBySimilarRestaurantsDescriptionIsNull(); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByScoreLessThan() { + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + Restaurant cyma = new Restaurant("Cyma", 81.3); + restaurantRepository.save(cyma); + + List results = restaurantRepository.findByScoreLessThan(75); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + + results = restaurantRepository.findByScoreLessThan(72.4); + assertNotNull(results); + assertEquals(0, results.size()); + + results = restaurantRepository.findByScoreLessThanEqual(72.4); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByScoreGreaterThan() { + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + Restaurant cyma = new Restaurant("Cyma", 81.3); + restaurantRepository.save(cyma); + + List results = restaurantRepository.findByScoreGreaterThan(75); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Cyma", results.get(0).getName()); + + results = restaurantRepository.findByScoreGreaterThan(90.0); + assertNotNull(results); + assertEquals(0, results.size()); + + results = restaurantRepository.findByScoreGreaterThanEqual(81.3); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Cyma", results.get(0).getName()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByLaunchDateBefore() { + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + kuroda.setLaunchDate(new Date(1000)); + restaurantRepository.save(kuroda); + + Restaurant cyma = new Restaurant("Cyma", 80.5); + cyma.setLaunchDate(new Date(2000)); + restaurantRepository.save(cyma); + + List results = restaurantRepository.findByLaunchDateBefore(new Date(1001)); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + + results = restaurantRepository.findByLaunchDateBefore(new Date(999)); + assertNotNull(results); + assertEquals(0, results.size()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByLaunchDateAfter() { + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + kuroda.setLaunchDate(new Date(1000)); + restaurantRepository.save(kuroda); + + Restaurant cyma = new Restaurant("Cyma", 80.5); + cyma.setLaunchDate(new Date(2000)); + restaurantRepository.save(cyma); + + List results = restaurantRepository.findByLaunchDateAfter(new Date(1500)); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Cyma", results.get(0).getName()); + + results = restaurantRepository.findByLaunchDateAfter(new Date(3000)); + assertNotNull(results); + assertEquals(0, results.size()); + } + + /** + * All findByPropertyLike does currently is to require an exact match, ignoring case. + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameNotLike() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameNotLike("kuroda"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + + /** + * All findByPropertyLike does currently is to require an exact match, ignoring case. + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameLike() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameLike("*san francisco international*"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameStartingWith() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameStartingWith("San Francisco"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameEndingWith() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameEndingWith("Airport (SFO)"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameContaining() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameContaining("International Airport"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + results = restaurantRepository.findByNameNotContaining("International Airport"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameContainingOrDescriptionIsNull() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + Restaurant cyma = new Restaurant("Cyma", "Greek Stuff"); + + List results = restaurantRepository.findByNameContaining("International Airport"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + results = restaurantRepository.findByNameNotContainingOrDescriptionIsNull("International Airport"); + Collections.sort(results); + assertNotNull(results); + assertEquals(2, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + assertEquals("San Francisco International Airport (SFO)", results.get(1).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameIn() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameIn(Arrays.asList("Kuroda", "Foo", "Bar")); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + + results = restaurantRepository.findByNameNotIn(Arrays.asList("Kuroda", "Foo", "Bar")); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameMatchesRegEx() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameMatchesRegex("(?i)san francisco.*"); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("San Francisco International Airport (SFO)", results.get(0).getName()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByNameExists() { + + Restaurant restaurant = new Restaurant("San Francisco International Airport (SFO)", 68.0); + restaurantRepository.save(restaurant); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByNameExists(); + assertNotNull(results); + assertEquals(2, results.size()); + + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByPropertyIsTrue() + { + Restaurant kazan = new Restaurant("Kazan", 77.0); + kazan.setHalal(true); + restaurantRepository.save(kazan); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + kuroda.setHalal(false); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByHalalIsTrue(); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kazan", results.get(0).getName()); + } + + /** + * @see DATAGRAPH-904 + */ + @Test + public void shouldFindByPropertyIsFalse() + { + Restaurant kazan = new Restaurant("Kazan", 77.0); + kazan.setHalal(true); + restaurantRepository.save(kazan); + + Restaurant kuroda = new Restaurant("Kuroda", 72.4); + kuroda.setHalal(false); + restaurantRepository.save(kuroda); + + List results = restaurantRepository.findByHalalIsFalse(); + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals("Kuroda", results.get(0).getName()); + } + } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Diner.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Diner.java new file mode 100644 index 000000000..590fa5a5f --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Diner.java @@ -0,0 +1,41 @@ +package org.springframework.data.neo4j.examples.restaurants.domain; + +import org.neo4j.ogm.annotation.GraphId; + +/** + * An entity (most likely human) that consumes meals in a Restaurant. Not to be confused with the 50s concept that + * serves meals. + */ +public class Diner { + + @GraphId + private Long id; + + private String firstName; + private String lastName; + + public Diner() + { + } + + public Diner(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Restaurant.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Restaurant.java index f0a53010b..5026e9fc3 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Restaurant.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/domain/Restaurant.java @@ -14,54 +14,145 @@ package org.springframework.data.neo4j.examples.restaurants.domain; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import org.neo4j.ogm.annotation.GraphId; +import org.neo4j.ogm.annotation.Relationship; import org.neo4j.ogm.annotation.typeconversion.Convert; +import org.neo4j.ogm.annotation.typeconversion.DateString; import org.springframework.data.geo.Point; import org.springframework.data.neo4j.conversion.PointConverter; /** * @author Jasper Blues */ -public class Restaurant { +public class Restaurant implements Comparable { - @GraphId - private Long id; - private String name; - @Convert(PointConverter.class) - private Point location; - private int zip; + @GraphId + private Long id; + private String name; + @Convert(PointConverter.class) + private Point location; + private int zip; + private double score; + private String description; + private boolean halal; - public Restaurant() { - } + @Relationship(type = "REGULAR_DINER", direction = Relationship.OUTGOING) + private List regularDiners = new ArrayList<>(); - public Restaurant(String name, Point location, int zip) { - this.name = name; - this.location = location; - this.zip = zip; - } + @Relationship(type = "SIMILAR_RESTAURANT", direction = Relationship.OUTGOING) + private List similarRestaurants = new ArrayList<>(); - public String getName() { - return name; - } + @DateString + private Date launchDate; - public void setName(String name) { - this.name = name; - } + public Restaurant() { + } - public Point getLocation() { - return location; - } + public Restaurant(String name, Point location, int zip) { + this.name = name; + this.location = location; + this.zip = zip; + } - public void setLocation(Point location) { - this.location = location; - } + public Restaurant(String name, double score) { + this.name = name; + this.score = score; + } - public int getZip() { - return zip; - } + public Restaurant(String name, String description) { + this.name = name; + this.description = description; + } - public void setZip(int zip) { - this.zip = zip; - } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public Point getLocation() { + return location; + } + + public void setLocation(Point location) { + this.location = location; + } + + public int getZip() { + return zip; + } + + public void setZip(int zip) { + this.zip = zip; + } + + public double getScore() { + return score; + } + + public void setScore(double score) { + this.score = score; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getLaunchDate() { + return launchDate; + } + + public void setLaunchDate(Date launchDate) { + this.launchDate = launchDate; + } + + public boolean halal() { + return halal; + } + + public void setHalal(boolean halal) { + this.halal = halal; + } + + public void addRegularDiner(Diner diner) { + this.regularDiners.add(diner); + } + + public List getRegularDiners() { + return this.regularDiners; + } + + public void addSimilarRestaurant(Restaurant restaurant) { + this.similarRestaurants.add(restaurant); + } + + public List getSimilarRestaurants() { + return this.similarRestaurants; + } + + @Override + public String toString() { + return "Restaurant{" + + "name='" + name + '\'' + + ", score=" + score + + '}'; + } + + @Override + public int compareTo(Restaurant o) { + if (this == o) { + return 0; + } + return this.getName().compareTo(o.getName()); + } } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/repo/RestaurantRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/repo/RestaurantRepository.java index a45314236..78aa737b4 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/repo/RestaurantRepository.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/restaurants/repo/RestaurantRepository.java @@ -14,6 +14,7 @@ package org.springframework.data.neo4j.examples.restaurants.repo; import java.util.Collection; +import java.util.Date; import java.util.List; import org.springframework.data.geo.Distance; @@ -30,4 +31,54 @@ public interface RestaurantRepository extends GraphRepository { List findByLocationNearAndName(Distance distance, Point point, String name); + List findByScoreBetween(double min, double max); + + List findByScoreLessThan(double max); + + List findByScoreLessThanEqual(double max); + + List findByScoreGreaterThan(double max); + + List findByScoreGreaterThanEqual(double max); + + List findByDescriptionIsNull(); + + List findByDescriptionIsNotNull(); + + List findByLaunchDateBefore(Date date); + + List findByLaunchDateAfter(Date date); + + List findByNameNotLike(String name); + + List findByNameLike(String name); + + List findByNameStartingWith(String string); + + List findByNameEndingWith(String string); + + List findByNameContaining(String string); + + List findByNameNotContaining(String string); + + List findByNameIn(Iterable candidates); + + List findByNameNotIn(Iterable candidates); + + List findByNameMatchesRegex(String foobar); + + List findByNameExists(); + + List findByHalalIsTrue(); + + List findByHalalIsFalse(); + + List findBySimilarRestaurantsDescriptionIsNull(); + + List findByRegularDinersLastNameIsNull(); + + List findByNameNotContainingOrDescriptionIsNull(String nameContaining); + } + + diff --git a/spring-data-neo4j/src/test/resources/logback-test.xml b/spring-data-neo4j/src/test/resources/logback-test.xml index a85467674..4394d1276 100644 --- a/spring-data-neo4j/src/test/resources/logback-test.xml +++ b/spring-data-neo4j/src/test/resources/logback-test.xml @@ -23,7 +23,7 @@ - +