diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQuery.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQuery.java index e47b9093..530d3c25 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQuery.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQuery.java @@ -67,6 +67,7 @@ else if (method.isSliceQuery() && !isSingleEntityResultsRestriction()) { protected abstract Query doCreateQuery(Object[] values); protected abstract Query doCreateCountQuery(Object[] values,boolean pageQuery); protected abstract boolean isCountQuery(); + protected abstract boolean isExistsQuery(); protected abstract Integer getResultsRestrictionIfApplicable(); protected abstract boolean isSingleEntityResultsRestriction(); @@ -250,10 +251,17 @@ public Object execute(AbstractDynamoDBQuery dynamoDBQuery, Object[] value { return dynamoDBQuery.doCreateCountQueryWithPermissions(values,false).getSingleResult(); } - else - { - return dynamoDBQuery.doCreateQueryWithPermissions(values).getSingleResult(); - } + else + { + if (isExistsQuery()) + { + return !dynamoDBQuery.doCreateQueryWithPermissions(values).getResultList().isEmpty(); + } + else + { + return dynamoDBQuery.doCreateQueryWithPermissions(values).getSingleResult(); + } + } } } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java index 438f21ad..9ba12403 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java @@ -75,10 +75,15 @@ public Query doCreateCountQuery(Object[] values,boolean pageQuery) { } - @Override - protected boolean isCountQuery() { - return tree.isCountProjection(); - } + @Override + protected boolean isCountQuery() { + return tree.isCountProjection(); + } + + @Override + protected boolean isExistsQuery() { + return tree.isExistsProjection(); + } @Override protected Integer getResultsRestrictionIfApplicable() { diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java b/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java index 03fca06c..3591b24b 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java @@ -3653,4 +3653,278 @@ public void testExecute_WhenFinderMethodIsFindingEntityList_WithSingleStringPara Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue()); } + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testExecute_WhenExistsQueryFindsNoEntity() { + setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class, + "existsByName", 1, "id", null); + Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name"); + + // Mock out specific DynamoDBOperations behavior expected by this method + ArgumentCaptor scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class); + ArgumentCaptor classCaptor = ArgumentCaptor.forClass(Class.class); + Mockito.when(mockUserScanResults.size()).thenReturn(0); + Mockito.when(mockUserScanResults.isEmpty()).thenReturn(true); + Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn( + mockUserScanResults); + + // Execute the query + Object[] parameters = new Object[] { "someName" }; + Object o = partTreeDynamoDBQuery.execute(parameters); + + // Assert that we obtain the expected single result + assertEquals(false, o); + + // Assert that we scanned DynamoDB for the correct class + assertEquals(User.class, classCaptor.getValue()); + + // Assert that we have only one filter condition, for the name of the + // property + Map filterConditions = scanCaptor.getValue().getScanFilter(); + assertEquals(1, filterConditions.size()); + Condition filterCondition = filterConditions.get("Name"); + assertNotNull(filterCondition); + + assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator()); + + // Assert we only have one attribute value for this filter condition + assertEquals(1, filterCondition.getAttributeValueList().size()); + + // Assert that there the attribute value type for this attribute value + // is String, + // and its value is the parameter expected + assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS()); + + // Assert that all other attribute value types other than String type + // are null + assertNull(filterCondition.getAttributeValueList().get(0).getSS()); + assertNull(filterCondition.getAttributeValueList().get(0).getN()); + assertNull(filterCondition.getAttributeValueList().get(0).getNS()); + assertNull(filterCondition.getAttributeValueList().get(0).getB()); + assertNull(filterCondition.getAttributeValueList().get(0).getBS()); + + // Verify that the expected DynamoDBOperations method was called + Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testExecute_WhenExistsQueryFindsOneEntity() { + setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class, + "existsByName", 1, "id", null); + Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name"); + + // Mock out specific DynamoDBOperations behavior expected by this method + ArgumentCaptor scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class); + ArgumentCaptor classCaptor = ArgumentCaptor.forClass(Class.class); + Mockito.when(mockUserScanResults.get(0)).thenReturn(mockUser); + Mockito.when(mockUserScanResults.size()).thenReturn(1); + Mockito.when(mockUserScanResults.isEmpty()).thenReturn(false); + Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn( + mockUserScanResults); + + // Execute the query + Object[] parameters = new Object[] { "someName" }; + Object o = partTreeDynamoDBQuery.execute(parameters); + + // Assert that we obtain the expected single result + assertEquals(true, o); + + // Assert that we scanned DynamoDB for the correct class + assertEquals(classCaptor.getValue(), User.class); + + // Assert that we have only one filter condition, for the name of the + // property + Map filterConditions = scanCaptor.getValue().getScanFilter(); + assertEquals(1, filterConditions.size()); + Condition filterCondition = filterConditions.get("Name"); + assertNotNull(filterCondition); + + assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator()); + + // Assert we only have one attribute value for this filter condition + assertEquals(1, filterCondition.getAttributeValueList().size()); + + // Assert that there the attribute value type for this attribute value + // is String, + // and its value is the parameter expected + assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS()); + + // Assert that all other attribute value types other than String type + // are null + assertNull(filterCondition.getAttributeValueList().get(0).getSS()); + assertNull(filterCondition.getAttributeValueList().get(0).getN()); + assertNull(filterCondition.getAttributeValueList().get(0).getNS()); + assertNull(filterCondition.getAttributeValueList().get(0).getB()); + assertNull(filterCondition.getAttributeValueList().get(0).getBS()); + + // Verify that the expected DynamoDBOperations method was called + Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue()); + } + + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testExecute_WhenExistsQueryFindsMultipleEntities() { + setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class, + "existsByName", 1, "id", null); + Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name"); + + // Mock out specific DynamoDBOperations behavior expected by this method + ArgumentCaptor scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class); + ArgumentCaptor classCaptor = ArgumentCaptor.forClass(Class.class); + Mockito.when(mockUserScanResults.get(0)).thenReturn(mockUser); + Mockito.when(mockUserScanResults.get(1)).thenReturn(mockUser); + Mockito.when(mockUserScanResults.size()).thenReturn(2); + Mockito.when(mockUserScanResults.isEmpty()).thenReturn(false); + Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn( + mockUserScanResults); + + // Execute the query + Object[] parameters = new Object[] { "someName" }; + Object o = partTreeDynamoDBQuery.execute(parameters); + + // Assert that we obtain the expected single result + assertEquals(true, o); + + // Assert that we scanned DynamoDB for the correct class + assertEquals(classCaptor.getValue(), User.class); + + // Assert that we have only one filter condition, for the name of the + // property + Map filterConditions = scanCaptor.getValue().getScanFilter(); + assertEquals(1, filterConditions.size()); + Condition filterCondition = filterConditions.get("Name"); + assertNotNull(filterCondition); + + assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator()); + + // Assert we only have one attribute value for this filter condition + assertEquals(1, filterCondition.getAttributeValueList().size()); + + // Assert that there the attribute value type for this attribute value + // is String, + // and its value is the parameter expected + assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS()); + + // Assert that all other attribute value types other than String type + // are null + assertNull(filterCondition.getAttributeValueList().get(0).getSS()); + assertNull(filterCondition.getAttributeValueList().get(0).getN()); + assertNull(filterCondition.getAttributeValueList().get(0).getNS()); + assertNull(filterCondition.getAttributeValueList().get(0).getB()); + assertNull(filterCondition.getAttributeValueList().get(0).getBS()); + + // Verify that the expected DynamoDBOperations method was called + Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testExecute_WhenExistsWithLimitQueryFindsNoEntity() { + setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class, + "existsTop1ByName", 1, "id", null); + Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name"); + + // Mock out specific DynamoDBOperations behavior expected by this method + ArgumentCaptor scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class); + ArgumentCaptor classCaptor = ArgumentCaptor.forClass(Class.class); + Mockito.when(mockUserScanResults.size()).thenReturn(0); + Mockito.when(mockUserScanResults.isEmpty()).thenReturn(true); + Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn( + mockUserScanResults); + + // Execute the query + Object[] parameters = new Object[] { "someName" }; + Object o = partTreeDynamoDBQuery.execute(parameters); + + // Assert that we obtain the expected single result + assertEquals(false, o); + + // Assert that we scanned DynamoDB for the correct class + assertEquals(User.class, classCaptor.getValue()); + + // Assert that we have only one filter condition, for the name of the + // property + Map filterConditions = scanCaptor.getValue().getScanFilter(); + assertEquals(1, filterConditions.size()); + Condition filterCondition = filterConditions.get("Name"); + assertNotNull(filterCondition); + + assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator()); + + // Assert we only have one attribute value for this filter condition + assertEquals(1, filterCondition.getAttributeValueList().size()); + + // Assert that there the attribute value type for this attribute value + // is String, + // and its value is the parameter expected + assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS()); + + // Assert that all other attribute value types other than String type + // are null + assertNull(filterCondition.getAttributeValueList().get(0).getSS()); + assertNull(filterCondition.getAttributeValueList().get(0).getN()); + assertNull(filterCondition.getAttributeValueList().get(0).getNS()); + assertNull(filterCondition.getAttributeValueList().get(0).getB()); + assertNull(filterCondition.getAttributeValueList().get(0).getBS()); + + // Verify that the expected DynamoDBOperations method was called + Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testExecute_WhenExistsWithLimitQueryFindsOneEntity() { + setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class, + "existsTop1ByName", 1, "id", null); + Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name"); + + // Mock out specific DynamoDBOperations behavior expected by this method + ArgumentCaptor scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class); + ArgumentCaptor classCaptor = ArgumentCaptor.forClass(Class.class); + Mockito.when(mockUserScanResults.get(0)).thenReturn(mockUser); + Mockito.when(mockUserScanResults.size()).thenReturn(1); + Mockito.when(mockUserScanResults.isEmpty()).thenReturn(false); + Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn( + mockUserScanResults); + + // Execute the query + Object[] parameters = new Object[] { "someName" }; + Object o = partTreeDynamoDBQuery.execute(parameters); + + // Assert that we obtain the expected single result + assertEquals(true, o); + + // Assert that we scanned DynamoDB for the correct class + assertEquals(classCaptor.getValue(), User.class); + + // Assert that we have only one filter condition, for the name of the + // property + Map filterConditions = scanCaptor.getValue().getScanFilter(); + assertEquals(1, filterConditions.size()); + Condition filterCondition = filterConditions.get("Name"); + assertNotNull(filterCondition); + + assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator()); + + // Assert we only have one attribute value for this filter condition + assertEquals(1, filterCondition.getAttributeValueList().size()); + + // Assert that there the attribute value type for this attribute value + // is String, + // and its value is the parameter expected + assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS()); + + // Assert that all other attribute value types other than String type + // are null + assertNull(filterCondition.getAttributeValueList().get(0).getSS()); + assertNull(filterCondition.getAttributeValueList().get(0).getN()); + assertNull(filterCondition.getAttributeValueList().get(0).getNS()); + assertNull(filterCondition.getAttributeValueList().get(0).getB()); + assertNull(filterCondition.getAttributeValueList().get(0).getBS()); + + // Verify that the expected DynamoDBOperations method was called + Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue()); + } }