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.
- 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
|
+
}
|