embulk-input-dynamodb 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -3
  3. data/build.gradle +29 -5
  4. data/circle.yml +8 -0
  5. data/config/checkstyle/checkstyle.xml +128 -0
  6. data/config/checkstyle/default.xml +108 -0
  7. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  8. data/gradle/wrapper/gradle-wrapper.properties +2 -2
  9. data/lib/embulk/input/dynamodb.rb +1 -1
  10. data/src/main/scala/org/embulk/input/dynamodb/AttributeValueHelper.scala +41 -0
  11. data/src/main/scala/org/embulk/input/dynamodb/AwsCredentials.scala +71 -0
  12. data/src/main/scala/org/embulk/input/{DynamoDBUtil.scala → dynamodb/DynamoDBUtil.scala} +54 -62
  13. data/src/main/scala/org/embulk/input/{DynamodbInputPlugin.scala → dynamodb/DynamodbInputPlugin.scala} +14 -8
  14. data/src/main/scala/org/embulk/input/{Filter.scala → dynamodb/Filter.scala} +2 -2
  15. data/src/main/scala/org/embulk/input/{FilterConfig.scala → dynamodb/FilterConfig.scala} +1 -1
  16. data/src/main/scala/org/embulk/input/{PluginTask.scala → dynamodb/PluginTask.scala} +10 -2
  17. data/src/test/resources/json/test.json +50 -0
  18. data/src/test/resources/json/test.template +27 -0
  19. data/src/test/resources/yaml/authMethodBasic.yml +20 -0
  20. data/src/test/resources/yaml/authMethodBasic_Error.yml +18 -0
  21. data/src/test/resources/yaml/authMethodEnv.yml +18 -0
  22. data/src/test/resources/yaml/authMethodProfile.yml +19 -0
  23. data/src/test/resources/yaml/notSetAuthMethod.yml +19 -0
  24. data/src/test/scala/org/embulk/input/dynamodb/AttributeValueHelperTest.scala +192 -0
  25. data/src/test/scala/org/embulk/input/dynamodb/AwsCredentialsTest.scala +135 -0
  26. metadata +29 -16
@@ -1,67 +1,34 @@
1
- package org.embulk.input
1
+ package org.embulk.input.dynamodb
2
2
 
3
3
  import java.util.{ArrayList => JArrayList, List => JList, Map => JMap}
4
4
 
5
- import com.amazonaws.auth.profile.ProfileCredentialsProvider
6
- import com.amazonaws.auth.{AWSCredentials, AWSCredentialsProvider, BasicAWSCredentials}
5
+ import com.amazonaws.ClientConfiguration
7
6
  import com.amazonaws.regions.Regions
8
7
  import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient
9
- import com.amazonaws.services.dynamodbv2.model._
10
- import com.amazonaws.{AmazonClientException, ClientConfiguration}
8
+ import com.amazonaws.services.dynamodbv2.model.{AttributeValue, Condition, ScanRequest, ScanResult}
11
9
  import org.embulk.spi._
10
+ import org.embulk.spi.`type`.Types
11
+ import org.msgpack.value.{ValueFactory, Value}
12
12
 
13
13
  import scala.collection.JavaConversions._
14
+ import scala.collection.JavaConverters._
14
15
 
