Skip to content

Commit

Permalink
Merge pull request #43 from trocco-io/update_by_id
Browse files Browse the repository at this point in the history
Add support for update by id
  • Loading branch information
d-hrs authored May 31, 2024
2 parents ce7b2d9 + ee6bcf3 commit 473d439
Show file tree
Hide file tree
Showing 143 changed files with 1,284 additions and 264 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ kintone output plugin for Embulk stores app records from kintone.
- **max_sort_memory**: Maximum memory usage for sorting input records (bytes in long, default is the estimated available memory, which is the approximate value of the JVM's current free memory)
- **prefer_nulls**: Whether to set fields to null instead of default value of type when column is null (boolean, default is `false`)
- **ignore_nulls**: Whether to completely ignore fields when column is null (boolean, default is `false`)
- **skip_if_non_existing_id_or_update_key**: The skip policy if the record corresponding to the id or update key does not exist (string `auto`, `never` or `always`, default is `auto`). No effect for insert mode.
- **auto**:
- **update mode**: Skip the record if no id or update key value is specified.
- **upsert mode**: Skip the record if corresponds to the id does not exist or no update key value is specified.
- **never**: Never skip the record even if corresponds to the id or update key does not exist.
- **update mode**: Throw exception if no id or update key value is specified.
- **upsert mode**: Insert the record if corresponds to the id or update key does not exist (also, if no id or update key value is specified).
- **always**: Always skip the record if corresponds to the id or update key does not exist (also, if no id or update key value is specified). update mode and upsert mode will the same behavior (only updated, never inserted).
- **column_options** advanced: a key-value pairs where key is a column name and value is options for the column.
- **field_code**: field code (string, required)
- **type**: field type (string, required). See [this page](https://cybozu.dev/ja/kintone/docs/overview/field-types/#field-type-update) for list of available types. However, following types are not yet supported
Expand Down
117 changes: 117 additions & 0 deletions src/main/java/org/embulk/output/kintone/KintoneClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package org.embulk.output.kintone;

import com.kintone.client.KintoneClientBuilder;
import com.kintone.client.RecordClient;
import com.kintone.client.model.app.field.FieldProperty;
import com.kintone.client.model.record.FieldType;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.embulk.config.ConfigException;
import org.embulk.output.kintone.record.Id;
import org.embulk.output.kintone.util.Lazy;
import org.embulk.spi.Column;
import org.embulk.spi.Schema;
import org.embulk.spi.type.Type;
import org.embulk.spi.type.Types;

public class KintoneClient implements AutoCloseable {
private final PluginTask task;
private final Schema schema;
private final com.kintone.client.KintoneClient client;
private final Map<String, FieldProperty> fields;

public static Lazy<KintoneClient> lazy(Supplier<PluginTask> task, Schema schema) {
return new Lazy<KintoneClient>() {
@Override
protected KintoneClient initialValue() {
return new KintoneClient(task.get(), schema);
}
};
}

private KintoneClient(PluginTask task, Schema schema) {
this.task = task;
this.schema = schema;
KintoneClientBuilder builder = KintoneClientBuilder.create("https://" + task.getDomain());
if (task.getGuestSpaceId().isPresent()) {
builder.setGuestSpaceId(task.getGuestSpaceId().get());
}
if (task.getBasicAuthUsername().isPresent() && task.getBasicAuthPassword().isPresent()) {
builder.withBasicAuth(task.getBasicAuthUsername().get(), task.getBasicAuthPassword().get());
}
if (task.getUsername().isPresent() && task.getPassword().isPresent()) {
builder.authByPassword(task.getUsername().get(), task.getPassword().get());
} else if (task.getToken().isPresent()) {
builder.authByApiToken(task.getToken().get());
} else {
throw new ConfigException("Username and password or token must be configured.");
}
client = builder.build();
fields = client.app().getFormFields(task.getAppId());
KintoneMode.of(task).validate(task, this);
}

public void validateIdOrUpdateKey(String columnName) {
Column column = getColumn(columnName);
if (column == null) {
throw new ConfigException("The column '" + columnName + "' for update does not exist.");
}
validateId(column);
validateUpdateKey(column);
}

public Column getColumn(String columnName) {
return schema.getColumns().stream()
.filter(column -> column.getName().equals(columnName))
.findFirst()
.orElse(null);
}

public FieldType getFieldType(String fieldCode) {
FieldProperty field = fields.get(fieldCode);
return field == null ? null : field.getType();
}

public RecordClient record() {
return client.record();
}

@Override
public void close() {
try {
client.close();
} catch (IOException e) {
throw new RuntimeException("kintone throw exception", e);
}
}

private void validateId(Column column) {
if (!column.getName().equals(Id.FIELD)) {
return;
}
Type type = column.getType();
if (!type.equals(Types.LONG)) {
throw new ConfigException("The id column must be 'long'.");
}
}

private void validateUpdateKey(Column column) {
if (column.getName().equals(Id.FIELD)) {
return;
}
String fieldCode = getFieldCode(column);
FieldType fieldType = getFieldType(fieldCode);
if (fieldType == null) {
throw new ConfigException("The field '" + fieldCode + "' for update does not exist.");
}
if (fieldType != FieldType.SINGLE_LINE_TEXT && fieldType != FieldType.NUMBER) {
throw new ConfigException("The update_key must be 'SINGLE_LINE_TEXT' or 'NUMBER'.");
}
}

private String getFieldCode(Column column) {
KintoneColumnOption option = task.getColumnOptions().get(column.getName());
return option != null ? option.getFieldCode() : column.getName();
}
}
43 changes: 30 additions & 13 deletions src/main/java/org/embulk/output/kintone/KintoneColumnType.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.kintone.client.model.record.NumberFieldValue;
import com.kintone.client.model.record.OrganizationSelectFieldValue;
import com.kintone.client.model.record.RadioButtonFieldValue;
import com.kintone.client.model.record.Record;
import com.kintone.client.model.record.RichTextFieldValue;
import com.kintone.client.model.record.SingleLineTextFieldValue;
import com.kintone.client.model.record.SubtableFieldValue;
Expand All @@ -34,6 +35,8 @@
import org.embulk.spi.time.Timestamp;
import org.embulk.spi.type.Type;
import org.embulk.spi.type.Types;
import org.msgpack.value.ArrayValue;
import org.msgpack.value.StringValue;
import org.msgpack.value.Value;
import org.msgpack.value.ValueFactory;

Expand All @@ -49,6 +52,11 @@ public SingleLineTextFieldValue getFieldValue(String value, KintoneColumnOption
return new SingleLineTextFieldValue(value);
}

@Override
public String getValue(Record record, String fieldCode) {
return record.getSingleLineTextFieldValue(fieldCode);
}

@Override
public void setUpdateKey(UpdateKey updateKey, String field) {
updateKey.setField(field);
Expand All @@ -60,7 +68,7 @@ public void setUpdateKey(UpdateKey updateKey, String field, FieldValue value) {
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((SingleLineTextFieldValue) value).getValue());
}

Expand All @@ -81,7 +89,7 @@ public MultiLineTextFieldValue getFieldValue(String value, KintoneColumnOption o
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((MultiLineTextFieldValue) value).getValue());
}

Expand All @@ -102,7 +110,7 @@ public RichTextFieldValue getFieldValue(String value, KintoneColumnOption option
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((RichTextFieldValue) value).getValue());
}

