protected Query<Long> buildFinderCountQuery(DynamoDBOperations dynamoDBOperations,boolean pageQuery) { if (isApplicableForQuery()) { if (isApplicableForGlobalSecondaryIndex()) { String tableName = dynamoDBOperations.getOverriddenTableName(entityInformation.getDynamoDBTableName()); QueryRequest queryRequest = buildQueryRequest(tableName, getGlobalSecondaryIndexName(), getHashKeyAttributeName(), getRangeKeyAttributeName(), this.getRangeKeyPropertyName(), getHashKeyConditions(), getRangeKeyConditions()); return new QueryRequestCountQuery<T>(dynamoDBOperations,entityInformation.getJavaType(), queryRequest); } else { DynamoDBQueryExpression<T> queryExpression = buildQueryExpression(); return new QueryExpressionCountQuery<T>(dynamoDBOperations, entityInformation.getJavaType(), queryExpression); } } else { return new ScanExpressionCountQuery<T>(dynamoDBOperations, clazz, buildScanExpression(),pageQuery); } }
/** * Queries the DynamoDB GSI for unprocessed {@link Metadata} with a maximum of 96 items. * * Iterates over all of the different partitions, returning a maximum of three items from each. * * @return {@link List} of unprocessed {@link Metadata} */ public List<Metadata> getUnprocessedCpcPlusMetaData() { return IntStream.range(0, Constants.CPC_DYNAMO_PARTITIONS).mapToObj(partition -> { Map<String, AttributeValue> valueMap = new HashMap<>(); valueMap.put(":cpcValue", new AttributeValue().withS(Constants.CPC_DYNAMO_PARTITION_START + partition)); valueMap.put(":cpcProcessedValue", new AttributeValue().withS("false")); DynamoDBQueryExpression<Metadata> metadataQuery = new DynamoDBQueryExpression<Metadata>() .withIndexName("Cpc-CpcProcessed_CreateDate-index") .withKeyConditionExpression(Constants.DYNAMO_CPC_ATTRIBUTE + " = :cpcValue and begins_with(" + Constants.DYNAMO_CPC_PROCESSED_CREATE_DATE_ATTRIBUTE + ", :cpcProcessedValue)") .withExpressionAttributeValues(valueMap) .withConsistentRead(false) .withLimit(LIMIT); return mapper.queryPage(Metadata.class, metadataQuery).getResults().stream(); }).flatMap(Function.identity()).collect(Collectors.toList()); }
@Override public List<Event> findEventsByCity(String city) { Map<String, AttributeValue> eav = new HashMap<>(); eav.put(":v1", new AttributeValue().withS(city)); DynamoDBQueryExpression<Event> query = new DynamoDBQueryExpression<Event>() .withIndexName(Event.CITY_INDEX) .withConsistentRead(false) .withKeyConditionExpression("city = :v1") .withExpressionAttributeValues(eav); return mapper.query(Event.class, query); // NOTE: without an index, this query would require a full table scan with a filter: /* DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withFilterExpression("city = :val1") .withExpressionAttributeValues(eav); return mapper.scan(Event.class, scanExpression); */ }
private static <T> QueryRequest testCreateQueryRequestFromExpression( Class<T> clazz, DynamoDBQueryExpression<T> queryExpression, String expectedErrorMessage) { try { QueryRequest request = (QueryRequest) testedMethod.invoke(mapper, clazz, queryExpression, DynamoDBMapperConfig.DEFAULT); if (expectedErrorMessage != null) { fail("Exception containing messsage (" + expectedErrorMessage + ") is expected."); } return request; } catch (InvocationTargetException ite) { if (expectedErrorMessage != null) { assertTrue("Exception message [" + ite.getCause().getMessage() + "] does not contain " + "the expected message [" + expectedErrorMessage + "].", ite.getCause().getMessage().contains(expectedErrorMessage)); } else { ite.getCause().printStackTrace(); fail("Internal error when calling createQueryRequestFromExpressio method"); } } catch (Exception e) { fail(e.getMessage()); } return null; }
protected void applySortIfSpecified(DynamoDBQueryExpression<T> queryExpression, List<String> permittedPropertyNames) { if (permittedPropertyNames.size() > 1) { throw new UnsupportedOperationException("Can only sort by at most a single range or index range key"); } if (sort != null) { boolean sortAlreadySet = false; for (Order order : sort) { if (permittedPropertyNames.contains(order.getProperty())) { if (sortAlreadySet) { throw new UnsupportedOperationException("Sorting by multiple attributes not possible"); } queryExpression.setScanIndexForward(order.getDirection().equals(Direction.ASC)); sortAlreadySet = true; } else { throw new UnsupportedOperationException("Sorting only possible by " + permittedPropertyNames + " for the criteria specified"); } } } }
protected Query<T> buildFinderQuery(DynamoDBOperations dynamoDBOperations) { if (isApplicableForQuery()) { if (isApplicableForGlobalSecondaryIndex()) { String tableName = dynamoDBOperations.getOverriddenTableName(entityInformation.getDynamoDBTableName()); QueryRequest queryRequest = buildQueryRequest(tableName, getGlobalSecondaryIndexName(), getHashKeyAttributeName(), getRangeKeyAttributeName(), this.getRangeKeyPropertyName(), getHashKeyConditions(), getRangeKeyConditions()); return new MultipleEntityQueryRequestQuery<T>(dynamoDBOperations,entityInformation.getJavaType(), queryRequest); } else { DynamoDBQueryExpression<T> queryExpression = buildQueryExpression(); return new MultipleEntityQueryExpressionQuery<T>(dynamoDBOperations, entityInformation.getJavaType(), queryExpression); } } else { return new MultipleEntityScanExpressionQuery<T>(dynamoDBOperations, clazz, buildScanExpression()); } }
private void maybeAddStateFilter(FilterCriteria filter, final DynamoDBQueryExpression<DynamoDBItem<?>> queryExpression) { if (filter.getOperator() != null && filter.getState() != null) { // Convert filter's state to DynamoDBItem in order get suitable string representation for the state final DynamoDBItem<?> filterState = AbstractDynamoDBItem.fromState(filter.getItemName(), filter.getState(), new Date()); queryExpression.setFilterExpression(String.format("%s %s :opstate", DynamoDBItem.ATTRIBUTE_NAME_ITEMSTATE, operatorAsString(filter.getOperator()))); filterState.accept(new DynamoDBItemVisitor() { @Override public void visit(DynamoDBStringItem dynamoStringItem) { queryExpression.setExpressionAttributeValues( ImmutableMap.of(":opstate", new AttributeValue().withS(dynamoStringItem.getState()))); } @Override public void visit(DynamoDBBigDecimalItem dynamoBigDecimalItem) { queryExpression.setExpressionAttributeValues(ImmutableMap.of(":opstate", new AttributeValue().withN(dynamoBigDecimalItem.getState().toPlainString()))); } }); } }
@Test void testGetUnprocessedCpcPlusMetaData() { int itemsPerPartition = 2; QueryResultPage<Metadata> mockMetadataPage = mock(QueryResultPage.class); when(mockMetadataPage.getResults()).thenReturn(Stream.generate(Metadata::new).limit(itemsPerPartition).collect(Collectors.toList())); when(dbMapper.queryPage(eq(Metadata.class), any(DynamoDBQueryExpression.class))).thenReturn(mockMetadataPage); List<Metadata> metaDataList = underTest.getUnprocessedCpcPlusMetaData(); verify(dbMapper, times(Constants.CPC_DYNAMO_PARTITIONS)).queryPage(any(Class.class), any(DynamoDBQueryExpression.class)); assertThat(metaDataList).hasSize(itemsPerPartition * Constants.CPC_DYNAMO_PARTITIONS); }
/** * Perform a query against DynamoDB. The List returned is a * {@code com.amazonaws.services.dynamodbv2.datamodeling.PaginatedQueryList}, which loads List items on demand * (as List is iterated through). Be aware that List methods requiring full iteration (e.g. size()) will * load all list items immediately into memory. * * @param conditionExpression Key condition expression defining the query * @param expressionAV Map of DynamoDB Expression Attribute Values (used to populate conditionExpression) * @param indexName Index to run the query against * @param consistentRead Whether to require consistent read (only available for LocalSecondaryIndexes) * @return PaginatedQueryList of ResourceTriples * @see com.amazonaws.services.dynamodbv2.datamodeling.PaginatedQueryList */ private List<ResourceTriple> executeFindInIndex(final String conditionExpression, final Map<String, AttributeValue> expressionAV, final String indexName, final boolean consistentRead) { final DynamoDBQueryExpression<ResourceTriple> query = new DynamoDBQueryExpression<ResourceTriple>() .withIndexName(indexName) .withConsistentRead(consistentRead) .withKeyConditionExpression(conditionExpression) .withExpressionAttributeValues(expressionAV); return mapper.query(ResourceTriple.class, query); }
public List<LeagueRecord> byType(GameType gameType) { PaginatedQueryList<LeagueRecord> results = tableMapper.query(new DynamoDBQueryExpression<LeagueRecord>() .withScanIndexForward(true) .withLimit(100) .withConsistentRead(false) .withHashKeyValues(LeagueRecord.builder().gameType(gameType).build()) .withIndexName("LeagueByType")); results.loadAllResults(); return results; }
public List<PlayerRecord> lookupByLeague(String leagueId) { PaginatedQueryList<PlayerRecord> results = tableMapper.query(new DynamoDBQueryExpression<PlayerRecord>() .withScanIndexForward(true) .withLimit(100) .withConsistentRead(false) .withHashKeyValues(PlayerRecord.builder().leagueId(leagueId).build()) .withIndexName("PlayerByLeague")); results.loadAllResults(); return results; }
public List<PlayerRecord> lookupByUser(String userId) { PaginatedQueryList<PlayerRecord> results = tableMapper.query(new DynamoDBQueryExpression<PlayerRecord>() .withScanIndexForward(true) .withLimit(100) .withConsistentRead(false) .withHashKeyValues(PlayerRecord.builder().userId(userId).build()) .withIndexName("LeagueByType")); results.loadAllResults(); return results; }
public UserRecord byEmail(String email) { UserRecord lookup = null; PaginatedQueryList<UserRecord> results = tableMapper.query(new DynamoDBQueryExpression<UserRecord>() .withLimit(1) .withConsistentRead(false) .withHashKeyValues(UserRecord.builder().email(email).build()) .withIndexName("UserByEmail")); if (results.size() > 0) { lookup = results.get(0); } return lookup; }
public Collection<T> findByPartition(String bucketName) { PaginatedQueryList<T> result = this.tableMapper.query( new DynamoDBQueryExpression<T>().withRangeKeyCondition(tableMapper.rangeKey().name(), new Condition() .withComparisonOperator(ComparisonOperator.EQ) .withAttributeValueList(new AttributeValue(bucketName)))); return result; }
@Override public List<Event> findEventsByTeam(String team) { DynamoDBQueryExpression<Event> homeQuery = new DynamoDBQueryExpression<>(); Event eventKey = new Event(); eventKey.setHomeTeam(team); homeQuery.setHashKeyValues(eventKey); List<Event> homeEvents = mapper.query(Event.class, homeQuery); Map<String, AttributeValue> eav = new HashMap<>(); eav.put(":v1", new AttributeValue().withS(team)); DynamoDBQueryExpression<Event> awayQuery = new DynamoDBQueryExpression<Event>() .withIndexName(Event.AWAY_TEAM_INDEX) .withConsistentRead(false) .withKeyConditionExpression("awayTeam = :v1") .withExpressionAttributeValues(eav); List<Event> awayEvents = mapper.query(Event.class, awayQuery); // need to create a new list because PaginatedList from query is immutable List<Event> allEvents = new LinkedList<>(); allEvents.addAll(homeEvents); allEvents.addAll(awayEvents); allEvents.sort( (e1, e2) -> e1.getEventDate() <= e2.getEventDate() ? -1 : 1 ); return allEvents; }
@BeforeClass public static void setUp() throws SecurityException, NoSuchMethodException { AmazonDynamoDB dynamo = new AmazonDynamoDBClient(); mapper = TestDynamoDBMapperFactory.createDynamoDBMapper(dynamo); testedMethod = DynamoDBMapper.class.getDeclaredMethod("createQueryRequestFromExpression", Class.class, DynamoDBQueryExpression.class, DynamoDBMapperConfig.class); testedMethod.setAccessible(true); }
@Test public void testHashOnlyQueryOnHashRangeTable() { // Primary hash only query on a Hash+Range table QueryRequest queryRequest = testCreateQueryRequestFromExpression( LSIRangeKeyTestClass.class, new DynamoDBQueryExpression<LSIRangeKeyTestClass>() .withHashKeyValues(new LSIRangeKeyTestClass("foo", null))); assertTrue(queryRequest.getKeyConditions().size() == 1); assertTrue(queryRequest.getKeyConditions().containsKey("primaryHashKey")); assertNull(queryRequest.getIndexName()); // Hash+Range query on a LSI queryRequest = testCreateQueryRequestFromExpression( LSIRangeKeyTestClass.class, new DynamoDBQueryExpression<LSIRangeKeyTestClass>() .withHashKeyValues(new LSIRangeKeyTestClass("foo", null)) .withRangeKeyCondition("lsiRangeKey", RANGE_KEY_CONDITION) .withIndexName("LSI")); assertTrue(queryRequest.getKeyConditions().size() == 2); assertTrue(queryRequest.getKeyConditions().containsKey("primaryHashKey")); assertTrue(queryRequest.getKeyConditions().containsKey("lsiRangeKey")); assertEquals("LSI", queryRequest.getIndexName()); // Hash-only query on a LSI queryRequest = testCreateQueryRequestFromExpression( LSIRangeKeyTestClass.class, new DynamoDBQueryExpression<LSIRangeKeyTestClass>() .withHashKeyValues(new LSIRangeKeyTestClass("foo", null)) .withIndexName("LSI")); assertTrue(queryRequest.getKeyConditions().size() == 1); assertTrue(queryRequest.getKeyConditions().containsKey("primaryHashKey")); assertEquals("LSI", queryRequest.getIndexName()); }
/** * Run Queries against dynamodb * @param clazz * @param itemKey * @param indexName * @param operator * @param rangeKeyConditions * @param limit * @param consistentRead * @return items */ public <T> List<T> query(final Class<T> clazz, final T itemKey, final String indexName, final ConditionalOperator operator, final Map<String, Condition> rangeKeyConditions, final int limit, final boolean consistentRead){ final DynamoDBQueryExpression<T> expression = new DynamoDBQueryExpression<T>(); expression.withHashKeyValues(itemKey); expression.withConsistentRead(consistentRead); /** * Optional Query parameters */ if(!Strings.isNullOrEmpty(indexName)){ expression.withIndexName(indexName); } if(operator!=null){ expression.withConditionalOperator(operator); } if(rangeKeyConditions != null && rangeKeyConditions.size()>0){ expression.withRangeKeyConditions(rangeKeyConditions); } if(limit>0){ expression.withLimit(limit); } List<T> items = this.query(clazz, expression); if(items==null){ return new ArrayList<T>(); }else{ return items; } }
/*** * Get range keys for a given hashKey * @param clazz * @param itemHash * @return rangeKeys */ public <T> List<T> getRanges(final Class<T> clazz, final T itemHash, int limit, Map<String, AttributeValue> startKey){ final Map<String, AttributeValue> starKey = Maps.newHashMap(); final DynamoDBQueryExpression<T> query = new DynamoDBQueryExpression<T>(); query.withHashKeyValues(itemHash); if(limit>0 && starKey!=null){ query.withLimit(limit); query.withExclusiveStartKey(starKey); } return this.mapper.query(clazz, query); }
/** * * @param userId * poster user id * @param timeWindow * how far back to go * @return */ public List<Post> getpostsByUser(String userId, int timeWindow) { long t = (new Date()).getTime() - (((long) timeWindow) * 24L * 60L * 60L * 1000L); Date time = new Date(); time.setTime(t); SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); df.setTimeZone(TimeZone.getTimeZone("UTC")); String timeString = df.format(time); Condition rangeKeyCondition = new Condition().withComparisonOperator( ComparisonOperator.GT.toString()).withAttributeValueList( new AttributeValue().withS(timeString)); Post postKey = new Post(); postKey.setPosterId(userId); DynamoDBQueryExpression<Post> queryExpression = new DynamoDBQueryExpression<Post>() .withHashKeyValues(postKey).withRangeKeyCondition( "PostTimestamp", rangeKeyCondition); List<Post> latestsPosts = mapper.query(Post.class, queryExpression); return latestsPosts; }
/** * * @param craftId * craft id * @param timeWindow * how far back to go * @return */ public List<Post> getpostsByCraft(String craftId, int timeWindow) { long t = (new Date()).getTime() - (((long) timeWindow) * 24L * 60L * 60L * 1000L); Date time = new Date(); time.setTime(t); SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); String timeString = df.format(time); Condition rangeKeyCondition = new Condition().withComparisonOperator( ComparisonOperator.GT.toString()).withAttributeValueList( new AttributeValue().withS(timeString)); Post postKey = new Post(); postKey.setCraftId(craftId); DynamoDBQueryExpression<Post> queryExpression = new DynamoDBQueryExpression<Post>() .withHashKeyValues(postKey) .withRangeKeyCondition("PostTimestamp", rangeKeyCondition) .withIndexName("CraftId-PostTimestamp-index"); queryExpression.setConsistentRead(false); List<Post> latestsPosts = mapper.query(Post.class, queryExpression); return latestsPosts; }
/** * * @param fandomId * fandom id * @param timeWindow * how far back to go * @return */ public List<Post> getpostsByFandom(String fandomtId, int timeWindow) { long t = (new Date()).getTime() - (((long) timeWindow) * 24L * 60L * 60L * 1000L); Date time = new Date(); time.setTime(t); SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); String timeString = df.format(time); Condition rangeKeyCondition = new Condition().withComparisonOperator( ComparisonOperator.GT.toString()).withAttributeValueList( new AttributeValue().withS(timeString)); Post postKey = new Post(); postKey.setFandomId(fandomtId); DynamoDBQueryExpression<Post> queryExpression = new DynamoDBQueryExpression<Post>() .withHashKeyValues(postKey) .withRangeKeyCondition("PostTimestamp", rangeKeyCondition) .withIndexName("FandomId-PostTimestamp-index"); queryExpression.setConsistentRead(false);// this is necessary, otherwise // throws an error List<Post> latestsPosts = mapper.query(Post.class, queryExpression); return latestsPosts; }
private static void FindRepliesInLast15Days(DynamoDBMapper mapper, String forumName, String threadSubject) throws Exception { System.out.println("FindRepliesInLast15Days: Replies within last 15 days."); String hashKey = forumName + "#" + threadSubject; long twoWeeksAgoMilli = (new Date()).getTime() - (15L*24L*60L*60L*1000L); Date twoWeeksAgo = new Date(); twoWeeksAgo.setTime(twoWeeksAgoMilli); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); String twoWeeksAgoStr = dateFormatter.format(twoWeeksAgo); Condition rangeKeyCondition = new Condition() .withComparisonOperator(ComparisonOperator.GT.toString()) .withAttributeValueList(new AttributeValue().withS(twoWeeksAgoStr.toString())); Reply replyKey = new Reply(); replyKey.setId(hashKey); DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>() .withHashKeyValues(replyKey) .withRangeKeyCondition("ReplyDateTime", rangeKeyCondition); List<Reply> latestReplies = mapper.query(Reply.class, queryExpression); for (Reply reply : latestReplies) { System.out.format("Id=%s, Message=%s, PostedBy=%s %n, ReplyDateTime=%s %n", reply.getId(), reply.getMessage(), reply.getPostedBy(), reply.getReplyDateTime() ); } }
private static void FindRepliesPostedWithinTimePeriod( DynamoDBMapper mapper, String forumName, String threadSubject) throws Exception { String hashKey = forumName + "#" + threadSubject; System.out.println("FindRepliesPostedWithinTimePeriod: Find replies for thread Message = 'DynamoDB Thread 2' posted within a period."); long startDateMilli = (new Date()).getTime() - (14L*24L*60L*60L*1000L); // Two weeks ago. long endDateMilli = (new Date()).getTime() - (7L*24L*60L*60L*1000L); // One week ago. SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); String startDate = dateFormatter.format(startDateMilli); String endDate = dateFormatter.format(endDateMilli); Condition rangeKeyCondition = new Condition() .withComparisonOperator(ComparisonOperator.BETWEEN.toString()) .withAttributeValueList(new AttributeValue().withS(startDate), new AttributeValue().withS(endDate)); Reply replyKey = new Reply(); replyKey.setId(hashKey); DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>() .withHashKeyValues(replyKey) .withRangeKeyCondition("ReplyDateTime", rangeKeyCondition); List<Reply> betweenReplies = mapper.query(Reply.class, queryExpression); for (Reply reply : betweenReplies) { System.out.format("Id=%s, Message=%s, PostedBy=%s %n, PostedDateTime=%s %n", reply.getId(), reply.getMessage(), reply.getPostedBy(), reply.getReplyDateTime() ); } }
@Override public <T> PaginatedQueryList<T> query(Class<T> domainClass, DynamoDBQueryExpression<T> queryExpression) { PaginatedQueryList<T> results = dynamoDBMapper.query(domainClass, queryExpression); maybeEmitEvent(new AfterQueryEvent<T>(results)); return results; }
@SuppressWarnings({ "unchecked", "rawtypes" }) // Can't sort by indexrangekey when querying by hash key only @Test(expected=UnsupportedOperationException.class) public void testExecute_WhenFinderMethodIsFindingEntityWithCompositeIdList_WhenFindingByCompositeIdWithHashKeyOnly_WhenSortingByIndexRangeKey() { PlaylistId playlistId = new PlaylistId(); playlistId.setUserName("someUserName"); setupCommonMocksForThisRepositoryMethod(mockPlaylistEntityMetadata, mockDynamoDBPlaylistQueryMethod, Playlist.class, "findByPlaylistIdOrderByDisplayNameDesc", 1, "userName", "playlistName"); Mockito.when(mockDynamoDBPlaylistQueryMethod.isCollectionQuery()).thenReturn(true); Playlist prototypeHashKey = new Playlist(); prototypeHashKey.setUserName("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getHashKeyPropotypeEntityForHashKey("someUserName")).thenReturn( prototypeHashKey); Mockito.when(mockPlaylistEntityMetadata.getHashKey(playlistId)).thenReturn("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getRangeKey(playlistId)).thenReturn(null); Set<String> indexRangeKeyPropertyNames = new HashSet<String>(); indexRangeKeyPropertyNames.add("displayName"); Mockito.when(mockPlaylistEntityMetadata.getIndexRangeKeyPropertyNames()).thenReturn(indexRangeKeyPropertyNames); // Mock out specific DynamoDBOperations behavior expected by this method ArgumentCaptor<DynamoDBQueryExpression> queryCaptor = ArgumentCaptor.forClass(DynamoDBQueryExpression.class); ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class); Mockito.when(mockPlaylistQueryResults.get(0)).thenReturn(mockPlaylist); Mockito.when(mockPlaylistQueryResults.size()).thenReturn(1); Mockito.when(mockDynamoDBOperations.query(classCaptor.capture(), queryCaptor.capture())).thenReturn( mockPlaylistQueryResults); // Execute the query Object[] parameters = new Object[] { playlistId }; partTreeDynamoDBQuery.execute(parameters); }
@SuppressWarnings({ "unchecked", "rawtypes" }) @Test(expected=UnsupportedOperationException.class) public void testExecute_WhenFinderMethodIsFindingEntityWithCompositeIdList_WhenFindingByHashKeyAndIndexRangeKey_WithInvalidOrderSpecified() { setupCommonMocksForThisRepositoryMethod(mockPlaylistEntityMetadata, mockDynamoDBPlaylistQueryMethod, Playlist.class, "findByUserNameAndDisplayNameOrderByPlaylistNameDesc", 2, "userName", "playlistName"); Set<String> indexRangeKeyPropertyNames = new HashSet<String>(); indexRangeKeyPropertyNames.add("displayName"); Mockito.when(mockPlaylistEntityMetadata.getIndexRangeKeyPropertyNames()).thenReturn(indexRangeKeyPropertyNames); Mockito.when(mockDynamoDBPlaylistQueryMethod.isCollectionQuery()).thenReturn(true); Playlist prototypeHashKey = new Playlist(); prototypeHashKey.setUserName("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getHashKeyPropotypeEntityForHashKey("someUserName")).thenReturn( prototypeHashKey); // Mock out specific DynamoDBOperations behavior expected by this method ArgumentCaptor<DynamoDBQueryExpression> queryCaptor = ArgumentCaptor.forClass(DynamoDBQueryExpression.class); ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class); Mockito.when(mockPlaylistQueryResults.get(0)).thenReturn(mockPlaylist); Mockito.when(mockPlaylistQueryResults.size()).thenReturn(1); Mockito.when(mockDynamoDBOperations.query(classCaptor.capture(), queryCaptor.capture())).thenReturn( mockPlaylistQueryResults); // Execute the query Object[] parameters = new Object[] { "someUserName","someDisplayName" }; partTreeDynamoDBQuery.execute(parameters); }
@SuppressWarnings({ "unchecked", "rawtypes" }) // Sorting by range key when querying by indexrangekey not supported @Test(expected=UnsupportedOperationException.class) public void testExecute_WhenFinderMethodIsFindingEntityWithCompositeIdList_WhenFindingByHashKeyAndIndexRangeKey_OrderByRangeKey() { setupCommonMocksForThisRepositoryMethod(mockPlaylistEntityMetadata, mockDynamoDBPlaylistQueryMethod, Playlist.class, "findByUserNameAndDisplayNameOrderByPlaylistNameDesc", 2, "userName", "playlistName"); Set<String> indexRangeKeyPropertyNames = new HashSet<String>(); indexRangeKeyPropertyNames.add("displayName"); Mockito.when(mockPlaylistEntityMetadata.getIndexRangeKeyPropertyNames()).thenReturn(indexRangeKeyPropertyNames); Mockito.when(mockDynamoDBPlaylistQueryMethod.isCollectionQuery()).thenReturn(true); Playlist prototypeHashKey = new Playlist(); prototypeHashKey.setUserName("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getHashKeyPropotypeEntityForHashKey("someUserName")).thenReturn( prototypeHashKey); // Mock out specific DynamoDBOperations behavior expected by this method ArgumentCaptor<DynamoDBQueryExpression> queryCaptor = ArgumentCaptor.forClass(DynamoDBQueryExpression.class); ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class); Mockito.when(mockPlaylistQueryResults.get(0)).thenReturn(mockPlaylist); Mockito.when(mockPlaylistQueryResults.size()).thenReturn(1); Mockito.when(mockDynamoDBOperations.query(classCaptor.capture(), queryCaptor.capture())).thenReturn( mockPlaylistQueryResults); // Execute the query Object[] parameters = new Object[] { "someUserName","someDisplayName" }; partTreeDynamoDBQuery.execute(parameters); }
/** * Construct dynamodb query from filter * * @param filter * @return DynamoDBQueryExpression corresponding to the given FilterCriteria */ private DynamoDBQueryExpression<DynamoDBItem<?>> createQueryExpression(Class<? extends DynamoDBItem<?>> dtoClass, FilterCriteria filter) { DynamoDBItem<?> item = getDynamoDBHashKey(dtoClass, filter.getItemName()); final DynamoDBQueryExpression<DynamoDBItem<?>> queryExpression = new DynamoDBQueryExpression<DynamoDBItem<?>>() .withHashKeyValues(item).withScanIndexForward(filter.getOrdering() == Ordering.ASCENDING) .withLimit(filter.getPageSize()); Condition timeFilter = maybeAddTimeFilter(queryExpression, filter); maybeAddStateFilter(filter, queryExpression); logger.debug("Querying: {} with {}", filter.getItemName(), timeFilter); return queryExpression; }
private Condition maybeAddTimeFilter(final DynamoDBQueryExpression<DynamoDBItem<?>> queryExpression, final FilterCriteria filter) { final Condition timeCondition = constructTimeCondition(filter); if (timeCondition != null) { queryExpression.setRangeKeyConditions( Collections.singletonMap(DynamoDBItem.ATTRIBUTE_NAME_TIMEUTC, timeCondition)); } return timeCondition; }
@Override public List<RecipeDraft> getDrafts(int userId) throws IOException { RecipeDraft recipeDraft = new RecipeDraft(); recipeDraft.setUserId(userId); DynamoDBQueryExpression<RecipeDraft> queryExpression = new DynamoDBQueryExpression<>(); queryExpression.withHashKeyValues(recipeDraft); return mapper.query(RecipeDraft.class, queryExpression); }
@Override public int countDrafts(int userId) throws IOException { RecipeDraft recipeDraft = new RecipeDraft(); recipeDraft.setUserId(userId); DynamoDBQueryExpression<RecipeDraft> queryExpression = new DynamoDBQueryExpression<>(); queryExpression.withHashKeyValues(recipeDraft); return mapper.count(RecipeDraft.class, queryExpression); }
@DynamoDBIgnore public HashSet<HNItemItem> getHNItemsByd(int minutes_ago, DynamoDBMapper mapper, DynamoDBMapperConfig dynamo_config) { // set up an expression to query screename#id DynamoDBQueryExpression<HNItemItem> queryExpression = new DynamoDBQueryExpression<HNItemItem>() .withIndexName("by-time-index") .withScanIndexForward(true) .withConsistentRead(false); // set the user_id part HNItemItem key = new HNItemItem(); key.setBy(getId()); queryExpression.setHashKeyValues(key); // set the msfe range part if(minutes_ago > 0) { //System.out.println("Getting comment children with a valid cutoff time."); Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, (minutes_ago * -1)); long time_cutoff = cal.getTimeInMillis() / 1000; // set the msfe range part Map<String, Condition> keyConditions = new HashMap<String, Condition>(); keyConditions.put("time",new Condition() .withComparisonOperator(ComparisonOperator.GT) .withAttributeValueList(new AttributeValue().withN(new Long(time_cutoff).toString()))); queryExpression.setRangeKeyConditions(keyConditions); } // execute List<HNItemItem> notificationitems = mapper.query(HNItemItem.class, queryExpression, dynamo_config); if(notificationitems != null && notificationitems.size() > 0) { HashSet<HNItemItem> returnset = new HashSet<HNItemItem>(); for (HNItemItem notificationitem : notificationitems) { returnset.add(notificationitem); } return returnset; } else { return null; } }
private static <T> QueryRequest testCreateQueryRequestFromExpression( Class<T> clazz, DynamoDBQueryExpression<T> queryExpression) { return testCreateQueryRequestFromExpression(clazz, queryExpression, null); }
public MultipleEntityQueryExpressionQuery(DynamoDBOperations dynamoDBOperations, Class<T> clazz, DynamoDBQueryExpression<T> queryExpression) { super(dynamoDBOperations, clazz); this.queryExpression = queryExpression; }
public QueryExpressionCountQuery(DynamoDBOperations dynamoDBOperations, Class<T> clazz, DynamoDBQueryExpression<T> queryExpression) { super(dynamoDBOperations, Long.class); this.queryExpression = queryExpression; this.domainClass = clazz; }
public DynamoDBQueryExpression<T> buildQueryExpression() { DynamoDBQueryExpression<T> queryExpression = new DynamoDBQueryExpression<T>(); if (isHashKeySpecified()) { T hashKeyPrototype = entityInformation.getHashKeyPropotypeEntityForHashKey(getHashKeyPropertyValue()); queryExpression.withHashKeyValues(hashKeyPrototype); queryExpression.withRangeKeyConditions(new HashMap<String, Condition>()); } if (isRangeKeySpecified() && !isApplicableForGlobalSecondaryIndex()) { Condition rangeKeyCondition = createSingleValueCondition(getRangeKeyPropertyName(), ComparisonOperator.EQ, getRangeKeyAttributeValue(), getRangeKeyAttributeValue().getClass(), true); queryExpression.withRangeKeyCondition(getRangeKeyAttributeName(), rangeKeyCondition); applySortIfSpecified(queryExpression, Arrays.asList(new String[] { getRangeKeyPropertyName() })); } else if (isOnlyASingleAttributeConditionAndItIsOnEitherRangeOrIndexRangeKey() || (isApplicableForGlobalSecondaryIndex())) { Entry<String, List<Condition>> singlePropertyConditions = propertyConditions.entrySet().iterator().next(); List<String> allowedSortProperties = new ArrayList<String>(); for (Entry<String, List<Condition>> singlePropertyCondition : propertyConditions.entrySet()) { if (entityInformation.getGlobalSecondaryIndexNamesByPropertyName().keySet() .contains(singlePropertyCondition.getKey())) { allowedSortProperties.add(singlePropertyCondition.getKey()); } } if (allowedSortProperties.size() == 0) { allowedSortProperties.add(singlePropertyConditions.getKey()); } for (Entry<String, List<Condition>> singleAttributeConditions : attributeConditions.entrySet()) { for (Condition condition : singleAttributeConditions.getValue()) { queryExpression.withRangeKeyCondition(singleAttributeConditions.getKey(), condition); } } applySortIfSpecified(queryExpression, allowedSortProperties); if (getGlobalSecondaryIndexName() != null) { queryExpression.setIndexName(getGlobalSecondaryIndexName()); } } else { applySortIfSpecified(queryExpression, Arrays.asList(new String[] { getRangeKeyPropertyName() })); } return queryExpression; }
@Override public <T> int count(Class<T> domainClass, DynamoDBQueryExpression<T> queryExpression) { return dynamoDBMapper.count(domainClass, queryExpression); }
@SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testExecute_WhenFinderMethodIsFindingEntityWithCompositeIdList_WithSingleStringParameter_WhenFindingByHashKeyOnly() { setupCommonMocksForThisRepositoryMethod(mockPlaylistEntityMetadata, mockDynamoDBPlaylistQueryMethod, Playlist.class, "findByUserName", 1, "userName", "playlistName"); Mockito.when(mockDynamoDBPlaylistQueryMethod.isCollectionQuery()).thenReturn(true); Playlist prototypeHashKey = new Playlist(); prototypeHashKey.setUserName("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getHashKeyPropotypeEntityForHashKey("someUserName")).thenReturn( prototypeHashKey); // Mock out specific DynamoDBOperations behavior expected by this method ArgumentCaptor<DynamoDBQueryExpression> queryCaptor = ArgumentCaptor.forClass(DynamoDBQueryExpression.class); ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class); Mockito.when(mockPlaylistQueryResults.get(0)).thenReturn(mockPlaylist); Mockito.when(mockPlaylistQueryResults.size()).thenReturn(1); Mockito.when(mockDynamoDBOperations.query(classCaptor.capture(), queryCaptor.capture())).thenReturn( mockPlaylistQueryResults); // Execute the query Object[] parameters = new Object[] { "someUserName" }; Object o = partTreeDynamoDBQuery.execute(parameters); // Assert that we obtain the expected results assertEquals(mockPlaylistQueryResults, o); assertEquals(1, mockPlaylistQueryResults.size()); assertEquals(mockPlaylist, mockPlaylistQueryResults.get(0)); // Assert that we scanned DynamoDB for the correct class assertEquals(classCaptor.getValue(), Playlist.class); // Assert that we have only one filter condition, for the name of the // property Object hashKeyPrototypeObject = queryCaptor.getValue().getHashKeyValues(); assertTrue(hashKeyPrototypeObject instanceof Playlist); Playlist hashKeyPropertyPlaylist = (Playlist) hashKeyPrototypeObject; assertEquals("someUserName", hashKeyPropertyPlaylist.getUserName()); // Verify that the expected DynamoDBOperations method was called Mockito.verify(mockDynamoDBOperations).query(classCaptor.getValue(), queryCaptor.getValue()); }
@SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testExecute_WhenFinderMethodIsFindingEntityWithCompositeIdList_WhenFindingByCompositeIdWithHashKeyOnly() { PlaylistId playlistId = new PlaylistId(); playlistId.setUserName("someUserName"); setupCommonMocksForThisRepositoryMethod(mockPlaylistEntityMetadata, mockDynamoDBPlaylistQueryMethod, Playlist.class, "findByPlaylistId", 1, "userName", "playlistName"); Mockito.when(mockDynamoDBPlaylistQueryMethod.isCollectionQuery()).thenReturn(true); Playlist prototypeHashKey = new Playlist(); prototypeHashKey.setUserName("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getHashKeyPropotypeEntityForHashKey("someUserName")).thenReturn( prototypeHashKey); Mockito.when(mockPlaylistEntityMetadata.getHashKey(playlistId)).thenReturn("someUserName"); Mockito.when(mockPlaylistEntityMetadata.getRangeKey(playlistId)).thenReturn(null); // Mock out specific DynamoDBOperations behavior expected by this method ArgumentCaptor<DynamoDBQueryExpression> queryCaptor = ArgumentCaptor.forClass(DynamoDBQueryExpression.class); ArgumentCaptor<Class> classCaptor = ArgumentCaptor.forClass(Class.class); Mockito.when(mockPlaylistQueryResults.get(0)).thenReturn(mockPlaylist); Mockito.when(mockPlaylistQueryResults.size()).thenReturn(1); Mockito.when(mockDynamoDBOperations.query(classCaptor.capture(), queryCaptor.capture())).thenReturn( mockPlaylistQueryResults); // Execute the query Object[] parameters = new Object[] { playlistId }; Object o = partTreeDynamoDBQuery.execute(parameters); // Assert that we obtain the expected results assertEquals(mockPlaylistQueryResults, o); assertEquals(1, mockPlaylistQueryResults.size()); assertEquals(mockPlaylist, mockPlaylistQueryResults.get(0)); // Assert that we scanned DynamoDB for the correct class assertEquals(classCaptor.getValue(), Playlist.class); // Assert that we have only one filter condition, for the name of the // property Object hashKeyPrototypeObject = queryCaptor.getValue().getHashKeyValues(); assertTrue(hashKeyPrototypeObject instanceof Playlist); Playlist hashKeyPropertyPlaylist = (Playlist) hashKeyPrototypeObject; assertEquals("someUserName", hashKeyPropertyPlaylist.getUserName()); assertEquals(0,queryCaptor.getValue().getRangeKeyConditions().size()); // Verify that the expected DynamoDBOperations method was called Mockito.verify(mockDynamoDBOperations).query(classCaptor.getValue(), queryCaptor.getValue()); }