From 6266f54ef4b845af212f3e1c3a1321dbe0156913 Mon Sep 17 00:00:00 2001 From: Johannes Vogel <31311694+johannes-vogel@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:56:37 +0200 Subject: [PATCH 01/12] feat: support current_utctimestamp --- hana/lib/cql-functions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/hana/lib/cql-functions.js b/hana/lib/cql-functions.js index b78516553..5b20180d7 100644 --- a/hana/lib/cql-functions.js +++ b/hana/lib/cql-functions.js @@ -45,6 +45,7 @@ const StandardFunctions = { current_date: () => 'current_utcdate', current_time: () => 'current_utctime', current_timestamp: () => 'current_utctimestamp', + current_utctimestamp: () => 'current_utctimestamp', fractionalseconds: x => `(TO_DECIMAL(SECOND(${x}),5,3) - TO_INTEGER(SECOND(${x})))`, } From 482948284cd9fe0d6f0e70b76ed5686691cb7646 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 11:16:49 +0100 Subject: [PATCH 02/12] add test --- hana/lib/cql-functions.js | 2 +- test/compliance/functions.test.js | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/hana/lib/cql-functions.js b/hana/lib/cql-functions.js index 5b20180d7..c86a433d4 100644 --- a/hana/lib/cql-functions.js +++ b/hana/lib/cql-functions.js @@ -45,7 +45,7 @@ const StandardFunctions = { current_date: () => 'current_utcdate', current_time: () => 'current_utctime', current_timestamp: () => 'current_utctimestamp', - current_utctimestamp: () => 'current_utctimestamp', + current_utctimestamp: x => x ? `current_utctimestamp(${x})` : 'current_utctimestamp', fractionalseconds: x => `(TO_DECIMAL(SECOND(${x}),5,3) - TO_INTEGER(SECOND(${x})))`, } diff --git a/test/compliance/functions.test.js b/test/compliance/functions.test.js index 09cee81de..5941136ee 100644 --- a/test/compliance/functions.test.js +++ b/test/compliance/functions.test.js @@ -342,8 +342,25 @@ describe('functions', () => { }) }) describe('CURRENT_UTCTIMESTAMP', () => { - test.skip('missing', () => { - throw new Error('not supported') + test('without args', async () => { + const cqn = { SELECT: { + one: true, + from: {ref: ['edge.hana.functions.timestamps']}, + columns: [ + {func: 'CURRENT_UTCTIMESTAMP', as: 'no_args'}, + {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 0}], as: 'prec0'}, + {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 3}], as: 'prec3'}, + {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 7}], as: 'prec7'}] + }} + + const res = await cds.run(cqn) + + expect(res.no_args.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 + expect(res.prec0.match(/\.0000000/)).not.to.be.null + expect(res.prec3.match(/\.(\d\d\d)0000/)).not.to.be.null + expect(res.prec7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null + + }) }) describe('DAYNAME', () => { From 90bb63b81ac9867a9c38a501a6c765bcd8e94fea Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 11:53:24 +0100 Subject: [PATCH 03/12] make function hana specific --- hana/test/hana-functions.test.js | 26 ++++++++++++++++++++++++++ test/compliance/functions.test.js | 21 ++------------------- 2 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 hana/test/hana-functions.test.js diff --git a/hana/test/hana-functions.test.js b/hana/test/hana-functions.test.js new file mode 100644 index 000000000..b4365064b --- /dev/null +++ b/hana/test/hana-functions.test.js @@ -0,0 +1,26 @@ +const cds = require('../../test/cds') + +describe('HANA custom functions', () => { + const { expect } = cds.test(__dirname, 'fuzzy.cds') + + test('current_utctimestamp', async () => { + const cqn = { SELECT: { + one: true, + from: {ref: ['DUMMY']}, + columns: [ + {func: 'CURRENT_UTCTIMESTAMP', as: 'no_args'}, + {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 0}], as: 'prec0'}, + {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 3}], as: 'prec3'}, + {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 7}], as: 'prec7'}] + }} + + const res = await cds.run(cqn) + + expect(res.no_args.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 + expect(res.prec0.match(/\.0000000/)).not.to.be.null + expect(res.prec3.match(/\.(\d\d\d)0000/)).not.to.be.null + expect(res.prec7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null + + + }) +}) \ No newline at end of file diff --git a/test/compliance/functions.test.js b/test/compliance/functions.test.js index 5941136ee..09cee81de 100644 --- a/test/compliance/functions.test.js +++ b/test/compliance/functions.test.js @@ -342,25 +342,8 @@ describe('functions', () => { }) }) describe('CURRENT_UTCTIMESTAMP', () => { - test('without args', async () => { - const cqn = { SELECT: { - one: true, - from: {ref: ['edge.hana.functions.timestamps']}, - columns: [ - {func: 'CURRENT_UTCTIMESTAMP', as: 'no_args'}, - {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 0}], as: 'prec0'}, - {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 3}], as: 'prec3'}, - {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 7}], as: 'prec7'}] - }} - - const res = await cds.run(cqn) - - expect(res.no_args.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 - expect(res.prec0.match(/\.0000000/)).not.to.be.null - expect(res.prec3.match(/\.(\d\d\d)0000/)).not.to.be.null - expect(res.prec7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null - - + test.skip('missing', () => { + throw new Error('not supported') }) }) describe('DAYNAME', () => { From bb41808f58400d46d5bdb246946acd29b6554009 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 11:58:18 +0100 Subject: [PATCH 04/12] use lowercase function in tests --- hana/test/hana-functions.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hana/test/hana-functions.test.js b/hana/test/hana-functions.test.js index b4365064b..fc2796800 100644 --- a/hana/test/hana-functions.test.js +++ b/hana/test/hana-functions.test.js @@ -8,10 +8,10 @@ describe('HANA custom functions', () => { one: true, from: {ref: ['DUMMY']}, columns: [ - {func: 'CURRENT_UTCTIMESTAMP', as: 'no_args'}, - {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 0}], as: 'prec0'}, - {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 3}], as: 'prec3'}, - {func: 'CURRENT_UTCTIMESTAMP', args: [{val: 7}], as: 'prec7'}] + {func: 'current_utctimestamp', as: 'no_args'}, + {func: 'current_utctimestamp', args: [{val: 0}], as: 'prec0'}, + {func: 'current_utctimestamp', args: [{val: 3}], as: 'prec3'}, + {func: 'current_utctimestamp', args: [{val: 7}], as: 'prec7'}] }} const res = await cds.run(cqn) From 875e3762490285d0a1a496d2f9048089fc0b593a Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 11:59:32 +0100 Subject: [PATCH 05/12] only append brackets for args if provided --- db-service/lib/cqn2sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db-service/lib/cqn2sql.js b/db-service/lib/cqn2sql.js index cdf3b4959..ccb1c68a5 100644 --- a/db-service/lib/cqn2sql.js +++ b/db-service/lib/cqn2sql.js @@ -990,7 +990,7 @@ class CQN2SQLRenderer { } else { cds.error`Invalid arguments provided for function '${func}' (${args})` } - const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}(${args})` + const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}${args ? `(${args})`: ''}` if (xpr) return `${fn} ${this.xpr({ xpr })}` return fn } From b237eeb6c03b3c6d285bf1390e6215ee8379a633 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 12:00:11 +0100 Subject: [PATCH 06/12] Revert "only append brackets for args if provided" This reverts commit 875e3762490285d0a1a496d2f9048089fc0b593a. --- db-service/lib/cqn2sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db-service/lib/cqn2sql.js b/db-service/lib/cqn2sql.js index ccb1c68a5..cdf3b4959 100644 --- a/db-service/lib/cqn2sql.js +++ b/db-service/lib/cqn2sql.js @@ -990,7 +990,7 @@ class CQN2SQLRenderer { } else { cds.error`Invalid arguments provided for function '${func}' (${args})` } - const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}${args ? `(${args})`: ''}` + const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}(${args})` if (xpr) return `${fn} ${this.xpr({ xpr })}` return fn } From 0f5f2915d2034b7e238531d6ebdfed5110b154f2 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 14:32:52 +0100 Subject: [PATCH 07/12] adapt test --- hana/test/hana-functions.test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hana/test/hana-functions.test.js b/hana/test/hana-functions.test.js index fc2796800..87438a54e 100644 --- a/hana/test/hana-functions.test.js +++ b/hana/test/hana-functions.test.js @@ -8,18 +8,18 @@ describe('HANA custom functions', () => { one: true, from: {ref: ['DUMMY']}, columns: [ - {func: 'current_utctimestamp', as: 'no_args'}, - {func: 'current_utctimestamp', args: [{val: 0}], as: 'prec0'}, - {func: 'current_utctimestamp', args: [{val: 3}], as: 'prec3'}, - {func: 'current_utctimestamp', args: [{val: 7}], as: 'prec7'}] + {func: 'current_utctimestamp', as: 'NO'}, + {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}, + {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, + {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] }} const res = await cds.run(cqn) - expect(res.no_args.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 - expect(res.prec0.match(/\.0000000/)).not.to.be.null - expect(res.prec3.match(/\.(\d\d\d)0000/)).not.to.be.null - expect(res.prec7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null + expect(res.NO.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 + expect(res.P0.match(/\.0000000/)).not.to.be.null + expect(res.P3.match(/\.(\d\d\d)0000/)).not.to.be.null + expect(res.P7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null }) From 35c35f10efedef6522f474d1c803469deeefb0b8 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Thu, 21 Nov 2024 14:57:04 +0100 Subject: [PATCH 08/12] no args, no brackets --- db-service/lib/cqn2sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db-service/lib/cqn2sql.js b/db-service/lib/cqn2sql.js index cdf3b4959..ccb1c68a5 100644 --- a/db-service/lib/cqn2sql.js +++ b/db-service/lib/cqn2sql.js @@ -990,7 +990,7 @@ class CQN2SQLRenderer { } else { cds.error`Invalid arguments provided for function '${func}' (${args})` } - const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}(${args})` + const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}${args ? `(${args})`: ''}` if (xpr) return `${fn} ${this.xpr({ xpr })}` return fn } From dd9373c6d2fc084b98a798ba90e393cc069dbc63 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Fri, 22 Nov 2024 10:44:31 +0100 Subject: [PATCH 09/12] reorder tests --- hana/test/hana-functions.test.js | 62 +++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/hana/test/hana-functions.test.js b/hana/test/hana-functions.test.js index 87438a54e..227e624af 100644 --- a/hana/test/hana-functions.test.js +++ b/hana/test/hana-functions.test.js @@ -1,26 +1,54 @@ const cds = require('../../test/cds') -describe('HANA custom functions', () => { +describe('HANA native functions', () => { const { expect } = cds.test(__dirname, 'fuzzy.cds') - test('current_utctimestamp', async () => { - const cqn = { SELECT: { - one: true, - from: {ref: ['DUMMY']}, - columns: [ - {func: 'current_utctimestamp', as: 'NO'}, - {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}, - {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, - {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] - }} + describe('current_timestamp', () => { + test('no arguments', async () => { + const cqn = { SELECT: { + one: true, + from: {ref: ['DUMMY']}, + columns: [ + {func: 'current_utctimestamp', as: 'NO'}, + {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}, + {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, + {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] + }} + + const res = await cds.run(cqn) + + expect(res.NO.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 + }) - const res = await cds.run(cqn) - - expect(res.NO.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 - expect(res.P0.match(/\.0000000/)).not.to.be.null - expect(res.P3.match(/\.(\d\d\d)0000/)).not.to.be.null - expect(res.P7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null + test('0 skips ms precision', async () => { + const cqn = { SELECT: { + one: true, + from: {ref: ['DUMMY']}, + columns: [ + {func: 'current_utctimestamp', as: 'NO'}, + {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}, + {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, + {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] + }} + + const res = await cds.run(cqn) + expect(res.P0.match(/\.0000000/)).not.to.be.null + }) + test('arbitrary values', async () => { + const cqn = { SELECT: { + one: true, + from: {ref: ['DUMMY']}, + columns: [ + {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, + {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] + }} + + const res = await cds.run(cqn) + + expect(res.P3.match(/\.(\d\d\d)0000/)).not.to.be.null + expect(res.P7.match(/\.(\d\d\d\d\d\d\d)/)).not.to.be.null + }) }) }) \ No newline at end of file From d22df56adfc5c5d069c306c0794b50b1cab5d392 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Fri, 22 Nov 2024 11:02:07 +0100 Subject: [PATCH 10/12] fix --- hana/test/hana-functions.test.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/hana/test/hana-functions.test.js b/hana/test/hana-functions.test.js index 227e624af..94b6fc08c 100644 --- a/hana/test/hana-functions.test.js +++ b/hana/test/hana-functions.test.js @@ -8,11 +8,7 @@ describe('HANA native functions', () => { const cqn = { SELECT: { one: true, from: {ref: ['DUMMY']}, - columns: [ - {func: 'current_utctimestamp', as: 'NO'}, - {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}, - {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, - {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] + columns: [{func: 'current_utctimestamp', as: 'NO'}] }} const res = await cds.run(cqn) @@ -26,9 +22,7 @@ describe('HANA native functions', () => { from: {ref: ['DUMMY']}, columns: [ {func: 'current_utctimestamp', as: 'NO'}, - {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}, - {func: 'current_utctimestamp', args: [{val: 3}], as: 'P3'}, - {func: 'current_utctimestamp', args: [{val: 7}], as: 'P7'}] + {func: 'current_utctimestamp', args: [{val: 0}], as: 'P0'}] }} const res = await cds.run(cqn) From 13e6f3665914b4178d3d74ea4e1c587a70093829 Mon Sep 17 00:00:00 2001 From: Johannes Vogel Date: Fri, 22 Nov 2024 11:14:40 +0100 Subject: [PATCH 11/12] skip failing tests on HXE --- hana/test/hana-functions.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hana/test/hana-functions.test.js b/hana/test/hana-functions.test.js index 94b6fc08c..b9f8bd4df 100644 --- a/hana/test/hana-functions.test.js +++ b/hana/test/hana-functions.test.js @@ -16,7 +16,8 @@ describe('HANA native functions', () => { expect(res.NO.match(/\.(\d\d\d)0000/)).not.to.be.null // default 3 }) - test('0 skips ms precision', async () => { + // HXE does not allow args + test.skip('0 skips ms precision', async () => { const cqn = { SELECT: { one: true, from: {ref: ['DUMMY']}, @@ -30,7 +31,8 @@ describe('HANA native functions', () => { expect(res.P0.match(/\.0000000/)).not.to.be.null }) - test('arbitrary values', async () => { + // HXE does not allow args + test.skip('arbitrary values', async () => { const cqn = { SELECT: { one: true, from: {ref: ['DUMMY']}, From 8d213911eaeca5e8f2f6fd8fc3638c2b0ec36da1 Mon Sep 17 00:00:00 2001 From: Johannes Vogel <31311694+johannes-vogel@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:22:24 +0100 Subject: [PATCH 12/12] revert --- db-service/lib/cqn2sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db-service/lib/cqn2sql.js b/db-service/lib/cqn2sql.js index ccb1c68a5..cdf3b4959 100644 --- a/db-service/lib/cqn2sql.js +++ b/db-service/lib/cqn2sql.js @@ -990,7 +990,7 @@ class CQN2SQLRenderer { } else { cds.error`Invalid arguments provided for function '${func}' (${args})` } - const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}${args ? `(${args})`: ''}` + const fn = this.class.Functions[func]?.apply(this.class.Functions, args) || `${func}(${args})` if (xpr) return `${fn} ${this.xpr({ xpr })}` return fn }