diff --git a/.circleci/config.yml b/.circleci/config.yml index 8d92636..84d6c95 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,32 +7,34 @@ jobs: environment: JVM_OPTS: -Xmx3200m docker: - - image: circleci/openjdk:14-jdk-buster-node - + - image: circleci/openjdk:17-jdk-buster-node working_directory: ~/project - steps: - checkout - restore_cache: keys: - mongo-spring-search-{{ checksum "pom.xml" }} - mongo-spring-search- - - - run: mvn dependency:go-offline - + - run: + name: Download dependencies + command: mvn dependency:go-offline - save_cache: paths: - ~/.m2 key: mongo-spring-search-{{ checksum "pom.xml" }} - - # run tests! - - run: mvn clean test + - run: + name: Run tests + command: mvn clean test + - store_artifacts: + path: target/surefire-reports + destination: surefire-reports - store_artifacts: - path: ~/project/target/coverage-reports - - codecov/upload: - file: ~/project/target/coverage-reports/jacoco/jacoco.xml - flags: coverage - upload_name: Coverage + path: target/coverage-reports + destination: coverage-reports + - run: + name: Upload coverage to Codecov + command: bash <(curl -s https://codecov.io/bash) -f target/coverage-reports/jacoco/jacoco.xml + workflows: version: 2 diff --git a/README.md b/README.md index 913006e..2dcd61f 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,18 @@ You could create custom repository methods to perform your searches. You could a ##### Maven -Include the dependency to your project inside your `pom.xml` file +Include the dependency to your project inside your `pom.xml` file. +For Java 17: +```xml + + io.github.ajclopez + mongo-spring-search + 2.0.0 + +``` + +For Java 14: ```xml io.github.ajclopez @@ -64,10 +74,20 @@ Include the dependency to your project inside your `pom.xml` file Add implementation to your project in your `build.gradle` file +For Java 17: +``` +implementation 'io.github.ajclopez:mongo-spring-search:2.0.0' +```` + +For Java 14: ``` implementation 'io.github.ajclopez:mongo-spring-search:1.0.5' ```` +#### Note +- **Version 2.x.x:** Requires Java 17. +- **Version 1.x.x:** Requires Java 14. + ## Usage Converts query into a MongoDB query object. diff --git a/pom.xml b/pom.xml index c7425af..1c06535 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.ajclopez mongo-spring-search - 1.0.5 + 2.0.0 jar mongo-spring-search @@ -29,16 +29,16 @@ UTF-8 - 14 - 4.13.1 - 3.4.5 - 4.9 + 17 + 5.10.2 + 4.3.0 + 4.13.1 - junit - junit + org.junit.jupiter + junit-jupiter-api ${junit.version} test @@ -62,16 +62,16 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.13.0 - 14 - 14 + 17 + 17 org.antlr antlr4-maven-plugin - 4.5 + 4.13.1 true true @@ -93,7 +93,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.0.0 + 3.6.0 generate-sources @@ -111,7 +111,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.2.4 sign-artifacts @@ -131,7 +131,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.8 + 1.7.0 true ossrh @@ -142,7 +142,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.1 attach-sources @@ -151,11 +151,11 @@ - + org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.6.3 attach-javadocs @@ -165,10 +165,20 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + **/*Test.java + + + org.jacoco jacoco-maven-plugin - 0.8.6 + 0.8.12 io/github/ajclopez/mss/Query* @@ -233,6 +243,13 @@ scm:git:ssh://github.com:ajclopez/mongo-spring-search.git https://github.com/ajclopez/mongo-spring-search/tree/master + + + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ + + diff --git a/src/main/antlr4/Query.g4 b/src/main/antlr4/Query.g4 index 00a2eac..ab37e8c 100644 --- a/src/main/antlr4/Query.g4 +++ b/src/main/antlr4/Query.g4 @@ -150,7 +150,7 @@ NEG_IDENTIFIER ; ENCODED_STRING - : ~([ \[\]<>!=()])+ + : ~([ \\[\]<>!=()])+ ; LineTerminator diff --git a/src/main/java/io/github/ajclopez/mss/MongoSpringSearch.java b/src/main/java/io/github/ajclopez/mss/MongoSpringSearch.java index f93a8f4..3efc6a0 100644 --- a/src/main/java/io/github/ajclopez/mss/MongoSpringSearch.java +++ b/src/main/java/io/github/ajclopez/mss/MongoSpringSearch.java @@ -3,7 +3,11 @@ import io.github.ajclopez.mss.criteria.CriteriaImpl; import io.github.ajclopez.mss.criteria.CriteriaQueryVisitor; import io.github.ajclopez.mss.exception.ArgumentNotValidException; -import io.github.ajclopez.mss.model.*; +import io.github.ajclopez.mss.model.Configuration; +import io.github.ajclopez.mss.model.SearchCriteria; +import io.github.ajclopez.mss.model.CastType; +import io.github.ajclopez.mss.model.KeySearchOperation; +import io.github.ajclopez.mss.model.SortSearchOperation; import io.github.ajclopez.mss.parser.QueryParser; import io.github.ajclopez.mss.pattern.SearchPatterns; import org.antlr.v4.runtime.CharStreams; @@ -61,17 +65,13 @@ public static Query mss(String query, Optional configuration) thr Query mongoQuery = new Query(); - List filters = new ArrayList(); + List filters = new ArrayList<>(); - Map casters = configuration.isPresent() ? configuration.get().getCasters() : null; + Map casters = configuration.map(Configuration::casters).orElse(null); Criteria filterCriteria = null; for ( SearchCriteria criteria : QueryParser.parse(query, casters) ) { switch (KeySearchOperation.getKeyOperation(criteria.getKey())) { - case DEFAULT: - default: - filters.add(criteria); - break; case FILTER: filterCriteria = parseFilterAdvanced(criteria.getValue(), casters); break; @@ -87,6 +87,10 @@ public static Query mss(String query, Optional configuration) thr case SORT: parseSort(mongoQuery, criteria.getValue()); break; + case DEFAULT: + default: + filters.add(criteria); + break; } } @@ -99,21 +103,21 @@ private static void parseDefaultFilter(Query query, List filters Map> groups = filters.stream().collect(Collectors.groupingBy(SearchCriteria::getKey)); - List criterias = new ArrayList(); + List criterias = new ArrayList<>(); if ( filterCriteria != null ) { criterias.add(filterCriteria); } - for ( String key : groups.keySet() ) { - for ( SearchCriteria criteria : groups.get(key) ) { + for ( Map.Entry> entry : groups.entrySet() ) { + for ( SearchCriteria criteria : entry.getValue() ) { criterias.add(CriteriaImpl.buildCriteria(criteria)); } } if ( !criterias.isEmpty() ) { - Criteria unique = filterCriteria != null ? filterCriteria : new Criteria().andOperator(criterias.toArray(new Criteria[criterias.size()])); + Criteria unique = filterCriteria != null ? filterCriteria : new Criteria().andOperator(criterias.toArray(new Criteria[criterias.size()])); query.addCriteria(criterias.size() == 1 ? unique : new Criteria().andOperator(criterias.toArray(new Criteria[criterias.size()]))); } } @@ -129,9 +133,9 @@ private static void parseSkip(Query query, String value) { private static void parseLimit(Query query, String value, Optional configuration) { try { - Optional maxLimit = configuration.isPresent() - ? configuration.get().getMaxLimit() != null ? Optional.of(configuration.get().getMaxLimit()) : Optional.empty() - : Optional.empty(); + Optional maxLimit = configuration + .filter(config -> config.maxLimit() != null) + .map(Configuration::maxLimit); if ( maxLimit.isPresent() ) { @@ -143,8 +147,8 @@ private static void parseLimit(Query query, String value, Optional) value).toArray()); - } else { - criteria.is(value); - } - break; case NOT_EQUAL: - if ( value instanceof Pattern ) { - criteria.not().regex(Pattern.quote(((Pattern)value).pattern())); + if ( value instanceof Pattern pattern) { + criteria.not().regex(Pattern.quote(pattern.pattern())); } else if ( value instanceof List ) { criteria.nin(((List) value).toArray()); } else { @@ -68,6 +57,16 @@ public static Criteria buildCriteria(SearchCriteria searchCriteria) { case EXISTS: criteria.exists(!searchCriteria.getPrefix()); break; + case EQUAL: + default: + if ( value instanceof Pattern pattern ) { + criteria.regex(pattern); + } else if ( value instanceof List ) { + criteria.in(((List) value).toArray()); + } else { + criteria.is(value); + } + break; } return criteria; diff --git a/src/main/java/io/github/ajclopez/mss/criteria/CriteriaQueryVisitor.java b/src/main/java/io/github/ajclopez/mss/criteria/CriteriaQueryVisitor.java index c031d68..26df0f6 100644 --- a/src/main/java/io/github/ajclopez/mss/criteria/CriteriaQueryVisitor.java +++ b/src/main/java/io/github/ajclopez/mss/criteria/CriteriaQueryVisitor.java @@ -14,15 +14,11 @@ */ public class CriteriaQueryVisitor extends QueryBaseVisitor { - private Map casters; + private final Map casters; public CriteriaQueryVisitor(Map casters) { this.casters = casters; } - - public Map getCasters() { - return casters; - } @Override public Criteria visitInput(io.github.ajclopez.mss.QueryParser.InputContext ctx) { @@ -44,20 +40,21 @@ public Criteria visitOpQuery(io.github.ajclopez.mss.QueryParser.OpQueryContext c Criteria left = visit(ctx != null ? ctx.left : null); Criteria right = visit(ctx != null ? ctx.right : null); + + String logicalOperation = null; - String logicalOperation = ctx != null ? (ctx.logicalOp != null ? ctx.logicalOp.getText() : null ) : null; - - if ( logicalOperation == null ) { - return new Criteria().andOperator(left, right); + if (ctx != null && ctx.logicalOp != null ) { + logicalOperation = ctx.logicalOp.getText(); } - switch (LogicalOperation.getLogicalOperation(logicalOperation)) { - case AND: - default: + if ( logicalOperation == null ) { return new Criteria().andOperator(left, right); - case OR: - return new Criteria().orOperator(left, right); } + + return switch (LogicalOperation.getLogicalOperation(logicalOperation)) { + case OR -> new Criteria().orOperator(left, right); + default -> new Criteria().andOperator(left, right); + }; } @Override diff --git a/src/main/java/io/github/ajclopez/mss/model/Configuration.java b/src/main/java/io/github/ajclopez/mss/model/Configuration.java index e224b34..b80bf52 100644 --- a/src/main/java/io/github/ajclopez/mss/model/Configuration.java +++ b/src/main/java/io/github/ajclopez/mss/model/Configuration.java @@ -3,45 +3,14 @@ import java.util.Map; /** - * *

