Skip to content

Commit 7158538

Browse files
authored
Merge pull request #94 from micw/support_exists_projection
Support for existsBy projection
2 parents 909c785 + adb3a96 commit 7158538

File tree

3 files changed

+295
-8
lines changed

3 files changed

+295
-8
lines changed

src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQuery.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ else if (method.isSliceQuery() && !isSingleEntityResultsRestriction()) {
6767
protected abstract Query<T> doCreateQuery(Object[] values);
6868
protected abstract Query<Long> doCreateCountQuery(Object[] values,boolean pageQuery);
6969
protected abstract boolean isCountQuery();
70+
protected abstract boolean isExistsQuery();
7071

7172
protected abstract Integer getResultsRestrictionIfApplicable();
7273
protected abstract boolean isSingleEntityResultsRestriction();
@@ -250,10 +251,17 @@ public Object execute(AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] value
250251
{
251252
return dynamoDBQuery.doCreateCountQueryWithPermissions(values,false).getSingleResult();
252253
}
253-
else
254-
{
255-
return dynamoDBQuery.doCreateQueryWithPermissions(values).getSingleResult();
256-
}
254+
else
255+
{
256+
if (isExistsQuery())
257+
{
258+
return !dynamoDBQuery.doCreateQueryWithPermissions(values).getResultList().isEmpty();
259+
}
260+
else
261+
{
262+
return dynamoDBQuery.doCreateQueryWithPermissions(values).getSingleResult();
263+
}
264+
}
257265

258266
}
259267
}

src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,15 @@ public Query<Long> doCreateCountQuery(Object[] values,boolean pageQuery) {
7575

7676
}
7777

78-
@Override
79-
protected boolean isCountQuery() {
80-
return tree.isCountProjection();
81-
}
78+
@Override
79+
protected boolean isCountQuery() {
80+
return tree.isCountProjection();
81+
}
82+
83+
@Override
84+
protected boolean isExistsQuery() {
85+
return tree.isExistsProjection();
86+
}
8287

8388
@Override
8489
protected Integer getResultsRestrictionIfApplicable() {

src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3653,4 +3653,278 @@ public void testExecute_WhenFinderMethodIsFindingEntityList_WithSingleStringPara
36533653
Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue());
36543654
}
36553655

