io.kestra.plugin.serdes.excel.IonToExcel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plugin-serdes Show documentation
Show all versions of plugin-serdes Show documentation
Serialize and deserialize data formats in Kestra workflows.
The newest version!
package io.kestra.plugin.serdes.excel;
import io.kestra.core.models.annotations.Example;
import io.kestra.core.models.annotations.Plugin;
import io.kestra.core.models.annotations.PluginProperty;
import io.kestra.core.models.executions.metrics.Counter;
import io.kestra.core.models.tasks.RunnableTask;
import io.kestra.core.runners.RunContext;
import io.kestra.core.serializers.FileSerde;
import io.kestra.plugin.serdes.AbstractTextWriter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.nio.charset.Charset;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import static io.kestra.core.utils.Rethrow.throwFunction;
@SuperBuilder
@ToString
@EqualsAndHashCode
@Getter
@NoArgsConstructor
@Schema(
title = "Read an ION-serialized file and transform it to an Excel file"
)
@Plugin(
examples = {
@Example(
full = true,
title = "Download a CSV file and convert it to the Excel file format.",
code = """
id: ion_to_excel
namespace: company.team
tasks:
- id: http_download
type: io.kestra.plugin.core.http.Download
uri: https://huggingface.co/datasets/kestra/datasets/raw/main/csv/products.csv
- id: convert
type: io.kestra.plugin.serdes.csv.CsvToIon
from: "{{ outputs.http_download.uri }}"
- id: to_excel
type: io.kestra.plugin.serdes.excel.IonToExcel
from: "{{ outputs.convert.uri }}"
"""
),
@Example(
full = true,
title = "Download CSV files and convert them into an Excel file with dedicated sheets.",
code = """
id: excel
namespace: company.team
tasks:
- id: dataset1
type: io.kestra.plugin.core.http.Download
uri: https://huggingface.co/datasets/kestra/datasets/raw/main/csv/products.csv
- id: dataset2
type: io.kestra.plugin.core.http.Download
uri: https://huggingface.co/datasets/kestra/datasets/raw/main/csv/fruit.csv
- id: convert1
type: io.kestra.plugin.serdes.csv.CsvToIon
from: "{{ outputs.dataset1.uri }}"
- id: convert2
type: io.kestra.plugin.serdes.csv.CsvToIon
from: "{{ outputs.dataset2.uri }}"
- id: write
type: io.kestra.plugin.serdes.excel.IonToExcel
from:
Sheet_1: "{{ outputs.convert1.uri }}"
Sheet_2: "{{ outputs.convert2.uri }}"
"""
)
}
)
public class IonToExcel extends AbstractTextWriter implements RunnableTask {
@NotNull
@Schema(
title = "Source file URI",
anyOf = {String.class, Map.class}
)
@PluginProperty(dynamic = true)
private Object from;
@Schema(
title = "The name of a supported character set",
defaultValue = "UTF-8"
)
@Builder.Default
@PluginProperty
private String charset = "UTF-8";
@Schema(
title = "The sheet title to be used when writing data to an Excel spreadsheet",
defaultValue = "Sheet"
)
@Builder.Default
@PluginProperty
private String sheetsTitle = "Sheet";
@Schema(
title = "Whether header should be written as the first line"
)
@Builder.Default
@PluginProperty
private boolean header = true;
@Schema(
title = "Whether styles should be applied to format values",
description = "Excel is limited to 64000 styles per document, and styles are applied on every date, " +
"removed this options when you have a lots of values."
)
@Builder.Default
@PluginProperty
private boolean styles = true;
@Override
public Output run(RunContext runContext) throws Exception {
Long lineCount;
if (this.from instanceof String fromStr) {
this.init(runContext);
try (SXSSFWorkbook workbook = new SXSSFWorkbook(1)) {
File tempFile = runContext.workingDir().createTempFile(".xlsx").toFile();
lineCount = writeQuery(runContext, sheetsTitle, runContext.render(fromStr), tempFile, workbook);
return Output.builder()
.uri(runContext.storage().putFile(tempFile))
.size(lineCount)
.build();
}
} else if (from instanceof Map,?> fromMap) {
try (SXSSFWorkbook workbook = new SXSSFWorkbook(1)) {
File tempFile = runContext.workingDir().createTempFile(".xlsx").toFile();
lineCount = runContext.renderMap((Map) fromMap).entrySet()
.stream()
.map(throwFunction(entry -> writeQuery(runContext, entry.getKey(), entry.getValue(), tempFile, workbook)))
.mapToLong(Long::longValue)
.sum();
return Output.builder()
.uri(runContext.storage().putFile(tempFile))
.size(lineCount)
.build();
}
}
throw new IllegalStateException("Invalid variable: 'from'");
}
private Long writeQuery(RunContext runContext, String title, String from, File tempFile, SXSSFWorkbook workbook) throws Exception {
URI fromUri = new URI(from);
Long lineCount;
try (
Reader reader = new BufferedReader(new InputStreamReader(runContext.storage().getFile(fromUri), Charset.forName(this.charset)), FileSerde.BUFFER_SIZE);
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(tempFile), FileSerde.BUFFER_SIZE)
) {
SXSSFSheet sheet = workbook.createSheet(title);
Flux