Socket
Socket
Sign inDemoInstall

@sap/cds-compiler

Package Overview
Dependencies
1
Maintainers
1
Versions
99
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.9.0 to 4.9.2

32

bin/cdsc.js

@@ -581,18 +581,8 @@ #!/usr/bin/env node

function displayNamedXsn( xsn, name ) {
if (options.rawOutput) {
if (options.rawOutput)
writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn, options.rawOutput), false, null), true);
}
else if (options.internalMsg) {
else if (options.internalMsg)
writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn).messages, { depth: null, maxArrayLength: null }), true);
}
else if (!options.parseOnly) { // no output if parseOnly but not rawOutput
const csn = compactModel(xsn, options);
if (command === 'toCsn' && options.tenantDiscriminator)
addTenantFields(csn, options);
if (command === 'toCsn' && options.withLocalized)
addLocalizationViews(csn, options);
if (options.enrichCsn)
enrichCsn( csn, options );
writeToFileOrDisplay(options.out, `${name}.json`, csn, true);
}
else if (!options.parseOnly) // no output if parseOnly but not rawOutput
displayNamedCsn(compactModel(xsn, options), name);
}

@@ -607,2 +597,14 @@

return;
if (command === 'toCsn' ) {
// If requested, run some CSN postprocessing.
if (options.tenantDiscriminator)
addTenantFields(csn, options); // always _before_ localized convenience views are added
if (options.withLocalized)
addLocalizationViews(csn, options);
}
if (options.enrichCsn)
enrichCsn( csn, options );
if (options.internalMsg) {

@@ -612,4 +614,2 @@ writeToFileOrDisplay(options.out, `${name}_raw.txt`, options.messages, true);

else if (!options.internalMsg) {
if (command === 'toCsn' && options.withLocalized)
addLocalizationViews(csn, options);
writeToFileOrDisplay(options.out, `${name}.json`, csn, true);

@@ -616,0 +616,0 @@ }

@@ -210,3 +210,3 @@ // Consistency checker on model (XSN = augmented CSN)

'$requireElementAccess', '_effectiveType', '$effectiveSeqNo', '_deps',
'$calcDepElement', '$filtered', '_parent',
'$calcDepElement', '$filtered', '$enclosed', '_parent',
],

