@sap/cds 6.1.0 → 6.1.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/apis/log.d.ts +112 -36
  3. package/apis/services.d.ts +13 -2
  4. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +2 -3
  5. package/bin/build/provider/hana/index.js +4 -2
  6. package/bin/build/provider/mtx/resourcesTarBuilder.js +4 -8
  7. package/bin/deploy/to-hana/hana.js +20 -25
  8. package/bin/deploy/to-hana/hdiDeployUtil.js +13 -2
  9. package/lib/dbs/cds-deploy.js +2 -2
  10. package/lib/env/schemas/cds-rc.json +10 -1
  11. package/lib/index.js +1 -1
  12. package/lib/log/format/kibana.js +19 -1
  13. package/lib/ql/Query.js +9 -3
  14. package/lib/ql/SELECT.js +1 -1
  15. package/lib/ql/UPDATE.js +2 -2
  16. package/lib/ql/cds-ql.js +4 -10
  17. package/lib/req/context.js +15 -11
  18. package/lib/srv/srv-api.js +8 -0
  19. package/lib/srv/srv-dispatch.js +11 -7
  20. package/lib/srv/srv-models.js +4 -3
  21. package/lib/srv/srv-tx.js +52 -40
  22. package/lib/utils/cds-utils.js +3 -3
  23. package/lib/utils/resources/index.js +5 -5
  24. package/lib/utils/resources/tar.js +1 -1
  25. package/libx/_runtime/auth/index.js +2 -2
  26. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
  27. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +0 -2
  28. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +3 -1
  29. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +0 -2
  30. package/libx/_runtime/cds-services/services/utils/compareJson.js +3 -1
  31. package/libx/_runtime/cds-services/util/assert.js +3 -0
  32. package/libx/_runtime/common/generic/input.js +17 -2
  33. package/libx/_runtime/common/generic/put.js +4 -1
  34. package/libx/_runtime/common/generic/temporal.js +0 -3
  35. package/libx/_runtime/common/utils/binary.js +3 -4
  36. package/libx/_runtime/common/utils/keys.js +14 -6
  37. package/libx/_runtime/common/utils/propagateForeignKeys.js +122 -0
  38. package/libx/_runtime/common/utils/resolveView.js +1 -1
  39. package/libx/_runtime/common/utils/template.js +2 -3
  40. package/libx/_runtime/db/expand/expandCQNToJoin.js +1 -1
  41. package/libx/_runtime/db/expand/rawToExpanded.js +7 -6
  42. package/libx/_runtime/db/generic/input.js +7 -4
  43. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
  44. package/libx/_runtime/extensibility/add.js +3 -0
  45. package/libx/_runtime/extensibility/handler/transformREAD.js +20 -18
  46. package/libx/_runtime/extensibility/push.js +11 -11
  47. package/libx/_runtime/extensibility/token.js +2 -1
  48. package/libx/_runtime/extensibility/utils.js +8 -6
  49. package/libx/_runtime/fiori/generic/new.js +1 -3
  50. package/libx/_runtime/fiori/generic/patch.js +1 -7
  51. package/libx/_runtime/fiori/utils/where.js +1 -1
  52. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +1 -1
  53. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +1 -2
  54. package/libx/_runtime/remote/utils/client.js +29 -10
  55. package/libx/_runtime/sqlite/Service.js +7 -5
  56. package/libx/_runtime/sqlite/execute.js +41 -28
  57. package/libx/odata/cqn2odata.js +6 -2
  58. package/libx/rest/RestAdapter.js +3 -6
  59. package/libx/rest/middleware/input.js +2 -3
  60. package/package.json +1 -1
  61. package/srv/extensibility-service.cds +4 -3
  62. package/srv/model-provider.js +1 -1
  63. package/srv/mtx.js +18 -9
  64. package/libx/_runtime/db/utils/propagateForeignKeys.js +0 -93
@@ -187,11 +187,13 @@ module.exports = class SQLiteDatabase extends DatabaseService {
187
187
  return
188
188
  }
189
189
 
190
- const tx = this.transaction()
191
- await tx.run(dropViews)
192
- await tx.run(dropTables)
193
- await tx.run(createEntities)
194
- await tx.commit()
190
+ await this.run(async tx => {
191
+ // This starts a new transaction if called from CLI, while joining
192
+ // existing root tx, e.g. when called from DeploymenrService
193
+ await tx.run(dropViews)
194
+ await tx.run(dropTables)
195
+ await tx.run(createEntities)
196
+ })
195
197
 
