embulk-output-kintone 0.4.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +63 -5
  3. data/build.gradle +1 -0
  4. data/classpath/commons-csv-1.9.0.jar +0 -0
  5. data/classpath/embulk-output-kintone-1.1.0.jar +0 -0
  6. data/classpath/externalsortinginjava-0.6.2.jar +0 -0
  7. data/classpath/{shadow-kintone-java-client-0.4.1-all.jar → shadow-kintone-java-client-1.1.0-all.jar} +0 -0
  8. data/src/main/java/org/embulk/output/kintone/KintoneColumnOption.java +6 -2
  9. data/src/main/java/org/embulk/output/kintone/KintoneColumnType.java +572 -0
  10. data/src/main/java/org/embulk/output/kintone/KintoneColumnVisitor.java +214 -135
  11. data/src/main/java/org/embulk/output/kintone/KintoneMode.java +0 -1
  12. data/src/main/java/org/embulk/output/kintone/KintoneOutputPlugin.java +12 -5
  13. data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +180 -160
  14. data/src/main/java/org/embulk/output/kintone/KintoneSortColumn.java +33 -0
  15. data/src/main/java/org/embulk/output/kintone/PluginTask.java +35 -0
  16. data/src/main/java/org/embulk/output/kintone/deserializer/DeserializeApplier.java +19 -0
  17. data/src/main/java/org/embulk/output/kintone/deserializer/DeserializeException.java +7 -0
  18. data/src/main/java/org/embulk/output/kintone/deserializer/Deserializer.java +279 -0
  19. data/src/main/java/org/embulk/output/kintone/reducer/CSVInputColumnVisitor.java +78 -0
  20. data/src/main/java/org/embulk/output/kintone/reducer/CSVOutputColumnVisitor.java +79 -0
  21. data/src/main/java/org/embulk/output/kintone/reducer/ReduceException.java +11 -0
  22. data/src/main/java/org/embulk/output/kintone/reducer/ReduceType.java +190 -0
  23. data/src/main/java/org/embulk/output/kintone/reducer/ReducedPageOutput.java +100 -0
  24. data/src/main/java/org/embulk/output/kintone/reducer/Reducer.java +355 -0
  25. data/src/test/java/org/embulk/output/kintone/KintoneColumnOptionBuilder.java +9 -3
  26. data/src/test/java/org/embulk/output/kintone/KintoneColumnTypeTest.java +194 -0
  27. data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorTest.java +703 -61
  28. data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorVerifier.java +45 -14
  29. data/src/test/java/org/embulk/output/kintone/KintonePageOutputVerifier.java +43 -5
  30. data/src/test/java/org/embulk/output/kintone/TestKintoneOutputPlugin.java +106 -16
  31. data/src/test/java/org/embulk/output/kintone/TestTaskMode.java +12 -0
  32. data/src/test/java/org/embulk/output/kintone/TestTaskReduce.java +46 -0
  33. data/src/test/java/org/embulk/output/kintone/TestTaskReduceException.java +50 -0
  34. data/src/test/java/org/embulk/output/kintone/TestTaskReduceSubtable.java +46 -0
  35. data/src/test/java/org/embulk/output/kintone/deserializer/DeserializerTest.java +165 -0
  36. data/src/test/java/org/embulk/output/kintone/reducer/ReduceTypeTest.java +154 -0
  37. data/src/test/resources/org/embulk/output/kintone/task/config.yml +1 -1
  38. data/src/test/resources/org/embulk/output/kintone/task/mode/config.yml +110 -0
  39. data/src/test/resources/org/embulk/output/kintone/task/mode/input.csv +7 -7
  40. data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_ignore_nulls_records.jsonl +6 -0
  41. data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_prefer_nulls_records.jsonl +6 -0
  42. data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_records.jsonl +6 -6
  43. data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_ignore_nulls_records.jsonl +3 -0
  44. data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_prefer_nulls_records.jsonl +3 -0
  45. data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_records.jsonl +6 -3
  46. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_ignore_nulls_records.jsonl +3 -0
  47. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_prefer_nulls_records.jsonl +3 -0
  48. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_records.jsonl +2 -2
  49. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_ignore_nulls_records.jsonl +3 -0
  50. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_prefer_nulls_records.jsonl +3 -0
  51. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_records.jsonl +4 -4
  52. data/src/test/resources/org/embulk/output/kintone/task/mode/values_ignore_nulls.json +1 -0
  53. data/src/test/resources/org/embulk/output/kintone/task/mode/values_prefer_nulls.json +1 -0
  54. data/src/test/resources/org/embulk/output/kintone/task/reduce/config.yml +171 -0
  55. data/src/test/resources/org/embulk/output/kintone/task/reduce/input.csv +7 -0
  56. data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_ignore_nulls_records.jsonl +6 -0
  57. data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_prefer_nulls_records.jsonl +6 -0
  58. data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_records.jsonl +6 -0
  59. data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_ignore_nulls_records.jsonl +3 -0
  60. data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_prefer_nulls_records.jsonl +3 -0
  61. data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_records.jsonl +6 -0
  62. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_add_ignore_nulls_records.jsonl +3 -0
  63. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_add_prefer_nulls_records.jsonl +3 -0
  64. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_add_records.jsonl +2 -0
  65. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_update_ignore_nulls_records.jsonl +3 -0
  66. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_update_prefer_nulls_records.jsonl +3 -0
  67. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_update_records.jsonl +4 -0
  68. data/src/test/resources/org/embulk/output/kintone/task/reduce/values.json +1 -0
  69. data/src/test/resources/org/embulk/output/kintone/task/reduce/values_ignore_nulls.json +1 -0
  70. data/src/test/resources/org/embulk/output/kintone/task/reduce/values_prefer_nulls.json +1 -0
  71. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/config.yml +36 -0
  72. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/derived_columns.json +1 -0
  73. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/input.csv +13 -0
  74. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/insert_add_records.jsonl +2 -0
  75. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/update_update_records.jsonl +2 -0
  76. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/config.yml +343 -0
  77. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/derived_columns.json +1 -0
  78. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/input.csv +13 -0
  79. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_ignore_nulls_records.jsonl +6 -0
  80. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_prefer_nulls_records.jsonl +6 -0
  81. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_records.jsonl +6 -0
  82. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_ignore_nulls_records.jsonl +3 -0
  83. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_prefer_nulls_records.jsonl +3 -0
  84. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_records.jsonl +6 -0
  85. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_add_ignore_nulls_records.jsonl +3 -0
  86. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_add_prefer_nulls_records.jsonl +3 -0
  87. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_add_records.jsonl +0 -0
  88. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_update_ignore_nulls_records.jsonl +3 -0
  89. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_update_prefer_nulls_records.jsonl +3 -0
  90. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_update_records.jsonl +6 -0
  91. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/values.json +1 -0
  92. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/values_ignore_nulls.json +1 -0
  93. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/values_prefer_nulls.json +1 -0
  94. metadata +73 -4
  95. data/classpath/embulk-output-kintone-0.4.1.jar +0 -0