Expand Down Expand Up @@ -132,6 +140,11 @@ public NumberFieldValue getFieldValue(Timestamp value, KintoneColumnOption optio
return (NumberFieldValue) getFieldValue(value.getEpochSecond(), option);
}

@Override
public BigDecimal getValue(Record record, String fieldCode) {
return record.getNumberFieldValue(fieldCode);
}

@Override
public void setUpdateKey(UpdateKey updateKey, String field) {
updateKey.setField(field);
Expand All @@ -143,8 +156,8 @@ public void setUpdateKey(UpdateKey updateKey, String field, FieldValue value) {
}

@Override
public Value asValue(FieldValue value) {
return ValueFactory.newString(((NumberFieldValue) value).getValue().toString());
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((NumberFieldValue) value).getValue().toPlainString());
}

@Override
Expand All @@ -164,7 +177,7 @@ public CheckBoxFieldValue getFieldValue(String value, KintoneColumnOption option
}

@Override
public Value asValue(FieldValue value) {
public ArrayValue asValue(FieldValue value) {
return ValueFactory.newArray(
((CheckBoxFieldValue) value)
.getValues().stream().map(ValueFactory::newString).collect(Collectors.toList()));
Expand All @@ -187,7 +200,7 @@ public RadioButtonFieldValue getFieldValue(String value, KintoneColumnOption opt
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((RadioButtonFieldValue) value).getValue());
}

Expand All @@ -208,7 +221,7 @@ public MultiSelectFieldValue getFieldValue(String value, KintoneColumnOption opt
}

@Override
public Value asValue(FieldValue value) {
public ArrayValue asValue(FieldValue value) {
return ValueFactory.newArray(
((MultiSelectFieldValue) value)
.getValues().stream().map(ValueFactory::newString).collect(Collectors.toList()));
Expand All @@ -231,7 +244,7 @@ public DropDownFieldValue getFieldValue(String value, KintoneColumnOption option
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((DropDownFieldValue) value).getValue());
}

Expand Down Expand Up @@ -336,7 +349,7 @@ public DateFieldValue getFieldValue(Timestamp value, KintoneColumnOption option)
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((DateFieldValue) value).getValue().toString());
}

Expand Down Expand Up @@ -378,7 +391,7 @@ public TimeFieldValue getFieldValue(Timestamp value, KintoneColumnOption option)
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((TimeFieldValue) value).getValue().toString());
}

Expand Down Expand Up @@ -416,7 +429,7 @@ public DateTimeFieldValue getFieldValue(Timestamp value, KintoneColumnOption opt
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((DateTimeFieldValue) value).getValue().toString());
}

Expand All @@ -437,7 +450,7 @@ public LinkFieldValue getFieldValue(String value, KintoneColumnOption option) {
}

@Override
public Value asValue(FieldValue value) {
public StringValue asValue(FieldValue value) {
return ValueFactory.newString(((LinkFieldValue) value).getValue());
}

Expand Down Expand Up @@ -540,6 +553,10 @@ public FieldValue getFieldValue(Value value, KintoneColumnOption option) {
}
}

public Object getValue(Record Record, String fieldCode) {
throw new UnsupportedOperationException();
}

public void setUpdateKey(UpdateKey updateKey, String field) {
throw new UnsupportedOperationException();
}
Expand Down
Loading

0 comments on commit 473d439

Please sign in to comment.