@cap-js/db-service 1.4.0 → 1.5.0

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,19 @@
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.5.0](https://github.com/cap-js/cds-dbs/compare/db-service-v1.4.0...db-service-v1.5.0) (2023-12-06)
8
+
9
+
10
+ ### Added
11
+
12
+ * Improved connection pool for HANAService ([#349](https://github.com/cap-js/cds-dbs/issues/349)) ([1c284e6](https://github.com/cap-js/cds-dbs/commit/1c284e69cccd76daad52249c0462bc62aa4d11a8))
13
+
14
+
15
+ ### Fixed
16
+
17
+ * **localized:** `ref`s in subqueries in `from` are translated ([#366](https://github.com/cap-js/cds-dbs/issues/366)) ([cfe4897](https://github.com/cap-js/cds-dbs/commit/cfe489715db0854d30b90b7f13c024e6e90be497))
18
+ * wrong odata count in filter with groupby ([#352](https://github.com/cap-js/cds-dbs/issues/352)) ([70690a1](https://github.com/cap-js/cds-dbs/commit/70690a1a13e72bfbb66f03bf315d3f2d48672bf6))
19
+
7
20
  ## [1.4.0](https://github.com/cap-js/cds-dbs/compare/db-service-v1.3.2...db-service-v1.4.0) (2023-11-20)
8
21
 
9
22
 
package/lib/SQLService.js CHANGED
@@ -230,16 +230,15 @@ class SQLService extends DatabaseService {
230
230
  if (max === undefined || (n < max && (n || !offset))) return n + offset
231
231
  }
232
232
  // REVISIT: made uppercase count because of HANA reserved word quoting
233
- const cq = cds.ql.clone(query, {
234
- columns: [{ func: 'count', as: 'COUNT' }],
233
+ const cq = SELECT.one([{ func: 'count', as: 'COUNT' }]).from(
234
+ cds.ql.clone(query, {
235
235
  localized: false,
236
236
  expand: false,
237
- limit: 0,
238
- orderBy: 0,
239
- })
240
- const { sql, values } = this.cqn2sql(cq)
241
- const ps = await this.prepare(sql)
242
- const { count, COUNT } = await ps.get(values)
237
+ limit: undefined,
238
+ orderBy: undefined,
239
+ }),
240
+ )
241
+ const { count, COUNT } = await this.onSELECT({ query: cq })
243
242
  return count ?? COUNT
244
243
  }
245
244
 
@@ -280,12 +279,12 @@ class SQLService extends DatabaseService {
280
279
  */
281
280
  cqn2sql(query, values) {
282
281
  let q = this.cqn4sql(query)
283
- if (q.SELECT && q.elements) q.SELECT.expand = q.SELECT.expand ?? 'root'
282
+ if (q.SELECT && 'elements' in q) q.SELECT.expand ??= 'root'
284
283
 
285
- let cmd = q.cmd || Object.keys(q)[0]
286
- if (cmd in { INSERT: 1, DELETE: 1, UPSERT: 1, UPDATE: 1 } || q.STREAM?.into) {
284
+ let kind = q.kind || Object.keys(q)[0]
285
+ if (kind in { INSERT: 1, DELETE: 1, UPSERT: 1, UPDATE: 1 } || q.STREAM?.into) {
287
286
  q = resolveView(q, this.model, this) // REVISIT: before resolveView was called on flat cqn obtained from cqn4sql -> is it correct to call on original q instead?
288
- let target = q[cmd]._transitions?.[0].target
287
+ let target = q[kind]._transitions?.[0].target
289
288
  if (target) q.target = target // REVISIT: Why isn't that done in resolveView?
290
289
  }
291
290
  let cqn2sql = new this.class.CQN2SQL(this)
@@ -63,6 +63,7 @@ class DatabaseService extends cds.Service {
63
63
 
64
64
  // Acquire a pooled connection
65
65
  this.dbc = await this.acquire()
66
+ this.dbc.destroy = this.destroy.bind(this)
66
67
 
67
68
  // Begin a session...
68
69
  try {
@@ -110,8 +111,20 @@ class DatabaseService extends cds.Service {
110
111
  */
111
112
  async release() {
112
113
  if (!this.dbc) return
113
- await this.pool.release(this.dbc)
114
+ const dbc = this.dbc
114
115
  this.dbc = undefined
116
+ await this.pool.release(dbc)
117
+ }
118
+
119
+ /**
120
+ * Destroys own connection, i.e. tix.dbc, from this.pool
121
+ * This is for subclasses to intercept, if required.
122
+ */
123
+ async destroy() {
124
+ if (!this.dbc) return
125
+ const dbc = this.dbc
126
+ this.dbc = undefined
127
+ await this.pool.destroy(dbc)
115
128
  }
116
129
 
117
130
  // REVISIT: should happen automatically after a configurable time
package/lib/cqn2sql.js CHANGED
@@ -62,14 +62,14 @@ class CQN2SQLRenderer {
62
62
  * @returns {CQN2SQLRenderer|unknown}
63
63
  */
64
64
  render(q, vars) {
65
- const cmd = q.cmd || Object.keys(q)[0] // SELECT, INSERT, ...
65
+ const kind = q.kind || Object.keys(q)[0] // SELECT, INSERT, ...
66
66
  /**
67
67
  * @type {string} the rendered SQL string
68
68
  */
69
69
  this.sql = '' // to have it as first property for debugging
70
70
  /** @type {unknown[]} */
71
71
  this.values = [] // prepare values, filled in by subroutines
72
- this[cmd]((this.cqn = q)) // actual sql rendering happens here
72
+ this[kind]((this.cqn = q)) // actual sql rendering happens here
73
73
  if (vars?.length && !this.values?.length) this.values = vars
74
74
  const sanitize_values = process.env.NODE_ENV === 'production' && cds.env.log.sanitize_values !== false
75
75
  DEBUG?.(
@@ -208,9 +208,8 @@ class CQN2SQLRenderer {
208
208
  if (limit) sql += ` LIMIT ${this.limit(limit)}`
209
209
  // Expand cannot work without an inferred query
210
210
  if (expand) {
211
- // REVISIT: Why don't we handle that as an error in SELECT_expand?
212
- if (!q.elements) cds.error`Query was not inferred and includes expand. For which the metadata is missing.`
213
- sql = this.SELECT_expand(q, sql)
211
+ if ('elements' in q) sql = this.SELECT_expand (q,sql)
212
+ else cds.error`Query was not inferred and includes expand. For which the metadata is missing.`
214
213
  }
215
214
  return (this.sql = sql)
216
215
  }
@@ -230,10 +229,12 @@ class CQN2SQLRenderer {
230
229
  * @param {string} sql
231
230
  * @returns {string} SQL
232
231
  */
233
- SELECT_expand({ SELECT, elements }, sql) {
232
+ SELECT_expand(q, sql) {
233
+ if (!('elements' in q)) return sql
234
+
235
+ const SELECT = q.SELECT
234
236
  if (!SELECT.columns) return sql
235
- if (!elements) return sql // REVISIT: Above we say this is an error condition, but here we say it's ok?
236
-
237
+
237
238
  let cols = SELECT.columns.map(x => {
238
239
  const name = this.column_name(x)
239
240
  let col = `'${name}',${this.output_converter4(x.element, this.quote(name))}`
@@ -256,7 +257,7 @@ class CQN2SQLRenderer {
256
257
  }
257
258
  // REVISIT: json_merge is a user defined function, bad performance!
258
259
  obj = `json_merge(${chunks})`
259
- }
260
+ }
260
261
 
261
262
 
262
263
  return `SELECT ${SELECT.one || SELECT.expand === 'root' ? obj : `json_group_array(${obj.includes('json_merge') ? `json_insert(${obj})` : obj})`} as _json_ FROM (${sql})`
package/lib/cqn4sql.js CHANGED
@@ -48,7 +48,7 @@ function cqn4sql(originalQuery, model = cds.context?.model || cds.model) {
48
48
  if (originalQuery.SELECT?.from.args && !originalQuery.joinTree) return inferred
49
49
 
50
50
  let transformedQuery = cds.ql.clone(inferred)
51
- const kind = inferred.cmd || Object.keys(inferred)[0]
51
+ const kind = inferred.kind || Object.keys(inferred)[0]
52
52
 
53
53
  if (inferred.INSERT || inferred.UPSERT) {
54
54
  transformedQuery = transformQueryForInsertUpsert(kind)
@@ -415,7 +415,6 @@ function cqn4sql(originalQuery, model = cds.context?.model || cds.model) {
415
415
  return transformedColumns
416
416
 
417
417
  function handleSubquery(col) {
418
- if (isLocalized(inferred.target)) col.SELECT.localized = true
419
418
  if (!col.SELECT.from.as) {
420
419
  const uniqueSubqueryAlias = inferred.joinTree.addNextAvailableTableAlias(
421
420
  getLastStringSegment(col.SELECT.from.ref[col.SELECT.from.ref.length - 1]),
@@ -830,7 +829,6 @@ function cqn4sql(originalQuery, model = cds.context?.model || cds.model) {
830
829
  one: column.$refLinks[column.$refLinks.length - 1].definition.is2one,
831
830
  },
832
831
  }
833
- if (isLocalized(inferred.target)) subquery.SELECT.localized = true
834
832
  const expanded = transformSubquery(subquery)
835
833
  const correlated = _correlate({ ...expanded, as: columnAlias }, outerAlias)
836
834
  Object.defineProperty(correlated, 'elements', { value: subquery.elements, writable: true })
@@ -946,6 +944,7 @@ function cqn4sql(originalQuery, model = cds.context?.model || cds.model) {
946
944
  outerQueries.push(inferred)
947
945
  Object.defineProperty(q, 'outerQueries', { value: outerQueries })
948
946
  }
947
+ if (isLocalized(inferred.target)) q.SELECT.localized = true
949
948
  return cqn4sql(q, model)
950
949
  }
951
950
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/db-service",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
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": {