1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
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  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 package software.amazon.awssdk.enhanced.dynamodb.model;
17 
18 import java.util.function.Consumer;
19 import software.amazon.awssdk.annotations.SdkPublicApi;
20 import software.amazon.awssdk.annotations.ThreadSafe;
21 import software.amazon.awssdk.enhanced.dynamodb.Expression;
22 import software.amazon.awssdk.enhanced.dynamodb.Key;
23 import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
24 import software.amazon.awssdk.enhanced.dynamodb.internal.conditional.BeginsWithConditional;
25 import software.amazon.awssdk.enhanced.dynamodb.internal.conditional.BetweenConditional;
26 import software.amazon.awssdk.enhanced.dynamodb.internal.conditional.EqualToConditional;
27 import software.amazon.awssdk.enhanced.dynamodb.internal.conditional.SingleKeyItemConditional;
28 
29 /**
30  * An interface for a literal conditional that can be used in an enhanced DynamoDB query. Contains convenient static
31  * methods that can be used to construct the most common conditional statements. Query conditionals are not linked to
32  * any specific table or schema and can be re-used in different contexts.
33  * <p>
34  * Example:
35  * <pre>
36  * {@code
37  * QueryConditional sortValueGreaterThanFour = QueryConditional.sortGreaterThan(k -> k.partitionValue(10).sortValue(4));
38  * }
39  * </pre>
40  */
41 @SdkPublicApi
42 @ThreadSafe
43 public interface QueryConditional {
44     /**
45      * Creates a {@link QueryConditional} that matches when the key of an index is equal to a specific value.
46      * @param key the literal key used to compare the value of the index against
47      */
keyEqualTo(Key key)48     static QueryConditional keyEqualTo(Key key) {
49         return new EqualToConditional(key);
50     }
51 
52     /**
53      * Creates a {@link QueryConditional} that matches when the key of an index is equal to a specific value.
54      * @param keyConsumer 'builder consumer' for the literal key used to compare the value of the index against
55      */
keyEqualTo(Consumer<Key.Builder> keyConsumer)56     static QueryConditional keyEqualTo(Consumer<Key.Builder> keyConsumer) {
57         Key.Builder builder = Key.builder();
58         keyConsumer.accept(builder);
59         return keyEqualTo(builder.build());
60     }
61 
62     /**
63      * Creates a {@link QueryConditional} that matches when the key of an index is greater than a specific value.
64      * @param key the literal key used to compare the value of the index against
65      */
sortGreaterThan(Key key)66     static QueryConditional sortGreaterThan(Key key) {
67         return new SingleKeyItemConditional(key, ">");
68     }
69 
70     /**
71      * Creates a {@link QueryConditional} that matches when the key of an index is greater than a specific value.
72      * @param keyConsumer 'builder consumer' for the literal key used to compare the value of the index against
73      */
sortGreaterThan(Consumer<Key.Builder> keyConsumer)74     static QueryConditional sortGreaterThan(Consumer<Key.Builder> keyConsumer) {
75         Key.Builder builder = Key.builder();
76         keyConsumer.accept(builder);
77         return sortGreaterThan(builder.build());
78     }
79 
80     /**
81      * Creates a {@link QueryConditional} that matches when the key of an index is greater than or equal to a specific
82      * value.
83      * @param key the literal key used to compare the value of the index against
84      */
sortGreaterThanOrEqualTo(Key key)85     static QueryConditional sortGreaterThanOrEqualTo(Key key) {
86         return new SingleKeyItemConditional(key, ">=");
87     }
88 
89     /**
90      * Creates a {@link QueryConditional} that matches when the key of an index is greater than or equal to a specific
91      * value.
92      * @param keyConsumer 'builder consumer' for the literal key used to compare the value of the index against
93      */
sortGreaterThanOrEqualTo(Consumer<Key.Builder> keyConsumer)94     static QueryConditional sortGreaterThanOrEqualTo(Consumer<Key.Builder> keyConsumer) {
95         Key.Builder builder = Key.builder();
96         keyConsumer.accept(builder);
97         return sortGreaterThanOrEqualTo(builder.build());
98     }
99 
100     /**
101      * Creates a {@link QueryConditional} that matches when the key of an index is less than a specific value.
102      * @param key the literal key used to compare the value of the index against
103      */
sortLessThan(Key key)104     static QueryConditional sortLessThan(Key key) {
105         return new SingleKeyItemConditional(key, "<");
106     }
107 
108     /**
109      * Creates a {@link QueryConditional} that matches when the key of an index is less than a specific value.
110      * @param keyConsumer 'builder consumer' for the literal key used to compare the value of the index against
111      */
sortLessThan(Consumer<Key.Builder> keyConsumer)112     static QueryConditional sortLessThan(Consumer<Key.Builder> keyConsumer) {
113         Key.Builder builder = Key.builder();
114         keyConsumer.accept(builder);
115         return sortLessThan(builder.build());
116     }
117 
118     /**
119      * Creates a {@link QueryConditional} that matches when the key of an index is less than or equal to a specific
120      * value.
121      * @param key the literal key used to compare the value of the index against
122      */
sortLessThanOrEqualTo(Key key)123     static QueryConditional sortLessThanOrEqualTo(Key key) {
124         return new SingleKeyItemConditional(key, "<=");
125     }
126 
127     /**
128      * Creates a {@link QueryConditional} that matches when the key of an index is less than or equal to a specific
129      * value.
130      * @param keyConsumer 'builder consumer' for the literal key used to compare the value of the index against
131      */
sortLessThanOrEqualTo(Consumer<Key.Builder> keyConsumer)132     static QueryConditional sortLessThanOrEqualTo(Consumer<Key.Builder> keyConsumer) {
133         Key.Builder builder = Key.builder();
134         keyConsumer.accept(builder);
135         return sortLessThanOrEqualTo(builder.build());
136     }
137 
138     /**
139      * Creates a {@link QueryConditional} that matches when the key of an index is between two specific values.
140      * @param keyFrom the literal key used to compare the start of the range to compare the value of the index against
141      * @param keyTo the literal key used to compare the end of the range to compare the value of the index against
142      */
sortBetween(Key keyFrom, Key keyTo)143     static QueryConditional sortBetween(Key keyFrom, Key keyTo) {
144         return new BetweenConditional(keyFrom, keyTo);
145     }
146 
147     /**
148      * Creates a {@link QueryConditional} that matches when the key of an index is between two specific values.
149      * @param keyFromConsumer 'builder consumer' for the literal key used to compare the start of the range to compare
150      *                        the value of the index against
151      * @param keyToConsumer 'builder consumer' for the literal key used to compare the end of the range to compare the
152      *                      value of the index against
153      */
sortBetween(Consumer<Key.Builder> keyFromConsumer, Consumer<Key.Builder> keyToConsumer)154     static QueryConditional sortBetween(Consumer<Key.Builder> keyFromConsumer, Consumer<Key.Builder> keyToConsumer) {
155         Key.Builder builderFrom = Key.builder();
156         Key.Builder builderTo = Key.builder();
157         keyFromConsumer.accept(builderFrom);
158         keyToConsumer.accept(builderTo);
159         return sortBetween(builderFrom.build(), builderTo.build());
160     }
161 
162     /**
163      * Creates a {@link QueryConditional} that matches when the key of an index begins with a specific value.
164      * @param key the literal key used to compare the start of the value of the index against
165      */
sortBeginsWith(Key key)166     static QueryConditional sortBeginsWith(Key key) {
167         return new BeginsWithConditional(key);
168     }
169 
170     /**
171      * Creates a {@link QueryConditional} that matches when the key of an index begins with a specific value.
172      * @param keyConsumer 'builder consumer'  the literal key used to compare the start of the value of the index
173      *                    against
174      */
sortBeginsWith(Consumer<Key.Builder> keyConsumer)175     static QueryConditional sortBeginsWith(Consumer<Key.Builder> keyConsumer) {
176         Key.Builder builder = Key.builder();
177         keyConsumer.accept(builder);
178         return sortBeginsWith(builder.build());
179     }
180 
181     /**
182      * Generates a conditional {@link Expression} based on specific context that is supplied as arguments.
183      * @param tableSchema A {@link TableSchema} that this expression will be used with
184      * @param indexName The specific index name of the index this expression will be used with
185      * @return A specific {@link Expression} that can be used as part of a query request
186      */
expression(TableSchema<?> tableSchema, String indexName)187     Expression expression(TableSchema<?> tableSchema, String indexName);
188 }
189