@sap/cds
Version:
SAP Cloud Application Programming Model - CDS for Node.js
65 lines (51 loc) • 2.1 kB
JavaScript
const $collected = Symbol.for('collected')
module.exports = function cds_compile_for_assert(csn) {
function _asserts4element(element, name, base) {
let xpr = element?.['@assert']?.xpr
if (!xpr) return
const inherited = base.elements[name]?.['@assert']?.xpr
if (inherited) {
// dedupe by splitting into "when ... then ..." blocks and filtering out own blocks already in @assert of projection target
const _inherited = _extract_cases(inherited).map(c => JSON.stringify(c))
const own = _extract_cases(xpr).filter(c => !_inherited.includes(JSON.stringify(c)))
if (own.length)
xpr = ['case', ...inherited.slice(1, -1), ...own.reduce((acc, cur) => (acc.push(...cur), acc), []), 'end']
}
return xpr
}
function _asserts4entity(entity) {
if (entity[$collected]) return
// buttom up collection of asserts -> process base entity first
projection: if (entity.projection || entity.query) {
// during compile for java, model is never linked -> no prototype chain
let base = (entity.projection || entity.query.SELECT)?.from?.ref?.[0]
if (!base) throw new Error(`Unable to determine base entity of ${entity.name}`)
base = csn.definitions[base]
// REVISIT: when compiling extensions, base may not be in the model -> OK to abort?
if (!base) break projection
_asserts4entity(base)
for (const each in entity.elements) {
const element = entity.elements[each]
if (element['@assert']) {
element['@assert']._xpr = element['@assert'].xpr
element['@assert'].xpr = _asserts4element(element, each, base)
}
}
}
entity[$collected] = true
}
for (const each in csn.definitions) {
const entity = csn.definitions[each]
if (entity.kind !== 'entity') continue
if (!entity.projection && !entity.query) continue
_asserts4entity(entity)
}
}
function _extract_cases(xpr) {
const cases = []
for (const each of xpr.slice(1, -1)) {
if (each === 'when') cases.push([])
cases.at(-1).push(each)
}
return cases
}