@sap/cds 7.5.2 → 7.6.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +79 -22
  2. package/app/index.js +1 -1
  3. package/lib/auth/index.js +3 -0
  4. package/lib/compile/extend.js +9 -4
  5. package/lib/compile/for/lean_drafts.js +3 -4
  6. package/lib/compile/load.js +11 -15
  7. package/lib/compile/minify.js +2 -4
  8. package/lib/compile/to/sql.js +6 -4
  9. package/lib/compile/to/srvinfo.js +25 -3
  10. package/lib/compile/to/yaml.js +1 -1
  11. package/lib/dbs/cds-deploy.js +7 -13
  12. package/lib/env/defaults.js +1 -10
  13. package/lib/env/schemas/cds-package.js +27 -0
  14. package/lib/env/schemas/cds-rc.js +693 -0
  15. package/lib/env/schemas/index.js +6 -4
  16. package/lib/i18n/localize.js +15 -1
  17. package/lib/index.js +40 -47
  18. package/lib/log/cds-error.js +6 -0
  19. package/lib/ql/Query.js +2 -1
  20. package/lib/ql/cds-ql.js +1 -2
  21. package/lib/ql/infer.js +0 -2
  22. package/lib/req/request.js +3 -6
  23. package/lib/srv/middlewares/trace.js +2 -2
  24. package/lib/srv/protocols/hcql.js +44 -30
  25. package/lib/srv/protocols/http.js +60 -0
  26. package/lib/srv/protocols/index.js +0 -7
  27. package/lib/srv/protocols/odata-v4.js +8 -2
  28. package/lib/srv/srv-api.js +129 -62
  29. package/lib/srv/srv-handlers.js +0 -1
  30. package/lib/srv/srv-models.js +1 -0
  31. package/lib/utils/cds-test.js +1 -1
  32. package/lib/utils/cds-utils.js +26 -0
  33. package/lib/utils/check-version.js +10 -13
  34. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +22 -6
  35. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +3 -4
  36. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +89 -21
  37. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/boundToCQN.js +4 -2
  38. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +1 -24
  39. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +1 -7
  40. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ApplyParser.js +3 -3
  41. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/TrustedResourceJsonSerializer.js +7 -0
  42. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +0 -5
  43. package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +2 -0
  44. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +17 -1
  45. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +22 -2
  46. package/libx/_runtime/cds-services/services/utils/columns.js +1 -2
  47. package/libx/_runtime/common/aspects/Association.js +17 -9
  48. package/libx/_runtime/common/generic/crud.js +13 -22
  49. package/libx/_runtime/common/generic/etag.js +1 -1
  50. package/libx/_runtime/common/generic/input.js +9 -1
  51. package/libx/_runtime/common/generic/paging.js +3 -3
  52. package/libx/_runtime/common/generic/sorting.js +25 -15
  53. package/libx/_runtime/common/generic/stream.js +2 -16
  54. package/libx/_runtime/common/utils/copy.js +5 -0
  55. package/libx/_runtime/common/utils/cqn.js +1 -1
  56. package/libx/_runtime/common/utils/cqn2cqn4sql.js +4 -3
  57. package/libx/_runtime/common/utils/csn.js +0 -49
  58. package/libx/_runtime/common/utils/foreignKeyPropagations.js +5 -5
  59. package/libx/_runtime/common/utils/generateOnCond.js +50 -25
  60. package/libx/_runtime/common/utils/resolveView.js +5 -44
  61. package/libx/_runtime/common/utils/rewriteAsterisks.js +17 -4
  62. package/libx/_runtime/common/utils/stream.js +16 -15
  63. package/libx/_runtime/common/utils/streamProp.js +25 -22
  64. package/libx/_runtime/db/Service.js +27 -8
  65. package/libx/_runtime/db/generic/input.js +6 -1
  66. package/libx/_runtime/db/generic/rewrite.js +3 -2
  67. package/libx/_runtime/db/query/read.js +15 -5
  68. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +0 -11
  69. package/libx/_runtime/db/utils/columns.js +1 -0
  70. package/libx/_runtime/db/utils/stream.js +41 -0
  71. package/libx/_runtime/fiori/generic/read.js +2 -1
  72. package/libx/_runtime/fiori/generic/readOverDraft.js +1 -1
  73. package/libx/_runtime/fiori/lean-draft.js +216 -59
  74. package/libx/_runtime/hana/Service.js +1 -1
  75. package/libx/_runtime/hana/execute.js +53 -14
  76. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +34 -15
  77. package/libx/_runtime/remote/Service.js +2 -1
  78. package/libx/_runtime/remote/utils/client.js +1 -1
  79. package/libx/_runtime/sqlite/Service.js +1 -1
  80. package/libx/_runtime/sqlite/execute.js +17 -5
  81. package/libx/odata/afterburner.js +58 -19
  82. package/libx/odata/cqn2odata.js +6 -8
  83. package/libx/odata/create.js +44 -0
  84. package/libx/odata/delete.js +25 -0
  85. package/libx/odata/error.js +8 -3
  86. package/libx/odata/metadata.js +6 -8
  87. package/libx/odata/service-document.js +1 -1
  88. package/libx/odata/update.js +110 -0
  89. package/libx/odata/utils.js +9 -6
  90. package/libx/outbox/index.js +48 -78
  91. package/libx/rest/RestAdapter.js +0 -3
  92. package/package.json +1 -1
  93. package/lib/env/schemas/cds-package.json +0 -17
  94. package/lib/env/schemas/cds-rc.json +0 -740
  95. package/lib/ql/STREAM.js +0 -90
