@sap/cds 7.8.1 → 7.9.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.
Files changed (137) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/_i18n/i18n_ar.properties +3 -0
  3. package/_i18n/i18n_cs.properties +3 -0
  4. package/_i18n/i18n_da.properties +3 -0
  5. package/_i18n/i18n_es_MX.properties +3 -0
  6. package/_i18n/i18n_fi.properties +3 -0
  7. package/_i18n/i18n_hu.properties +6 -0
  8. package/_i18n/i18n_ko.properties +3 -0
  9. package/_i18n/i18n_ms.properties +3 -0
  10. package/_i18n/i18n_nl.properties +3 -0
  11. package/_i18n/i18n_no.properties +3 -0
  12. package/_i18n/i18n_ro.properties +3 -0
  13. package/_i18n/i18n_sv.properties +3 -0
  14. package/_i18n/i18n_th.properties +3 -0
  15. package/_i18n/i18n_tr.properties +6 -0
  16. package/_i18n/i18n_zh_TW.properties +3 -0
  17. package/bin/serve.js +5 -5
  18. package/lib/auth/basic-auth.js +1 -1
  19. package/lib/compile/cdsc.js +33 -6
  20. package/lib/compile/etc/_localized.js +14 -7
  21. package/lib/compile/for/lean_drafts.js +9 -0
  22. package/lib/compile/to/edm-files.js +116 -0
  23. package/lib/compile/to/edm.js +8 -1
  24. package/lib/compile/to/hdbtabledata.js +3 -3
  25. package/lib/compile/to/sql.js +4 -2
  26. package/lib/compile/to/yaml.js +22 -21
  27. package/lib/dbs/cds-deploy.js +5 -6
  28. package/lib/env/cds-env.js +7 -0
  29. package/lib/env/cds-requires.js +20 -1
  30. package/lib/env/defaults.js +21 -5
  31. package/lib/env/schemas/cds-package.js +1 -1
  32. package/lib/env/schemas/cds-rc.js +85 -4
  33. package/lib/index.js +1 -1
  34. package/lib/linked/classes.js +2 -2
  35. package/lib/linked/entities.js +10 -0
  36. package/lib/linked/models.js +1 -1
  37. package/lib/plugins.js +1 -1
  38. package/lib/ql/INSERT.js +17 -3
  39. package/lib/ql/Query.js +4 -0
  40. package/lib/ql/infer.js +1 -1
  41. package/lib/req/request.js +1 -1
  42. package/lib/srv/cds-serve.js +1 -0
  43. package/lib/srv/middlewares/cds-context.js +1 -1
  44. package/lib/srv/protocols/odata-v4.js +5 -6
  45. package/lib/srv/srv-models.js +9 -2
  46. package/lib/utils/cds-test.js +2 -0
  47. package/lib/utils/cds-utils.js +9 -4
  48. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
  49. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
  50. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  51. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -1
  52. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +3 -6
  53. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +22 -10
  54. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +4 -4
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +4 -3
  56. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +1 -1
  57. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +4 -1
  58. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  59. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +38 -1
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +2 -2
  61. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +32 -21
  62. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +1 -1
  63. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +1 -2
  64. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +0 -10
  65. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +3 -1
  66. package/libx/_runtime/cds-services/services/utils/compareJson.js +2 -274
  67. package/libx/_runtime/{cds-services/services → common}/Service.js +39 -29
  68. package/libx/_runtime/common/generic/auth/autoexpose.js +41 -0
  69. package/libx/_runtime/common/generic/auth/index.js +2 -0
  70. package/libx/_runtime/common/generic/auth/readOnly.js +0 -11
  71. package/libx/_runtime/common/generic/auth/restrict.js +6 -5
  72. package/libx/_runtime/common/generic/auth/utils.js +1 -1
  73. package/libx/_runtime/common/generic/crud.js +5 -8
  74. package/libx/_runtime/common/generic/etag.js +8 -6
  75. package/libx/_runtime/common/generic/sorting.js +2 -2
  76. package/libx/_runtime/common/i18n/messages.properties +1 -0
  77. package/libx/_runtime/{cds-services/services → common}/utils/columns.js +4 -4
  78. package/libx/_runtime/common/utils/compareJson.js +274 -0
  79. package/libx/_runtime/common/utils/cqn2cqn4sql.js +1 -1
  80. package/libx/_runtime/{cds-services/services → common}/utils/differ.js +8 -8
  81. package/libx/_runtime/common/utils/ensureIEEE754.js +29 -0
  82. package/libx/_runtime/common/utils/{postProcessing.js → postProcess.js} +1 -3
  83. package/libx/_runtime/common/utils/resolveView.js +0 -16
  84. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -1
  85. package/libx/_runtime/common/utils/search2cqn4sql.js +1 -1
  86. package/libx/_runtime/common/utils/streamProp.js +9 -2
  87. package/libx/_runtime/common/utils/ucsn.js +1 -1
  88. package/libx/_runtime/db/expand/expandCQNToJoin.js +5 -3
  89. package/libx/_runtime/db/generic/rewrite.js +7 -13
  90. package/libx/_runtime/fiori/generic/activate.js +1 -1
  91. package/libx/_runtime/fiori/generic/edit.js +1 -1
  92. package/libx/_runtime/fiori/generic/prepare.js +1 -1
  93. package/libx/_runtime/fiori/lean-draft.js +151 -46
  94. package/libx/_runtime/fiori/utils/handler.js +1 -1
  95. package/libx/_runtime/hana/execute.js +6 -2
  96. package/libx/_runtime/hana/search2cqn4sql.js +1 -1
  97. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
  98. package/libx/_runtime/messaging/event-broker.js +212 -0
  99. package/libx/_runtime/remote/Service.js +9 -32
  100. package/libx/_runtime/remote/utils/client.js +13 -21
  101. package/libx/_runtime/sqlite/convertAssocToOneManaged.js +7 -1
  102. package/libx/_runtime/sqlite/execute.js +8 -3
  103. package/libx/_runtime/ucl/Service.js +259 -0
  104. package/libx/common/assert/index.js +6 -11
  105. package/libx/common/assert/validation.js +6 -1
  106. package/libx/odata/index.js +47 -25
  107. package/libx/odata/middleware/batch.js +8 -7
  108. package/libx/odata/middleware/create.js +42 -16
  109. package/libx/odata/middleware/delete.js +18 -11
  110. package/libx/odata/middleware/metadata.js +15 -14
  111. package/libx/odata/middleware/operation.js +30 -40
  112. package/libx/odata/middleware/parse.js +2 -3
  113. package/libx/odata/middleware/read.js +59 -52
  114. package/libx/odata/middleware/service-document.js +7 -7
  115. package/libx/odata/middleware/stream.js +26 -24
  116. package/libx/odata/middleware/update.js +53 -92
  117. package/libx/odata/parse/afterburner.js +45 -47
  118. package/libx/odata/parse/grammar.peggy +3 -3
  119. package/libx/odata/parse/multipartToJson.js +10 -22
  120. package/libx/odata/parse/parser.js +1 -1
  121. package/libx/odata/utils/etag.js +13 -0
  122. package/libx/odata/utils/handler.js +120 -0
  123. package/libx/odata/utils/index.js +15 -2
  124. package/libx/odata/utils/metaInfo.js +410 -0
  125. package/libx/odata/utils/path.js +5 -2
  126. package/libx/odata/utils/readAfterWrite.js +23 -0
  127. package/libx/odata/utils/result.js +4 -5
  128. package/libx/rest/RestAdapter.js +4 -13
  129. package/libx/rest/middleware/parse.js +40 -7
  130. package/package.json +1 -1
  131. package/server.js +2 -1
  132. package/libx/_runtime/cds-services/util/dataProcessUtils.js +0 -93
  133. package/libx/_runtime/common/utils/thenable.js +0 -51
  134. package/libx/_runtime/rest/service.js +0 -2
  135. package/libx/odata/parse/parseToCqn.js +0 -39
  136. package/libx/rest/middleware/input.js +0 -54
  137. package/libx/rest/middleware/payload.js +0 -13
