embulk-output-kintone 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +52 -5
- data/README.md +3 -2
- data/build.gradle +1 -1
- data/classpath/{embulk-output-kintone-0.2.0.jar → embulk-output-kintone-0.3.0.jar} +0 -0
- data/src/main/java/org/embulk/output/kintone/KintoneColumnOption.java +0 -4
- data/src/main/java/org/embulk/output/kintone/KintoneColumnVisitor.java +39 -29
- data/src/main/java/org/embulk/output/kintone/KintoneOutputPlugin.java +6 -19
- data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +116 -123
- data/src/main/java/org/embulk/output/kintone/PluginTask.java +4 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2004bfc2e202eeb6c57f3149bc7311f90343a67e
|
|
4
|
+
data.tar.gz: 86e036bc863ac7d8ca632488d0eb84c645658c43
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 723f4b6b9e5341a7e0bef48c6de38528860985d46d9a139c2d3e133c59ab867c9a4507b0c98a431b5b654f332178f90038168bc0143d9d9dcb2916dfe1956e44
|
|
7
|
+
data.tar.gz: 84441877b034060e5876ae67d8afd1d01f15a91d1aab8a76065bd4549a85c7de1639b0557a814482edc8312bbc11cbcbdc0565fa87aedfb794493966064201b7
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -1,13 +1,60 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: main
|
|
2
2
|
|
|
3
|
-
on:
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- 'master'
|
|
7
|
+
tags:
|
|
8
|
+
- '*'
|
|
9
|
+
pull_request:
|
|
10
|
+
branches:
|
|
11
|
+
- 'master'
|
|
12
|
+
types: [opened, synchronize]
|
|
4
13
|
|
|
5
14
|
jobs:
|
|
6
|
-
|
|
15
|
+
main:
|
|
7
16
|
runs-on: ubuntu-latest
|
|
8
17
|
steps:
|
|
9
18
|
- uses: actions/checkout@v2
|
|
10
|
-
-
|
|
19
|
+
- name: Set Up
|
|
20
|
+
uses: actions/setup-java@v1
|
|
11
21
|
with:
|
|
12
22
|
java-version: 1.8
|
|
13
|
-
|
|
23
|
+
|
|
24
|
+
- name: Test
|
|
25
|
+
run: ./gradlew test
|
|
26
|
+
|
|
27
|
+
- name: Build Gem
|
|
28
|
+
run: ./gradlew gem
|
|
29
|
+
|
|
30
|
+
- name: Set up JRuby
|
|
31
|
+
uses: ruby/setup-ruby@v1
|
|
32
|
+
with:
|
|
33
|
+
ruby-version: jruby
|
|
34
|
+
|
|
35
|
+
- name: Publish to GPR
|
|
36
|
+
if: startsWith( github.ref, 'refs/tags/' )
|
|
37
|
+
run: |
|
|
38
|
+
mkdir -p $HOME/.gem
|
|
39
|
+
touch $HOME/.gem/credentials
|
|
40
|
+
chmod 0600 $HOME/.gem/credentials
|
|
41
|
+
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
42
|
+
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} ./pkg/*.gem
|
|
43
|
+
env:
|
|
44
|
+
GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
|
|
45
|
+
OWNER: ${{ github.repository_owner }}
|
|
46
|
+
|
|
47
|
+
- name: Publish to RubyGems
|
|
48
|
+
if: startsWith( github.ref, 'refs/tags/' )
|
|
49
|
+
run: |
|
|
50
|
+
mkdir -p $HOME/.gem
|
|
51
|
+
touch $HOME/.gem/credentials
|
|
52
|
+
chmod 0600 $HOME/.gem/credentials
|
|
53
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
54
|
+
# TODO: If it is possible to accept input in the middle of a step, then the OTP Token should be inputted instead of generated.
|
|
55
|
+
gem install rotp -v 6.2.0
|
|
56
|
+
OTP_TOKEN=$(echo ${OTP_SECRET} | ruby -rtime -rrotp -e "puts ROTP::TOTP.new(STDIN.read.chomp, issuer: 'rubygems.org').at(Time.now)")
|
|
57
|
+
gem push --otp="${OTP_TOKEN}" ./pkg/*.gem
|
|
58
|
+
env:
|
|
59
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_API_KEY}}"
|
|
60
|
+
OTP_SECRET: "${{secrets.RUBYGEMS_OTP_SECRET}}"
|
data/README.md
CHANGED
|
@@ -17,11 +17,11 @@ kintone output plugin for Embulk stores app records from kintone.
|
|
|
17
17
|
- **basic_auth_password**: kintone basic auth password (string, optional)
|
|
18
18
|
- **guest_space_id**: kintone app belongs to guest space, guest space id is required. (integer, optional)
|
|
19
19
|
- **mode**: kintone mode (string, required)
|
|
20
|
+
- **update_key**: column name to set update key (string, required if mode is update or upsert)
|
|
20
21
|
- **column_options** advanced: a key-value pairs where key is a column name and value is options for the column.
|
|
21
22
|
- **field_code**: field code (string, required)
|
|
22
23
|
- **type**: field type (string, required)
|
|
23
24
|
- **timezone**: timezone to convert into `date` (string, default is `UTC`)
|
|
24
|
-
- **update_key**: update key (boolean, default is `false`)
|
|
25
25
|
- **val_sep**: Used to specify multiple checkbox values (string, default is `,`)
|
|
26
26
|
|
|
27
27
|
## Example
|
|
@@ -33,7 +33,8 @@ out:
|
|
|
33
33
|
username: username
|
|
34
34
|
password: password
|
|
35
35
|
app_id: 1
|
|
36
|
-
mode:
|
|
36
|
+
mode: upsert
|
|
37
|
+
update_key: id
|
|
37
38
|
column_options:
|
|
38
39
|
id: {field_code: "id", type: "NUMBER"}
|
|
39
40
|
name: {field_code: "name", type: "SINGLE_LINE_TEXT"}
|
data/build.gradle
CHANGED
|
Binary file
|
|
@@ -19,10 +19,6 @@ public interface KintoneColumnOption
|
|
|
19
19
|
@ConfigDefault("\"UTC\"")
|
|
20
20
|
public Optional<String> getTimezone();
|
|
21
21
|
|
|
22
|
-
@Config("update_key")
|
|
23
|
-
@ConfigDefault("false")
|
|
24
|
-
public boolean getUpdateKey();
|
|
25
|
-
|
|
26
22
|
@Config("val_sep")
|
|
27
23
|
@ConfigDefault("\",\"")
|
|
28
24
|
public String getValueSeparator();
|
|
@@ -22,6 +22,7 @@ import java.time.Instant;
|
|
|
22
22
|
import java.time.ZoneId;
|
|
23
23
|
import java.time.ZonedDateTime;
|
|
24
24
|
import java.util.Map;
|
|
25
|
+
import java.util.Objects;
|
|
25
26
|
|
|
26
27
|
public class KintoneColumnVisitor
|
|
27
28
|
implements ColumnVisitor
|
|
@@ -30,6 +31,7 @@ public class KintoneColumnVisitor
|
|
|
30
31
|
private Record record;
|
|
31
32
|
private UpdateKey updateKey;
|
|
32
33
|
private Map<String, KintoneColumnOption> columnOptions;
|
|
34
|
+
private String updateKeyName;
|
|
33
35
|
|
|
34
36
|
public KintoneColumnVisitor(PageReader pageReader,
|
|
35
37
|
Map<String, KintoneColumnOption> columnOptions)
|
|
@@ -38,6 +40,15 @@ public class KintoneColumnVisitor
|
|
|
38
40
|
this.columnOptions = columnOptions;
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
public KintoneColumnVisitor(PageReader pageReader,
|
|
44
|
+
Map<String, KintoneColumnOption> columnOptions,
|
|
45
|
+
String updateKeyName)
|
|
46
|
+
{
|
|
47
|
+
this.pageReader = pageReader;
|
|
48
|
+
this.columnOptions = columnOptions;
|
|
49
|
+
this.updateKeyName = updateKeyName;
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
public void setRecord(Record record)
|
|
42
53
|
{
|
|
43
54
|
this.record = record;
|
|
@@ -50,36 +61,31 @@ public class KintoneColumnVisitor
|
|
|
50
61
|
|
|
51
62
|
private void setValue(String fieldCode, Object value, FieldType type, boolean isUpdateKey)
|
|
52
63
|
{
|
|
53
|
-
if (value == null) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
64
|
if (isUpdateKey && updateKey != null) {
|
|
58
65
|
updateKey
|
|
59
66
|
.setField(fieldCode)
|
|
60
|
-
.setValue(
|
|
67
|
+
.setValue(Objects.toString(value, ""));
|
|
61
68
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
record.putField(fieldCode, fieldValue);
|
|
69
|
+
String stringValue = Objects.toString(value, "");
|
|
70
|
+
FieldValue fieldValue;
|
|
71
|
+
switch (type) {
|
|
72
|
+
case NUMBER:
|
|
73
|
+
BigDecimal setValue = stringValue.equals("") ? null : new BigDecimal(stringValue);
|
|
74
|
+
fieldValue = new NumberFieldValue(setValue);
|
|
75
|
+
break;
|
|
76
|
+
case MULTI_LINE_TEXT:
|
|
77
|
+
fieldValue = new MultiLineTextFieldValue(stringValue);
|
|
78
|
+
break;
|
|
79
|
+
case DROP_DOWN:
|
|
80
|
+
fieldValue = new DropDownFieldValue(stringValue);
|
|
81
|
+
break;
|
|
82
|
+
case LINK:
|
|
83
|
+
fieldValue = new LinkFieldValue(stringValue);
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
fieldValue = new SingleLineTextFieldValue(stringValue);
|
|
82
87
|
}
|
|
88
|
+
record.putField(fieldCode, fieldValue);
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
private void setTimestampValue(String fieldCode, Instant instant, ZoneId zoneId, FieldType type)
|
|
@@ -135,11 +141,11 @@ public class KintoneColumnVisitor
|
|
|
135
141
|
|
|
136
142
|
private boolean isUpdateKey(Column column)
|
|
137
143
|
{
|
|
138
|
-
|
|
139
|
-
if (option == null) {
|
|
144
|
+
if (this.updateKeyName == null) {
|
|
140
145
|
return false;
|
|
141
146
|
}
|
|
142
|
-
|
|
147
|
+
|
|
148
|
+
return this.updateKeyName.equals(column.getName());
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
private String getValueSeparator(Column column)
|
|
@@ -164,7 +170,11 @@ public class KintoneColumnVisitor
|
|
|
164
170
|
{
|
|
165
171
|
String fieldCode = getFieldCode(column);
|
|
166
172
|
FieldType type = getType(column, FieldType.NUMBER);
|
|
167
|
-
|
|
173
|
+
if (pageReader.isNull(column)) {
|
|
174
|
+
setValue(fieldCode, null, type, isUpdateKey(column));
|
|
175
|
+
} else {
|
|
176
|
+
setValue(fieldCode, pageReader.getLong(column), type, isUpdateKey(column));
|
|
177
|
+
}
|
|
168
178
|
}
|
|
169
179
|
|
|
170
180
|
@Override
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package org.embulk.output.kintone;
|
|
2
2
|
|
|
3
3
|
import org.embulk.config.ConfigDiff;
|
|
4
|
+
import org.embulk.config.ConfigException;
|
|
4
5
|
import org.embulk.config.ConfigSource;
|
|
5
6
|
import org.embulk.config.TaskReport;
|
|
6
7
|
import org.embulk.config.TaskSource;
|
|
@@ -50,32 +51,18 @@ public class KintoneOutputPlugin
|
|
|
50
51
|
KintoneMode mode = KintoneMode.getKintoneModeByValue(task.getMode());
|
|
51
52
|
switch (mode) {
|
|
52
53
|
case INSERT:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
throw new IllegalArgumentException(
|
|
56
|
-
"when mode is insert, require no update_key.");
|
|
57
|
-
}
|
|
54
|
+
if (task.getUpdateKeyName().isPresent()) {
|
|
55
|
+
throw new ConfigException("when mode is insert, require no update_key.");
|
|
58
56
|
}
|
|
59
57
|
break;
|
|
60
58
|
case UPDATE:
|
|
61
59
|
case UPSERT:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (option.getUpdateKey()) {
|
|
65
|
-
if (hasUpdateKey) {
|
|
66
|
-
throw new IllegalArgumentException(
|
|
67
|
-
"when mode is update and upsert, only one column can have an update_key.");
|
|
68
|
-
}
|
|
69
|
-
hasUpdateKey = true;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (!hasUpdateKey) {
|
|
73
|
-
throw new IllegalArgumentException(
|
|
74
|
-
"when mode is update and upsert, require update_key.");
|
|
60
|
+
if (!task.getUpdateKeyName().isPresent()) {
|
|
61
|
+
throw new ConfigException("when mode is update or upsert, require update_key.");
|
|
75
62
|
}
|
|
76
63
|
break;
|
|
77
64
|
default:
|
|
78
|
-
throw new
|
|
65
|
+
throw new ConfigException(String.format(
|
|
79
66
|
"Unknown mode '%s'",
|
|
80
67
|
task.getMode()));
|
|
81
68
|
}
|
|
@@ -3,6 +3,7 @@ package org.embulk.output.kintone;
|
|
|
3
3
|
import com.kintone.client.KintoneClient;
|
|
4
4
|
import com.kintone.client.KintoneClientBuilder;
|
|
5
5
|
import com.kintone.client.api.record.GetRecordsByCursorResponseBody;
|
|
6
|
+
import com.kintone.client.model.record.FieldType;
|
|
6
7
|
import com.kintone.client.model.record.Record;
|
|
7
8
|
import com.kintone.client.model.record.RecordForUpdate;
|
|
8
9
|
import com.kintone.client.model.record.UpdateKey;
|
|
@@ -14,17 +15,16 @@ import org.embulk.spi.PageReader;
|
|
|
14
15
|
import org.embulk.spi.Schema;
|
|
15
16
|
import org.embulk.spi.TransactionalPageOutput;
|
|
16
17
|
|
|
17
|
-
import java.math.BigDecimal;
|
|
18
18
|
import java.util.ArrayList;
|
|
19
19
|
import java.util.Arrays;
|
|
20
|
-
import java.util.HashMap;
|
|
21
20
|
import java.util.List;
|
|
22
|
-
import java.util.Map;
|
|
23
21
|
import java.util.stream.Collectors;
|
|
24
22
|
|
|
25
23
|
public class KintonePageOutput
|
|
26
24
|
implements TransactionalPageOutput
|
|
27
25
|
{
|
|
26
|
+
public static final int UPSERT_BATCH_SIZE = 10000;
|
|
27
|
+
public static final int CHUNK_SIZE = 100;
|
|
28
28
|
private PageReader pageReader;
|
|
29
29
|
private PluginTask task;
|
|
30
30
|
private KintoneClient client;
|
|
@@ -138,7 +138,7 @@ public class KintonePageOutput
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
records.add(record);
|
|
141
|
-
if (records.size() ==
|
|
141
|
+
if (records.size() == CHUNK_SIZE) {
|
|
142
142
|
client.record().addRecords(task.getAppId(), records);
|
|
143
143
|
records.clear();
|
|
144
144
|
}
|
|
@@ -157,10 +157,16 @@ public class KintonePageOutput
|
|
|
157
157
|
{
|
|
158
158
|
execute(client -> {
|
|
159
159
|
try {
|
|
160
|
-
|
|
160
|
+
if (!task.getUpdateKeyName().isPresent()) {
|
|
161
|
+
// already validated in KintoneOutputPlugin.open()
|
|
162
|
+
throw new RuntimeException("unreachable error");
|
|
163
|
+
}
|
|
164
|
+
ArrayList<RecordForUpdate> updateRecords = new ArrayList<>();
|
|
161
165
|
pageReader.setPage(page);
|
|
166
|
+
|
|
162
167
|
KintoneColumnVisitor visitor = new KintoneColumnVisitor(pageReader,
|
|
163
|
-
task.getColumnOptions()
|
|
168
|
+
task.getColumnOptions(),
|
|
169
|
+
task.getUpdateKeyName().get());
|
|
164
170
|
while (pageReader.nextRecord()) {
|
|
165
171
|
Record record = new Record();
|
|
166
172
|
UpdateKey updateKey = new UpdateKey();
|
|
@@ -170,9 +176,13 @@ public class KintonePageOutput
|
|
|
170
176
|
column.visit(visitor);
|
|
171
177
|
}
|
|
172
178
|
|
|
179
|
+
if (updateKey.getValue() == "") {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
173
183
|
record.removeField(updateKey.getField());
|
|
174
184
|
updateRecords.add(new RecordForUpdate(updateKey, record));
|
|
175
|
-
if (updateRecords.size() ==
|
|
185
|
+
if (updateRecords.size() == CHUNK_SIZE) {
|
|
176
186
|
client.record().updateRecords(task.getAppId(), updateRecords);
|
|
177
187
|
updateRecords.clear();
|
|
178
188
|
}
|
|
@@ -187,150 +197,133 @@ public class KintonePageOutput
|
|
|
187
197
|
});
|
|
188
198
|
}
|
|
189
199
|
|
|
190
|
-
private
|
|
200
|
+
private void upsertPage(final Page page)
|
|
191
201
|
{
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return allRecords;
|
|
205
|
-
}
|
|
202
|
+
execute(client -> {
|
|
203
|
+
try {
|
|
204
|
+
if (!task.getUpdateKeyName().isPresent()) {
|
|
205
|
+
// already validated in KintoneOutputPlugin.open()
|
|
206
|
+
throw new RuntimeException("unreachable error");
|
|
207
|
+
}
|
|
208
|
+
ArrayList<Record> records = new ArrayList<>();
|
|
209
|
+
ArrayList<UpdateKey> updateKeys = new ArrayList<>();
|
|
210
|
+
pageReader.setPage(page);
|
|
206
211
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
ArrayList<Record> insertRecords = new ArrayList<>();
|
|
219
|
-
ArrayList<RecordForUpdate> updateRecords = new ArrayList<RecordForUpdate>();
|
|
220
|
-
pageReader.setPage(page);
|
|
221
|
-
KintoneColumnVisitor visitor = new KintoneColumnVisitor(pageReader,
|
|
222
|
-
task.getColumnOptions());
|
|
223
|
-
while (pageReader.nextRecord()) {
|
|
224
|
-
Record record = new Record();
|
|
225
|
-
UpdateKey updateKey = new UpdateKey();
|
|
226
|
-
visitor.setRecord(record);
|
|
227
|
-
visitor.setUpdateKey(updateKey);
|
|
228
|
-
for (Column column : pageReader.getSchema().getColumns()) {
|
|
229
|
-
column.visit(visitor);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (existsRecord(updateKeyValues, record)) {
|
|
233
|
-
record.removeField(updateKey.getField());
|
|
234
|
-
updateRecords.add(new RecordForUpdate(updateKey, record));
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
insertRecords.add(record);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (insertRecords.size() == 100) {
|
|
241
|
-
client.record().addRecords(task.getAppId(), insertRecords);
|
|
242
|
-
insertRecords.clear();
|
|
243
|
-
}
|
|
244
|
-
else if (updateRecords.size() == 100) {
|
|
245
|
-
client.record().updateRecords(task.getAppId(), updateRecords);
|
|
246
|
-
updateRecords.clear();
|
|
247
|
-
}
|
|
212
|
+
KintoneColumnVisitor visitor = new KintoneColumnVisitor(pageReader,
|
|
213
|
+
task.getColumnOptions(),
|
|
214
|
+
task.getUpdateKeyName().get());
|
|
215
|
+
while (pageReader.nextRecord()) {
|
|
216
|
+
Record record = new Record();
|
|
217
|
+
UpdateKey updateKey = new UpdateKey();
|
|
218
|
+
visitor.setRecord(record);
|
|
219
|
+
visitor.setUpdateKey(updateKey);
|
|
220
|
+
for (Column column : pageReader.getSchema().getColumns()) {
|
|
221
|
+
column.visit(visitor);
|
|
248
222
|
}
|
|
223
|
+
records.add(record);
|
|
224
|
+
updateKeys.add(updateKey);
|
|
249
225
|
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
client.record().updateRecords(task.getAppId(), updateRecords);
|
|
226
|
+
if (records.size() == UPSERT_BATCH_SIZE) {
|
|
227
|
+
upsert(records, updateKeys);
|
|
228
|
+
records.clear();
|
|
229
|
+
updateKeys.clear();
|
|
255
230
|
}
|
|
256
231
|
}
|
|
257
|
-
|
|
258
|
-
|
|
232
|
+
if (records.size() > 0) {
|
|
233
|
+
upsert(records, updateKeys);
|
|
259
234
|
}
|
|
260
|
-
}
|
|
261
|
-
|
|
235
|
+
}
|
|
236
|
+
catch (Exception e) {
|
|
237
|
+
throw new RuntimeException("kintone throw exception", e);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
262
240
|
}
|
|
263
241
|
|
|
264
|
-
|
|
242
|
+
private void upsert(ArrayList<Record> records, ArrayList<UpdateKey> updateKeys)
|
|
265
243
|
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
public UpsertPageByStringKey(String fieldCode)
|
|
269
|
-
{
|
|
270
|
-
this.fieldCode = fieldCode;
|
|
244
|
+
if (records.size() != updateKeys.size()) {
|
|
245
|
+
throw new RuntimeException("records.size() != updateKeys.size()");
|
|
271
246
|
}
|
|
272
247
|
|
|
273
|
-
|
|
274
|
-
{
|
|
275
|
-
return getAllRecords(fieldCode)
|
|
276
|
-
.stream()
|
|
277
|
-
.map(r -> r.getSingleLineTextFieldValue(fieldCode))
|
|
278
|
-
.collect(Collectors.toList());
|
|
279
|
-
}
|
|
248
|
+
List<Record> existingRecords = getExistingRecordsByUpdateKey(updateKeys);
|
|
280
249
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
250
|
+
ArrayList<Record> insertRecords = new ArrayList<>();
|
|
251
|
+
ArrayList<RecordForUpdate> updateRecords = new ArrayList<>();
|
|
252
|
+
for (int i = 0; i < records.size(); i++) {
|
|
253
|
+
Record record = records.get(i);
|
|
254
|
+
UpdateKey updateKey = updateKeys.get(i);
|
|
286
255
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
256
|
+
if (existsRecord(existingRecords, updateKey)) {
|
|
257
|
+
record.removeField(updateKey.getField());
|
|
258
|
+
updateRecords.add(new RecordForUpdate(updateKey, record));
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
insertRecords.add(record);
|
|
262
|
+
}
|
|
290
263
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
264
|
+
if (insertRecords.size() == CHUNK_SIZE) {
|
|
265
|
+
client.record().addRecords(task.getAppId(), insertRecords);
|
|
266
|
+
insertRecords.clear();
|
|
267
|
+
}
|
|
268
|
+
else if (updateRecords.size() == CHUNK_SIZE) {
|
|
269
|
+
client.record().updateRecords(task.getAppId(), updateRecords);
|
|
270
|
+
updateRecords.clear();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (insertRecords.size() > 0) {
|
|
274
|
+
client.record().addRecords(task.getAppId(), insertRecords);
|
|
275
|
+
}
|
|
276
|
+
if (updateRecords.size() > 0) {
|
|
277
|
+
client.record().updateRecords(task.getAppId(), updateRecords);
|
|
294
278
|
}
|
|
279
|
+
}
|
|
280
|
+
|
|
295
281
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
282
|
+
private List<Record> getExistingRecordsByUpdateKey(ArrayList<UpdateKey> updateKeys)
|
|
283
|
+
{
|
|
284
|
+
String fieldCode = updateKeys.get(0).getField();
|
|
285
|
+
List<String> queryValues = updateKeys
|
|
299
286
|
.stream()
|
|
300
|
-
.
|
|
287
|
+
.filter(k -> k.getValue() != "")
|
|
288
|
+
.map(k -> "\"" + k.getValue().toString() + "\"")
|
|
301
289
|
.collect(Collectors.toList());
|
|
302
|
-
}
|
|
303
290
|
|
|
304
|
-
|
|
305
|
-
{
|
|
306
|
-
return
|
|
291
|
+
List<Record> allRecords = new ArrayList<>();
|
|
292
|
+
if (queryValues.isEmpty()) {
|
|
293
|
+
return allRecords;
|
|
307
294
|
}
|
|
308
|
-
|
|
295
|
+
String cursorId = client.record().createCursor(
|
|
296
|
+
task.getAppId(),
|
|
297
|
+
Arrays.asList(fieldCode),
|
|
298
|
+
fieldCode + " in (" + String.join(",", queryValues) + ")"
|
|
299
|
+
);
|
|
300
|
+
while (true) {
|
|
301
|
+
GetRecordsByCursorResponseBody resp = client.record().getRecordsByCursor(cursorId);
|
|
302
|
+
List<Record> records = resp.getRecords();
|
|
303
|
+
allRecords.addAll(records);
|
|
309
304
|
|
|
310
|
-
|
|
311
|
-
{
|
|
312
|
-
KintoneColumnOption updateKeyColumn = null;
|
|
313
|
-
for (KintoneColumnOption v : task.getColumnOptions().values()) {
|
|
314
|
-
if (v.getUpdateKey()) {
|
|
315
|
-
updateKeyColumn = v;
|
|
305
|
+
if (!resp.hasNext()) {
|
|
316
306
|
break;
|
|
317
307
|
}
|
|
318
308
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
309
|
+
return allRecords;
|
|
310
|
+
}
|
|
322
311
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
case
|
|
329
|
-
|
|
330
|
-
|
|
312
|
+
private boolean existsRecord(List<Record> distRecords, UpdateKey updateKey)
|
|
313
|
+
{
|
|
314
|
+
String fieldCode = updateKey.getField();
|
|
315
|
+
FieldType type = client.app().getFormFields(task.getAppId()).get(fieldCode).getType();
|
|
316
|
+
switch (type) {
|
|
317
|
+
case SINGLE_LINE_TEXT:
|
|
318
|
+
return distRecords
|
|
319
|
+
.stream()
|
|
320
|
+
.anyMatch(d -> d.getSingleLineTextFieldValue(fieldCode).equals(updateKey.getValue()));
|
|
321
|
+
case NUMBER:
|
|
322
|
+
return distRecords
|
|
323
|
+
.stream()
|
|
324
|
+
.anyMatch(d -> d.getNumberFieldValue(fieldCode).equals(updateKey.getValue()));
|
|
331
325
|
default:
|
|
332
326
|
throw new RuntimeException("The update_key must be 'SINGLE_LINE_TEXT' or 'NUMBER'.");
|
|
333
327
|
}
|
|
334
|
-
runner.run(page);
|
|
335
328
|
}
|
|
336
329
|
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: embulk-output-kintone
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- takeshi fujita
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-03-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,7 +52,7 @@ files:
|
|
|
52
52
|
- README.md
|
|
53
53
|
- Rakefile
|
|
54
54
|
- build.gradle
|
|
55
|
-
- classpath/embulk-output-kintone-0.
|
|
55
|
+
- classpath/embulk-output-kintone-0.3.0.jar
|
|
56
56
|
- config/checkstyle/checkstyle.xml
|
|
57
57
|
- config/checkstyle/default.xml
|
|
58
58
|
- gradle/wrapper/gradle-wrapper.jar
|