package/CHANGELOG.md CHANGED
@@ -4,6 +4,63 @@
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
+ ## Version 7.6.1 - 2024-01-30
8
+
9
+ ### Fixed
10
+
11
+ - Garbage collection of draft is configured with `cds.fiori.draft_deletion_timeout`
12
+
13
+ ## Version 7.6.0 - 2024-01-29
14
+
15
+ ### Added
16
+
17
+ - `cds.upsert` as shortcut for `cds.db.upsert`
18
+ - Automatic deletion of stale drafts. Feature is enabled if `cds.env.fiori.deletionTimeout` is set to a value of `true`; `true` uses the default timeout of `30d` (30 days).
19
+ - Support for default exports (ESM/TS) in custom authentication
20
+ - Support for executing SAP HANA procedures from SYS schema
21
+ - Support for more complex on-conditions in case of READ requests
22
+ - Best effort mechanism for supporting lambda expressions targeting remote odata-v2 services
23
+ - Support for actions and functions which are bound to singletons
24
+
25
+ ### Changed
26
+
27
+ - Draft: Standard Sorting Behavior for SAP Fiori List Report Floorplan
28
+ - Use new CDS schema for validation and code completion in `package.json` and `.cdsrc.json` files
29
+ - Media Data Streaming
30
+ + OData: Large binaries without `@Core.MediaType` annotation were previously returned as base64-encoded buffer. Starting from this `@sap/cds` version also not-annotated large binaries are ignored by OData. It is strongly recommended to annotate all large binary properties with `@Core.MediaType` and use it according to streaming scenarios.
31
+ + Custom Handlers: `SELECT` with explicitely listed `SELECT.columns` of type `cds.LargeBinary` returns them as Readable streams. Large binary columns requested implicitely by `SELECT` (for example, with `.columns('*')`) are ignored.
32
+ + Streaming API: `cds.stream()` and `srv.stream()` are deprecated and will be removed with the next major release. Use `SELECT` with a single `cds.LargeBinary` column instead. The resulting object will contain the name of the column and a stream value. For example, `SELECT.one.from(E).columns(['image']).where(...)` returns `{ image: <media stream> }`.
33
+ + Backward Compatibility: To restore previous behavior use `stream_compat`.
34
+
35
+ ### Fixed
36
+
37
+ - `cds.minify` returned a shallow clone. When callers like 2sql `cds.linked` that subsequently, this left the passed-in csn in a broken, partially linked state. Now, `cds.minify` doesn't clone anymore, but modifies the passed in csn.
38
+ - Handling of read-only fields in drafts
39
+ - Event Mesh: Better error message for incoming messages without a topic
40
+ - `cds build` now logs a better error message if an incompatible `@sap/cds` version is used.
41
+ - Better error message for runtime requests to non-existing tenants in extensibility scenario.
42
+ - Do not generate UUIDs for association key during `CREATE` operation.
43
+ - OData aggregation with lean draft
44
+ - Sorting in new odata parser with nested select statements. The default sort order is now added to the outer select statement.
45
+ - Server crash in case of misformatted `groupby` transformation in `$apply`
46
+ - Switched EM webhook endpoints to also use new authentication implementation
47
+ - `odata_new_parser`: better error message and code for expand on non-existing elements
48
+
49
+ ### Removed
50
+
51
+ - Experimental `STREAM` CQN is removed and cannot be used anymore
52
+
53
+ ## Version 7.5.3 - 2024-01-23
54
+
55
+ ### Fixed
56
+
57
+ - `cds.localize` and `cds build` produce `i18n.json` again with keys from all base languages
58
+ - `cds.compile.to.serviceinfo` now correctly parses SpringBoot config with nested objects, e.g. for `cds.odata-v4.endpoint.path`
59
+ - Recommend to use `chai` 4 for the time being, as `chai` 5 doesn't properly work yet (requires ESM, `chai-as-promised` not working)
60
+ - View resolving for entities using property names that are identical to entity names
61
+ - Direct modifications with `cds.fiori.bypass_draft` if `cds.fiori.draft_compat` is not enabled
62
+ - Draft: Field validation error message does not display the name of the field
63
+
7
64
  ## Version 7.5.2 - 2024-01-05