3656+
@SuppressWarnings({ "unchecked", "rawtypes" })
3657+
@Test
3658+
public void testExecute_WhenExistsQueryFindsNoEntity() {
3659+
setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class,
3660+
"existsByName", 1, "id", null);
3661+
Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name");
3662+
3663+
// Mock out specific DynamoDBOperations behavior expected by this method
3664+
ArgumentCaptor<DynamoDBScanExpression> scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class);
3665+
ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class);
3666+
Mockito.when(mockUserScanResults.size()).thenReturn(0);
3667+
Mockito.when(mockUserScanResults.isEmpty()).thenReturn(true);
3668+
Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn(
3669+
mockUserScanResults);
3670+
3671+
// Execute the query
3672+
Object[] parameters = new Object[] { "someName" };
3673+
Object o = partTreeDynamoDBQuery.execute(parameters);
3674+
3675+
// Assert that we obtain the expected single result
3676+
assertEquals(false, o);
3677+
3678+
// Assert that we scanned DynamoDB for the correct class
3679+
assertEquals(User.class, classCaptor.getValue());
3680+
3681+
// Assert that we have only one filter condition, for the name of the
3682+
// property
3683+
Map<String, Condition> filterConditions = scanCaptor.getValue().getScanFilter();
3684+
assertEquals(1, filterConditions.size());
3685+
Condition filterCondition = filterConditions.get("Name");
3686+
assertNotNull(filterCondition);
3687+
3688+
assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator());
3689+
3690+
// Assert we only have one attribute value for this filter condition
3691+
assertEquals(1, filterCondition.getAttributeValueList().size());
3692+
3693+
// Assert that there the attribute value type for this attribute value
3694+
// is String,
3695+
// and its value is the parameter expected
3696+
assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS());
3697+
3698+
// Assert that all other attribute value types other than String type
3699+
// are null
3700+
assertNull(filterCondition.getAttributeValueList().get(0).getSS());
3701+
assertNull(filterCondition.getAttributeValueList().get(0).getN());
3702+
assertNull(filterCondition.getAttributeValueList().get(0).getNS());
3703+
assertNull(filterCondition.getAttributeValueList().get(0).getB());
3704+
assertNull(filterCondition.getAttributeValueList().get(0).getBS());
3705+
3706+
// Verify that the expected DynamoDBOperations method was called
3707+
Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue());
3708+
}
3709+
3710+
@SuppressWarnings({ "unchecked", "rawtypes" })
3711+
@Test
3712+
public void testExecute_WhenExistsQueryFindsOneEntity() {
3713+
setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class,
3714+
"existsByName", 1, "id", null);
3715+
Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name");
3716+
3717+
// Mock out specific DynamoDBOperations behavior expected by this method
3718+
ArgumentCaptor<DynamoDBScanExpression> scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class);
3719+
ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class);
3720+
Mockito.when(mockUserScanResults.get(0)).thenReturn(mockUser);
3721+
Mockito.when(mockUserScanResults.size()).thenReturn(1);
3722+
Mockito.when(mockUserScanResults.isEmpty()).thenReturn(false);
3723+
Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn(
3724+
mockUserScanResults);
3725+
3726+
// Execute the query
3727+
Object[] parameters = new Object[] { "someName" };
3728+
Object o = partTreeDynamoDBQuery.execute(parameters);
3729+
3730+
// Assert that we obtain the expected single result
3731+
assertEquals(true, o);
3732+
3733+
// Assert that we scanned DynamoDB for the correct class
3734+
assertEquals(classCaptor.getValue(), User.class);
3735+
3736+
// Assert that we have only one filter condition, for the name of the
3737+
// property
3738+
Map<String, Condition> filterConditions = scanCaptor.getValue().getScanFilter();
3739+
assertEquals(1, filterConditions.size());
3740+
Condition filterCondition = filterConditions.get("Name");
3741+
assertNotNull(filterCondition);
3742+
3743+
assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator());
3744+
3745+
// Assert we only have one attribute value for this filter condition
3746+
assertEquals(1, filterCondition.getAttributeValueList().size());
3747+
3748+
// Assert that there the attribute value type for this attribute value
3749+
// is String,
3750+
// and its value is the parameter expected
3751+
assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS());
3752+
3753+
// Assert that all other attribute value types other than String type
3754+
// are null
3755+
assertNull(filterCondition.getAttributeValueList().get(0).getSS());
3756+
assertNull(filterCondition.getAttributeValueList().get(0).getN());
3757+
assertNull(filterCondition.getAttributeValueList().get(0).getNS());
3758+
assertNull(filterCondition.getAttributeValueList().get(0).getB());
3759+
assertNull(filterCondition.getAttributeValueList().get(0).getBS());
3760+
3761+
// Verify that the expected DynamoDBOperations method was called
3762+
Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue());
3763+
}
3764+
3765+
3766+
@SuppressWarnings({ "unchecked", "rawtypes" })
3767+
@Test
3768+
public void testExecute_WhenExistsQueryFindsMultipleEntities() {
3769+
setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class,
3770+
"existsByName", 1, "id", null);
3771+
Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name");
3772+
3773+
// Mock out specific DynamoDBOperations behavior expected by this method
3774+
ArgumentCaptor<DynamoDBScanExpression> scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class);
3775+
ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class);
3776+
Mockito.when(mockUserScanResults.get(0)).thenReturn(mockUser);
3777+
Mockito.when(mockUserScanResults.get(1)).thenReturn(mockUser);
3778+
Mockito.when(mockUserScanResults.size()).thenReturn(2);
3779+
Mockito.when(mockUserScanResults.isEmpty()).thenReturn(false);
3780+
Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn(
3781+
mockUserScanResults);
3782+
3783+
// Execute the query
3784+
Object[] parameters = new Object[] { "someName" };
3785+
Object o = partTreeDynamoDBQuery.execute(parameters);
3786+
3787+
// Assert that we obtain the expected single result
3788+
assertEquals(true, o);
3789+
3790+
// Assert that we scanned DynamoDB for the correct class
3791+
assertEquals(classCaptor.getValue(), User.class);
3792+
3793+
// Assert that we have only one filter condition, for the name of the
3794+
// property
3795+
Map<String, Condition> filterConditions = scanCaptor.getValue().getScanFilter();
3796+
assertEquals(1, filterConditions.size());
3797+
Condition filterCondition = filterConditions.get("Name");
3798+
assertNotNull(filterCondition);
3799+
3800+
assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator());
3801+
3802+
// Assert we only have one attribute value for this filter condition
3803+
assertEquals(1, filterCondition.getAttributeValueList().size());
3804+
3805+
// Assert that there the attribute value type for this attribute value
3806+
// is String,
3807+
// and its value is the parameter expected
3808+
assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS());
3809+
3810+
// Assert that all other attribute value types other than String type
3811+
// are null
3812+
assertNull(filterCondition.getAttributeValueList().get(0).getSS());
3813+
assertNull(filterCondition.getAttributeValueList().get(0).getN());
3814+
assertNull(filterCondition.getAttributeValueList().get(0).getNS());
3815+
assertNull(filterCondition.getAttributeValueList().get(0).getB());
3816+
assertNull(filterCondition.getAttributeValueList().get(0).getBS());
3817+
3818+
// Verify that the expected DynamoDBOperations method was called
3819+
Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue());
3820+
}
3821+
3822+
@SuppressWarnings({ "unchecked", "rawtypes" })
3823+
@Test
3824+
public void testExecute_WhenExistsWithLimitQueryFindsNoEntity() {
3825+
setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class,
3826+
"existsTop1ByName", 1, "id", null);
3827+
Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name");
3828+
3829+
// Mock out specific DynamoDBOperations behavior expected by this method
3830+
ArgumentCaptor<DynamoDBScanExpression> scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class);
3831+
ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class);
3832+
Mockito.when(mockUserScanResults.size()).thenReturn(0);
3833+
Mockito.when(mockUserScanResults.isEmpty()).thenReturn(true);
3834+
Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn(
3835+
mockUserScanResults);
3836+
3837+
// Execute the query
3838+
Object[] parameters = new Object[] { "someName" };
3839+
Object o = partTreeDynamoDBQuery.execute(parameters);
3840+
3841+
// Assert that we obtain the expected single result
3842+
assertEquals(false, o);
3843+
3844+
// Assert that we scanned DynamoDB for the correct class
3845+
assertEquals(User.class, classCaptor.getValue());
3846+
3847+
// Assert that we have only one filter condition, for the name of the
3848+
// property
3849+
Map<String, Condition> filterConditions = scanCaptor.getValue().getScanFilter();
3850+
assertEquals(1, filterConditions.size());
3851+
Condition filterCondition = filterConditions.get("Name");
3852+
assertNotNull(filterCondition);
3853+
3854+
assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator());
3855+
3856+
// Assert we only have one attribute value for this filter condition
3857+
assertEquals(1, filterCondition.getAttributeValueList().size());
3858+
3859+
// Assert that there the attribute value type for this attribute value
3860+
// is String,
3861+
// and its value is the parameter expected
3862+
assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS());
3863+
3864+
// Assert that all other attribute value types other than String type
3865+
// are null
3866+
assertNull(filterCondition.getAttributeValueList().get(0).getSS());
3867+
assertNull(filterCondition.getAttributeValueList().get(0).getN());
3868+
assertNull(filterCondition.getAttributeValueList().get(0).getNS());
3869+
assertNull(filterCondition.getAttributeValueList().get(0).getB());
3870+
assertNull(filterCondition.getAttributeValueList().get(0).getBS());
3871+
3872+
// Verify that the expected DynamoDBOperations method was called
3873+
Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue());
3874+
}
3875+
3876+
@SuppressWarnings({ "unchecked", "rawtypes" })
3877+
@Test
3878+
public void testExecute_WhenExistsWithLimitQueryFindsOneEntity() {
3879+
setupCommonMocksForThisRepositoryMethod(mockUserEntityMetadata, mockDynamoDBUserQueryMethod, User.class,
3880+
"existsTop1ByName", 1, "id", null);
3881+
Mockito.when(mockUserEntityMetadata.getOverriddenAttributeName("name")).thenReturn("Name");
3882+
3883+
// Mock out specific DynamoDBOperations behavior expected by this method
3884+
ArgumentCaptor<DynamoDBScanExpression> scanCaptor = ArgumentCaptor.forClass(DynamoDBScanExpression.class);
3885+
ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class);
3886+
Mockito.when(mockUserScanResults.get(0)).thenReturn(mockUser);
3887+
Mockito.when(mockUserScanResults.size()).thenReturn(1);
3888+
Mockito.when(mockUserScanResults.isEmpty()).thenReturn(false);
3889+
Mockito.when(mockDynamoDBOperations.scan(classCaptor.capture(), scanCaptor.capture())).thenReturn(
3890+
mockUserScanResults);
3891+
3892+
// Execute the query
3893+
Object[] parameters = new Object[] { "someName" };
3894+
Object o = partTreeDynamoDBQuery.execute(parameters);
3895+
3896+
// Assert that we obtain the expected single result
3897+
assertEquals(true, o);
3898+
3899+
// Assert that we scanned DynamoDB for the correct class
3900+
assertEquals(classCaptor.getValue(), User.class);
3901+
3902+
// Assert that we have only one filter condition, for the name of the
3903+
// property
3904+
Map<String, Condition> filterConditions = scanCaptor.getValue().getScanFilter();
3905+
assertEquals(1, filterConditions.size());
3906+
Condition filterCondition = filterConditions.get("Name");
3907+
assertNotNull(filterCondition);
3908+
3909+
assertEquals(ComparisonOperator.EQ.name(), filterCondition.getComparisonOperator());
3910+
3911+
// Assert we only have one attribute value for this filter condition
3912+
assertEquals(1, filterCondition.getAttributeValueList().size());
3913+
3914+
// Assert that there the attribute value type for this attribute value
3915+
// is String,
3916+
// and its value is the parameter expected
3917+
assertEquals("someName", filterCondition.getAttributeValueList().get(0).getS());
3918+
3919+
// Assert that all other attribute value types other than String type
3920+
// are null
3921+
assertNull(filterCondition.getAttributeValueList().get(0).getSS());
3922+
assertNull(filterCondition.getAttributeValueList().get(0).getN());
3923+
assertNull(filterCondition.getAttributeValueList().get(0).getNS());
3924+
assertNull(filterCondition.getAttributeValueList().get(0).getB());
3925+
assertNull(filterCondition.getAttributeValueList().get(0).getBS());
3926+
3927+
// Verify that the expected DynamoDBOperations method was called
3928+
Mockito.verify(mockDynamoDBOperations).scan(classCaptor.getValue(), scanCaptor.getValue());
3929+
}
36563930
}

0 commit comments

Comments
 (0)