@cap-js/db-service 1.9.1 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@
4
4
  - The format is based on [Keep a Changelog](http://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [1.10.1](https://github.com/cap-js/cds-dbs/compare/db-service-v1.10.0...db-service-v1.10.1) (2024-06-19)
8
+
9
+
10
+ ### Fixed
11
+
12
+ * Only check first row if no changes required ([#552](https://github.com/cap-js/cds-dbs/issues/552)) ([39b0b85](https://github.com/cap-js/cds-dbs/commit/39b0b85d5cb4807f63f10acea13fb4d688fa1dcd))
13
+
14
+ ## [1.10.0](https://github.com/cap-js/cds-dbs/compare/db-service-v1.9.2...db-service-v1.10.0) (2024-05-29)
15
+
16
+
17
+ ### Added
18
+
19
+ * Add simple queries feature flag ([#660](https://github.com/cap-js/cds-dbs/issues/660)) ([3335202](https://github.com/cap-js/cds-dbs/commit/33352024201a96cc6bdfa30a0fe3fff4227dee10))
20
+
21
+ ## [1.9.2](https://github.com/cap-js/cds-dbs/compare/db-service-v1.9.1...db-service-v1.9.2) (2024-05-28)
22
+
23
+
24
+ ### Fixed
25
+
26
+ * do not prepend table alias to session variables ([#656](https://github.com/cap-js/cds-dbs/issues/656)) ([24e8b19](https://github.com/cap-js/cds-dbs/commit/24e8b1995aff3ea971e22849d2f85605f45b0a26))
27
+
7
28
  ## [1.9.1](https://github.com/cap-js/cds-dbs/compare/db-service-v1.9.0...db-service-v1.9.1) (2024-05-16)
8
29
 
9
30
 
package/lib/SQLService.js CHANGED
@@ -65,21 +65,22 @@ class SQLService extends DatabaseService {
65
65
  return
66
66
  }
67
67
 
68
+ let changes = false
68
69
  for (let col of columns) {
69
70
  const name = col.as || col.ref?.[col.ref.length - 1] || (typeof col === 'string' && col)
70
71
  if (col.element?.isAssociation) {
71
72
  if (one) this._changeToStreams(col.SELECT.columns, rows[0][name], false, compat)
72
73
  else
73
- rows.forEach(row => {
74
- this._changeToStreams(col.SELECT.columns, row[name], false, compat)
75
- })
74
+ changes = rows.some(row => !this._changeToStreams(col.SELECT.columns, row[name], false, compat))
76
75
  } else if (col.element?.type === 'cds.LargeBinary') {
76
+ changes = true
77
77
  if (one) rows[0][name] = this._stream(rows[0][name])
78
78
  else
79
79
  rows.forEach(row => {
80
80
  row[name] = this._stream(row[name])
81
81
  })
82
82
  } else if (col.element?.type in BINARY_TYPES) {
83
+ changes = true
83
84
  if (one) rows[0][name] = this._buffer(rows[0][name])
84
85
  else
85
86
  rows.forEach(row => {
@@ -87,6 +88,7 @@ class SQLService extends DatabaseService {
87
88
  })
88
89
  }
89
90
  }
91
+ return changes
90
92
  }
91
93
 
92
94
  _stream(val) {
@@ -115,7 +117,7 @@ class SQLService extends DatabaseService {
115
117
  */
116
118
  async onSELECT({ query, data }) {
117
119
  if (!query.target) {
118
- try { this.infer(query) } catch (e) { /**/ }
120
+ try { this.infer(query) } catch { /**/ }
119
121
  }
120
122
  if (query.target && !query.target._unresolved) {
121
123
  // Will return multiple rows with objects inside
package/lib/cqn2sql.js CHANGED
@@ -1,6 +1,8 @@
1
1
  const cds = require('@sap/cds')
2
2
  const cds_infer = require('./infer')
3
3
  const cqn4sql = require('./cqn4sql')
4
+ const _simple_queries = cds.env.features.sql_simple_queries
5
+ const _strict_booleans = _simple_queries < 2
4
6
 
5
7
  const BINARY_TYPES = {
6
8
  'cds.Binary': 1,
@@ -257,18 +259,41 @@ class CQN2SQLRenderer {
257
259
  const SELECT = q.SELECT
258
260
  if (!SELECT.columns) return sql
259
261
 
260
- let cols = SELECT.columns.map(x => {
261
- const name = this.column_name(x)
262
- let col = `'$."${name}"',${this.output_converter4(x.element, this.quote(name))}`
263
- if (x.SELECT?.count) {
264
- // Return both the sub select and the count for @odata.count
265
- const qc = cds.ql.clone(x, { columns: [{ func: 'count' }], one: 1, limit: 0, orderBy: 0 })
266
- return [col, `'${name}@odata.count',${this.expr(qc)}`]
262
+ const isRoot = SELECT.expand === 'root'
263
+ const isSimple = _simple_queries &&
264
+ isRoot && // Simple queries are only allowed to have a root
265
+ !ObjectKeys(q.elements).some(e =>
266
+ _strict_booleans && q.elements[e].type === 'cds.Boolean' || // REVISIT: Booleans require json for sqlite
267
+ q.elements[e].isAssociation || // Indicates columns contains an expand
268
+ q.elements[e].$assocExpand || // REVISIT: sometimes associations are structs
269
+ q.elements[e].items // Array types require to be inlined with a json result
270
+ )
271
+
272
+ let cols = SELECT.columns.map(isSimple
273
+ ? x => {
274
+ const name = this.column_name(x)
275
+ const escaped = `${name.replace(/"/g, '""')}`
276
+ let col = `${this.output_converter4(x.element, this.quote(name))} AS "${escaped}"`
277
+ if (x.SELECT?.count) {
278
+ // Return both the sub select and the count for @odata.count
279
+ const qc = cds.ql.clone(x, { columns: [{ func: 'count' }], one: 1, limit: 0, orderBy: 0 })
280
+ return [col, `${this.expr(qc)} AS "${escaped}@odata.count"`]
281
+ }
282
+ return col
267
283
  }
268
- return col
269
- }).flat()
284
+ : x => {
285
+ const name = this.column_name(x)
286
+ const escaped = `${name.replace(/"/g, '""')}`
287
+ let col = `'$."${escaped}"',${this.output_converter4(x.element, this.quote(name))}`
288
+ if (x.SELECT?.count) {
289
+ // Return both the sub select and the count for @odata.count
290
+ const qc = cds.ql.clone(x, { columns: [{ func: 'count' }], one: 1, limit: 0, orderBy: 0 })
291
+ return [col, `'$."${escaped}@odata.count"',${this.expr(qc)}`]
292
+ }
293
+ return col
294
+ }).flat()
270
295
 
271
- const isRoot = SELECT.expand === 'root'
296
+ if (isSimple) return `SELECT ${cols} FROM (${sql})`
272
297
 
273
298
  // Prevent SQLite from hitting function argument limit of 100
274
299
  let obj = "'{}'"
package/lib/cqn4sql.js CHANGED
@@ -1798,6 +1798,10 @@ function cqn4sql(originalQuery, model) {
1798
1798
  if (res === '$self')
1799
1799
  // next is resolvable in entity
1800
1800
  return prev
1801
+ if (res in pseudos.elements) {
1802
+ thing.$refLinks.push({ definition: pseudos.elements[res], target: pseudos })
1803
+ return pseudos.elements[res]
1804
+ }
1801
1805
  const definition =
1802
1806
  prev?.elements?.[res] || getDefinition(prev?.target)?.elements[res] || pseudos.elements[res]
1803
1807
  const target = getParentEntity(definition)
@@ -1826,8 +1830,9 @@ function cqn4sql(originalQuery, model) {
1826
1830
  lhs.ref[0] in { $self: true, $projection: true } ? getParentEntity(assocRefLink.definition) : target,
1827
1831
  )
1828
1832
  else {
1829
- const lhsLeafArt = lhs.ref && lhs.$refLinks[lhs.$refLinks.length - 1].definition
1830
- const rhsLeafArt = rhs.ref && rhs.$refLinks[rhs.$refLinks.length - 1].definition
1833
+ const lhsLeafArt = lhs.ref && lhs.$refLinks.at(-1).definition
1834
+ const rhsLeafArt = rhs.ref && rhs.$refLinks.at(-1).definition
1835
+ // compare structures in on-condition
1831
1836
  if ((lhsLeafArt?.target && rhsLeafArt?.target) || (lhsLeafArt?.elements && rhsLeafArt?.elements)) {
1832
1837
  if (rhs.$refLinks[0].definition !== assocRefLink.definition) {
1833
1838
  rhs.ref.unshift(targetSideRefLink.alias)
@@ -1884,7 +1889,7 @@ function cqn4sql(originalQuery, model) {
1884
1889
  }
1885
1890
  result.splice(i, 3, ...(wrapInXpr ? [asXpr(backlinkOnCondition)] : backlinkOnCondition))
1886
1891
  i += wrapInXpr ? 1 : backlinkOnCondition.length // skip inserted tokens
1887
- } else if (lhs.ref) {
1892
+ } else if (lhs.ref && lhs.$refLinks[0]?.target !== pseudos) {
1888
1893
  if (lhs.ref[0] === '$self') {
1889
1894
  // $self in ref of length > 1
1890
1895
  // if $self is followed by association, the alias of the association must be used
@@ -1892,11 +1897,7 @@ function cqn4sql(originalQuery, model) {
1892
1897
  // otherwise $self is replaced by the alias of the entity
1893
1898
  else result[i].ref.splice(0, 1, targetSideRefLink.alias)
1894
1899
  } else if (lhs.ref.length > 1) {
1895
- if (
1896
- !(lhs.ref[0] in pseudos.elements) &&
1897
- lhs.ref[0] !== assocRefLink.alias &&
1898
- lhs.ref[0] !== targetSideRefLink.alias
1899
- ) {
1900
+ if (lhs.ref[0] !== assocRefLink.alias && lhs.ref[0] !== targetSideRefLink.alias) {
1900
1901
  // we need to find correct table alias for the structured access
1901
1902
  const { definition } = lhs.$refLinks[0]
1902
1903
  if (definition === assocRefLink.definition) {
@@ -1910,7 +1911,8 @@ function cqn4sql(originalQuery, model) {
1910
1911
  result[i].ref = [targetSideRefLink.alias, lhs.ref.join('_')]
1911
1912
  }
1912
1913
  }
1913
- } else if (lhs.ref.length === 1) result[i].ref.unshift(targetSideRefLink.alias)
1914
+ } else if (lhs.ref.length === 1)
1915
+ result[i].ref.unshift(targetSideRefLink.alias)
1914
1916
  }
1915
1917
  }
1916
1918
  return result
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/db-service",
3
- "version": "1.9.1",
3
+ "version": "1.10.1",
4
4
  "description": "CDS base database service",
5
5
  "homepage": "https://github.com/cap-js/cds-dbs/tree/main/db-service#cds-base-database-service",
6
6
  "repository": {
@@ -21,10 +21,6 @@
21
21
  "lib",
22
22
  "CHANGELOG.md"
23
23
  ],
24
- "engines": {
25
- "node": ">=16",
26
- "npm": ">=8"
27
- },
28
24
  "scripts": {
29
25
  "test": "jest --silent"
30
26
  },