@sap/cds-dk
Version:
Command line client and development toolkit for the SAP Cloud Application Programming Model
75 lines (70 loc) • 2.76 kB
JavaScript
const { elementsSorter } = require('./as-json')
/**
* Serializes the given JSON data to CSV format
* @param {object} data JSON data to serialize
* @param {object} csn the model
* @param {{ headerOnly: boolean, separator: boolean }} options
* @returns {Promise<string>} CSV string
*/
module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) => {
// We might need multiple passes if data for associations/compositions is created on the fly.
// So loop as long as there is some non-string data left.
while (Object.values(data).some(d => typeof d === 'object')) {
Object.entries(data)
.filter(([_, value]) => typeof value === 'object')
.map(([name]) => csn.definitions[name])
.forEach(entity => {
const entityData = data[entity.name]
const header = []
const records = []
for (let i = 0; i < entityData.length; i++) {
let record = []
const elements = Object.values(entity.elements).sort(elementsSorter(csn))
for (const element of elements) {
const name = element.name
let value = entityData[i][name]
if (value === undefined)
continue
if (element._type === 'cds.Composition') {
data[element.target] = value // Add object for a new entity. Next pass will process it.
}
else if (element._type === 'cds.Association') {
if (element.on) {
continue // skip unmanaged associations with explicit on condition
}
if (i === 0) {
header.push(...Object.keys(value).map(foreignKey => name + '_' + foreignKey))
}
record.push(...Object.values(value))
}
else if (element.is_struct && element.type !== 'cds.Map') {
if (i === 0) {
header.push(...Object.keys(value).map(structField => name + '_' + structField))
}
record.push(...Object.values(value))
}
else {
if (i === 0) header.push(name)
if (Array.isArray(value) || typeof value === 'object') { // `array of`/`many` and `cds.Map`
value = JSON.stringify(value)
}
value = escape(value)
record.push(value)
}
}
records.push(record.join(separator))
}
let res = header.join(separator)
if (!headerOnly)
res += '\n' + records.join('\n')
data[entity.name] = res
function escape(value) {
if (typeof value === 'string' && (value.includes('"') || value.includes(separator))) {
return `"${value.replace(/"/g, '""')}"` // escape double quotes, then quote the value
}
return value
}
})
}
return data
}