@sap/cds
Version:
SAP Cloud Application Programming Model - CDS for Node.js
169 lines (152 loc) • 6.34 kB
JavaScript
const cds = require ('../index')
const compile = require ('@sap/cds-compiler')
const _4cdsc = Symbol('_4cdsc')
/**
* Returns a copy of the given options object, with all mappings applied and
* finally overridden with entries from cds.env.cdsc. That is, the equivalent
* of {...o, ...[...mappings], ...cds.env.cdsc }.
* @type <T> (src:T,...mappings:{}[]) => T
*/
function _options4 (src, ...mappings) {
if (src[_4cdsc]) return src //> already prepared for cdsc
// Create a derivate of given src options object
const dst = Object.defineProperty({__proto__:src, ...src}, _4cdsc,{value:true}) // NOTE: {__proto__:src} alone doesn't suffice, due to compiler obviously cloning options; {...src} doesn't suffice as non-enumerables from .effective.odata would get lost
// Apply mappings in order of appearance -> latter ones override formers
for (let map of mappings) for (let k in map) {
let v = dst[k]; if (v === undefined) continue
let m = map[k]; if (typeof m === 'function') m(dst,v); else dst[m] = v
}
// Optionally add .messages array to avoid compiler writing messages to stderr
dst.messages = dst.messages || []
// Finally override with options from cds.env.cdsc
return Object.assign(dst,cds.env.cdsc)
}
/**
* Decorates the _options4 function with individual options mapping functions
* for use in respective calls to cdsc functions. Can be used as follows:
*
* const {_options} = require(<this module>) // from external
* _options.for.odata({...}) // same in here
*/
const _options = {for: Object.assign (_options4, {
odata(o,_more) {
const odata = cds.env.odata
if (o && o[_4cdsc]) return o
let f = o && o.flavor || odata.flavor || o, flavor = odata.flavors && odata.flavors[f] || {}
let v = o && o.version || flavor.version || odata.version //> env.odata.flavors.version overrides env.odata.version!
let o2 = { ...flavor, ...odata, ...o, version:v }
if (o2.refs && o2.proxies === undefined) o2.proxies = true //> o.proxies follows o.refs
o2.names = this.sql().names
return _options4 (o2, {
version : 'odataVersion',
structs : (o,v) => o.odataFormat = v ? 'structured' : 'flat',
refs : (o,v) => o.odataForeignKeys = !v,
xrefs : 'odataXServiceRefs',
proxies : 'odataProxies',
containment : 'odataContainment',
// IMPORTANT: as a matter of fact we need the below not only for .to.sql tasks
sql_mapping : 'names', //> legacy
names : (o,v) => v !== 'plain' ? o.sqlMapping = v : undefined,
}, _more)
},
edm(o) {
return this.odata (o, {
version : 'odataVersion',
service : 'service',
})
},
sql (_o, _env, _conf = cds.requires.db) {
// REVISIT: compiler requires to only provide assertIntegrityType if defined
if (_o?._4sql) return _o
const o = _options4 ({ ..._env||cds.env.sql, ..._o, _4sql: true }, {
sql_mapping : 'names', //> legacy
sqlDialect : 'dialect', //> legacy
sqlMapping : 'names',
dialect : 'sqlDialect',
names : (o,v) => v !== 'plain' ? o.sqlMapping = v : undefined,
})
if (!o.sqlDialect) {
let conf = _conf || cds.requires.kinds.sql
let dialect = conf.dialect || conf.kind
if (dialect) o.sqlDialect = dialect
}
const _using_legacy_db = (()=>{
if (_conf?.impl) return _conf.impl.includes('@sap/cds/libx/_runtime/')
if (cds.requires.kinds.sqlite.impl === '@cap-js/sqlite') return false
else try { return require('sqlite3', { paths:[cds.root] }) } catch {/* ignore */}
})()
if (_using_legacy_db) {
o.betterSqliteSessionVariables = false
o.fewerLocalizedViews = false
}
const { native_hana_associations, transitive_localized_views } = cds.env.sql
if (native_hana_associations !== undefined)
o.withHanaAssociations = native_hana_associations
if (transitive_localized_views !== undefined)
o.fewerLocalizedViews = !transitive_localized_views
const { assert_integrity } = cds.env.features
if (assert_integrity)
o.assertIntegrityType = assert_integrity.toString().toUpperCase()
return o
},
hana(o) {
let cdsc = this.sql (o, cds.env.hana, cds.requires.kinds.hana) // returns clone
cdsc.sqlChangeMode ??= cdsc.journal && cdsc.journal['change-mode']
cdsc.disableHanaComments ??= !cdsc.comments
delete cdsc.journal // cleanup avoiding side effects
delete cdsc.comments
return cdsc
},
env() {
const odata = this.edm()
const sql = this.sql()
const hana = this.hana()
const env = {
odata: odata.__proto__,
sql: sql.__proto__,
hana: hana.__proto__,
cdsc: { ...odata, ...sql, ...hana }
}
delete env.odata.flavors
return env
},
})}
/**
* Return a derivate of cdsc, with the most prominent
* @type { import('@sap/cds-compiler') }
*/
module.exports = exports = {__proto__:compile, _options,
for: {__proto__: compile.for,
odata: (csn,o) => compile.for.odata (csn, _options.for.odata(o)),
},
to: {__proto__: compile.to,
edmx: Object.assign ((csn,o) => compile.to.edmx (csn, _options.for.edm(o)), {
all: (csn,o) => compile.to.edmx.all (csn, _options.for.edm(o))
}),
edm: Object.assign ((csn,o) => compile.to.edm (csn, _options.for.edm(o)), {
all: (csn,o) => compile.to.edm.all (csn, _options.for.edm(o))
}),
hdi: Object.assign ((csn,o) => compile.to.hdi (csn, _options.for.hana(o)),
compile.to.hdi, // keywords
{
migration: (csn,o,...etc) => {
o = Object.assign ({...o},_options.for.hana(o)) //> REVISIT: need to flatten as compiler seems to clone options in that impl
return compile.to.hdi.migration (csn, o, ...etc)
}
},
),
hdbcds: Object.assign(
(csn,o) => compile.to.hdbcds (csn, _options.for.hana(o)),
compile.to.hdbcds // keywords
),
sql: Object.assign(
(csn,o) => compile.to.sql (csn, _options.for.sql(o)),
compile.to.sql // smart* functions
),
deltaSql: (csn, o, beforeCsn) => compile.to.sql.migration(csn, o, beforeCsn), // or like hdi.migration
cdl: Object.assign(
(csn,o) => compile.to.cdl (csn, _options4(o||{})),
compile.to.cdl // smart* functions
),
},
}