@@ -1,47 +1,53 @@
1
1
  package org.embulk.output.kintone;
2
2
 
3
- import com.kintone.client.model.record.CheckBoxFieldValue;
4
- import com.kintone.client.model.record.DateFieldValue;
5
- import com.kintone.client.model.record.DateTimeFieldValue;
6
- import com.kintone.client.model.record.DropDownFieldValue;
7
- import com.kintone.client.model.record.FieldType;
8
3
  import com.kintone.client.model.record.FieldValue;
9
- import com.kintone.client.model.record.LinkFieldValue;
10
- import com.kintone.client.model.record.MultiLineTextFieldValue;
11
- import com.kintone.client.model.record.NumberFieldValue;
12
4
  import com.kintone.client.model.record.Record;
13
- import com.kintone.client.model.record.SingleLineTextFieldValue;
14
5
  import com.kintone.client.model.record.UpdateKey;
15
- import java.math.BigDecimal;
16
6
  import java.time.Instant;
17
- import java.time.ZoneId;
18
- import java.time.ZonedDateTime;
19
- import java.util.Arrays;
20
- import java.util.List;
21
7
  import java.util.Map;
22
- import java.util.Objects;
8
+ import java.util.Set;
23
9
  import org.embulk.spi.Column;
24
10
  import org.embulk.spi.ColumnVisitor;