8
65
 
9
66
  ### Fixed
@@ -23,7 +80,7 @@
23
80
  ### Added
24
81
 
25
82
  - Support for expressions in where clause of `@restrict` annotation.
26
- - Example: `@(restrict : [{ grant : ['*'], where : (NAME = $user) }])`
83
+ + Example: `@(restrict : [{ grant : ['*'], where : (NAME = $user) }])`
27
84
  - Function `cds.unboxed(srv)` to get the non-outboxed variant of the service
28
85
  - Service implementations can now be provided in .mjs modules.
29
86
  - Remote services: advanced configurable `CSRF` token fetching HTTP method and the URL.
@@ -37,16 +94,16 @@
37
94
  "csrf": { // this configuration implies `csrf: true`
38
95
  "method": "get",
39
96
  "url": "..."
40
- }
97
+ }
41
98
  }
42
99
  }
43
100
  }
44
101
  ```
45
102
  - `cds.log`'s built-in JSON formatter:
46
103
  + Extract custom fields (`cds.env.log.als_custom_fields`) and categories from args (not only error-like first objects)
47
- * Example: `LOG.info('foo', { query: 'SELECT * FROM DUMMY' }, 'bar', { categories: ['baz'] })`
104
+ + Example: `LOG.info('foo', { query: 'SELECT * FROM DUMMY' }, 'bar', { categories: ['baz'] })`
48
105
  + `cds.env.log.mask_headers = [...]` allows to specify a list of matchers for which the header value shall be masked (i.e., printed as `***`)
49
- * Default: `['/authorization/i', '/cookie/i']`
106
+ + Default: `['/authorization/i', '/cookie/i']`
50
107
  - `cds.env.fiori.bypass_draft` feature flag, designed to enable direct modifications via `POST` and `PATCH` of
51
108
  active instances in lean draft mode (`cds.env.fiori.lean_draft=true`). For example:
52
109
 
@@ -57,29 +114,29 @@ POST /Orders
57
114
  }
58
115
  ```
59
116
 
60
- - Auth kind `ias`: same SAML attr api as auth kind `xsuaa` for easier migration
117
+ - Auth kind `ias`: same SAML attr API as auth kind `xsuaa` for easier migration
61
118
 
62
119
  ### Changed
63
120
 
64
121
  - Removed and integrated former `ctx-auth` middleware into `cds.auth` middleware
65
122
  - `cds.log`:
66
123
  + `cds.env.log.format = 'plain'|'json'` allows to configure which built-in formatter is used. Defaults to `json` in production, `plain` otherwise.
