From 6525aca85ae22974d9ab0270254d529fba35fbb2 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Thu, 12 Sep 2024 16:35:50 +0200 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20use=20`for=20=E2=80=A6=20of`=20+?= =?UTF-8?q?=20`if`=20instead=20of=20arrow=20func=20chaining?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [cap/dev] etc/perf.js for (each of keys) if ... 196 ms for (each of keys) || ... 188 ms keys.filter.forEach (...) 323 ms --- db-service/lib/cqn4sql.js | 42 +++++++++++++++-------------------- db-service/lib/infer/index.js | 18 +++++++++------ 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/db-service/lib/cqn4sql.js b/db-service/lib/cqn4sql.js index 21e929ac9..f3d92fc10 100644 --- a/db-service/lib/cqn4sql.js +++ b/db-service/lib/cqn4sql.js @@ -132,15 +132,12 @@ function cqn4sql(originalQuery, model) { const queryTarget = Object.values(inferred.sources)[0].definition const keys = Object.values(queryTarget.elements).filter(e => e.key === true) const primaryKey = { list: [] } - keys - .filter(k => !k.virtual) // e.g. draft column `isActiveEntity` is virtual and key - .forEach(k => { - // cqn4sql will add the table alias to the column later, no need to add it here - subquery.SELECT.columns.push({ ref: [k.name] }) - - // add the alias of the main query to the list of primary key references - primaryKey.list.push({ ref: [transformedFrom.as, k.name] }) - }) + for (const k of keys) { + if (!k.virtual) { + subquery.SELECT.columns.push({ ref: [k.name] }) + primaryKey.list.push({ ref: [transformedFrom.as, k.name] }) + } + } const transformedSubquery = cqn4sql(subquery, model) @@ -1069,13 +1066,12 @@ function cqn4sql(originalQuery, model) { */ function getColumnsForWildcard(exclude = [], replace = [], baseName = null) { const wildcardColumns = [] - Object.keys(inferred.$combinedElements) - .filter(k => !exclude.includes(k)) - .forEach(k => { + for (const k of Object.keys(inferred.$combinedElements)) { + if (!exclude.includes(k)) { const { index, tableAlias } = inferred.$combinedElements[k][0] const element = tableAlias.elements[k] // ignore FK for odata csn / ignore blobs from wildcard expansion - if (isManagedAssocInFlatMode(element) || element.type === 'cds.LargeBinary') return + if (isManagedAssocInFlatMode(element) || element.type === 'cds.LargeBinary') continue // for wildcard on subquery in from, just reference the elements if (tableAlias.SELECT && !element.elements && !element.target) { wildcardColumns.push(index ? { ref: [index, k] } : { ref: [k] }) @@ -1091,7 +1087,8 @@ function cqn4sql(originalQuery, model) { ) wildcardColumns.push(...flatColumns) } - }) + } + } return wildcardColumns /** @@ -1421,12 +1418,12 @@ function cqn4sql(originalQuery, model) { const keys = def.keys // use key aspect on entity const keyValComparisons = [] const flatKeys = [] - Object.values(keys) - // up__ID already part of inner where exists, no need to add it explicitly here - .filter(k => k !== backlinkFor($baseLink.definition)?.[0]) - .forEach(v => { + for (const v of Object.values(keys)) { + if (v !== backlinkFor($baseLink.definition)?.[0]) { + // up__ID already part of inner where exists, no need to add it explicitly here flatKeys.push(...getFlatColumnsFor(v, { tableAlias: $baseLink.alias })) - }) + } + } if (flatKeys.length > 1) throw new Error('Filters can only be applied to managed associations which result in a single foreign key') flatKeys.forEach(c => keyValComparisons.push([...[c, '=', token]])) @@ -1586,10 +1583,7 @@ function cqn4sql(originalQuery, model) { if (!def.$refLinks) return def const leaf = def.$refLinks[def.$refLinks.length - 1] const first = def.$refLinks[0] - const tableAlias = getTableAlias( - def, - def.ref.length > 1 && first.definition.isAssociation ? first : $baseLink, - ) + const tableAlias = getTableAlias(def, def.ref.length > 1 && first.definition.isAssociation ? first : $baseLink) if (leaf.definition.parent.kind !== 'entity') // we need the base name return getFlatColumnsFor(leaf.definition, { @@ -1855,7 +1849,7 @@ function cqn4sql(originalQuery, model) { result[i] = asXpr(xpr) continue } - if(lhs.args) { + if (lhs.args) { const args = calculateOnCondition(lhs.args) result[i] = { ...lhs, args } continue diff --git a/db-service/lib/infer/index.js b/db-service/lib/infer/index.js index 704099822..c02ac1496 100644 --- a/db-service/lib/infer/index.js +++ b/db-service/lib/infer/index.js @@ -170,7 +170,8 @@ function infer(originalQuery, model) { if (list) list.forEach(arg => attachRefLinksToArg(arg, $baseLink, expandOrExists)) if (!ref) return init$refLinks(arg) - ref.forEach((step, i) => { + let i = 0 + for (const step of ref) { const id = step.id || step if (i === 0) { // infix filter never have table alias @@ -231,7 +232,8 @@ function infer(originalQuery, model) { step.where.forEach(walkTokenStream) } else throw new Error('A filter can only be provided when navigating along associations') } - }) + i += 1 + } const { definition, target } = arg.$refLinks[arg.$refLinks.length - 1] if (definition.value) { // nested calculated element @@ -1046,15 +1048,17 @@ function infer(originalQuery, model) { if (Object.keys(queryElements).length === 0 && aliases.length === 1) { const { elements } = getDefinitionFromSources(sources, aliases[0]) // only one query source and no overwritten columns - Object.keys(elements) - .filter(k => !exclude(k)) - .forEach(k => { + for (const k of Object.keys(elements)) { + if (!exclude(k)) { const element = elements[k] - if (element.type !== 'cds.LargeBinary') queryElements[k] = element + if (element.type !== 'cds.LargeBinary') { + queryElements[k] = element + } if (element.value) { linkCalculatedElement(element) } - }) + } + } return } From f581632c1a74bd79c498bab89b6400832d470fb5 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Mon, 23 Sep 2024 15:12:45 +0200 Subject: [PATCH 2/2] two more --- db-service/lib/cqn4sql.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/db-service/lib/cqn4sql.js b/db-service/lib/cqn4sql.js index f3d92fc10..284724b3f 100644 --- a/db-service/lib/cqn4sql.js +++ b/db-service/lib/cqn4sql.js @@ -130,12 +130,12 @@ function cqn4sql(originalQuery, model) { // calculate the primary keys of the target entity, there is always exactly // one query source for UPDATE / DELETE const queryTarget = Object.values(inferred.sources)[0].definition - const keys = Object.values(queryTarget.elements).filter(e => e.key === true) const primaryKey = { list: [] } - for (const k of keys) { - if (!k.virtual) { - subquery.SELECT.columns.push({ ref: [k.name] }) - primaryKey.list.push({ ref: [transformedFrom.as, k.name] }) + for (const k of Object.keys(queryTarget.elements)) { + const e = queryTarget.elements[k] + if (e.key === true && !e.virtual) { + subquery.SELECT.columns.push({ ref: [e.name] }) + primaryKey.list.push({ ref: [transformedFrom.as, e.name] }) } } @@ -809,10 +809,12 @@ function cqn4sql(originalQuery, model) { // `SELECT from Authors { books.genre as genreOfBooks { name } } becomes `SELECT from Books:genre as genreOfBooks` const from = { ref: subqueryFromRef, as: uniqueSubqueryAlias } - const subqueryBase = Object.fromEntries( - // preserve all props on subquery (`limit`, `order by`, …) but `expand` and `ref` - Object.entries(column).filter(([key]) => !(key in { ref: true, expand: true })), - ) + const subqueryBase = {} + for (const [key, value] of Object.entries(column)) { + if (!(key in { ref: true, expand: true })) { + subqueryBase[key] = value; + } + } const subquery = { SELECT: { ...subqueryBase,