embulk-input-dynamodb 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +19 -3
- data/build.gradle +29 -5
- data/circle.yml +8 -0
- data/config/checkstyle/checkstyle.xml +128 -0
- data/config/checkstyle/default.xml +108 -0
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +2 -2
- data/lib/embulk/input/dynamodb.rb +1 -1
- data/src/main/scala/org/embulk/input/dynamodb/AttributeValueHelper.scala +41 -0
- data/src/main/scala/org/embulk/input/dynamodb/AwsCredentials.scala +71 -0
- data/src/main/scala/org/embulk/input/{DynamoDBUtil.scala → dynamodb/DynamoDBUtil.scala} +54 -62
- data/src/main/scala/org/embulk/input/{DynamodbInputPlugin.scala → dynamodb/DynamodbInputPlugin.scala} +14 -8
- data/src/main/scala/org/embulk/input/{Filter.scala → dynamodb/Filter.scala} +2 -2
- data/src/main/scala/org/embulk/input/{FilterConfig.scala → dynamodb/FilterConfig.scala} +1 -1
- data/src/main/scala/org/embulk/input/{PluginTask.scala → dynamodb/PluginTask.scala} +10 -2
- data/src/test/resources/json/test.json +50 -0
- data/src/test/resources/json/test.template +27 -0
- data/src/test/resources/yaml/authMethodBasic.yml +20 -0
- data/src/test/resources/yaml/authMethodBasic_Error.yml +18 -0
- data/src/test/resources/yaml/authMethodEnv.yml +18 -0
- data/src/test/resources/yaml/authMethodProfile.yml +19 -0
- data/src/test/resources/yaml/notSetAuthMethod.yml +19 -0
- data/src/test/scala/org/embulk/input/dynamodb/AttributeValueHelperTest.scala +192 -0
- data/src/test/scala/org/embulk/input/dynamodb/AwsCredentialsTest.scala +135 -0
- 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.
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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(
|
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:
|
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
|
100
|
-
case
|
101
|
-
|
102
|
-
case
|
103
|
-
|
104
|
-
case
|
105
|
-
|
106
|
-
case
|
107
|
-
|
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 =>
|
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
|
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(
|
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
|
-
|
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.{
|
5
|
+
import com.fasterxml.jackson.annotation.{JsonCreator, JsonValue}
|
6
6
|
import com.google.common.base.Objects
|
7
7
|
|
8
8
|
class Filter {
|
@@ -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.{
|
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
|
+
}
|