prepared for cdr

This commit is contained in:
Daniel
2020-04-21 21:21:45 +02:00
parent 50428b4d26
commit 3831951b65
4 changed files with 147 additions and 116 deletions

View File

@@ -23,6 +23,9 @@
"jest": "npx jest --verbose", "jest": "npx jest --verbose",
"test": "npm run jest -s" "test": "npm run jest -s"
}, },
"jest": {
"testEnvironment": "node"
},
"license": "SAP SAMPLE CODE LICENSE", "license": "SAP SAMPLE CODE LICENSE",
"private": true "private": true
} }

View File

@@ -10,15 +10,17 @@ if (!is_cds_333) {
const up = UPDATE('x').constructor.prototype const up = UPDATE('x').constructor.prototype
up.with = up.set up.with = up.set
} }
const { parse:cdr } = cds.ql
// while jest has 'test' as alias to 'it', mocha doesn't // while jest has 'test' as alias to 'it', mocha doesn't
if (!global.test) global.test = it if (!global.test) global.test = it
describe('cds.ql → cqn', () => { describe('cds.ql → cqn', () => {
// //
let cqn
describe(`BUGS + GAPS...`, () => { describe(`BUGS + GAPS...`, () => {
it.skip('should consistently handle *', () => { !(cdr ? it : it.skip)('should consistently handle *', () => {
expect({ expect({
SELECT: { from: { ref: ['Foo'] }, columns: ['*'] }, SELECT: { from: { ref: ['Foo'] }, columns: ['*'] },
}) })
@@ -28,8 +30,8 @@ describe('cds.ql → cqn', () => {
.to.eql(SELECT.from(Foo, ['*'])) .to.eql(SELECT.from(Foo, ['*']))
}) })
it.skip('should correctly handle { ... and:{...} }', () => { !(cdr ? it : it.skip)('should correctly handle { ... and:{...} }', () => {
expect(SELECT.from(Foo).where({ x: 1, and: { y: 2, or: { z: 2 } } })).to.eql({ expect(SELECT.from(Foo).where({ x: 1, and: { y: 2, or: { z: 3 } } })).to.eql({
SELECT: { SELECT: {
from: { ref: ['Foo'] }, from: { ref: ['Foo'] },
where: [ where: [
@@ -117,17 +119,20 @@ describe('cds.ql → cqn', () => {
test('from ( ..., => {...})', () => { test('from ( ..., => {...})', () => {
// single *, prefix and postfix, as array and function // single *, prefix and postfix, as array and function
expect(CQL`SELECT * from Foo`).to.eql(CQL`SELECT from Foo{*}`) let parsed, fluid
expect((parsed = CQL`SELECT * from Foo`)).to.eql(CQL`SELECT from Foo{*}`)
//> .to.eql... FIXME: see skipped 'should handle * correctly' below //> .to.eql... FIXME: see skipped 'should handle * correctly' below
expect(SELECT('*').from(Foo)) expect((fluid = SELECT('*').from(Foo)))
.to.eql(SELECT.from(Foo, ['*'])) .to.eql(SELECT.from(Foo, ['*']))
.to.eql(SELECT.from(Foo, (foo) => foo('*'))) .to.eql(SELECT.from(Foo, (foo) => foo('*')))
.to.eql(SELECT.from(Foo).columns('*')) .to.eql(SELECT.from(Foo).columns('*'))
.to.eql(SELECT.from(Foo).columns((foo) => foo('*'))) .to.eql(SELECT.from(Foo).columns((foo) => foo('*')))
.to.eql({ .to.eql({
SELECT: { from: { ref: ['Foo'] }, columns: [{ ref: ['*'] }] }, SELECT: { from: { ref: ['Foo'] }, columns: [cdr ? '*' : { ref: ['*'] }] },
}) })
if (cdr) expect(parsed).to.eql(fluid)
// single column, prefix and postfix, as array and function // single column, prefix and postfix, as array and function
expect(CQL`SELECT a from Foo`) expect(CQL`SELECT a from Foo`)
expect(CQL`SELECT from Foo {a}`) expect(CQL`SELECT from Foo {a}`)
@@ -139,26 +144,26 @@ describe('cds.ql → cqn', () => {
// multiple columns, prefix and postfix, as array and function // multiple columns, prefix and postfix, as array and function
expect(CQL`SELECT a,b as c from Foo`) expect(CQL`SELECT a,b as c from Foo`)
expect(CQL`SELECT from Foo {a,b as c}`)
.to.eql(SELECT.from(Foo, ['a', { b: 'c' }])) expect (CQL`SELECT from Foo {a,b as c}`).to.eql(cqn = {
.to.eql( SELECT: {
SELECT.from(Foo, (foo) => { from: { ref: ['Foo'] },
foo.a, foo.b.as('c') columns: [{ ref: ['a'] }, { ref: ['b'], as: 'c' }],
}) },
) })
.to.eql(SELECT.from(Foo).columns('a', { b: 'c' })) expect(SELECT.from(Foo, ['a', { b: 'c' }])).to.eql(cqn)
.to.eql(SELECT.from(Foo).columns(['a', { b: 'c' }])) expect(
.to.eql( SELECT.from(Foo, (foo) => {
SELECT.from(Foo).columns((foo) => { foo.a, foo.b.as('c')
foo.a, foo.b.as('c')
})
)
.to.eql({
SELECT: {
from: { ref: ['Foo'] },
columns: [{ ref: ['a'] }, { ref: ['b'], as: 'c' }],
},
}) })
).to.eql(cqn)
expect(SELECT.from(Foo).columns('a', { b: 'c' })).to.eql(cqn)
expect(SELECT.from(Foo).columns(['a', { b: 'c' }])).to.eql(cqn)
expect(
SELECT.from(Foo).columns((foo) => {
foo.a, foo.b.as('c')
})
).to.eql(cqn)
// multiple columns and *, prefix and postfix, as array and function // multiple columns and *, prefix and postfix, as array and function
expect(CQL`SELECT *,a,b from Foo`).to.eql(CQL`SELECT from Foo{*,a,b}`) expect(CQL`SELECT *,a,b from Foo`).to.eql(CQL`SELECT from Foo{*,a,b}`)
@@ -174,7 +179,7 @@ describe('cds.ql → cqn', () => {
.to.eql({ .to.eql({
SELECT: { SELECT: {
from: { ref: ['Foo'] }, from: { ref: ['Foo'] },
columns: [{ ref: ['a'] }, { ref: ['b'] }, { ref: ['*'] }], columns: [{ ref: ['a'] }, { ref: ['b'] }, cdr ? '*' : { ref: ['*'] }],
}, },
}) })
}) })
@@ -195,7 +200,7 @@ describe('cds.ql → cqn', () => {
SELECT: { SELECT: {
from: { ref: ['Foo'] }, from: { ref: ['Foo'] },
columns: [ columns: [
{ ref: ['*'] }, cdr ? '*' : { ref: ['*'] },
{ ref: ['x'] }, { ref: ['x'] },
{ ref: ['car'], expand: ['*'] }, { ref: ['car'], expand: ['*'] },
{ {
@@ -231,23 +236,23 @@ describe('cds.ql → cqn', () => {
}) })
test('one / distinct ...', () => { test('one / distinct ...', () => {
expect(SELECT.distinct.from(Foo).cqn) expect(SELECT.distinct.from(Foo).SELECT)
// .to.eql(CQL(`SELECT distinct from Foo`).SELECT) // .to.eql(CQL(`SELECT distinct from Foo`).SELECT)
.to.eql(SELECT.distinct(Foo).cqn) .to.eql(SELECT.distinct(Foo).SELECT)
.to.eql({ distinct: true, from: { ref: ['Foo'] } }) .to.eql({ distinct: true, from: { ref: ['Foo'] } })
expect(SELECT.one.from(Foo).cqn) expect(SELECT.one.from(Foo).SELECT)
// .to.eql(CQL(`SELECT one from Foo`).SELECT) // .to.eql(CQL(`SELECT one from Foo`).SELECT)
.to.eql(SELECT.one(Foo).cqn) .to.eql(SELECT.one(Foo).SELECT)
.to.eql({ one: true, from: { ref: ['Foo'] } }) .to.eql({ one: true, from: { ref: ['Foo'] } })
expect(SELECT.one('a').from(Foo).cqn) expect(SELECT.one('a').from(Foo).SELECT)
// .to.eql(CQL(`SELECT distinct a from Foo`).SELECT) // .to.eql(CQL(`SELECT distinct a from Foo`).SELECT)
.to.eql(SELECT.one(['a']).from(Foo).cqn) .to.eql(SELECT.one(['a']).from(Foo).SELECT)
.to.eql(SELECT.one(Foo, ['a']).cqn) .to.eql(SELECT.one(Foo, ['a']).SELECT)
.to.eql(SELECT.one(Foo, (foo) => foo.a).cqn) .to.eql(SELECT.one(Foo, (foo) => foo.a).SELECT)
.to.eql(SELECT.one.from(Foo, (foo) => foo.a).cqn) .to.eql(SELECT.one.from(Foo, (foo) => foo.a).SELECT)
.to.eql(SELECT.one.from(Foo, ['a']).cqn) .to.eql(SELECT.one.from(Foo, ['a']).SELECT)
.to.eql({ .to.eql({
one: true, one: true,
from: { ref: ['Foo'] }, from: { ref: ['Foo'] },
@@ -271,85 +276,108 @@ describe('cds.ql → cqn', () => {
).to.eql({ ).to.eql({
SELECT: { SELECT: {
from: { ref: ['Foo'] }, from: { ref: ['Foo'] },
where: [ where: cdr
'(', //> this one is not required ? [
{ ref: ['ID'] }, // '(', //> this one is not required
'=', { ref: ['ID'] },
{ val: ID }, '=',
'and', { val: ID },
{ ref: ['args'] }, 'and',
'in', { ref: ['args'] },
{ val: args }, 'in',
'and', { val: args },
// '(', //> this one is missing, and that's changing the logic -> that's a BUG 'and',
{ ref: ['x'] }, '(', //> this one is missing, and that's changing the logic -> that's a BUG
'like', { ref: ['x'] },
{ val: '%x%' }, 'like',
'or', { val: '%x%' },
{ ref: ['y'] }, 'or',
'>=', { ref: ['y'] },
{ val: 9 }, '>=',
')', { val: 9 },
], ')',
]
: [
'(', //> this one is not required
{ ref: ['ID'] },
'=',
{ val: ID },
'and',
{ ref: ['args'] },
'in',
{ val: args },
'and',
// '(', //> this one is missing, and that's changing the logic -> that's a BUG
{ ref: ['x'] },
'like',
{ val: '%x%' },
'or',
{ ref: ['y'] },
'>=',
{ val: 9 },
')',
],
}, },
}) })
// using CQL fragments -> uses cds.parse.expr // using CQL fragments -> uses cds.parse.expr
expect(CQL`SELECT from Foo where ID=11 and x in ( foo, 'bar', 3)`) expect((cqn = CQL`SELECT from Foo where ID=11 and x in ( foo, 'bar', 3)`)).to.eql({
.to.eql(SELECT.from(Foo).where(`ID=`, ID, `and x in`, args)) SELECT: {
.to.eql(SELECT.from(Foo).where(`ID=${ID} and x in (${args})`)) from: { ref: ['Foo'] },
.to.eql({ where: [
SELECT: { { ref: ['ID'] },
from: { ref: ['Foo'] }, '=',
where: [ { val: ID },
{ ref: ['ID'] }, 'and',
'=', { ref: ['x'] },
{ val: ID }, 'in',
'and', '(',
{ ref: ['x'] }, { ref: ['foo'] },
'in', ',',
'(', { val: 'bar' },
{ ref: ['foo'] }, ',',
',', { val: 3 },
{ val: 'bar' }, ')',
',', ],
{ val: 3 }, },
')', })
], expect(SELECT.from(Foo).where(`ID=`, ID, `and x in`, args)).to.eql(cqn)
}, expect(SELECT.from(Foo).where(`ID=${ID} and x in (${args})`)).to.eql(cqn)
})
expect(CQL`SELECT from Foo where x=1 or y.z is null and (a>2 or b=3)`).to.eql( expect(
SELECT.from(Foo).where(`x=`, 1, `or y.z is null and (a>`, 2, `or b=`, 3, `)`) SELECT.from(Foo).where(`x=`, 1, `or y.z is null and (a>`, 2, `or b=`, 3, `)`)
) ).to.eql(CQL`SELECT from Foo where x=1 or y.z is null and (a>2 or b=3)`)
expect(CQL`SELECT from Foo where x between 1 and 9`).to.eql( expect(SELECT.from(Foo).where(`x between`, 1, `and`, 9)).to.eql(
SELECT.from(Foo).where(`x between`, 1, `and`, 9) CQL`SELECT from Foo where x between 1 and 9`
) )
}) })
test('w/ sub selects', () => { test('w/ sub selects', () => {
// in where causes // in where causes
expect(CQL`SELECT from Foo where x in (SELECT y from Bar)`).to.eql( expect(SELECT.from(Foo).where({ x: SELECT('y').from('Bar') })).to.eql(
SELECT.from(Foo).where({ x: SELECT('y').from('Bar') }) CQL`SELECT from Foo where x in (SELECT y from Bar)`
) )
// in classical semi joins // in classical semi joins
expect(CQL`SELECT x from Foo where exists (SELECT 1 from Bar where y=x)`).to.eql( expect(
SELECT('x').from(Foo) .where ( `exists`, SELECT('x').from(Foo) .where ( `exists`,
SELECT(1).from('Bar') .where ({ y: { ref: ['x'] } }) SELECT(1).from('Bar') .where ({ y: { ref: ['x'] } })
) // prettier-ignore ) // prettier-ignore
) ).to.eql(CQL`SELECT x from Foo where exists (SELECT 1 from Bar where y=x)`)
// in select clauses // in select clauses
cqn = CQL`SELECT from Foo { x, (SELECT y from Bar) as y }`
cds.version >= '3.33.3' && cds.version >= '3.33.3' &&
expect(CQL`SELECT from Foo { x, (SELECT y from Bar) as y }`) expect(
.to.eql( SELECT.from(Foo, (foo) => {
SELECT.from(Foo, (foo) => { foo.x, foo(SELECT.from('Bar', (b) => b.y)).as('y')
foo.x, foo(SELECT.from('Bar', (b) => b.y)).as('y') })
}) ).to.eql(cqn)
) cds.version >= '3.33.3' &&
.to.eql( expect(
SELECT.from(Foo, ['x', Object.assign(SELECT('y').from('Bar'), { as: 'y' })]) SELECT.from(Foo, ['x', Object.assign(SELECT('y').from('Bar'), { as: 'y' })])
) ).to.eql(cqn)
}) })
it('w/ plain SQL', () => { it('w/ plain SQL', () => {
@@ -435,8 +463,7 @@ describe('cds.ql → cqn', () => {
notation or as simple expression objects. notation or as simple expression objects.
*/ */
test('with', () => { test('with', () => {
expect(UPDATE(Foo).with(`foo=11, bar = bar - 22`)) expect(UPDATE(Foo).with(`foo=`, 11, `bar-=`, 22))
.to.eql(UPDATE(Foo).with(`foo=`, 11, `bar-=`, 22))
.to.eql(UPDATE(Foo).with({ foo: 11, bar: { '-=': 22 } })) .to.eql(UPDATE(Foo).with({ foo: 11, bar: { '-=': 22 } }))
.to.eql({ .to.eql({
UPDATE: { UPDATE: {
@@ -449,15 +476,15 @@ describe('cds.ql → cqn', () => {
}) })
// some more // some more
expect(UPDATE(Foo).with(`bar = coalesce(x,y), car = 'foo''s bar, car'`)).to.eql({ // expect(UPDATE(Foo).with(`bar = coalesce(x,y), car = 'foo''s bar, car'`)).to.eql({
UPDATE: { // UPDATE: {
entity: 'Foo', // entity: 'Foo',
with: { // with: {
bar: { func: 'coalesce', args: [{ ref: ['x'] }, { ref: ['y'] }] }, // bar: { func: 'coalesce', args: [{ ref: ['x'] }, { ref: ['y'] }] },
car: { val: "foo's bar, car" }, // car: { val: "foo's bar, car" },
}, // },
}, // },
}) // })
}) })
/* /*
@@ -511,10 +538,6 @@ describe('cds.ql → cqn', () => {
}) })
describe(`cds.ql etc...`, () => { describe(`cds.ql etc...`, () => {
it('queries marked for cds repl', () => {
expect(UPDATE(Foo)._isQuery).to.be.true
})
it('should keep null and undefined', () => { it('should keep null and undefined', () => {
for (let each of [null, undefined]) { for (let each of [null, undefined]) {
expect(SELECT.from(Foo).where({ ID: each })).to.eql({ expect(SELECT.from(Foo).where({ ID: each })).to.eql({

View File

@@ -12,6 +12,8 @@ describe('Consuming Services locally', () => {
expect(Authors).not.to.be.undefined expect(Authors).not.to.be.undefined
}) })
it('bootrapped the database successfully', ()=>{})
it('supports targets as strings or reflected defs', async () => { it('supports targets as strings or reflected defs', async () => {
const AdminService = cds.connect.to('AdminService') const AdminService = cds.connect.to('AdminService')
const { Authors } = AdminService.entities const { Authors } = AdminService.entities

View File

@@ -4,6 +4,7 @@ const cds = require ('@sap/cds')
// monkey patching older releases: // monkey patching older releases:
if (!cds.compile.cdl) cds.compile.cdl = cds.parse if (!cds.compile.cdl) cds.compile.cdl = cds.parse
const { parse:cdr } = cds.ql
const model = cds.compile.cdl (` const model = cds.compile.cdl (`
entity Categories { entity Categories {
@@ -76,12 +77,14 @@ describe('Hierarchical Data', ()=>{
it ('supports cascaded deletes', async()=>{ it ('supports cascaded deletes', async()=>{
const affectedRows = await DELETE.from (Cats) .where ({ID:[102,106]}) const affectedRows = await DELETE.from (Cats) .where ({ID:[102,106]})
expect (affectedRows) .to.equal (5) expect (affectedRows) .to.equal (5)
expect ( await SELECT.from(Cats) ).to.eql ([ const expected = [
{ ID:100, name:'Some Cats...' }, { ID:100, name:'Some Cats...' },
{ ID:101, name:'Cat' }, { ID:101, name:'Cat' },
{ ID:104, name:'Aristocat' }, // REVISIT: Should be deleted as well? { ID:104, name:'Aristocat' }, // REVISIT: Should be deleted as well?
{ ID:108, name:'Catweazle' } { ID:108, name:'Catweazle' }
]) ]
if (cdr) expect ( await SELECT.from(Cats) ).to.containSubset (expected)
else expect ( await SELECT.from(Cats) ).to.eql (expected)
}) })
}) })