@sap/cds 9.8.2 → 9.8.3

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,12 @@
4
4
  - The format is based on [Keep a Changelog](https://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## Version 9.8.3 - 2026-03-12
8
+
9
+ ### Fixed
10
+
11
+ - OData batch parallel processing: Drain remaining queue when aborting
12
+
7
13
  ## Version 9.8.2 - 2026-03-10
8
14
 
9
15
  ### Fixed
@@ -47,7 +47,7 @@ class HCQLAdapter extends require('./http') {
47
47
 
48
48
  // Error formatting
49
49
  router.use ((err, req, res, next) => {
50
- err.$response = e => ({ errors: [ { ...e, message: e.message } ] })
50
+ if (typeof err === 'object') err.$response = e => ({ errors: [ { ...e, message: e.message } ] })
51
51
  next(err)
52
52
  })
53
53
 
@@ -487,42 +487,43 @@ const _processBatch = async (srv, router, req, res, next, body, ct, boundary) =>
487
487
 
488
488
  // ensure all subrequests run in this tx
489
489
  // (if first subrequest fails without really opening the tx, the rest are executed in a "dangling tx")
490
- return Promise.allSettled(subrequests)
491
- .then(ress => {
492
- // wait for all previous atomicity groups (ignoring errors via allSettled) for odata v2
493
- const prevs = []
494
- for (let i = 0; i < agIndex; i++) prevs.push(promises[i])
495
- return Promise.allSettled(prevs).then(() => ress)
496
- })
497
- .then(ress => {
498
- const failed = ress.filter(({ status }) => status === 'rejected')
499
- if (!failed.length) return
500
- // throw first error and call srv.on('error') for the others
501
- const first = failed.shift()
502
- if (srv.handlers._error?.length)
503
- for (const other of failed)
504
- for (const each of srv.handlers._error) each.handler.call(srv, other.reason, cds.context)
505
- throw first.reason
506
- })
490
+ return Promise.allSettled(subrequests).then(ress => {
491
+ const failed = ress.filter(({ status }) => status === 'rejected')
492
+ if (!failed.length) return
493
+ // throw first error and call srv.on('error') for the others
494
+ const first = failed.shift()
495
+ if (srv.handlers._error?.length)
496
+ for (const other of failed)
497
+ for (const each of srv.handlers._error) each.handler.call(srv, other.reason, cds.context)
498
+ throw first.reason
499
+ })
507
500
  })
508
501
  .catch(err => {
509
502
  responses._has_failure = true
510
503
 
511
504
  // abort batch on first failure with odata.continue-on-error: false
512
- if (!continue_on_error) _continue = false
505
+ if (!continue_on_error) {
506
+ _continue = false
507
+ while (queue.length) queue.shift()()
508
+ }
513
509
 
514
510
  if (!responses.some(r => r.status === 'fail')) {
515
511
  // here, the commit was rejected even though all requests were successful (e.g., by custom handler or db consistency check)
516
512
  _replaceResponsesWithCommitErrors(err, responses, ids)
517
513
  }
518
514
  })
519
- .finally(() => {
515
+ .finally(async () => {
520
516
  // trigger next in queue
521
517
  if (queue.length) queue.shift()()
522
518
 
523
519
  // late error serialization
524
520
  if (responses._has_failure) _serializeErrors(responses)
525
521
 
522
+ // wait for all previous atomicity groups (ignoring errors via allSettled) for odata v2
523
+ const prevs = []
524
+ for (let i = 0; i < agIndex; i++) prevs.push(promises[i])
525
+ await Promise.allSettled(prevs)
526
+
526
527
  if (isJson) _writeResponseJson(responses, res)
527
528
  else _writeResponseMultipart(responses, res, boundary)
528
529
  })
@@ -540,7 +541,7 @@ const _processBatch = async (srv, router, req, res, next, body, ct, boundary) =>
540
541
  // trigger first max_parallel in queue
541
542
  for (let i = 0; i < max_parallel; i++) if (queue.length) queue.shift()()
542
543
 
543
- await Promise.all(promises)
544
+ await Promise.allSettled(promises)
544
545
 
545
546
  res.write(isJson ? ']}' : `--${boundary}--${CRLF}`)
546
547
  res.end()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds",
3
- "version": "9.8.2",
3
+ "version": "9.8.3",
4
4
  "description": "SAP Cloud Application Programming Model - CDS for Node.js",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [