Skip to content

Commit 5c11642

Browse files
authored
Merge pull request #1181 from atlanhq/FT-717
Adds interchangeable Excel and CSV options for export packages
2 parents 6b139d0 + 91c5bbd commit 5c11642

File tree

29 files changed

+1244
-389
lines changed

29 files changed

+1244
-389
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* SPDX-License-Identifier: Apache-2.0
2+
Copyright 2023 Atlan Pte. Ltd. */
3+
package com.atlan.pkg.serde
4+
5+
/**
6+
* Generic interface through which to write out tabular content.
7+
*/
8+
interface TabularWriter {
9+
/**
10+
* Create a header row for the tabular output.
11+
*
12+
* @param headers ordered map of header names and descriptions
13+
*/
14+
fun writeHeader(headers: Map<String, String>)
15+
16+
/**
17+
* Create a header row for the tabular output.
18+
*
19+
* @param values ordered list of header column names
20+
*/
21+
fun writeHeader(values: Iterable<String>)
22+
23+
/**
24+
* Write a row of data into the tabular output, where key of the map is the column name and the value
25+
* is the value to write for that column of the row of data.
26+
* Note: be sure you have first called {@code writeHeader} to output the header row.
27+
*
28+
* @param values map keyed by column name with values for the row of data
29+
*/
30+
fun writeRecord(values: Map<String, Any?>?)
31+
32+
/**
33+
* Add a row of data to the end of the tabular output.
34+
*
35+
* @param data the row of data to add
36+
*/
37+
fun writeRecord(data: Iterable<Any?>?)
38+
}

package-toolkit/runtime/src/main/kotlin/com/atlan/pkg/serde/csv/CSVWriter.kt

+21-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package com.atlan.pkg.serde.csv
44

55
import com.atlan.model.assets.Asset
66
import com.atlan.pkg.Utils
7+
import com.atlan.pkg.serde.TabularWriter
78
import de.siegmar.fastcsv.writer.CsvWriter
89
import de.siegmar.fastcsv.writer.LineDelimiter
910
import de.siegmar.fastcsv.writer.QuoteStrategies
@@ -22,7 +23,7 @@ import java.util.stream.Stream
2223
*/
2324
class CSVWriter
2425
@JvmOverloads
25-
constructor(path: String, fieldSeparator: Char = ',') : Closeable {
26+
constructor(path: String, fieldSeparator: Char = ',') : Closeable, TabularWriter {
2627
private val writer =
2728
CsvWriter.builder()
2829
.fieldSeparator(fieldSeparator)
@@ -33,12 +34,24 @@ class CSVWriter
3334

3435
private val header = mutableListOf<String>()
3536

37+
/**
38+
* Write a header row into the CSV file.
39+
* Note: since this is a CSV output, the description will be dropped (no standard way to add
40+
* a comment to a CSV file).
41+
*
42+
* @param headers ordered map of header names and descriptions
43+
*/
44+
override fun writeHeader(headers: Map<String, String>) {
45+
header.addAll(headers.keys)
46+
writeRecord(headers.keys)
47+
}
48+
3649
/**
3750
* Write a header row into the CSV file.
3851
*
3952
* @param values to use for the header
4053
*/
41-
fun writeHeader(values: Iterable<String>) {
54+
override fun writeHeader(values: Iterable<String>) {
4255
header.addAll(values)
4356
writeRecord(values)
4457
}
@@ -50,9 +63,9 @@ class CSVWriter
5063
*
5164
* @param values map keyed by column name with values for the row of data
5265
*/
53-
fun writeRecord(values: Map<String, String?>?) {
66+
override fun writeRecord(values: Map<String, Any?>?) {
5467
if (values != null) {
55-
val list = mutableListOf<String>()
68+
val list = mutableListOf<Any>()
5669
header.forEach { name ->
5770
list.add(values.getOrDefault(name, "") ?: "")
5871
}
@@ -64,11 +77,11 @@ class CSVWriter
6477
* Write a row of data into the CSV file, where the values are already sequenced
6578
* in the same order as the header columns.
6679
*
67-
* @param values to use for the row of data
80+
* @param data to use for the row of data
6881
*/
69-
fun writeRecord(values: Iterable<String?>?) {
70-
if (values != null) {
71-
synchronized(writer) { writer.writeRecord(values) }
82+
override fun writeRecord(data: Iterable<Any?>?) {
83+
if (data != null) {
84+
synchronized(writer) { writer.writeRecord(data.map { it?.toString() ?: "" }) }
7285
}
7386
}
7487

package-toolkit/runtime/src/main/kotlin/com/atlan/pkg/serde/csv/CSVXformer.kt

+23-7
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,27 @@ abstract class CSVXformer(
8686
fun trimWhitespace(s: String): String {
8787
return s.trim().trim('\uFEFF', '\u200B')
8888
}
89+
90+
/**
91+
* Translate a row of input values into a map, keyed by input header name
92+
* with the value being the value for that column on the row.
93+
*
94+
* @param header list of header column names
95+
* @param values list of values, in the same order as the header columns
96+
* @return map from header name to value on that row
97+
*/
98+
fun getRowByHeader(
99+
header: List<String>,
100+
values: List<String>,
101+
): Map<String, String> {
102+
val map = mutableMapOf<String, String>()
103+
header.forEachIndexed { index, s ->
104+
// Explicitly trim all whitespace from headers, including byte order mark (BOM) or zero-width space (ZWSP) characters
105+
val trimmed = trimWhitespace(s)
106+
map[trimmed] = values.getOrElse(index) { "" }
107+
}
108+
return map.toMap()
109+
}
89110
}
90111

91112
/**
@@ -147,16 +168,11 @@ abstract class CSVXformer(
147168
* Translate a row of input values into a map, keyed by input header name
148169
* with the value being the value for that column on the row.
149170
*
171+
* @param values a row of values, in the same order as the headers
150172
* @return map from header name to value on that row
151173
*/
152174
private fun getRowByHeader(values: List<String>): Map<String, String> {
153-
val map = mutableMapOf<String, String>()
154-
header.forEachIndexed { index, s ->
155-
// Explicitly trim all whitespace from headers, including byte order mark (BOM) or zero-width space (ZWSP) characters
156-
val trimmed = trimWhitespace(s)
157-
map[trimmed] = values.getOrElse(index) { "" }
158-
}
159-
return map.toMap()
175+
return getRowByHeader(header, values)
160176
}
161177

162178
/** {@inheritDoc} */

0 commit comments

Comments
 (0)