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: starts endswith for null values #975

Merged
merged 11 commits into from
Jan 15, 2025
4 changes: 2 additions & 2 deletions db-service/lib/cql-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

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

this covers only SQLite, is this also relevant for other dbs?:)

Copy link
Contributor Author

@larslutz96 larslutz96 Jan 10, 2025

Choose a reason for hiding this comment

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

added same for postgres. Not relevant for hana

// 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
6 changes: 6 additions & 0 deletions test/compliance/SELECT.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ describe('SELECT', () => {
const query = CQL`SELECT * FROM ${string} WHERE ${{ xpr: [CXL`not startswith(string,${'n'})`] }} ORDER BY string DESC`
const res = await cds.run(query)
assert.strictEqual(res[0].string, 'yes')
assert.strictEqual(res[1].string, null)
})

test('deep nested boolean function w/o operator', async () => {
Expand All @@ -488,13 +489,15 @@ describe('SELECT', () => {
const query = CQL`SELECT * FROM ${string} WHERE ${{ xpr: [CXL`not startswith(string,${'n'}) and not startswith(string,${'n'})`] }} ORDER BY string DESC`
const res = await cds.run(query)
assert.strictEqual(res[0].string, 'yes')
assert.strictEqual(res[1].string, null)
})

test('multiple levels of not negations of expressions', async () => {
const { string } = cds.entities('basic.literals')
const query = CQL`SELECT * FROM ${string} WHERE ${{ xpr: ['not', { xpr: ['not', CXL`not startswith(string,${'n'})`] }] }} ORDER BY string DESC`
const res = await cds.run(query)
assert.strictEqual(res[0].string, 'yes')
assert.strictEqual(res[1].string, null)
})

test('multiple not in a single deep nested expression', async () => {
Expand All @@ -509,6 +512,7 @@ describe('SELECT', () => {
throw err
}
assert.strictEqual(res[0].string, 'yes')
assert.strictEqual(res[1].string, null)
})
})

Expand All @@ -517,6 +521,7 @@ describe('SELECT', () => {
const query = CQL`SELECT * FROM ${string} WHERE ${{ xpr: ['not', { xpr: ['not', CXL`not startswith(string,${'n'}) and not startswith(string,${'n'})`] }] }} ORDER BY string DESC`
const res = await cds.run(query)
assert.strictEqual(res[0].string, 'yes')
assert.strictEqual(res[1].string, null)
})

test('multiple levels of not negations of expression with multiple not in a single expression', async () => {
Expand All @@ -531,6 +536,7 @@ describe('SELECT', () => {
throw err
}
assert.strictEqual(res[0].string, 'yes')
assert.strictEqual(res[1].string, null)
})
})

Expand Down
Loading