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: deep delete for views without navigation #434

Merged
merged 41 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c6eceb7
test for deep delete fix
larslutz96 Jan 30, 2024
de82ca1
Update SQLService.js
larslutz96 Jan 30, 2024
50d6530
Update SQLService.js
larslutz96 Jan 30, 2024
2f23c30
Update DELETE.test.js
larslutz96 Jan 31, 2024
dc6a9fa
Merge branch 'main' into fix-deep-delete
larslutz96 Jan 31, 2024
fe1b0e8
remove unused lines
larslutz96 Jan 31, 2024
af76a17
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 1, 2024
8d221a6
update test & fix subselect
larslutz96 Feb 2, 2024
60b0088
Merge branch 'fix-deep-delete' of https://github.com/cap-js/cds-dbs i…
larslutz96 Feb 2, 2024
22d9885
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 2, 2024
176e4e3
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 2, 2024
7045ba7
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 5, 2024
cba0175
remove servicem & update test
larslutz96 Feb 6, 2024
3226782
Update SQLService.js
larslutz96 Feb 6, 2024
ff8ba58
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 6, 2024
c72041a
Update DELETE.test.js
larslutz96 Feb 6, 2024
0bde6fc
Update SQLService.js
larslutz96 Feb 6, 2024
944064a
Update SQLService.js
larslutz96 Feb 7, 2024
b516094
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 7, 2024
3b8e822
fix for entitys with no keys
larslutz96 Feb 7, 2024
8c6466f
update testsuite
larslutz96 Feb 12, 2024
ab99535
Update DELETE.test.js
larslutz96 Feb 12, 2024
20e02d7
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 12, 2024
e064521
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 14, 2024
7a2a128
fix: unique alias for scoped subqueries
patricebender Feb 14, 2024
c6a9216
add test
patricebender Feb 14, 2024
a94ddab
Merge remote-tracking branch 'origin/fix-subquery' into fix-deep-delete
larslutz96 Feb 14, 2024
b7a1280
Merge branch 'main' into fix-deep-delete
patricebender Feb 16, 2024
f2a10f0
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 22, 2024
ba65014
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 27, 2024
0226235
delete test
larslutz96 Feb 27, 2024
11b0266
Update DELETE.test.js
larslutz96 Feb 27, 2024
9d7f99d
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 27, 2024
05ca371
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 28, 2024
4b1ef4b
check virtual instead of IsActiveEntity
larslutz96 Feb 28, 2024
95ffd6f
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 28, 2024
ebd0800
remove object.keys
larslutz96 Feb 28, 2024
1b5c740
unify physical elements check
I543501 Feb 29, 2024
4260741
Merge branch 'main' into fix-deep-delete
larslutz96 Feb 29, 2024
225cfd5
update test: child with were clause
I543501 Mar 4, 2024
71796a3
Merge branch 'main' into fix-deep-delete
larslutz96 Mar 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions db-service/lib/SQLService.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const cds = require('@sap/cds/lib'),
DEBUG = cds.debug('sql|db')
const { Readable } = require('stream')
const { resolveView } = require('@sap/cds/libx/_runtime/common/utils/resolveView')
const { resolveView, getDBTable, getTransition } = require('@sap/cds/libx/_runtime/common/utils/resolveView')
const DatabaseService = require('./common/DatabaseService')
const cqn4sql = require('./cqn4sql')

