From 2f3e1c02885a52f66a5e94a3651253394e88a7ed Mon Sep 17 00:00:00 2001 From: I543501 <56645452+larslutz96@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:55:46 +0100 Subject: [PATCH 1/4] Update HANAService.js --- hana/lib/HANAService.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/hana/lib/HANAService.js b/hana/lib/HANAService.js index 7d7f57cfe..d3f1d001f 100644 --- a/hana/lib/HANAService.js +++ b/hana/lib/HANAService.js @@ -338,9 +338,10 @@ class HANAService extends SQLService { // When one of these is defined wrap the query in a sub query if (expand || (parent && (limit || one || orderBy))) { const walkAlias = q => { - if (q.args) return q.as || walkAlias(q.args[0]) + if (q.as) return q.as + if (q.args) return walkAlias(q.args[0]) if (q.SELECT?.from) return walkAlias(q.SELECT?.from) - return q.as + cds.error`Missing alias for subquery` } q.as = walkAlias(q) q.alias = `${parent ? parent.alias + '.' : ''}${q.as}` @@ -510,13 +511,22 @@ class HANAService extends SQLService { // if (col.ref?.length === 1) { col.ref.unshift(parent.as) } if (col.ref?.length > 1) { const colName = this.column_name(col) - if (col.ref[0] !== parent.as) { + if (col.ref[0] !== x.as) { // Inject foreign columns into parent selects (recursively) const as = `$$${col.ref.join('.')}$$` let curPar = parent + const isSource = from => { + if (from.as === col.ref[0]) return true + return from.args?.some(a => { + if (a.args) return isSource(a) + return a.as === col.ref[0] + }) + } + while (curPar) { - if (curPar.SELECT.from?.args?.some(a => a.as === col.ref[0])) { - if (!curPar.SELECT.columns.find(c => c.as === as)) curPar.SELECT.columns.push({ __proto__: col, ref: col.ref, as }) + if (isSource(curPar.SELECT.from)) { + if (!curPar.SELECT.columns.find(c => c.as === as)) + curPar.SELECT.columns.push({ __proto__: col, ref: col.ref, as }) break } else { curPar.SELECT.columns.push({ __proto__: col, ref: [curPar.SELECT.parent.as, as], as }) From 390491e1c32d29e483dfad916e91e75af00c94c8 Mon Sep 17 00:00:00 2001 From: Bob den Os Date: Wed, 27 Nov 2024 12:39:49 +0100 Subject: [PATCH 2/4] Do proper source checking and seperate path alias from reference alias --- hana/lib/HANAService.js | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/hana/lib/HANAService.js b/hana/lib/HANAService.js index d3f1d001f..139bf6a08 100644 --- a/hana/lib/HANAService.js +++ b/hana/lib/HANAService.js @@ -333,18 +333,17 @@ class HANAService extends SQLService { } let { limit, one, orderBy, expand, columns = ['*'], localized, count, parent } = q.SELECT - // When one of these is defined wrap the query in a sub query if (expand || (parent && (limit || one || orderBy))) { const walkAlias = q => { - if (q.as) return q.as - if (q.args) return walkAlias(q.args[0]) + if (q.args) return q.as || walkAlias(q.args[0]) if (q.SELECT?.from) return walkAlias(q.SELECT?.from) - cds.error`Missing alias for subquery` + return q.as || cds.error`Missing alias for subquery` } - q.as = walkAlias(q) - q.alias = `${parent ? parent.alias + '.' : ''}${q.as}` + const alias = q.as // Use query alias as path name + q.as = walkAlias(q) // Use from alias for query re use alias + q.alias = `${parent ? parent.alias + '.' : ''}${alias || q.as}` const src = q const { element, elements } = q @@ -511,10 +510,7 @@ class HANAService extends SQLService { // if (col.ref?.length === 1) { col.ref.unshift(parent.as) } if (col.ref?.length > 1) { const colName = this.column_name(col) - if (col.ref[0] !== x.as) { - // Inject foreign columns into parent selects (recursively) - const as = `$$${col.ref.join('.')}$$` - let curPar = parent + if (!parent.SELECT.columns.some(c => this.column_name(c) === colName)) { const isSource = from => { if (from.as === col.ref[0]) return true return from.args?.some(a => { @@ -523,21 +519,32 @@ class HANAService extends SQLService { }) } + // Inject foreign columns into parent selects (recursively) + const as = `$$${col.ref.join('.')}$$` + let rename = col.ref[0] !== parent.as + let curPar = parent while (curPar) { if (isSource(curPar.SELECT.from)) { - if (!curPar.SELECT.columns.find(c => c.as === as)) - curPar.SELECT.columns.push({ __proto__: col, ref: col.ref, as }) + if (curPar.SELECT.columns.find(c => c.as === as)) { + rename = true + } else { + rename = rename || curPar === parent + curPar.SELECT.columns.push(rename ? { __proto__: col, ref: col.ref, as } : { __proto__: col, ref: [...col.ref] }) + } break } else { curPar.SELECT.columns.push({ __proto__: col, ref: [curPar.SELECT.parent.as, as], as }) curPar = curPar.SELECT.parent } } - col.as = colName - col.ref = [parent.as, as] - } else if (!parent.SELECT.columns.some(c => this.column_name(c) === colName)) { - // Inject local columns into parent select - parent.SELECT.columns.push({ __proto__: col }) + if (rename) { + col.as = colName + col.ref = [parent.as, as] + } else { + col.ref = [parent.as, colName] + } + } else { + col.ref[1] = colName } } }) From 80037c563fbfe9a514b7f039e34489618a15b6a5 Mon Sep 17 00:00:00 2001 From: I543501 <56645452+larslutz96@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:31:14 +0100 Subject: [PATCH 3/4] Update read.test.js --- test/scenarios/bookshop/read.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/scenarios/bookshop/read.test.js b/test/scenarios/bookshop/read.test.js index 3fcbb1d04..622357b39 100644 --- a/test/scenarios/bookshop/read.test.js +++ b/test/scenarios/bookshop/read.test.js @@ -79,6 +79,21 @@ describe('Bookshop - Read', () => { expect(res.data.value.every(row => row.author.name)).to.be.true }) + test('groupby with multiple path expressions', async () => { + const res = await GET('/admin/A?$apply=groupby((toB/toC/ID,toC/toB/ID))', admin) + expect(res.status).to.be.eq(200) + }) + + test('groupby with multiple path expressions and orderby', async () => { + const res = await GET('/admin/A?$apply=groupby((toB/toC/ID,toB/toC/ID))&$orderby=toB/toC/ID', admin) + expect(res.status).to.be.eq(200) + }) + + test('groupby with multiple path expressions and filter', async () => { + const res = await GET('/admin/A?$apply=groupby((toB/toC/ID,toB/toC/ID))&$filter=ID eq 1', admin) + expect(res.status).to.be.eq(200) + }) + test('Path expression', async () => { const q = CQL`SELECT title, author.name as author FROM sap.capire.bookshop.Books where author.name LIKE '%a%'` const res = await cds.run(q) From 781702f9f92c65432de86c8fd5e862f20e7396bf Mon Sep 17 00:00:00 2001 From: I543501 <56645452+larslutz96@users.noreply.github.com> Date: Thu, 28 Nov 2024 13:00:45 +0100 Subject: [PATCH 4/4] Update admin-service.cds --- test/bookshop/srv/admin-service.cds | 1 + 1 file changed, 1 insertion(+) diff --git a/test/bookshop/srv/admin-service.cds b/test/bookshop/srv/admin-service.cds index fd36161f5..96a80f0bd 100644 --- a/test/bookshop/srv/admin-service.cds +++ b/test/bookshop/srv/admin-service.cds @@ -2,6 +2,7 @@ using { sap.capire.bookshop as my } from '../db/schema'; service AdminService @(requires:'admin', path:'/admin') { entity Books as projection on my.Books; entity Authors as projection on my.Authors; + entity A as projection on my.A; @cds.redirection.target: false entity RenameKeys as projection on my.Books {