Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: dont use virtual key for UPDATE … where (<key>) in <subquery> #800

Merged
merged 10 commits into from
Sep 12, 2024
4 changes: 3 additions & 1 deletion db-service/lib/cqn4sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ 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.forEach(k => {
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] })

Expand Down
34 changes: 33 additions & 1 deletion db-service/test/cqn4sql/UPDATE.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('UPDATE', () => {
left join bookshop.Books as books on books.author_ID = Authors.ID
where books.title LIKE '%Heights%'
)
`
`,
]
expected.UPDATE.entity = {
as: 'Authors2',
Expand Down Expand Up @@ -169,3 +169,35 @@ describe('UPDATE', () => {
expect(query.UPDATE).to.deep.equal(expected.UPDATE)
})
})
describe('UPDATE with path expression', () => {
let model
beforeAll(async () => {
model = cds.model = await cds.load(__dirname + '/model/update').then(cds.linked)
model = cds.compile.for.nodejs(model)
})

it('with path expressions with draft enabled entity', () => {
const { UPDATE } = cds.ql
let u = UPDATE.entity({ ref: ['bookshop.CatalogService.Books'] }).where(`author.name LIKE '%Bron%'`)

let expected = UPDATE.entity({ ref: ['bookshop.CatalogService.Books'] })

// dont use virtual key `isActiveEntity` in `UPDATE … where (<key>) in <subquery>`
expected.UPDATE.where = [
{ list: [{ ref: ['Books2', 'ID'] }] },
'in',
CQL`
(SELECT Books.ID from bookshop.CatalogService.Books as Books
left join bookshop.CatalogService.Authors as author on author.ID = Books.author_ID
where author.name LIKE '%Bron%'
)
`,
]
expected.UPDATE.entity = {
as: 'Books2',
ref: ['bookshop.CatalogService.Books'],
}
let res = cqn4sql(u, model)
expect(JSON.parse(JSON.stringify(res))).to.deep.equal(JSON.parse(JSON.stringify(expected)))
})
})
23 changes: 23 additions & 0 deletions db-service/test/cqn4sql/model/update.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// dont use virtual key `isActiveEntity` in `UPDATE … where (<key>) in <subquery>`
// in case of path expressions
namespace bookshop;

entity Books {
key ID : Integer;
title : String;
stock : Integer;
author : Association to Authors;
}

entity Authors {
key ID : Integer;
name : String;
alive : Boolean;
}

service CatalogService {
@odata.draft.enabled
entity Books as projection on bookshop.Books;

entity Authors as projection on bookshop.Authors;
}
6 changes: 5 additions & 1 deletion test/bookshop/srv/draft-enabled-service.cds
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using { sap.capire.bookshop as my } from '../db/schema';
service DraftService {
@odata.draft.enabled
entity DraftEnabledBooks
{
key ID : Integer;
title : String;
}
}

@odata.draft.enabled
entity MoreDraftEnabledBooks as projection on my.Books;
}
14 changes: 14 additions & 0 deletions test/scenarios/bookshop/update.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,18 @@ describe('Bookshop - Update', () => {
const res = await UPSERT.into('DraftService.DraftEnabledBooks').entries({ ID: 42, title: 'Foo' })
expect(res).to.equal(1)
})

test('with path expressions on draft enabled service entity', async () => {
// make sure `isActiveEntity` is not used in `UPDATE … where (<key>) in <subquery>`
// as it is a virtual <key>
const { MoreDraftEnabledBooks } = cds.entities('DraftService')
const updateRichardsBooks = UPDATE.entity(MoreDraftEnabledBooks)
.where(`author.name = 'Richard Carpenter'`)
.set('ID = 42')
const selectRichardsBooks = CQL`SELECT * FROM ${MoreDraftEnabledBooks} where author.name = 'Richard Carpenter'`

await cds.run(updateRichardsBooks)
const afterUpdate = await cds.db.run(selectRichardsBooks)
expect(afterUpdate[0]).to.have.property('ID').that.equals(42)
})
})