View Javadoc
1   /*
2    * Copyright 2012-2025 CodeLibs Project and the Others.
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    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.query;
17  
18  import java.io.IOException;
19  import java.util.Objects;
20  
21  import org.apache.lucene.search.Query;
22  import org.opensearch.core.common.io.stream.StreamOutput;
23  import org.opensearch.core.xcontent.XContentBuilder;
24  import org.opensearch.index.query.BoolQueryBuilder;
25  import org.opensearch.index.query.DisMaxQueryBuilder;
26  import org.opensearch.index.query.QueryBuilder;
27  import org.opensearch.index.query.QueryBuilderVisitor;
28  import org.opensearch.index.query.QueryRewriteContext;
29  import org.opensearch.index.query.QueryShardContext;
30  
31  /**
32   * Default implementation of QueryBuilder that wraps other QueryBuilder instances
33   * and provides additional functionality for adding inner queries dynamically.
34   * Supports both BoolQueryBuilder and DisMaxQueryBuilder as underlying implementations.
35   */
36  public class DefaultQueryBuilder implements QueryBuilder {
37  
38      /** The underlying query builder being wrapped. */
39      private final QueryBuilder queryBuilder;
40  
41      /** The type of the underlying query builder. */
42      private final QueryType queryType;
43  
44      /**
45       * Creates a new DefaultQueryBuilder wrapping the specified QueryBuilder.
46       *
47       * @param queryBuilder the query builder to wrap (must be BoolQueryBuilder or DisMaxQueryBuilder)
48       * @throws IllegalArgumentException if the query builder type is not supported
49       */
50      public DefaultQueryBuilder(final QueryBuilder queryBuilder) {
51          this.queryBuilder = queryBuilder;
52          if (queryBuilder instanceof BoolQueryBuilder) {
53              queryType = QueryType.BOOL;
54          } else if (queryBuilder instanceof DisMaxQueryBuilder) {
55              queryType = QueryType.DISMAX;
56          } else {
57              throw new IllegalArgumentException("Unknown query builder: " + queryBuilder);
58          }
59      }
60  
61      /**
62       * Adds an inner query builder to the wrapped query.
63       * For BoolQueryBuilder, adds as a should clause.
64       * For DisMaxQueryBuilder, adds as a query.
65       *
66       * @param innerQueryBuilder the query builder to add
67       * @return this instance for method chaining
68       */
69      public DefaultQueryBuilder add(final QueryBuilder innerQueryBuilder) {
70          switch (queryType) {
71          case BOOL:
72              ((BoolQueryBuilder) queryBuilder).should(innerQueryBuilder);
73              break;
74          case DISMAX:
75              ((DisMaxQueryBuilder) queryBuilder).add(innerQueryBuilder);
76              break;
77          default:
78              break;
79          }
80          return this;
81      }
82  
83      /**
84       * Enumeration of supported query types.
85       */
86      enum QueryType {
87          /** Boolean query type. */
88          BOOL,
89          /** DisMax query type. */
90          DISMAX;
91      }
92  
93      /**
94       * Returns the writeable name of the wrapped query builder.
95       *
96       * @return the writeable name
97       */
98      @Override
99      public String getWriteableName() {
100         return queryBuilder.getWriteableName();
101     }
102 
103     /**
104      * Creates a Lucene Query from this query builder.
105      *
106      * @param context the query shard context
107      * @return the Lucene Query
108      * @throws IOException if an I/O error occurs
109      */
110     @Override
111     public Query toQuery(final QueryShardContext context) throws IOException {
112         return queryBuilder.toQuery(context);
113     }
114 
115     /**
116      * Returns whether this query builder is a fragment.
117      *
118      * @return true if this is a fragment, false otherwise
119      */
120     @Override
121     public boolean isFragment() {
122         return queryBuilder.isFragment();
123     }
124 
125     /**
126      * Sets the query name.
127      *
128      * @param queryName the query name to set
129      * @return the query builder
130      */
131     @Override
132     public QueryBuilder queryName(final String queryName) {
133         return queryBuilder.queryName(queryName);
134     }
135 
136     /**
137      * Returns the query name.
138      *
139      * @return the query name
140      */
141     @Override
142     public String queryName() {
143         return queryBuilder.queryName();
144     }
145 
146     /**
147      * Returns the boost value.
148      *
149      * @return the boost value
150      */
151     @Override
152     public float boost() {
153         return queryBuilder.boost();
154     }
155 
156     /**
157      * Sets the boost value.
158      *
159      * @param boost the boost value to set
160      * @return the query builder
161      */
162     @Override
163     public QueryBuilder boost(final float boost) {
164         return queryBuilder.boost(boost);
165     }
166 
167     /**
168      * Applies a filter to the query.
169      *
170      * @param filter the filter query builder
171      * @return the query builder
172      */
173     @Override
174     public QueryBuilder filter(QueryBuilder filter) {
175         return queryBuilder.filter(filter);
176     }
177 
178     /**
179      * Returns the name of the query.
180      *
181      * @return the query name
182      */
183     @Override
184     public String getName() {
185         return queryBuilder.getName();
186     }
187 
188     /**
189      * Rewrites the query using the provided rewrite context.
190      *
191      * @param queryShardContext the query rewrite context
192      * @return the rewritten query builder
193      * @throws IOException if an I/O error occurs during rewriting
194      */
195     @Override
196     public QueryBuilder rewrite(final QueryRewriteContext queryShardContext) throws IOException {
197         return queryBuilder.rewrite(queryShardContext);
198     }
199 
200     @Override
201     public void visit(final QueryBuilderVisitor visitor) {
202         queryBuilder.visit(visitor);
203     }
204 
205     @Override
206     public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
207         return queryBuilder.toXContent(builder, params);
208     }
209 
210     @Override
211     public void writeTo(final StreamOutput out) throws IOException {
212         queryBuilder.writeTo(out);
213     }
214 
215     @Override
216     public int hashCode() {
217         return queryBuilder.hashCode();
218     }
219 
220     @Override
221     public boolean equals(final Object obj) {
222         if (this == obj) {
223             return true;
224         }
225         if (obj == null || getClass() != obj.getClass()) {
226             return false;
227         }
228         final DefaultQueryBuilder other = (DefaultQueryBuilder) obj;
229         return Objects.equals(queryBuilder, other.queryBuilder);
230     }
231 
232     @Override
233     public String toString() {
234         return queryBuilder.toString();
235     }
236 
237 }