Expand Down Expand Up @@ -192,7 +192,26 @@ class SQLService extends DatabaseService {
// REVISIT: It's not yet 100 % clear under which circumstances we can rely on db constraints
return (super.onDELETE = /* cds.env.features.assert_integrity === 'db' ? this.onSIMPLE : */ deep_delete)
async function deep_delete(/** @type {Request} */ req) {
let { compositions } = req.target
const transitions = getTransition(req.query.target, this)
if (transitions.target !== transitions.queryTarget) {
const targetKeys = transitions.queryTarget.keys
const matchedKeys = Object.keys(targetKeys).filter(key => transitions.mapping.has(key))
const query = DELETE.from({
ref: [
{
id: transitions.target.name,
where: [
{ list: Object.keys(transitions.target.keys || {}).map(k => ({ ref: [k] })) },
'in',
SELECT.from(req.query.DELETE.from).columns(matchedKeys).where(req.query.DELETE.where),
],
},
],
})
return this.onDELETE({ query })
}
const table = getDBTable(req.query.target)
const {compositions} = table
if (compositions) {
// Transform CQL`DELETE from Foo[p1] WHERE p2` into CQL`DELETE from Foo[p1 and p2]`
let { from, where } = req.query.DELETE
Expand All @@ -204,11 +223,11 @@ class SQLService extends DatabaseService {
}
// Process child compositions depth-first
let { depth = 0, visited = [] } = req
visited.push(req.target.name)
visited.push(req.query.target.name)
await Promise.all(
Object.values(compositions).map(c => {
if (c._target['@cds.persistence.skip'] === true) return
if (c._target === req.target) {
if (c._target === req.query.target) {
// the Genre.children case
if (++depth > (c['@depth'] || 3)) return
} else if (visited.includes(c._target.name))
Expand All @@ -219,7 +238,7 @@ class SQLService extends DatabaseService {
)
// Prepare and run deep query, à la CQL`DELETE from Foo[pred]:comp1.comp2...`
const query = DELETE.from({ ref: [...from.ref, c.name] })
return this.onDELETE({ query, depth, visited: [...visited], target: c._target })
return this.onDELETE({ query, depth, visited: [...visited] })
}),
)
}
Expand Down
42 changes: 42 additions & 0 deletions test/compliance/DELETE.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
const cds = require('../../test/cds.js')
const complex = cds.utils.path.resolve(__dirname, '../compliance/resources')
const Root = 'complex.Root'
const GrandChild = 'complex.GrandChild'

describe('DELETE', () => {
const { expect, GET, DELETE } = cds.test(complex)
describe('from', () => {
test('deep delete', async () => {
const inserts = [
INSERT.into(Root).entries([
{
ID: 5,
children: [
{
ID: 6,
children: [
{
ID: 7,
},
],
},
],
},
]),
]
const insertsResp = await cds.run(inserts)
expect(insertsResp[0].affectedRows).to.be.eq(1)

const deepDelete = await DELETE('/comp/RootP(5)')
expect(deepDelete.status).to.be.eq(204)

const root2 = await GET('/comp/RootP')
expect(root2.status).to.be.eq(200)
expect(root2.data.value.length).to.be.eq(0)

const child2 = await GET('/comp/ChildP')
expect(child2.status).to.be.eq(200)
expect(child2.data.value.length).to.be.eq(0)

const grandchild2 = await cds.run(SELECT.from(GrandChild))
expect(grandchild2.length).to.be.eq(0)
})

test.skip('missing', () => {
throw new Error('not supported')
})
Expand Down
20 changes: 20 additions & 0 deletions test/compliance/resources/db/complex/index.cds
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,23 @@ entity Authors {
name : String(111);
books : Association to many Books on books.author = $self;
}


entity Root {
key ID : Integer;
fooRoot: String;
children : Composition of many Child on children.parent = $self;
}

entity Child {
key ID: Integer;
fooChild: String;
parent: Association to one Root;
children: Composition of many GrandChild on children.parent = $self
}

entity GrandChild {
key ID: Integer;
fooGrandChild: String;
parent: Association to one Child;
}
17 changes: 17 additions & 0 deletions test/compliance/resources/srv/index.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using {complex as my} from '../db/complex';

service ComplexService @(path:'/comp') {
entity RootP as
projection on my.Root {
key ID,
fooRoot,
children
};

entity ChildP as
projection on my.Child {
key ID,
fooChild,
parent
}
}