@loaders.gl/csv
Version:
Framework-independent loader for CSV and DSV table formats
62 lines (53 loc) • 1.95 kB
text/typescript
// loaders.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
// Copyright 2022 Foursquare Labs, Inc.
import {Table, makeArrayRowIterator, getTableNumCols} from '@loaders.gl/schema';
import {csvFormatRows} from 'd3-dsv';
import type {CSVWriterOptions} from '../../csv-writer';
type EncodableData = string | null;
/**
* Encode a Table object as CSV
*/
export function encodeTableAsCSV(
table: Table,
options: CSVWriterOptions = {csv: {useDisplayNames: true}}
): string {
const useDisplayNames = options.useDisplayNames || options.csv?.useDisplayNames;
const fields = table.schema?.fields || [];
const columnNames = fields.map((f) => {
// This is a leaky abstraction, assuming Kepler metadata
const displayName = f.metadata?.displayName;
return useDisplayNames && typeof displayName === 'string' ? displayName : f.name;
});
const formattedData: EncodableData[][] = [columnNames];
for (const row of makeArrayRowIterator(table)) {
const formattedRow: EncodableData[] = [];
for (let columnIndex = 0; columnIndex < getTableNumCols(table); ++columnIndex) {
const value = row[columnIndex];
formattedRow[columnIndex] = preformatFieldValue(value);
}
formattedData.push(formattedRow);
}
return csvFormatRows(formattedData);
}
/**
* Stringifies a value
* @todo Why is it called parse?
*/
const preformatFieldValue = (value: unknown): EncodableData => {
if (value === null || value === undefined) {
// TODO: It would be nice to distinguish between missing values and the empty string
// https://github.com/d3/d3-dsv/issues/84
return null;
}
if (value instanceof Date) {
// d3-dsv formats dates without timezones if they don't have time info;
// this forces them to always use fully-qualified ISO time strings
return value.toISOString();
}
if (typeof value === 'object') {
return JSON.stringify(value);
}
return String(value);
};