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.
- checksums.yaml +4 -4
- data/README.md +63 -5
- 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-0.4.1-all.jar → shadow-kintone-java-client-1.1.0-all.jar} +0 -0
- data/src/main/java/org/embulk/output/kintone/KintoneColumnOption.java +6 -2
- data/src/main/java/org/embulk/output/kintone/KintoneColumnType.java +572 -0
- data/src/main/java/org/embulk/output/kintone/KintoneColumnVisitor.java +214 -135
- data/src/main/java/org/embulk/output/kintone/KintoneMode.java +0 -1
- data/src/main/java/org/embulk/output/kintone/KintoneOutputPlugin.java +12 -5
- data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +180 -160
- data/src/main/java/org/embulk/output/kintone/KintoneSortColumn.java +33 -0
- data/src/main/java/org/embulk/output/kintone/PluginTask.java +35 -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 +9 -3
- data/src/test/java/org/embulk/output/kintone/KintoneColumnTypeTest.java +194 -0
- data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorTest.java +703 -61
- data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorVerifier.java +45 -14
- data/src/test/java/org/embulk/output/kintone/KintonePageOutputVerifier.java +43 -5
- data/src/test/java/org/embulk/output/kintone/TestKintoneOutputPlugin.java +106 -16
- data/src/test/java/org/embulk/output/kintone/TestTaskMode.java +12 -0
- 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 +110 -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 +6 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_prefer_nulls_records.jsonl +6 -0
- 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 +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_prefer_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_records.jsonl +6 -3
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_ignore_nulls_records.jsonl +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_prefer_nulls_records.jsonl +3 -0
- 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 +3 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_prefer_nulls_records.jsonl +3 -0
- 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/mode/values_ignore_nulls.json +1 -0
- data/src/test/resources/org/embulk/output/kintone/task/mode/values_prefer_nulls.json +1 -0
- 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 +73 -4
- data/classpath/embulk-output-kintone-0.4.1.jar +0 -0
@@ -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
|
+
}
|
@@ -0,0 +1,190 @@
|
|
1
|
+
package org.embulk.output.kintone.reducer;
|
2
|
+
|
3
|
+
import java.time.Instant;
|
4
|
+
import java.util.ArrayList;
|
5
|
+
import java.util.Comparator;
|
6
|
+
import java.util.List;
|
7
|
+
import java.util.Map;
|
8
|
+
import java.util.function.Supplier;
|
9
|
+
import org.embulk.output.kintone.KintoneColumnOption;
|
10
|
+
import org.embulk.output.kintone.KintoneColumnType;
|
11
|
+
import org.embulk.output.kintone.KintoneSortColumn;
|
12
|
+
import org.embulk.spi.Column;
|
13
|
+
import org.embulk.spi.time.Timestamp;
|
14
|
+
import org.msgpack.value.ArrayValue;
|
15
|
+
import org.msgpack.value.MapValue;
|
16
|
+
import org.msgpack.value.Value;
|
17
|
+
import org.msgpack.value.ValueFactory;
|
18
|
+
|
19
|
+
public enum ReduceType {
|
20
|
+
BOOLEAN {
|
21
|
+
@Override
|
22
|
+
public MapValue value(String value, KintoneColumnOption option) {
|
23
|
+
KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.NUMBER);
|
24
|
+
Supplier<Value> supplier =
|
25
|
+
() -> type.asValue(type.getFieldValue(Boolean.parseBoolean(value), option));
|
26
|
+
return value(type, value, supplier);
|
27
|
+
}
|
28
|
+
|
29
|
+
@Override
|
30
|
+
public Comparator<String> comparator(KintoneSortColumn.Order order) {
|
31
|
+
return Comparator.comparing(Boolean::parseBoolean, order(order));
|
32
|
+
}
|
33
|
+
},
|
34
|
+
LONG {
|
35
|
+
@Override
|
36
|
+
public MapValue value(String value, KintoneColumnOption option) {
|
37
|
+
KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.NUMBER);
|
38
|
+
Supplier<Value> supplier =
|
39
|
+
() -> type.asValue(type.getFieldValue(Long.parseLong(value), option));
|
40
|
+
return value(type, value, supplier);
|
41
|
+
}
|
42
|
+
|
43
|
+
@Override
|
44
|
+
public Comparator<String> comparator(KintoneSortColumn.Order order) {
|
45
|
+
return Comparator.comparing(Long::parseLong, order(order));
|
46
|
+
}
|
47
|
+
},
|
48
|
+
DOUBLE {
|
49
|
+
@Override
|
50
|
+
public MapValue value(String value, KintoneColumnOption option) {
|
51
|
+
KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.NUMBER);
|
52
|
+
Supplier<Value> supplier =
|
53
|
+
() -> type.asValue(type.getFieldValue(Double.parseDouble(value), option));
|
54
|
+
return value(type, value, supplier);
|
55
|
+
}
|
56
|
+
|
57
|
+
@Override
|
58
|
+
public Comparator<String> comparator(KintoneSortColumn.Order order) {
|
59
|
+
return Comparator.comparing(Double::parseDouble, order(order));
|
60
|
+
}
|
61
|
+
},
|
62
|
+
STRING {
|
63
|
+
@Override
|
64
|
+
public MapValue value(String value, KintoneColumnOption option) {
|
65
|
+
KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.MULTI_LINE_TEXT);
|
66
|
+
Supplier<Value> supplier = () -> type.asValue(type.getFieldValue(value, option));
|
67
|
+
return value(type, value, supplier);
|
68
|
+
}
|
69
|
+
|
70
|
+
@Override
|
71
|
+
public Comparator<String> comparator(KintoneSortColumn.Order order) {
|
72
|
+
return order(order);
|
73
|
+
}
|
74
|
+
},
|
75
|
+
TIMESTAMP {
|
76
|
+
@Override
|
77
|
+
public MapValue value(String value, KintoneColumnOption option) {
|
78
|
+
KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.DATETIME);
|
79
|
+
Supplier<Value> supplier =
|
80
|
+
() -> type.asValue(type.getFieldValue(Timestamp.ofInstant(Instant.parse(value)), option));
|
81
|
+
return value(type, value, supplier);
|
82
|
+
}
|
83
|
+
|
84
|
+
@Override
|
85
|
+
public Comparator<String> comparator(KintoneSortColumn.Order order) {
|
86
|
+
return Comparator.comparing(Instant::parse, order(order));
|
87
|
+
}
|
88
|
+
},
|
89
|
+
JSON {
|
90
|
+
@Override
|
91
|
+
public MapValue value(String value, KintoneColumnOption option) {
|
92
|
+
KintoneColumnType type = KintoneColumnType.getType(option, KintoneColumnType.MULTI_LINE_TEXT);
|
93
|
+
Supplier<Value> supplier =
|
94
|
+
() -> type.asValue(type.getFieldValue(Reducer.PARSER.parse(value), option));
|
95
|
+
return value(type, value, supplier);
|
96
|
+
}
|
97
|
+
|
98
|
+
@Override
|
99
|
+
public Comparator<String> comparator(KintoneSortColumn.Order order) {
|
100
|
+
return order(order);
|
101
|
+
}
|
102
|
+
};
|
103
|
+
private static final Value NIL = ValueFactory.newNil();
|
104
|
+
private static final Value ID = ValueFactory.newString("id");
|
105
|
+
private static final Value TYPE = ValueFactory.newString("type");
|
106
|
+
private static final Value VALUE = ValueFactory.newString("value");
|
107
|
+
private static final Value KEY_SET = ValueFactory.newString("$$key_set");
|
108
|
+
private static final Value SORT_VALUE = ValueFactory.newString("$$sort_value");
|
109
|
+
|
110
|
+
public abstract MapValue value(String value, KintoneColumnOption option);
|
111
|
+
|
112
|
+
public abstract Comparator<String> comparator(KintoneSortColumn.Order order);
|
113
|
+
|
114
|
+
public static Comparator<String> comparator(Column column, KintoneSortColumn.Order order) {
|
115
|
+
return valueOf(column).comparator(order);
|
116
|
+
}
|
117
|
+
|
118
|
+
public static String asString(Value value, KintoneSortColumn sortColumn) {
|
119
|
+
return asString(sortValue(value).map().get(value(sortColumn.getName())));
|
120
|
+
}
|
121
|
+
|
122
|
+
public static boolean isEmpty(MapValue value) {
|
123
|
+
return value.values().stream()
|
124
|
+
.map(Value::asMapValue)
|
125
|
+
.map(MapValue::map)
|
126
|
+
.map(map -> map.get(VALUE))
|
127
|
+
.allMatch(Value::isNilValue);
|
128
|
+
}
|
129
|
+
|
130
|
+
public static Value value(String value) {
|
131
|
+
return value == null ? NIL : ValueFactory.newString(value);
|
132
|
+
}
|
133
|
+
|
134
|
+
public static MapValue value(Value value) {
|
135
|
+
ValueFactory.MapBuilder builder = ValueFactory.newMapBuilder();
|
136
|
+
Map<Value, Value> map = value.asMapValue().map();
|
137
|
+
builder.put(ID, map.get(ID));
|
138
|
+
builder.put(VALUE, value(map.get(VALUE).asMapValue().map(), map.get(KEY_SET).asArrayValue()));
|
139
|
+
return builder.build();
|
140
|
+
}
|
141
|
+
|
142
|
+
public static MapValue value(Long id, MapValue value, MapValue sortValue) {
|
143
|
+
ValueFactory.MapBuilder builder = ValueFactory.newMapBuilder();
|
144
|
+
builder.put(ID, id == null ? NIL : ValueFactory.newString(id.toString()));
|
145
|
+
builder.put(VALUE, value == null ? ValueFactory.emptyMap() : value);
|
146
|
+
builder.put(KEY_SET, value == null ? ValueFactory.emptyArray() : keySet(value));
|
147
|
+
builder.put(SORT_VALUE, sortValue == null ? ValueFactory.emptyMap() : sortValue);
|
148
|
+
return builder.build();
|
149
|
+
}
|
150
|
+
|
151
|
+
public static MapValue value(Column column, List<String> values, KintoneColumnOption option) {
|
152
|
+
return valueOf(column).value(values.get(column.getIndex()), option);
|
153
|
+
}
|
154
|
+
|
155
|
+
protected static MapValue value(KintoneColumnType type, String value, Supplier<Value> supplier) {
|
156
|
+
ValueFactory.MapBuilder builder = ValueFactory.newMapBuilder();
|
157
|
+
builder.put(TYPE, value(type.name()));
|
158
|
+
builder.put(VALUE, value == null ? NIL : supplier.get());
|
159
|
+
return builder.build();
|
160
|
+
}
|
161
|
+
|
162
|
+
private static <T extends Comparable<? super T>> Comparator<T> order(
|
163
|
+
KintoneSortColumn.Order order) {
|
164
|
+
return order == KintoneSortColumn.Order.DESC
|
165
|
+
? Comparator.reverseOrder()
|
166
|
+
: Comparator.naturalOrder();
|
167
|
+
}
|
168
|
+
|
169
|
+
private static String asString(Value value) {
|
170
|
+
return value.isNilValue() ? null : value.asStringValue().asString();
|
171
|
+
}
|
172
|
+
|
173
|
+
private static MapValue sortValue(Value value) {
|
174
|
+
return value.asMapValue().map().get(SORT_VALUE).asMapValue();
|
175
|
+
}
|
176
|
+
|
177
|
+
private static MapValue value(Map<Value, Value> map, ArrayValue keySet) {
|
178
|
+
ValueFactory.MapBuilder builder = ValueFactory.newMapBuilder();
|
179
|
+
keySet.forEach(key -> builder.put(key, map.get(key)));
|
180
|
+
return builder.build();
|
181
|
+
}
|
182
|
+
|
183
|
+
private static ArrayValue keySet(MapValue value) {
|
184
|
+
return ValueFactory.newArray(new ArrayList<>(value.asMapValue().keySet()));
|
185
|
+
}
|
186
|
+
|
187
|
+
private static ReduceType valueOf(Column column) {
|
188
|
+
return valueOf(column.getType().getName().toUpperCase());
|
189
|
+
}
|
190
|
+
}
|