25
11
  import org.embulk.spi.PageReader;
26
12
  import org.embulk.spi.time.Timestamp;
13
+ import org.msgpack.value.Value;
14
+ import org.msgpack.value.ValueFactory;
27
15
 
28
16
  public class KintoneColumnVisitor implements ColumnVisitor {
29
- private final PageReader pageReader;
17
+ private final PageReader reader;
18
+ private final Set<Column> derived;
19
+ private final Map<String, KintoneColumnOption> options;
20
+ private final boolean preferNulls;
21
+ private final boolean ignoreNulls;
22
+ private final String reduceKeyName;
23
+ private final String updateKeyName;
30
24
  private Record record;
31
25
  private UpdateKey updateKey;
32
- private final Map<String, KintoneColumnOption> columnOptions;
33
- private String updateKeyName;
34
26
 
35
27
  public KintoneColumnVisitor(
36
- PageReader pageReader, Map<String, KintoneColumnOption> columnOptions) {
37
- this.pageReader = pageReader;
38
- this.columnOptions = columnOptions;
28
+ PageReader reader,
29
+ Set<Column> derived,
30
+ Map<String, KintoneColumnOption> options,
31
+ boolean preferNulls,
32
+ boolean ignoreNulls,
33
+ String reduceKeyName) {
34
+ this(reader, derived, options, preferNulls, ignoreNulls, reduceKeyName, null);
39
35
  }
40
36
 
41
37
  public KintoneColumnVisitor(
42
- PageReader pageReader, Map<String, KintoneColumnOption> columnOptions, String updateKeyName) {
43
- this.pageReader = pageReader;
44
- this.columnOptions = columnOptions;
38
+ PageReader reader,
39
+ Set<Column> derived,
40
+ Map<String, KintoneColumnOption> options,
41
+ boolean preferNulls,
42
+ boolean ignoreNulls,
43
+ String reduceKeyName,
44
+ String updateKeyName) {
45
+ this.reader = reader;
46
+ this.derived = derived;
47
+ this.options = options;
48
+ this.preferNulls = preferNulls;
49
+ this.ignoreNulls = ignoreNulls;
50
+ this.reduceKeyName = reduceKeyName;
45
51
  this.updateKeyName = updateKeyName;
46
52
  }
47
53
 
@@ -53,156 +59,229 @@ public class KintoneColumnVisitor implements ColumnVisitor {
53
59
  this.updateKey = updateKey;
54
60
  }
55
61
 
56
- private void setValue(String fieldCode, Object value, FieldType type, boolean isUpdateKey) {
57
- if (isUpdateKey && updateKey != null) {
58
- updateKey.setField(fieldCode).setValue(Objects.toString(value, ""));
59
- }
60
- String stringValue = Objects.toString(value, "");
61
- FieldValue fieldValue;
62
- switch (type) {
63
- case NUMBER:
64
- BigDecimal setValue = stringValue.equals("") ? null : new BigDecimal(stringValue);
65
- fieldValue = new NumberFieldValue(setValue);
66
- break;
67
- case MULTI_LINE_TEXT:
68
- fieldValue = new MultiLineTextFieldValue(stringValue);
69
- break;
70
- case DROP_DOWN:
71
- fieldValue = new DropDownFieldValue(stringValue);
72
- break;
73
- case LINK:
74
- fieldValue = new LinkFieldValue(stringValue);
75
- break;
76
- default:
77
- fieldValue = new SingleLineTextFieldValue(stringValue);
62
+ @Override
63
+ public void booleanColumn(Column column) {
64
+ if (isReduced(column) || isIgnoreNull(column)) {
65
+ return;
66
+ }
67
+ KintoneColumnOption option = getOption(column);
68
+ UpdateKey updateKey = getUpdateKey(column);
69
+ KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.NUMBER);
70
+ String fieldCode = getFieldCode(column);
71
+ if (isPreferNull(column)) {
72
+ setNull(type, fieldCode, updateKey);
73
+ } else if (reader.isNull(column)) {
74
+ setBoolean(type, fieldCode, updateKey, false, option);
75
+ } else {
76
+ setBoolean(type, fieldCode, updateKey, reader.getBoolean(column), option);
78
77
  }
79
- record.putField(fieldCode, fieldValue);
80
78
  }
81
79
 
82
- private void setTimestampValue(String fieldCode, Instant instant, ZoneId zoneId, FieldType type) {
83
- FieldValue fieldValue = null;
84
- ZonedDateTime datetime = instant.atZone(zoneId);
85
- switch (type) {
86
- case DATE:
87
- fieldValue = new DateFieldValue(datetime.toLocalDate());
88
- break;
89
- case DATETIME:
90
- fieldValue = new DateTimeFieldValue(datetime);
80
+ @Override
81
+ public void longColumn(Column column) {
82
+ if (isReduced(column) || isIgnoreNull(column)) {
83
+ return;
84
+ }
85
+ KintoneColumnOption option = getOption(column);
86
+ UpdateKey updateKey = getUpdateKey(column);
87
+ KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.NUMBER);
88
+ String fieldCode = getFieldCode(column);
89
+ if (isPreferNull(column)) {
90
+ setNull(type, fieldCode, updateKey);
91
+ } else if (reader.isNull(column)) {
92
+ setLong(type, fieldCode, updateKey, 0, option);
93
+ } else {
94
+ setLong(type, fieldCode, updateKey, reader.getLong(column), option);
91
95
  }
92
- record.putField(fieldCode, fieldValue);
93
96
  }
94
97
 
95
- private void setCheckBoxValue(String fieldCode, Object value, String valueSeparator) {
96
- String str = String.valueOf(value);
97
- CheckBoxFieldValue checkBoxFieldValue = new CheckBoxFieldValue();
98
-
99
- if (str != null && !str.equals("")) {
100
- List<String> values = Arrays.asList(str.split(valueSeparator, 0));
101
- checkBoxFieldValue = new CheckBoxFieldValue(values);
98
+ @Override
99
+ public void doubleColumn(Column column) {
100
+ if (isReduced(column) || isIgnoreNull(column)) {
101
+ return;
102
+ }
103
+ KintoneColumnOption option = getOption(column);
104
+ UpdateKey updateKey = getUpdateKey(column);
105
+ KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.NUMBER);
106
+ String fieldCode = getFieldCode(column);
107
+ if (isPreferNull(column)) {
108
+ setNull(type, fieldCode, updateKey);
109
+ } else if (reader.isNull(column)) {
110
+ setDouble(type, fieldCode, updateKey, 0, option);
111
+ } else {
112
+ setDouble(type, fieldCode, updateKey, reader.getDouble(column), option);
102
113
  }
103
- record.putField(fieldCode, checkBoxFieldValue);
104
114
  }
105
115
 
106
- private FieldType getType(Column column, FieldType defaultType) {
107
- KintoneColumnOption option = columnOptions.get(column.getName());
108
- if (option == null) {
109
- return defaultType;
116
+ @Override
117
+ public void stringColumn(Column column) {
118
+ if (isReduced(column) || isIgnoreNull(column)) {
119
+ return;
120
+ }
121
+ KintoneColumnOption option = getOption(column);
122
+ UpdateKey updateKey = getUpdateKey(column);
123
+ KintoneColumnType defaultType =
124
+ updateKey != null ? KintoneColumnType.SINGLE_LINE_TEXT : KintoneColumnType.MULTI_LINE_TEXT;
125
+ KintoneColumnType type = KintoneColumnType.getType(option, defaultType);
126
+ String fieldCode = getFieldCode(column);
127
+ if (isPreferNull(column)) {
128
+ setNull(type, fieldCode, updateKey);
129
+ } else if (reader.isNull(column)) {
130
+ setString(type, fieldCode, updateKey, "", option);
110
131
  } else {
111
- return FieldType.valueOf(option.getType());
132
+ setString(type, fieldCode, updateKey, reader.getString(column), option);
112
133
  }
113
134
  }
114
135
 
115
- private String getFieldCode(Column column) {
116
- KintoneColumnOption option = columnOptions.get(column.getName());
117
- if (option == null) {
118
- return column.getName();
136
+ @Override
137
+ public void timestampColumn(Column column) {
138
+ if (isReduced(column) || isIgnoreNull(column)) {
139
+ return;
140
+ }
141
+ KintoneColumnOption option = getOption(column);
142
+ UpdateKey updateKey = getUpdateKey(column);
143
+ KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.DATETIME);
144
+ String fieldCode = getFieldCode(column);
145
+ if (isPreferNull(column)) {
146
+ setNull(type, fieldCode, updateKey);
147
+ } else if (reader.isNull(column)) {
148
+ setTimestamp(type, fieldCode, updateKey, Timestamp.ofInstant(Instant.EPOCH), option);
119
149
  } else {
120
- return option.getFieldCode();
150
+ setTimestamp(type, fieldCode, updateKey, reader.getTimestamp(column), option);
121
151
  }
122
152
  }
123
153
 
124
- private ZoneId getZoneId(Column column) {
125
- KintoneColumnOption option = columnOptions.get(column.getName());
126
- if (option == null) {
127
- return ZoneId.of("UTC");
154
+ @Override
155
+ public void jsonColumn(Column column) {
156
+ if (isReduced(column) || isIgnoreNull(column)) {
157
+ return;
158
+ }
159
+ KintoneColumnOption option = getOption(column);
160
+ UpdateKey updateKey = getUpdateKey(column);
161
+ KintoneColumnType defaultType =
162
+ isDerived(column) ? KintoneColumnType.SUBTABLE : KintoneColumnType.MULTI_LINE_TEXT;
163
+ KintoneColumnType type = KintoneColumnType.getType(option, defaultType);
164
+ String fieldCode = getFieldCode(column);
165
+ if (isPreferNull(column)) {
166
+ setNull(type, fieldCode, updateKey);
167
+ } else if (reader.isNull(column)) {
168
+ setJson(type, fieldCode, updateKey, ValueFactory.newString(""), option);
169
+ } else {
170
+ setJson(type, fieldCode, updateKey, reader.getJson(column), option);
128
171
  }
129
- return ZoneId.of(option.getTimezone().orElse("UTC"));
130
172
  }
131
173
 
132
- private boolean isUpdateKey(Column column) {
133
- if (this.updateKeyName == null) {
134
- return false;
174
+ private void setNull(KintoneColumnType type, String fieldCode, UpdateKey updateKey) {
175
+ if (updateKey != null) {
176
+ type.setUpdateKey(updateKey, fieldCode);
135
177
  }
136
-
137
- return this.updateKeyName.equals(column.getName());
178
+ record.putField(fieldCode, type.getFieldValue());
138
179
  }
139
180
 
140
- private String getValueSeparator(Column column) {
141
- KintoneColumnOption option = columnOptions.get(column.getName());
142
- if (option == null) {
143
- return ",";
181
+ private void setBoolean(
182
+ KintoneColumnType type,
183
+ String fieldCode,
184
+ UpdateKey updateKey,
185
+ boolean value,
186
+ KintoneColumnOption option) {
187
+ FieldValue fieldValue = type.getFieldValue(value, option);
188
+ if (updateKey != null) {
189
+ type.setUpdateKey(updateKey, fieldCode, fieldValue);
144
190
  }
145
- return option.getValueSeparator();
191
+ record.putField(fieldCode, fieldValue);
146
192
  }
147
193
 
148
- @Override
149
- public void booleanColumn(Column column) {
150
- String fieldCode = getFieldCode(column);
151
- FieldType type = getType(column, FieldType.NUMBER);
152
- setValue(fieldCode, pageReader.getBoolean(column), type, isUpdateKey(column));
194
+ private void setLong(
195
+ KintoneColumnType type,
196
+ String fieldCode,
197
+ UpdateKey updateKey,
198
+ long value,
199
+ KintoneColumnOption option) {
200
+ FieldValue fieldValue = type.getFieldValue(value, option);
201
+ if (updateKey != null) {
202
+ type.setUpdateKey(updateKey, fieldCode, fieldValue);
203
+ }
204
+ record.putField(fieldCode, fieldValue);
153
205
  }
154
206
 
155
- @Override
156
- public void longColumn(Column column) {
157
- String fieldCode = getFieldCode(column);
158
- FieldType type = getType(column, FieldType.NUMBER);
159
- if (pageReader.isNull(column)) {
160
- setValue(fieldCode, null, type, isUpdateKey(column));
161
- } else {
162
- setValue(fieldCode, pageReader.getLong(column), type, isUpdateKey(column));
207
+ private void setDouble(
208
+ KintoneColumnType type,
209
+ String fieldCode,
210
+ UpdateKey updateKey,
211
+ double value,
212
+ KintoneColumnOption option) {
213
+ FieldValue fieldValue = type.getFieldValue(value, option);
214
+ if (updateKey != null) {
215
+ type.setUpdateKey(updateKey, fieldCode, fieldValue);
163
216
  }
217
+ record.putField(fieldCode, fieldValue);
164
218
  }
165
219
 
166
- @Override
167
- public void doubleColumn(Column column) {
168
- String fieldCode = getFieldCode(column);
169
- FieldType type = getType(column, FieldType.NUMBER);
170
- setValue(fieldCode, pageReader.getDouble(column), type, isUpdateKey(column));
220
+ private void setString(
221
+ KintoneColumnType type,
222
+ String fieldCode,
223
+ UpdateKey updateKey,
224
+ String value,
225
+ KintoneColumnOption option) {
226
+ FieldValue fieldValue = type.getFieldValue(value, option);
227
+ if (updateKey != null) {
228
+ type.setUpdateKey(updateKey, fieldCode, fieldValue);
229
+ }
230
+ record.putField(fieldCode, fieldValue);
171
231
  }
172
232
 
173
- @Override
174
- public void stringColumn(Column column) {
175
- String fieldCode = getFieldCode(column);
176
- FieldType type = getType(column, FieldType.MULTI_LINE_TEXT);
177
- Object value = pageReader.getString(column);
178
- if (type == FieldType.CHECK_BOX) {
179
- String stringValue = Objects.toString(value, "");
180
- setCheckBoxValue(fieldCode, value, getValueSeparator(column));
181
- return;
233
+ private void setTimestamp(
234
+ KintoneColumnType type,
235
+ String fieldCode,
236
+ UpdateKey updateKey,
237
+ Timestamp value,
238
+ KintoneColumnOption option) {
239
+ FieldValue fieldValue = type.getFieldValue(value, option);
240
+ if (updateKey != null) {
241
+ type.setUpdateKey(updateKey, fieldCode, fieldValue);
182
242
  }
183
- setValue(fieldCode, value, type, isUpdateKey(column));
243
+ record.putField(fieldCode, fieldValue);
184
244
  }
185
245
 
186
- @Override
187
- public void timestampColumn(Column column) {
188
- Timestamp value = pageReader.getTimestamp(column);
189
- if (value == null) {
190
- return;
246
+ private void setJson(
247
+ KintoneColumnType type,
248
+ String fieldCode,
249
+ UpdateKey updateKey,
250
+ Value value,
251
+ KintoneColumnOption option) {
252
+ FieldValue fieldValue = type.getFieldValue(value, option);
253
+ if (updateKey != null) {
254
+ type.setUpdateKey(updateKey, fieldCode, fieldValue);
191
255
  }
256
+ record.putField(fieldCode, fieldValue);
257
+ }
192
258
 
193
- String fieldCode = getFieldCode(column);
194
- FieldType type = getType(column, FieldType.DATETIME);
195
- ZoneId zoneId = getZoneId(column);
196
- if (type == FieldType.DATETIME) {
197
- zoneId = ZoneId.of("UTC");
198
- }
199
- setTimestampValue(fieldCode, value.getInstant(), zoneId, type);
259
+ private String getFieldCode(Column column) {
260
+ KintoneColumnOption option = getOption(column);
261
+ return option != null ? option.getFieldCode() : column.getName();
200
262
  }
201
263
 
202
- @Override
203
- public void jsonColumn(Column column) {
204
- String fieldCode = getFieldCode(column);
205
- FieldType type = getType(column, FieldType.MULTI_LINE_TEXT);
206
- setValue(fieldCode, pageReader.getJson(column), type, isUpdateKey(column));
264
+ private KintoneColumnOption getOption(Column column) {
265
+ return options.get(column.getName());
266
+ }
267
+
268
+ private UpdateKey getUpdateKey(Column column) {
269
+ return updateKeyName != null && updateKeyName.equals(column.getName()) ? updateKey : null;
270
+ }
271
+
272
+ private boolean isReduced(Column column) {
273
+ return reduceKeyName != null && column.getName().matches("^.*\\..*$");
274
+ }
275
+
276
+ private boolean isDerived(Column column) {
277
+ return reduceKeyName != null && derived.contains(column);
278
+ }
279
+
280
+ private boolean isIgnoreNull(Column column) {
281
+ return ignoreNulls && reader.isNull(column);
282
+ }
283
+
284
+ private boolean isPreferNull(Column column) {
285
+ return preferNulls && reader.isNull(column);
207
286
  }
208
287
  }
@@ -6,7 +6,6 @@ public enum KintoneMode {
6
6
  INSERT("insert"),
7
7
  UPDATE("update"),
8
8
  UPSERT("upsert");
9
-
10
9
  private final String value;
11
10
 
12
11
  KintoneMode(String value) {
@@ -1,11 +1,14 @@
1
1
  package org.embulk.output.kintone;
2
2
 
3
+ import java.util.Collections;
3
4
  import java.util.List;
4
5
  import org.embulk.config.ConfigDiff;
5
6
  import org.embulk.config.ConfigException;
6
7
  import org.embulk.config.ConfigSource;
7
8
  import org.embulk.config.TaskReport;
8
9
  import org.embulk.config.TaskSource;
10
+ import org.embulk.output.kintone.reducer.ReducedPageOutput;
11
+ import org.embulk.output.kintone.reducer.Reducer;
9
12
  import org.embulk.spi.Exec;
10
13
  import org.embulk.spi.OutputPlugin;
11
14
  import org.embulk.spi.Schema;
@@ -16,9 +19,12 @@ public class KintoneOutputPlugin implements OutputPlugin {
16
19
  public ConfigDiff transaction(
17
20
  ConfigSource config, Schema schema, int taskCount, OutputPlugin.Control control) {
18
21
  PluginTask task = config.loadConfig(PluginTask.class);
19
-
20
- control.run(task.dump());
21
- return Exec.newConfigDiff();
22
+ task.setDerivedColumns(Collections.emptySet());
23
+ List<TaskReport> taskReports = control.run(task.dump());
24
+ return task.getReduceKeyName().isPresent()
25
+ ? new Reducer(task, schema)
26
+ .reduce(taskReports, schema.lookupColumn(task.getReduceKeyName().get()))
27
+ : Exec.newConfigDiff();
22
28
  }
23
29
 
24
30
  @Override
@@ -34,7 +40,6 @@ public class KintoneOutputPlugin implements OutputPlugin {
34
40
  @Override
35
41
  public TransactionalPageOutput open(TaskSource taskSource, Schema schema, int taskIndex) {
36
42
  PluginTask task = taskSource.loadTask(PluginTask.class);
37
-
38
43
  KintoneMode mode = KintoneMode.getKintoneModeByValue(task.getMode());
39
44
  switch (mode) {
40
45
  case INSERT:
@@ -51,6 +56,8 @@ public class KintoneOutputPlugin implements OutputPlugin {
51
56
  default:
52
57
  throw new ConfigException(String.format("Unknown mode '%s'", task.getMode()));
53
58
  }
54
- return new KintonePageOutput(task, schema);
59
+ return task.getReduceKeyName().isPresent()
60
+ ? new ReducedPageOutput(schema, taskIndex)
61
+ : new KintonePageOutput(task, schema);
55
62
  }
56
63
  }