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

feat: strict mode to validate input for INSERT, UPDATE and UPSERT #384

Merged
merged 28 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8be2c8d
strict mode and test
larslutz96 Dec 13, 2023
ff2edc6
Update SQLService.js
larslutz96 Dec 13, 2023
cf6de09
require test
larslutz96 Dec 14, 2023
7539475
Update SQLService.js
larslutz96 Dec 14, 2023
ba0b49a
add next
larslutz96 Dec 14, 2023
a9f0b2c
Update strictMode.test.js
larslutz96 Dec 14, 2023
b1294fc
Update strictMode.test.js
larslutz96 Dec 15, 2023
99aff6d
move test to general
larslutz96 Dec 15, 2023
e71bb4a
Merge branch 'main' into feat-strict-mode
larslutz96 Dec 15, 2023
bd58498
remove http error statusCode
larslutz96 Dec 15, 2023
51b40a7
Update SQLService.js
I543501 Dec 18, 2023
ccd3da7
Merge branch 'main' into feat-strict-mode
larslutz96 Dec 18, 2023
d4d0451
Merge branch 'main' into feat-strict-mode
larslutz96 Dec 20, 2023
f2f4e4e
remove strictMode test from general/sqlite and add to compliance
larslutz96 Dec 22, 2023
fcb398e
Merge branch 'main' into feat-strict-mode
larslutz96 Dec 22, 2023
0e10359
Merge branch 'main' into feat-strict-mode
larslutz96 Jan 15, 2024
6c3e140
using namespace instead of service
larslutz96 Jan 15, 2024
a7e4eff
Create index.cds
larslutz96 Jan 15, 2024
48655a3
Merge branch 'main' into feat-strict-mode
larslutz96 Jan 15, 2024
8cfea4b
Merge branch 'main' into feat-strict-mode
larslutz96 Jan 22, 2024
1981939
update service.js & test
larslutz96 Jan 23, 2024
53986e8
Merge branch 'feat-strict-mode' of https://github.com/cap-js/cds-dbs …
larslutz96 Jan 23, 2024
e705c4b
Update SQLService.js
larslutz96 Jan 23, 2024
756619f
Update SQLService.js
larslutz96 Jan 23, 2024
beb6e88
Merge branch 'main' into feat-strict-mode
larslutz96 Jan 23, 2024
9e7d9d9
Update strictMode.test.js
larslutz96 Jan 23, 2024
be12f28
Update db-service/lib/SQLService.js
larslutz96 Jan 24, 2024
1236000
Merge branch 'main' into feat-strict-mode
larslutz96 Jan 30, 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
20 changes: 20 additions & 0 deletions db-service/lib/SQLService.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ class SQLService extends DatabaseService {
init() {
this.on(['INSERT', 'UPSERT', 'UPDATE'], require('./fill-in-keys')) // REVISIT should be replaced by correct input processing eventually
this.on(['INSERT', 'UPSERT', 'UPDATE'], require('./deep-queries').onDeep)
if (cds.env.features.db_strict) {
this.on(['INSERT', 'UPSERT', 'UPDATE'], ({ query }, next) => {
const kind = query.kind || Object.keys(query)[0]
const operation = query[kind]
if (!operation.columns && !operation.entries && !operation.data) return next()
const columns =
operation.columns ||
Object.keys(
operation.entries?.reduce((acc, obj) => {
return Object.assign(acc, obj)
}, {}) || operation.data,
)
const invalidColumns = columns.filter(c => !query.target?.elements?.[c])

if (invalidColumns.length > 0) {
cds.error(`STRICT MODE: Trying to ${kind} non existent columns (${invalidColumns})`)
}
return next()
})
}
this.on(['SELECT'], this.onSELECT)
this.on(['INSERT'], this.onINSERT)
this.on(['UPSERT'], this.onUPSERT)
Expand Down
5 changes: 5 additions & 0 deletions test/compliance/resources/srv/index.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using {complex} from '../db/index.cds';

service ComplianceService {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really required ?

entity Books as projection on complex.Books;
}
120 changes: 120 additions & 0 deletions test/compliance/strictMode.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
const cds = require('../cds.js')

describe('strict mode', () => {
beforeAll(() => {
process.env.cds_features_db__strict = true
})

cds.test(__dirname + '/resources')

afterAll(() => {
process.env.cds_features_db__strict = undefined
})

async function runAndExpectError(cqn, expectedMessage) {
let error
try {
await cds.run(cqn)
} catch (e) {
error = e
}
expect(error.message).toEqual(expectedMessage)
}
describe('UPDATE Scenarios', () => {
test('Update with multiple errors', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
UPDATE.entity(Books).where({ ID: 2 }).set({ abc: 'bar', abc2: 'baz' }),
'STRICT MODE: Trying to UPDATE non existent columns (abc,abc2)',
)
})

test('Update with single error', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
UPDATE.entity(Books).where({ ID: 2 }).set({ abc: 'bar' }),
'STRICT MODE: Trying to UPDATE non existent columns (abc)',
)
})

test.skip('Update on non existing entity', async () => {
await runAndExpectError(
UPDATE.entity('notExisting').where({ ID: 2 }).set({ abc: 'bar' }),
'STRICT MODE: Trying to UPDATE non existent columns (abc,abc2)',
)
})
})

describe('INSERT Scenarios', () => {
test('Insert with single error using entries', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
INSERT.into(Books).entries({ abc: 'bar' }),
'STRICT MODE: Trying to INSERT non existent columns (abc)',
)
})

test('Insert with multiple errors using entries', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
INSERT.into(Books).entries([{ abc: 'bar' }, { abc2: 'bar2' }]),
'STRICT MODE: Trying to INSERT non existent columns (abc,abc2)',
)
})

test('Insert with single error using columns and values', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
INSERT.into(Books).columns(['abc']).values(['foo', 'bar']),
'STRICT MODE: Trying to INSERT non existent columns (abc)',
)
})

test('Insert with multiple errors with columns and rows', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
INSERT.into(Books).columns(['abc', 'abc2']).rows(['foo', 'bar'], ['foo2', 'bar2'], ['foo3', 'bar3']),
'STRICT MODE: Trying to INSERT non existent columns (abc,abc2)',
)
})

test('Insert with single error using columns and rows', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
INSERT.into(Books).columns(['abc']).rows(['foo', 'bar'], ['foo2', 'bar2'], ['foo3', 'bar3']),
'STRICT MODE: Trying to INSERT non existent columns (abc)',
)
})

test('Insert on non existing entity using entries', async () => {
await runAndExpectError(
INSERT.into('notExisting').entries({ abc: 'bar' }),
'STRICT MODE: Trying to INSERT non existent columns (abc)',
)
})
})

describe('UPSERT Scenarios', () => {
test('UPSERT with single error', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
UPSERT.into(Books).entries({ abc: 'bar' }),
'STRICT MODE: Trying to UPSERT non existent columns (abc)',
)
})
test('UPSERT with multiple errors', async () => {
const { Books } = cds.entities('ComplianceService')
await runAndExpectError(
UPSERT.into(Books).entries({ abc: 'bar', abc2: 'baz' }),
'STRICT MODE: Trying to UPSERT non existent columns (abc,abc2)',
)
})

test('UPSERT on non existing entity', async () => {
await runAndExpectError(
UPSERT.into('notExisting').entries({ abc: 'bar' }),
'STRICT MODE: Trying to UPSERT non existent columns (abc)',
)
})
})
})
Loading