diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/DuplicateColumnUsageTest.java b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/DuplicateColumnUsageTest.java new file mode 100644 index 00000000..10372b5b --- /dev/null +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/DuplicateColumnUsageTest.java @@ -0,0 +1,114 @@ +package org.socialsignin.spring.data.dynamodb.domain.sample; + +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.model.AttributeDefinition; +import com.amazonaws.services.dynamodbv2.model.CreateTableRequest; +import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex; +import com.amazonaws.services.dynamodbv2.model.KeySchemaElement; +import com.amazonaws.services.dynamodbv2.model.KeyType; +import com.amazonaws.services.dynamodbv2.model.Projection; +import com.amazonaws.services.dynamodbv2.model.ProjectionType; +import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; +import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories; +import org.socialsignin.spring.data.dynamodb.utils.DynamoDBLocalResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {DynamoDBLocalResource.class, DuplicateColumnUsageTest.DuplicateColumnUsageTestConfig.class}) +public class DuplicateColumnUsageTest { + + + @Configuration + @EnableDynamoDBRepositories(basePackages = "org.socialsignin.spring.data.dynamodb.domain.sample") + static class DuplicateColumnUsageTestConfig { + + } + + + @Before + public void setUp() { + // DynamoDBLocalResource.createTable(ddb, Playlist.class); + List ad = new ArrayList<>(); + ad.add(new AttributeDefinition("Genre", ScalarAttributeType.S)); + ad.add(new AttributeDefinition("PlaylistName", ScalarAttributeType.S)); + ad.add(new AttributeDefinition("UserName", ScalarAttributeType.S)); + + List ks = new ArrayList<>(); + ks.add(new KeySchemaElement("UserName", KeyType.HASH)); + ks.add(new KeySchemaElement("PlaylistName", KeyType.RANGE)); + + List gsiks = new ArrayList<>(); + gsiks.add(new KeySchemaElement("Genre", KeyType.HASH)); + gsiks.add(new KeySchemaElement("PlaylistName", KeyType.RANGE)); + + List gsis = new ArrayList<>(); + gsis.add(new GlobalSecondaryIndex() + .withIndexName("Genre-PlaylistName-index") + .withKeySchema(gsiks) + .withProjection(new Projection().withProjectionType(ProjectionType.ALL)) + .withProvisionedThroughput(new ProvisionedThroughput(10L, 10L))); + + CreateTableRequest ctr = new CreateTableRequest(); + ctr.withTableName("playlist"); + ctr.withAttributeDefinitions(ad); + ctr.withKeySchema(ks); + ctr.withGlobalSecondaryIndexes(gsis); + ctr.withProvisionedThroughput(new ProvisionedThroughput(10L, 10L)); + + ddb.createTable(ctr); + } + + + @Autowired + private PlaylistRepository playlistRepository; + @Autowired + private AmazonDynamoDB ddb; + + + private Playlist generatePlaylist(String genre, String playlistName) { + final String userName = "userName-" + UUID.randomUUID().toString(); + final String displayName = "displayName-" + UUID.randomUUID().toString(); + PlaylistId id = new PlaylistId(userName, playlistName); + + Playlist playlist = new Playlist(id); + playlist.setDisplayName(displayName); + playlist.setGenre(genre); + + return playlist; + } + + @Test + public void testGsiSharedRange() { + final String GENRE = "GENRE"; + playlistRepository.save(generatePlaylist(GENRE, "1")); + playlistRepository.save(generatePlaylist(GENRE, "2")); + playlistRepository.save(generatePlaylist(GENRE, "3")); + try { + Thread.sleep(2000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + assertEquals(3, playlistRepository.findByGenre(GENRE).size()); + + assertEquals(1, playlistRepository.findByGenreAndPlaylistName(GENRE, "2").size()); + + List actual = playlistRepository.findByGenreAndPlaylistNameBetween(GENRE, "2", "3"); + + assertEquals(2, actual.size()); + } + +} diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/HashRangeKeyIT.java b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/HashRangeKeyIT.java index f151bd30..a5c7cce9 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/HashRangeKeyIT.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/HashRangeKeyIT.java @@ -21,6 +21,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -37,20 +38,28 @@ public class HashRangeKeyIT { @Autowired - PlaylistRepository playlistRepository; + private PlaylistRepository playlistRepository; - @Test - public void runCrudOperations() { - final String displayName = "displayName" + UUID.randomUUID().toString(); + private Playlist generatePlaylist(String genre, String displayName) { final String userName = "userName-" + UUID.randomUUID().toString(); final String playlistName = "playlistName-" + UUID.randomUUID().toString(); PlaylistId id = new PlaylistId(userName, playlistName); - Optional actual = playlistRepository.findById(id); - assertFalse(actual.isPresent()); - Playlist playlist = new Playlist(id); playlist.setDisplayName(displayName); + playlist.setGenre(genre); + + return playlist; + } + + @Test + public void runCrudOperations() { + String displayName = "displayName" + UUID.randomUUID().toString(); + Playlist playlist = generatePlaylist("genre-" + UUID.randomUUID().toString(), displayName); + PlaylistId id = playlist.getId(); + + Optional actual = playlistRepository.findById(id); + assertFalse(actual.isPresent()); playlistRepository.save(playlist); @@ -60,4 +69,16 @@ public void runCrudOperations() { assertEquals(id.getPlaylistName(), actual.get().getPlaylistName()); assertEquals(id.getUserName(), actual.get().getUserName()); } + + @Test + public void testGsiSharedRange() { + final String GENRE = "GENRE"; + playlistRepository.save(generatePlaylist(GENRE, "1")); + playlistRepository.save(generatePlaylist(GENRE, "2")); + playlistRepository.save(generatePlaylist(GENRE, "3")); + + List actual = playlistRepository.findByGenreAndPlaylistNameBetween(GENRE, "2", "3"); + + assertEquals(2, actual.size()); + } } diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/Playlist.java b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/Playlist.java index bbd48469..dca83e61 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/Playlist.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/Playlist.java @@ -17,6 +17,9 @@ import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable; import org.springframework.data.annotation.Id; @@ -27,6 +30,7 @@ public class Playlist { @Id private PlaylistId playlistId; private String displayName; + private String genre; public Playlist() { } @@ -34,6 +38,11 @@ public Playlist() { public Playlist(PlaylistId playlistId) { this.playlistId = playlistId; } + + @DynamoDBIgnore + public PlaylistId getId() { + return this.playlistId; + } @DynamoDBAttribute(attributeName="DisplayName") public String getDisplayName() { @@ -57,6 +66,7 @@ public void setUserName(String userName) { } @DynamoDBRangeKey(attributeName = "PlaylistName") + @DynamoDBIndexRangeKey(attributeName = "PlaylistName", globalSecondaryIndexName="Genre-PlaylistName-index") public String getPlaylistName() { return playlistId != null ? playlistId.getPlaylistName() : null; } @@ -67,4 +77,13 @@ public void setPlaylistName(String playlistName) { } playlistId.setPlaylistName(playlistName); } + + @DynamoDBIndexHashKey(attributeName = "Genre", globalSecondaryIndexName="Genre-PlaylistName-index") + public String getGenre() { + return this.genre; + } + + public void setGenre(String genre) { + this.genre = genre; + } } diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/PlaylistRepository.java b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/PlaylistRepository.java index 29e39a38..e22dc5fe 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/PlaylistRepository.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/PlaylistRepository.java @@ -15,8 +15,15 @@ */ package org.socialsignin.spring.data.dynamodb.domain.sample; +import java.util.List; + +import org.socialsignin.spring.data.dynamodb.repository.EnableScan; import org.springframework.data.repository.CrudRepository; +@EnableScan public interface PlaylistRepository extends CrudRepository { + List findByGenre(String genre); + List findByGenreAndPlaylistName(String genre, String playlistName); + List findByGenreAndPlaylistNameBetween(String genre, String startPlaylistName, String endPlaylistName); } diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/utils/DynamoDBLocalResource.java b/src/test/java/org/socialsignin/spring/data/dynamodb/utils/DynamoDBLocalResource.java index f8146f7e..6148d568 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/utils/DynamoDBLocalResource.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/utils/DynamoDBLocalResource.java @@ -57,7 +57,8 @@ public static CreateTableResult createTable(AmazonDynamoDB ddb, Class dom Optional rangeKey = Optional.empty(); if (entityInfo instanceof DynamoDBIdIsHashAndRangeKeyEntityInformation) { - rangeKey = Optional.of(((DynamoDBIdIsHashAndRangeKeyEntityInformation)entityInfo).getRangeKeyPropertyName()); + rangeKey = Optional.of(((DynamoDBIdIsHashAndRangeKeyEntityInformation)entityInfo).getRangeKeyPropertyName()) + .flatMap(e -> entityInfo.getOverriddenAttributeName(e)); } return createTable(ddb, tableName, hashKey, rangeKey); diff --git a/src/test/resources/playlist_table.json b/src/test/resources/playlist_table.json index 14ab1d91..efaa372a 100755 --- a/src/test/resources/playlist_table.json +++ b/src/test/resources/playlist_table.json @@ -7,8 +7,34 @@ { "AttributeName": "PlaylistName", "AttributeType": "S" + }, + { + "AttributeName": "Genre", + "AttributeType": "S" } ], + "GlobalSecondaryIndexes": [ + { + "IndexName": "Genre-PlaylistName-index", + "KeySchema": [ + { + "AttributeName": "Genre", + "KeyType": "HASH" + }, + { + "AttributeName": "PlaylistName", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "ALL" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": "10", + "WriteCapacityUnits": "10" + } + } + ], "KeySchema": [ { "AttributeName": "UserName",