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