@@ -265,2 +265,3 @@ schema: {

$filtered: { kind: true, inherits: 'value' }, // for assoc+filter
$enclosed: { kind: true, inherits: 'value' }, // for comp+filter
params: { kind: true, inherits: 'definitions' },

@@ -267,0 +268,0 @@ _extendType: { kind: true, test: TODO },

@@ -1027,11 +1027,7 @@ // Compiler phase 1 = "define": transform dictionary of AST-like XSNs into XSN

if (obj.foreignKeys) {
error( 'type-unexpected-foreign-keys', [ obj.foreignKeys[$location], construct ],
{},
'A managed aspect composition can\'t have a foreign keys specification' );
error( 'type-unexpected-foreign-keys', [ obj.foreignKeys[$location], construct ] );
delete obj.foreignKeys; // continuation semantics: not specified
}
if (obj.on && !obj.target) {
error( 'type-unexpected-on-condition', [ obj.on.location, construct ],
{},
'A managed aspect composition can\'t have a specified ON-condition' );
error( 'type-unexpected-on-condition', [ obj.on.location, construct ] );
delete obj.on; // continuation semantics: not specified

@@ -1186,4 +1182,4 @@ }

// Special case (hack) for calculated elements that use associations+filter:
// See "Notes on `$filtered`" in `ExposingAssocWithFilter.md` for details.
// Special case (hack) for calculated elements that use composition+filter:
// See "Notes on `$enclosed`" in `ExposingAssocWithFilter.md` for details.
if (elem.target && elem.value.path?.[elem.value.path.length - 1]?.where) {

@@ -1190,0 +1186,0 @@ delete elem.type;

@@ -620,4 +620,2 @@ // Populate views with elements, elements with association targets, ...

// effectiveType() must not be called on $self, is unnecessary for mixins:
// TODO: have a test for `select from E { a, $self.a as b, $self.{ b as c } }`
// TODO: have a negative test for `select from E { $self.*, assoc.* }`
// (we might have those already)

@@ -624,0 +622,0 @@ if (alias.kind === 'mixin' || alias.kind === '$self')

@@ -59,3 +59,4 @@ // Propagate properties in XSN

returns,
$filtered: annotation,
$filtered: annotation, // TODO(v5): Remove
$enclosed: annotation,
};

@@ -285,3 +286,3 @@ const ruleToFunction = {

if (target.type?._artifact === model.definitions['cds.Association'])
return; // don't propagate targetAspect to associations (e.g. via $filtered)
return; // don't propagate targetAspect to associations (e.g. via $enclosed)
const ta = source.targetAspect;

@@ -288,0 +289,0 @@ if (!ta.elements && !ta._origin) { // _origin set for elements in source

@@ -8,2 +8,3 @@ // Tweak associations: rewrite keys and on conditions

forEachInOrder,
isBetaEnabled,
} = require('../base/model');

@@ -22,2 +23,3 @@ const { dictLocation, weakLocation, weakRefLocation } = require('../base/location');

setExpandStatus,
getUnderlyingBuiltinType,
} = require('./utils');

@@ -44,2 +46,8 @@ const { Location } = require('../base/location');

Object.assign(model.$functions, {
firstProjectionForPath,
});
const isV5preview = isBetaEnabled( model.options, 'v5preview' );
// Phase 5: rewrite associations

@@ -454,10 +462,23 @@ model._entities.forEach( rewriteArtifact );

elem.$filtered = {
val: true,
literal: 'boolean',
location,
$inferred: '$generated',
};
if (!isV5preview) { // TODO(v5): Remove, only use $enclosed
elem.$filtered = {
val: true,
literal: 'boolean',
location,
$inferred: '$generated',
};
}
const isComp = (getUnderlyingBuiltinType( assoc )?.name?.id === 'cds.Composition');
if (isComp) {
elem.$enclosed = {
val: true,
literal: 'boolean',
location,
$inferred: '$generated',
};
}
}
/**

@@ -548,3 +569,3 @@ * Transform a filter on `assocPathStep` into an ON-condition.

if (elem.$syntax !== 'calc') { // different to lhs!
const projectedFk = firstProjectionForPath( rhs.path, nav.tableAlias, elem );
const projectedFk = firstProjectionForPath( rhs.path, 0, nav.tableAlias, elem );
rewritePath( rhs, projectedFk.item, elem, projectedFk.elem, elem.value.location );

@@ -604,3 +625,4 @@ }

return; // are not allowed anyway - there was an error before
const result = firstProjectionForPath( expr.path, tableAlias, assoc );
const startIndex = (root.kind === '$self' ? 1 : 0);
const result = firstProjectionForPath( expr.path, startIndex, tableAlias, assoc );
// For `assoc[…]`, ensure that we don't rewrite to another projection on `assoc`.

@@ -791,27 +813,34 @@ if (result.item && assoc._origin === result.item._artifact)

/**
* For a path `a.b.c.d`, return a projection for the first path item that is projected.
* For a path `a.b.c.d`, return a projection for the first path item that is projected,
* starting at `startIndex` in this path using the given navigation (table alias or
* navigation element).
* For example, if a query has multiple projections such as `a.b, a, a.b.c`, the
* _first_ possible projection will be used and the caller can rewrite `a.b.c.d` to `b.c.d`.
* This avoids that `extend`s affect the ON-condition.
* This avoids `extend`s affect the ON-condition.
*
* The returned object `ret` has `ret.item`, which is the path item that is projected.
* `ret.elem` is the element projection.
* The returned object `ret` has `ret.item`, which is the path item at index `ret.index`
* that is projected. `ret.elem` is the element projection.
*
* @param {any[]} path
* @param {object} tableAlias
* @param {object} assoc Preferred association that should be used if projected.
* @param {number} startIndex
* @param {object} nav
* @param {object} elem Preferred association/element that should be used if projected.
* @return {{elem: object, item: object}|null}
*/
function firstProjectionForPath( path, tableAlias, assoc ) {
const viaSelf = (path[0]._navigation || path[0]._artifact).kind === '$self';
const root = viaSelf ? 1 : 0;
if (root >= path.length) // e.g. just `$self` path item
function firstProjectionForPath( path, startIndex, nav, elem ) {
if (startIndex >= path.length) // e.g. just `$self` path item
return { item: undefined, elem: {} };
let tableAlias = nav;
while (tableAlias.kind === '$navElement')
tableAlias = tableAlias._parent;
// We want to use the _first_ valid projection that is written by the user (if the preferred
// `assoc` is not directly projected). To achieve that, look into the table alias' elements.
// `assoc` is not directly projected). To achieve that, look into the query's elements.
const selectedElements = Object.values(tableAlias._parent.elements);
const proj = [];
let navItem = tableAlias;
for (const item of path.slice(root)) {
let proj = null;
let navItem = nav;
for (let i = startIndex; i < path.length; ++i) {
const item = path[i];
navItem = item?.id && navItem.elements?.[item.id];

@@ -822,10 +851,14 @@ if (!navItem) {

else if (navItem._projections) {
const elem = navProjection( navItem, assoc );
if (elem && elem === assoc) {
const projElem = navProjection( navItem, elem );
if (projElem && projElem === elem) {
// in case the specified association is found, _always_ use it.
return { item, elem };
return { index: i, item, elem };
}
else if (elem) {
const index = selectedElements.indexOf(elem);
proj.push({ item, elem, index });
else if (projElem) {
const queryIndex = selectedElements.indexOf(projElem);
if (!proj || queryIndex < proj.queryIndex) {
proj = {
index: i, item, elem: projElem, queryIndex,
};
}
}

@@ -835,5 +868,3 @@ }

return (proj.length === 0)
? { item: path[root], elem: null }
: proj.reduce( (acc, curr) => (acc.index > curr.index ? curr : acc), proj[0] ); // first
return proj || { index: startIndex, item: path[startIndex], elem: null };
}

@@ -840,0 +871,0 @@

@@ -101,6 +101,7 @@ // Rewrite paths in annotation expressions.

// ----------------------
// A bare select item that gets an annotation via propagation from its origin behaves
// similar to an element that gets it via an include.
// A bare select item of path length one, that gets an annotation via propagation from
// its origin, behaves similar to an element that gets it via an include.
// However, elements may have been renamed or may not be available at all.
// On top of that, they may be inside nested projections (expand).
// Or even simpler: sub-elements may have been selected.
//

@@ -111,2 +112,7 @@ // Instead of changing the path prefix, we need to check if the referenced path

//
// Furthermore, as the target is a select item, and this select item belongs to a table
// alias, we should rewrite all annotation paths only to projected elements of that
// table alias. Cross-rewriting between table aliases should not be done.
// This is the same we do for association rewriting.
//
// TODO:

@@ -163,2 +169,3 @@ // For now, we do not rewrite sub-structure elements. The whole structure needs

isInFilter;
tokenExpr;
}

@@ -173,2 +180,3 @@

resolvePathRoot,
firstProjectionForPath,
} = model.$functions;

@@ -282,2 +290,7 @@

// magic variables / replacement variables are never rewritten; they can't
// have filters nor can they point to elements.
if (expr._artifact?.kind === 'builtin')
return null;
let hasError = false;

@@ -343,8 +356,37 @@ if (config.isViaType || config.isViaCalcElement)

const { target } = config;
if (expr.scope === 'param') // path is absolute
return navigationEnv( config.targetRoot, null, null, 'nav' );
// On select items, use navigation elements or table alias
// TODO: Expand/inline paths don't have a `_navigation` property on their last
// path step, yet. We need to implement expand/inline.
const isSimpleSelectItem = target.value?.path && target._main?.query && !target._pathHead;
if (isSimpleSelectItem) {
const isSelfPath = (expr.path[0]?._navigation?.kind === '$self');
if (isSelfPath) {
// Path is absolute, use table alias to resolve it.
let tableAlias = target.value.path[0]._navigation;
while (tableAlias && tableAlias.kind === '$navElement')
tableAlias = tableAlias._parent;
if (tableAlias)
return tableAlias;
}
else {
// Path is relative
const nav = target.value.path[target.value.path.length - 1]._navigation?._parent;
if (nav)
return nav;
}
}
if (isSimpleSelectItem && model.options.testMode)
throw new CompilerAssertion(`select item has no table alias: ${ JSON.stringify(target.value.path) }`);
if (isAnnoPathAbsolute( expr ))
return navigationEnv( config.targetRoot, null, null, 'nav' );
// root item is element reference (others were already rejected)
if (isAnnoRootArt( target ))
return navigationEnv( target, null, null, 'nav' );
return navigationEnv( target._parent, null, null, 'nav' );
// anno path is relative / element reference (others were already rejected)
// if the target is a root artifact, use it. Otherwise, use its parent.
return navigationEnv( isAnnoRootArt( target ) ? target : target._parent, null, null, 'nav' );
}

@@ -359,6 +401,11 @@

function rewriteGenericAnnoPath( expr, config, refCtx ) {
const rootIndex = isAnnoPathAbsolute( expr ) ? 1 : 0;
let env = getRootEnv( expr, config );
const isAbsolute = isAnnoPathAbsolute( expr );
const rootIndex = isAbsolute ? 1 : 0;
// reset artifact link
// We get the root environment now, even though below we resolve the root item
// again if it was absolute (e.g. $self). We do so, because for queries, we
// want to respect the select item's corresponding table alias.
const rootEnv = getRootEnv( expr, config );
// reset artifact link; we'll set it again
setArtifactLink( expr, null );

@@ -368,3 +415,3 @@

const rootItem = expr.path[0];
if (rootIndex === 1) {
if (isAbsolute) {
delete rootItem._artifact;

@@ -379,6 +426,6 @@ delete rootItem._navigation;

let env = rootEnv;
let art = rootItem._artifact;
for (let i = rootIndex; i < expr.path.length; ++i) {
const item = expr.path[i];
art = rewriteItem( expr, config, env, item );
art = rewriteItem( expr, config, env, i );
if (!art)

@@ -593,44 +640,70 @@ return reportAnnoRewriteError( expr, config );

function rewriteItem( expr, config, env, item ) {
const found = setArtifactLink( item, findRewriteTarget( item, env, config.target ));
if (found) {
if (item.id !== found.name.id) {
// Path was rewritten; original token text string is no longer accurate
config.tokenExpr.$tokenTexts = true;
item.id = found.name.id;
}
return found;
/**
* Rewrite the item in `expr.path` at the given index.
* This function may splice the array if more than one path segment
* is replaced by a single item (e.g. in queries).
*
* @param {XSN.Expression} expr
* @param {AnnoRewriteConfig} config
* @param {object} env
* @param {number} index
* @returns {*|null}
*/
function rewriteItem( expr, config, env, index ) {
const item = expr.path[index];
const rewriteTarget = findRewriteTarget( expr, index, env, config.target );
const found = setArtifactLink( item, rewriteTarget[0] );
if (!found)
return null;
if (item.id !== found.name.id) {
// Path was rewritten; original token text string is no longer accurate
config.tokenExpr.$tokenTexts = true;
item.id = found.name.id;
}
return null;
if (rewriteTarget[1] > index)
expr.path.splice(index + 1, rewriteTarget[1] - index);
return rewriteTarget[0];
}
function findRewriteTarget( item, env, target ) {
if (!env.query && env.kind !== 'select')
return env.elements?.[item.id] || null;
function findRewriteTarget( expr, index, env, target ) {
if (env.kind === '$navElement' || env.kind === '$tableAlias') {
const r = firstProjectionForPath( expr.path, index, env, target );
return [ r.elem, r.index ];
}
const item = expr.path[index];
// Not a query -> no $navElement -> use `elements`
if (!env.query && env.kind !== 'select') {
if (env.elements?.[item.id])
return [ env.elements[item.id], index ];
return [ null, expr.path.length ];
}
const items = (env._leadingQuery || env)._combined?.[item.id];
const navs = !items || Array.isArray(items) ? items : [ items ];
const allNavs = !items || Array.isArray(items) ? items : [ items ];
// If the annotation target itself has a table alias, require projections of that
// table alias. Of course, that only works if we're talking about the same query.
const tableAlias = (target._main?._origin === item._artifact._main &&
target.value?.path[0]?._navigation?.kind === '$tableAlias')
? target.value.path[0]._navigation : null;
// Look at all table aliase that could project `item` and only select
// those that have actual projections.
let projected = navs?.filter(p => p._origin === item._artifact && p._projections);
if (!projected || projected.length === 0)
return null;
const navs = allNavs?.filter(p => p._origin === item._artifact &&
(!tableAlias || tableAlias === p._parent));
if (!navs || navs.length === 0)
return [ null, expr.path.length ];
// If the annotation target itself has a table alias, prefer projections
// of that table alias over others when rewriting.
const tableAlias = target.value?.path[0]?._navigation;
if (tableAlias?.kind === '$tableAlias') {
// TODO: Is the _parent always a table alias?
const taProjected = projected.filter(p => p._parent === tableAlias);
if (taProjected.length)
projected = taProjected;
// If there are multiple navigations for the element, just use the first that matches.
// In case of table aliases, it's just one.
for (const nav of navs) {
const r = firstProjectionForPath( expr.path, index, nav._parent, target );
if (r.elem)
return [ r.elem, r.index ];
}
// Of the possible entries, choose the first one
projected = projected[0];
// If there are multiple projections, check if the annotation target is
// projected as well, otherwise, simply take the first one.
return projected._projections.find(proj => proj === target) ||
projected._projections[0] || null;
return [ null, expr.path.length ];
}

@@ -637,0 +710,0 @@ }

@@ -251,4 +251,11 @@ 'use strict';

transform.in = (parent, prop, xpr) => {
evalArgs({ min: 1 }, xpr[1].list, prop);
parent.$In = [ xpr[0], ...xpr[1].list ];
let args = xpr[1].list;
if (!args) {
if (Array.isArray(xpr[1].xpr))
args = xpr[1].xpr;
else
args = [ xpr[1] ];
}
evalArgs({ min: 1 }, args, prop);
parent.$In = [ xpr[0], args ];
delete parent[prop];

@@ -297,5 +304,5 @@ transformExpression(parent, undefined, transform);

transform.$Mul = noOp;
transform['/'] = op('$Div');
transform.$Div = noOp;
// $DivBy, $Mod are functions
transform['/'] = op('$DivBy');
transform.$DivBy = noOp;
// $Div, $Mod are functions
//----------------------------------

@@ -580,2 +587,11 @@ // LITERALS

else {
// Error out for arbitrary types until we know better
// probably todo: Check for reachability of arb type names such as namespace
// reqDef entry etc...
if (typeDef) { // eslint-disable-line no-lonely-if
error('odata-anno-xpr-type', location, {
anno, op: `${xpr}(…)`, type: `${typeDef}`, '#': 'edm',
});
}
/*
typeFacets.forEach((facet) => {

@@ -588,2 +604,3 @@ if (facet.args.length === 1 && facet.args[0].val) {

});
*/
}

@@ -655,4 +672,4 @@

Has: [ twoArgs, dollar ],
$DivBy: twoArgs,
DivBy: [ twoArgs, dollar ],
$Div: twoArgs,
Div: [ twoArgs, dollar ],
$Mod: twoArgs,

@@ -659,0 +676,0 @@ Mod: [ twoArgs, dollar ],

@@ -96,3 +96,4 @@ // Transform XSN (augmented CSN) into CSN

target,
$filtered: value, // assoc+filter
$filtered: value, // assoc+filter v4
$enclosed: value, // comp+filter v5
foreignKeys,

@@ -99,0 +100,0 @@ enum: enumDict,

@@ -920,7 +920,7 @@ // CSN functionality for resolving references

function initColumnElement( col, colIndex, parentElementOrQueryCache ) {
function initColumnElement( col, colIndex, parentElementOrQueryCache, externalElements ) {
if (col === '*')
return;
if (col.inline) {
col.inline.map( c => initColumnElement( c, null, parentElementOrQueryCache ) );
col.inline.map( c => initColumnElement( c, null, parentElementOrQueryCache, externalElements ) );
return;

@@ -940,7 +940,14 @@ }

type = type.items;
if (!type.elements) {
// in OData backend, the sub elements from a column with expand might have
// been “externalized” into a named type. No backward _column link is
// possible this way, of course...
type = artifactRef( type.type );
externalElements = true;
}
const elem = setCache( col, '_element', type.elements[as] );
if (elem) // TODO to.sql: something is strange if this is not set
if (elem && !externalElements) // TODO to.sql: something is strange if `elem` is not set
setCache( elem, '_column', col );
if (col.expand)
col.expand.map( c => initColumnElement( c, null, elem ) );
col.expand.map( c => initColumnElement( c, null, elem, externalElements ) );
}

@@ -947,0 +954,0 @@

@@ -190,3 +190,9 @@ 'use strict';

*/
function attachConstraintsToDependentKeys( dependentKeys, parentKeys, parentTable, sourceAssociation, upLinkFor = null ) {
function attachConstraintsToDependentKeys(
dependentKeys,
parentKeys,
parentTable,
sourceAssociation,
upLinkFor = null
) {
while (dependentKeys.length > 0) {

@@ -197,18 +203,30 @@ const dependentKeyValuePair = dependentKeys.pop();

// this is the case for <up_> associations in on-conditions of compositions
if (Object.prototype.hasOwnProperty.call(dependentKey, '$foreignKeyConstraint'))
const { $foreignKeyConstraint } = dependentKey;
// in contrast to foreign keys which stem from managed associations,
// a tenant foreign key column may have multiple parent keys as partners
const tenantForeignKey = isTenant && dependentKeyValuePair[0] === 'tenant';
if ($foreignKeyConstraint && (!tenantForeignKey || $foreignKeyConstraint.upLinkFor)) {
return;
}
else if ($foreignKeyConstraint && tenantForeignKey) {
parentKeys.pop();
$foreignKeyConstraint.sourceAssociation.push(sourceAssociation);
}
else {
const parentKeyValuePair = parentKeys.pop();
const parentKeyName = parentKeyValuePair[0];
const parentKeyValuePair = parentKeys.pop();
const parentKeyName = parentKeyValuePair[0];
const constraint = {
parentKey: parentKeyName,
parentTable,
upLinkFor,
sourceAssociation,
onDelete: upLinkFor ? 'CASCADE' : 'RESTRICT',
validated,
enforced,
};
dependentKey.$foreignKeyConstraint = constraint;
const constraint = {
parentKey: parentKeyName,
parentTable,
upLinkFor,
sourceAssociation: tenantForeignKey
? [ sourceAssociation ]
: sourceAssociation,
onDelete: upLinkFor ? 'CASCADE' : 'RESTRICT',
validated,
enforced,
};
dependentKey.$foreignKeyConstraint = constraint;
}
}

@@ -478,7 +496,7 @@ }

/**
* Creates the final referential constraints from all dependent key <-> parent key pairs stemming from the same $sourceAssociation
* Creates the final referential constraints from all dependent key <-> parent key pairs stemming from the same sourceAssociation
* and attaches it to the given artifact.
*
* Go over all elements with $foreignKeyConstraint property:
* - Find all other elements in artifact with the same $sourceAssociation
* - Find all other elements in artifact with the same sourceAssociation
* - Create constraints with the information supplied by $parentKey, $parentTable and $onDelete

@@ -491,2 +509,19 @@ *

const referentialConstraints = Object.create(null);
// tenant foreign keys may have multiple parent keys
// process tenant foreign key first
if (isTenant && artifact.elements?.tenant) {
const element = artifact.elements.tenant;
if (element.$foreignKeyConstraint) {
const $foreignKeyConstraint = Object.assign({}, element.$foreignKeyConstraint);
delete element.$foreignKeyConstraint;
// create a foreign key constraint for the tenant column with each association in the dependent entity
$foreignKeyConstraint.sourceAssociation.forEach((sourceAssociation) => {
const copy = Object.assign({}, $foreignKeyConstraint);
copy.sourceAssociation = sourceAssociation;
createReferentialConstraints(copy, 'tenant');
});
}
}
for (const elementName in artifact.elements) {

@@ -499,2 +534,20 @@ const element = artifact.elements[elementName];

delete element.$foreignKeyConstraint;
createReferentialConstraints($foreignKeyConstraint, elementName);
}
if (Object.keys(referentialConstraints).length) {
if (!('$tableConstraints' in artifact))
artifact.$tableConstraints = Object.create(null);
artifact.$tableConstraints.referential = referentialConstraints;
}
/**
* Creates referential constraints for database relationships. This function constructs constraints based on foreign key information and element names,
* and determines deletion rules based on the existing constraints and options. It manages dependencies and names for constraints dynamically during
* execution.
*
* @param {object} $foreignKeyConstraint - An object encapsulating details about the foreign key constraint
* @param {string} elementName - The name of the dependent element or table that is linked by the foreign key.
*/
function createReferentialConstraints($foreignKeyConstraint, elementName) {
const { parentTable } = $foreignKeyConstraint;

@@ -506,6 +559,6 @@ const parentKey = [ $foreignKeyConstraint.parentKey ];

forEach(artifact.elements, (foreignKeyName, foreignKey) => {
// find all other `$foreignKeyConstraint`s with same `$sourceAssociation` and same `parentTable`
// find all other `$foreignKeyConstraint`s with same `sourceAssociation` and same `parentTable`
const matchingForeignKeyFound = foreignKey.$foreignKeyConstraint &&
foreignKey.$foreignKeyConstraint.sourceAssociation === $foreignKeyConstraint.sourceAssociation &&
foreignKey.$foreignKeyConstraint.parentTable === $foreignKeyConstraint.parentTable;
foreignKey.$foreignKeyConstraint.sourceAssociation === $foreignKeyConstraint.sourceAssociation &&
foreignKey.$foreignKeyConstraint.parentTable === $foreignKeyConstraint.parentTable;
if (!matchingForeignKeyFound)

@@ -545,8 +598,2 @@ return;

}
if (Object.keys(referentialConstraints).length) {
if (!('$tableConstraints' in artifact))
artifact.$tableConstraints = Object.create(null);
artifact.$tableConstraints.referential = referentialConstraints;
}
}

@@ -553,0 +600,0 @@ }

@@ -245,3 +245,3 @@ 'use strict';

// setProp(parent, '$structRef', parent.ref);
parent.ref = flattenStructStepsInRef(ref, scopedPath, links, scope, resolvedLinkTypes);
[ parent.ref ] = flattenStructStepsInRef(ref, scopedPath, links, scope, resolvedLinkTypes);
resolved.set(parent, { links, art, scope });

@@ -547,3 +547,3 @@ // Explicitly set implicit alias for things that are now flattened - but only in columns

// Now we need to properly flatten the whole ref
clone.ref = flattenStructStepsInRef(clone.ref, pathToKey);
[ clone.ref ] = flattenStructStepsInRef(clone.ref, pathToKey);
}

@@ -550,0 +550,0 @@ if (!clone.as) {

@@ -954,3 +954,3 @@ 'use strict';

// First, compute the name from the path, e.g ['s', 's1', 's2' ] will result in 'S_s1_s2' ...
const refPath = flattenStructStepsInRef(val.ref, path);
const [ refPath ] = flattenStructStepsInRef(val.ref, path);
// ... and take this as the prefix for all elements

@@ -971,3 +971,3 @@ const flattenedElems = flattenStructuredElement(art, refPath, [], ['definitions', artName, 'elements']);

// The reference is not structured, so just replace it by a ref to the combined prefix path
const refPath = flattenStructStepsInRef(val.ref, path);
const [ refPath ] = flattenStructStepsInRef(val.ref, path);
flattenedIndex.push({ ref: refPath });

@@ -974,0 +974,0 @@ }

@@ -293,2 +293,3 @@ 'use strict';

function flattenAndPrefixExprPaths(carrier, propNames, csnPath, rootPrefix, typeIdx, refParentIsItems = false) {
const refCheck = {

@@ -320,14 +321,35 @@ ref: (elemref, prop, xpr, path) => {

let refChanged = false;
const absolutifier = {
ref : (parent, prop, xpr) => {
const head = xpr[0].id || xpr[0];
if (typeIdx < rootPrefix.length && head === '$self' && !isMagicVariable(head)) {
const [xprHead, ...xprTail] = xpr.slice(1, xpr.length);
if(xprHead) {
if (xprHead.id) {
xprHead.id = rootPrefix.slice(1, typeIdx).concat(xprHead.id).join('_');
parent[prop] = [ xprHead, ...xprTail ];
let isPrefixed = false;
if(!isMagicVariable(head)) {
if (head === '$self' && typeIdx < rootPrefix.length) {
isPrefixed = true;
const [xprHead, ...xprTail] = xpr.slice(1, xpr.length);
if(xprHead) {
if (xprHead.id) {
xprHead.id = rootPrefix.slice(1, typeIdx).concat(xprHead.id).join('_');
parent[prop] = [ xprHead, ...xprTail ];
}
else
parent[prop] = [ rootPrefix.slice(1, typeIdx).concat(xprHead).join('_'), ...xprTail];
}
}
else if (head !== '$self' && !parent.param && rootPrefix.length > 2) {
isPrefixed = true;
const [xprHead, ...xprTail] = xpr;
if (!refParentIsItems) {
if (xprHead.id) {
xprHead.id = rootPrefix.slice(1, -1).concat(xprHead.id).join('_');
parent[prop] = [ xprHead, ...xprTail ];
}
else
parent[prop] = [ rootPrefix.slice(1, -1).concat(xprHead).join('_'), ...xprTail];
}
else
parent[prop] = [ rootPrefix.slice(1, typeIdx).concat(xprHead).join('_'), ...xprTail];
parent[prop] = [ ...rootPrefix.slice(0, rootPrefix.length-1), ...xpr];
}
if(isPrefixed) {
if (carrier.$scope === 'params')

@@ -339,31 +361,17 @@ parent.param = true;

}
else if (rootPrefix.length > 2 && head !== '$self' && !parent.param && !isMagicVariable(head)) {
const [xprHead, ...xprTail] = xpr;
if (!refParentIsItems) {
if (xprHead.id) {
xprHead.id = rootPrefix.slice(1, -1).concat(xprHead.id).join('_');
parent[prop] = [ xprHead, ...xprTail ];
}
else
parent[prop] = [ rootPrefix.slice(1, -1).concat(xprHead).join('_'), ...xprTail];
}
else
parent[prop] = [ ...rootPrefix.slice(0, rootPrefix.length-1), ...xpr];
if (carrier.$scope === 'params')
parent.param = true;
else
parent[prop].unshift('$self');
}
if(isPrefixed)
refChanged = isPrefixed;
}
}
propNames.forEach(pn => {
refChanged = false;
refCheck.anno = pn;
transformExpression(carrier, pn, [ refCheck, refFlattener ], csnPath);
adaptRefs.forEach(fn =>
{ if( fn(refParentIsItems)) refChanged = true });
adaptRefs.length = 0;
transformExpression(carrier, pn, absolutifier, csnPath)
if(refChanged && carrier[pn]['='])
carrier[pn]['='] = true;
});
adaptRefs.forEach(fn => fn(refParentIsItems));
adaptRefs.length = 0;
propNames.forEach(pn => {
transformExpression(carrier, pn, absolutifier, csnPath)
})
}

@@ -443,9 +451,13 @@

Object.keys(member).filter(pn => pn[0] === '@').forEach(pn => {
let refChanged = false;
refCheck.anno = pn;
transformExpression(member, pn, [ refCheck, refFlattener ], csnPath);
adaptRefs.forEach(fn => {
if (fn(true, 1)) refChanged = true });
adaptRefs.length = 0;
if(refChanged && member[pn]['='])
member[pn]['='] = true;
});
}, [ 'definitions', tn ]);
})
adaptRefs.forEach(fn => fn(true, 1));
adaptRefs.length = 0;
}

@@ -475,2 +487,3 @@

ref: (parent, prop, ref, path) => {
let refChanged = false;
const { links, art, scope } = inspectRef(path);

@@ -488,3 +501,3 @@ const resolvedLinkTypes = resolveLinkTypes(links);

// setProp(parent, '$structRef', parent.ref);
parent.ref = flattenStructStepsInRef(ref,
[ parent.ref, refChanged ] = flattenStructStepsInRef(ref,
scopedPath, links, scope, resolvedLinkTypes,

@@ -505,5 +518,6 @@ suspend, suspendPos, parent.$bparam);

parent.as = lastRef;
}
}
return refChanged;
}
return false;
/**

@@ -510,0 +524,0 @@ * Return true if the path points inside columns

@@ -329,3 +329,3 @@ 'use strict';

* @param {bool} [revokeAtSuspendPos] revoke suspension after suspendPos (binding parameter path use case)
* @returns {string[]}
* @returns [string[], bool]
*/

@@ -335,3 +335,3 @@ function flattenStructStepsInRef(ref, path, links, scope, resolvedLinkTypes=new WeakMap(), suspend=false, suspendPos=0, revokeAtSuspendPos=false) {

if (ref.length < 2 || (scope === '$self' && ref.length === 2)) {
return ref;
return [ ref, false ];
}

@@ -347,3 +347,3 @@

if (scope === '$magic')
return ref;
return [ ref, false ];

@@ -359,3 +359,4 @@ // Don't process a leading $self - it will a .art with .elements!

let flattenStep = false;
let refChanged = false
let flattenStep = false;
suspend = !!art('items') || (suspend && i <= suspendPos);

@@ -372,2 +373,3 @@ for(; i < links.length; i++) {

}
refChanged = true;
// suspend flattening if the next path step has some 'items'

@@ -389,3 +391,3 @@ suspend = !!art('items');

}
return result;
return [ result, refChanged ];
}

@@ -392,0 +394,0 @@

@@ -283,3 +283,4 @@ 'use strict';

forEachValue(params, (param) => {
const propagateToParams = typeof param.type === 'string' ? csn.definitions[param.type]?.kind !== 'entity' : true;
const propagateToParams = (param.type !== '$self' || csn.definitions.$self) &&
(typeof param.type !== 'string' || csn.definitions[param.type]?.kind !== 'entity');
propagateMemberPropsFromOrigin(param, {

@@ -343,4 +344,4 @@ '@': !propagateToParams, items: true, elements: true, enum: true, virtual: true,

// For a `type of` with .items, we want to take stuff from types (which we skip for "normal" propagation, see specialItemsRules).
// So for a type of we also propagate stuff from the virtual origin (which we don't give a "kind", therefore skipping that part of the check)
if (target.type && target.type.ref)
// So for a `type of` we also propagate stuff from the virtual origin (which we don't give a "kind", therefore skipping that part of the check)
if (target.type?.ref)
copyProperties(virtualOrigin, target, getMemberPropagationRuleFor, except);

@@ -347,0 +348,0 @@

{
"name": "@sap/cds-compiler",
"version": "4.9.0",
"version": "4.9.2",
"description": "CDS (Core Data Services) compiler and backends",

@@ -5,0 +5,0 @@ "homepage": "https://cap.cloud.sap/",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc