Skip to content

Commit

Permalink
Merge branch 'refractor-like-search-for-escaped-quotes' of https://gi…
Browse files Browse the repository at this point in the history
…thub.com/cap-js/cds-dbs into refractor-like-search-for-escaped-quotes
  • Loading branch information
larslutz96 committed Jan 17, 2025
2 parents 34cdf28 + 35f130f commit 0373266
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 10 deletions.
6 changes: 3 additions & 3 deletions db-service/lib/cql-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const StandardFunctions = {
* @param {...string} args
* @returns {string}
*/
contains: (...args) => `ifnull(instr(${args}),0)`,
contains: (...args) => `(ifnull(instr(${args}),0) > 0)`,
/**
* Generates SQL statement that produces the number of elements in a given collection
* @param {string} x
Expand All @@ -75,15 +75,15 @@ const StandardFunctions = {
* @param {string} y
* @returns {string}
*/
startswith: (x, y) => `instr(${x},${y}) = 1`, // sqlite instr is 1 indexed
startswith: (x, y) => `coalesce(instr(${x},${y}) = 1,false)`, // sqlite instr is 1 indexed
// takes the end of the string of the size of the target and compares it with the target
/**
* Generates SQL statement that produces a boolean value indicating whether the first string ends with the second string
* @param {string} x
* @param {string} y
* @returns {string}
*/
endswith: (x, y) => `substr(${x}, length(${x}) + 1 - length(${y})) = ${y}`,
endswith: (x, y) => `coalesce(substr(${x}, length(${x}) + 1 - length(${y})) = ${y},false)`,
/**
* Generates SQL statement that produces the substring of a given string
* @example
Expand Down
2 changes: 1 addition & 1 deletion hana/lib/HANAService.js
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ SELECT ${mixing} FROM JSON_TABLE(SRC.JSON, '$' COLUMNS(${extraction})) AS NEW LE
async dispatch(req) {
// Look for deployment batch dispatch and execute as single query
// When deployment is not executed in a batch it will fail to create views
if (Array.isArray(req.query) && !req.query.find(q => typeof q !== 'string')) {
if (Array.isArray(req.query) && !req.query.find(q => typeof q !== 'string' || this.hasResults(q))) {
req.query = `DO BEGIN ${req.query
.map(
q =>
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions postgres/lib/cql-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ const StandardFunctions = {
countdistinct: x => `count(distinct ${x.val || x || '*'})`,
contains: (...args) => `(coalesce(strpos(${args}),0) > 0)`,
indexof: (x, y) => `strpos(${x},${y}) - 1`, // strpos is 1 indexed
startswith: (x, y) => `strpos(${x},${y}) = 1`, // strpos is 1 indexed
endswith: (x, y) => `substr(${x},length(${x}) + 1 - length(${y})) = ${y}`,
startswith: (x, y) => `coalesce(strpos(${x},${y}) = 1,false)`, // strpos is 1 indexed
endswith: (x, y) => `coalesce(substr(${x},length(${x}) + 1 - length(${y})) = ${y},false)`,
matchesPattern: (x, y) => `regexp_like(${x}, ${y})`,
matchespattern: (x, y) => `regexp_like(${x}, ${y})`,

Expand Down
42 changes: 42 additions & 0 deletions test/scenarios/bookshop/funcs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,30 @@ describe('Bookshop - Functions', () => {
expect(res.data.value.length).to.be.eq(2)
})

test('contains with search string that can not be found', async () => {
const res = await GET(`/browse/Books?$filter=contains(author,'string that can not be found in any author name')`)
expect(res.status).to.be.eq(200)
expect(res.data.value.length).to.be.eq(0)
})

test('contains with search string null', async () => {
const res = await GET(`/browse/Books?$filter=contains(author,null)`)
expect(res.status).to.be.eq(200)
expect(res.data.value.length).to.be.eq(0)
})

test('contains with explicit equals boolean value', async () => {
const res = await GET("/browse/Books?$filter=contains(author,'Allen') eq true")
expect(res.status).to.be.eq(200)
expect(res.data.value.length).to.be.eq(2)
})

test('contains with explicit not equals boolean value', async () => {
const res = await GET("/browse/Books?$filter=contains(author,'Allen') ne false")
expect(res.status).to.be.eq(200)
expect(res.data.value.length).to.be.eq(2)
})

test('avg', async () => {
const { Books } = cds.entities
const res = await cds.run(CQL`SELECT from ${Books} {
Expand All @@ -42,6 +66,15 @@ describe('Bookshop - Functions', () => {
expect(wrong.data.value.length).to.be.eq(0)
})

test('not endswith finds null', async () => {
const { Books } = cds.entities('sap.capire.bookshop')
await cds.run(INSERT({ ID: 123, title: 'Harry Potter', stock: undefined }).into(Books))
const res = await GET(`/browse/Books?$filter=not endswith(author,'Poe')`)
expect(res.status).to.be.eq(200)
expect(res.data.value.some(item => item.ID === 123)).to.be.true
await cds.run(DELETE.from(Books).where({ ID: 123 }))
})

test('indexof', async () => {
const res = await GET(`/browse/Books?$filter=indexof(author,'Allen') eq 6`)

Expand All @@ -67,6 +100,15 @@ describe('Bookshop - Functions', () => {
expect(wrong.data.value.length).to.be.eq(0)
})

test('not startswith finds null', async () => {
const { Books } = cds.entities('sap.capire.bookshop')
await cds.run(INSERT({ ID: 123, title: 'Harry Potter', stock: undefined }).into(Books))
const res = await GET(`/browse/Books?$filter=not startswith(author,'Poe')`)
expect(res.status).to.be.eq(200)
expect(res.data.value.some(item => item.ID === 123)).to.be.true
await cds.run(DELETE.from(Books).where({ ID: 123 }))
})

test('substring', async () => {
const [three, two, negative] = await Promise.all([
GET(`/browse/Books?$filter=substring(author,1,2) eq 'dg'`),
Expand Down
6 changes: 6 additions & 0 deletions test/scenarios/bookshop/read.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ describe('Bookshop - Read', () => {
test('Plain sql', async () => {
const res = await cds.run('SELECT * FROM sap_capire_bookshop_Books')
expect(res.length).to.be.eq(5)
const [res1, res2] = await cds.run([
'SELECT * FROM sap_capire_bookshop_Books',
'SELECT * FROM sap_capire_bookshop_Books',
])
expect(res1.length).to.be.eq(5)
expect(res2.length).to.be.eq(5)
})

test('Plain sql with values', async () => {
Expand Down

0 comments on commit 0373266

Please sign in to comment.