001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.converter;
014
015import org.apache.juneau.*;
016import org.apache.juneau.objecttools.*;
017import org.apache.juneau.rest.*;
018import org.apache.juneau.rest.httppart.*;
019
020/**
021 * Converter for enabling of search/view/sort/page support on response objects returned by a <c>@RestOp</c>-annotated method.
022 *
023 * <p>
024 * When enabled, objects in a POJO tree can be filtered using the functionality described in the {@link ObjectSearcher},
025 * {@link ObjectViewer}, {@link ObjectSorter}, and {@link ObjectPaginator} classes.
026 *
027 * <p>
028 * The following HTTP request parameters are available for tabular data (e.g. {@code Collections} of {@code Maps},
029 * arrays of beans, etc...):
030 * <ul class='spaced-list'>
031 *    <li>
032 *       <c>&amp;s=</c> Search arguments.
033 *       <br>Comma-delimited list of key/value pairs representing column names and search tokens.
034 *       <br>Example:
035 *       <p class='burlenc'>
036 *    &amp;s=name=Bill*,birthDate&gt;2000
037 *       </p>
038 *    <li>
039 *       <c>&amp;v=</c> Visible columns.
040 *       <br>Comma-delimited list of column names to display.
041 *       <br>Example:
042 *       <p class='burlenc'>
043 *    &amp;v=name,birthDate
044 *       </p>
045 *    <li>
046 *       <c>&amp;o=</c> Sort commands.
047 *       <br>Comma-delimited list of columns to sort by.
048 *       <br>Column names can be suffixed with <js>'+'</js> or <js>'-'</js> to indicate ascending or descending order.
049 *       <br>The default is ascending order.
050 *       <br>Example:
051 *       <p class='burlenc'>
052 *    &amp;o=name,birthDate-
053 *       </p>
054 *    <li>
055 *       <c>&amp;i=</c> Case-insensitive parameter.
056 *       <br>Boolean flag for case-insensitive matching on the search parameters.
057 *    <li>
058 *       <c>&amp;p=</c> - Position parameter.
059 *       <br>Only return rows starting at the specified index position (zero-indexed).
060 *       <br>Default is {@code 0}.
061 *    <li>
062 *       <c>&amp;l=</c> Limit parameter.
063 *       <br>Only return the specified number of rows.
064 *       <br>Default is {@code 0} (meaning return all rows).
065 * </ul>
066 *
067 * <h5 class='section'>See Also:</h5><ul>
068 *    <li class='jc'>{@link ObjectSearcher} - Additional information on searching POJO models.
069 *    <li class='jc'>{@link ObjectViewer} - Additional information on filtering POJO models.
070 *    <li class='jc'>{@link ObjectSorter} - Additional information on sorting POJO models.
071 *    <li class='jc'>{@link ObjectPaginator} - Additional information on paginating POJO models.
072 *    <li class='jm'>{@link org.apache.juneau.rest.RestOpContext.Builder#converters()} - Registering converters with REST resources.
073 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.Converters">Converters</a>
074 * </ul>
075 */
076public final class Queryable implements RestConverter {
077
078   /**
079    * Swagger parameters for this converter.
080    */
081   public static final String SWAGGER_PARAMS=""
082      + "{"
083         + "in:'query',"
084         + "name:'s',"
085         + "description:'"
086            + "Search.\n"
087            + "Key/value pairs representing column names and search tokens.\n"
088            + "\\'*\\' and \\'?\\' can be used as meta-characters in string fields.\n"
089            + "\\'>\\', \\'>=\\', \\'<\\', and \\'<=\\' can be used as limits on numeric and date fields.\n"
090            + "Date fields can be matched with partial dates (e.g. \\'2018\\' to match any date in the year 2018)."
091         + "',"
092         + "type:'array',"
093         + "collectionFormat:'csv',"
094         + "examples:{example:'?s=Bill*,birthDate>2000'}"
095      + "},"
096      + "{"
097         + "in:'query',"
098         + "name:'v',"
099         + "description:'"
100            + "View.\n"
101            + "Column names to display."
102         + "',"
103         + "type:'array',"
104         + "collectionFormat:'csv',"
105         + "examples:{example:'?v=name,birthDate'}"
106      + "},"
107      + "{"
108         + "in:'query',"
109         + "name:'o',"
110         + "description:'"
111            + "Order by.\n"
112            + "Columns to sort by.\n"
113            + "Column names can be suffixed with \\'+\\' or \\'-\\' to indicate ascending or descending order.\n"
114            + "The default is ascending order."
115         + "',"
116         + "type:'array',"
117         + "collectionFormat:'csv',"
118         + "examples:{example:'?o=name,birthDate-'}"
119      + "},"
120      + "{"
121         + "in:'query',"
122         + "name:'p',"
123         + "description:'"
124            + "Position.\n"
125            + "Only return rows starting at the specified index position (zero-indexed).\n"
126            + "Default is 0"
127         + "',"
128         + "type:'integer',"
129         + "examples:{example:'?p=100'}"
130      + "},"
131      + "{"
132         + "in:'query',"
133         + "name:'l',"
134         + "description:'"
135            + "Limit.\n"
136            + "Only return the specified number of rows.\n"
137            + "Default is 0 (meaning return all rows)."
138         + "',"
139         + "type:'integer',"
140         + "examples:{example:'?l=100'}"
141      + "}"
142   ;
143
144   @Override /* RestConverter */
145   public Object convert(RestRequest req, Object o) {
146      if (o == null)
147         return null;
148
149      Value<Object> v = Value.of(o);
150      RequestQueryParams params = req.getQueryParams();
151      BeanSession bs = req.getBeanSession();
152
153      params.getSearchArgs().ifPresent(x -> v.set(ObjectSearcher.create().run(bs, v.get(), x)));
154      params.getSortArgs().ifPresent(x -> v.set(ObjectSorter.create().run(bs, v.get(), x)));
155      params.getViewArgs().ifPresent(x -> v.set(ObjectViewer.create().run(bs, v.get(), x)));
156      params.getPageArgs().ifPresent(x -> v.set(ObjectPaginator.create().run(bs, v.get(), x)));
157      return v.get();
158   }
159}