Skip to content

Commit

Permalink
fix: preserve $count for result of SELECT queries (#280)
Browse files Browse the repository at this point in the history
* fix: preserve $count for result of SELECT

* make _arrayWithCount a static function

* use static function in HANA Service
  • Loading branch information
johannes-vogel authored Oct 13, 2023
1 parent e8c7838 commit 23bef24
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
17 changes: 16 additions & 1 deletion db-service/lib/SQLService.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ class SQLService extends DatabaseService {
let rows = await ps.all(values)
if (rows.length)
if (cqn.SELECT.expand) rows = rows.map(r => (typeof r._json_ === 'string' ? JSON.parse(r._json_) : r._json_ || r))
if (cqn.SELECT.count) rows.$count = await this.count(query, rows)
if (cqn.SELECT.count) {
// REVISIT: the runtime always expects that the count is preserved with .map, required for renaming in mocks
return SQLService._arrayWithCount(rows, await this.count(query, rows))
}
return cqn.SELECT.one || query.SELECT.from?.ref?.[0].cardinality?.max === 1 ? rows[0] : rows
}

Expand Down Expand Up @@ -252,6 +255,17 @@ class SQLService extends DatabaseService {
*/
static CQN2SQL = require('./cqn2sql').class

// REVISIT: There must be a better way
// preserves $count for .map calls on array
static _arrayWithCount = function (a, count) {
const _map = a.map
const map = function (..._) { return SQLService._arrayWithCount(_map.call(a, ..._), count) }
return Object.defineProperties(a, {
$count: { value: count, enumerable: false, configurable: true, writable: true },
map: { value: map, enumerable: false, configurable: true, writable: true }
})
}

/** @param {unknown[]} args */
constructor(...args) {
super(...args)
Expand Down Expand Up @@ -387,6 +401,7 @@ const _unquirked = q => {
return q
}


const sqls = new class extends SQLService { get factory() { return null } }
cds.extend(cds.ql.Query).with(
class {
Expand Down
5 changes: 4 additions & 1 deletion hana/lib/HANAService.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ class HANAService extends SQLService {
if (rows.length) {
rows = this.parseRows(rows)
}
if (cqn.SELECT.count) rows.$count = await this.count(query, rows)
if (cqn.SELECT.count) {
// REVISIT: the runtime always expects that the count is preserved with .map, required for renaming in mocks
return HANAService._arrayWithCount(rows, await this.count(query, rows))
}
return cqn.SELECT.one || query.SELECT.from.ref?.[0].cardinality?.max === 1 ? rows[0] || null : rows
}

Expand Down
9 changes: 7 additions & 2 deletions test/compliance/SELECT.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,13 @@ describe('SELECT', () => {
})

describe('count', () => {
test.skip('missing', () => {
throw new Error('not supported')
test('count is preserved with .map', async () => {
const query = SELECT.from('complex.Authors')
query.SELECT.count = true
const result = await query
assert.strictEqual(result.$count, 1)
const renamed = result.map(row => ({key: row.ID, fullName: row.name}))
assert.strictEqual(renamed.$count, 1)
})
})

Expand Down

0 comments on commit 23bef24

Please sign in to comment.