package se.kodapan.lucene.query; import org.apache.lucene.index.Term; import org.apache.lucene.search.*; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; /** * @author kalle * @since 2014-09-10 18:20 */ public class JSONQueryUnmarshaller { public Query parse(JSONObject jsonQuery) throws JSONException { String type = jsonQuery.getString("type"); if ("boolean query".equalsIgnoreCase(type)) { BooleanQuery booleanQuery = new BooleanQuery(); JSONArray jsonClauses = jsonQuery.getJSONArray("clauses"); for (int i = 0; i < jsonClauses.length(); i++) { JSONObject jsonClause = jsonClauses.getJSONObject(i); BooleanClause.Occur occur; String jsonOccur = jsonClause.getString("occur"); if (jsonOccur.equalsIgnoreCase("must")) { occur = BooleanClause.Occur.MUST; } else if (jsonOccur.equalsIgnoreCase("should")) { occur = BooleanClause.Occur.SHOULD; } else if (jsonOccur.equalsIgnoreCase("must not")) { occur = BooleanClause.Occur.MUST_NOT; } else { throw new IllegalArgumentException("Expected occurs with value 'must', 'should' or 'must not', but was '" + jsonOccur + "'."); } booleanQuery.add(new BooleanClause(parse(jsonClause.getJSONObject("query")), occur)); } return booleanQuery; } else if ("match all documents".equalsIgnoreCase(type)) { return new MatchAllDocsQuery(); } else if ("term".equalsIgnoreCase(type)) { return new TermQuery(new Term(jsonQuery.getString("field"), jsonQuery.getString("value"))); } else if ("coordinate envelope".equalsIgnoreCase(type)) { return new CoordinateEnvelopeQueryFactory() .setLatitudeField(jsonQuery.getString("latitudeField")) .setLongitudeField(jsonQuery.getString("longitudeField")) .setSouth(jsonQuery.getDouble("southLatitude")) .setWest(jsonQuery.getDouble("westLongitude")) .setNorth(jsonQuery.getDouble("northLatitude")) .setEast(jsonQuery.getDouble("eastLongitude")) .build(); } else if ("coordinate circle envelope".equalsIgnoreCase(type)) { return new CoordinateCircleEnvelopeQueryFactory() .setLatitudeField(jsonQuery.getString("latitudeField")) .setLongitudeField(jsonQuery.getString("longitudeField")) .setCentroidLatitude(jsonQuery.getDouble("centroidLatitude")) .setCentroidLongitude(jsonQuery.getDouble("centroidLongitude")) .setRadiusKilometers(jsonQuery.getDouble("radiusKilometers")) .build(); } else if ("integer range".equalsIgnoreCase(type)) { int minimum = !jsonQuery.isNull("minimum") ? jsonQuery.getInt("minimum") : Integer.MIN_VALUE; boolean includeMinimum = !jsonQuery.has("includeMinimum") || jsonQuery.getBoolean("includeMinimum"); int maximum = !jsonQuery.isNull("maximum") ? jsonQuery.getInt("maximum") : Integer.MAX_VALUE; boolean includeMaximum = !jsonQuery.has("includeMaximum") || jsonQuery.getBoolean("includeMaximum"); return NumericRangeQuery.newIntRange(jsonQuery.getString("field"), minimum, maximum, includeMinimum, includeMaximum); } else if ("long range".equalsIgnoreCase(type)) { long minimum = !jsonQuery.isNull("minimum") ? jsonQuery.getLong("minimum") : Long.MIN_VALUE; boolean includeMinimum = !jsonQuery.has("includeMinimum") || jsonQuery.getBoolean("includeMinimum"); long maximum = !jsonQuery.isNull("maximum") ? jsonQuery.getLong("maximum") : Long.MAX_VALUE; boolean includeMaximum = !jsonQuery.has("includeMaximum") || jsonQuery.getBoolean("includeMaximum"); return NumericRangeQuery.newLongRange(jsonQuery.getString("field"), minimum, maximum, includeMinimum, includeMaximum); } else if ("float range".equalsIgnoreCase(type)) { float minimum = !jsonQuery.isNull("minimum") ? (float) jsonQuery.getDouble("minimum") : Float.MIN_VALUE; boolean includeMinimum = !jsonQuery.has("includeMinimum") || jsonQuery.getBoolean("includeMinimum"); float maximum = !jsonQuery.isNull("maximum") ? (float) jsonQuery.getDouble("maximum") : Float.MAX_VALUE; boolean includeMaximum = !jsonQuery.has("includeMaximum") || jsonQuery.getBoolean("includeMaximum"); return NumericRangeQuery.newFloatRange(jsonQuery.getString("field"), minimum, maximum, includeMinimum, includeMaximum); } else if ("double range".equalsIgnoreCase(type)) { double minimum = !jsonQuery.isNull("minimum") ? jsonQuery.getDouble("minimum") : Double.MIN_VALUE; boolean includeMinimum = !jsonQuery.has("includeMinimum") || jsonQuery.getBoolean("includeMinimum"); double maximum = !jsonQuery.isNull("maximum") ? jsonQuery.getDouble("maximum") : Double.MAX_VALUE; boolean includeMaximum = !jsonQuery.has("includeMaximum") || jsonQuery.getBoolean("includeMaximum"); return NumericRangeQuery.newDoubleRange(jsonQuery.getString("field"), minimum, maximum, includeMinimum, includeMaximum); } else { throw new IllegalArgumentException("Unsupported query type '" + type + "'."); } } }