001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bdelbosc 018 */ 019 020package org.nuxeo.elasticsearch.query; 021 022import java.util.Calendar; 023import java.util.Collection; 024import java.util.List; 025 026import org.elasticsearch.index.query.QueryBuilder; 027import org.elasticsearch.index.query.QueryBuilders; 028import org.nuxeo.ecm.core.api.DocumentModel; 029import org.nuxeo.ecm.core.query.sql.NXQL; 030import org.nuxeo.ecm.core.schema.utils.DateParser; 031import org.nuxeo.ecm.platform.query.api.PredicateDefinition; 032import org.nuxeo.ecm.platform.query.api.PredicateFieldDefinition; 033import org.nuxeo.ecm.platform.query.api.WhereClauseDefinition; 034import org.nuxeo.ecm.platform.query.nxql.NXQLQueryBuilder; 035 036/** 037 * Elasticsearch query builder for Native Page provider. 038 */ 039public class PageProviderQueryBuilder { 040 041 private PageProviderQueryBuilder() { 042 } 043 044 /** 045 * Create a ES request from a PP pattern 046 */ 047 public static QueryBuilder makeQuery(final String pattern, final Object[] params, 048 final boolean quotePatternParameters, final boolean escapePatternParameters, final boolean useNativeQuery) { 049 String query = pattern; 050 if (params != null) { 051 for (Object param : params) { 052 query = query.replaceFirst("\\?", convertParam(param, quotePatternParameters)); 053 } 054 } 055 if (useNativeQuery) { 056 return QueryBuilders.queryStringQuery(query); 057 } else { 058 return NxqlQueryConverter.toESQueryBuilder(query); 059 } 060 } 061 062 /** 063 * Create a ES request from a PP whereClause 064 */ 065 public static QueryBuilder makeQuery(final DocumentModel model, final WhereClauseDefinition whereClause, 066 final Object[] params, final boolean useNativeQuery) { 067 assert (model != null); 068 assert (whereClause != null); 069 NxqlQueryConverter.ExpressionBuilder eb = new NxqlQueryConverter.ExpressionBuilder("AND"); 070 String fixedPart = whereClause.getFixedPart(); 071 if (params != null) { 072 for (Object param : params) { 073 fixedPart = fixedPart.replaceFirst("\\?", convertParam(param, true)); 074 } 075 if (useNativeQuery) { 076 // Fixed part handled as query_string 077 eb.add(QueryBuilders.queryStringQuery(fixedPart)); 078 } else { 079 eb.add(NxqlQueryConverter.toESQueryBuilder(fixedPart)); 080 } 081 } 082 // Process predicates 083 for (PredicateDefinition predicate : whereClause.getPredicates()) { 084 PredicateFieldDefinition[] fieldDef = predicate.getValues(); 085 Object[] values = new Object[fieldDef.length]; 086 for (int fidx = 0; fidx < fieldDef.length; fidx++) { 087 if (fieldDef[fidx].getXpath() != null) { 088 values[fidx] = model.getPropertyValue(fieldDef[fidx].getXpath()); 089 } else { 090 values[fidx] = model.getProperty(fieldDef[fidx].getSchema(), fieldDef[fidx].getName()); 091 } 092 } 093 if (!isNonNullParam(values)) { 094 // skip predicate where all values are null 095 continue; 096 } 097 Object value = values[0]; 098 if (values[0] instanceof Collection<?>) { 099 Collection<?> vals = (Collection<?>) values[0]; 100 values = vals.toArray(new Object[vals.size()]); 101 } else if (values[0] instanceof Object[]) { 102 values = (Object[]) values[0]; 103 } 104 String name = predicate.getParameter(); 105 String operator = predicate.getOperator().toUpperCase(); 106 if ("FULLTEXT".equals(operator) || "FULLTEXT ALL".equals(operator)) { 107 operator = "="; 108 if (!name.startsWith(NXQL.ECM_FULLTEXT)) { 109 name = NXQL.ECM_FULLTEXT + "." + name; 110 } 111 } 112 eb.add(NxqlQueryConverter.makeQueryFromSimpleExpression(operator, name, value, values, null, null)); 113 } 114 return eb.get(); 115 } 116 117 /** 118 * Convert a params for fixed part 119 */ 120 protected static String convertParam(final Object param, boolean quote) { 121 String ret; 122 if (param == null) { 123 ret = ""; 124 } else if (param instanceof List<?>) { 125 StringBuilder stringBuilder = new StringBuilder(""); 126 NXQLQueryBuilder.appendStringList(stringBuilder, (List<?>) param, quote, true); 127 ret = stringBuilder.toString(); 128 // quote is already taken in account 129 quote = false; 130 } else if (param instanceof Calendar) { 131 ret = DateParser.formatW3CDateTime(((Calendar) param).getTime()); 132 } else { 133 ret = param.toString(); 134 } 135 if (quote && param instanceof String) { 136 ret = "\"" + ret + "\""; 137 } 138 return ret; 139 } 140 141 @SuppressWarnings("rawtypes") 142 protected static boolean isNonNullParam(final Object[] val) { 143 if (val == null) { 144 return false; 145 } 146 for (Object v : val) { 147 if (v != null) { 148 if (v instanceof String) { 149 if (!((String) v).isEmpty()) { 150 return true; 151 } 152 } else if (v instanceof String[]) { 153 if (((String[]) v).length > 0) { 154 return true; 155 } 156 } else if (v instanceof Collection) { 157 if (!((Collection) v).isEmpty()) { 158 return true; 159 } 160 } else { 161 return true; 162 } 163 } 164 } 165 return false; 166 } 167 168}