15
16
  object DynamoDBUtil {
16
17
  def createClient(task: PluginTask): AmazonDynamoDBClient = {
17
- try {
18
- createClientUsingIAMRole(task)
19
- } catch {
20
- case e: AmazonClientException =>
21
- createClientUsingCredentials(task)
22
- }
23
- }
24
-
25
- private def getCredentialsProvider(task: PluginTask): AWSCredentialsProvider = {
26
- {for {
27
- accessKey <- Option(task.getAccessKey.orNull)
28
- secretKey <- Option(task.getSecretKey.orNull)
29
- } yield {
30
- new AWSCredentialsProvider {
31
- override def refresh(): Unit = { }
32
- override def getCredentials: AWSCredentials = {
33
- new BasicAWSCredentials(accessKey, secretKey)
34
- }
35
- }
36
- }}.getOrElse {
37
- new ProfileCredentialsProvider()
38
- }
39
- }
40
-
41
- private def createClientUsingIAMRole(task: PluginTask): AmazonDynamoDBClient = {
42
- val client: AmazonDynamoDBClient = new AmazonDynamoDBClient(
43
- new ClientConfiguration().withMaxConnections(10))
44
- .withRegion(Regions.fromName(task.getRegion))
45
-
46
- client.describeTable(task.getTable) // FIXME
47
-
48
- client
49
- }
50
-
51
- private def createClientUsingCredentials(task: PluginTask): AmazonDynamoDBClient = {
52
- val credentialsProvider: AWSCredentialsProvider = getCredentialsProvider(task)
53
- val client: AmazonDynamoDBClient = new AmazonDynamoDBClient(
54
- credentialsProvider,
55
- new ClientConfiguration().withMaxConnections(10))
18
+ new AmazonDynamoDBClient(
19
+ AwsCredentials.getCredentialsProvider(task),
20
+ new ClientConfiguration()
21
+ .withMaxConnections(50)) // SDK Default Value
56
22
  .withRegion(Regions.fromName(task.getRegion))
57
-
58
- client.describeTable(task.getTable) // FIXME
59
-
60
- client
61
23
  }
62
24
 
63
25
 
64
- def scan(client: AmazonDynamoDBClient, task: PluginTask, schema: Schema, output: PageOutput): Unit = {
26
+ def scan(
27
+ task: PluginTask,
28
+ schema: Schema,
29
+ output: PageOutput)
30
+ (implicit client: AmazonDynamoDBClient): Unit =
31
+ {
65
32
  val allocator: BufferAllocator = task.getBufferAllocator
66
33
  val pageBuilder: PageBuilder = new PageBuilder(allocator, schema, output)
67
34
 
@@ -70,7 +37,7 @@ object DynamoDBUtil {
70
37
  schema.getColumns.foreach { column =>
71
38
  attributes.add(column.getName)
72
39
  }
73
- val scanFilter: Map[String, Condition] = createScanFilter(task)
40
+ val scanFilter: JMap[String, Condition] = createScanFilter(task)
74
41
  var evaluateKey: JMap[String, AttributeValue] = null
75
42
 
76
43
  val scanLimit: Long = task.getScanLimit
@@ -95,23 +62,24 @@ object DynamoDBUtil {
95
62
 
96
63
  result.getItems.foreach { item =>
97
64
  schema.getColumns.foreach { column =>
98
- val value = item.get(column.getName)
99
- column.getType.getName match {
100
- case "string" =>
101
- pageBuilder.setString(column, Option(value) map { _.getS } getOrElse { "" })
102
- case "long" =>
103
- pageBuilder.setLong(column, Option(value) map { _.getN.toLong } getOrElse { 0L })
104
- case "double" =>
105
- pageBuilder.setDouble(column, Option(value) map { _.getN.toDouble } getOrElse { 0D })
106
- case "boolean" =>
107
- pageBuilder.setBoolean(column, Option(value) map { _.getBOOL == true } getOrElse { false })
65
+ val value = item.asScala.get(column.getName)
66
+ column.getType match {
67
+ case Types.STRING =>
68
+ convert(column, value, pageBuilder.setString)
69
+ case Types.LONG =>
70
+ convert(column, value, pageBuilder.setLong)
71
+ case Types.DOUBLE =>
72
+ convert(column, value, pageBuilder.setDouble)
73
+ case Types.BOOLEAN =>
74
+ convert(column, value, pageBuilder.setBoolean)
75
+ case Types.JSON =>
76
+ convert(column, value, pageBuilder.setJson)
108
77
  case _ => /* Do nothing */
109
78
  }
110
79
  }
111
80
  pageBuilder.addRecord()
112
81
  recordCount += 1
113
82
  }
114
- println(s"$recordLimit $recordLimit $recordCount")
115
83
  } while(evaluateKey != null && (recordLimit == 0 || recordLimit > recordCount))
116
84
 
117
85
  pageBuilder.finish()
@@ -132,7 +100,8 @@ object DynamoDBUtil {
132
100
  filters.getFilters.map { filter =>
133
101
  val attributeValueList = collection.mutable.ArrayBuffer[AttributeValue]()
134
102
  attributeValueList += createAttributeValue(filter.getType, filter.getValue)
135
- Option(filter.getValue2).map { value2 => attributeValueList += createAttributeValue(filter.getType, value2) }
103
+ Option(filter.getValue2).map { value2 =>
104
+ attributeValueList+= createAttributeValue(filter.getType, value2) }
136
105
 
137
106
  filterMap += filter.getName -> new Condition()
138
107
  .withComparisonOperator(filter.getCondition)
@@ -153,4 +122,27 @@ object DynamoDBUtil {
153
122
  new AttributeValue().withBOOL(v.toBoolean)
154
123
  }
155
124
  }
125
+
126
+ private def convert[A](column: Column,
127
+ value: Option[AttributeValue],
128
+ f: (Column, A) => Unit)(implicit f1: Option[AttributeValue] => A): Unit =
129
+ f(column, f1(value))
130
+
131
+ implicit private def StringConvert(value: Option[AttributeValue]): String =
132
+ value.map(_.getS).getOrElse("")
133
+
134
+ implicit private def LongConvert(value: Option[AttributeValue]): Long =
135
+ value.map(_.getN.toLong).getOrElse(0L)
136
+
137
+ implicit private def DoubleConvert(value: Option[AttributeValue]): Double =
138
+ value.map(_.getN.toDouble).getOrElse(0D)
139
+
140
+ implicit private def BooleanConvert(value: Option[AttributeValue]): Boolean =
141
+ value.exists(_.getS.toBoolean)
142
+
143
+ implicit private def JsonConvert(value: Option[AttributeValue]): Value = {
144
+ value.map { attr =>
145
+ AttributeValueHelper.decodeToValue(attr)
146
+ }.getOrElse(ValueFactory.newNil())
147
+ }
156
148
  }
@@ -1,4 +1,4 @@
1
- package org.embulk.input
1
+ package org.embulk.input.dynamodb
2
2
 
3
3
  import java.util.{List => JList}
4
4
 
@@ -21,15 +21,21 @@ class DynamodbInputPlugin extends InputPlugin {
21
21
  Exec.newConfigDiff()
22
22
  }
23
23
 
24
- def cleanup(taskSource: TaskSource, schema: Schema, taskCount: Int, successCommitReports: JList[CommitReport]): Unit = {
25
- }
26
-
27
- def run(taskSource: TaskSource, schema: Schema, taskIndex: Int, output: PageOutput): CommitReport = {
24
+ def run(taskSource: TaskSource, schema: Schema, taskIndex: Int, output: PageOutput): TaskReport = {
28
25
  val task: PluginTask = taskSource.loadTask(classOf[PluginTask])
29
26
 
30
- val client: AmazonDynamoDBClient = DynamoDBUtil.createClient(task)
31
- DynamoDBUtil.scan(client, task, schema, output)
27
+ implicit val client: AmazonDynamoDBClient = DynamoDBUtil.createClient(task)
28
+ DynamoDBUtil.scan(task, schema, output)
29
+
30
+ Exec.newTaskReport()
31
+ }
32
+
33
+ def cleanup(taskSource: TaskSource, schema: Schema, taskCount: Int, successTaskReports: JList[TaskReport]): Unit = {
34
+ // TODO
35
+ }
32
36
 
33
- Exec.newCommitReport()
37
+ def guess(config: ConfigSource): ConfigDiff = {
38
+ // TODO
39
+ null
34
40
  }
35
41
  }
@@ -1,8 +1,8 @@
1
- package org.embulk.input
1
+ package org.embulk.input.dynamodb
2
2
 
3
3
  import java.util.{List => JList}
4
4
 
5
- import com.fasterxml.jackson.annotation.{JsonValue, JsonCreator}
5
+ import com.fasterxml.jackson.annotation.{JsonCreator, JsonValue}
6
6
  import com.google.common.base.Objects
7
7
 
8
8
  class Filter {
@@ -1,4 +1,4 @@
1
- package org.embulk.input
1
+ package org.embulk.input.dynamodb
2
2
 
3
3
  import com.fasterxml.jackson.annotation.JsonProperty
4
4
  import com.google.common.base.Objects
@@ -1,10 +1,14 @@
1
- package org.embulk.input
1
+ package org.embulk.input.dynamodb
2
2
 
3
3
  import com.google.common.base.Optional
4
- import org.embulk.config.{ConfigInject, ConfigDefault, Config, Task}
4
+ import org.embulk.config.{Config, ConfigDefault, ConfigInject, Task}
5
5
  import org.embulk.spi.{BufferAllocator, SchemaConfig}
6
6
 
7
7
  trait PluginTask extends Task {
8
+ @Config("auth_method")
9
+ @ConfigDefault("null")
10
+ def getAuthMethod: Optional[String]
11
+
8
12
  @Config("access_key")
9
13
  @ConfigDefault("null")
10
14
  def getAccessKey: Optional[String]
@@ -13,6 +17,10 @@ trait PluginTask extends Task {
13
17
  @ConfigDefault("null")
14
18
  def getSecretKey: Optional[String]
15
19
 
20
+ @Config("profile_name")
21
+ @ConfigDefault("null")
22
+ def getProfileName: Optional[String]
23
+
16
24
  @Config("region")
17
25
  @ConfigDefault("ap-northeast-1")
18
26
  def getRegion: String
@@ -0,0 +1,50 @@
1
+ {
2
+ "_id": "56d8e1377a72374918f73bd2",
3
+ "index": 0,
4
+ "guid": "5309640c-499a-43f6-801d-3076c810892b",
5
+ "isActive": true,
6
+ "age": 37,
7
+ "name": "Battle Lancaster",
8
+ "email": "battlelancaster@zytrac.com",
9
+ "registered": "2014-07-16T04:40:58 -09:00",
10
+ "latitude": 45.574906,
11
+ "longitude": 36.596302,
12
+ "tags": [
13
+ "veniam",
14
+ "exercitation",
15
+ "velit",
16
+ "pariatur",
17
+ "sit",
18
+ "non",
19
+ "dolore"
20
+ ],
21
+ "friends": [
22
+ {
23
+ "id": 0,
24
+ "name": "Mejia Montgomery",
25
+ "tags": [
26
+ "duis",
27
+ "proident",
28
+ "et"
29
+ ]
30
+ },
31
+ {
32
+ "id": 1,
33
+ "name": "Carpenter Reed",
34
+ "tags": [
35
+ "labore",
36
+ "nisi",
37
+ "ipsum"
38
+ ]
39
+ },
40
+ {
41
+ "id": 2,
42
+ "name": "Gamble Watts",
43
+ "tags": [
44
+ "occaecat",
45
+ "voluptate",
46
+ "eu"
47
+ ]
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ _id: '{{objectId()}}',
3
+ index: '{{index()}}',
4
+ guid: '{{guid()}}',
5
+ isActive: '{{bool()}}',
6
+ age: '{{integer(20, 40)}}',
7
+ name: '{{firstName()}} {{surname()}}',
8
+ email: '{{email()}}',
9
+ registered: '{{date(new Date(2014, 0, 1), new Date(), "YYYY-MM-ddThh:mm:ss Z")}}',
10
+ latitude: '{{floating(-90.000001, 90)}}',
11
+ longitude: '{{floating(-180.000001, 180)}}',
12
+ tags: [
13
+ '{{repeat(7)}}',
14
+ '{{lorem(1, "words")}}'
15
+ ],
16
+ friends: [
17
+ '{{repeat(3)}}',
18
+ {
19
+ id: '{{index()}}',
20
+ name: '{{firstName()}} {{surname()}}',
21
+ tags: [
22
+ '{{repeat(3)}}',
23
+ '{{lorem(1, "words")}}'
24
+ ]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,20 @@
1
+ in:
2
+ type: dynamodb
3
+ region: ENV_VAR
4
+ table: ENV_VAR
5
+ auth_method: basic
6
+ access_key: ENV_VAR
7
+ secret_key: ENV_VAR
8
+ columns:
9
+ - {name: pri-key, type: string}
10
+ - {name: sort-key, type: long}
11
+ - {name: value, type: string}
12
+
13
+ out:
14
+ type: file
15
+ path_prefix: result
16
+ file_ext: tsv
17
+ formatter:
18
+ type: csv
19
+ delimiter: "\t"
20
+ header_line: false
@@ -0,0 +1,18 @@
1
+ in:
2
+ type: dynamodb
3
+ region: ENV_VAR
4
+ table: ENV_VAR
5
+ auth_method: basic
6
+ columns:
7
+ - {name: pri-key, type: string}
8
+ - {name: sort-key, type: long}
9
+ - {name: value, type: string}
10
+
11
+ out:
12
+ type: file
13
+ path_prefix: result
14
+ file_ext: tsv
15
+ formatter:
16
+ type: csv
17
+ delimiter: "\t"
18
+ header_line: false
@@ -0,0 +1,18 @@
1
+ in:
2
+ type: dynamodb
3
+ region: ENV_VAR
4
+ table: ENV_VAR
5
+ auth_method: env
6
+ columns:
7
+ - {name: pri-key, type: string}
8
+ - {name: sort-key, type: long}
9
+ - {name: value, type: string}
10
+
11
+ out:
12
+ type: file
13
+ path_prefix: result
14
+ file_ext: tsv
15
+ formatter:
16
+ type: csv
17
+ delimiter: "\t"
18
+ header_line: false
@@ -0,0 +1,19 @@
1
+ in:
2
+ type: dynamodb
3
+ region: ENV_VAR
4
+ table: ENV_VAR
5
+ auth_method: profile
6
+ profile_name: ENV_VAR
7
+ columns:
8
+ - {name: pri-key, type: string}
9
+ - {name: sort-key, type: long}
10
+ - {name: value, type: string}
11
+
12
+ out:
13
+ type: file
14
+ path_prefix: result
15
+ file_ext: tsv
16
+ formatter:
17
+ type: csv
18
+ delimiter: "\t"
19
+ header_line: false
@@ -0,0 +1,19 @@
1
+ in:
2
+ type: dynamodb
3
+ region: ENV_VAR
4
+ table: ENV_VAR
5
+ access_key: ENV_VAR
6
+ secret_key: ENV_VAR
7
+ columns:
8
+ - {name: pri-key, type: string}
9
+ - {name: sort-key, type: long}
10
+ - {name: value, type: string}
11
+
12
+ out:
13
+ type: file
14
+ path_prefix: result
15
+ file_ext: tsv
16
+ formatter:
17
+ type: csv
18
+ delimiter: "\t"
19
+ header_line: false
@@ -0,0 +1,192 @@
1
+ package org.embulk.input.dynamodb
2
+
3
+
4
+ import java.io.File
5
+ import java.{util => JUtil}
6
+
7
+ import com.amazonaws.services.dynamodbv2.model.AttributeValue
8
+ import com.fasterxml.jackson.databind.ObjectMapper
9
+ import org.embulk.input.dynamodb.AttributeValueHelper._
10
+ import org.hamcrest.CoreMatchers._
11
+ import org.junit.Assert._
12
+ import org.junit.Test
13
+ import org.msgpack.value.ValueFactory
14
+
15
+ import scala.collection.JavaConverters._
16
+
17
+ class AttributeValueHelperTest {
18
+ @Test
19
+ def decodeTest(): Unit = {
20
+ val stringValue = decodeToValue(new AttributeValue().withS("STR"))
21
+ assertEquals(stringValue.asStringValue.asString, "STR")
22
+
23
+ val intValue = decodeToValue(new AttributeValue().withN("123456789"))
24
+ assertEquals(intValue.asNumberValue().toInt, 123456789)
25
+
26
+ val doubleValue = decodeToValue(new AttributeValue().withN("-98765432.00000001"))
27
+ assertEquals(doubleValue.asNumberValue().toDouble, -98765432.00000001, 0.0)
28
+
29
+ val trueValue = decodeToValue(new AttributeValue().withBOOL(true))
30
+ assertEquals(trueValue.asBooleanValue().getBoolean, true)
31
+
32
+ val falseValue = decodeToValue(new AttributeValue().withBOOL(false))
33
+ assertEquals(falseValue.asBooleanValue().getBoolean, false)
34
+
35
+ val nilValue = decodeToValue(new AttributeValue().withNULL(true))
36
+ assertEquals(nilValue.isNilValue, true)
37
+ }
38
+
39
+
40
+ @Test
41
+ def listDecodeTest(): Unit = {
42
+ val stringListValue = decodeToValue(new AttributeValue().withL(
43
+ new AttributeValue().withS("ValueA"),
44
+ new AttributeValue().withS("ValueB"),
45
+ new AttributeValue().withS("ValueC")))
46
+
47
+ assertTrue(stringListValue.isArrayValue)
48
+ assertEquals(stringListValue.asArrayValue().size(), 3)
49
+
50
+ assertTrue(stringListValue.asArrayValue().get(0).isStringValue)
51
+ assertEquals(stringListValue.asArrayValue().get(0).asStringValue().asString(), "ValueA")
52
+ assertEquals(stringListValue.asArrayValue().get(1).asStringValue().asString(), "ValueB")
53
+ assertEquals(stringListValue.asArrayValue().get(2).asStringValue().asString(), "ValueC")
54
+
55
+
56
+ val numberListValue = decodeToValue(new AttributeValue().withL(
57
+ new AttributeValue().withN("123"),
58
+ new AttributeValue().withN("-456"),
59
+ new AttributeValue().withN("0.0000045679"),
60
+ new AttributeValue().withN("-1234567890.123")))
61
+
62
+ assertTrue(numberListValue.isArrayValue)
63
+ assertEquals(numberListValue.asArrayValue().size(), 4)
64
+
65
+ assertTrue(numberListValue.asArrayValue().get(0).isIntegerValue)
66
+ assertEquals(numberListValue.asArrayValue().get(0).asNumberValue().toInt, 123)
67
+ assertEquals(numberListValue.asArrayValue().get(1).asNumberValue().toInt, -456)
68
+
69
+ assertTrue(numberListValue.asArrayValue().get(2).isFloatValue)
70
+ assertEquals(numberListValue.asArrayValue().get(2).asNumberValue().toDouble, 0.0000045679, 0.0)
71
+ assertEquals(numberListValue.asArrayValue().get(3).asNumberValue().toDouble, -1234567890.123, 0.0)
72
+
73
+
74
+ val stringSetValue = decodeToValue(new AttributeValue().withSS(
75
+ new JUtil.HashSet[String]() {
76
+ add("ValueA")
77
+ add("ValueB")
78
+ add("ValueC")
79
+ }))
80
+
81
+ assertTrue(stringSetValue.isArrayValue)
82
+ assertEquals(stringSetValue.asArrayValue().size(), 3)
83
+
84
+ assertThat(List("ValueA", "ValueB", "ValueC").asJava,
85
+ hasItems(
86
+ equalTo(stringSetValue.asArrayValue().get(0).asStringValue().asString),
87
+ equalTo(stringSetValue.asArrayValue().get(1).asStringValue().asString),
88
+ equalTo(stringSetValue.asArrayValue().get(2).asStringValue().asString)))
89
+
90
+
91
+ val numberSetValue = decodeToValue(new AttributeValue().withNS(
92
+ new JUtil.HashSet[String]() {
93
+ add("123")
94
+ add("-456")
95
+ add("0.0000045679")
96
+ add("-1234567890.123")
97
+ }))
98
+
99
+ assertTrue(numberSetValue.isArrayValue)
100
+ assertEquals(numberSetValue.asArrayValue().size(), 4)
101
+ }
102
+
103
+
104
+ @Test
105
+ def mapDecodeTest(): Unit = {
106
+ val stringMap = decodeToValue(new AttributeValue().withM(
107
+ new JUtil.HashMap[String, AttributeValue]() {
108
+ put("KeyA", new AttributeValue().withS("ValueA"))
109
+ put("KeyB", new AttributeValue().withS("ValueB"))
110
+ put("KeyC", new AttributeValue().withS("ValueC"))
111
+ }))
112
+
113
+ assertTrue(stringMap.isMapValue)
114
+ assertEquals(stringMap.asMapValue().size(), 3)
115
+ assertEquals(stringMap.asMapValue().map().get(ValueFactory.newString("KeyA")).asStringValue().asString(), "ValueA")
116
+ assertEquals(stringMap.asMapValue().map().get(ValueFactory.newString("KeyB")).asStringValue().asString(), "ValueB")
117
+ assertEquals(stringMap.asMapValue().map().get(ValueFactory.newString("KeyC")).asStringValue().asString(), "ValueC")
118
+
119
+
120
+ val numberMap = decodeToValue(new AttributeValue().withM(
121
+ new JUtil.HashMap[String, AttributeValue]() {
122
+ put("KeyA", new AttributeValue().withN("123"))
123
+ put("KeyB", new AttributeValue().withN("-456"))
124
+ put("KeyC", new AttributeValue().withN("0.0000045679"))
125
+ put("KeyD", new AttributeValue().withN("-1234567890.123"))
126
+ }))
127
+
128
+ assertTrue(numberMap.isMapValue)
129
+ assertEquals(numberMap.asMapValue().size(), 4)
130
+
131
+ assertTrue(numberMap.asMapValue().map().get(ValueFactory.newString("KeyA")).isIntegerValue)
132
+ assertEquals(numberMap.asMapValue().map().get(ValueFactory.newString("KeyA")).asNumberValue().toInt, 123)
133
+ assertEquals(numberMap.asMapValue().map().get(ValueFactory.newString("KeyB")).asNumberValue().toInt, -456)
134
+
135
+ assertTrue(numberMap.asMapValue().map().get(ValueFactory.newString("KeyC")).isFloatValue)
136
+ assertEquals(numberMap.asMapValue().map().get(ValueFactory.newString("KeyC")).asFloatValue().toDouble, 0.0000045679, 0.0)
137
+ assertEquals(numberMap.asMapValue().map().get(ValueFactory.newString("KeyD")).asFloatValue().toDouble, -1234567890.123, 0.0)
138
+ }
139
+
140
+ def attr[A](value: A)(implicit f: A=> AttributeValue): AttributeValue = f(value)
141
+ implicit def StringAttributeValue(value: String): AttributeValue = new AttributeValue().withS(value)
142
+ implicit def IntegerAttributeValue(value: Int): AttributeValue = new AttributeValue().withN(value.toString)
143
+ implicit def LongAttributeValue(value: Long): AttributeValue = new AttributeValue().withN(value.toString)
144
+ implicit def FloatAttributeValue(value: Float): AttributeValue = new AttributeValue().withN(value.toString)
145
+ implicit def DoubleAttributeValue(value: Double): AttributeValue = new AttributeValue().withN(value.toString)
146
+ implicit def BooleanAttributeValue(value: Boolean): AttributeValue = new AttributeValue().withBOOL(value)
147
+ implicit def MapAttributeValue(value: Map[String, AttributeValue]): AttributeValue
148
+ = new AttributeValue().withM(value.asJava)
149
+ implicit def ListAttributeValue(value: List[AttributeValue]): AttributeValue
150
+ = new AttributeValue().withL(value.asJava)
151
+
152
+ @Test
153
+ def nestedDecodeTest(): Unit = {
154
+ // TODO: Json -> AttributeValue...
155
+ val testData = decodeToValue(attr(Map(
156
+ "_id" -> attr("56d8e1377a72374918f73bd2"),
157
+ "index" -> attr(0),
158
+ "guid" -> attr("5309640c-499a-43f6-801d-3076c810892b"),
159
+ "isActive" -> attr(true),
160
+ "age" -> attr(37),
161
+ "name" -> attr("Battle Lancaster"),
162
+ "email" -> attr("battlelancaster@zytrac.com"),
163
+ "registered" -> attr("2014-07-16T04:40:58 -09:00"),
164
+ "latitude" -> attr(45.574906),
165
+ "longitude" -> attr(36.596302),
166
+ "tags" -> attr(List(
167
+ attr("veniam"),
168
+ attr("exercitation"),
169
+ attr("velit"),
170
+ attr("pariatur"),
171
+ attr("sit"),
172
+ attr("non"),
173
+ attr("dolore"))),
174
+ "friends" -> attr(List(
175
+ attr(Map("id" -> attr(0), "name" -> attr("Mejia Montgomery"),
176
+ "tags" -> attr(List(attr("duis"), attr("proident"), attr("et"))))),
177
+ attr(Map("id" -> attr(1), "name" -> attr("Carpenter Reed"),
178
+ "tags" -> attr(List(attr("labore"), attr("nisi"), attr("ipsum"))))),
179
+ attr(Map("id" -> attr(2), "name" -> attr("Gamble Watts"),
180
+ "tags" -> attr(List(attr("occaecat"), attr("voluptate"), attr("eu")))))
181
+ ))
182
+ )
183
+ ))
184
+
185
+ val testA = new ObjectMapper().readValue(
186
+ testData.toJson, classOf[JUtil.Map[String, Any]])
187
+ val testB = new ObjectMapper().readValue(
188
+ new File("src/test/resources/json/test.json"), classOf[JUtil.Map[String, Any]])
189
+
190
+ assertThat(testA, is(testB))
191
+ }
192
+ }