embulk-output-kintone 1.1.0 → 1.2.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 +8 -0
- data/classpath/embulk-output-kintone-1.2.0.jar +0 -0
- data/classpath/{shadow-kintone-java-client-1.1.0-all.jar → shadow-kintone-java-client-1.2.0-all.jar} +0 -0
- data/src/main/java/org/embulk/output/kintone/KintoneClient.java +117 -0
- data/src/main/java/org/embulk/output/kintone/KintoneColumnType.java +30 -13
- data/src/main/java/org/embulk/output/kintone/KintoneColumnVisitor.java +54 -4
- data/src/main/java/org/embulk/output/kintone/KintoneMode.java +52 -4
- data/src/main/java/org/embulk/output/kintone/KintoneOutputPlugin.java +0 -17
- data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +106 -118
- data/src/main/java/org/embulk/output/kintone/PluginTask.java +5 -0
- data/src/main/java/org/embulk/output/kintone/record/Id.java +18 -0
- data/src/main/java/org/embulk/output/kintone/record/IdOrUpdateKey.java +45 -0
- data/src/main/java/org/embulk/output/kintone/record/Skip.java +14 -0
- data/src/main/java/org/embulk/output/kintone/util/Lazy.java +20 -0
- data/src/test/java/org/embulk/output/kintone/KintoneClientTest.java +139 -0
- data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorTest.java +33 -33
- data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorVerifier.java +6 -6
- data/src/test/java/org/embulk/output/kintone/KintonePageOutputVerifier.java +79 -53
- data/src/test/java/org/embulk/output/kintone/MockClient.java +112 -0
- data/src/test/java/org/embulk/output/kintone/TestKintoneOutputPlugin.java +64 -16
- data/src/test/java/org/embulk/output/kintone/TestTaskMode.java +1 -0
- data/src/test/java/org/embulk/output/kintone/TestTaskReduce.java +1 -0
- data/src/test/java/org/embulk/output/kintone/TestTaskReduceSubtable.java +1 -0
- data/src/test/java/org/embulk/output/kintone/TestTaskSkip.java +80 -0
- data/src/test/java/org/embulk/output/kintone/TestTaskSkipId.java +80 -0
- data/src/test/resources/org/embulk/output/kintone/client/config.yml +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/config.yml +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_never_skip_double_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_double_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/config.yml +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/input.csv +7 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/insert_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/insert_always_skip_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/insert_always_skip_prefer_nulls_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/insert_never_skip_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/insert_never_skip_prefer_nulls_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/insert_prefer_nulls_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_long_number_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_long_number_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_prefer_nulls_long_number_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_prefer_nulls_long_number_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_update_records.jsonl +5 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_never_skip_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_prefer_nulls_update_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/update_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_add_records.jsonl +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_prefer_nulls_string_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_prefer_nulls_string_single_line_text_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_string_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_string_single_line_text_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_add_records.jsonl +4 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_add_records.jsonl +4 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_string_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_string_single_line_text_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_string_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_string_single_line_text_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_add_records.jsonl +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_string_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_string_single_line_text_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_string_single_line_text_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_string_single_line_text_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/config.yml +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/input.csv +7 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_always_skip_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_always_skip_prefer_nulls_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_never_skip_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_never_skip_prefer_nulls_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_prefer_nulls_add_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_prefer_nulls__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_prefer_nulls__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_update_records.jsonl +5 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_never_skip_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_prefer_nulls_update_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_update_records.jsonl +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_prefer_nulls__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_prefer_nulls__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_update_records.jsonl +5 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_add_records.jsonl +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls_add_records.jsonl +4 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_update_records.jsonl +5 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls__id_add_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls__id_values.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls_add_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls_update_records.jsonl +2 -0
- data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_update_records.jsonl +5 -0
- metadata +131 -43
- data/classpath/embulk-output-kintone-1.1.0.jar +0 -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/mode/{insert_add_ignore_nulls_records.jsonl → insert_ignore_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{insert_add_prefer_nulls_records.jsonl → insert_prefer_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{update_update_ignore_nulls_records.jsonl → update_ignore_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{update_update_prefer_nulls_records.jsonl → update_prefer_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_add_records.jsonl → upsert_never_skip_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{values.json → upsert_never_skip_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_add_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{values_ignore_nulls.json → upsert_never_skip_ignore_nulls_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_update_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_add_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{values_prefer_nulls.json → upsert_never_skip_prefer_nulls_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_update_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_update_records.jsonl → upsert_never_skip_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{insert_add_ignore_nulls_records.jsonl → insert_ignore_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{insert_add_prefer_nulls_records.jsonl → insert_prefer_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{update_update_ignore_nulls_records.jsonl → update_ignore_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{update_update_prefer_nulls_records.jsonl → update_prefer_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{upsert_add_records.jsonl → upsert_never_skip_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{values.json → upsert_never_skip_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{upsert_add_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{values_ignore_nulls.json → upsert_never_skip_ignore_nulls_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{upsert_update_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{upsert_add_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{values_prefer_nulls.json → upsert_never_skip_prefer_nulls_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{upsert_update_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce/{upsert_update_records.jsonl → upsert_never_skip_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{insert_add_ignore_nulls_records.jsonl → insert_ignore_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{insert_add_prefer_nulls_records.jsonl → insert_prefer_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{update_update_ignore_nulls_records.jsonl → update_ignore_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{update_update_prefer_nulls_records.jsonl → update_prefer_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{values.json → upsert_never_skip_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{upsert_add_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{values_ignore_nulls.json → upsert_never_skip_ignore_nulls_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{upsert_update_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{upsert_add_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_add_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{values_prefer_nulls.json → upsert_never_skip_prefer_nulls_double_single_line_text_values.json} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{upsert_update_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_update_records.jsonl} +0 -0
- /data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/{upsert_update_records.jsonl → upsert_never_skip_update_records.jsonl} +0 -0
@@ -5,15 +5,11 @@ import static org.embulk.spi.util.RetryExecutor.retryExecutor;
|
|
5
5
|
import com.fasterxml.jackson.databind.JsonNode;
|
6
6
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
7
7
|
import com.google.common.collect.Maps;
|
8
|
-
import com.kintone.client.KintoneClient;
|
9
|
-
import com.kintone.client.KintoneClientBuilder;
|
10
8
|
import com.kintone.client.api.record.GetRecordsByCursorResponseBody;
|
11
9
|
import com.kintone.client.exception.KintoneApiRuntimeException;
|
12
|
-
import com.kintone.client.model.app.field.FieldProperty;
|
13
10
|
import com.kintone.client.model.record.FieldType;
|
14
11
|
import com.kintone.client.model.record.Record;
|
15
12
|
import com.kintone.client.model.record.RecordForUpdate;
|
16
|
-
import com.kintone.client.model.record.UpdateKey;
|
17
13
|
import java.io.IOException;
|
18
14
|
import java.lang.invoke.MethodHandles;
|
19
15
|
import java.math.BigDecimal;
|
@@ -28,8 +24,11 @@ import java.util.function.Function;
|
|
28
24
|
import java.util.function.Supplier;
|
29
25
|
import java.util.stream.Collectors;
|
30
26
|
import org.apache.commons.lang3.tuple.Pair;
|
31
|
-
import org.embulk.config.ConfigException;
|
32
27
|
import org.embulk.config.TaskReport;
|
28
|
+
import org.embulk.output.kintone.record.Id;
|
29
|
+
import org.embulk.output.kintone.record.IdOrUpdateKey;
|
30
|
+
import org.embulk.output.kintone.record.Skip;
|
31
|
+
import org.embulk.output.kintone.util.Lazy;
|
33
32
|
import org.embulk.spi.Exec;
|
34
33
|
import org.embulk.spi.Page;
|
35
34
|
import org.embulk.spi.PageReader;
|
@@ -53,30 +52,17 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
53
52
|
private final Map<String, Pair<FieldType, FieldType>> wrongTypeFields = new TreeMap<>();
|
54
53
|
private final PluginTask task;
|
55
54
|
private final PageReader reader;
|
56
|
-
private KintoneClient client;
|
57
|
-
private Map<String, FieldProperty> formFields;
|
55
|
+
private final Lazy<KintoneClient> client;
|
58
56
|
|
59
57
|
public KintonePageOutput(PluginTask task, Schema schema) {
|
60
58
|
this.task = task;
|
61
59
|
reader = new PageReader(schema);
|
60
|
+
client = KintoneClient.lazy(() -> task, schema);
|
62
61
|
}
|
63
62
|
|
64
63
|
@Override
|
65
64
|
public void add(Page page) {
|
66
|
-
KintoneMode
|
67
|
-
switch (mode) {
|
68
|
-
case INSERT:
|
69
|
-
insertPage(page);
|
70
|
-
break;
|
71
|
-
case UPDATE:
|
72
|
-
updatePage(page);
|
73
|
-
break;
|
74
|
-
case UPSERT:
|
75
|
-
upsertPage(page);
|
76
|
-
break;
|
77
|
-
default:
|
78
|
-
throw new UnsupportedOperationException(String.format("Unknown mode '%s'", task.getMode()));
|
79
|
-
}
|
65
|
+
KintoneMode.of(task).add(page, task.getSkipIfNonExistingIdOrUpdateKey(), this);
|
80
66
|
}
|
81
67
|
|
82
68
|
@Override
|
@@ -86,14 +72,7 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
86
72
|
|
87
73
|
@Override
|
88
74
|
public void close() {
|
89
|
-
|
90
|
-
return; // Not connected
|
91
|
-
}
|
92
|
-
try {
|
93
|
-
client.close();
|
94
|
-
} catch (Exception e) {
|
95
|
-
throw new RuntimeException("kintone throw exception", e);
|
96
|
-
}
|
75
|
+
client.get().close();
|
97
76
|
}
|
98
77
|
|
99
78
|
@Override
|
@@ -112,38 +91,15 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
112
91
|
return Exec.newTaskReport();
|
113
92
|
}
|
114
93
|
|
115
|
-
private void connectIfNeeded() {
|
116
|
-
if (client != null) {
|
117
|
-
return; // Already connected
|
118
|
-
}
|
119
|
-
KintoneClientBuilder builder = KintoneClientBuilder.create("https://" + task.getDomain());
|
120
|
-
if (task.getGuestSpaceId().isPresent()) {
|
121
|
-
builder.setGuestSpaceId(task.getGuestSpaceId().get());
|
122
|
-
}
|
123
|
-
if (task.getBasicAuthUsername().isPresent() && task.getBasicAuthPassword().isPresent()) {
|
124
|
-
builder.withBasicAuth(task.getBasicAuthUsername().get(), task.getBasicAuthPassword().get());
|
125
|
-
}
|
126
|
-
if (task.getUsername().isPresent() && task.getPassword().isPresent()) {
|
127
|
-
builder.authByPassword(task.getUsername().get(), task.getPassword().get());
|
128
|
-
} else if (task.getToken().isPresent()) {
|
129
|
-
builder.authByApiToken(task.getToken().get());
|
130
|
-
} else {
|
131
|
-
throw new ConfigException("Username and password or token must be configured.");
|
132
|
-
}
|
133
|
-
client = builder.build();
|
134
|
-
formFields = client.app().getFormFields(task.getAppId());
|
135
|
-
}
|
136
|
-
|
137
94
|
private void insert(List<Record> records) {
|
138
|
-
executeWithRetry(() -> client.record().addRecords(task.getAppId(), records));
|
95
|
+
executeWithRetry(() -> client.get().record().addRecords(task.getAppId(), records));
|
139
96
|
}
|
140
97
|
|
141
98
|
private void update(List<RecordForUpdate> records) {
|
142
|
-
executeWithRetry(() -> client.record().updateRecords(task.getAppId(), records));
|
99
|
+
executeWithRetry(() -> client.get().record().updateRecords(task.getAppId(), records));
|
143
100
|
}
|
144
101
|
|
145
102
|
private <T> T executeWithRetry(Supplier<T> operation) {
|
146
|
-
connectIfNeeded();
|
147
103
|
KintoneRetryOption retryOption = task.getRetryOptions();
|
148
104
|
try {
|
149
105
|
return retryExecutor()
|
@@ -153,7 +109,7 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
153
109
|
.runInterruptible(
|
154
110
|
new Retryable<T>() {
|
155
111
|
@Override
|
156
|
-
public T call()
|
112
|
+
public T call() {
|
157
113
|
return operation.get();
|
158
114
|
}
|
159
115
|
|
@@ -175,8 +131,7 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
175
131
|
|
176
132
|
@Override
|
177
133
|
public void onRetry(
|
178
|
-
Exception exception, int retryCount, int retryLimit, int retryWait)
|
179
|
-
throws RetryGiveupException {
|
134
|
+
Exception exception, int retryCount, int retryLimit, int retryWait) {
|
180
135
|
String message =
|
181
136
|
String.format(
|
182
137
|
"Retrying %d/%d after %d seconds. Message: %s",
|
@@ -189,15 +144,14 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
189
144
|
}
|
190
145
|
|
191
146
|
@Override
|
192
|
-
public void onGiveup(Exception firstException, Exception lastException)
|
193
|
-
throws RetryGiveupException {}
|
147
|
+
public void onGiveup(Exception firstException, Exception lastException) {}
|
194
148
|
});
|
195
149
|
} catch (RetryGiveupException | InterruptedException e) {
|
196
150
|
throw new RuntimeException("kintone throw exception", e);
|
197
151
|
}
|
198
152
|
}
|
199
153
|
|
200
|
-
|
154
|
+
public void insertPage(Page page) {
|
201
155
|
List<Record> records = new ArrayList<>();
|
202
156
|
reader.setPage(page);
|
203
157
|
KintoneColumnVisitor visitor =
|
@@ -224,7 +178,8 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
224
178
|
}
|
225
179
|
}
|
226
180
|
|
227
|
-
|
181
|
+
public void updatePage(Page page) {
|
182
|
+
Skip skip = task.getSkipIfNonExistingIdOrUpdateKey();
|
228
183
|
List<RecordForUpdate> records = new ArrayList<>();
|
229
184
|
reader.setPage(page);
|
230
185
|
KintoneColumnVisitor visitor =
|
@@ -235,20 +190,21 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
235
190
|
task.getPreferNulls(),
|
236
191
|
task.getIgnoreNulls(),
|
237
192
|
task.getReduceKeyName().orElse(null),
|
238
|
-
task.getUpdateKeyName()
|
239
|
-
.orElseThrow(() -> new RuntimeException("unreachable"))); // Already validated
|
193
|
+
task.getUpdateKeyName().orElse(Id.FIELD));
|
240
194
|
while (reader.nextRecord()) {
|
241
195
|
Record record = new Record();
|
242
|
-
|
196
|
+
IdOrUpdateKey idOrUpdateKey = new IdOrUpdateKey();
|
243
197
|
visitor.setRecord(record);
|
244
|
-
visitor.
|
198
|
+
visitor.setIdOrUpdateKey(idOrUpdateKey);
|
245
199
|
reader.getSchema().visitColumns(visitor);
|
246
200
|
putWrongTypeFields(record);
|
247
|
-
if (
|
248
|
-
|
201
|
+
if (skip == Skip.NEVER && !idOrUpdateKey.isPresent()) {
|
202
|
+
throw new RuntimeException("No id or update key value was specified");
|
203
|
+
} else if (!idOrUpdateKey.isPresent()) {
|
204
|
+
LOGGER.warn("Record skipped because no id or update key value was specified");
|
249
205
|
continue;
|
250
206
|
}
|
251
|
-
records.add(
|
207
|
+
records.add(idOrUpdateKey.forUpdate(record));
|
252
208
|
if (records.size() == task.getChunkSize()) {
|
253
209
|
update(records);
|
254
210
|
records.clear();
|
@@ -259,9 +215,9 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
259
215
|
}
|
260
216
|
}
|
261
217
|
|
262
|
-
|
218
|
+
public void upsertPage(Page page) {
|
263
219
|
List<Record> records = new ArrayList<>();
|
264
|
-
List<
|
220
|
+
List<IdOrUpdateKey> idOrUpdateKeys = new ArrayList<>();
|
265
221
|
reader.setPage(page);
|
266
222
|
KintoneColumnVisitor visitor =
|
267
223
|
new KintoneColumnVisitor(
|
@@ -271,40 +227,72 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
271
227
|
task.getPreferNulls(),
|
272
228
|
task.getIgnoreNulls(),
|
273
229
|
task.getReduceKeyName().orElse(null),
|
274
|
-
task.getUpdateKeyName()
|
275
|
-
.orElseThrow(() -> new RuntimeException("unreachable"))); // Already validated
|
230
|
+
task.getUpdateKeyName().orElse(Id.FIELD));
|
276
231
|
while (reader.nextRecord()) {
|
277
232
|
Record record = new Record();
|
278
|
-
|
233
|
+
IdOrUpdateKey idOrUpdateKey = new IdOrUpdateKey();
|
279
234
|
visitor.setRecord(record);
|
280
|
-
visitor.
|
235
|
+
visitor.setIdOrUpdateKey(idOrUpdateKey);
|
281
236
|
reader.getSchema().visitColumns(visitor);
|
282
237
|
putWrongTypeFields(record);
|
283
238
|
records.add(record);
|
284
|
-
|
239
|
+
idOrUpdateKeys.add(idOrUpdateKey);
|
285
240
|
if (records.size() == UPSERT_BATCH_SIZE) {
|
286
|
-
upsert(records,
|
241
|
+
upsert(records, idOrUpdateKeys);
|
287
242
|
records.clear();
|
288
|
-
|
243
|
+
idOrUpdateKeys.clear();
|
289
244
|
}
|
290
245
|
}
|
291
246
|
if (!records.isEmpty()) {
|
292
|
-
upsert(records,
|
247
|
+
upsert(records, idOrUpdateKeys);
|
293
248
|
}
|
294
249
|
}
|
295
250
|
|
296
|
-
private void upsert(List<Record> records, List<
|
297
|
-
if (records.size() !=
|
298
|
-
throw new RuntimeException("records.size() !=
|
251
|
+
private void upsert(List<Record> records, List<IdOrUpdateKey> idOrUpdateKeys) {
|
252
|
+
if (records.size() != idOrUpdateKeys.size()) {
|
253
|
+
throw new RuntimeException("records.size() != idOrUpdateKeys.size()");
|
299
254
|
}
|
300
|
-
|
255
|
+
Skip skip = task.getSkipIfNonExistingIdOrUpdateKey();
|
256
|
+
String columnName = task.getUpdateKeyName().orElse(Id.FIELD);
|
257
|
+
boolean isId = columnName.equals(Id.FIELD);
|
258
|
+
List<String> existingValues =
|
259
|
+
executeWithRetry(() -> getExistingValuesByIdOrUpdateKey(idOrUpdateKeys, columnName));
|
301
260
|
List<Record> insertRecords = new ArrayList<>();
|
302
261
|
List<RecordForUpdate> updateRecords = new ArrayList<>();
|
303
262
|
for (int i = 0; i < records.size(); i++) {
|
263
|
+
RecordForUpdate recordForUpdate = null;
|
304
264
|
Record record = records.get(i);
|
305
|
-
|
306
|
-
if (existsRecord(existingValues,
|
307
|
-
|
265
|
+
IdOrUpdateKey idOrUpdateKey = idOrUpdateKeys.get(i);
|
266
|
+
if (existsRecord(existingValues, idOrUpdateKey)) {
|
267
|
+
recordForUpdate = idOrUpdateKey.forUpdate(record);
|
268
|
+
} else if (skip == Skip.ALWAYS && idOrUpdateKey.isPresent()) {
|
269
|
+
LOGGER.warn(
|
270
|
+
"Record skipped because non existing id or update key '"
|
271
|
+
+ idOrUpdateKey.getValue()
|
272
|
+
+ "' was specified");
|
273
|
+
continue;
|
274
|
+
} else if (skip == Skip.ALWAYS && !idOrUpdateKey.isPresent()) {
|
275
|
+
LOGGER.warn("Record skipped because no id or update key value was specified");
|
276
|
+
continue;
|
277
|
+
} else if (skip == Skip.AUTO && idOrUpdateKey.isIdPresent()) {
|
278
|
+
LOGGER.warn(
|
279
|
+
"Record skipped because non existing id '"
|
280
|
+
+ idOrUpdateKey.getValue()
|
281
|
+
+ "' was specified");
|
282
|
+
continue;
|
283
|
+
} else if (skip == Skip.AUTO && !isId && !idOrUpdateKey.isUpdateKeyPresent()) {
|
284
|
+
LOGGER.warn("Record skipped because no update key value was specified");
|
285
|
+
continue;
|
286
|
+
} else if (idOrUpdateKey.isIdPresent()) {
|
287
|
+
LOGGER.warn(
|
288
|
+
"Record inserted though non existing id '"
|
289
|
+
+ idOrUpdateKey.getValue()
|
290
|
+
+ "' was specified");
|
291
|
+
} else if (!isId && !idOrUpdateKey.isUpdateKeyPresent()) {
|
292
|
+
LOGGER.warn("Record inserted though no update key value was specified");
|
293
|
+
}
|
294
|
+
if (recordForUpdate != null) {
|
295
|
+
updateRecords.add(recordForUpdate);
|
308
296
|
} else {
|
309
297
|
insertRecords.add(record);
|
310
298
|
}
|
@@ -324,51 +312,53 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
324
312
|
}
|
325
313
|
}
|
326
314
|
|
327
|
-
private List<String>
|
328
|
-
|
329
|
-
updateKeys.stream()
|
330
|
-
.map(UpdateKey::getField)
|
331
|
-
.filter(Objects::nonNull)
|
332
|
-
.findFirst()
|
333
|
-
.orElse(null);
|
334
|
-
if (fieldCode == null) {
|
335
|
-
return Collections.emptyList();
|
336
|
-
}
|
337
|
-
Function<Record, String> fieldValueAsString;
|
338
|
-
FieldType fieldType = getFieldType(fieldCode);
|
339
|
-
if (fieldType == FieldType.SINGLE_LINE_TEXT) {
|
340
|
-
fieldValueAsString = record -> record.getSingleLineTextFieldValue(fieldCode);
|
341
|
-
} else if (fieldType == FieldType.NUMBER) {
|
342
|
-
fieldValueAsString = record -> toString(record.getNumberFieldValue(fieldCode));
|
343
|
-
} else {
|
344
|
-
throw new ConfigException("The update_key must be 'SINGLE_LINE_TEXT' or 'NUMBER'.");
|
345
|
-
}
|
315
|
+
private List<String> getExistingValuesByIdOrUpdateKey(
|
316
|
+
List<IdOrUpdateKey> idOrUpdateKeys, String columnName) {
|
346
317
|
List<String> queryValues =
|
347
|
-
|
348
|
-
.filter(
|
318
|
+
idOrUpdateKeys.stream()
|
319
|
+
.filter(IdOrUpdateKey::isPresent)
|
349
320
|
.map(k -> "\"" + k.getValue() + "\"")
|
350
321
|
.collect(Collectors.toList());
|
351
322
|
if (queryValues.isEmpty()) {
|
352
323
|
return Collections.emptyList();
|
353
324
|
}
|
325
|
+
return columnName.equals(Id.FIELD)
|
326
|
+
? getExistingValuesById(queryValues)
|
327
|
+
: getExistingValuesByUpdateKey(columnName, queryValues);
|
328
|
+
}
|
329
|
+
|
330
|
+
private List<String> getExistingValuesById(List<String> queryValues) {
|
331
|
+
return getExistingValues(Id.FIELD, Record::getId, queryValues);
|
332
|
+
}
|
333
|
+
|
334
|
+
private List<String> getExistingValuesByUpdateKey(String columnName, List<String> queryValues) {
|
335
|
+
KintoneColumnOption option = task.getColumnOptions().get(columnName);
|
336
|
+
String fieldCode = option != null ? option.getFieldCode() : columnName;
|
337
|
+
KintoneColumnType type = KintoneColumnType.valueOf(getFieldType(fieldCode).name());
|
338
|
+
return getExistingValues(fieldCode, record -> type.getValue(record, fieldCode), queryValues);
|
339
|
+
}
|
340
|
+
|
341
|
+
private List<String> getExistingValues(
|
342
|
+
String fieldCode, Function<Record, Object> toValue, List<String> queryValues) {
|
354
343
|
String cursorId =
|
355
344
|
client
|
345
|
+
.get()
|
356
346
|
.record()
|
357
347
|
.createCursor(
|
358
348
|
task.getAppId(),
|
359
349
|
Collections.singletonList(fieldCode),
|
360
350
|
fieldCode + " in (" + String.join(",", queryValues) + ")");
|
361
|
-
List<Record>
|
351
|
+
List<Record> records = new ArrayList<>();
|
362
352
|
while (true) {
|
363
|
-
GetRecordsByCursorResponseBody
|
364
|
-
|
365
|
-
|
366
|
-
if (!resp.hasNext()) {
|
353
|
+
GetRecordsByCursorResponseBody cursor = client.get().record().getRecordsByCursor(cursorId);
|
354
|
+
records.addAll(cursor.getRecords());
|
355
|
+
if (!cursor.hasNext()) {
|
367
356
|
break;
|
368
357
|
}
|
369
358
|
}
|
370
|
-
return
|
371
|
-
.map(
|
359
|
+
return records.stream()
|
360
|
+
.map(toValue)
|
361
|
+
.map(KintonePageOutput::toString)
|
372
362
|
.filter(Objects::nonNull)
|
373
363
|
.collect(Collectors.toList());
|
374
364
|
}
|
@@ -384,13 +374,11 @@ public class KintonePageOutput implements TransactionalPageOutput {
|
|
384
374
|
}
|
385
375
|
|
386
376
|
private FieldType getFieldType(String fieldCode) {
|
387
|
-
|
388
|
-
FieldProperty field = formFields.get(fieldCode);
|
389
|
-
return field == null ? null : field.getType();
|
377
|
+
return client.get().getFieldType(fieldCode);
|
390
378
|
}
|
391
379
|
|
392
|
-
private static boolean existsRecord(List<String> existingValues,
|
393
|
-
String value = toString(
|
380
|
+
private static boolean existsRecord(List<String> existingValues, IdOrUpdateKey idOrUpdateKey) {
|
381
|
+
String value = toString(idOrUpdateKey.getValue());
|
394
382
|
return value != null && existingValues.stream().anyMatch(v -> v.equals(value));
|
395
383
|
}
|
396
384
|
|
@@ -7,6 +7,7 @@ import java.util.Set;
|
|
7
7
|
import org.embulk.config.Config;
|
8
8
|
import org.embulk.config.ConfigDefault;
|
9
9
|
import org.embulk.config.Task;
|
10
|
+
import org.embulk.output.kintone.record.Skip;
|
10
11
|
import org.embulk.spi.Column;
|
11
12
|
|
12
13
|
public interface PluginTask extends Task {
|
@@ -52,6 +53,10 @@ public interface PluginTask extends Task {
|
|
52
53
|
@ConfigDefault("\"false\"")
|
53
54
|
boolean getIgnoreNulls();
|
54
55
|
|
56
|
+
@Config("skip_if_non_existing_id_or_update_key")
|
57
|
+
@ConfigDefault("\"auto\"")
|
58
|
+
Skip getSkipIfNonExistingIdOrUpdateKey();
|
59
|
+
|
55
60
|
@Config("mode")
|
56
61
|
@ConfigDefault("\"insert\"")
|
57
62
|
String getMode();
|
@@ -0,0 +1,18 @@
|
|
1
|
+
package org.embulk.output.kintone.record;
|
2
|
+
|
3
|
+
public class Id {
|
4
|
+
public static final String FIELD = "$id";
|
5
|
+
private Long value;
|
6
|
+
|
7
|
+
public void setValue(Long value) {
|
8
|
+
this.value = value;
|
9
|
+
}
|
10
|
+
|
11
|
+
public Long getValue() {
|
12
|
+
return value;
|
13
|
+
}
|
14
|
+
|
15
|
+
public boolean isPresent() {
|
16
|
+
return value != null;
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
package org.embulk.output.kintone.record;
|
2
|
+
|
3
|
+
import com.kintone.client.model.record.Record;
|
4
|
+
import com.kintone.client.model.record.RecordForUpdate;
|
5
|
+
import com.kintone.client.model.record.UpdateKey;
|
6
|
+
|
7
|
+
public class IdOrUpdateKey {
|
8
|
+
private final Id id = new Id();
|
9
|
+
private final UpdateKey updateKey = new UpdateKey();
|
10
|
+
|
11
|
+
public Id getId() {
|
12
|
+
return id;
|
13
|
+
}
|
14
|
+
|
15
|
+
public UpdateKey getUpdateKey() {
|
16
|
+
return updateKey;
|
17
|
+
}
|
18
|
+
|
19
|
+
public String getField() {
|
20
|
+
return isIdPresent() ? Id.FIELD : updateKey.getField();
|
21
|
+
}
|
22
|
+
|
23
|
+
public Object getValue() {
|
24
|
+
return isIdPresent() ? id.getValue() : updateKey.getValue();
|
25
|
+
}
|
26
|
+
|
27
|
+
public RecordForUpdate forUpdate(Record record) {
|
28
|
+
return isIdPresent()
|
29
|
+
? new RecordForUpdate(id.getValue(), record)
|
30
|
+
: new RecordForUpdate(updateKey, record.removeField(updateKey.getField()));
|
31
|
+
}
|
32
|
+
|
33
|
+
public boolean isPresent() {
|
34
|
+
return isIdPresent() || isUpdateKeyPresent();
|
35
|
+
}
|
36
|
+
|
37
|
+
public boolean isIdPresent() {
|
38
|
+
return id.isPresent();
|
39
|
+
}
|
40
|
+
|
41
|
+
public boolean isUpdateKeyPresent() {
|
42
|
+
Object value = updateKey.getValue();
|
43
|
+
return value != null && !value.toString().isEmpty();
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
package org.embulk.output.kintone.record;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.annotation.JsonCreator;
|
4
|
+
|
5
|
+
public enum Skip {
|
6
|
+
AUTO,
|
7
|
+
NEVER,
|
8
|
+
ALWAYS;
|
9
|
+
|
10
|
+
@JsonCreator
|
11
|
+
public static Skip of(String name) {
|
12
|
+
return valueOf(name.toUpperCase());
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
package org.embulk.output.kintone.util;
|
2
|
+
|
3
|
+
public abstract class Lazy<T extends AutoCloseable> implements AutoCloseable {
|
4
|
+
private T value;
|
5
|
+
|
6
|
+
public T get() {
|
7
|
+
if (value == null) {
|
8
|
+
value = initialValue();
|
9
|
+
}
|
10
|
+
return value;
|
11
|
+
}
|
12
|
+
|
13
|
+
public void close() throws Exception {
|
14
|
+
if (value != null) {
|
15
|
+
value.close();
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
protected abstract T initialValue();
|
20
|
+
}
|
@@ -0,0 +1,139 @@
|
|
1
|
+
package org.embulk.output.kintone;
|
2
|
+
|
3
|
+
import static org.hamcrest.MatcherAssert.assertThat;
|
4
|
+
import static org.hamcrest.Matchers.is;
|
5
|
+
import static org.junit.Assert.assertThrows;
|
6
|
+
|
7
|
+
import java.util.Collections;
|
8
|
+
import org.embulk.config.ConfigException;
|
9
|
+
import org.embulk.config.ConfigSource;
|
10
|
+
import org.embulk.output.kintone.util.Lazy;
|
11
|
+
import org.embulk.spi.Schema;
|
12
|
+
import org.embulk.spi.type.Type;
|
13
|
+
import org.embulk.spi.type.Types;
|
14
|
+
import org.junit.Before;
|
15
|
+
import org.junit.Test;
|
16
|
+
|
17
|
+
public class KintoneClientTest extends TestKintoneOutputPlugin {
|
18
|
+
private ConfigSource config;
|
19
|
+
|
20
|
+
@Before
|
21
|
+
public void before() {
|
22
|
+
config = loadConfigYaml("client/config.yml");
|
23
|
+
}
|
24
|
+
|
25
|
+
@Test
|
26
|
+
public void testInsert() {
|
27
|
+
merge(config("mode: insert"));
|
28
|
+
merge(config("update_key: null"));
|
29
|
+
runWithMockClient(Lazy::get);
|
30
|
+
merge(config("update_key: long_number"));
|
31
|
+
assertConfigException("When mode is insert, require no update_key.");
|
32
|
+
merge(config("update_key: string_single_line_text"));
|
33
|
+
assertConfigException("When mode is insert, require no update_key.");
|
34
|
+
merge(config("update_key: $id"));
|
35
|
+
assertConfigException("When mode is insert, require no update_key.", id(Types.LONG));
|
36
|
+
merge(config("update_key: null"));
|
37
|
+
runWithMockClient(Lazy::get, id(Types.STRING));
|
38
|
+
}
|
39
|
+
|
40
|
+
@Test
|
41
|
+
public void testUpdate() {
|
42
|
+
merge(config("mode: update"));
|
43
|
+
merge(config("update_key: null"));
|
44
|
+
assertConfigException("When mode is update, require update_key or id column.");
|
45
|
+
merge(config("update_key: non_existing_column"));
|
46
|
+
assertConfigException("The column 'non_existing_column' for update does not exist.");
|
47
|
+
merge(config("update_key: non_existing_field"));
|
48
|
+
assertConfigException("The field 'non_existing_field' for update does not exist.");
|
49
|
+
merge(config("update_key: invalid_type_field_multi_line_text"));
|
50
|
+
assertConfigException("The update_key must be 'SINGLE_LINE_TEXT' or 'NUMBER'.");
|
51
|
+
merge(config("update_key: long_number"));
|
52
|
+
runWithMockClient(Lazy::get);
|
53
|
+
merge(config("update_key: string_single_line_text"));
|
54
|
+
runWithMockClient(Lazy::get);
|
55
|
+
merge(config("update_key: $id"));
|
56
|
+
runWithMockClient(Lazy::get, id(Types.LONG));
|
57
|
+
merge(config("update_key: null"));
|
58
|
+
assertConfigException("The id column must be 'long'.", id(Types.STRING));
|
59
|
+
}
|
60
|
+
|
61
|
+
@Test
|
62
|
+
public void testUpsert() {
|
63
|
+
merge(config("mode: upsert"));
|
64
|
+
merge(config("update_key: null"));
|
65
|
+
assertConfigException("When mode is upsert, require update_key or id column.");
|
66
|
+
merge(config("update_key: non_existing_column"));
|
67
|
+
assertConfigException("The column 'non_existing_column' for update does not exist.");
|
68
|
+
merge(config("update_key: non_existing_field"));
|
69
|
+
assertConfigException("The field 'non_existing_field' for update does not exist.");
|
70
|
+
merge(config("update_key: invalid_type_field_multi_line_text"));
|
71
|
+
assertConfigException("The update_key must be 'SINGLE_LINE_TEXT' or 'NUMBER'.");
|
72
|
+
merge(config("update_key: long_number"));
|
73
|
+
runWithMockClient(Lazy::get);
|
74
|
+
merge(config("update_key: string_single_line_text"));
|
75
|
+
runWithMockClient(Lazy::get);
|
76
|
+
merge(config("update_key: $id"));
|
77
|
+
runWithMockClient(Lazy::get, id(Types.LONG));
|
78
|
+
merge(config("update_key: null"));
|
79
|
+
assertConfigException("The id column must be 'long'.", id(Types.STRING));
|
80
|
+
}
|
81
|
+
|
82
|
+
private void assertConfigException(String message) {
|
83
|
+
assertConfigException(message, builder());
|
84
|
+
}
|
85
|
+
|
86
|
+
private void assertConfigException(String message, Schema.Builder builder) {
|
87
|
+
runWithMockClient(
|
88
|
+
client ->
|
89
|
+
assertThat(assertThrows(ConfigException.class, client::get).getMessage(), is(message)),
|
90
|
+
builder);
|
91
|
+
}
|
92
|
+
|
93
|
+
private void runWithMockClient(Consumer<Lazy<KintoneClient>> consumer) {
|
94
|
+
runWithMockClient(consumer, builder());
|
95
|
+
}
|
96
|
+
|
97
|
+
private void runWithMockClient(Consumer<Lazy<KintoneClient>> consumer, Schema.Builder builder) {
|
98
|
+
MockClient mockClient =
|
99
|
+
new MockClient(
|
100
|
+
config.get(String.class, "domain"),
|
101
|
+
Collections.emptyList(),
|
102
|
+
Collections.emptyList(),
|
103
|
+
"");
|
104
|
+
try (Lazy<KintoneClient> client = KintoneClient.lazy(this::task, schema(builder))) {
|
105
|
+
mockClient.run(() -> consumer.accept(client));
|
106
|
+
} catch (Exception e) {
|
107
|
+
throw new RuntimeException(e);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
private void merge(ConfigSource config) {
|
112
|
+
this.config.merge(config);
|
113
|
+
}
|
114
|
+
|
115
|
+
private PluginTask task() {
|
116
|
+
return config.loadConfig(PluginTask.class);
|
117
|
+
}
|
118
|
+
|
119
|
+
private static Schema schema(Schema.Builder builder) {
|
120
|
+
return builder
|
121
|
+
.add("non_existing_field", Types.LONG)
|
122
|
+
.add("invalid_type_field_multi_line_text", Types.STRING)
|
123
|
+
.add("long_number", Types.LONG)
|
124
|
+
.add("string_single_line_text", Types.STRING)
|
125
|
+
.build();
|
126
|
+
}
|
127
|
+
|
128
|
+
private static Schema.Builder id(Type type) {
|
129
|
+
return builder().add("$id", type);
|
130
|
+
}
|
131
|
+
|
132
|
+
private static Schema.Builder builder() {
|
133
|
+
return Schema.builder();
|
134
|
+
}
|
135
|
+
|
136
|
+
private interface Consumer<T> {
|
137
|
+
void accept(T t) throws Exception;
|
138
|
+
}
|
139
|
+
}
|