Skip to content

Commit 46ae10d

Browse files
authored
Fix CSV writer with empty list (#6333) [ci fast]
Signed-off-by: Ben Sherman <[email protected]>
1 parent 17b05ba commit 46ae10d

File tree

2 files changed

+56
-30
lines changed

2 files changed

+56
-30
lines changed

modules/nextflow/src/main/groovy/nextflow/util/CsvWriter.groovy

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,46 +36,55 @@ class CsvWriter {
3636
}
3737

3838
void apply(List records, Path path) {
39-
Collection columns
40-
if( header == true ) {
41-
final first = records.first()
42-
if( first !instanceof Map )
43-
throw new IllegalArgumentException('Records must be map objects when header=true')
44-
columns = ((Map)first).keySet()
45-
}
46-
else if( header instanceof List ) {
47-
columns = header
48-
}
49-
else {
50-
columns = null
51-
}
52-
5339
path.delete()
5440

41+
final columns = columnHeaders(header, records)
5542
if( columns )
5643
path << columns.collect(column -> "\"${column}\"").join(sep) << '\n'
5744

58-
for( final record : records ) {
59-
Collection values
60-
if( record instanceof List ) {
61-
values = record
62-
}
63-
else if( record instanceof Map ) {
64-
values = columns
65-
? record.subMap(columns).values()
66-
: record.values()
67-
}
68-
else if( isSerializable(record) ) {
69-
values = [ record ]
70-
}
71-
else {
72-
throw new IllegalArgumentException("Record of type `${record.class.name}` can not be serialized to CSV")
73-
}
45+
if( records.isEmpty() )
46+
path << ''
7447

48+
for( final record : records ) {
49+
final values = rowValues(record, columns)
7550
path << values.collect(v -> "\"${toCsvString(v)}\"").join(sep) << '\n'
7651
}
7752
}
7853

54+
private static Collection columnHeaders(Object header, List records) {
55+
if( header instanceof List ) {
56+
return header
57+
}
58+
59+
if( header == true && !records.isEmpty() ) {
60+
final first = records.first()
61+
if( first instanceof Map )
62+
return first.keySet()
63+
else
64+
throw new IllegalArgumentException('Records must be map objects when header=true')
65+
}
66+
67+
return null
68+
}
69+
70+
private static Collection rowValues(Object record, Collection columns) {
71+
if( record instanceof List ) {
72+
return record
73+
}
74+
75+
if( record instanceof Map ) {
76+
return columns
77+
? record.subMap(columns).values()
78+
: record.values()
79+
}
80+
81+
if( isSerializable(record) ) {
82+
return [ record ]
83+
}
84+
85+
throw new IllegalArgumentException("Record of type `${record.class.name}` can not be serialized to CSV")
86+
}
87+
7988
private static boolean isSerializable(value) {
8089
return value == null
8190
|| value instanceof Boolean

modules/nextflow/src/test/groovy/nextflow/util/CsvWriterTest.groovy

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,21 @@ class CsvWriterTest extends Specification {
3838
'''.stripIndent()
3939
}
4040

41+
def 'should write empty csv file'() {
42+
given:
43+
def file = TestHelper.createInMemTempFile()
44+
and:
45+
def records = []
46+
47+
when:
48+
new CsvWriter([:]).apply(records, file)
49+
then:
50+
file.text == ''
51+
52+
when:
53+
new CsvWriter([header: true]).apply(records, file)
54+
then:
55+
file.text == ''
56+
}
57+
4158
}

0 commit comments

Comments
 (0)