/* * Hibernate OGM, Domain model persistence for NoSQL datastores * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.ogm.datastore.mongodb.test.query.parsing.nativequery; import static org.fest.assertions.Assertions.assertThat; import org.hibernate.ogm.datastore.mongodb.query.impl.MongoDBQueryDescriptor; import org.hibernate.ogm.datastore.mongodb.query.impl.MongoDBQueryDescriptor.Operation; import org.hibernate.ogm.datastore.mongodb.query.parsing.nativequery.impl.MongoDBQueryDescriptorBuilder; import org.hibernate.ogm.datastore.mongodb.query.parsing.nativequery.impl.NativeQueryParser; import org.hibernate.ogm.datastore.mongodb.utils.DocumentUtil; import org.hibernate.ogm.utils.TestForIssue; import org.junit.Test; import org.bson.Document; import org.parboiled.Parboiled; import org.parboiled.parserunners.RecoveringParseRunner; import org.parboiled.parserunners.ReportingParseRunner; import org.parboiled.support.ParseTreeUtils; import org.parboiled.support.ParsingResult; /** * Unit test for {@link NativeQueryParser}. * * @author Gunnar Morling * @see <a href="https://docs.mongodb.com/manual/tutorial/insert-documents/"> InsertOne documents in 3.4 API</a> */ public class NativeQueryParserTest { @Test @TestForIssue(jiraKey = "OGM-1024") public void shouldParseSimplifiedAggregateQuery() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); String match = "{ '$match': {'author' : 'Oscar Wilde' } }"; String sort = "{ '$sort': {'name' : -1 } }"; ParsingResult<MongoDBQueryDescriptorBuilder> run = new ReportingParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.aggregate([" + match + ", " + sort + " ])" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.AGGREGATE_PIPELINE ); assertThat( queryDescriptor.getPipeline() ) .containsExactly( Document.parse( match ), Document.parse( sort ) ); } @Test @TestForIssue(jiraKey = "OGM-1024") public void shouldParseComplexAggregateQuery() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); String match = "{ '$match': { 'NAME':{'$regex':'Bangalore', '$options': 'i'}}}"; String unwind = "{'$unwind': '$clicks'}"; String group = "{ '$group': {'_id' : '$_id' ,'clicks' : {'$push':'$clicks'} ,'token' : { '$push': '$TOKEN' } } }"; String sort = "{ '$sort': { '_id' : -1 } }"; String nativeQuery = "db.UserFactualContent.aggregate([" + match + "," + unwind + "," + group + "," + sort + "])"; ParsingResult<MongoDBQueryDescriptorBuilder> run = new ReportingParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ).run( nativeQuery ); System.out.println( ParseTreeUtils.printNodeTree( run ) ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "UserFactualContent" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.AGGREGATE_PIPELINE ); assertThat( queryDescriptor.getPipeline() ) .containsExactly( Document.parse( match ) , Document.parse( unwind ) , Document.parse( group ) , Document.parse( sort ) ); } @Test @TestForIssue(jiraKey = "OGM-1247") public void shouldParseDistinctQueryWithFieldOnly() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.distinct('item')" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.DISTINCT ); assertThat( queryDescriptor.getCriteria() ).isNull(); assertThat( queryDescriptor.getCollation() ).isNull(); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); assertThat( queryDescriptor.getDistinctFieldName() ).isEqualTo( "item" ); } @Test @TestForIssue(jiraKey = "OGM-1247") public void shouldParseDistinctQueryWithCriteriaAndCollation() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.distinct('item',{'orderId': { '$in': ['XYZ123', '123']}},{'collation' : {'locale' : 'fr'}})" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.DISTINCT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ 'orderId' : { '$in': ['XYZ123', '123'] } }" ) ); assertThat( queryDescriptor.getCollation().getLocale() ).isEqualTo( "fr" ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); assertThat( queryDescriptor.getDistinctFieldName() ).isEqualTo( "item" ); } @Test @TestForIssue(jiraKey = "OGM-1247") public void shouldParseDistinctQueryWithCollationOnly() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.distinct('item', {}, {'collation' : {'locale' : 'fr'}})" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.DISTINCT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{}" ) ); assertThat( queryDescriptor.getCollation().getLocale() ).isEqualTo( "fr" ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); assertThat( queryDescriptor.getDistinctFieldName() ).isEqualTo( "item" ); } @Test public void shouldParseSimplifiedFindQuery() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "{ \"foo\" : true }" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isNull(); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseSimpleQuery() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find({\"foo\":true})" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseSimpleQueryUsingSingleQuotes() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find( { 'foo' : true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryWithEmptyFind() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find({})" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCriteria() ).isEqualTo( new Document() ); } @Test public void shouldParseQueryInsertSingleDocument() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.insertOne( { 'item': 'card', 'qty': 15 } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.INSERTONE ); assertThat( queryDescriptor.getUpdateOrInsertOne() ).isEqualTo( Document.parse( "{ 'item': 'card', 'qty': 15 }" ) ); } @Test public void shouldParseQueryInsertSingleDocumentAndOptions() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.insertOne( { 'item': 'card', 'qty': 15 }, { 'ordered': true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.INSERTONE ); assertThat( queryDescriptor.getUpdateOrInsertOne() ).isEqualTo( Document.parse( "{ 'item': 'card', 'qty': 15 }" ) ); assertThat( queryDescriptor.getUpdateOrInsertMany() ).isNull(); assertThat( queryDescriptor.getOptions() ).isEqualTo( Document.parse( "{ ordered: true })" ) ); } @Test public void shouldParseQueryInsertMultipleDocuments() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.insertMany( [ { '_id': 11, 'item': 'pencil', 'qty': 50, 'type': 'no.2' }, { 'item': 'pen', 'qty': 20 }, { 'item': 'eraser', 'qty': 25 } ] )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.INSERTMANY ); assertThat( queryDescriptor.getUpdateOrInsertOne() ).isNull(); assertThat( queryDescriptor.getUpdateOrInsertMany() ).isEqualTo( DocumentUtil.fromJsonArray( "[ { '_id': 11, 'item': 'pencil', 'qty': 50, 'type': 'no.2' }, { 'item': 'pen', 'qty': 20 }, { 'item': 'eraser', 'qty': 25 } ]" ) ); } @Test public void shouldParseQueryInsertUnkwounDocuments() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.insert( [ { '_id': 11, 'item': 'pencil', 'qty': 50, 'type': 'no.2' }, { 'item': 'pen', 'qty': 20 }, { 'item': 'eraser', 'qty': 25 } ] )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.INSERT ); assertThat( queryDescriptor.getUpdateOrInsertOne() ).isNull(); assertThat( queryDescriptor.getUpdateOrInsertMany() ).isEqualTo( DocumentUtil.fromJsonArray( "[ { '_id': 11, 'item': 'pencil', 'qty': 50, 'type': 'no.2' }, { 'item': 'pen', 'qty': 20 }, { 'item': 'eraser', 'qty': 25 } ]" ) ); } @Test public void shouldParseQueryInsertMultipleDocumentsAndOptions() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.insertMany( [ { '_id': 11, 'item': 'pencil', 'qty': 50, 'type': 'no.2' }, { 'item': 'pen', 'qty': 20 }, { 'item': 'eraser', 'qty': 25 } ], { 'ordered': true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.INSERTMANY ); assertThat( queryDescriptor.getUpdateOrInsertMany() ).isEqualTo( DocumentUtil.fromJsonArray( "[ { '_id': 11, 'item': 'pencil', 'qty': 50, 'type': 'no.2' }, { 'item': 'pen', 'qty': 20 }, { 'item': 'eraser', 'qty': 25 } ]" ) ); assertThat( queryDescriptor.getOptions() ).isEqualTo( Document.parse( "{ ordered: true })" ) ); } @Test public void shouldParseQueryWithEmptyRemove() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.remove( {\n }\n )" ); // Include superfluous whitespace. MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.REMOVE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( new Document() ); } @Test public void shouldParseQueryWithEmptyRemoveAndOptionalJustOne() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.remove({},true)" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.REMOVE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( new Document() ); assertThat( queryDescriptor.getOptions() ).isEqualTo( Document.parse( "{ \"justOne\" : true }" ) ); } @Test public void shouldParseQueryWithEmptyRemoveAndOptions() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.remove( { }, { 'justOne': true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.REMOVE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( new Document() ); assertThat( queryDescriptor.getOptions() ).isEqualTo( Document.parse( "{ \"justOne\" : true }" ) ); } @Test public void shouldParseQueryUpdate() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.update( { 'name': 'Andy' }, { 'rating': 1, 'score': 1 } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.UPDATE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ 'name': 'Andy' }" ) ); assertThat( queryDescriptor.getUpdateOrInsertOne() ).isEqualTo( Document.parse( "{ 'rating': 1, 'score': 1 }" ) ); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryUpdateWithOptions() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.update( { 'name': 'Andy' }, { 'rating': 1, 'score': 1 }, { 'upsert': true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.UPDATE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ 'name': 'Andy' }" ) ); assertThat( queryDescriptor.getUpdateOrInsertOne() ).isEqualTo( Document.parse( "{ 'rating': 1, 'score': 1 }" ) ); assertThat( queryDescriptor.getOptions() ).isEqualTo( Document.parse( "{ 'upsert': true }" ) ); } @Test public void shouldParseQueryFindAndModify() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.findAndModify( { 'query': { 'name': 'Andy' }, 'sort': { 'rating': 1 }, 'update': { '$inc': { 'score': 1 } }, 'upsert': true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FINDANDMODIFY ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ 'query': { 'name': 'Andy' }, 'sort': { 'rating': 1 }, 'update': { '$inc': { 'score': 1 } }, 'upsert': true }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryFindOneWithoutCriteriaNorProjection() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.findOne( )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FINDONE ); assertThat( queryDescriptor.getCriteria() ).isNull(); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryFindOneWithoutProjection() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.findOne( { \"foo\" : true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FINDONE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryFindOneWithCriteriaAndProjection() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.findOne( { \"foo\" : true }, { \"foo\" : 1 } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FINDONE ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isEqualTo( Document.parse( "{ \"foo\" : 1 }" ) ); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryWithProjection() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find( { \"foo\" : true }, { \"foo\" : 1 } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isEqualTo( Document.parse( "{ \"foo\" : 1 }" ) ); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryWithWhitespace() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( " db . Order . find ( { \" foo \" : true } , { \"foo\" : 1 } ) " ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( run.hasErrors() ).isFalse(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \" foo \" : true }" ) ); assertThat( queryDescriptor.getProjection() ).isEqualTo( Document.parse( "{ \"foo\" : 1 }" ) ); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseQueryWithSeveralConditions() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ReportingParseRunner<MongoDBQueryDescriptorBuilder> runner = new ReportingParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ); ParsingResult<MongoDBQueryDescriptorBuilder> run = runner .run( "db.Order.find( { \"foo\" : true, \"bar\" : 42, \"baz\" : \"qux\" } )" ); assertThat( run.hasErrors() ).isFalse(); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ \"foo\" : true, \"bar\" : 42, \"baz\" : \"qux\" }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseCountQuery() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.count()" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getCriteria() ).isNull(); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseCountQueryWithCriteria() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.count( { 'foo' : true } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ 'foo' : true }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseCountQueryWithLogicalOperatorOR() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.count( { '$or': [ { 'foo' : true }, { 'bar' : '42' } ] } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$or': [ { 'foo' : true }, { 'bar' : '42' } ] } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseCountQueryWithLogicalOperatorAND() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.count( { '$and': [ { 'foo' : true }, { 'bar' : '42' } ] } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$and': [ { 'foo' : true }, { 'bar' : '42' } ] } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseCountQueryWithLogicalOperatorNOR() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.count( { '$nor': [ { 'foo' : true }, { 'bar' : '42' } ] } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$nor': [ { 'foo' : true }, { 'bar' : '42' } ] } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseCountQueryWithLogicalOperatorNOT() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.count( { '$not': { 'foo' : false } } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$not': { 'foo' : false } } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseFindQueryWithLogicalOperatorOR() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find( { '$or': [ { 'foo' : true }, { 'bar' : '42' } ] } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$or': [ { 'foo' : true }, { 'bar' : '42' } ] } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldParseFindQueryWithLogicalOperatorAND() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find( { '$and': [ { 'foo' : true }, { 'bar' : '42' } ] } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$and': [ { 'foo' : true }, { 'bar' : '42' } ] } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldFindCountQueryWithLogicalOperatorNOR() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find( { '$nor': [ { 'foo' : true }, { 'bar' : '42' } ] } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$nor': [ { 'foo' : true }, { 'bar' : '42' } ] } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test public void shouldFindeCountQueryWithLogicalOperatorNOT() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.Order.find( { '$not': { 'foo' : false } } )" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "Order" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.FIND ); assertThat( queryDescriptor.getCriteria() ).isEqualTo( Document.parse( "{ '$not': { 'foo' : false } } }" ) ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } @Test @TestForIssue(jiraKey = "OGM-900") public void shouldSupportDotInCollectionName() { NativeQueryParser parser = Parboiled.createParser( NativeQueryParser.class ); ParsingResult<MongoDBQueryDescriptorBuilder> run = new RecoveringParseRunner<MongoDBQueryDescriptorBuilder>( parser.Query() ) .run( "db.POEM.COM.count()" ); MongoDBQueryDescriptor queryDescriptor = run.resultValue.build(); assertThat( queryDescriptor.getCollectionName() ).isEqualTo( "POEM.COM" ); assertThat( queryDescriptor.getOperation() ).isEqualTo( Operation.COUNT ); assertThat( queryDescriptor.getProjection() ).isNull(); assertThat( queryDescriptor.getOrderBy() ).isNull(); } }