@sap/cds 8.2.2 → 8.2.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 +14 -0
- package/bin/serve.js +3 -0
- package/lib/dbs/cds-deploy.js +2 -0
- package/lib/linked/validate.js +5 -3
- package/libx/_runtime/common/utils/streamProp.js +1 -1
- package/libx/_runtime/fiori/lean-draft.js +4 -1
- package/libx/odata/middleware/read.js +5 -0
- package/libx/odata/utils/result.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
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 8.2.3 - 2024-09-20
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- All annotations in input data are skipped and removed from the input by `cds.validate()` - as we did in legacy OData adapter
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Unmanaged associations are excluded from `@mandatory` checks
|
|
16
|
+
- Properly reject direct requests to `DraftAdministrativeData`
|
|
17
|
+
- Virtual elements annotated with `@Core.MediaType`
|
|
18
|
+
- OData Requests targeting a specific instance and custom handler returns empty array
|
|
19
|
+
- `cds-serve` and `cds-deploy` now set `cds.cli` information
|
|
20
|
+
|
|
7
21
|
## Version 8.2.2 - 2024-09-13
|
|
8
22
|
|
|
9
23
|
### Fixed
|
package/bin/serve.js
CHANGED
|
@@ -158,6 +158,9 @@ async function serve (all=[], o={}) {
|
|
|
158
158
|
if (o.watch) return _watch.call(this, o.project,o) // cds serve --watch <project>
|
|
159
159
|
if (o.project) _chdir_to (o.project) // cds run --project <project>
|
|
160
160
|
|
|
161
|
+
// let plugins know about the CLI
|
|
162
|
+
cds.cli = { command: 'serve', argv: all, options: o }
|
|
163
|
+
|
|
161
164
|
// Ensure loading plugins before calling cds.env!
|
|
162
165
|
await cds.plugins
|
|
163
166
|
|
package/lib/dbs/cds-deploy.js
CHANGED
|
@@ -384,6 +384,7 @@ const _entity4 = (file, csn) => {
|
|
|
384
384
|
|
|
385
385
|
/** CLI used as via cds-deploy as deployer for PostgreSQL */
|
|
386
386
|
if (!module.parent) (async function CLI () {
|
|
387
|
+
cds.cli = { command: 'deploy', argv: process.argv.slice(2), options: {} }
|
|
387
388
|
await cds.plugins // IMPORTANT: that has to go before any call to cds.env, like through cds.deploy or cds.requires below
|
|
388
389
|
let db = cds.requires.db
|
|
389
390
|
try {
|
|
@@ -400,6 +401,7 @@ if (!module.parent) (async function CLI () {
|
|
|
400
401
|
if (o.username) (db.credentials ??= {}).username = o.username
|
|
401
402
|
if (o.password) (db.credentials ??= {}).password = o.password
|
|
402
403
|
}
|
|
404
|
+
cds.cli.options = o
|
|
403
405
|
db = await cds.connect.to(db);
|
|
404
406
|
db = await cds.deploy('*',o).to(db)
|
|
405
407
|
} finally {
|
package/lib/linked/validate.js
CHANGED
|
@@ -46,7 +46,8 @@ class Validation {
|
|
|
46
46
|
return filter.length ? `(${filter})` : `[${index}]`
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
unknown(e,d) {
|
|
49
|
+
unknown(e,d,input) {
|
|
50
|
+
if (e.startsWith('@')) return delete input[e] //> skip all annotations, like @odata.Type
|
|
50
51
|
d['@open'] || cds.error (`Property "${e}" does not exist in ${d.name}`, {status:400})
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -190,12 +191,13 @@ class struct extends $any {
|
|
|
190
191
|
if (each.name in skip) continue // skip uplinks in deep inserts -> see Composition.validate()
|
|
191
192
|
if (each.$struct in data) continue // got struct for flattened element/fk, e.g. {author:{ID:1}}
|
|
192
193
|
if (each.elements || each.foreignKeys) continue // skip struct-likes as we check flat payloads above, and deep payloads via struct.validate()
|
|
194
|
+
if (each.isAssociation) continue // unmanaged associations are always ignored (no value like)
|
|
193
195
|
else ctx.error ('ASSERT_NOT_NULL', path_, each.name) // ASSERT_NOT_NULL should be ASSERT_REQUIRED
|
|
194
196
|
}
|
|
195
197
|
// check values of given data
|
|
196
198
|
for (let each in data) { // will work for structured payloads as well as flattened ones with universal CSN
|
|
197
199
|
let /** @type {$any} */ d = elements[each]
|
|
198
|
-
if (!d
|
|
200
|
+
if (!d) ctx.unknown (each, this, data)
|
|
199
201
|
else if (ctx.cleanse && d._is_readonly()) delete data[each]
|
|
200
202
|
else if (d['@cds.validate'] !== false) d.validate (data[each], path_, ctx)
|
|
201
203
|
}
|
|
@@ -310,4 +312,4 @@ $.LargeBinary.prototype .type_check = v => Buffer.isBuffer(v) || typeof v === 's
|
|
|
310
312
|
$.LargeString.prototype .type_check = v => Buffer.isBuffer(v) || typeof v === 'string' || v instanceof Readable
|
|
311
313
|
|
|
312
314
|
// Mixin above class extensions to cds.linked.classes
|
|
313
|
-
$.mixin ( Decimal, string, $any, action, array, struct, entity, Association, Composition )
|
|
315
|
+
$.mixin ( Decimal, string, $any, action, array, struct, entity, Association, Composition )
|
|
@@ -60,7 +60,7 @@ const handleStreamProperties = (target, columns, model) => {
|
|
|
60
60
|
_addColumns(target, columns)
|
|
61
61
|
} else if (col.ref && (type === 'cds.LargeBinary' || (mediaType && !ignoreMediaType))) {
|
|
62
62
|
if (mediaType) {
|
|
63
|
-
_addColumn(name, mediaType, columns, element['@Core.IsURL'], target)
|
|
63
|
+
if (!element.virtual) _addColumn(name, mediaType, columns, element['@Core.IsURL'], target)
|
|
64
64
|
columns.splice(index, 1)
|
|
65
65
|
} else if (!cds.env.features.stream_compat) {
|
|
66
66
|
columns.splice(index, 1)
|
|
@@ -781,7 +781,10 @@ const Read = {
|
|
|
781
781
|
|
|
782
782
|
// DraftAdministrativeData is only accessible via drafts
|
|
783
783
|
if (_isCount(query)) return run(query)
|
|
784
|
-
if (query._target.name.endsWith('.DraftAdministrativeData'))
|
|
784
|
+
if (query._target.name.endsWith('.DraftAdministrativeData')) {
|
|
785
|
+
if (query.SELECT.from.ref?.length === 1) throw new Error('Invalid draft request') // only via drafts
|
|
786
|
+
return run(query._drafts)
|
|
787
|
+
}
|
|
785
788
|
if (!query._target._isDraftEnabled) return run(query)
|
|
786
789
|
if (
|
|
787
790
|
!query.SELECT.groupBy &&
|
|
@@ -262,6 +262,11 @@ module.exports = adapter => {
|
|
|
262
262
|
|
|
263
263
|
const metadata = getODataMetadata(query, { result, isCollection: !one })
|
|
264
264
|
result = getODataResult(result, metadata, { isCollection: !one, property: _propertyAccess })
|
|
265
|
+
|
|
266
|
+
if (!result) {
|
|
267
|
+
throw Object.assign(new Error('404'), { statusCode: 404 })
|
|
268
|
+
}
|
|
269
|
+
|
|
265
270
|
res.send(result)
|
|
266
271
|
})
|
|
267
272
|
.catch(err => {
|
|
@@ -53,13 +53,15 @@ const _rewriteMetadataDeep = result => {
|
|
|
53
53
|
* @returns {object} - the odata result
|
|
54
54
|
*/
|
|
55
55
|
module.exports = function getODataResult(result, metadata, options = {}) {
|
|
56
|
-
if (result == null) return
|
|
56
|
+
if (result == null) return
|
|
57
57
|
|
|
58
58
|
const { isCollection, property } = options
|
|
59
59
|
|
|
60
60
|
if (isCollection && !Array.isArray(result)) result = [result]
|
|
61
61
|
else if (!isCollection && Array.isArray(result)) result = result[0]
|
|
62
62
|
|
|
63
|
+
if (result === undefined) return
|
|
64
|
+
|
|
63
65
|
// make sure @odata.context is the first element (per OData spec)
|
|
64
66
|
const odataResult = {
|
|
65
67
|
[METADATA.$context]: metadata.context
|