embulk-output-cassandra 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3a5a33db3984bac71c043a99cf1306c12aed2fa
|
4
|
+
data.tar.gz: 6351267b4e17e6d75617fa4ddda29f4c5b2551e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45f9a322c118f1b4786d730f1db68eefbdccfb1f63fcc9c14967319c9a441bb6b003f0f06a075228c042fdd217f82064f215fb807812cd9e6152c2e76a557a02
|
7
|
+
data.tar.gz: 6a29cfbd03d3ecb2f070563af73265b711c093c0b88ffd68b57d27f98b541964f8002f9f9d59aa3dcba8c33afb8ea680fab6ce77560c44653bd390a87b48cef6
|
data/README.md
CHANGED
@@ -67,7 +67,9 @@ For example, If input data = {id: 1, count: 5}, Executed Statement is `UPDATE ta
|
|
67
67
|
- **cluster_name**: cluster name (string, default: `null`)
|
68
68
|
- **keyspace**: target keyspace name (string, required)
|
69
69
|
- **table**: target table name (string, required)
|
70
|
+
- **mode**: insert or update (string, default: `"insert"`)
|
70
71
|
- **if_not_exists**: Add "IF NOT EXISTS" to INSERT query (boolean, default: `false`)
|
72
|
+
- **if_exists**: Add "IF EXISTS" to UPDATE query (boolean, default: `false`)
|
71
73
|
- **ttl**: Add "TTL" to INSERT query (integer, default: `null`)
|
72
74
|
- **idempotent**: Treat INSERT query as idempotent (boolean, default: `false`)
|
73
75
|
- **connect_timeout**: Set connect timeout millisecond (integer, default: `5000`)
|
data/build.gradle
CHANGED
data/embulk-output-cassandra.iml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<module external.linked.project.id="embulk-output-cassandra" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="0.
|
2
|
+
<module external.linked.project.id="embulk-output-cassandra" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="0.2.0" type="JAVA_MODULE" version="4">
|
3
3
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
4
4
|
<exclude-output />
|
5
5
|
<content url="file://$MODULE_DIR$">
|
@@ -13,6 +13,8 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
|
|
13
13
|
import com.datastax.driver.core.querybuilder.Insert;
|
14
14
|
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
15
15
|
import com.datastax.driver.core.querybuilder.Update;
|
16
|
+
import com.fasterxml.jackson.annotation.JsonCreator;
|
17
|
+
import com.fasterxml.jackson.annotation.JsonValue;
|
16
18
|
import com.google.common.base.Optional;
|
17
19
|
import com.google.common.collect.ImmutableList;
|
18
20
|
import com.google.common.collect.ImmutableMap;
|
@@ -20,6 +22,7 @@ import com.google.common.collect.Lists;
|
|
20
22
|
import org.embulk.config.Config;
|
21
23
|
import org.embulk.config.ConfigDefault;
|
22
24
|
import org.embulk.config.ConfigDiff;
|
25
|
+
import org.embulk.config.ConfigException;
|
23
26
|
import org.embulk.config.ConfigSource;
|
24
27
|
import org.embulk.config.Task;
|
25
28
|
import org.embulk.config.TaskReport;
|
@@ -27,6 +30,7 @@ import org.embulk.config.TaskSource;
|
|
27
30
|
import org.embulk.output.cassandra.setter.CassandraColumnSetter;
|
28
31
|
import org.embulk.output.cassandra.setter.CassandraColumnSetterFactory;
|
29
32
|
import org.embulk.output.cassandra.setter.ColumnSetterVisitor;
|
33
|
+
import org.embulk.spi.Column;
|
30
34
|
import org.embulk.spi.Exec;
|
31
35
|
import org.embulk.spi.OutputPlugin;
|
32
36
|
import org.embulk.spi.Page;
|
@@ -37,7 +41,9 @@ import org.slf4j.Logger;
|
|
37
41
|
|
38
42
|
import java.net.InetSocketAddress;
|
39
43
|
import java.util.List;
|
44
|
+
import java.util.Locale;
|
40
45
|
import java.util.Map;
|
46
|
+
import java.util.stream.Collectors;
|
41
47
|
|
42
48
|
public class CassandraOutputPlugin
|
43
49
|
implements OutputPlugin
|
@@ -46,7 +52,7 @@ public class CassandraOutputPlugin
|
|
46
52
|
extends Task
|
47
53
|
{
|
48
54
|
@Config("hosts")
|
49
|
-
public List<String>
|
55
|
+
public List<String> getHosts();
|
50
56
|
|
51
57
|
@Config("port")
|
52
58
|
@ConfigDefault("9042")
|
@@ -70,10 +76,18 @@ public class CassandraOutputPlugin
|
|
70
76
|
@Config("table")
|
71
77
|
public String getTable();
|
72
78
|
|
79
|
+
@Config("mode")
|
80
|
+
@ConfigDefault("\"insert\"")
|
81
|
+
public Mode getMode();
|
82
|
+
|
73
83
|
@Config("if_not_exists")
|
74
84
|
@ConfigDefault("false")
|
75
85
|
public Boolean getIfNotExists();
|
76
86
|
|
87
|
+
@Config("if_exists")
|
88
|
+
@ConfigDefault("false")
|
89
|
+
public Boolean getIfExists();
|
90
|
+
|
77
91
|
@Config("ttl")
|
78
92
|
@ConfigDefault("null")
|
79
93
|
public Optional<Integer> getTtl();
|
@@ -89,10 +103,6 @@ public class CassandraOutputPlugin
|
|
89
103
|
@Config("request_timeout")
|
90
104
|
@ConfigDefault("12000")
|
91
105
|
public int getRequestTimeout();
|
92
|
-
|
93
|
-
@Config("counter_columnName")
|
94
|
-
@ConfigDefault("null")
|
95
|
-
public Optional<String> getCounterColumnName();
|
96
106
|
}
|
97
107
|
|
98
108
|
private final Logger logger = Exec.getLogger(CassandraOutputPlugin.class);
|
@@ -155,12 +165,36 @@ public class CassandraOutputPlugin
|
|
155
165
|
if (column.getType().getName() == DataType.Name.COUNTER) {
|
156
166
|
update.with(QueryBuilder.incr(column.getName(), QueryBuilder.bindMarker(column.getName())));
|
157
167
|
}
|
158
|
-
else{
|
168
|
+
else {
|
159
169
|
update.where(QueryBuilder.eq(column.getName(), QueryBuilder.bindMarker(column.getName())));
|
160
170
|
}
|
161
171
|
}
|
162
172
|
query = update;
|
163
173
|
}
|
174
|
+
else if (task.getMode() == Mode.UPDATE) {
|
175
|
+
Update update = QueryBuilder.update(task.getKeyspace(), task.getTable());
|
176
|
+
List<String> primaryKeys = tableMetadata.getPrimaryKey().stream().map(ColumnMetadata::getName).collect(Collectors.toList());
|
177
|
+
List<String> columnNames = tableMetadata.getColumns().stream().map(ColumnMetadata::getName).collect(Collectors.toList());
|
178
|
+
|
179
|
+
if (task.getIfExists()) {
|
180
|
+
update.where().ifExists();
|
181
|
+
}
|
182
|
+
if (task.getTtl().isPresent()) {
|
183
|
+
update.using(QueryBuilder.ttl(task.getTtl().get()));
|
184
|
+
}
|
185
|
+
for (String pkey : primaryKeys) {
|
186
|
+
update.where(QueryBuilder.eq(pkey, QueryBuilder.bindMarker(pkey)));
|
187
|
+
}
|
188
|
+
for (Column col : schema.getColumns()) {
|
189
|
+
if (primaryKeys.contains(col.getName())) {
|
190
|
+
continue;
|
191
|
+
}
|
192
|
+
if (columnNames.contains(col.getName())) {
|
193
|
+
update.with(QueryBuilder.set(col.getName(), QueryBuilder.bindMarker(col.getName())));
|
194
|
+
}
|
195
|
+
}
|
196
|
+
query = update;
|
197
|
+
}
|
164
198
|
else {
|
165
199
|
Insert insert = QueryBuilder.insertInto(task.getKeyspace(), task.getTable());
|
166
200
|
if (task.getIfNotExists()) {
|
@@ -190,7 +224,7 @@ public class CassandraOutputPlugin
|
|
190
224
|
List<ColumnSetterVisitor> columnVisitors = Lists.transform(schema.getColumns(), (column) ->
|
191
225
|
new ColumnSetterVisitor(pageReader, columnSetters.get(column.getName())));
|
192
226
|
|
193
|
-
logger.info("
|
227
|
+
logger.info("Query: {}", query.getQueryString());
|
194
228
|
|
195
229
|
PreparedStatement prepared = session.prepare(query);
|
196
230
|
if (task.getIdempotent()) {
|
@@ -203,7 +237,7 @@ public class CassandraOutputPlugin
|
|
203
237
|
private Cluster getCluster(PluginTask task)
|
204
238
|
{
|
205
239
|
Cluster.Builder builder = Cluster.builder();
|
206
|
-
for (String host : task.
|
240
|
+
for (String host : task.getHosts()) {
|
207
241
|
builder.addContactPointsWithPorts(new InetSocketAddress(host, task.getPort()));
|
208
242
|
}
|
209
243
|
|
@@ -311,4 +345,29 @@ public class CassandraOutputPlugin
|
|
311
345
|
return report;
|
312
346
|
}
|
313
347
|
}
|
348
|
+
|
349
|
+
public enum Mode {
|
350
|
+
INSERT,
|
351
|
+
UPDATE;
|
352
|
+
|
353
|
+
@JsonValue
|
354
|
+
@Override
|
355
|
+
public String toString()
|
356
|
+
{
|
357
|
+
return name().toLowerCase(Locale.ENGLISH);
|
358
|
+
}
|
359
|
+
|
360
|
+
@JsonCreator
|
361
|
+
public static Mode fromString(String value)
|
362
|
+
{
|
363
|
+
switch(value) {
|
364
|
+
case "insert":
|
365
|
+
return INSERT;
|
366
|
+
case "update":
|
367
|
+
return UPDATE;
|
368
|
+
default:
|
369
|
+
throw new ConfigException(String.format("Unknown mode '%s'", value));
|
370
|
+
}
|
371
|
+
}
|
372
|
+
}
|
314
373
|
}
|
@@ -3,7 +3,6 @@ package org.embulk.output.cassandra;
|
|
3
3
|
import com.datastax.driver.core.Cluster;
|
4
4
|
import com.datastax.driver.core.DataType;
|
5
5
|
import com.datastax.driver.core.LocalDate;
|
6
|
-
import com.datastax.driver.core.ResultSet;
|
7
6
|
import com.datastax.driver.core.Row;
|
8
7
|
import com.datastax.driver.core.Session;
|
9
8
|
import com.datastax.driver.core.TupleType;
|
@@ -33,7 +32,12 @@ import java.util.List;
|
|
33
32
|
import java.util.Map;
|
34
33
|
import java.util.Set;
|
35
34
|
|
36
|
-
import static org.junit.Assert
|
35
|
+
import static org.junit.Assert.assertArrayEquals;
|
36
|
+
import static org.junit.Assert.assertEquals;
|
37
|
+
import static org.junit.Assert.assertFalse;
|
38
|
+
import static org.junit.Assert.assertNotNull;
|
39
|
+
import static org.junit.Assert.assertNull;
|
40
|
+
import static org.junit.Assert.assertTrue;
|
37
41
|
|
38
42
|
public class TestCassandraOutputPlugin
|
39
43
|
{
|
@@ -249,6 +253,56 @@ public class TestCassandraOutputPlugin
|
|
249
253
|
assertTrue(UUIDs.unixTimestamp(row1.getUUID("timeuuid_item")) < ZonedDateTime.now().toInstant().toEpochMilli());
|
250
254
|
}
|
251
255
|
|
256
|
+
@Test
|
257
|
+
public void testBasicWithUpdateMode() throws IOException
|
258
|
+
{
|
259
|
+
Path input = getInputPath("test1.csv");
|
260
|
+
ConfigSource config = loadYamlResource("test_basic.yaml");
|
261
|
+
config.set("hosts", getCassandraHostAsList());
|
262
|
+
config.set("mode", "update");
|
263
|
+
|
264
|
+
assertEquals(0, session.execute("SELECT * FROM embulk_test.test_basic").all().size());
|
265
|
+
|
266
|
+
embulk.runOutput(config, input);
|
267
|
+
|
268
|
+
Row row1 = session.execute("SELECT * FROM embulk_test.test_basic WHERE id = 'A001'").one();
|
269
|
+
Row row2 = session.execute("SELECT * FROM embulk_test.test_basic WHERE id = 'A002'").one();
|
270
|
+
Row row3 = session.execute("SELECT * FROM embulk_test.test_basic WHERE id = 'A003'").one();
|
271
|
+
assertEquals("A001", row1.getString("id"));
|
272
|
+
assertEquals(9, row1.getLong("int_item"));
|
273
|
+
assertEquals(createDate(2018, 7, 1, 10, 0, 0, 0), row1.getTimestamp("timestamp_item"));
|
274
|
+
assertEquals("A002", row2.getString("id"));
|
275
|
+
assertEquals(0, row2.getLong("int_item"));
|
276
|
+
assertEquals(createDate(2018, 7, 1, 10, 0, 1, 0), row2.getTimestamp("timestamp_item"));
|
277
|
+
assertEquals("A003", row3.getString("id"));
|
278
|
+
assertEquals(9, row3.getLong("int_item"));
|
279
|
+
assertEquals(createDate(2018, 7, 1, 10, 0, 2, 0), row3.getTimestamp("timestamp_item"));
|
280
|
+
}
|
281
|
+
|
282
|
+
@Test
|
283
|
+
public void testBasicWithIfExists() throws IOException
|
284
|
+
{
|
285
|
+
Path input = getInputPath("test1.csv");
|
286
|
+
ConfigSource config = loadYamlResource("test_basic.yaml");
|
287
|
+
config.set("hosts", getCassandraHostAsList());
|
288
|
+
config.set("mode", "update");
|
289
|
+
config.set("if_exists", true);
|
290
|
+
|
291
|
+
session.execute("INSERT INTO embulk_test.test_basic (id) VALUES ('A001')");
|
292
|
+
assertEquals(1, session.execute("SELECT * FROM embulk_test.test_basic").all().size());
|
293
|
+
|
294
|
+
embulk.runOutput(config, input);
|
295
|
+
|
296
|
+
Row row1 = session.execute("SELECT * FROM embulk_test.test_basic WHERE id = 'A001'").one();
|
297
|
+
Row row2 = session.execute("SELECT * FROM embulk_test.test_basic WHERE id = 'A002'").one();
|
298
|
+
Row row3 = session.execute("SELECT * FROM embulk_test.test_basic WHERE id = 'A003'").one();
|
299
|
+
assertEquals("A001", row1.getString("id"));
|
300
|
+
assertEquals(9, row1.getLong("int_item"));
|
301
|
+
assertEquals(createDate(2018, 7, 1, 10, 0, 0, 0), row1.getTimestamp("timestamp_item"));
|
302
|
+
assertNull(row2);
|
303
|
+
assertNull(row3);
|
304
|
+
}
|
305
|
+
|
252
306
|
@Test
|
253
307
|
public void testComplex() throws IOException
|
254
308
|
{
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-output-cassandra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- joker1007
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -55,7 +55,7 @@ files:
|
|
55
55
|
- classpath/asm-tree-5.0.3.jar
|
56
56
|
- classpath/asm-util-5.0.3.jar
|
57
57
|
- classpath/cassandra-driver-core-3.5.0.jar
|
58
|
-
- classpath/embulk-output-cassandra-0.
|
58
|
+
- classpath/embulk-output-cassandra-0.3.0.jar
|
59
59
|
- classpath/guava-19.0.jar
|
60
60
|
- classpath/jffi-1.2.16-native.jar
|
61
61
|
- classpath/jffi-1.2.16.jar
|