67
- + If built-in JSON formatter is used:
68
- * Field `tenant_subdomain` is filled if running on CF and information is available through authentication
69
- * Additional CF-related fields are filled if running on CF
70
- * Custom fields (`cds.env.log.als_custom_fields`) are filled if bound to an instance of Application Logging Service
71
- * Field `categories` is filled if bound to an instance of Application Logging Service
72
- + Config `cds.env.log.kibana_custom_fields` changed to `cds.env.log.als_custom_fields` (ALS = Application Logging Service) with compatibility until next major
124
+ + If a built-in JSON formatter is used:
125
+ + Field `tenant_subdomain` is filled if running on CF and information is available through authentication
126
+ + Additional CF-related fields are filled if running on CF
127
+ + Custom fields (`cds.env.log.als_custom_fields`) are filled if bound to an instance of Application Logging Service
128
+ + Field `categories` is filled if bound to an instance of Application Logging Service
129
+ + Config `cds.env.log.kibana_custom_fields` changed to `cds.env.log.als_custom_fields` (ALS = Application Logging Service) with compatibility until the next major
73
130
  - Package `passport` is no longer required (if `cds.env.requires.middlewares` is not set to `false`)
74
131
  - Type definitions for the APIs of this package are now maintained in package [`@cap-js/cds-types`](https://npmjs.com/package/@cap-js/cds-types).
75
- - If you used one of the types `CSN`, `Definitions`, `entity` of _@sap/cds/apis/reflect_, use the `Linked` counterparts instead.
76
- - If you used the type `CQNQuery` of _@sap/cds/apis/cqn_, use `SELECT` or a union type instead.
77
- - This also includes various fixes to Typings for
78
- - `req.subject` like `SELECT.from(req.subject)`
79
- - `SELECT.columns([...])`
80
- - `cds.db`
81
- - `cds.util`
82
- - `cds.context.features`
132
+ + If you used one of the types `CSN`, `Definitions`, `entity` of _@sap/cds/apis/reflect_, use the `Linked` counterparts instead.
133
+ + If you used the type `CQNQuery` of _@sap/cds/apis/cqn_, use `SELECT` or a union type instead.
134
+ + This also includes various fixes to Typings for
135
+ + `req.subject` like `SELECT.from(req.subject)`
136
+ + `SELECT.columns([...])`
137
+ + `cds.db`
138
+ + `cds.util`
139
+ + `cds.context.features`
83
140
  - The number of files logged on `cds serve` is now limited to 30 by default. You can run with `DEBUG=serve` to show all files.
84
141
  - `express.static` is only mounted if the target folder (`cds.folders.app`) exists
85
142
  - `cds.outbox.Messages` no longer uses aspect `cuid` to reduce model size impact in case `@sap/cds/common` is not used otherwise
@@ -97,18 +154,18 @@ POST /Orders
97
154
  - Use original logic (based on `NODE_ENV`) to load cds plugins from `devDependencies`
98
155
  - Property `tenant` also available on express' `req` object with basic and mocked auth
99
156
  - Empty `req.data` in before `DELETE` handler in draft
100
- - Loading `cds-plugins` now offers a hook to add more flexible plugin loader, e.g. for corrupt `package.json` files.
157
+ - Loading `cds-plugins` now offers a hook to add a more flexible plugin loader, e.g., for corrupt `package.json` files.
101
158
  - Ignore default values of associations for draft entities
102
159
  - OData: client-side errors (4xx) logged as warnings instead of errors
103
160
  - IAS authentication: use `tokenInfo.getClientId()` instead of `payload.azp` as it implements a fallback
104
161
  - Deep updates with binary keys
105
162
  - Allow `null` values in `cds.env` (example package.json excerpt: `{ "cds": { "features": { "foo": null } } }`)
106
- - Collection bound actions/functions called via navigation
163
+ - Collection-bound actions/functions called via navigation
107
164
 
108
165
  ### Removed
109
166
 
110
167
  - Deprecated global configuration feature flag `cds.env.features.fetch_csrf`.
111
- Instead, please use `csrf` and `csrfInBatch` in the configuration of your remote services.
168
+ Instead, please use `csrf` and `csrfInBatch` to configure your remote services.
112
169
  These options will allow to configure CSRF-token handling.
113
170
  - Compat for deprecated `cds.env.auth.passport`. Use `cds.env.requires.auth` instead.
114
171
 
package/app/index.js CHANGED
@@ -11,7 +11,7 @@ module.exports = { get html(){
11
11
  .replace (/{{package}}/g, _project())
12
12
  .replace (/{{app}}/g, cds.env.folders.app.replace(/*trailing slash*/ /\/$/, ''))
13
13
  .replace ('{{apps}}', _app_links().map(
14
- html => `\n<li><a href="${html}">/${html.replace(/^[/]/,'')}</a></li>`
14
+ html => `\n<li><a href="${html}">/${html.replace(/^\//,'').replace('/index.html','')}</a></li>`
15
15
  ).join('\n') || '— none —'
16
16
  )
17
17
  .replace ('{{services}}', cds.service.providers.map (srv => srv._is_dark ? '' : `
package/lib/auth/index.js CHANGED
@@ -39,6 +39,9 @@ module.exports = function auth_factory (o) {
39
39
  cds.log().info ('using auth strategy', config, '\n')
40
40
  let auth = require (impl)
41
41
 
42
+ // default export of ESM / .ts auth
43
+ if (auth && auth.default) auth = auth.default
44
+
42
45
  // if auth is a factory itself, call it to get the middleware
43
46
  if (typeof auth === 'function' && auth.length < 3) auth = auth(options)
44
47
 
@@ -1,6 +1,11 @@
1
- const compile = require ('./cds-compile')
1
+ const cds = new class { get compile(){ return super.compile = require ('./cds-compile') }}
2
2
  const { extend } = require ('../lazy')
3
3
 
4
+ /** @type <T> (target:T) => ({
5
+ with <X,Y,Z> (x:X, y:Y, z:Z): ( T & X & Y & Z )
6
+ with <X,Y> (x:X, y:Y): ( T & X & Y )
7
+ with <X> (x:X): ( T & X )
8
+ }) */
4
9
  module.exports = o => o.definitions ? { with(...csns) {
5
10
 
6
11
  // merge all extension csns
@@ -11,9 +16,9 @@ module.exports = o => o.definitions ? { with(...csns) {
11
16
  }
12
17
 
13
18
  // extend given base csn with merged extensions
14
- const extended = compile({
15
- 'base.csn': compile.to.json(csn),
16
- 'ext.csn': compile.to.json(merged)
19
+ const extended = cds.compile({
20
+ 'base.csn': cds.compile.to.json(csn),
21
+ 'ext.csn': cds.compile.to.json(merged)
17
22
  })
18
23
 
19
24
  // handle localized extension elements
@@ -123,12 +123,11 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
123
123
  for (const key in newEl) {
124
124
  if (
125
125
  key.startsWith('@assert') ||
126
- key.startsWith('@FieldControl') ||
127
- key.startsWith('@Common.FieldControl') ||
128
126
  key.startsWith('@PersonalData') ||
127
+ key === '@Common.FieldControl' && newEl[key]?.['#'] === 'Mandatory' ||
128
+ key === '@Common.FieldControl.Mandatory' ||
129
+ key === '@FieldControl.Mandatory' ||
129
130
  key === '@mandatory' ||
130
- key === '@readonly' ||
131
- key === '@Core.Computed' ||
132
131
  key === '@Core.Immutable'
133
132
  )
134
133
  newEl[key] = undefined
@@ -2,22 +2,21 @@ const cds = require('..')
2
2
  const TRACE = cds.debug('trace')
3
3
 
4
4
  module.exports = exports = function load (files, options) {
5
- const all = cds.resolve(files,options)
6
- if (!all) return Promise.reject (new cds.error ({
5
+ const any = cds.resolve(files,options)
6
+ if (!any) return Promise.reject (new cds.error ({
7
7
  message: `Couldn't find a CDS model for '${files}' in ${cds.root}`,
8
8
  code: 'MODEL_NOT_FOUND', files,
9
9
  }))
10
- return this.get (all,options,'inferred')
10
+ return this.get (any,options,'inferred')
11
11
  }
12
12
 
13
13
 
14
- exports.parsed = function cds_get (files, options, _flavor) { // NOSONAR
15
-
14
+ exports.parsed = function cds_get (files, options, _flavor) {
16
15
  const o = typeof options === 'string' ? { flavor:options } : options || {}
17
- if (!o.silent) TRACE?.time('cds.load model ')
18
16
  if (!files) files = ['*']; else if (!Array.isArray(files)) files = [files]
19
17
  if (o.files || o.flavor === 'files') return cds.resolve(files,o)
20
18
  if (o.sources || o.flavor === 'sources') return _sources4 (cds.resolve(files,o))
19
+ if (!o.silent) TRACE?.time('cds.load model')
21
20
 
22
21
  const csn = cds.compile (files,o,
23
22
  o.parse ? 'parsed' :
@@ -25,15 +24,12 @@ exports.parsed = function cds_get (files, options, _flavor) { // NOSONAR
25
24
  o.clean ? 'xtended' : // for compatibility
26
25
  o.flavor || _flavor || 'parsed'
27
26
  )
28
- return csn.then
29
- ? csn.then (_csn => _finalize(_csn,o)) // async compile
30
- : _finalize (csn,o) // synchronous compile
31
- }
32
-
33
- const _finalize = (csn,o) => {
34
- if (!o.silent) cds.emit ('loaded', csn)
35
- if (!o.silent) TRACE?.timeEnd('cds.load model ')
36
- return csn
27
+ return csn.then?.(_finalize) || _finalize(csn)
28
+ function _finalize (csn) {
29
+ if (!o.silent) cds.emit ('loaded', csn)
30
+ if (!o.silent) TRACE?.timeEnd('cds.load model ')
31
+ return csn
32
+ }
37
33
  }
38
34
 
39
35
  const _sources4 = async (files) => {
@@ -1,8 +1,7 @@
1
1
  const cds = require('../index')
2
2
  const DEBUG = cds.debug('minify')
3
3
 
4
- module.exports = function cds_minify (csn, _roots) { // IMPORTANT: don't add cds.env.features.skip_unused as default for _roots here, as that will break VSCode's IntelliSense
5
- const roots = _roots !== undefined ? _roots : cds.env.features.skip_unused
4
+ module.exports = function cds_minify (csn, roots = cds.env.features.skip_unused) {
6
5
  if (roots === false) return csn
7
6
  if (csn[_minified]) return csn
8
7
  const all = csn.definitions, reached = new Set
@@ -56,8 +55,7 @@ module.exports = function cds_minify (csn, _roots) { // IMPORTANT: don't add cds
56
55
  for (let a in d.actions) _visit (d.actions[a])
57
56
  for (let p in d.params) _visit (d.params[p])
58
57
  }
59
- const minified = Object.create (csn.__proto__, Object.getOwnPropertyDescriptors(csn))
60
- const less = minified.definitions = {}
58
+ const minified = csn, less = minified.definitions = {}
61
59
  for (let n in all) if (reached.has(all[n])) less[n] = all[n]
62
60
  else DEBUG?.('skipping', all[n].kind, n)
63
61
  Object.defineProperty (minified,_minified,{value:true})
@@ -4,7 +4,8 @@ const keywords = require("@sap/cds-compiler").to.sql.sqlite.keywords
4
4
  const { unfold_ddl } = require ('../etc/_localized')
5
5
 
6
6
  function cds_compile_to_sql (csn,_o) {
7
- csn = _extended(cds.minify(csn))
7
+ csn = cds.minify(csn)
8
+ csn = _extended(csn)
8
9
  const o = cdsc._options.for.sql(_o) //> used twice below...
9
10
  const all = cdsc.to.sql(csn,o) .map (each => each.replace(/^-- .+\n/,'')) //> strip comments
10
11
  const sql = unfold_ddl(all, csn, o)
@@ -58,12 +59,13 @@ module.exports = Object.assign (cds_compile_to_sql, {
58
59
 
59
60
  /////////////////////////////////////////////////////////////////////////////
60
61
  // UI Flex - read extensions__ to views, when ext fields are read
62
+ // REVISIT: We planned to remove the uiflex feature -> should do so
61
63
  const _extended = (csn) => {
62
64
  const defs = cds.linked(csn).definitions
63
65
  for (let each in defs) {
64
- const d = defs[each], q = d.query // TODO: q may have SET instead of SELECT
65
- if (q && q.SELECT && q.SELECT.columns && _is_extensible(d)) {
66
- if (!q.SELECT.columns.some(({ref}) => ref && ref[0] === _extensions)) q.SELECT.columns.push({ref:[_extensions]})
66
+ const d = defs[each], columns = d.query?.SELECT?.columns || d.projection?.columns
67
+ if (columns && _is_extensible(d)) {
68
+ if (!columns.some(({ref}) => ref?.[0] === _extensions)) columns.push({ref:[_extensions]})
67
69
  }
68
70
  }
69
71
  return csn
@@ -79,10 +79,12 @@ module.exports = (model, options={}) => {
79
79
  if (file) {
80
80
  const yaml = cds.load.yaml(file)
81
81
  for (let yamlDoc of Array.isArray(yaml) ? yaml : [yaml]) {
82
- const cds = yamlDoc?.cds;
82
+ let cds = yamlDoc?.cds;
83
83
  if (!cds) continue
84
- return cds['odataV4.endpoint.path'] || cds['odataV2.endpoint.path'] // https://cap.cloud.sap/docs/java/application-services#configure-base-path
85
- || cds['odata-v4.endpoint.path'] || cds['odata-v2.endpoint.path'] // older/intermediate config, keep for backward compatibility
84
+ cds = _normalizeSpringBootCfg(cds)
85
+ // https://cap.cloud.sap/docs/java/application-services#configure-base-path
86
+ return cds.odataV4?.endpoint?.path || cds.odataV2?.endpoint?.path
87
+ || cds['odata-v4']?.endpoint?.path || cds['odata-v2']?.endpoint?.path // alternative config
86
88
  || javaPrefixDefault
87
89
  }
88
90
  return javaPrefixDefault
@@ -92,4 +94,24 @@ module.exports = (model, options={}) => {
92
94
  return is_java && javaPrefixDefault
93
95
  }
94
96
 
97
+ // SpringBoot allows dots in keys to express nested objects, so we need to split them
98
+ function _normalizeSpringBootCfg(obj) {
99
+ if (typeof obj !== 'object') return obj
100
+ Object.keys(obj).forEach(k => {
101
+ const prop = k.split('.')
102
+ const last = prop.pop()
103
+ // and define the object if not already defined
104
+ const res = prop.reduce((o, key) => {
105
+ // define the object if not defined and return
106
+ return o[key] = o[key] ?? {}
107
+ }, obj)
108
+ res[last] = obj[k]
109
+ // recursively normalize
110
+ _normalizeSpringBootCfg(obj[k])
111
+ // delete the original property from object if it was rewritten
112
+ if (prop.length) delete obj[k]
113
+ })
114
+ return obj
115
+ }
116
+
95
117
  }
@@ -28,7 +28,7 @@ module.exports = function _2yaml (object, options={}) { // NOSONAR
28
28
  if (typeof o === 'string') {
29
29
  if (o.indexOf('\n')>=0) return '|'+'\n'+indent+ o.replace(/\n/g,'\n'+indent)
30
30
  let s = o.trim()
31
- return !s || /^[@#:,*]/.test(s) ? '"'+ o +'"' : s
31
+ return !s || /^[\^@#:,*]/.test(s) ? '"'+ o.replace(/\\/g,'\\\\') +'"' : s
32
32
  }
33
33
  else return o
34
34
 
@@ -21,14 +21,14 @@ module.exports = exports = function cds_deploy (model,options,csvs) {
21
21
  TRACE?.time('cds.deploy db ')
22
22
 
23
23
  if (!model) throw new Error('Must provide a model or a path to model, received: ' + model)
24
- if (model && !model.definitions) model = await cds.load(model).then(cds.minify)
24
+ if (!model?.definitions) model = await cds.load(model).then(cds.minify)
25
25
 
26
26
  if (o.mocked) exports.include_external_entities_in(model)
27
27
  else exports.exclude_external_entities_in(model)
28
28
 
29
29
  if (!db.run) db = await cds.connect.to(db)
30
30
  if (!cds.db) cds.db = cds.services.db = db
31
- if (!db.model) db.model = model
31
+ if (!db.model) db.model = model // NOTE: this calls compile.for.nodejs!
32
32
 
33
33
  // eslint-disable-next-line no-console
34
34
  const LOG = o.silent || o.dry || !cds.log('deploy')._info ? () => {} : console.log
@@ -99,7 +99,7 @@ exports.create = async function cds_deploy_create (db, csn=db.model, o) {
99
99
  drops = d
100
100
  } else {
101
101
  // cds deploy -- w/o auto schema evoution > drop-create db
102
- creas = cds.compile.to.sql(csn, o)
102
+ creas = cds.compile.to.sql(csn,o) // NOTE: this used to call cds.linked(cds.minify) and thereby corrupted the passed in csn
103
103
  }
104
104
 
105
105
  if (!drops) {
@@ -125,8 +125,6 @@ exports.create = async function cds_deploy_create (db, csn=db.model, o) {
125
125
  return
126
126
  }
127
127
 
128
- // Set the context model while deploying for cqn42sql in new db layers
129
- db.model = cds.compile.for.nodejs(csn)
130
128
  await db.run(drops)
131
129
  await db.run(creas)
132
130
  return true
@@ -140,12 +138,9 @@ exports.create = async function cds_deploy_create (db, csn=db.model, o) {
140
138
  if (o.dry) return {}
141
139
 
142
140
  let [table_exists] = await db.run(
143
- // REVISIT: prettier forced this horrible, unreadable formatting:
144
- db.kind === 'postgres'
145
- ? `SELECT 1 from pg_tables WHERE tablename = 'cds_model' and schemaname = current_schema()`
146
- : db.kind === 'sqlite'
147
- ? `SELECT 1 from sqlite_schema WHERE name = 'cds_model'`
148
- : cds.error`Schema evolution is not supported for ${db.kind} databases`,
141
+ db.kind === 'postgres' ? `SELECT 1 from pg_tables WHERE tablename = 'cds_model' and schemaname = current_schema()` :
142
+ db.kind === 'sqlite' ? `SELECT 1 from sqlite_schema WHERE name = 'cds_model'` :
143
+ cds.error`Schema evolution is not supported for ${db.kind} databases`,
149
144
  )
150
145
 
151
146
  if (o['model-only'])
@@ -209,7 +204,7 @@ exports.init = async function cds_deploy_init (db, csn=db.model, o, srces, log=(
209
204
  const t = cds.context?.tenant; if (t && t === cds.requires.multitenancy?.t0) return
210
205
  return db.run (async tx => {
211
206
 
212
- const m = tx.model = cds.compile.for.nodejs(csn) //> use correct model while deploying
207
+ const m = tx.model = cds.compile.for.nodejs(csn) // NOTE: this used to create a redundant 4nodejs model for tha same csn
213
208
  const data = await exports.data (m,srces)
214
209
  const query = _queries4 (db,m)
215
210
  const INSERT_from = INSERT_from4 (db,m,o)
@@ -432,4 +427,3 @@ if (!module.parent) (async () => {
432
427
  await db?.disconnect?.()
433
428
  }
434
429
  })().catch(console.error)
435
-
@@ -19,12 +19,6 @@ const defaults = module.exports = {
19
19
  'hcql' : { path: '/hcql' },
20
20
  },
21
21
 
22
- // kept for backwards compatibility
23
- schemas: {
24
- 'cds-rc.json': join(__dirname, 'schemas/cds-rc.json'),
25
- 'cds-package.json': join(__dirname, 'schemas/cds-package.json'),
26
- },
27
-
28
22
  features: {
29
23
  folders: 'fts/*', // where to find feature toggles -> switch on by default when released
30
24
  live_reload: !production,
@@ -65,10 +59,7 @@ const defaults = module.exports = {
65
59
  '[production]': { format: 'json' },
66
60
  levels: {
67
61
  compile: 'warn',
68
- cli: 'warn',
69
- deploy: 'info',
70
- serve: 'info',
71
- server: 'info'
62
+ cli: 'warn'
72
63
  },
73
64
  service: false,
74
65
  // the rest is only applicable for the json formatter
@@ -0,0 +1,27 @@
1
+ const cds = require('../../index')
2
+
3
+ module.exports = {
4
+ _version: cds.version,
5
+
6
+ // base schema file for package.json
7
+ // includes cdsRoot schema from cds-rc.js to enforce cds configuration only in cds section
8
+ // and not in the root of the package.json
9
+
10
+ title: 'JSON schema for CDS configuration in package.json',
11
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
12
+ description: 'This is a JSON schema representation of the CDS project configuration inside a project root level package.json',
13
+ type: 'object',
14
+ properties: {
15
+ extends: {
16
+ description: 'Name of the application that shall be extended',
17
+ type: 'string'
18
+ },
19
+ cds: {
20
+ type: 'object',
21
+ additionalProperties: true,
22
+ $ref: 'cdsJsonSchema://schemas/cds-rc.json#/$defs/cdsRoot',
23
+ description: 'CDS configuration',
24
+ default: {}
25
+ }
26
+ }
27
+ }