196
198
  return true
197
199
  }
@@ -19,31 +19,47 @@ const SANITIZE_VALUES = process.env.NODE_ENV === 'production' && cds.env.log.san
19
19
  * -> only if DEBUG (which should not be used in production)
20
20
  */
21
21
  const DEBUG = cds.debug('sqlite')
22
- const _captureStack = DEBUG
23
- ? () => {
24
- const o = {}
25
- Error.captureStackTrace(o, _captureStack)
26
- return o
22
+ const _exec = DEBUG
23
+ ? (dbc, op, ...args) => {
24
+ const callback = args[args.length - 1]
25
+ const captured = {}
26
+ Error.captureStackTrace(captured, _exec)
27
+ args[args.length - 1] = function (err) {
28
+ if (err) {
29
+ err.message += ' in: \n' + args[0]
30
+ err.query = args[0]
31
+ if (args.length > 2) err.values = SANITIZE_VALUES ? ['***'] : args[1]
32
+ err.stack =
33
+ err.message +
34
+ captured.stack
35
+ .slice(5)
36
+ .replace(/at( _exec)? /, 'at SQLite.' + op + ' ')
37
+ .replace(/\s+at new Promise .*\n.*/, '')
38
+ }
39
+ callback.apply(this, arguments)
40
+ }
41
+ return dbc[op](...args)
42
+ }
43
+ : (dbc, op, ...args) => {
44
+ const callback = args[args.length - 1]
45
+ args[args.length - 1] = function (err) {
46
+ if (err) {
47
+ err.message += ' in: \n' + args[0]
48
+ err.query = args[0]
49
+ if (args.length > 2) err.values = SANITIZE_VALUES ? ['***'] : args[1]
50
+ }
51
+ callback.apply(this, arguments)
52
+ }
53
+ return dbc[op](...args)
27
54
  }
28
- : () => undefined
29
-
30
- const _augmented = (err, sql, values, o) => {
31
- err.query = sql
32
- if (values) err.values = SANITIZE_VALUES ? ['***'] : values
33
- err.message += ' in: \n' + sql
34
- if (o) err.stack = err.message + o.stack.slice(5)
35
- return err
36
- }
37
55
 
38
56
  function _executeSimpleSQL(dbc, sql, values) {
39
57
  LOG._debug &&
40
58
  LOG.debug(coloredTxCommands[sql] || sql, Array.isArray(values) ? (SANITIZE_VALUES ? ['***'] : values) : '')
41
59
 
42
60
  return new Promise((resolve, reject) => {
43
- const o = _captureStack()
44
- dbc.run(sql, values, function (err) {
45
- if (err) return reject(_augmented(err, sql, values, o))
46
-
61
+ _exec(dbc, 'run', sql, values, function (err) {
62
+ if (err) return reject(err)
47
63
  resolve(this.changes)
48
64
  })
49
65
  })
@@ -53,9 +69,8 @@ function executeSelectSQL(dbc, sql, values, isOne, postMapper) {
53
69
  LOG._debug && LOG.debug(sql, SANITIZE_VALUES ? ['***'] : values)
54
70
 
55
71
  return new Promise((resolve, reject) => {
56
- const o = _captureStack()
57
- dbc[isOne ? 'get' : 'all'](sql, values, (err, result) => {
58
- if (err) return reject(_augmented(err, sql, values, o))
72
+ _exec(dbc, isOne ? 'get' : 'all', sql, values, (err, result) => {
73
+ if (err) return reject(err)
59
74
 
60
75
  // REVISIT
61
76
  // .get returns undefined if nothing in db
@@ -140,9 +155,8 @@ const _executeBulkInsertSQL = (dbc, sql, values) =>
140
155
  }
141
156
 
142
157
  LOG._debug && LOG.debug(sql, SANITIZE_VALUES ? ['***'] : values)
143
- const o = _captureStack()
144
- const stmt = dbc.prepare(sql, err => {
145
- if (err) return reject(_augmented(err, sql, values, o))
158
+ const stmt = _exec(dbc, 'prepare', sql, err => {
159
+ if (err) return reject(err)
146
160
 
147
161
  if (!Array.isArray(values[0])) values = [values]
148
162
 
@@ -159,7 +173,7 @@ const _executeBulkInsertSQL = (dbc, sql, values) =>
159
173
  if (!isFinalized) {
160
174
  isFinalized = true
161
175
  stmt.finalize()
162
- return reject(_augmented(err, sql, each, o))
176
+ return reject(err)
163
177
  }
164
178
  }
165
179
 
@@ -212,9 +226,8 @@ function executeInsertSQL(dbc, sql, values, query) {
212
226
  LOG._debug && LOG.debug(sql, SANITIZE_VALUES ? ['***'] : values)
213
227
 
214
228
  return new Promise((resolve, reject) => {
215
- const o = _captureStack()
216
- dbc.run(sql, values, function (err) {
217
- if (err) return reject(_augmented(err, sql, values, o))
229
+ _exec(dbc, 'run', sql, values, function (err) {
230
+ if (err) return reject(err)
218
231
 
219
232
  // InsertResult needs an object per row with its values
220
233
  if (query && values.length > 0) {
@@ -200,8 +200,12 @@ const _keysOfWhere = (where, kind, target) => {
200
200
  if (where.length === 3) {
201
201
  const [left, op, right] = where
202
202
  if (op === '=' && (('val' in left && right.ref) || (left.ref && 'val' in right))) {
203
- if ('val' in left) return `(${formatVal(left.val, right.ref.join('/'), target, kind)})`
204
- return `(${formatVal(right.val, left.ref.join('/'), target, kind)})`
203
+ const formattedValue =
204
+ 'val' in left
205
+ ? formatVal(left.val, right.ref.join('/'), target, kind)
206
+ : formatVal(right.val, left.ref.join('/'), target, kind)
207
+
208
+ return `(${encodeURIComponent(formattedValue)})`
205
209
  }
206
210
  }
207
211
 
@@ -117,8 +117,7 @@ const RestAdapter = function(srv) {
117
117
  // begin tx
118
118
  router.use((req, res, next) => { // REVISIT: -> move to actual handler(s)
119
119
  // create tx and set as cds.context
120
- // REVISIT: req._tx should not be used like that!
121
- req.tx = cds.context = srv.tx({ user: req.user, req, res })
120
+ cds.context = srv.tx(new cds.EventContext({ user: req.user, req, res }))
122
121
  next()
123
122
  })
124
123
 
@@ -148,8 +147,7 @@ const RestAdapter = function(srv) {
148
147
 
149
148
  // unfortunately, express doesn't catch async errors -> try catch needed
150
149
  try {
151
- // REVISIT: req._tx should not be used like that!
152
- await req.tx.commit(result)
150
+ await cds.context?.tx?.commit(result)
153
151
  } catch (e) {
154
152
  return next(e)
155
153
  }
@@ -179,8 +177,7 @@ const RestAdapter = function(srv) {
179
177
  // request may fail during processing or during commit -> both caught here
180
178
 
181
179
  // REVISIT: rollback needed if error occured before commit attempted -> how to distinguish?
182
- // REVISIT: req._tx should not be used like that!
183
- if (req.tx) req.tx.rollback(err).catch(() => {}) // REVISIT: silently ?!?
180
+ cds.context?.tx?.rollback(err).catch(() => {}) // REVISIT: silently ?!?
184
181
 
185
182
  next(err)
186
183
  })
@@ -1,10 +1,9 @@
1
1
  // const cds = require('../../_runtime/cds')
2
2
  const getTemplate = require('../../_runtime/common/utils/template')
3
3
  const templateProcessor = require('../../_runtime/common/utils/templateProcessor')
4
- const { checkStaticElementByKey, assertNotNullError } = require('../../_runtime/cds-services/util/assert')
4
+ const { checkStaticElementByKey } = require('../../_runtime/cds-services/util/assert')
5
5
  const { MULTIPLE_ERRORS } = require('../../_runtime/common/error/constants')
6
6
 
7
-
8
7
  //
9
8
  // REVISIT: We need to decipher what we are doing here...
10
9
  //
@@ -20,7 +19,7 @@ const _picker = () => {
20
19
  }
21
20
 
22
21
  const _processorFn = errors => {
23
- return ({ row, key, plain: categories, target, element }) => {
22
+ return ({ row, key, plain: categories, target }) => {
24
23
  // REVISIT move validation to generic asserter => see PR 717
25
24
  if (categories['static_validation'] && row[key] != null) {
26
25
  const validations = checkStaticElementByKey(target, key, row[key])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds",
3
- "version": "6.1.0",
3
+ "version": "6.1.3",
4
4
  "description": "SAP Cloud Application Programming Model - CDS for Node.js",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [
@@ -1,5 +1,5 @@
1
+ // using { cds.xt.TAR } from './model-provider'; //> IMPORTANT: don't add this as it will cause services loaded twice
1
2
  using { cds.xt.Extensions } from './extensions';
2
- using { cds.xt.TAR } from './model-provider';
3
3
 
4
4
  @protocol: 'rest'
5
5
  @(requires : 'authenticated-user')
@@ -8,7 +8,8 @@ service cds.xt.ExtensibilityService @(path:'/-/cds/extensibility', impl:'@sap/cd
8
8
  // TODO: async jobs
9
9
 
10
10
  type ActivationLevel : Extensions:activated;
11
- type CSN: String; // REVISIT: should reuse cds.xt.CSN
11
+ type TAR : LargeBinary;
12
+ type CSN : String; // REVISIT: should reuse cds.xt.CSN
12
13
  type CSN_OR_CDL: String;
13
14
 
14
15
  // UIFLEX API
@@ -46,7 +47,7 @@ service cds.xt.ExtensibilityService @(path:'/-/cds/extensibility', impl:'@sap/cd
46
47
 
47
48
  @(requires : ['cds.ExtensionDeveloper'])
48
49
  action push (
49
- extension : TAR,
50
+ extension : LargeBinary, // REVISIT: Using TAR here leads to a strange type check failure
50
51
  tag : Extensions:tag
51
52
  // activate : ActivationLevel
52
53
  );
@@ -109,7 +109,7 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
109
109
  const extensions = !base && await _getExtensions4 (req.data.tenant)
110
110
  if (!extensions && checkExt) req.reject(404, 'Missing extensions')
111
111
 
112
- const features = !toggles ? [] : toggles === '*' || toggles.includes('*') ? [fts] : toggles.map (f => fts.replace('*',f))
112
+ const features = (!toggles || !main.requires.toggles) ? [] : toggles === '*' || toggles.includes('*') ? [fts] : toggles.map (f => fts.replace('*',f))
113
113
  const models = cds.resolve (['*',...features], main); if (!models) return
114
114
 
115
115
  DEBUG && DEBUG ('loading models for', { tenant, toggles } ,'from', models.map (cds.utils.local))
package/srv/mtx.js CHANGED
@@ -8,19 +8,28 @@ class MTXServices extends cds.Service { async init(){
8
8
  }
9
9
  // else...
10
10
  DEBUG && DEBUG ('bootstrapping MTX services...')
11
+ let defs = cds.model.definitions
11
12
  let sources = []
12
- if (cds.requires.multitenancy) {
13
- if (!('cds.xt.DeploymentService' in cds.requires)) {
14
- sources.push('@sap/cds-mtxs/srv/deployment-service')
15
- if (!('cds.xt.SaasProvisioningService' in cds.requires)) sources.push('@sap/cds-mtxs/srv/cf/saas-provisioning-service')
16
- }
13
+
14
+ if (cds.requires.multitenancy && !('cds.xt.SaasProvisioningService' in defs)) {
15
+ sources.push('@sap/cds-mtxs/srv/cf/saas-provisioning-service')
16
+ sources.push('@sap/cds/srv/model-provider')
17
+ }
18
+
19
+ if (cds.requires.multitenancy && !('cds.xt.DeploymentService' in defs)) {
20
+ sources.push('@sap/cds-mtxs/srv/deployment-service')
21
+ sources.push('@sap/cds/srv/model-provider')
17
22
  }
18
- if (cds.requires.extensibility) {
19
- if (!('cds.xt.ExtensibilityService' in cds.requires)) sources.push('@sap/cds/srv/extensibility-service')
23
+
24
+ if (cds.requires.extensibility && !('cds.xt.ExtensibilityService' in defs)) {
25
+ sources.push('@sap/cds/srv/extensibility-service')
26
+ sources.push('@sap/cds/srv/model-provider')
20
27
  }
21
- if (cds.requires.toggles) {
22
- if (!('cds.xt.ModelProviderService' in cds.requires)) sources.push('@sap/cds/srv/model-provider')
28
+
29
+ if (cds.requires.toggles && !('cds.xt.ModelProviderService' in defs)) {
30
+ sources.push('@sap/cds/srv/model-provider')
23
31
  }
32
+
24
33
  let models = cds.resolve(sources); if (!models) return
25
34
  let base = cds.model.$sources; models = models.filter(m => !base.includes(m))
26
35
  if (models.length) return cds.serve(models).in(cds.app)
@@ -1,93 +0,0 @@
1
- const cds = require('../../cds')
2
-
3
- const { prefixForStruct } = require('../../common/utils/csn')
4
-
5
- const _autoGenerate = e => e && e.isUUID && e.key
6
-
7
- const _generateParentField = ({ parentElement }, row) => {
8
- if (_autoGenerate(parentElement) && !row[parentElement.name]) {
9
- row[parentElement.name] = cds.utils.uuid()
10
- }
11
- }
12
-
13
- const _generateChildField = ({ deep, childElement }, childRow) => {
14
- if (deep) {
15
- _generateChildField(deep.propagation, childRow[deep.targetName])
16
- } else if (_autoGenerate(childElement) && childRow && !childRow[childElement.name]) {
17
- childRow[childElement.name] = cds.utils.uuid()
18
- }
19
- }
20
-
21
- const _getNestedVal = (row, prefix) => {
22
- let val = row
23
- const splitted = prefix.split('_')
24
- splitted.pop() // remove last `_`
25
- let k = ''
26
-
27
- while (splitted.length > 0) {
28
- k += splitted.shift()
29
- if (k in val) {
30
- val = val[k]
31
- k = ''
32
- } else {
33
- k += '_'
34
- }
35
- }
36
-
37
- return val
38
- }
39
-
40
- const _propagateToChid = ({ parentElement, childElement, parentFieldValue }, row, childRow) => {
41
- if (!childElement) return
42
- if (parentElement) {
43
- const prefix = prefixForStruct(parentElement)
44
- if (prefix) {
45
- const nested = _getNestedVal(row, prefix)
46
- childRow[childElement.name] = nested[parentElement.name]
47
- } else {
48
- childRow[childElement.name] = row[parentElement.name]
49
- }
50
- } else if (parentFieldValue !== undefined) {
51
- childRow[childElement.name] = parentFieldValue
52
- }
53
- }
54
-
55
- const _propagateToParent = ({ parentElement, childElement, deep }, childRow, row) => {
56
- if (deep) {
57
- _propagateToParent(deep.propagation, childRow[deep.targetName], childRow)
58
- }
59
- if (parentElement && childElement && childRow && childElement.name in childRow) {
60
- row[parentElement.name] = childRow[childElement.name]
61
- }
62
- }
63
-
64
- module.exports = (tKey, row, foreignKeyPropagations, isCompositionEffective) => {
65
- if (row[tKey] === null) {
66
- for (const foreignKeyPropagation of foreignKeyPropagations) {
67
- if (!foreignKeyPropagation.fillChild) row[foreignKeyPropagation.parentElement.name] = null
68
- }
69
- if (!isCompositionEffective) delete row[tKey]
70
- return
71
- }
72
-
73
- const childRows = Array.isArray(row[tKey]) ? row[tKey] : [row[tKey]]
74
-
75
- for (const childRow of childRows) {
76
- if (!childRow) return
77
-
78
- for (const foreignKeyPropagation of foreignKeyPropagations) {
79
- if (foreignKeyPropagation.fillChild) {
80
- // propagate or generate in parent
81
- const pk = foreignKeyPropagation.parentElement && foreignKeyPropagation.parentElement.name
82
- if (pk && !(pk in row)) _propagateToParent(foreignKeyPropagation, childRow, row)
83
- if (!(pk in row)) _generateParentField(foreignKeyPropagation, row)
84
-
85
- if (isCompositionEffective) _propagateToChid(foreignKeyPropagation, row, childRow)
86
- } else {
87
- _generateChildField(foreignKeyPropagation, childRow)
88
- _propagateToParent(foreignKeyPropagation, childRow, row)
89
- }
90
- }
91
- }
92
- if (!isCompositionEffective) delete row[tKey]
93
- }