Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / search / SortExpression.java
bloba7614115a852fea9c0b5fb8318f0b1f06118ed8e
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.search;
5 import com.google.appengine.api.search.checkers.FieldChecker;
6 import com.google.appengine.api.search.checkers.Preconditions;
8 import java.util.Date;
10 /**
11 * Sorting specification for a single dimension. Multi-dimensional sorting
12 * is supported by a collection of SortExpressions.
15 public final class SortExpression {
17 /**
18 * The expression to be used if you wish to sort by order ID field.
19 * By default, results are sorted in descending value of order ID.
20 * To sort in ascending order, you need to create a sort expression as
21 * <pre>
22 * SortExpression expr = SortExpression.newBuilder()
23 * .setExpression(SortExpression.ORDER_ID_FIELD_NAME)
24 * .setDirection(SortExpression.SortDirection.ASCENDING)
25 * .setDefaultValueNumeric(0)
26 * .build();
27 * </pre>
29 public static final String ORDER_ID_FIELD_NAME = "_order_id";
31 /**
32 * The expression to be used if you wish to sort by document score.
33 * You need to create a sort expression as
34 * <pre>
35 * SortExpression expr = SortExpression.newBuilder()
36 * .setExpression(String.format(
37 * "%s + rating * 0.01", SortExpression.SCORE_FIELD_NAME))
38 * .setDirection(SortExpression.SortDirection.DESCENDING)
39 * .setDefaultValueNumeric(0)
40 * .build();
41 * </pre>
43 public static final String SCORE_FIELD_NAME = "_score";
45 /**
46 * The direction search results are sorted by, either ascending or descending.
48 public enum SortDirection {
49 /**
50 * The search results are sorted in ascending order,
51 * e.g. alphabetic aaa ... zzz
53 ASCENDING,
55 /**
56 * The search results are sorted in descending order,
57 * e.g. zzz ... aaa
59 DESCENDING
62 /**
63 * A builder that constructs {@link SortExpression SortExpressions}. The user
64 * must provide an expression. The expression can be as simple as a field
65 * name, or can be some other expression such as <code>&quot;score +
66 * count(likes) * 0.1&quot;</code>, which combines a scorer score with a count
67 * of the number of likes values times 0.1. A default value must be specified
68 * for the expression.
69 * <p>
70 * <pre>
71 * SortExpression expr = SortExpression.newBuilder()
72 * .setExpression(String.format(
73 * "%s + count(likes) * 0.1", SortExpression.SCORE_FIELD_NAME))
74 * .setDirection(SortExpression.SortDirection.ASCENDING)
75 * .setDefaultValueNumeric(0.0)
76 * .build()
77 * </pre>
79 public static final class Builder {
80 private String expression;
81 private SortDirection direction; private String defaultValue; private Double defaultValueNumeric; private Date defaultValueDate;
83 private Builder() {
86 /**
87 * Sets an expression to be evaluated for each document to sort by.
88 * A default string value {@link #setDefaultValue(String)} or numeric
89 * {@link #setDefaultValueNumeric(double)} or date
90 * {@link #setDefaultValueDate(Date)} must be specified for the expression.
92 * @param expression the expression to evaluate for each
93 * document to sort by
94 * @return this Builder
95 * @throws IllegalArgumentException if the expression is invalid
97 public Builder setExpression(String expression) {
98 this.expression = FieldChecker.checkExpression(expression);
99 return this;
103 * Sets the direction to sort the search results in.
105 * @param direction the direction to sort the search results in. The
106 * default direction is {@link SortDirection#DESCENDING}
107 * @return this Builder
109 public Builder setDirection(SortDirection direction) {
110 this.direction = direction;
111 return this;
115 * Sets the default value for the field for sorting purposes. Must provide
116 * for text sorts.
118 * @param defaultValue the default value for the field
119 * @return this Builder
120 * @throws IllegalArgumentException if the {@code defaultValue} is not valid
122 public Builder setDefaultValue(String defaultValue) {
123 this.defaultValue = FieldChecker.checkText(defaultValue);
124 return this;
128 * Sets the default value for the field for sorting purposes. Must provide
129 * for numeric sorts.
131 * @param defaultValue the default value for the field
132 * @return this Builder
134 public Builder setDefaultValueNumeric(double defaultValue) {
135 this.defaultValueNumeric = defaultValue;
136 return this;
140 * Sets the default value for the field for sorting purposes. Must provide
141 * for Date sorts. Typically, you should use {@link DateUtil#MIN_DATE} or
142 * {@link DateUtil#MAX_DATE} as a default value.
144 * @param defaultValue the default value for the field
145 * @return this Builder
147 public Builder setDefaultValueDate(Date defaultValue) {
148 this.defaultValueDate = FieldChecker.checkDate(defaultValue);
149 return this;
153 * Builds a {@link SortExpression} from the set values.
155 * @return a {@link SortExpression} built from the set values
156 * @throws IllegalArgumentException if the field name or
157 * default value is invalid
159 public SortExpression build() {
160 return new SortExpression(this);
164 private final SortDirection direction;
165 private final String expression;
167 private final String defaultValue;
168 private final Double defaultValueNumeric;
169 private final Date defaultValueDate;
172 * Constructs a text sort specification using the values from the
173 * {@link Builder}.
175 private SortExpression(Builder builder) {
176 this.expression = builder.expression;
177 this.direction = Util.defaultIfNull(builder.direction, SortDirection.DESCENDING);
178 this.defaultValue = builder.defaultValue;
179 this.defaultValueNumeric = builder.defaultValueNumeric;
180 this.defaultValueDate = builder.defaultValueDate;
181 checkValid();
185 * @return the expression to evaluate for each document and sort by
187 public String getExpression() {
188 return expression;
192 * @return the direction to sort the search results in
194 public SortDirection getDirection() {
195 return direction;
199 * @return the default value for the field. Can be null
201 public String getDefaultValue() {
202 return defaultValue;
206 * @return the default numeric value for the field. Can be null
208 public Double getDefaultValueNumeric() {
209 return defaultValueNumeric;
213 * @return the default date value for the field. Can be null
215 public Date getDefaultValueDate() {
216 return defaultValueDate;
220 * Checks whether this sort specification is valid.
222 * @return this {@code SortExpression}
223 * @throws IllegalArgumentException if the expression is null or invalid,
224 * or no default value for the expression is specified or a default string
225 * value is too long
227 private SortExpression checkValid() {
228 Preconditions.checkNotNull(expression, "expression cannot be null");
229 int defaultValueCount = 0;
230 if (defaultValue != null) {
231 defaultValueCount++;
233 if (defaultValueNumeric != null) {
234 defaultValueCount++;
236 if (defaultValueDate != null) {
237 defaultValueCount++;
239 Preconditions.checkArgument(defaultValueCount == 1,
240 "Exactly one default value must be specified for the SortExpression");
241 if (defaultValue != null) {
242 FieldChecker.checkText(defaultValue);
244 return this;
248 * Copies this sort specification object contents into a protocol buffer.
250 * @return the protocol buffer with the contents of the {@code sortSpec}
252 SearchServicePb.SortSpec copyToProtocolBuffer() {
253 SearchServicePb.SortSpec.Builder builder = SearchServicePb.SortSpec.newBuilder();
254 if (SortDirection.ASCENDING.equals(getDirection())) {
255 builder.setSortDescending(false);
257 builder.setSortExpression(getExpression());
258 if (getDefaultValue() != null) {
259 builder.setDefaultValueText(getDefaultValue());
261 if (getDefaultValueNumeric() != null) {
262 builder.setDefaultValueNumeric(getDefaultValueNumeric());
264 if (getDefaultValueDate() != null) {
265 builder.setDefaultValueText(DateUtil.serializeDate(getDefaultValueDate()));
267 return builder.build();
271 * Creates and returns a SortExpression Builder.
273 * @return a new {@link SortExpression.Builder}. Set the parameters for the sort
274 * specification on the Builder, and use the {@link Builder#build()} method
275 * to create a concrete instance of SortExpression
277 public static Builder newBuilder() {
278 return new Builder();
281 @Override
282 public String toString() {
283 return String.format("SortExpression(direction=%s%s%s%s)",
284 direction,
285 Util.fieldToString("expression", expression),
286 Util.fieldToString("defaultValue", defaultValue),
287 Util.fieldToString("defaultValueNumeric", defaultValueNumeric),
288 Util.fieldToString("defaultValueDate", defaultValueDate));