prepared for cdr
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user