View Javadoc

1   /**
2    * Copyright © 2018 spring-data-dynamodb (https://github.com/derjust/spring-data-dynamodb)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.socialsignin.spring.data.dynamodb.repository.query;
17  
18  import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperTableModel;
19  import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
20  import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
21  import org.socialsignin.spring.data.dynamodb.query.Query;
22  import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation;
23  import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBIdIsHashAndRangeKeyEntityInformation;
24  import org.springframework.data.mapping.PropertyPath;
25  import org.springframework.data.repository.query.ParameterAccessor;
26  import org.springframework.data.repository.query.parser.AbstractQueryCreator;
27  import org.springframework.data.repository.query.parser.Part;
28  import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
29  import org.springframework.data.repository.query.parser.PartTree;
30  import org.springframework.util.Assert;
31  import org.springframework.util.ClassUtils;
32  import org.springframework.util.ObjectUtils;
33  
34  import java.util.Arrays;
35  import java.util.Iterator;
36  import java.util.Optional;
37  
38  /**
39   * @author Michael Lavelle
40   * @author Sebastian Just
41   */
42  public abstract class AbstractDynamoDBQueryCreator<T, ID, R>
43  		extends
44  			AbstractQueryCreator<Query<R>, DynamoDBQueryCriteria<T, ID>> {
45  
46  	protected final DynamoDBEntityInformation<T, ID> entityMetadata;
47  	protected final DynamoDBOperations dynamoDBOperations;
48  	protected final Optional<String> projection;
49  
50  	public AbstractDynamoDBQueryCreator(PartTree tree, DynamoDBEntityInformation<T, ID> entityMetadata,
51  			Optional<String> projection, DynamoDBOperations dynamoDBOperations) {
52  		super(tree);
53  		this.entityMetadata = entityMetadata;
54  		this.projection = projection;
55  		this.dynamoDBOperations = dynamoDBOperations;
56  	}
57  
58  	public AbstractDynamoDBQueryCreator(PartTree tree, ParameterAccessor parameterAccessor,
59  			DynamoDBEntityInformation<T, ID> entityMetadata, Optional<String> projection,
60  			DynamoDBOperations dynamoDBOperations) {
61  		super(tree, parameterAccessor);
62  		this.entityMetadata = entityMetadata;
63  		this.projection = projection;
64  		this.dynamoDBOperations = dynamoDBOperations;
65  	}
66  
67  	@Override
68  	protected DynamoDBQueryCriteria<T, ID> create(Part part, Iterator<Object> iterator) {
69  		final DynamoDBMapperTableModel<T> tableModel = dynamoDBOperations.getTableModel(entityMetadata.getJavaType());
70  		DynamoDBQueryCriteria<T, ID> criteria = entityMetadata.isRangeKeyAware()
71  				? new DynamoDBEntityWithHashAndRangeKeyCriteria<T, ID>(
72  						(DynamoDBIdIsHashAndRangeKeyEntityInformation<T, ID>) entityMetadata, tableModel)
73  				: new DynamoDBEntityWithHashKeyOnlyCriteria<>(entityMetadata, tableModel);
74  		return addCriteria(criteria, part, iterator);
75  	}
76  
77  	protected DynamoDBQueryCriteria<T, ID> addCriteria(DynamoDBQueryCriteria<T, ID> criteria, Part part,
78  			Iterator<Object> iterator) {
79  		if (part.shouldIgnoreCase().equals(IgnoreCaseType.ALWAYS))
80  			throw new UnsupportedOperationException("Case insensitivity not supported");
81  
82  		Class<?> leafNodePropertyType = part.getProperty().getLeafProperty().getType();
83  
84  		PropertyPath leafNodePropertyPath = part.getProperty().getLeafProperty();
85  		String leafNodePropertyName = leafNodePropertyPath.toDotPath();
86  		if (leafNodePropertyName.indexOf(".") != -1) {
87  			int index = leafNodePropertyName.lastIndexOf(".");
88  			leafNodePropertyName = leafNodePropertyName.substring(index);
89  		}
90  
91  		switch (part.getType()) {
92  
93  			case IN :
94  				Object in = iterator.next();
95  				Assert.notNull(in, "Creating conditions on null parameters not supported: please specify a value for '"
96  						+ leafNodePropertyName + "'");
97  				boolean isIterable = ClassUtils.isAssignable(Iterable.class, in.getClass());
98  				boolean isArray = ObjectUtils.isArray(in);
99  				Assert.isTrue(isIterable || isArray, "In criteria can only operate with Iterable or Array parameters");
100 				Iterable<?> iterable = isIterable ? ((Iterable<?>) in) : Arrays.asList(ObjectUtils.toObjectArray(in));
101 				return criteria.withPropertyIn(leafNodePropertyName, iterable, leafNodePropertyType);
102 			case CONTAINING :
103 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.CONTAINS,
104 						iterator.next(), leafNodePropertyType);
105 			case STARTING_WITH :
106 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.BEGINS_WITH,
107 						iterator.next(), leafNodePropertyType);
108 			case BETWEEN :
109 				Object first = iterator.next();
110 				Object second = iterator.next();
111 				return criteria.withPropertyBetween(leafNodePropertyName, first, second, leafNodePropertyType);
112 			case AFTER :
113 			case GREATER_THAN :
114 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.GT, iterator.next(),
115 						leafNodePropertyType);
116 			case BEFORE :
117 			case LESS_THAN :
118 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.LT, iterator.next(),
119 						leafNodePropertyType);
120 			case GREATER_THAN_EQUAL :
121 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.GE, iterator.next(),
122 						leafNodePropertyType);
123 			case LESS_THAN_EQUAL :
124 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.LE, iterator.next(),
125 						leafNodePropertyType);
126 			case IS_NULL :
127 				return criteria.withNoValuedCriteria(leafNodePropertyName, ComparisonOperator.NULL);
128 			case IS_NOT_NULL :
129 				return criteria.withNoValuedCriteria(leafNodePropertyName, ComparisonOperator.NOT_NULL);
130 			case TRUE :
131 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.EQ, Boolean.TRUE,
132 						leafNodePropertyType);
133 			case FALSE :
134 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.EQ, Boolean.FALSE,
135 						leafNodePropertyType);
136 			case SIMPLE_PROPERTY :
137 				return criteria.withPropertyEquals(leafNodePropertyName, iterator.next(), leafNodePropertyType);
138 			case NEGATING_SIMPLE_PROPERTY :
139 				return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.NE, iterator.next(),
140 						leafNodePropertyType);
141 			default :
142 				throw new IllegalArgumentException("Unsupported keyword " + part.getType());
143 		}
144 
145 	}
146 
147 	@Override
148 	protected DynamoDBQueryCriteria<T, ID> and(Part part, DynamoDBQueryCriteria<T, ID> base,
149 			Iterator<Object> iterator) {
150 		return addCriteria(base, part, iterator);
151 
152 	}
153 
154 	@Override
155 	protected DynamoDBQueryCriteria<T, ID> or(DynamoDBQueryCriteria<T, ID> base,
156 			DynamoDBQueryCriteria<T, ID> criteria) {
157 		throw new UnsupportedOperationException("Or queries not supported");
158 	}
159 
160 }