Class used for advanced options [optional].

- * + * *
    *
  • casters: object which map keys to casters ({@code BOOLEAN, NUMBER, PATTERN, DATE, STRING}). *
  • defaultLimit: default value for {@code limit} key. - *
  • maxLimit: maximum value for {@code limit} key. + *
  • maxLimit: maximum value for {@code limit} key. *
- * */ -public class Configuration { +public record Configuration(Map casters, Integer defaultLimit, Integer maxLimit) { - private Map casters; - private Integer defaultLimit; - private Integer maxLimit; - - /** - * Creates a new {@link Configuration} with parameters applied. - * - * @param casters object which map keys to casters ({@code BOOLEAN, NUMBER, PATTERN, DATE, STRING}). - * @param defaultLimit default value for {@code limit} key. - * @param maxLimit maximum value for {@code limit} key. - */ - public Configuration(Map casters, Integer defaultLimit, Integer maxLimit) { - this.casters = casters; - this.defaultLimit = defaultLimit; - this.maxLimit = maxLimit; - } - - public Map getCasters() { - return casters; - } - - public Integer getDefaultLimit() { - return defaultLimit; - } - - public Integer getMaxLimit() { - return maxLimit; - } - } diff --git a/src/main/java/io/github/ajclopez/mss/model/KeySearchOperation.java b/src/main/java/io/github/ajclopez/mss/model/KeySearchOperation.java index 8a033ad..74c28fd 100644 --- a/src/main/java/io/github/ajclopez/mss/model/KeySearchOperation.java +++ b/src/main/java/io/github/ajclopez/mss/model/KeySearchOperation.java @@ -5,20 +5,14 @@ public enum KeySearchOperation { SKIP, LIMIT, SORT, FIELDS, FILTER, DEFAULT; public static KeySearchOperation getKeyOperation(String input) { - switch (input) { - case "skip": - return SKIP; - case "limit": - return LIMIT; - case "sort": - return SORT; - case "fields": - return FIELDS; - case "filter": - return FILTER; - default: - return DEFAULT; - } + return switch (input) { + case "skip" -> SKIP; + case "limit" -> LIMIT; + case "sort" -> SORT; + case "fields" -> FIELDS; + case "filter" -> FILTER; + default -> DEFAULT; + }; } } diff --git a/src/main/java/io/github/ajclopez/mss/model/LogicalOperation.java b/src/main/java/io/github/ajclopez/mss/model/LogicalOperation.java index ebe0299..e1b83c2 100644 --- a/src/main/java/io/github/ajclopez/mss/model/LogicalOperation.java +++ b/src/main/java/io/github/ajclopez/mss/model/LogicalOperation.java @@ -5,16 +5,11 @@ public enum LogicalOperation { AND, OR; public static LogicalOperation getLogicalOperation(String input) { - switch (input) { - case "AND": - case "and": - return AND; - case "OR": - case "or": - return OR; - default: - return null; - } + return switch (input) { + case "AND", "and" -> AND; + case "OR", "or" -> OR; + default -> null; + }; } } diff --git a/src/main/java/io/github/ajclopez/mss/model/SearchOperation.java b/src/main/java/io/github/ajclopez/mss/model/SearchOperation.java index 4bc4ec9..308a63b 100644 --- a/src/main/java/io/github/ajclopez/mss/model/SearchOperation.java +++ b/src/main/java/io/github/ajclopez/mss/model/SearchOperation.java @@ -5,23 +5,15 @@ public enum SearchOperation { EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_EQUAL, LESS_THAN, LESS_THAN_EQUAL, EXISTS; public static SearchOperation getOperation(String input) { - switch (input) { - case "=": - return EQUAL; - case "!=": - return NOT_EQUAL; - case ">": - return GREATER_THAN; - case ">=": - return GREATER_THAN_EQUAL; - case "<": - return LESS_THAN; - case "<=": - return LESS_THAN_EQUAL; - case "!": - default: - return EXISTS; - } + return switch (input) { + case "=" -> EQUAL; + case "!=" -> NOT_EQUAL; + case ">" -> GREATER_THAN; + case ">=" -> GREATER_THAN_EQUAL; + case "<" -> LESS_THAN; + case "<=" -> LESS_THAN_EQUAL; + default -> EXISTS; + }; } } diff --git a/src/main/java/io/github/ajclopez/mss/model/SortSearchOperation.java b/src/main/java/io/github/ajclopez/mss/model/SortSearchOperation.java index a264fec..21620aa 100644 --- a/src/main/java/io/github/ajclopez/mss/model/SortSearchOperation.java +++ b/src/main/java/io/github/ajclopez/mss/model/SortSearchOperation.java @@ -5,14 +5,10 @@ public enum SortSearchOperation { ASC, DESC; public static SortSearchOperation getSortOperation(String input) { - switch (input) { - case "+": - case " ": - default: - return ASC; - case "-": - return DESC; - } + return switch (input) { + case "-" -> DESC; + default -> ASC; + }; } } diff --git a/src/main/java/io/github/ajclopez/mss/parser/QueryParser.java b/src/main/java/io/github/ajclopez/mss/parser/QueryParser.java index a26637a..dc6e581 100644 --- a/src/main/java/io/github/ajclopez/mss/parser/QueryParser.java +++ b/src/main/java/io/github/ajclopez/mss/parser/QueryParser.java @@ -44,7 +44,7 @@ private QueryParser() { */ public static List parse(String query, Map casters) { - List criterias = new ArrayList(); + List criterias = new ArrayList<>(); for ( String condition : query.split("&") ) { criterias.add(criteriaParser(condition, casters)); @@ -97,7 +97,7 @@ public static Object parseValue(String value, CastType caster) { case BOOLEAN: return Boolean.parseBoolean(value); case DATE: - return parseLocalDateTime(value, DATE_FORMAT); + return parseLocalDateTime(value); case NUMBER: try { return NumberFormat.getInstance().parse(value); @@ -128,7 +128,7 @@ private static Object parseValue(String value) { String[] parts = value.split(","); if ( parts.length > 1 ) { - List list = new ArrayList(); + List list = new ArrayList<>(); for ( String part : parts ) { list.add(parseValue(part)); } @@ -143,17 +143,19 @@ private static Object parseValue(String value) { if ( value.equals("null") ) { return null; } - - try { - return parseLocalDateTime(value, DATE_FORMAT); + + try { + return parseLocalDateTime(value); } catch(DateTimeParseException | IllegalArgumentException ignored) { + // default implementation ignored } - + try { if ( SearchPatterns.getNumberPattern().matcher(value).matches() ) { return NumberFormat.getInstance().parse(value); } } catch(ParseException ignored) { + // default implementation ignored } Matcher matcher = SearchPatterns.getRegExpPattern().matcher(value); @@ -164,9 +166,9 @@ private static Object parseValue(String value) { return value; } - private static Instant parseLocalDateTime(String value, String format) { + private static Instant parseLocalDateTime(String value) { - return LocalDateTime.parse(value, DateTimeFormatter.ofPattern(format)).atZone(ZoneId.of("UTC")).toInstant(); + return LocalDateTime.parse(value, DateTimeFormatter.ofPattern(QueryParser.DATE_FORMAT)).atZone(ZoneId.of("UTC")).toInstant(); } } diff --git a/src/main/java/io/github/ajclopez/mss/pattern/SearchPatterns.java b/src/main/java/io/github/ajclopez/mss/pattern/SearchPatterns.java index 7ea922d..4cb2a26 100644 --- a/src/main/java/io/github/ajclopez/mss/pattern/SearchPatterns.java +++ b/src/main/java/io/github/ajclopez/mss/pattern/SearchPatterns.java @@ -11,13 +11,13 @@ public class SearchPatterns { private static final String OPERATOR_PATTERN = "(!?)([^><]=?|!?=|)(.*)"; private static final String REGEX_PATTERN = "^/(.*)/([igmsx]*)$"; - private static final String SORT_PATTERN = "^(\\+|-)?(.*)"; + private static final String SORT_PATTERN = "^([+\\-])?(.*)"; private static final String NUMBER_PATTERN = "^(-?)(\\d+)([.0-9]*)$"; - private static Pattern operatorPattern; - private static Pattern regExpPattern; - private static Pattern sortPattern; - private static Pattern numberPattern; + private static final Pattern operatorPattern; + private static final Pattern regExpPattern; + private static final Pattern sortPattern; + private static final Pattern numberPattern; static { operatorPattern = Pattern.compile(OPERATOR_PATTERN); @@ -55,23 +55,14 @@ public static int getFlags(String options) { } for ( int i = 0; i < options.split("").length; i++ ) { - switch (options.charAt(i)) { - case 'i': - flags = flags | Pattern.CASE_INSENSITIVE; - break; - case 'g': - flags = flags | Pattern.LITERAL; - break; - case 'm': - flags = flags | Pattern.MULTILINE; - break; - case 's': - flags = flags | Pattern.DOTALL; - break; - case 'x': - flags = flags | Pattern.COMMENTS; - break; - } + flags = switch (options.charAt(i)) { + case 'i' -> flags | Pattern.CASE_INSENSITIVE; + case 'g' -> flags | Pattern.LITERAL; + case 'm' -> flags | Pattern.MULTILINE; + case 's' -> flags | Pattern.DOTALL; + case 'x' -> flags | Pattern.COMMENTS; + default -> flags; + }; } return flags; diff --git a/src/test/java/io/github/ajclopez/mss/MongoSpringSearchApplicationTest.java b/src/test/java/io/github/ajclopez/mss/MongoSpringSearchApplicationTest.java index fe7d2d4..536df5d 100644 --- a/src/test/java/io/github/ajclopez/mss/MongoSpringSearchApplicationTest.java +++ b/src/test/java/io/github/ajclopez/mss/MongoSpringSearchApplicationTest.java @@ -1,38 +1,16 @@ package io.github.ajclopez.mss; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Unit test for simple App. */ -public class MongoSpringSearchApplicationTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public MongoSpringSearchApplicationTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( MongoSpringSearchApplicationTest.class ); - } +class MongoSpringSearchApplicationTest { - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); + @Test + void testApp() { + assertTrue(true); } } diff --git a/src/test/java/io/github/ajclopez/mss/MongoSpringSearchTest.java b/src/test/java/io/github/ajclopez/mss/MongoSpringSearchTest.java index 6dcbb9b..ab4e3a0 100644 --- a/src/test/java/io/github/ajclopez/mss/MongoSpringSearchTest.java +++ b/src/test/java/io/github/ajclopez/mss/MongoSpringSearchTest.java @@ -6,8 +6,8 @@ import io.github.ajclopez.mss.model.Configuration; import io.github.ajclopez.mss.model.LogicalOperation; import org.bson.Document; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.springframework.data.mongodb.core.query.Query; import java.time.Clock; @@ -19,26 +19,28 @@ import java.util.Optional; import java.util.regex.Pattern; -public class MongoSpringSearchTest { +import static java.util.regex.Pattern.compile; + +class MongoSpringSearchTest { @Test - public void queryEmptyAndNullCreateQueryMongoDBEmpty() { - Assert.assertNotNull(MongoSpringSearch.mss(null)); - Assert.assertNotNull(MongoSpringSearch.mss("")); + void queryEmptyAndNullCreateQueryMongoDBEmpty() { + Assertions.assertNotNull(MongoSpringSearch.mss(null)); + Assertions.assertNotNull(MongoSpringSearch.mss("")); } @Test - public void findQuery() { + void findQuery() { - String query = "age>=10&mobile=/^+34.*/&firstname=jhon&date>2021-01-08T00:00:00.000Z"; + String query = "age>=10&mobile=/^+34.*/&firstname=john&date>2021-01-08T00:00:00.000Z"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Integer.valueOf(query.split("&").length), Integer.valueOf(mongoQuery.getQueryObject().get("$and", BasicDBList.class).size())); + + Assertions.assertEquals(Integer.valueOf(query.split("&").length), Integer.valueOf(mongoQuery.getQueryObject().get("$and", BasicDBList.class).size())); } @Test - public void findAllOperatorsInQuery() { + void findAllOperatorsInQuery() { String query = "age>=18&age<=21" + "&mobile=/^+34.*/" @@ -46,184 +48,184 @@ public void findAllOperatorsInQuery() { + "&city!=USA&!email&code=123456,98765&zone!=zone1,zone2&mobile" + "&email!=/.*@example.com/"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Integer.valueOf(query.split("&").length), Integer.valueOf(mongoQuery.getQueryObject().get("$and", BasicDBList.class).size())); + + Assertions.assertEquals(Integer.valueOf(query.split("&").length), Integer.valueOf(mongoQuery.getQueryObject().get("$and", BasicDBList.class).size())); } @Test - public void canUseAllTypeValueInQuery() { + void canUseAllTypeValueInQuery() { String query = "age=21&name=Elisa&data>2021-01-08T00:00:00.000Z&female=true&email=/.*@example.com/&flag=null"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Integer.valueOf(query.split("&").length), Integer.valueOf(mongoQuery.getQueryObject().get("$and", BasicDBList.class).size())); + + Assertions.assertEquals(Integer.valueOf(query.split("&").length), Integer.valueOf(mongoQuery.getQueryObject().get("$and", BasicDBList.class).size())); } @Test - public void canUseRegex() { + void canUseRegex() { String query = "mobile=/^58/"; Query mongoQuery = MongoSpringSearch.mss(query); - Pattern pattern = Pattern.compile("/^58/"); + Pattern pattern = compile("/^58/"); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - String expected = Pattern.compile(pattern.pattern().replace("/", "")).pattern(); - - Assert.assertEquals(expected, document.get("mobile").toString()); + String expected = compile(pattern.pattern().replace("/", "")).pattern(); + + Assertions.assertEquals(expected, document.get("mobile").toString()); } @Test - public void canUseRegexWithSpecialCharacters() { + void canUseRegexWithSpecialCharacters() { String query = "mobile=/^\\+58/"; Query mongoQuery = MongoSpringSearch.mss(query); - Pattern pattern = Pattern.compile("/^\\+58/"); + Pattern pattern = compile("/^\\+58/"); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - String expected = Pattern.compile(pattern.pattern().replace("/", "")).pattern(); - - Assert.assertEquals(expected, document.get("mobile").toString()); + String expected = compile(pattern.pattern().replace("/", "")).pattern(); + + Assertions.assertEquals(expected, document.get("mobile").toString()); } @Test - public void canUseRegexWithOptions() { + void canUseRegexWithOptions() { String query = "firstname=/JOHN/i"; Query mongoQuery = MongoSpringSearch.mss(query); - Pattern pattern = Pattern.compile("/JOHN/", Pattern.CASE_INSENSITIVE); + Pattern pattern = compile("/JOHN/", Pattern.CASE_INSENSITIVE); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - String expected = Pattern.compile(pattern.pattern().replace("/", ""), Pattern.CASE_INSENSITIVE).pattern(); + String expected = compile(pattern.pattern().replace("/", ""), Pattern.CASE_INSENSITIVE).pattern(); - Assert.assertEquals(expected, document.get("firstname").toString()); + Assertions.assertEquals(expected, document.get("firstname").toString()); } @Test - public void canUseRegexWithAllOptions() { + void canUseRegexWithAllOptions() { String query = "firstname=/JOHN/gmixs"; Query mongoQuery = MongoSpringSearch.mss(query); - Pattern pattern = Pattern.compile("/JOHN/", Pattern.CASE_INSENSITIVE); + Pattern pattern = compile("/JOHN/", Pattern.CASE_INSENSITIVE); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - String expected = Pattern.compile(pattern.pattern().replace("/", ""), Pattern.CASE_INSENSITIVE).pattern(); + String expected = compile(pattern.pattern().replace("/", ""), Pattern.CASE_INSENSITIVE).pattern(); - Assert.assertEquals(expected, document.get("firstname").toString()); + Assertions.assertEquals(expected, document.get("firstname").toString()); } @Test - public void limitQuery() { + void limitQuery() { String query = "limit=10"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Integer.valueOf(10), Integer.valueOf(mongoQuery.getLimit())); + + Assertions.assertEquals(Integer.valueOf(10), Integer.valueOf(mongoQuery.getLimit())); } - @Test(expected = ArgumentNotValidException.class) - public void limitIsAnArgumentNotValid() { + @Test + void limitIsAnArgumentNotValid() { String query = "limit=a"; - MongoSpringSearch.mss(query); + Assertions.assertThrows(ArgumentNotValidException.class, () -> MongoSpringSearch.mss(query)); } @Test - public void canUseDefaultLimitValue() { + void canUseDefaultLimitValue() { Configuration options = new Configuration(null, 10, null); String query = "city=Madrid&limit=a"; Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); - - Assert.assertEquals(Integer.valueOf(10), Integer.valueOf(mongoQuery.getLimit())); + + Assertions.assertEquals(Integer.valueOf(10), Integer.valueOf(mongoQuery.getLimit())); } @Test - public void canUseMaxLimitValue() { + void canUseMaxLimitValue() { Configuration options = new Configuration(null, 10, 500); String query = "city=Madrid&limit=100"; Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); - - Assert.assertEquals(Integer.valueOf(100), Integer.valueOf(mongoQuery.getLimit())); + + Assertions.assertEquals(Integer.valueOf(100), Integer.valueOf(mongoQuery.getLimit())); } @Test - public void canUseMaxLimitValueIfLimitParamExceedsRule() { + void canUseMaxLimitValueIfLimitParamExceedsRule() { Configuration options = new Configuration(null, 10, 500); String query = "city=Madrid&limit=10000"; Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); - - Assert.assertEquals(Integer.valueOf(500), Integer.valueOf(mongoQuery.getLimit())); + + Assertions.assertEquals(Integer.valueOf(500), Integer.valueOf(mongoQuery.getLimit())); } @Test - public void skipQuery() { + void skipQuery() { String query = "skip=50"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Long.valueOf(50), Long.valueOf(mongoQuery.getSkip())); + + Assertions.assertEquals(Long.valueOf(50), Long.valueOf(mongoQuery.getSkip())); } - @Test(expected = ArgumentNotValidException.class) - public void skipIsAnArgumentNotValid() { + @Test + void skipIsAnArgumentNotValid() { String query = "skip=a"; - MongoSpringSearch.mss(query); + Assertions.assertThrows(ArgumentNotValidException.class, () -> MongoSpringSearch.mss(query)); } @Test - public void projectionQuery() { + void projectionQuery() { String query = "fields=firstname,lastname,age"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("firstname")); - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("lastname")); - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("age")); + + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("firstname")); + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("lastname")); + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("age")); } @Test - public void sortQuery() { + void sortQuery() { String query = "sort=+date,id,-city"; Query mongoQuery = MongoSpringSearch.mss(query); - - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getSortObject().getInteger("date")); - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getSortObject().getInteger("id")); - Assert.assertEquals(Integer.valueOf(-1), mongoQuery.getSortObject().getInteger("city")); + + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getSortObject().getInteger("date")); + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getSortObject().getInteger("id")); + Assertions.assertEquals(Integer.valueOf(-1), mongoQuery.getSortObject().getInteger("city")); } @Test - public void canUseLogicalOperators() { + void canUseLogicalOperators() { String query = "filter=(country=Mexico OR country=Spain) and gender=female"; Query mongoQuery = MongoSpringSearch.mss(query); BasicDBList list = mongoQuery.getQueryObject().get("$and", BasicDBList.class); - - Assert.assertEquals(Integer.valueOf(2), Integer.valueOf(list.size())); - Assert.assertEquals(Integer.valueOf(2), Integer.valueOf(((Document)list.get(0)).get("$or", BasicDBList.class).size())); + + Assertions.assertEquals(Integer.valueOf(2), Integer.valueOf(list.size())); + Assertions.assertEquals(Integer.valueOf(2), Integer.valueOf(((Document)list.get(0)).get("$or", BasicDBList.class).size())); } @Test - public void canUseCastingString() { + void canUseCastingString() { - Map caster = new HashMap(); + Map caster = new HashMap<>(); caster.put("mobile", CastType.STRING); Configuration options = new Configuration(caster, null, null); @@ -232,14 +234,14 @@ public void canUseCastingString() { Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - - Assert.assertEquals("134000000000", document.getString("mobile")); + + Assertions.assertEquals("134000000000", document.getString("mobile")); } @Test - public void canUseCastingNumber() { + void canUseCastingNumber() { - Map caster = new HashMap(); + Map caster = new HashMap<>(); caster.put("mobile", CastType.NUMBER); Configuration options = new Configuration(caster, null, null); @@ -248,25 +250,27 @@ public void canUseCastingNumber() { Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - - Assert.assertEquals(Long.valueOf(134000000000l), document.getLong("mobile")); + + Assertions.assertEquals(Long.valueOf(134000000000L), document.getLong("mobile")); } - @Test(expected = ArgumentNotValidException.class) - public void canThrowArgumentNotValidCastingNumber() { + @Test + void canThrowArgumentNotValidCastingNumber() { - Map caster = new HashMap(); + Map caster = new HashMap<>(); caster.put("mobile", CastType.NUMBER); - Configuration options = new Configuration(caster, null, null); - - MongoSpringSearch.mss("mobile=a", Optional.of(options)); + Configuration configuration = new Configuration(caster, null, null); + var query = "mobile=a"; + var options = Optional.of(configuration); + + Assertions.assertThrows(ArgumentNotValidException.class, () -> MongoSpringSearch.mss(query, options)); } @Test - public void canUseCastingBoolean() { + void canUseCastingBoolean() { - Map caster = new HashMap(); + Map caster = new HashMap<>(); caster.put("flag", CastType.BOOLEAN); Configuration options = new Configuration(caster, null, null); @@ -275,14 +279,14 @@ public void canUseCastingBoolean() { Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - - Assert.assertEquals(Boolean.valueOf(false), document.getBoolean("flag")); + + Assertions.assertEquals(Boolean.FALSE, document.getBoolean("flag")); } @Test - public void canUseCastingDate() { + void canUseCastingDate() { - Map caster = new HashMap(); + Map caster = new HashMap<>(); caster.put("date", CastType.DATE); Configuration options = new Configuration(caster, null, null); @@ -294,32 +298,32 @@ public void canUseCastingDate() { Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - - Assert.assertEquals(formatter.format(now), document.get("date").toString()); + + Assertions.assertEquals(formatter.format(now), document.get("date").toString()); } @Test - public void canUseCastingPattern() { + void canUseCastingPattern() { - Map caster = new HashMap(); + Map caster = new HashMap<>(); caster.put("email", CastType.PATTERN); Configuration options = new Configuration(caster, null, null); - Pattern pattern = Pattern.compile("/.*@example.com/"); + Pattern pattern = compile("/.*@example.com/"); String query = String.format("email=%s", pattern.pattern()); Query mongoQuery = MongoSpringSearch.mss(query, Optional.of(options)); Document document = ((Document)mongoQuery.getQueryObject().get("$and", BasicDBList.class).get(0)); - String expected = Pattern.compile(pattern.pattern().replace("/", "")).pattern(); - - Assert.assertEquals(expected, document.get("email").toString()); + String expected = compile(pattern.pattern().replace("/", "")).pattern(); + + Assertions.assertEquals(expected, document.get("email").toString()); } @Test - public void complexQuery() { + void complexQuery() { String query = "filter=(city=Madrid or city=Barcelona) and gender=female" + "&skip=50" @@ -331,35 +335,35 @@ public void complexQuery() { Query mongoQuery = MongoSpringSearch.mss(query); BasicDBList list = mongoQuery.getQueryObject().get("$and", BasicDBList.class); - - Assert.assertEquals(Integer.valueOf(4), Integer.valueOf(list.size())); - Assert.assertEquals(Long.valueOf(50), Long.valueOf(mongoQuery.getSkip())); - Assert.assertEquals(Integer.valueOf(10), Integer.valueOf(mongoQuery.getLimit())); - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("firstname")); - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("lastname")); - Assert.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("age")); - Assert.assertEquals(Integer.valueOf(-1), mongoQuery.getSortObject().getInteger("birthday")); + + Assertions.assertEquals(Integer.valueOf(4), Integer.valueOf(list.size())); + Assertions.assertEquals(Long.valueOf(50), Long.valueOf(mongoQuery.getSkip())); + Assertions.assertEquals(Integer.valueOf(10), Integer.valueOf(mongoQuery.getLimit())); + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("firstname")); + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("lastname")); + Assertions.assertEquals(Integer.valueOf(1), mongoQuery.getFieldsObject().getInteger("age")); + Assertions.assertEquals(Integer.valueOf(-1), mongoQuery.getSortObject().getInteger("birthday")); } @Test - public void whenUseInvalidLogicalOperator() { + void whenUseInvalidLogicalOperator() { LogicalOperation result = LogicalOperation.getLogicalOperation("y"); - Assert.assertEquals(null, result); + Assertions.assertNull(result); } @Test - public void whenUseKeyWithSpecialCharacterThenReturnQuery() { + void whenUseKeyWithSpecialCharacterThenReturnQuery() { String query = "filter=(core:city=Madrid and core:city=Barcelona)"; Query mongoQuery = MongoSpringSearch.mss(query); - System.out.println(mongoQuery); + BasicDBList list = mongoQuery.getQueryObject().get("$and", BasicDBList.class); Document document = (Document) list.get(0); - Assert.assertEquals(Integer.valueOf(2), Integer.valueOf(list.size())); - Assert.assertTrue(document.containsKey("core:city")); + Assertions.assertEquals(Integer.valueOf(2), Integer.valueOf(list.size())); + Assertions.assertTrue(document.containsKey("core:city")); } } diff --git a/src/test/java/io/github/ajclopez/mss/QueryParserTest.java b/src/test/java/io/github/ajclopez/mss/QueryParserTest.java new file mode 100644 index 0000000..40f888f --- /dev/null +++ b/src/test/java/io/github/ajclopez/mss/QueryParserTest.java @@ -0,0 +1,43 @@ +package io.github.ajclopez.mss; + +import io.github.ajclopez.mss.model.CastType; +import io.github.ajclopez.mss.model.SearchCriteria; +import io.github.ajclopez.mss.parser.QueryParser; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.regex.Pattern; + +class QueryParserTest { + + + @Test + void whenQueryNotMatchThenReturnNull() { + + SearchCriteria result = io.github.ajclopez.mss.parser.QueryParser.criteriaParser("", null); + Assertions.assertNull(result); + } + + @Test + void whenRegexNotMatchWithPatternThenReturnPatternWithValue() { + + String regex = "^58"; + Object result = io.github.ajclopez.mss.parser.QueryParser.parseValue(regex, CastType.PATTERN); + Assertions.assertEquals(Pattern.compile(regex).toString(), result.toString()); + } + + @Test + void whenFalseValueThenReturnBooleanWithFalseValue() { + + Object result = io.github.ajclopez.mss.parser.QueryParser.parseValue("false", null); + Assertions.assertEquals(false, result); + } + + @Test + void whenValueIsNullThenReturnNullValue() { + + Object result = QueryParser.parseValue(null, null); + Assertions.assertNull(result); + } + +} diff --git a/src/test/java/io/github/ajclopez/mss/SearchCriteriaTest.java b/src/test/java/io/github/ajclopez/mss/SearchCriteriaTest.java new file mode 100644 index 0000000..8617cb8 --- /dev/null +++ b/src/test/java/io/github/ajclopez/mss/SearchCriteriaTest.java @@ -0,0 +1,29 @@ +package io.github.ajclopez.mss; + +import io.github.ajclopez.mss.model.SearchCriteria; +import io.github.ajclopez.mss.model.SearchOperation; +import io.github.ajclopez.mss.parser.QueryParser; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class SearchCriteriaTest { + + @Test + void canUseSearchCriteriaObject() { + + SearchCriteria expected = new SearchCriteria(); + expected.setPrefix(false); + expected.setKey("name"); + expected.setOperation(SearchOperation.getOperation("=")); + expected.setValue("john"); + expected.setCaster(null); + + String condition = "name=john"; + + SearchCriteria criteria = QueryParser.criteriaParser(condition, null); + + Assertions.assertNotNull(criteria); + Assertions.assertEquals(expected.toString(), criteria.toString()); + } + +} diff --git a/src/test/java/io/github/ajclopez/mss/SearchPatternsTest.java b/src/test/java/io/github/ajclopez/mss/SearchPatternsTest.java new file mode 100644 index 0000000..90cc6a5 --- /dev/null +++ b/src/test/java/io/github/ajclopez/mss/SearchPatternsTest.java @@ -0,0 +1,21 @@ +package io.github.ajclopez.mss; + +import io.github.ajclopez.mss.pattern.SearchPatterns; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class SearchPatternsTest { + + @Test + void canUseDefaultFlagWithNullOptions() { + int flags = SearchPatterns.getFlags(null); + Assertions.assertEquals(0x00, flags); + } + + @Test + void canUseDefaultFlagWithUnknownRegexFlag() { + int flags = SearchPatterns.getFlags("t"); + Assertions.assertEquals(0x00, flags); + } + +} diff --git a/src/test/java/io/github/ajclopez/mss/model/SearchCriteriaTest.java b/src/test/java/io/github/ajclopez/mss/model/SearchCriteriaTest.java deleted file mode 100644 index ba9a46d..0000000 --- a/src/test/java/io/github/ajclopez/mss/model/SearchCriteriaTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.github.ajclopez.mss.model; - -import org.junit.Assert; -import org.junit.Test; - -import io.github.ajclopez.mss.parser.QueryParser; - -public class SearchCriteriaTest { - - @Test - public void canUseSearchCriteriaObject() { - - SearchCriteria expected = new SearchCriteria(); - expected.setPrefix(false); - expected.setKey("name"); - expected.setOperation(SearchOperation.getOperation("=")); - expected.setValue("jhon"); - expected.setCaster(null); - - String condition = "name=jhon"; - - SearchCriteria criteria = QueryParser.criteriaParser(condition, null); - - Assert.assertEquals(expected.toString(), criteria.toString()); - } - -} diff --git a/src/test/java/io/github/ajclopez/mss/parser/QueryParserTest.java b/src/test/java/io/github/ajclopez/mss/parser/QueryParserTest.java deleted file mode 100644 index fb33bea..0000000 --- a/src/test/java/io/github/ajclopez/mss/parser/QueryParserTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.ajclopez.mss.parser; - -import io.github.ajclopez.mss.model.CastType; -import io.github.ajclopez.mss.model.SearchCriteria; -import org.junit.Assert; -import org.junit.Test; - -import java.util.regex.Pattern; - -public class QueryParserTest { - - - @Test - public void whenQueryNotMatchThenReturnNull() { - - SearchCriteria result = QueryParser.criteriaParser("", null); - Assert.assertEquals(null, result); - } - - @Test - public void whenRegexNotMatchWithPatternThenReturnPatternWithValue() { - - String regex = "^58"; - Object result = QueryParser.parseValue(regex, CastType.PATTERN); - Assert.assertEquals(Pattern.compile(regex).toString(), result.toString()); - } - - @Test - public void whenFalseValueThenReturnBooleanWithFalseValue() { - - Object result = QueryParser.parseValue("false", null); - Assert.assertEquals(Boolean.parseBoolean("false"), result); - } - - @Test - public void whenValueIsNullThenReturnNullValue() { - - Object result = QueryParser.parseValue(null, null); - Assert.assertEquals(null, result); - } - -} diff --git a/src/test/java/io/github/ajclopez/mss/pattern/SearchPatternsTest.java b/src/test/java/io/github/ajclopez/mss/pattern/SearchPatternsTest.java deleted file mode 100644 index 5b377f4..0000000 --- a/src/test/java/io/github/ajclopez/mss/pattern/SearchPatternsTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.ajclopez.mss.pattern; - -import org.junit.Assert; -import org.junit.Test; - -public class SearchPatternsTest { - - @Test - public void canUseDefaultFlagWithNullOptions() { - int flags = SearchPatterns.getFlags(null); - Assert.assertEquals(0x00, flags); - } - - @Test - public void canUseDefaultFlagWithUnknownRegexFlag() { - int flags = SearchPatterns.getFlags("t"); - Assert.assertEquals(0x00, flags); - } - -}