embulk-output-cassandra 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab4a3fa7b0b477c2c6ebed457fa48f248ce7a6ae
4
- data.tar.gz: a7355ea7423d856a3533e2b3d4dbbb50d05c60be
3
+ metadata.gz: f3a5a33db3984bac71c043a99cf1306c12aed2fa
4
+ data.tar.gz: 6351267b4e17e6d75617fa4ddda29f4c5b2551e5
5
5
  SHA512:
6
- metadata.gz: 0a8b7043a53d758515a06274ffd00955013d8533d447e512a01228f17e63e378e9d70a5f149f54e9451b52a74718951261e3e6a6493889f8d6213b06db480ea3
7
- data.tar.gz: f51f4f392c31bb8928e97b14ef4059a523578883517ea390e3beac76ffd84dc1f30b464cac999d05e478fc6ae4ad102739a26590b219dd5437901c00debc1181
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`)
@@ -13,7 +13,7 @@ configurations {
13
13
  provided
14
14
  }
15
15
 
16
- version = "0.2.0"
16
+ version = "0.3.0"
17
17
 
18
18
  sourceCompatibility = 1.8
19
19
  targetCompatibility = 1.8
@@ -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.1.1" type="JAVA_MODULE" version="4">
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> gethosts();
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("Insert Query: {}", query.getQueryString());
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.gethosts()) {
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.2.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-08-12 00:00:00.000000000 Z
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.2.0.jar
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