<commit_before>package net.canadensys.query.interpreter;

import java.util.ArrayList;
import java.util.List;

import net.canadensys.databaseutils.PostgisUtils;
import net.canadensys.query.QueryOperatorEnum;
import net.canadensys.query.SearchQueryPart;
import net.canadensys.query.SearchableField;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;

/**
 * Interprets a SearchQueryPart representing a geospatial query where we target a polygon. 
 * @author canadensys
 *
 */
public class InsidePolygonFieldInterpreter implements QueryPartInterpreter{
	
	//get log4j handler
	private static final Logger LOGGER = Logger.getLogger(InsidePolygonFieldInterpreter.class);
	
	/**
	 * Needs at least one related field and type should not be specified.
	 */
	@Override
	public boolean canHandleSearchableField(SearchableField searchableField) {
		return (searchableField.getRelatedFields() != null && 
				searchableField.getRelatedFields().size() >= 1 &&
				searchableField.getType() == null);
	}
	
	@Override
	public boolean canHandleSearchQueryPart(SearchQueryPart searchQueryPart) {
		
		if(!canHandleSearchableField(searchQueryPart.getSearchableField()) || 
			!QueryOperatorEnum.IN.equals(searchQueryPart.getOp())){
			return false;
		}
		
		//validate that the parsedValue are in the right type(class)
		List<String> valueList = searchQueryPart.getValueList();
		Object parsedValue = null;
		//get the parsed value of the first SearchableField only (e.g. the_geom)
		String searchableFieldKey = searchQueryPart.getSearchableField().getRelatedFields().get(0);
		for(String currValue : valueList){
			parsedValue = searchQueryPart.getParsedValue(currValue, searchableFieldKey);
			if(parsedValue instanceof Pair){
				Pair<?,?> a = (Pair<?,?>)parsedValue;
				if(!String.class.equals(a.getLeft().getClass()) ||
						!String.class.equals(a.getRight().getClass())){
					return false;
				}
			}
			else{
				return false;
			}
		}
		return true;
	}
	
	@Override
	public Criterion toCriterion(SearchQueryPart searchQueryPart) {
		String sqlCmd = toSQL(searchQueryPart);
		if(sqlCmd == null){
			return null;
		}
		return Restrictions.sqlRestriction(sqlCmd);
	}

	@SuppressWarnings("unchecked")
	@Override
	public String toSQL(SearchQueryPart searchQueryPart) {
		
		if(!canHandleSearchQueryPart(searchQueryPart)){
			LOGGER.error("Can't handle QueryPart : " + searchQueryPart);
			return null;
		}	
		
		List<Pair<String,String>> polygon = new ArrayList<Pair<String,String>>();
		SearchableField searchableField = searchQueryPart.getSearchableField();
		
		List<String> valueList = searchQueryPart.getValueList();
		Object parsedValue = null;
		for(String currValue : valueList){
			parsedValue = searchQueryPart.getParsedValue(currValue);
			polygon.add((Pair<String,String>)parsedValue);
		}
		String geomColumn = searchableField.getRelatedField();
		return PostgisUtils.getInsidePolygonSQLClause(geomColumn, polygon, true);
	}
}<commit_msg>use new SearchQueryPart hints to check IDL<commit_after>package net.canadensys.query.interpreter;

import java.util.ArrayList;
import java.util.List;

import net.canadensys.databaseutils.PostgisUtils;
import net.canadensys.query.QueryOperatorEnum;
import net.canadensys.query.SearchQueryPart;
import net.canadensys.query.SearchableField;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;

/**
 * Interprets a SearchQueryPart representing a geospatial query where we target a polygon.
 * If the polygon is crossing the IDL, make sure to add the hint IS_CROSSING_IDL_HINT so the 
 * interpreter can use the shifted_geom column.
 * @author canadensys
 *
 */
public class InsidePolygonFieldInterpreter implements QueryPartInterpreter{
	
	//get log4j handler
	private static final Logger LOGGER = Logger.getLogger(InsidePolygonFieldInterpreter.class);
	
	public static final String IS_CROSSING_IDL_HINT = "isCrossingIDL";
	public static final int GEOM_FIELD_IDX = 0;
	public static final int SHIFTED_GEOM_FIELD_IDX = 1;
	
	/**
	 * Needs at least one related field and type should not be specified.
	 */
	@Override
	public boolean canHandleSearchableField(SearchableField searchableField) {
		return (searchableField.getRelatedFields() != null && 
				searchableField.getRelatedFields().size() >= 1 &&
				searchableField.getType() == null);
	}
	
	@Override
	public boolean canHandleSearchQueryPart(SearchQueryPart searchQueryPart) {
		
		if(!canHandleSearchableField(searchQueryPart.getSearchableField()) || 
			!QueryOperatorEnum.IN.equals(searchQueryPart.getOp())){
			return false;
		}
		
		//validate that the parsedValue are in the right type(class)
		List<String> valueList = searchQueryPart.getValueList();
		Object parsedValue = null;
		//get the parsed value of the first SearchableField only (e.g. the_geom)
		String searchableFieldKey = searchQueryPart.getSearchableField().getRelatedFields().get(GEOM_FIELD_IDX);
		for(String currValue : valueList){
			parsedValue = searchQueryPart.getParsedValue(currValue, searchableFieldKey);
			if(parsedValue instanceof Pair){
				Pair<?,?> a = (Pair<?,?>)parsedValue;
				if(!String.class.equals(a.getLeft().getClass()) ||
						!String.class.equals(a.getRight().getClass())){
					return false;
				}
			}
			else{
				return false;
			}
		}
		return true;
	}
	
	@Override
	public Criterion toCriterion(SearchQueryPart searchQueryPart) {
		String sqlCmd = toSQL(searchQueryPart);
		if(sqlCmd == null){
			return null;
		}
		return Restrictions.sqlRestriction(sqlCmd);
	}

	@SuppressWarnings("unchecked")
	@Override
	public String toSQL(SearchQueryPart searchQueryPart) {
		
		if(!canHandleSearchQueryPart(searchQueryPart)){
			LOGGER.error("Can't handle QueryPart : " + searchQueryPart);
			return null;
		}	
		
		List<Pair<String,String>> polygon = new ArrayList<Pair<String,String>>();
		SearchableField searchableField = searchQueryPart.getSearchableField();
		String geomColumn = searchableField.getRelatedFields().get(GEOM_FIELD_IDX);
		List<String> valueList = searchQueryPart.getValueList();
		
		Object parsedValue = null;
		for(String currValue : valueList){
			parsedValue = searchQueryPart.getParsedValue(currValue,geomColumn);
			polygon.add((Pair<String,String>)parsedValue);
		}
		
		//If the polygon is crossing the IDL, we use the shiftedGeomColumn.
		if(BooleanUtils.toBoolean((Boolean)searchQueryPart.getHint(IS_CROSSING_IDL_HINT))){
			String shiftedGeomColumn = searchableField.getRelatedFields().get(SHIFTED_GEOM_FIELD_IDX);
			return PostgisUtils.getInsidePolygonSQLClause(shiftedGeomColumn, polygon, true);
		}
		return PostgisUtils.getInsidePolygonSQLClause(geomColumn, polygon, false);
	}
}
{'fraction_non_alphanumeric': 0.10254545454545455, 'fraction_numerical': 0.0017454545454545455, 'mean_word_length': 5.290942360475754, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7395235', 'n_tokens_mistral': 2325, 'n_tokens_neox': 2095, 'n_words': 439}