From 865b94a1bc460efb0fd83143c61d76c72ab66cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20T=C3=A1rraga=20Gim=C3=A9nez?= Date: Mon, 28 Oct 2024 09:03:45 +0100 Subject: [PATCH] datastore: set range format to field[start..end]:step, #TASK-7151, #TASK-7134 --- .../MongoDBFacetToFacetFieldsConverter.java | 2 +- .../datastore/mongodb/MongoDBQueryUtils.java | 37 ++++++++++++++----- .../mongodb/MongoDBCollectionTest.java | 27 +++++++++++--- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBFacetToFacetFieldsConverter.java b/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBFacetToFacetFieldsConverter.java index d10ba290..c02757f7 100644 --- a/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBFacetToFacetFieldsConverter.java +++ b/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBFacetToFacetFieldsConverter.java @@ -70,7 +70,7 @@ public List convertToDataModelType(Document document) { } key = key.substring(0, key.length() - RANGES_SUFFIX.length()).replace(GenericDocumentComplexConverter.TO_REPLACE_DOTS, "."); if (other != null) { - key += " (out of range = " + other + ")"; + key += " (counts out of range: " + other + ")"; } FacetField facetField = new FacetField(key, "range", facetFieldValues) .setStart(start) diff --git a/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBQueryUtils.java b/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBQueryUtils.java index e44900ac..b80be5f0 100644 --- a/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBQueryUtils.java +++ b/commons-datastore/commons-datastore-mongodb/src/main/java/org/opencb/commons/datastore/mongodb/MongoDBQueryUtils.java @@ -49,7 +49,14 @@ public class MongoDBQueryUtils { private static final Pattern OPERATION_DATE_PATTERN = Pattern.compile("^(<=?|>=?|!=|!?=?~|=?=?)([0-9]+)(-?)([0-9]*)"); private static final Pattern FUNC_ACCUMULATOR_PATTERN = Pattern.compile("([a-zA-Z]+)\\(([.a-zA-Z0-9]+)\\)"); - private static final Pattern RANGE_PATTERN = Pattern.compile("([.a-zA-Z0-9]+)\\[([.0-9]+):([.0-9]+)\\]:([.0-9]+)"); + private static final String RANGE_MARK = ".."; + private static final String RANGE_MARK1 = "["; + private static final String RANGE_MARK2 = "]"; + private static final String RANGE_SPLIT_MARK = "\\.\\."; + private static final Pattern RANGE_START_PATTERN = Pattern.compile("([.a-zA-Z0-9]+)\\[([.0-9]+)"); + private static final Pattern RANGE_END_PATTERN = Pattern.compile("([.0-9]+)\\]:([.0-9]+)"); + public static final String INVALID_FORMAT_MSG = "Invalid format "; + public static final String RANGE_FORMAT_MSG = " for range aggregation. Valid format is: field[start..end]:step, e.g: size[0..1000]:200"; public static final String INTERNAL_ID = "_id"; public static final String AND_SEPARATOR = "_and_"; @@ -704,15 +711,25 @@ private static List createFacet(Bson query, List facetFields) { accumulator = Accumulator.valueOf(matcher.group(1)); field = matcher.group(2); } else { - matcher = RANGE_PATTERN.matcher(facetField); - if (matcher.matches()) { - accumulator = bucket; - field = matcher.group(1); - double start = Double.parseDouble(matcher.group(2)); - double end = Double.parseDouble(matcher.group(3)); - double step = Double.parseDouble(matcher.group(4)); - for (double i = start; i <= end; i += step) { - boundaries.add(i); + if (facetField.contains(RANGE_MARK) || facetField.contains(RANGE_MARK1) || facetField.contains(RANGE_MARK2)) { + String[] split = facetField.split(RANGE_SPLIT_MARK); + if (split.length == 2) { + Matcher matcher1 = RANGE_START_PATTERN.matcher(split[0]); + Matcher matcher2 = RANGE_END_PATTERN.matcher(split[1]); + if (matcher1.matches() && matcher2.matches()) { + accumulator = bucket; + field = matcher1.group(1); + double start = Double.parseDouble(matcher1.group(2)); + double end = Double.parseDouble(matcher2.group(1)); + double step = Double.parseDouble(matcher2.group(2)); + for (double i = start; i <= end; i += step) { + boundaries.add(i); + } + } else { + throw new IllegalArgumentException(INVALID_FORMAT_MSG + facetField + RANGE_FORMAT_MSG); + } + } else { + throw new IllegalArgumentException(INVALID_FORMAT_MSG + facetField + RANGE_FORMAT_MSG); } } else { accumulator = count; diff --git a/commons-datastore/commons-datastore-mongodb/src/test/java/org/opencb/commons/datastore/mongodb/MongoDBCollectionTest.java b/commons-datastore/commons-datastore-mongodb/src/test/java/org/opencb/commons/datastore/mongodb/MongoDBCollectionTest.java index 9f51cee6..434d84fa 100644 --- a/commons-datastore/commons-datastore-mongodb/src/test/java/org/opencb/commons/datastore/mongodb/MongoDBCollectionTest.java +++ b/commons-datastore/commons-datastore-mongodb/src/test/java/org/opencb/commons/datastore/mongodb/MongoDBCollectionTest.java @@ -480,13 +480,13 @@ public void testFacet() { Document match = new Document("age", new BasicDBObject("$gt", 2)); // Document match = new Document("house.m2", new BasicDBObject("$gt", 10000)); // List facets = MongoDBQueryUtils.createFacet(match, ""); -// List facets = MongoDBQueryUtils.createFacet(match, "count(name);name,surname;avg(age);min(age);max(age);number[0:1000000]:100000"); +// List facets = MongoDBQueryUtils.createFacet(match, "count(name);name,surname;avg(age);min(age);max(age);number[0..1000000]100000"); // List facets = MongoDBQueryUtils.createFacet(match, "name,surname"); // List facets = MongoDBQueryUtils.createFacet(match, "avg(house.numRooms)"); // List facets = MongoDBQueryUtils.createFacet(match, "avg(house.m2)"); // List facets = MongoDBQueryUtils.createFacet(match, "name,house.color"); - List facetsWithDots = MongoDBQueryUtils.createFacet(match, "avg(house.numRooms);count(house.color);name,house.color;avg(house.m2);min(house.m2);max(house.m2);house.m2[0:20000]:1000"); - // List facets = MongoDBQueryUtils.createFacet(match, "house.m2[0:20000]:1000"); + List facetsWithDots = MongoDBQueryUtils.createFacet(match, "avg(house.numRooms);count(house.color);name,house.color;avg(house.m2);min(house.m2);max(house.m2);house.m2[0..20000]:1000"); + // List facets = MongoDBQueryUtils.createFacet(match, "house.m2[0..20000]:1000"); System.out.println("facetsWithDots = " + facetsWithDots); @@ -532,11 +532,11 @@ public void testFacetUsingConverter() { Document match = new Document("age", new BasicDBObject("$gt", 2)); // Document match = new Document("house.m2", new BasicDBObject("$gt", 10000)); // List facets = MongoDBQueryUtils.createFacet(match, ""); - List facets = MongoDBQueryUtils.createFacet(match, "count(name);name,surname;avg(age);min(age);max(age);number[0:1000000]:100000"); +// List facets = MongoDBQueryUtils.createFacet(match, "count(name);name,surname;avg(age);min(age);max(age);number[0..1000000]:100000"); // List facets = MongoDBQueryUtils.createFacet(match, "avg(house.m2);name;name,surname"); // List facets = MongoDBQueryUtils.createFacet(match, "avg(house.numRooms)"); // List facets = MongoDBQueryUtils.createFacet(match, "avg(house.m2);name"); -// List facets = MongoDBQueryUtils.createFacet(match, "house.m2[0:20000]:1000"); + List facets = MongoDBQueryUtils.createFacet(match, "house.m2[0..20000]:1000"); MongoDBFacetToFacetFieldsConverter converter = new MongoDBFacetToFacetFieldsConverter(); DataResult> aggregate = mongoDBCollection.aggregate(facets, converter, null); @@ -548,6 +548,23 @@ public void testFacetUsingConverter() { } } + @Test(expected = IllegalArgumentException.class) + public void testFacetInvalidRangeFormat() { + Document match = new Document("age", new BasicDBObject("$gt", 2)); + MongoDBQueryUtils.createFacet(match, "house.m2[toto0..20000]:1000"); + } + + @Test(expected = IllegalArgumentException.class) + public void testFacetInvalidRangeFormat1() { + Document match = new Document("age", new BasicDBObject("$gt", 2)); + MongoDBQueryUtils.createFacet(match, "house.m2[0:20000]:1000"); + } + + @Test(expected = IllegalArgumentException.class) + public void testFacetInvalidRangeFormat2() { + Document match = new Document("age", new BasicDBObject("$gt", 2)); + MongoDBQueryUtils.createFacet(match, "house.m2[toto0..20000]..1000"); + } @Test public void testInsert() throws Exception {