@@ -1,36 +1,37 @@
1
1
  // A simple YAML serializer
2
- module.exports = function _2yaml (object, options={}) { // NOSONAR
3
- if (!object) return object
4
- const limit = options.limit || 111
5
- return (function $(o, indent='') { // NOSONAR
6
-
7
- if (o === null) return o
8
- if (typeof o === 'function') return ''
9
- if (o.toJSON) o = o.toJSON()
2
+ module.exports = function _2yaml (object, {limit=111}={}) {
3
+ return $(object,'',1).toString().replace(/^\n/,'')
4
+ function $(o, indent, count, _visited) {
5
+ if (o == null) return o
6
+ if (o.toJSON) o = o.toJSON()
10
7
  if (Array.isArray(o)) {
11
8
  let s = ''
12
- for (let e of o) s += '\n'+indent+'- '+ $(e,indent+' ')
13
- return s.length > limit ? s : '['+ s.replace (/\n\s*- /g, ', ').slice(2) +']'
9
+ for (let e of o) s += '\n'+indent+'- '+ $(e,indent+' ',0)
10
+ return s.length > limit ? s : '['+ s.replace (/\n\s*- /g, ', ').replace(/^, /,'') +']'
14
11
  }
15
12
  if (typeof o === 'object') {
13
+ const visited = new Set (_visited)
14
+ if (visited.has(o)) return console.error('circular reference to',o)
15
+ else visited.add(o)
16
16
  let s = ''
17
17
  for (let k in o) {
18
18
  let e = o[k]
19
- if (e === undefined) continue
20
- if (typeof e === 'function') continue
21
- if ((e||1).valueOf && (e||1).valueOf() === undefined) continue
22
- if ((e||1).toJSON && (e||1).toJSON() === undefined) continue
19
+ if (e === undefined) continue
20
+ if (typeof e === 'function') continue
21
+ if (e?.valueOf && e.valueOf() === undefined) continue
22
+ if (e?.toJSON && e.toJSON() === undefined) continue
23
23
  let key = /^[$\w]/.test(k) ? k : "'"+ k +"'"
24
- s += '\n'+indent + key +': '+ $(e,indent+' ')
24
+ if (count++ > 0) s += '\n'+indent
25
+ s += key +': '+ $(e,indent+' ',1,visited)
25
26
  }
26
- return s.length > limit ? s : '{'+ s.replace (/\n\s*/g, ', ').slice(2) +'}'
27
+ return s.length > limit ? s : '{'+ s.replace (/\n\s*/g, ', ').replace(/^, /,'') +'}'
27
28
  }
28
29
  if (typeof o === 'string') {
29
- if (o.indexOf('\n')>=0) return '|'+'\n'+indent+ o.replace(/\n/g,'\n'+indent)
30
+ if (o.indexOf('\n')>=0) return '|'+'\n'+indent+ o.replace(/\n/g,'\n'+indent)
30
31
  let s = o.trim()
31
- return !s || /^[\^@#:,*]/.test(s) ? '"'+ o.replace(/\\/g,'\\\\') +'"' : s
32
+ return !s || /^[\^@#:,=!<>*|]/.test(s) ? '"'+ o.replace(/\\/g,'\\\\') +'"' : s
32
33
  }
34
+ if (typeof o === 'function') return ''
33
35
  else return o
34
-
35
- })(object).toString().replace(/^\n/,'')
36
- }
36
+ }
37
+ }
@@ -58,14 +58,13 @@ const deploy = module.exports = function cds_deploy (model, options, csvs) {
58
58
  deploy.schema = async function (db, csn = db.model, o) {
59
59
 
60
60
  if (!o.to || o.to === db.options.kind) o = { ...db.options, ...o }
61
- if (o.impl === '@cap-js/sqlite') {
62
- // REVISIT: Move that to configuration or to cds.compile -> currently cds compile creates wrong output
63
- o.betterSqliteSessionVariables = true
64
- o.sqlDialect = 'sqlite'
65
- }
66
61
 
67
62
  let drops, creas
68
- let schevo = o.schema_evolution === 'auto' || o['with-auto-schema-evolution'] || o['model-only'] || o['delta-from'] || (o.kind === 'postgres' && o.schema_evolution !== false);
63
+ let schevo = (o.kind === 'postgres' && o.schema_evolution !== false)
64
+ || o.schema_evolution === 'auto'
65
+ || o['with-auto-schema-evolution']
66
+ || o['model-only']
67
+ || o['delta-from']
69
68
  if (schevo) {
70
69
  const { prior, table_exists } = await get_prior_model()
71
70
  const { afterImage, drops: d, createsAndAlters } = cds.compile.to.sql.delta(csn, o, prior);
@@ -91,6 +91,13 @@ class Config {
91
91
  if (this.features && this.features.emulate_vcap_services) {
92
92
  this._emulate_vcap_services()
93
93
  }
94
+
95
+ // new odata adapter shall include new parser, cds.assert(), and decimals as strings
96
+ if (this.features?.odata_new_adapter) {
97
+ this.features.odata_new_parser = true
98
+ this.features.cds_assert = true
99
+ this.features.string_decimals = true
100
+ }
94
101
  }
95
102
 
96
103
  /**
@@ -91,7 +91,7 @@ const _services = {
91
91
 
92
92
  "app-service": {
93
93
  // this is the default implementation used for provided services
94
- impl: `${_runtime}/cds-services/services/Service.js`
94
+ impl: `${_runtime}/common/Service.js`
95
95
  },
96
96
  "rest": {
97
97
  impl: `${_runtime}/remote/Service.js`,
@@ -125,6 +125,7 @@ const _databases = {
125
125
  },
126
126
 
127
127
  "sqlite": {
128
+ '[legacy-sqlite]': { impl: `${_runtime}/sqlite/Service.js` },
128
129
  '[better-sqlite]': { impl: '@cap-js/sqlite' },
129
130
  impl: `${_runtime}/sqlite/Service.js`,
130
131
  credentials: { url: 'db.sqlite' },
@@ -141,11 +142,16 @@ const _databases = {
141
142
  },
142
143
 
143
144
  "hana": {
145
+ '[better-hana]': { impl: '@cap-js/hana' },
144
146
  impl: `${_runtime}/hana/Service.js`,
145
147
  },
146
148
  "hana-cloud": {
147
149
  kind: 'hana', "deploy-format": "hdbtable",
148
150
  },
151
+ "legacy-hana": {
152
+ impl: `${_runtime}/hana/Service.js`,
153
+ kind: 'hana'
154
+ },
149
155
 
150
156
  "sql-mt": { // For compatibility only
151
157
  '[development]': { kind: 'sqlite' },
@@ -213,6 +219,12 @@ const _messaging = {
213
219
  vcap: { label: "enterprise-messaging" },
214
220
  outbox: true
215
221
  },
222
+ "event-broker": {
223
+ impl: `${_runtime}/messaging/event-broker.js`,
224
+ vcap: {
225
+ label: "eventmesh-sap2sap-internal"
226
+ }
227
+ },
216
228
  'message-queuing': {
217
229
  impl: `${_runtime}/messaging/message-queuing.js`,
218
230
  outbox: true
@@ -243,6 +255,13 @@ const _messaging = {
243
255
 
244
256
  const _platform_services = {
245
257
 
258
+ ucl: {
259
+ impl: `${_runtime}/ucl/Service.js`,
260
+ host: 'compass-gateway-sap-mtls.mps.kyma.cloud.sap',
261
+ path: '/director/graphql',
262
+ vcap: { label: 'xsuaa' }
263
+ },
264
+
246
265
  destinations: {
247
266
  vcap: {
248
267
  label: 'destination'
@@ -20,6 +20,8 @@ const defaults = module.exports = {
20
20
 
21
21
  features: {
22
22
  folders: 'fts/*', // where to find feature toggles -> switch on by default when released
23
+ pre_compile_edmxs: false,
24
+ odata_new_adapter: false, // switch default with cds^8
23
25
  live_reload: !production,
24
26
  in_memory_db: !production,
25
27
  test_data: !production,
@@ -34,24 +36,26 @@ const defaults = module.exports = {
34
36
  assert_integrity: false,
35
37
  cds_tx_inheritance: true,
36
38
  serve_on_root: false,
37
- precise_timestamps: false
39
+ precise_timestamps: false,
40
+ string_decimals: false, // switch default with cds^8
38
41
  },
39
42
 
40
43
  fiori: {
41
44
  preview: !production,
42
45
  routes: !production,
43
46
  lean_draft: true,
44
- wrap_multiple_errors: true, // switch default with cds 8
47
+ wrap_multiple_errors: true, // switch default with cds^8
45
48
  draft_lock_timeout: true,
46
- draft_deletion_timeout: false, // switch default with cds 8
49
+ draft_deletion_timeout: false, // switch default with cds^8
47
50
  draft_compat: undefined,
48
51
  '[better-sqlite]': { lean_draft: true },
52
+ '[better-hana]': { lean_draft: true },
49
53
  '[lean-draft]': { lean_draft: true },
50
54
  '[draft-compat]': { draft_compat: true },
51
55
  },
52
56
 
53
57
  ql: {
54
- quirks_mode: true, // IMPORTANT: Remove that for cds7 !!
58
+ quirks_mode: true, // IMPORTANT: Remove that for cds^7 !!
55
59
  },
56
60
 
57
61
  log: {
@@ -65,7 +69,7 @@ const defaults = module.exports = {
65
69
  service: false,
66
70
  // the rest is only applicable for the json formatter
67
71
  user: false,
68
- mask_headers: ['/authorization/i', '/cookie/i'],
72
+ mask_headers: ['/authorization/i', '/cookie/i', '/cert/i', '/ssl/i'],
69
73
  aspects: ['./aspects/cf', './aspects/als'], //> EXPERIMENTAL!!!
70
74
  // adds custom fields in kibana's error rendering (unknown fields are ignored); key: index
71
75
  // note: custom fields are a feature of Application Logging Service (ALS) and not Kibana per se
@@ -142,6 +146,17 @@ const defaults = module.exports = {
142
146
  },
143
147
 
144
148
  sql: {
149
+ /**
150
+ * Allows to skip generating transitive localized views for entities which don't have own localized elements, but only associations to such.
151
+ * - `undefined` → skipped for new db services.
152
+ * - `false` → always skipped.
153
+ * - `true` → never skipped.
154
+ */
155
+ transitive_localized_views: true,
156
+ '[java]': {
157
+ transitive_localized_views: false
158
+ },
159
+ native_hana_associations: true,
145
160
  names: 'plain', // or 'quoted', or 'hdbcds'
146
161
  dialect: 'sqlite' // or 'plain' or 'hana'
147
162
  },
@@ -173,6 +188,7 @@ const defaults = module.exports = {
173
188
  cdsc: {
174
189
  moduleLookupDirectories: ['node_modules/'],
175
190
  '[java]': {
191
+ betterSqliteSessionVariables: true,
176
192
  moduleLookupDirectories: ['node_modules/', 'target/cds/'],
177
193
  }
178
194
  // cv2: {
@@ -8,7 +8,7 @@ module.exports = {
8
8
  // and not in the root of the package.json
9
9
 
10
10
  title: 'JSON schema for CDS configuration in package.json',
11
- $schema: 'https://json-schema.org/draft/2020-12/schema',
11
+ $schema: 'https://json-schema.org/draft-07/schema',
12
12
  description: 'This is a JSON schema representation of the CDS project configuration inside a project root level package.json',
13
13
  type: 'object',
14
14
  properties: {
@@ -4,7 +4,7 @@ module.exports = {
4
4
  _version: cds.version,
5
5
 
6
6
  title: 'JSON schema for CDS configuration',
7
- $schema: 'https://json-schema.org/draft/2020-12/schema',
7
+ $schema: 'https://json-schema.org/draft-07/schema',
8
8
  description: 'This is a JSON schema representation for CDS project configuration',
9
9
  type: 'object',
10
10
  additionalProperties: true,
@@ -27,17 +27,32 @@ module.exports = {
27
27
 
28
28
  $defs: {
29
29
  cdsRoot: {
30
+ allowAdditionalProperties: true,
31
+ patternProperties: {
32
+ '\\[.+\\]': {
33
+ default: {},
34
+ description: 'Generic cds profile',
35
+ $ref: '#/$defs/cdsRoot'
36
+ }
37
+ },
30
38
  properties: {
31
39
  '[development]': {
32
- type: 'object'
40
+ default: {},
41
+ description: 'Development profile',
42
+ $ref: '#/$defs/cdsRoot'
33
43
  },
34
44
  '[production]': {
35
- type: 'object'
45
+ default: {},
46
+ description: 'Production profile',
47
+ $ref: '#/$defs/cdsRoot'
36
48
  },
37
49
  '[hybrid]': {
38
- type: 'object'
50
+ default: {},
51
+ description: 'Hybrid profile',
52
+ $ref: '#/$defs/cdsRoot'
39
53
  },
40
54
  profile: {
55
+ default: {},
41
56
  description: 'A single static profile',
42
57
  anyOf: [
43
58
  {
@@ -53,6 +68,7 @@ module.exports = {
53
68
  ]
54
69
  },
55
70
  profiles: {
71
+ default: [],
56
72
  description: 'An array of profiles',
57
73
  type: 'array',
58
74
  uniqueItems: true,
@@ -62,6 +78,7 @@ module.exports = {
62
78
  },
63
79
  folders: {
64
80
  type: 'object',
81
+ default: {},
65
82
  description: 'Only set folders if you don\'t want to use the defaults \'app/\', \'db/\', \'srv/\'.',
66
83
  additionalProperties: true,
67
84
  properties: {
@@ -82,6 +99,11 @@ module.exports = {
82
99
  }
83
100
  },
84
101
  patternProperties: {
102
+ '\\[.+\\]': {
103
+ default: {},
104
+ description: 'Generic folders profile',
105
+ $ref: '#/$defs/cdsRoot/properties/folders'
106
+ },
85
107
  '.+': {
86
108
  description: 'A static name identifying this folder.'
87
109
  }
@@ -91,6 +113,13 @@ module.exports = {
91
113
  type: 'object',
92
114
  description: 'Customize CDS translation settings.',
93
115
  additionalProperties: true,
116
+ patternProperties: {
117
+ '\\[.+\\]': {
118
+ default: {},
119
+ description: 'Generic i18n profile',
120
+ $ref: '#/$defs/cdsRoot/properties/i18n'
121
+ }
122
+ },
94
123
  properties: {
95
124
  default_language: {
96
125
  type: 'string'
@@ -104,6 +133,7 @@ module.exports = {
104
133
  },
105
134
  requires: {
106
135
  type: 'object',
136
+ default: {},
107
137
  description: 'List CDS dependencies to databases and services within the requires section.',
108
138
  additionalProperties: true,
109
139
  properties: {
@@ -126,6 +156,13 @@ module.exports = {
126
156
  description: 'Use custom authentication settings.',
127
157
  default: {},
128
158
  additionalProperties: true,
159
+ // support for [profileName] syntax
160
+ patternProperties: {
161
+ '\\[.+\\]': {
162
+ description: 'aloha',
163
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/auth'
164
+ }
165
+ },
129
166
  properties: {
130
167
  kind: {
131
168
  type: 'string',
@@ -176,6 +213,11 @@ module.exports = {
176
213
  description: 'Use custom database-specific settings.',
177
214
  default: {},
178
215
  additionalProperties: true,
216
+ patternProperties: {
217
+ '\\[.+\\]': {
218
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/db'
219
+ }
220
+ },
179
221
  properties: {
180
222
  kind: {
181
223
  type: 'string',
@@ -232,6 +274,12 @@ module.exports = {
232
274
  {
233
275
  type: 'object',
234
276
  description: 'Multitenancy configuration options.',
277
+ additionalProperties: true,
278
+ patternProperties: {
279
+ '\\[.+\\]': {
280
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/multitenancy'
281
+ }
282
+ },
235
283
  properties: {
236
284
  jobs: {
237
285
  type: 'object',
@@ -260,6 +308,12 @@ module.exports = {
260
308
  {
261
309
  type: 'object',
262
310
  description: 'Extensibility configuration options.',
311
+ additionalProperties: true,
312
+ patternProperties: {
313
+ '\\[.+\\]': {
314
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/extensibility'
315
+ }
316
+ },
263
317
  properties: {
264
318
  tenantCheckInterval: {
265
319
  type: 'number',
@@ -290,6 +344,11 @@ module.exports = {
290
344
  type: 'object',
291
345
  description: 'ModelProviderService configuration options.',
292
346
  additionalProperties: true,
347
+ patternProperties: {
348
+ '\\[.+\\]': {
349
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/cds.xt.ModelProviderService'
350
+ }
351
+ },
293
352
  properties: {
294
353
  root: {
295
354
  type: 'string',
@@ -323,6 +382,12 @@ module.exports = {
323
382
  {
324
383
  type: 'object',
325
384
  description: 'DeploymentService configuration options.',
385
+ additionalProperties: true,
386
+ patternProperties: {
387
+ '\\[.+\\]': {
388
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/cds.xt.DeploymentService'
389
+ }
390
+ },
326
391
  properties: {
327
392
  hdi: {
328
393
  type: 'object',
@@ -367,6 +432,11 @@ module.exports = {
367
432
  type: 'object',
368
433
  description: 'SaasProvisioningService configuration options.',
369
434
  additionalProperties: true,
435
+ patternProperties: {
436
+ '\\[.+\\]': {
437
+ $ref: '#/$defs/cdsRoot/properties/requires/properties/cds.xt.SaasProvisioningService'
438
+ }
439
+ },
370
440
  properties: {
371
441
  jobs: {
372
442
  type: 'object',
@@ -389,6 +459,11 @@ module.exports = {
389
459
  }
390
460
  },
391
461
  patternProperties: {
462
+ '\\[.+\\]': {
463
+ default: {},
464
+ description: 'Generic requires profile',
465
+ $ref: '#/$defs/cdsRoot/properties/requires'
466
+ },
392
467
  '.+': {
393
468
  oneOf: [
394
469
  {
@@ -448,9 +523,15 @@ module.exports = {
448
523
  },
449
524
  protocols: {
450
525
  type: 'object',
526
+ default: {},
451
527
  description: 'List protocols to enable in addition to the default protocol adaptors.',
452
528
  additionalProperties: true,
453
529
  patternProperties: {
530
+ '\\[.+\\]': {
531
+ default: {},
532
+ description: 'Generic protocols profile',
533
+ $ref: '#/$defs/cdsRoot/properties/protocols/patternProperties/.+/oneOf/2'
534
+ },
454
535
  '.+': {
455
536
  oneOf: [
456
537
  {
package/lib/index.js CHANGED
@@ -79,7 +79,7 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
79
79
  get User() { return super.User = require('./req/user') }
80
80
 
81
81
  // Services, Protocols and Periphery
82
- get ApplicationService() { return super.ApplicationService = require('../libx/_runtime/cds-services/services/Service.js') }
82
+ get ApplicationService() { return super.ApplicationService = require('../libx/_runtime/common/Service.js') }
83
83
  get MessagingService() { return super.MessagingService = require('../libx/_runtime/messaging/service.js') }
84
84
  get DatabaseService() { return super.DatabaseService = require('../libx/_runtime/db/Service.js') }
85
85
  get RemoteService() { return super.RemoteService = require('../libx/_runtime/remote/Service.js') }
@@ -166,10 +166,10 @@ class event extends aspect {}
166
166
  class LinkedDefinitions {
167
167
  *[Symbol.iterator](){ for (let e in this) yield this[e] }
168
168
  forEach(f){ let i=0; for (let k in this) f(this[k],i++,this) }
169
- filter(f){ let i=0, r=[]; for (let k in this) f(this[k],i++,this) && r.push(k); return r }
169
+ filter(f){ let i=0, r=[]; for (let k in this) f(this[k],i++,this) && r.push(this[k]); return r }
170
170
  map(f){ let i=0, r=[]; for (let k in this) r.push(f(this[k],i++,this)); return r }
171
171
  some(f){ for (let k in this) if (f(this[k])) return true }
172
- find(f){ for (let k in this) if (f(this[k])) return k }
172
+ find(f){ for (let k in this) if (f(this[k])) return this[k] }
173
173
  }
174
174
 
175
175
 
@@ -5,6 +5,16 @@ const _derived = Symbol('derived')
5
5
 
6
6
  class entity extends struct {
7
7
  is (kind) { return kind === 'entity' || kind === 'view' && !!this.query || super.is(kind) }
8
+
9
+ /**
10
+ * Experimental API to write:
11
+ * ```js
12
+ * SELECT.from(Foo.as('bar')) // ... as alternative to:
13
+ * SELECT.from(Foo).alias('bar')
14
+ * ```
15
+ */
16
+ as (alias) { return { ntt:this, ref:[this.name], as:alias } }
17
+
8
18
  get keys() {
9
19
  return this._elements ('key')
10
20
  }
@@ -15,7 +15,7 @@ class LinkedCSN {
15
15
  constructor(x) {
16
16
 
17
17
  if (typeof x === 'string') x = require('../index').compile(x) //> for convenience in repl
18
- const defs = x.definitions = _iterable (x.definitions)
18
+ const defs = x.definitions = _iterable (x.definitions||{})
19
19
  for (let d in defs) _link (defs[d],d)
20
20
  return Object.setPrototypeOf (x, new.target.prototype)
21
21
 
package/lib/plugins.js CHANGED
@@ -30,7 +30,7 @@ exports.fetch = function (DEV = process.env.NODE_ENV !== 'production') {
30
30
  exports.activate = async function () {
31
31
  const DEBUG = cds.debug ('plugins', {label:'cds'})
32
32
  DEBUG && console.time ('[cds] - loaded plugins in')
33
- const { plugins } = cds.env, { local } = cds.utils
33
+ const plugins = exports.fetch(), { local } = cds.utils
34
34
  await Promise.all (Object.entries(plugins) .map (async ([ plugin, conf ]) => {
35
35
  DEBUG?.(`loading plugin ${plugin}:`, { impl: local(conf.impl) })
36
36
  // TODO: support ESM plugins. But see cap/cds/pull/1838#issuecomment-1177200 !
package/lib/ql/INSERT.js CHANGED
@@ -13,6 +13,8 @@ module.exports = class Query extends require('./Query') {
13
13
  }
14
14
 
15
15
  entries (...x) {
16
+ if (!x.length) return this
17
+ if (x[0].SELECT) return this.from(x[0])
16
18
  this[this.cmd].entries = is_array(x[0]) ? x[0] : x
17
19
  return this
18
20
  }
@@ -31,11 +33,22 @@ module.exports = class Query extends require('./Query') {
31
33
  return this
32
34
  }
33
35
 
34
- as (query) {
35
- if (!query || !query.SELECT) this._expected `${{query}} to be a CQN {SELECT} query object`
36
- this[this.cmd].as = query
36
+ from (query) {
37
+ if (!query) return this
38
+ if (!query.SELECT) {
39
+ if (query.name || typeof query === 'string') query = SELECT.from(query)
40
+ else this._expected `${{query}} to be a CQN {SELECT} query object`
41
+ }
42
+ this[this.cmd].as = query // REVISIT: should we also change CSN spec, and adopt db service impls?
37
43
  return this
38
44
  }
45
+
46
+ /** @deprecated */ as (query) {
47
+ INSERT_as_SELECT ??= require('../utils').deprecated(()=>{},{old:'INSERT.as(SELECT)', use:'INSERT.entries(SELECT)'})
48
+ INSERT_as_SELECT()
49
+ return this.from(query)
50
+ }
51
+
39
52
  valueOf() {
40
53
  return super.valueOf('INSERT INTO')
41
54
  }
@@ -44,3 +57,4 @@ module.exports = class Query extends require('./Query') {
44
57
  }
45
58
 
46
59
  const is_array = Array.isArray
60
+ let INSERT_as_SELECT
package/lib/ql/Query.js CHANGED
@@ -5,6 +5,10 @@ class Query {
5
5
 
6
6
  constructor(_={}) { this[this.cmd] = _ }
7
7
 
8
+ /**
9
+ * Note to self: We can't use .as (alias) as that would conflict with
10
+ * sub selects in columns, which in turn may has aliases in .as.
11
+ */
8
12
  alias (a) {
9
13
  this._target_ref.as = a
10
14
  return this
package/lib/ql/infer.js CHANGED
@@ -78,7 +78,7 @@ function elements4 (columns, source) {
78
78
  if (c.ref && d?.elements) {
79
79
  for (let r of ref) d = (d.SELECT ? d : d._target||d).elements?.[r]
80
80
  || cds.error `Couldn't resolve element "${ref.join('/')}" in ${source.kind} ${source.name||''} ${Object.keys(source.elements)}`
81
- if (d._target) { is2many = d.is2many; d = d._target }
81
+ if (d._target) { is2many = d.is2many; c.expand || c.inline ? d = d._target : d }
82
82
  // ... d is further processed in steps 5,6,7 below
83
83
  }
84
84
 
@@ -205,5 +205,5 @@ const _path4 = (x,p) => {
205
205
  // REVISIT: Legacy stuff...
206
206
  //
207
207
  Object.defineProperties (Request.prototype, {
208
- diff: { get: ()=> require('../../libx/_runtime/cds-services/services/utils/differ').reqDiff }
208
+ diff: { get: ()=> require('../../libx/_runtime/common/utils/differ').reqDiff }
209
209
  })
@@ -101,6 +101,7 @@ module.exports = function cds_serve (som, _options) { // NOSONAR
101
101
 
102
102
  /** Fluent method to serve constructed providers to express app */
103
103
  in (app) {
104
+ if (!cds.env.features.odata_new_adapter && cds.edmxs) ready = ready.then (()=> cds.edmxs)
104
105
  ready = ready.then (()=> all.forEach (each => {
105
106
  const d = each.definition
106
107
  if (d['@protocol'] === 'none' || d['@cds.api.ignore']) return each._is_dark = true
@@ -19,7 +19,7 @@ module.exports = ()=> {
19
19
  req.headers['x-vcap-request-id'] ||
20
20
  uuid()
21
21
  )
22
- req.res.set('X-Correlation-ID', id)
22
+ req.res.set('x-correlation-id', id)
23
23
  return id
24
24
  }
25
25
 
@@ -4,11 +4,10 @@ const cds = require('../../index'),
4
4
  const express = require('express') // eslint-disable-line cds/no-missing-dependencies
5
5
 
6
6
  if (cds.env.features.odata_new_adapter) {
7
+ cds.log().info('using new OData adapter')
8
+
7
9
  const { isStream, stream } = require('../../../libx/odata/middleware/stream')
8
10
  const BaseProtocolAdapter = require('./http')
9
- // REVISIT: odata_new_adapter shouldn't influence odata_new_parser and cds_assert, but we'd need to set marker in cds.context or so to remove this
10
- cds.env.features.odata_new_parser = true
11
- cds.env.features.cds_assert = true
12
11
 
13
12
  module.exports = class ODataAdapter extends BaseProtocolAdapter {
14
13
  log(req) {
@@ -44,7 +43,7 @@ if (cds.env.features.odata_new_adapter) {
44
43
  if (typeof req.body === 'object') return next()
45
44
  if (req.method === 'PUT' && isStream(req._query)) {
46
45
  req.body = { value: req }
47
- return next(null, req, res)
46
+ return next()
48
47
  }
49
48
  // TODO: check if the raw body still exists, then we can remove deepCopy() in the handlers
50
49
  return jsonBodyParser(req, res, next)
@@ -59,8 +58,8 @@ if (cds.env.features.odata_new_adapter) {
59
58
  .post('*', require('../../../libx/odata/middleware/create')(srv))
60
59
  .get('*', stream(srv))
61
60
  .get('*', require('../../../libx/odata/middleware/read')(srv))
62
- .put('*', require('../../../libx/odata/middleware/update')(srv))
63
- .patch('*', require('../../../libx/odata/middleware/update')(srv))
61
+ .put('*', require('../../../libx/odata/middleware/update')(srv, router))
62
+ .patch('*', require('../../../libx/odata/middleware/update')(srv, router))
64
63
  .delete('*', require('../../../libx/odata/middleware/delete')(srv))
65
64
  // error
66
65
  .use(require('../../../libx/odata/middleware/error')(srv))
@@ -182,9 +182,16 @@ if (!extensibility) {
182
182
 
183
183
  // helper to get model for tenant/features
184
184
  const _is_extended = extensibility ? ()=> cds.db.exists('cds.xt.Extensions') : ()=> false
185
- const _get_model4 = (tenant, features) => {
185
+ const _get_model4 = async (tenant, features) => {
186
186
  const { 'cds.xt.ModelProviderService':mps } = cds.services
187
- return mps.getCsn (tenant, features) .then (cds.compile.for.nodejs)
187
+ const csn = await mps.getCsn (tenant, features)
188
+ const nsn = cds.compile.for.nodejs(csn)
189
+ if (cds.edmxs) await cds.compile.to.edmx.files ( csn,
190
+ // adding tenant and features to runtime model, for later use when fetching generated files
191
+ nsn.tenant = tenant,
192
+ nsn.features = features.join()
193
+ )
194
+ return nsn
188
195
  }
189
196
 
190
197