Skip to content

Commit 797b6e1

Browse files
committed
support update / delete
1 parent f589292 commit 797b6e1

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

db-service/lib/cqn4sql.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ function cqn4sql(originalQuery, model) {
8383
transformedProp.where = getTransformedTokenStream(where)
8484
}
8585

86+
const queryNeedsJoins = inferred.joinTree && !inferred.joinTree.isInitial
8687
// Transform the from clause: association path steps turn into `WHERE EXISTS` subqueries.
8788
// The already transformed `where` clause is then glued together with the resulting subqueries.
8889
const { transformedWhere, transformedFrom } = getTransformedFrom(from || entity, transformedProp.where)
89-
const queryNeedsJoins = inferred.joinTree && !inferred.joinTree.isInitial
9090

9191
if (inferred.SELECT) {
9292
transformedQuery = transformSelectQuery(queryProp, transformedFrom, transformedWhere, transformedQuery)
@@ -1721,8 +1721,13 @@ function cqn4sql(originalQuery, model) {
17211721
}
17221722

17231723
// only append infix filter to outer where if it is the leaf of the from ref
1724-
if (refReverse[0].where)
1725-
filterConditions.push(getTransformedTokenStream(refReverse[0].where, $refLinksReverse[0]))
1724+
if (refReverse[0].where) {
1725+
const whereIsTransformedLater = (inferred.joinTree && !inferred.joinTree.isInitial) && (originalQuery.DELETE || originalQuery.UPDATE)
1726+
if (whereIsTransformedLater)
1727+
filterConditions.push(refReverse[0].where)
1728+
else
1729+
filterConditions.push(getTransformedTokenStream(refReverse[0].where, $refLinksReverse[0]))
1730+
}
17261731

17271732
if (existingWhere.length > 0) filterConditions.push(existingWhere)
17281733
if (whereExistsSubSelects.length > 0) {

db-service/test/cqn4sql/where-exists.test.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,4 +1720,71 @@ describe('path expression within infix filter following exists predicate', () =>
17201720
)`,
17211721
)
17221722
})
1723+
1724+
it('renders inner joins for the path expression at the leaf of scoped queries (DELETE)', () => {
1725+
// subquery has flat author_ID, which is not part of client csn
1726+
const forNodeModel = cds.compile.for.nodejs(JSON.parse(JSON.stringify(cds.model)))
1727+
let query = DELETE.from('bookshop.Authors:books[genre.name = null]')
1728+
1729+
const transformed = cqn4sql(query, forNodeModel)
1730+
const subquery = cds.ql`
1731+
SELECT books.ID from bookshop.Books as books
1732+
inner join bookshop.Genres as genre on genre.ID = books.genre_ID
1733+
WHERE EXISTS (
1734+
SELECT 1 from bookshop.Authors as Authors where Authors.ID = books.author_ID
1735+
) and genre.name = null`
1736+
const expected = DELETE.from('bookshop.Books').alias('books2')
1737+
expected.DELETE.where = [ { list: [ {ref: ['books2', 'ID'] }] }, 'in', subquery ]
1738+
expect(transformed).to.deep.equal( expected )
1739+
})
1740+
it('renders inner joins for the path expression at the leaf of scoped queries, two assocs (DELETE)', () => {
1741+
// subquery has flat author_ID, which is not part of client csn
1742+
const forNodeModel = cds.compile.for.nodejs(JSON.parse(JSON.stringify(cds.model)))
1743+
let query = DELETE.from('bookshop.Authors:books[genre.parent.name = null]')
1744+
1745+
const transformed = cqn4sql(query, forNodeModel)
1746+
const subquery = cds.ql`
1747+
SELECT books.ID from bookshop.Books as books
1748+
inner join bookshop.Genres as genre on genre.ID = books.genre_ID
1749+
inner join bookshop.Genres as parent on parent.ID = genre.parent_ID
1750+
WHERE EXISTS (
1751+
SELECT 1 from bookshop.Authors as Authors where Authors.ID = books.author_ID
1752+
) and parent.name = null`
1753+
const expected = DELETE.from('bookshop.Books').alias('books2')
1754+
expected.DELETE.where = [ { list: [ {ref: ['books2', 'ID'] }] }, 'in', subquery ]
1755+
expect(transformed).to.deep.equal( expected )
1756+
})
1757+
it('renders inner joins for the path expression at the leaf of scoped queries (UPDATE)', () => {
1758+
// subquery has flat author_ID, which is not part of client csn
1759+
const forNodeModel = cds.compile.for.nodejs(JSON.parse(JSON.stringify(cds.model)))
1760+
let query = UPDATE.entity('bookshop.Authors:books[genre.name = null]')
1761+
1762+
const transformed = cqn4sql(query, forNodeModel)
1763+
const subquery = cds.ql`
1764+
SELECT books.ID from bookshop.Books as books
1765+
inner join bookshop.Genres as genre on genre.ID = books.genre_ID
1766+
WHERE EXISTS (
1767+
SELECT 1 from bookshop.Authors as Authors where Authors.ID = books.author_ID
1768+
) and genre.name = null`
1769+
const expected = UPDATE.entity('bookshop.Books').alias('books2')
1770+
expected.UPDATE.where = [ { list: [ {ref: ['books2', 'ID'] }] }, 'in', subquery ]
1771+
expect(transformed).to.deep.equal( expected )
1772+
})
1773+
it('renders inner joins for the path expression at the leaf of scoped queries, two assocs (DELETE)', () => {
1774+
// subquery has flat author_ID, which is not part of client csn
1775+
const forNodeModel = cds.compile.for.nodejs(JSON.parse(JSON.stringify(cds.model)))
1776+
let query = UPDATE.entity('bookshop.Authors:books[genre.parent.name = null]')
1777+
1778+
const transformed = cqn4sql(query, forNodeModel)
1779+
const subquery = cds.ql`
1780+
SELECT books.ID from bookshop.Books as books
1781+
inner join bookshop.Genres as genre on genre.ID = books.genre_ID
1782+
inner join bookshop.Genres as parent on parent.ID = genre.parent_ID
1783+
WHERE EXISTS (
1784+
SELECT 1 from bookshop.Authors as Authors where Authors.ID = books.author_ID
1785+
) and parent.name = null`
1786+
const expected = UPDATE.entity('bookshop.Books').alias('books2')
1787+
expected.UPDATE.where = [ { list: [ {ref: ['books2', 'ID'] }] }, 'in', subquery ]
1788+
expect(transformed).to.deep.equal( expected )
1789+
})
17231790
})

0 commit comments

Comments
 (0)