Handle quote escaping in csv export

This commit is contained in:
Andrew Eisenberg
2022-06-13 11:17:37 -07:00
parent aa270e57ec
commit a3a05131c7
2 changed files with 39 additions and 4 deletions

View File

@@ -372,11 +372,12 @@ export class QueryEvaluationInfo {
pageSize: 100,
offset: nextOffset,
});
const quotes = chunk.columns.map(col => col.kind === 'String' ? '"' : '');
chunk.tuples.forEach((tuple) => {
out.write(tuple.map((v, i) => {
return `${quotes[i]}${v}${quotes[i]}`;
}).join(',') + '\n');
out.write(tuple.map((v, i) =>
chunk.columns[i].kind === 'String'
? `"${typeof v === 'string' ? v.replaceAll('"', '""') : v}"`
: v
).join(',') + '\n');
});
nextOffset = chunk.next;
} while (nextOffset && !stopDecoding);

View File

@@ -91,6 +91,40 @@ describe('run-queries', () => {
});
});
it('should export csv results with characters that need to be escaped', async () => {
const csvLocation = path.join(tmpDir.name, 'test.csv');
const qs = createMockQueryServerClient(
createMockCliServer({
bqrsInfo: [{ 'result-sets': [{ name: SELECT_QUERY_NAME }, { name: 'hucairz' }] }],
bqrsDecode: [{
columns: [{ kind: 'NotString' }, { kind: 'String' }],
// We only escape string columns. In practice, we will only see quotes in strings, but
// it is a good test anyway.
tuples: [
['"a"', '"b"'],
['c,xxx', 'd,yyy'],
['aaa " bbb', 'ccc " ddd'],
[true, false],
[123, 456],
[123.98, 456.99],
],
}]
})
);
const info = createMockQueryInfo();
const promise = info.exportCsvResults(qs, csvLocation);
const result = await promise;
expect(result).to.eq(true);
const csv = fs.readFileSync(csvLocation, 'utf8');
expect(csv).to.eq('"a","""b"""\nc,xxx,"d,yyy"\naaa " bbb,"ccc "" ddd"\ntrue,"false"\n123,"456"\n123.98,"456.99"\n');
// now verify that we are using the expected result set
expect((qs.cliServer.bqrsDecode as sinon.SinonStub).callCount).to.eq(1);
expect((qs.cliServer.bqrsDecode as sinon.SinonStub).getCall(0).args[1]).to.eq(SELECT_QUERY_NAME);
});
it('should handle csv exports for a query with no result sets', async () => {
const csvLocation = path.join(tmpDir.name, 'test.csv');
const qs = createMockQueryServerClient(