123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- /*
- * Copyright 2013 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.gitblit.tickets;
-
- import com.gitblit.utils.StringUtils;
-
- /**
- * A Lucene query builder.
- *
- * @author James Moger
- *
- */
- public class QueryBuilder {
-
- private final QueryBuilder parent;
- private String q;
- private transient StringBuilder sb;
- private int opCount;
-
- public static QueryBuilder q(String kernel) {
- return new QueryBuilder(kernel);
- }
-
- private QueryBuilder(QueryBuilder parent) {
- this.sb = new StringBuilder();
- this.parent = parent;
- }
-
- public QueryBuilder() {
- this("");
- }
-
- public QueryBuilder(String query) {
- this.sb = new StringBuilder(query == null ? "" : query);
- this.parent = null;
- }
-
- public boolean containsField(String field) {
- return sb.toString().contains(field + ":");
- }
-
- /**
- * Creates a new AND subquery. Make sure to call endSubquery to
- * get return *this* query.
- *
- * e.g. field:something AND (subquery)
- *
- * @return a subquery
- */
- public QueryBuilder andSubquery() {
- sb.append(" AND (");
- return new QueryBuilder(this);
- }
-
- /**
- * Creates a new OR subquery. Make sure to call endSubquery to
- * get return *this* query.
- *
- * e.g. field:something OR (subquery)
- *
- * @return a subquery
- */
- public QueryBuilder orSubquery() {
- sb.append(" OR (");
- return new QueryBuilder(this);
- }
-
- /**
- * Ends a subquery and returns the parent query.
- *
- * @return the parent query
- */
- public QueryBuilder endSubquery() {
- this.q = sb.toString().trim();
- if (q.length() > 0) {
- parent.sb.append(q).append(')');
- }
- return parent;
- }
-
- /**
- * Append an OR condition.
- *
- * @param condition
- * @return
- */
- public QueryBuilder or(String condition) {
- return op(condition, " OR ");
- }
-
- /**
- * Append an AND condition.
- *
- * @param condition
- * @return
- */
- public QueryBuilder and(String condition) {
- return op(condition, " AND ");
- }
-
- /**
- * Append an AND NOT condition.
- *
- * @param condition
- * @return
- */
- public QueryBuilder andNot(String condition) {
- return op(condition, " AND NOT ");
- }
-
- /**
- * Nest this query as a subquery.
- *
- * e.g. field:something AND field2:something else
- * ==> (field:something AND field2:something else)
- *
- * @return this query nested as a subquery
- */
- public QueryBuilder toSubquery() {
- if (opCount > 1) {
- sb.insert(0, '(').append(')');
- }
- return this;
- }
-
- /**
- * Nest this query as an AND subquery of the condition
- *
- * @param condition
- * @return the query nested as an AND subquery of the specified condition
- */
- public QueryBuilder subqueryOf(String condition) {
- if (!StringUtils.isEmpty(condition)) {
- toSubquery().and(condition);
- }
- return this;
- }
-
- /**
- * Removes a condition from the query.
- *
- * @param condition
- * @return the query
- */
- public QueryBuilder remove(String condition) {
- int start = sb.indexOf(condition);
- if (start == 0) {
- // strip first condition
- sb.replace(0, condition.length(), "");
- } else if (start > 1) {
- // locate condition in query
- int space1 = sb.lastIndexOf(" ", start - 1);
- int space0 = sb.lastIndexOf(" ", space1 - 1);
- if (space0 > -1 && space1 > -1) {
- String conjunction = sb.substring(space0, space1).trim();
- if ("OR".equals(conjunction) || "AND".equals(conjunction)) {
- // remove the conjunction
- sb.replace(space0, start + condition.length(), "");
- } else {
- // unknown conjunction
- sb.replace(start, start + condition.length(), "");
- }
- } else {
- sb.replace(start, start + condition.length(), "");
- }
- }
- return this;
- }
-
- /**
- * Generate the return the Lucene query.
- *
- * @return the generated query
- */
- public String build() {
- if (parent != null) {
- throw new IllegalAccessError("You can not build a subquery! endSubquery() instead!");
- }
- this.q = sb.toString().trim();
-
- // cleanup paranthesis
- while (q.contains("()")) {
- q = q.replace("()", "");
- }
- if (q.length() > 0) {
- if (q.charAt(0) == '(' && q.charAt(q.length() - 1) == ')') {
- // query is wrapped by unnecessary paranthesis
- q = q.substring(1, q.length() - 1);
- }
- }
- return q;
- }
-
- private QueryBuilder op(String condition, String op) {
- opCount++;
- if (!StringUtils.isEmpty(condition)) {
- if (sb.length() != 0) {
- sb.append(op);
- }
- sb.append(condition);
- }
- return this;
- }
-
- @Override
- public String toString() {
- return sb.toString().trim();
- }
- }
|