/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* bdelbosc
*/
package org.nuxeo.elasticsearch.query;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.query.sql.NXQL;
import org.nuxeo.ecm.core.schema.utils.DateParser;
import org.nuxeo.ecm.platform.query.api.PredicateDefinition;
import org.nuxeo.ecm.platform.query.api.PredicateFieldDefinition;
import org.nuxeo.ecm.platform.query.api.WhereClauseDefinition;
import org.nuxeo.ecm.platform.query.nxql.NXQLQueryBuilder;
/**
* Elasticsearch query builder for Native Page provider.
*/
public class PageProviderQueryBuilder {
private PageProviderQueryBuilder() {
}
/**
* Create a ES request from a PP pattern
*/
public static QueryBuilder makeQuery(final String pattern, final Object[] params,
final boolean quotePatternParameters, final boolean escapePatternParameters, final boolean useNativeQuery) {
String query = pattern;
if (params != null) {
for (Object param : params) {
query = query.replaceFirst("\\?", convertParam(param, quotePatternParameters));
}
}
if (useNativeQuery) {
return QueryBuilders.queryStringQuery(query);
} else {
return NxqlQueryConverter.toESQueryBuilder(query);
}
}
/**
* Create a ES request from a PP whereClause
*/
public static QueryBuilder makeQuery(final DocumentModel model, final WhereClauseDefinition whereClause,
final Object[] params, final boolean useNativeQuery) {
return makeQuery(model, whereClause, null, params, useNativeQuery);
}
/**
* @since 8.4
*/
public static QueryBuilder makeQuery(final DocumentModel model, final WhereClauseDefinition whereClause,
final String additionalFixedPart, final Object[] params, final boolean useNativeQuery) {
assert (model != null);
assert (whereClause != null);
NxqlQueryConverter.ExpressionBuilder eb = new NxqlQueryConverter.ExpressionBuilder("AND");
String fixedPart = whereClause.getFixedPart();
if (!StringUtils.isBlank(additionalFixedPart)) {
fixedPart = (!StringUtils.isBlank(fixedPart))
? NXQLQueryBuilder.appendClause(fixedPart, additionalFixedPart) : additionalFixedPart;
}
if (params != null) {
for (Object param : params) {
fixedPart = fixedPart.replaceFirst("\\?", convertParam(param, true));
}
if (useNativeQuery) {
// Fixed part handled as query_string
eb.add(QueryBuilders.queryStringQuery(fixedPart));
} else {
eb.add(NxqlQueryConverter.toESQueryBuilder(fixedPart));
}
}
// Process predicates
for (PredicateDefinition predicate : whereClause.getPredicates()) {
PredicateFieldDefinition[] fieldDef = predicate.getValues();
Object[] values = new Object[fieldDef.length];
for (int fidx = 0; fidx < fieldDef.length; fidx++) {
if (fieldDef[fidx].getXpath() != null) {
values[fidx] = model.getPropertyValue(fieldDef[fidx].getXpath());
} else {
values[fidx] = model.getProperty(fieldDef[fidx].getSchema(), fieldDef[fidx].getName());
}
}
if (!isNonNullParam(values)) {
// skip predicate where all values are null
continue;
}
Object value = values[0];
if (values[0] instanceof Collection<?>) {
Collection<?> vals = (Collection<?>) values[0];
values = vals.toArray(new Object[vals.size()]);
} else if (values[0] instanceof Object[]) {
values = (Object[]) values[0];
}
String name = predicate.getParameter();
String operator = predicate.getOperator().toUpperCase();
if ("FULLTEXT".equals(operator) || "FULLTEXT ALL".equals(operator)) {
operator = "=";
if (!name.startsWith(NXQL.ECM_FULLTEXT)) {
name = NXQL.ECM_FULLTEXT + "." + name;
}
}
eb.add(NxqlQueryConverter.makeQueryFromSimpleExpression(operator, name, value, values, null, null));
}
return eb.get();
}
/**
* Convert a params for fixed part
*/
protected static String convertParam(final Object param, boolean quote) {
String ret;
if (param == null) {
ret = "";
} else if (param instanceof List<?>) {
StringBuilder stringBuilder = new StringBuilder("");
NXQLQueryBuilder.appendStringList(stringBuilder, (List<?>) param, quote, true);
ret = stringBuilder.toString();
// quote is already taken in account
quote = false;
} else if (param instanceof Calendar) {
ret = DateParser.formatW3CDateTime(((Calendar) param).getTime());
} else {
ret = param.toString();
}
if (quote && param instanceof String) {
ret = "\"" + ret + "\"";
}
return ret;
}
@SuppressWarnings("rawtypes")
protected static boolean isNonNullParam(final Object[] val) {
if (val == null) {
return false;
}
for (Object v : val) {
if (v != null) {
if (v instanceof String) {
if (!((String) v).isEmpty()) {
return true;
}
} else if (v instanceof String[]) {
if (((String[]) v).length > 0) {
return true;
}
} else if (v instanceof Collection) {
if (!((Collection) v).isEmpty()) {
return true;
}
} else {
return true;
}
}
}
return false;
}
}