🚨 Latest Research:Tanstack npm Packages Compromised in Ongoing Mini Shai-Hulud Supply-Chain Attack.Learn More β†’
Socket
Book a DemoSign in
Socket

@cap-js/db-service

Package Overview
Dependencies
Maintainers
2
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cap-js/db-service - npm Package Compare versions

Comparing version
2.6.0
to
2.7.0
+13
-0
CHANGELOG.md

@@ -7,2 +7,15 @@ # Changelog

## [2.7.0](https://github.com/cap-js/cds-dbs/compare/db-service-v2.6.0...db-service-v2.7.0) (2025-11-26)
### Added
* `error` standard function ([#1421](https://github.com/cap-js/cds-dbs/issues/1421)) ([b1b0fca](https://github.com/cap-js/cds-dbs/commit/b1b0fca00387c45ed91280b2df4282be90ea0a6e))
### Fixed
* LimitedRank with compositions ([#1391](https://github.com/cap-js/cds-dbs/issues/1391)) ([31766cd](https://github.com/cap-js/cds-dbs/commit/31766cd8f9b626d090129b174ac9a04b4d578c21))
* reject nested projection if duplicated ([#1411](https://github.com/cap-js/cds-dbs/issues/1411)) ([6e924c9](https://github.com/cap-js/cds-dbs/commit/6e924c9942de6e6a4abf7b2c168d4378efcaefa9))
## [2.6.0](https://github.com/cap-js/cds-dbs/compare/db-service-v2.5.1...db-service-v2.6.0) (2025-10-23)

@@ -9,0 +22,0 @@

@@ -8,2 +8,44 @@ 'use strict'

/**
* Generates SQL statement that produces a runtime compatible error object
* @param {string|object} message - The i18n key or message of the error object
* @param {Array<xpr>} args - The arguments to apply to the i18n string
* @param {Array<xpr>} targets - The name of the element that the error is related to
* @return {string} - SQL statement
*/
error: function (message, args, targets) {
targets = targets && (targets.list || (targets.val || targets.ref) && [targets])
if (Array.isArray(targets)) targets = targets.map(e => e.ref && { val: e.ref.at(-1) } || e)
args = args && (args.list || (args.val || args.ref) && [args])
return `(${this.SELECT({
SELECT: {
expand: 'root',
columns: [
{
__proto__: (message || { val: null }),
as: 'message',
},
args ? {
func: 'json_array',
args: args,
as: 'args',
element: cds.builtin.types.Map,
} : { val: null, as: 'args' },
targets ? {
func: 'json_array',
args: targets,
as: 'targets',
element: cds.builtin.types.Map,
} : { val: null, as: 'targets' },
]
},
elements: {
message: cds.builtin.types.String,
args: cds.builtin.types.Map,
targets: cds.builtin.types.Map,
}
})})`
},
/**
* Generates SQL statement that produces a boolean value indicating whether the search term is contained in the given columns

@@ -10,0 +52,0 @@ * @param {string} ref - The reference object containing column information

+2
-2

@@ -328,3 +328,3 @@ const cds = require('@sap/cds')

LimitedDescendantCount: { xpr: [{ ref: ['HIERARCHY_TREE_SIZE'] }, '-', { val: 1, param: false }], as: 'LimitedDescendantCount' },
LimitedRank: { xpr: [{ func: 'row_number', args: [] }, 'OVER', { xpr: [] }, '-', { val: 1, param: false }], as: 'LimitedRank' }
LimitedRank: { xpr: [{ func: 'row_number', args: [] }, 'OVER', { xpr: ['ORDER', 'BY', { ref: ['HIERARCHY_RANK'] }, 'ASC'] }, '-', { val: 1, param: false }], as: 'LimitedRank' }
}

@@ -1330,3 +1330,3 @@

}
const fn = this.class.Functions[func]?.apply(this, args) || `${func}(${args})`
const fn = this.class.Functions[func]?.apply(this, Array.isArray(args) ? args: [args]) || `${func}(${args})`
if (xpr) return `${fn} ${this.xpr({ xpr })}`

@@ -1333,0 +1333,0 @@ return fn

@@ -50,3 +50,2 @@ 'use strict'

const sources = inferTarget(_.into || _.from || _.entity, {}) // IMPORTANT: _.into has to go before _.from for INSERT.into().from(SELECT)
const joinTree = new JoinTree(sources)
const aliases = Object.keys(sources)

@@ -76,3 +75,2 @@ const target = aliases.length === 1 ? getDefinitionFromSources(sources, aliases[0]) : originalQuery

elements: { value: elements, writable: true, configurable: true },
joinTree: { value: joinTree, writable: true, configurable: true }, // REVISIT: eliminate
})

@@ -101,2 +99,6 @@ // also enrich original query -> writable because it may be inferred again

const { ref } = from
// Given a from clause `Root:parent[$main.name = name].parent as Foo`
// we need to first resolve until to the last step of the from.ref
// before we can replace $main with `Foo`
const $mainLazyResolve = [] // TODO: remove and replace with real alias breakout
if (ref) {

@@ -117,3 +119,3 @@ const { id, args } = ref[0]

inferArg(from, null, null, { inFrom: true })
inferArg(from, null, null, { inFrom: true, $mainLazyResolve })
const alias =

@@ -144,2 +146,6 @@ from.uniqueSubqueryAlias ||

}
const joinTree = new JoinTree(querySources)
Object.defineProperty( inferred, 'joinTree', { value: joinTree, writable: true, configurable: true } )
for(const lazyRef of $mainLazyResolve) inferArg(lazyRef)
return querySources

@@ -209,3 +215,3 @@ }

if (as === undefined) cds.error`Expecting expression to have an alias name`
if (queryElements[as]) cds.error`Duplicate definition of element β€œ${as}”`
if (queryElements[as]) rejectDuplicatedElement(as)
if (col.xpr || col.SELECT) {

@@ -431,3 +437,4 @@ queryElements[as] = getElementForXprOrSubquery(col, queryElements, dollarSelfRefs)

let firstStepIsTableAlias, firstStepIsSelf, expandOnTableAlias
if (!inFrom) {
const firstStepIsDollarMain = arg.ref.length > 1 && arg.ref[0] === '$main'
if (!inFrom && !firstStepIsDollarMain) {
firstStepIsTableAlias = arg.ref.length > 1 && arg.ref[0] in sources

@@ -437,2 +444,3 @@ firstStepIsSelf = !firstStepIsTableAlias && arg.ref.length > 1 && ['$self', '$projection'].includes(arg.ref[0])

}
if (dollarSelfRefs && firstStepIsSelf) {

@@ -449,6 +457,16 @@ defineProperty(arg, 'inXpr', true)

let pseudoPath = false
arg.ref.forEach((step, i) => {
for(let i = 0; i < arg.ref.length; i++) {
const step = arg.ref[i]
const id = step.id || step
if (i === 0) {
if (id in pseudos.elements) {
if(firstStepIsDollarMain) {
if(inFrom) { // we need to resolve the full from clause first
context.$mainLazyResolve.push(arg)
return; // this will be done once the from clause is fully resolved
} else {
// replace $main with the alias of the outermost query
const mainAlias = getMainAlias(inferred)
arg.$refLinks.push(Object.assign(mainAlias, {$main: true}))
}
} else if (id in pseudos.elements) {
// pseudo path

@@ -581,2 +599,3 @@ arg.$refLinks.push({ definition: pseudos.elements[id], target: pseudos })

inferArg(token, false, arg.$refLinks[i], {
...context,
inExists: skipJoinsForFilter || inExists,

@@ -599,3 +618,4 @@ inXpr: !!token.xpr,

arg.$refLinks[i].alias = !arg.ref[i + 1] && arg.as ? arg.as : id.split('.').pop()
if(!arg.$refLinks[i].$main)
arg.$refLinks[i].alias = !arg.ref[i + 1] && arg.as ? arg.as : id.split('.').pop()
if (hasOwnSkip(getDefinition(arg.$refLinks[i].definition.target))) isPersisted = false

@@ -616,5 +636,13 @@ if (!arg.ref[i + 1]) {

else elementName = arg.as || flatName
if (queryElements) queryElements[elementName] = elements
if (queryElements) {
if (queryElements[elementName] !== undefined)
rejectDuplicatedElement(elementName)
queryElements[elementName] = elements
}
} else if (arg.inline && queryElements) {
const elements = resolveInline(arg)
for (const elName in elements) {
if (queryElements[elName] !== undefined) rejectDuplicatedElement(elName)
}
Object.assign(queryElements, elements)

@@ -641,3 +669,3 @@ } else {

if (queryElements[elementName] !== undefined)
throw new Error(`Duplicate definition of element β€œ${elementName}”`)
rejectDuplicatedElement(elementName)
const element = getCopyWithAnnos(arg, leafArt)

@@ -648,4 +676,3 @@ queryElements[elementName] = element

}
})
}
// we need inner joins for the path expressions inside filter expressions after exists predicate

@@ -673,3 +700,5 @@ if ($baseLink?.pathExpressionInsideFilter) defineProperty(arg, 'join', 'inner')

defineProperty(arg, 'isJoinRelevant', true)
joinTree.mergeColumn(colWithBase, originalQuery.outerQueries)
// join resolved in outer query
if(!(arg.$refLinks[0].$main && originalQuery.outerQueries))
inferred.joinTree.mergeColumn(colWithBase, originalQuery.outerQueries)
}

@@ -825,2 +854,6 @@ }

}
function rejectDuplicatedElement(elementName) {
throw new Error(`Duplicate definition of element β€œ${elementName}”`)
}
function linkCalculatedElement(column, baseLink, baseColumn, context = {}) {

@@ -920,3 +953,3 @@ const calcElement = column.$refLinks?.[column.$refLinks.length - 1].definition || column

defineProperty(step, 'isJoinRelevant',true)
joinTree.mergeColumn(p, originalQuery.outerQueries)
inferred.joinTree.mergeColumn(p, originalQuery.outerQueries)
} else {

@@ -1180,2 +1213,10 @@ // we need to explicitly set the value to false in this case,

function getMainAlias (query) {
let mainAlias
if (query.outerQueries) mainAlias = query.outerQueries[0].SELECT?.from.$refLinks.at(-1)
else mainAlias = query.SELECT?.from.$refLinks.at(-1)
if(!mainAlias) throw new Error('Cannot determine main query source for $main, please report this')
return mainAlias
}
module.exports = infer
{
"name": "@cap-js/db-service",
"version": "2.6.0",
"version": "2.7.0",
"description": "CDS base database service",

@@ -30,5 +30,5 @@ "homepage": "https://github.com/cap-js/cds-dbs/tree/main/db-service#cds-base-database-service",

"peerDependencies": {
"@sap/cds": ">=9"
"@sap/cds": ">=9.4.5"
},
"license": "Apache-2.0"
}

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