View Javadoc

1   package com.atlassian.marketplace.client.api;
2   
3   import com.atlassian.fugue.Option;
4   
5   import com.google.common.collect.ImmutableList;
6   
7   import static com.atlassian.fugue.Option.none;
8   import static com.atlassian.fugue.Option.some;
9   import static com.google.common.base.Preconditions.checkArgument;
10  import static com.google.common.base.Preconditions.checkNotNull;
11  
12  /**
13   * Holds the pagination parameters {@code offset} and {@code limit}, which are supported by many queries.
14   * @since 2.0.0
15   */
16  public class QueryBounds
17  {
18      private static final QueryBounds DEFAULT = new QueryBounds(0, none(Integer.class));
19      private static final QueryBounds EMPTY = new QueryBounds(0, some(0));
20      
21      private final int offset;
22      private final Option<Integer> limit;
23      
24      private QueryBounds(int offset, Option<Integer> limit)
25      {
26          checkArgument(offset >= 0, "offset may not be negative");
27          for (int l: checkNotNull(limit))
28          {
29              checkArgument(l >= 0, "limit may not be negative");
30          }
31          
32          this.offset = offset;
33          this.limit = limit;
34      }
35      
36      /**
37       * Constructs a new {@link QueryBounds} instance that specifies some number of items to skip past at the
38       * start of the result set.
39       * @param offset  the number of items to skip
40       * @return  a {@link QueryBounds} instance
41       */
42      public static QueryBounds offset(int offset)
43      {
44          return new QueryBounds(offset, none(Integer.class));
45      }
46  
47      /**
48       * Constructs a new {@link QueryBounds} instance that optionally specifies the maximum number of items
49       * to be included in each page of the result set.  Note that the server may choose to impose a
50       * smaller maximum limit.
51       * @param limit  the maximum number of items per result page, or {@link Option#none()} to leave this unspecified 
52       * @return  a {@link QueryBounds} instance
53       */
54      public static QueryBounds limit(Option<Integer> limit)
55      {
56          return new QueryBounds(0, limit);
57      }
58  
59      /**
60       * Returns a {@link QueryBounds} instance with no {@link #offset} or {@link #limit} specified.
61       */
62      public static QueryBounds defaultBounds()
63      {
64          return DEFAULT;
65      }
66  
67      /**
68       * Returns a {@link QueryBounds} instance with {@link #limit} set to <tt>some(0)</tt>, so that the
69       * result set will always be empty.  This is useful if you want to query a collection resource
70       * simply to find out the total number of items it contains, or to look at its links, without
71       * actually accessing the items.
72       */
73      public static QueryBounds empty()
74      {
75          return EMPTY;
76      }
77      
78      /**
79       * The number of items that the client wants to skip past at the start of the result set.
80       */
81      public int getOffset()
82      {
83          return offset;
84      }
85      
86      /**
87       * The maximum number of items that the client wants to receive in the result set.
88       */
89      public Option<Integer> getLimit()
90      {
91          return limit;
92      }
93      
94      /**
95       * Returns a copy of this QueryBounds instance with the <tt>offset</tt> property changed.
96       * @see QueryBounds#offset
97       */
98      public QueryBounds withOffset(int offset)
99      {
100         return new QueryBounds(offset, this.limit);
101     }
102     
103     /**
104      * Returns a copy of this QueryBounds instance with the <tt>limit</tt> property changed.
105      * @see QueryBounds#limit
106      */
107     public QueryBounds withLimit(Option<Integer> limit)
108     {
109         return new QueryBounds(this.offset, limit);
110     }
111     
112     @Override
113     public boolean equals(Object other)
114     {
115         if (other instanceof QueryBounds)
116         {
117             QueryBounds o = (QueryBounds) other;
118             return offset == o.offset && limit.equals(o.limit);
119         }
120         return false;
121     }
122     
123     @Override
124     public int hashCode()
125     {
126         return offset + limit.hashCode();
127     }
128     
129     public Iterable<String> describe()
130     {
131         ImmutableList.Builder<String> ret = ImmutableList.builder();
132         if (offset > 0)
133         {
134             ret.add("offset(" + offset + ")");
135         }
136         for (Integer l: limit)
137         {
138             ret.add("limit(" + l + ")");
139         }
140         return ret.build();
141     }
142 }