embulk-output-kintone 1.0.0 → 1.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 +57 -1
- data/build.gradle +1 -0
- data/classpath/commons-csv-1.9.0.jar +0 -0
- data/classpath/embulk-output-kintone-1.1.0.jar +0 -0
- data/classpath/externalsortinginjava-0.6.2.jar +0 -0
- data/classpath/{shadow-kintone-java-client-1.0.0-all.jar → shadow-kintone-java-client-1.1.0-all.jar} +0 -0
- data/src/main/java/org/embulk/output/kintone/KintoneColumnOption.java +5 -0
- data/src/main/java/org/embulk/output/kintone/KintoneColumnType.java +209 -5
- data/src/main/java/org/embulk/output/kintone/KintoneColumnVisitor.java +28 -9
- data/src/main/java/org/embulk/output/kintone/KintoneOutputPlugin.java +12 -3
- data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +20 -12
- data/src/main/java/org/embulk/output/kintone/KintoneSortColumn.java +33 -0
- data/src/main/java/org/embulk/output/kintone/PluginTask.java +27 -0
- data/src/main/java/org/embulk/output/kintone/deserializer/DeserializeApplier.java +19 -0
- data/src/main/java/org/embulk/output/kintone/deserializer/DeserializeException.java +7 -0
- data/src/main/java/org/embulk/output/kintone/deserializer/Deserializer.java +279 -0
- data/src/main/java/org/embulk/output/kintone/reducer/CSVInputColumnVisitor.java +78 -0
- data/src/main/java/org/embulk/output/kintone/reducer/CSVOutputColumnVisitor.java +79 -0
- data/src/main/java/org/embulk/output/kintone/reducer/ReduceException.java +11 -0
- data/src/main/java/org/embulk/output/kintone/reducer/ReduceType.java +190 -0
- data/src/main/java/org/embulk/output/kintone/reducer/ReducedPageOutput.java +100 -0
- data/src/main/java/org/embulk/output/kintone/reducer/Reducer.java +355 -0
- data/src/test/java/org/embulk/output/kintone/KintoneColumnOptionBuilder.java +7 -0
- data/src/test/java/org/embulk/output/kintone/KintoneColumnTypeTest.java +194 -0
- data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorTest.java +153 -34
- data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorVerifier.java +13 -3
- data/src/test/java/org/embulk/output/kintone/KintonePageOutputVerifier.java +44 -1
- data/src/test/java/org/embulk/output/kintone/TestKintoneOutputPlugin.java +89 -12
- data/src/test/java/org/embulk/output/kintone/TestTaskReduce.java +46 -0
- data/src/test/java/org/embulk/output/kintone/TestTaskReduceException.java +50 -0
- data/src/test/java/org/embulk/output/kintone/TestTaskReduceSubtable.java +46 -0
- data/src/test/java/org/embulk/output/kintone/deserializer/DeserializerTest.java +165 -0
- data/src/test/java/org/embulk/output/kintone/reducer/ReduceTypeTest.java +154 -0
- data/src/test/resources/org/embulk/output/kintone/task/config.yml +1 -1
- data/src/test/resources/org/embulk/output/kintone/task/mode/config.yml +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/input.csv +7 -7
- data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_ignore_nulls_records.jsonl +2 -2
- data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_prefer_nulls_records.jsonl +6 -6
- data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_records.jsonl +6 -6
- data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_ignore_nulls_records.jsonl +2 -2
- data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_prefer_nulls_records.jsonl +3 -3
- data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_records.jsonl +6 -6
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_prefer_nulls_records.jsonl +3 -3
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_records.jsonl +2 -2
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_ignore_nulls_records.jsonl +2 -2
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_prefer_nulls_records.jsonl +3 -3
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_records.jsonl +4 -4
- data/src/test/resources/org/embulk/output/kintone/task/reduce/config.yml +171 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/input.csv +7 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_ignore_nulls_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_prefer_nulls_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_add_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_add_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_add_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_update_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_update_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_update_records.jsonl +4 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/values_ignore_nulls.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/values_prefer_nulls.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/config.yml +36 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/derived_columns.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/input.csv +13 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/insert_add_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/update_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/config.yml +343 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/derived_columns.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/input.csv +13 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_ignore_nulls_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_prefer_nulls_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_add_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_add_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_add_records.jsonl +0 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_update_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_update_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/values_ignore_nulls.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/values_prefer_nulls.json +1 -0
- metadata +62 -4
- data/classpath/embulk-output-kintone-1.0.0.jar +0 -0
@@ -50,7 +50,6 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
50
50
|
"GAIA_DA02" // データベースのロックに失敗したため、変更を保存できませんでした。時間をおいて再度お試しください。
|
51
51
|
);
|
52
52
|
private static final int UPSERT_BATCH_SIZE = 10000;
|
53
|
-
private static final int CHUNK_SIZE = 100;
|
54
53
|
private final Map<String, Pair<FieldType, FieldType>> wrongTypeFields = new TreeMap<>();
|
55
54
|
private final PluginTask task;
|
56
55
|
private final PageReader reader;
|
@@ -113,7 +112,7 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
113
112
|
return Exec.newTaskReport();
|
114
113
|
}
|
115
114
|
|
116
|
-
|
115
|
+
private void connectIfNeeded() {
|
117
116
|
if (client != null) {
|
118
117
|
return; // Already connected
|
119
118
|
}
|
@@ -203,14 +202,19 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
203
202
|
reader.setPage(page);
|
204
203
|
KintoneColumnVisitor visitor =
|
205
204
|
new KintoneColumnVisitor(
|
206
|
-
reader,
|
205
|
+
reader,
|
206
|
+
task.getDerivedColumns(),
|
207
|
+
task.getColumnOptions(),
|
208
|
+
task.getPreferNulls(),
|
209
|
+
task.getIgnoreNulls(),
|
210
|
+
task.getReduceKeyName().orElse(null));
|
207
211
|
while (reader.nextRecord()) {
|
208
212
|
Record record = new Record();
|
209
213
|
visitor.setRecord(record);
|
210
214
|
reader.getSchema().visitColumns(visitor);
|
211
215
|
putWrongTypeFields(record);
|
212
216
|
records.add(record);
|
213
|
-
if (records.size() ==
|
217
|
+
if (records.size() == task.getChunkSize()) {
|
214
218
|
insert(records);
|
215
219
|
records.clear();
|
216
220
|
}
|
@@ -226,9 +230,11 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
226
230
|
KintoneColumnVisitor visitor =
|
227
231
|
new KintoneColumnVisitor(
|
228
232
|
reader,
|
233
|
+
task.getDerivedColumns(),
|
229
234
|
task.getColumnOptions(),
|
230
235
|
task.getPreferNulls(),
|
231
236
|
task.getIgnoreNulls(),
|
237
|
+
task.getReduceKeyName().orElse(null),
|
232
238
|
task.getUpdateKeyName()
|
233
239
|
.orElseThrow(() -> new RuntimeException("unreachable"))); // Already validated
|
234
240
|
while (reader.nextRecord()) {
|
@@ -243,7 +249,7 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
243
249
|
continue;
|
244
250
|
}
|
245
251
|
records.add(new RecordForUpdate(updateKey, record.removeField(updateKey.getField())));
|
246
|
-
if (records.size() ==
|
252
|
+
if (records.size() == task.getChunkSize()) {
|
247
253
|
update(records);
|
248
254
|
records.clear();
|
249
255
|
}
|
@@ -260,9 +266,11 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
260
266
|
KintoneColumnVisitor visitor =
|
261
267
|
new KintoneColumnVisitor(
|
262
268
|
reader,
|
269
|
+
task.getDerivedColumns(),
|
263
270
|
task.getColumnOptions(),
|
264
271
|
task.getPreferNulls(),
|
265
272
|
task.getIgnoreNulls(),
|
273
|
+
task.getReduceKeyName().orElse(null),
|
266
274
|
task.getUpdateKeyName()
|
267
275
|
.orElseThrow(() -> new RuntimeException("unreachable"))); // Already validated
|
268
276
|
while (reader.nextRecord()) {
|
@@ -300,10 +308,10 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
300
308
|
} else {
|
301
309
|
insertRecords.add(record);
|
302
310
|
}
|
303
|
-
if (insertRecords.size() ==
|
311
|
+
if (insertRecords.size() == task.getChunkSize()) {
|
304
312
|
insert(insertRecords);
|
305
313
|
insertRecords.clear();
|
306
|
-
} else if (updateRecords.size() ==
|
314
|
+
} else if (updateRecords.size() == task.getChunkSize()) {
|
307
315
|
update(updateRecords);
|
308
316
|
updateRecords.clear();
|
309
317
|
}
|
@@ -365,11 +373,6 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
365
373
|
.collect(Collectors.toList());
|
366
374
|
}
|
367
375
|
|
368
|
-
private boolean existsRecord(List<String> existingValues, UpdateKey updateKey) {
|
369
|
-
String value = toString(updateKey.getValue());
|
370
|
-
return value != null && existingValues.stream().anyMatch(v -> v.equals(value));
|
371
|
-
}
|
372
|
-
|
373
376
|
private void putWrongTypeFields(Record record) {
|
374
377
|
record.getFieldCodes(true).stream()
|
375
378
|
.map(
|
@@ -386,6 +389,11 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
386
389
|
return field == null ? null : field.getType();
|
387
390
|
}
|
388
391
|
|
392
|
+
private static boolean existsRecord(List<String> existingValues, UpdateKey updateKey) {
|
393
|
+
String value = toString(updateKey.getValue());
|
394
|
+
return value != null && existingValues.stream().anyMatch(v -> v.equals(value));
|
395
|
+
}
|
396
|
+
|
389
397
|
private static String toString(Object value) {
|
390
398
|
return value == null
|
391
399
|
? null
|
@@ -0,0 +1,33 @@
|
|
1
|
+
package org.embulk.output.kintone;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.annotation.JsonCreator;
|
4
|
+
import com.fasterxml.jackson.annotation.JsonProperty;
|
5
|
+
|
6
|
+
public class KintoneSortColumn {
|
7
|
+
private final String name;
|
8
|
+
private final Order order;
|
9
|
+
|
10
|
+
@JsonCreator
|
11
|
+
public KintoneSortColumn(@JsonProperty("name") String name, @JsonProperty("order") Order order) {
|
12
|
+
this.name = name;
|
13
|
+
this.order = order;
|
14
|
+
}
|
15
|
+
|
16
|
+
public String getName() {
|
17
|
+
return name;
|
18
|
+
}
|
19
|
+
|
20
|
+
public Order getOrder() {
|
21
|
+
return order;
|
22
|
+
}
|
23
|
+
|
24
|
+
public enum Order {
|
25
|
+
ASC,
|
26
|
+
DESC;
|
27
|
+
|
28
|
+
@JsonCreator
|
29
|
+
public static Order of(String name) {
|
30
|
+
return valueOf(name.toUpperCase());
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
@@ -1,10 +1,13 @@
|
|
1
1
|
package org.embulk.output.kintone;
|
2
2
|
|
3
|
+
import java.util.List;
|
3
4
|
import java.util.Map;
|
4
5
|
import java.util.Optional;
|
6
|
+
import java.util.Set;
|
5
7
|
import org.embulk.config.Config;
|
6
8
|
import org.embulk.config.ConfigDefault;
|
7
9
|
import org.embulk.config.Task;
|
10
|
+
import org.embulk.spi.Column;
|
8
11
|
|
9
12
|
public interface PluginTask extends Task {
|
10
13
|
@Config("domain")
|
@@ -57,7 +60,31 @@ public interface PluginTask extends Task {
|
|
57
60
|
@ConfigDefault("null")
|
58
61
|
Optional<String> getUpdateKeyName();
|
59
62
|
|
63
|
+
@Config("reduce_key")
|
64
|
+
@ConfigDefault("null")
|
65
|
+
Optional<String> getReduceKeyName();
|
66
|
+
|
67
|
+
@Config("sort_columns")
|
68
|
+
@ConfigDefault("[]")
|
69
|
+
List<KintoneSortColumn> getSortColumns();
|
70
|
+
|
71
|
+
@Config("max_sort_tmp_files")
|
72
|
+
@ConfigDefault("null")
|
73
|
+
Optional<Integer> getMaxSortTmpFiles();
|
74
|
+
|
75
|
+
@Config("max_sort_memory")
|
76
|
+
@ConfigDefault("null")
|
77
|
+
Optional<Long> getMaxSortMemory();
|
78
|
+
|
79
|
+
@Config("chunk_size")
|
80
|
+
@ConfigDefault("100")
|
81
|
+
Integer getChunkSize();
|
82
|
+
|
60
83
|
@Config("retry_options")
|
61
84
|
@ConfigDefault("{}")
|
62
85
|
KintoneRetryOption getRetryOptions();
|
86
|
+
|
87
|
+
Set<Column> getDerivedColumns();
|
88
|
+
|
89
|
+
void setDerivedColumns(Set<Column> columns);
|
63
90
|
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
package org.embulk.output.kintone.deserializer;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.core.JsonParser;
|
4
|
+
import com.fasterxml.jackson.databind.DeserializationContext;
|
5
|
+
import com.fasterxml.jackson.databind.JsonDeserializer;
|
6
|
+
import java.util.function.BiFunction;
|
7
|
+
|
8
|
+
public class DeserializeApplier<T> extends JsonDeserializer<T> {
|
9
|
+
private final BiFunction<JsonParser, DeserializationContext, T> deserializer;
|
10
|
+
|
11
|
+
public DeserializeApplier(BiFunction<JsonParser, DeserializationContext, T> deserializer) {
|
12
|
+
this.deserializer = deserializer;
|
13
|
+
}
|
14
|
+
|
15
|
+
@Override
|
16
|
+
public T deserialize(JsonParser parser, DeserializationContext context) {
|
17
|
+
return deserializer.apply(parser, context);
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,279 @@
|
|
1
|
+
package org.embulk.output.kintone.deserializer;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.core.JsonParser;
|
4
|
+
import com.fasterxml.jackson.core.ObjectCodec;
|
5
|
+
import com.fasterxml.jackson.databind.DeserializationContext;
|
6
|
+
import com.fasterxml.jackson.databind.JsonNode;
|
7
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
8
|
+
import com.fasterxml.jackson.databind.module.SimpleModule;
|
9
|
+
import com.fasterxml.jackson.databind.node.TextNode;
|
10
|
+
import com.kintone.client.model.FileBody;
|
11
|
+
import com.kintone.client.model.Group;
|
12
|
+
import com.kintone.client.model.Organization;
|
13
|
+
import com.kintone.client.model.User;
|
14
|
+
import com.kintone.client.model.record.CalcFieldValue;
|
15
|
+
import com.kintone.client.model.record.CheckBoxFieldValue;
|
16
|
+
import com.kintone.client.model.record.DateFieldValue;
|
17
|
+
import com.kintone.client.model.record.DateTimeFieldValue;
|
18
|
+
import com.kintone.client.model.record.DropDownFieldValue;
|
19
|
+
import com.kintone.client.model.record.FieldType;
|
20
|
+
import com.kintone.client.model.record.FieldValue;
|
21
|
+
import com.kintone.client.model.record.FileFieldValue;
|
22
|
+
import com.kintone.client.model.record.GroupSelectFieldValue;
|
23
|
+
import com.kintone.client.model.record.LinkFieldValue;
|
24
|
+
import com.kintone.client.model.record.MultiLineTextFieldValue;
|
25
|
+
import com.kintone.client.model.record.MultiSelectFieldValue;
|
26
|
+
import com.kintone.client.model.record.NumberFieldValue;
|
27
|
+
import com.kintone.client.model.record.OrganizationSelectFieldValue;
|
28
|
+
import com.kintone.client.model.record.RadioButtonFieldValue;
|
29
|
+
import com.kintone.client.model.record.RichTextFieldValue;
|
30
|
+
import com.kintone.client.model.record.SingleLineTextFieldValue;
|
31
|
+
import com.kintone.client.model.record.SubtableFieldValue;
|
32
|
+
import com.kintone.client.model.record.TableRow;
|
33
|
+
import com.kintone.client.model.record.TimeFieldValue;
|
34
|
+
import com.kintone.client.model.record.UserSelectFieldValue;
|
35
|
+
import java.io.IOException;
|
36
|
+
import java.lang.invoke.MethodHandles;
|
37
|
+
import java.math.BigDecimal;
|
38
|
+
import java.time.LocalDate;
|
39
|
+
import java.time.LocalTime;
|
40
|
+
import java.time.ZonedDateTime;
|
41
|
+
import java.util.Iterator;
|
42
|
+
import java.util.List;
|
43
|
+
import java.util.Spliterator;
|
44
|
+
import java.util.Spliterators;
|
45
|
+
import java.util.function.BiFunction;
|
46
|
+
import java.util.function.Function;
|
47
|
+
import java.util.stream.Collectors;
|
48
|
+
import java.util.stream.Stream;
|
49
|
+
import java.util.stream.StreamSupport;
|
50
|
+
import org.slf4j.Logger;
|
51
|
+
import org.slf4j.LoggerFactory;
|
52
|
+
|
53
|
+
public class Deserializer {
|
54
|
+
private static final Logger LOGGER =
|
55
|
+
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
56
|
+
private static final JsonNode NULL = new TextNode(null);
|
57
|
+
private final ObjectMapper mapper = new ObjectMapper();
|
58
|
+
|
59
|
+
public Deserializer() {
|
60
|
+
SimpleModule module = new SimpleModule();
|
61
|
+
// spotless:off
|
62
|
+
addDeserializer(module, SubtableFieldValue.class, this::deserializeSubtable);
|
63
|
+
addDeserializer(module, TableRow.class, this::deserializeTableRow);
|
64
|
+
addDeserializer(module, SingleLineTextFieldValue.class, this::deserializeSingleLineText);
|
65
|
+
addDeserializer(module, MultiLineTextFieldValue.class, this::deserializeMultiLineText);
|
66
|
+
addDeserializer(module, RichTextFieldValue.class, this::deserializeRichText);
|
67
|
+
addDeserializer(module, NumberFieldValue.class, this::deserializeNumber);
|
68
|
+
addDeserializer(module, CalcFieldValue.class, this::deserializeCalc);
|
69
|
+
addDeserializer(module, CheckBoxFieldValue.class, this::deserializeCheckBox);
|
70
|
+
addDeserializer(module, RadioButtonFieldValue.class, this::deserializeRadioButton);
|
71
|
+
addDeserializer(module, MultiSelectFieldValue.class, this::deserializeMultiSelect);
|
72
|
+
addDeserializer(module, DropDownFieldValue.class, this::deserializeDropDown);
|
73
|
+
addDeserializer(module, UserSelectFieldValue.class, this::deserializeUserSelect);
|
74
|
+
addDeserializer(module, User.class, this::deserializeUser);
|
75
|
+
addDeserializer(module, OrganizationSelectFieldValue.class, this::deserializeOrganizationSelect);
|
76
|
+
addDeserializer(module, Organization.class, this::deserializeOrganization);
|
77
|
+
addDeserializer(module, GroupSelectFieldValue.class, this::deserializeGroupSelect);
|
78
|
+
addDeserializer(module, Group.class, this::deserializeGroup);
|
79
|
+
addDeserializer(module, DateFieldValue.class, this::deserializeDate);
|
80
|
+
addDeserializer(module, TimeFieldValue.class, this::deserializeTime);
|
81
|
+
addDeserializer(module, DateTimeFieldValue.class, this::deserializeDateTime);
|
82
|
+
addDeserializer(module, LinkFieldValue.class, this::deserializeLink);
|
83
|
+
addDeserializer(module, FileFieldValue.class, this::deserializeFile);
|
84
|
+
addDeserializer(module, FileBody.class, this::deserializeFileBody);
|
85
|
+
// spotless:on
|
86
|
+
mapper.registerModule(module);
|
87
|
+
}
|
88
|
+
|
89
|
+
public <T> T deserialize(String content, Class<T> type) {
|
90
|
+
try {
|
91
|
+
return mapper.readValue(content, type);
|
92
|
+
} catch (IOException e) {
|
93
|
+
throw new DeserializeException(e);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
private <T> void addDeserializer(
|
98
|
+
SimpleModule module,
|
99
|
+
Class<T> type,
|
100
|
+
BiFunction<JsonParser, DeserializationContext, T> deserializer) {
|
101
|
+
module.addDeserializer(type, new DeserializeApplier<>(deserializer));
|
102
|
+
}
|
103
|
+
|
104
|
+
private SubtableFieldValue deserializeSubtable(
|
105
|
+
JsonParser parser, DeserializationContext context) {
|
106
|
+
return new SubtableFieldValue(readList(parser, TableRow.class));
|
107
|
+
}
|
108
|
+
|
109
|
+
private TableRow deserializeTableRow(JsonParser parser, DeserializationContext context) {
|
110
|
+
ObjectCodec codec = parser.getCodec();
|
111
|
+
JsonNode node = readTree(codec, parser);
|
112
|
+
TableRow row = new TableRow(get(node, "id", JsonNode::asLong));
|
113
|
+
stream(node.get("value").fields())
|
114
|
+
.forEach(entry -> row.putField(entry.getKey(), readValue(entry.getValue(), codec)));
|
115
|
+
return row;
|
116
|
+
}
|
117
|
+
|
118
|
+
private SingleLineTextFieldValue deserializeSingleLineText(
|
119
|
+
JsonParser parser, DeserializationContext context) {
|
120
|
+
return new SingleLineTextFieldValue(readText(parser));
|
121
|
+
}
|
122
|
+
|
123
|
+
private MultiLineTextFieldValue deserializeMultiLineText(
|
124
|
+
JsonParser parser, DeserializationContext context) {
|
125
|
+
return new MultiLineTextFieldValue(readText(parser));
|
126
|
+
}
|
127
|
+
|
128
|
+
private RichTextFieldValue deserializeRichText(
|
129
|
+
JsonParser parser, DeserializationContext context) {
|
130
|
+
return new RichTextFieldValue(readText(parser));
|
131
|
+
}
|
132
|
+
|
133
|
+
private NumberFieldValue deserializeNumber(JsonParser parser, DeserializationContext context) {
|
134
|
+
return new NumberFieldValue(read(parser, BigDecimal::new));
|
135
|
+
}
|
136
|
+
|
137
|
+
private CalcFieldValue deserializeCalc(JsonParser parser, DeserializationContext context) {
|
138
|
+
LOGGER.warn(
|
139
|
+
String.format(
|
140
|
+
"Ignore field: %s", new CalcFieldValue((BigDecimal) read(parser, BigDecimal::new))));
|
141
|
+
return null;
|
142
|
+
}
|
143
|
+
|
144
|
+
private CheckBoxFieldValue deserializeCheckBox(
|
145
|
+
JsonParser parser, DeserializationContext context) {
|
146
|
+
return new CheckBoxFieldValue(readList(parser, String.class));
|
147
|
+
}
|
148
|
+
|
149
|
+
private RadioButtonFieldValue deserializeRadioButton(
|
150
|
+
JsonParser parser, DeserializationContext context) {
|
151
|
+
return new RadioButtonFieldValue(readText(parser));
|
152
|
+
}
|
153
|
+
|
154
|
+
private MultiSelectFieldValue deserializeMultiSelect(
|
155
|
+
JsonParser parser, DeserializationContext context) {
|
156
|
+
return new MultiSelectFieldValue(readList(parser, String.class));
|
157
|
+
}
|
158
|
+
|
159
|
+
private DropDownFieldValue deserializeDropDown(
|
160
|
+
JsonParser parser, DeserializationContext context) {
|
161
|
+
return new DropDownFieldValue(readText(parser));
|
162
|
+
}
|
163
|
+
|
164
|
+
private UserSelectFieldValue deserializeUserSelect(
|
165
|
+
JsonParser parser, DeserializationContext context) {
|
166
|
+
return new UserSelectFieldValue(readList(parser, User.class));
|
167
|
+
}
|
168
|
+
|
169
|
+
private User deserializeUser(JsonParser parser, DeserializationContext context) {
|
170
|
+
JsonNode node = readTree(parser);
|
171
|
+
return new User(get(node, "name", JsonNode::asText), get(node, "code", JsonNode::asText));
|
172
|
+
}
|
173
|
+
|
174
|
+
private OrganizationSelectFieldValue deserializeOrganizationSelect(
|
175
|
+
JsonParser parser, DeserializationContext context) {
|
176
|
+
return new OrganizationSelectFieldValue(readList(parser, Organization.class));
|
177
|
+
}
|
178
|
+
|
179
|
+
private Organization deserializeOrganization(JsonParser parser, DeserializationContext context) {
|
180
|
+
JsonNode node = readTree(parser);
|
181
|
+
return new Organization(
|
182
|
+
get(node, "name", JsonNode::asText), get(node, "code", JsonNode::asText));
|
183
|
+
}
|
184
|
+
|
185
|
+
private GroupSelectFieldValue deserializeGroupSelect(
|
186
|
+
JsonParser parser, DeserializationContext context) {
|
187
|
+
return new GroupSelectFieldValue(readList(parser, Group.class));
|
188
|
+
}
|
189
|
+
|
190
|
+
private Group deserializeGroup(JsonParser parser, DeserializationContext context) {
|
191
|
+
JsonNode node = readTree(parser);
|
192
|
+
return new Group(get(node, "name", JsonNode::asText), get(node, "code", JsonNode::asText));
|
193
|
+
}
|
194
|
+
|
195
|
+
private DateFieldValue deserializeDate(JsonParser parser, DeserializationContext context) {
|
196
|
+
return new DateFieldValue(read(parser, LocalDate::parse));
|
197
|
+
}
|
198
|
+
|
199
|
+
private TimeFieldValue deserializeTime(JsonParser parser, DeserializationContext context) {
|
200
|
+
return new TimeFieldValue(read(parser, LocalTime::parse));
|
201
|
+
}
|
202
|
+
|
203
|
+
private DateTimeFieldValue deserializeDateTime(
|
204
|
+
JsonParser parser, DeserializationContext context) {
|
205
|
+
return new DateTimeFieldValue(read(parser, ZonedDateTime::parse));
|
206
|
+
}
|
207
|
+
|
208
|
+
private LinkFieldValue deserializeLink(JsonParser parser, DeserializationContext context) {
|
209
|
+
return new LinkFieldValue(readText(parser));
|
210
|
+
}
|
211
|
+
|
212
|
+
private FileFieldValue deserializeFile(JsonParser parser, DeserializationContext context) {
|
213
|
+
return new FileFieldValue(readList(parser, FileBody.class));
|
214
|
+
}
|
215
|
+
|
216
|
+
private FileBody deserializeFileBody(JsonParser parser, DeserializationContext context) {
|
217
|
+
JsonNode node = readTree(parser);
|
218
|
+
return new FileBody()
|
219
|
+
.setContentType(get(node, "contentType", JsonNode::asText))
|
220
|
+
.setFileKey(get(node, "fileKey", JsonNode::asText))
|
221
|
+
.setName(get(node, "name", JsonNode::asText))
|
222
|
+
.setSize(get(node, "size", JsonNode::asInt));
|
223
|
+
}
|
224
|
+
|
225
|
+
private static <T> T get(JsonNode node, String name, Function<JsonNode, T> as) {
|
226
|
+
return node.has(name) ? as.apply(node.get(name)) : null;
|
227
|
+
}
|
228
|
+
|
229
|
+
private static FieldValue readValue(JsonNode node, ObjectCodec codec) {
|
230
|
+
return node == null
|
231
|
+
? null
|
232
|
+
: readValueAs(
|
233
|
+
node.has("value") ? node.get("value") : NULL,
|
234
|
+
codec,
|
235
|
+
FieldType.valueOf(node.get("type").asText()).getFieldValueClass());
|
236
|
+
}
|
237
|
+
|
238
|
+
private static <T> List<T> readList(JsonParser parser, Class<T> type) {
|
239
|
+
ObjectCodec codec = parser.getCodec();
|
240
|
+
return stream(readTree(codec, parser).elements())
|
241
|
+
.map(node -> readValueAs(node, codec, type))
|
242
|
+
.collect(Collectors.toList());
|
243
|
+
}
|
244
|
+
|
245
|
+
private static <T> Stream<T> stream(Iterator<T> iterator) {
|
246
|
+
return StreamSupport.stream(
|
247
|
+
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false);
|
248
|
+
}
|
249
|
+
|
250
|
+
private static <T> T read(JsonParser parser, Function<String, T> as) {
|
251
|
+
String text = readText(parser);
|
252
|
+
return text == null || text.isEmpty() ? null : as.apply(text);
|
253
|
+
}
|
254
|
+
|
255
|
+
private static String readText(JsonParser parser) {
|
256
|
+
JsonNode node = readTree(parser);
|
257
|
+
return node == null || node.isNull() ? null : node.asText();
|
258
|
+
}
|
259
|
+
|
260
|
+
private static JsonNode readTree(JsonParser parser) {
|
261
|
+
return readTree(parser.getCodec(), parser);
|
262
|
+
}
|
263
|
+
|
264
|
+
private static JsonNode readTree(ObjectCodec codec, JsonParser parser) {
|
265
|
+
try {
|
266
|
+
return codec.readTree(parser);
|
267
|
+
} catch (IOException e) {
|
268
|
+
throw new DeserializeException(e);
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
private static <T> T readValueAs(JsonNode node, ObjectCodec codec, Class<T> type) {
|
273
|
+
try (JsonParser parser = node.traverse(codec)) {
|
274
|
+
return parser.readValueAs(type);
|
275
|
+
} catch (IOException e) {
|
276
|
+
throw new DeserializeException(e);
|
277
|
+
}
|
278
|
+
}
|
279
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
package org.embulk.output.kintone.reducer;
|
2
|
+
|
3
|
+
import java.time.Instant;
|
4
|
+
import java.util.List;
|
5
|
+
import org.embulk.spi.Column;
|
6
|
+
import org.embulk.spi.ColumnVisitor;
|
7
|
+
import org.embulk.spi.PageBuilder;
|
8
|
+
import org.embulk.spi.time.Timestamp;
|
9
|
+
|
10
|
+
public class CSVInputColumnVisitor implements ColumnVisitor {
|
11
|
+
private final PageBuilder builder;
|
12
|
+
private final List<String> values;
|
13
|
+
|
14
|
+
public CSVInputColumnVisitor(PageBuilder builder, List<String> values) {
|
15
|
+
this.builder = builder;
|
16
|
+
this.values = values;
|
17
|
+
}
|
18
|
+
|
19
|
+
@Override
|
20
|
+
public void booleanColumn(Column column) {
|
21
|
+
String value = values.get(column.getIndex());
|
22
|
+
if (value == null) {
|
23
|
+
builder.setNull(column);
|
24
|
+
} else {
|
25
|
+
builder.setBoolean(column, Boolean.parseBoolean(value));
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
@Override
|
30
|
+
public void longColumn(Column column) {
|
31
|
+
String value = values.get(column.getIndex());
|
32
|
+
if (value == null) {
|
33
|
+
builder.setNull(column);
|
34
|
+
} else {
|
35
|
+
builder.setLong(column, Long.parseLong(value));
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
@Override
|
40
|
+
public void doubleColumn(Column column) {
|
41
|
+
String value = values.get(column.getIndex());
|
42
|
+
if (value == null) {
|
43
|
+
builder.setNull(column);
|
44
|
+
} else {
|
45
|
+
builder.setDouble(column, Double.parseDouble(value));
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
@Override
|
50
|
+
public void stringColumn(Column column) {
|
51
|
+
String value = values.get(column.getIndex());
|
52
|
+
if (value == null) {
|
53
|
+
builder.setNull(column);
|
54
|
+
} else {
|
55
|
+
builder.setString(column, value);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
@Override
|
60
|
+
public void timestampColumn(Column column) {
|
61
|
+
String value = values.get(column.getIndex());
|
62
|
+
if (value == null) {
|
63
|
+
builder.setNull(column);
|
64
|
+
} else {
|
65
|
+
builder.setTimestamp(column, Timestamp.ofInstant(Instant.parse(value)));
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
@Override
|
70
|
+
public void jsonColumn(Column column) {
|
71
|
+
String value = values.get(column.getIndex());
|
72
|
+
if (value == null) {
|
73
|
+
builder.setNull(column);
|
74
|
+
} else {
|
75
|
+
builder.setJson(column, Reducer.PARSER.parse(value));
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
package org.embulk.output.kintone.reducer;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import org.apache.commons.csv.CSVPrinter;
|
5
|
+
import org.embulk.spi.Column;
|
6
|
+
import org.embulk.spi.ColumnVisitor;
|
7
|
+
import org.embulk.spi.PageReader;
|
8
|
+
|
9
|
+
public class CSVOutputColumnVisitor implements ColumnVisitor {
|
10
|
+
private final PageReader reader;
|
11
|
+
private final CSVPrinter printer;
|
12
|
+
|
13
|
+
public CSVOutputColumnVisitor(PageReader reader, CSVPrinter printer) {
|
14
|
+
this.reader = reader;
|
15
|
+
this.printer = printer;
|
16
|
+
}
|
17
|
+
|
18
|
+
@Override
|
19
|
+
public void booleanColumn(Column column) {
|
20
|
+
if (reader.isNull(column)) {
|
21
|
+
print(null);
|
22
|
+
} else {
|
23
|
+
print(reader.getBoolean(column));
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
@Override
|
28
|
+
public void longColumn(Column column) {
|
29
|
+
if (reader.isNull(column)) {
|
30
|
+
print(null);
|
31
|
+
} else {
|
32
|
+
print(reader.getLong(column));
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
@Override
|
37
|
+
public void doubleColumn(Column column) {
|
38
|
+
if (reader.isNull(column)) {
|
39
|
+
print(null);
|
40
|
+
} else {
|
41
|
+
print(reader.getDouble(column));
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
@Override
|
46
|
+
public void stringColumn(Column column) {
|
47
|
+
if (reader.isNull(column)) {
|
48
|
+
print(null);
|
49
|
+
} else {
|
50
|
+
print(reader.getString(column));
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
@Override
|
55
|
+
public void timestampColumn(Column column) {
|
56
|
+
if (reader.isNull(column)) {
|
57
|
+
print(null);
|
58
|
+
} else {
|
59
|
+
print(reader.getTimestamp(column).getInstant());
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
@Override
|
64
|
+
public void jsonColumn(Column column) {
|
65
|
+
if (reader.isNull(column)) {
|
66
|
+
print(null);
|
67
|
+
} else {
|
68
|
+
print(reader.getJson(column).toJson());
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
private void print(Object value) {
|
73
|
+
try {
|
74
|
+
printer.print(value);
|
75
|
+
} catch (IOException e) {
|
76
|
+
throw new ReduceException(e);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|