@sap/cds 7.0.2 → 7.0.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/lib/compile/for/lean_drafts.js +1 -1
- package/lib/compile/to/srvinfo.js +6 -2
- package/lib/linked/models.js +2 -1
- package/lib/ql/SELECT.js +1 -0
- package/lib/srv/protocols/index.js +17 -0
- package/lib/utils/tar.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +2 -1
- package/libx/_runtime/hana/streaming.js +3 -4
- package/libx/rest/RestAdapter.js +2 -2
- package/libx/rest/middleware/error.js +4 -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 7.0.3 - 2023-07-19
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Compile for lean draft: do not add draft entity for external entities
|
|
12
|
+
- Rollback awaited in REST adapter
|
|
13
|
+
- `service.on('error')` handler invoked only once
|
|
14
|
+
- `SELECT.one.localized`
|
|
15
|
+
- `COPYFILE_DISABLE=1` is now set for building `tar` archives by default
|
|
16
|
+
- Actions of projection target are no longer accessible in linked models
|
|
17
|
+
- Batch execute model-less mass inputs when on `@sap/hana-client`
|
|
18
|
+
- Requests to `/<path>/webapp` return 404 for absolute `@path` specifications
|
|
19
|
+
- `cds compile --to serviceinfo` no longer returns paths w/ Windows `\` path characters
|
|
20
|
+
|
|
7
21
|
## Version 7.0.2 - 2023-07-06
|
|
8
22
|
|
|
9
23
|
### Fixed
|
|
@@ -106,7 +106,7 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
|
106
106
|
}
|
|
107
107
|
for (const name in csn.definitions) {
|
|
108
108
|
const def = csn.definitions[name]
|
|
109
|
-
if (!_isDraft(def)) continue
|
|
109
|
+
if (!_isDraft(def) || def['@cds.external']) continue
|
|
110
110
|
def.elements.IsActiveEntity.virtual = true
|
|
111
111
|
def.elements.HasDraftEntity.virtual = true
|
|
112
112
|
def.elements.HasActiveEntity.virtual = true
|
|
@@ -62,13 +62,17 @@ module.exports = (model, options={}) => {
|
|
|
62
62
|
|
|
63
63
|
// the URL path that is *likely* effective at runtime
|
|
64
64
|
function _url4 (p) {
|
|
65
|
-
|
|
65
|
+
p = p.replace(/\\/g, '/') // handle Windows
|
|
66
|
+
.replace(/^\/+/, '') // strip leading
|
|
67
|
+
.replace(/\/+$/, '') // strip trailing
|
|
68
|
+
p += '/' // end with /
|
|
69
|
+
return p
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
function _javaPath (service) {
|
|
69
73
|
const d = model.definitions[service.name]
|
|
70
74
|
const path = d && d['@path'] ? d['@path'].replace(/^[^/]/, c => '/'+c) : service.name
|
|
71
|
-
return join(javaPrefix, path)
|
|
75
|
+
return join(javaPrefix, path)
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
function _isNodeProject(root) {
|
package/lib/linked/models.js
CHANGED
|
@@ -25,7 +25,8 @@ class LinkedCSN extends any {
|
|
|
25
25
|
/* else: */ any.prototype
|
|
26
26
|
)
|
|
27
27
|
if (p.key && !d.key && d.kind === 'element') Object.defineProperty (d,'key',{value:undefined}) //> don't propagate .key
|
|
28
|
-
if (p.params && !d.params && d.kind === 'entity') Object.defineProperty (d,'params',{value:undefined}) //> don't propagate .
|
|
28
|
+
if (p.params && !d.params && d.kind === 'entity') Object.defineProperty (d,'params',{value:undefined}) //> don't propagate .params
|
|
29
|
+
if (p.actions && !d.actions && d.kind === 'entity') Object.defineProperty (d,'actions',{value:undefined}) //> don't propagate .actions
|
|
29
30
|
if (d.elements && d.elements.localized) Object.defineProperty (d,'texts',{value: defs [d.elements.localized.target] })
|
|
30
31
|
try { return Object.setPrototypeOf(d,p) } //> link d to resolved proto
|
|
31
32
|
catch(e) { //> cyclic proto error
|
package/lib/ql/SELECT.js
CHANGED
|
@@ -17,6 +17,7 @@ module.exports = class Query extends Whereable {
|
|
|
17
17
|
one: $((...x) => new this({one:true})._select_or_from(...x),{
|
|
18
18
|
columns: (..._) => new this({one:true}).columns(..._),
|
|
19
19
|
from: (..._) => new this({one:true}).from(..._),
|
|
20
|
+
localized: (..._) => new this({one:true,localized:true}).from(..._)
|
|
20
21
|
}),
|
|
21
22
|
from: $((..._) => new this().from(..._), {
|
|
22
23
|
localized: (..._) => new this({localized:true}).from(..._)
|
|
@@ -83,11 +83,28 @@ class ProtocolAdapter {
|
|
|
83
83
|
app.use (`/${path}`, before, adapter, after)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
if (!cds.env.features.serve_on_root) {
|
|
87
|
+
// log warning for changed path if $metadata is accessed
|
|
88
|
+
let logged = false
|
|
89
|
+
app.use(`*/${path}/\\$metadata`, (req,res,next) => {
|
|
90
|
+
if (!logged) {
|
|
91
|
+
const logger = cds.log('adapters')
|
|
92
|
+
logger._warn && logger.warn(`With @sap/cds version 7, the service path has changed to '${srv.path}'.
|
|
93
|
+
If you use SAP Fiori Elements, make sure to adapt the 'dataSources.uri' paths
|
|
94
|
+
in 'manifest.json' files accordingly. For more information, see the release notes at
|
|
95
|
+
https://cap.cloud.sap/docs/releases/jun23.`)
|
|
96
|
+
logged = true
|
|
97
|
+
}
|
|
98
|
+
next()
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
prefix = this.protocols[p.kind].path
|
|
87
103
|
prefix = prefix ? (prefix.endsWith('/') ? prefix : prefix + '/') : '/'
|
|
88
104
|
path = prefix + path
|
|
89
105
|
}
|
|
90
106
|
|
|
107
|
+
app.use (`${path}/webapp/`, (_,res) => res.sendStatus(404))
|
|
91
108
|
DEBUG?.('app.use(', path, ', ... )')
|
|
92
109
|
app.use (path, before, adapter, after)
|
|
93
110
|
// REVISIT this doesn't handle multiple protocols correctly
|
package/lib/utils/tar.js
CHANGED
|
@@ -102,7 +102,7 @@ exports.create = async (dir='.', ...args) => {
|
|
|
102
102
|
args.push('.')
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
c = spawn ('tar', ['c', '-C', dir, ...args])
|
|
105
|
+
c = spawn ('tar', ['c', '-C', dir, ...args], { env: { COPYFILE_DISABLE: 1 }})
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
return {__proto__:c, // returning a thenable + fluent ChildProcess...
|
|
@@ -169,7 +169,7 @@ exports.extract = (archive, ...args) => ({
|
|
|
169
169
|
to (...dest) {
|
|
170
170
|
if (typeof dest === 'string') dest = _resolve(...dest)
|
|
171
171
|
const input = typeof archive !== 'string' || archive == '-' ? '-' : _resolve(archive)
|
|
172
|
-
const x = spawn('tar', ['xf', win(input), '-C', win(dest), ...args]
|
|
172
|
+
const x = spawn('tar', ['xf', win(input), '-C', win(dest), ...args])
|
|
173
173
|
if (archive === '-') return x.stdin
|
|
174
174
|
if (Buffer.isBuffer(archive)) archive = require('stream').Readable.from (archive)
|
|
175
175
|
if (typeof archive !== 'string') archive.pipe (x.stdin)
|
|
@@ -112,6 +112,7 @@ const getErrorHandler = (crashOnError = true, srv) => {
|
|
|
112
112
|
if ('_data' in err && !('data' in req)) req.data = err._data
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// REVISIT: invoking service.on('error') handlers needs a cleanup with new protocol adapters!!!
|
|
115
116
|
// invoke srv.on('error', function (err, req) { ... }) here in special situations
|
|
116
117
|
// REVISIT: if for compat reasons, remove once cds^5.1
|
|
117
118
|
if (srv._handlers._error.length) {
|
|
@@ -124,7 +125,7 @@ const getErrorHandler = (crashOnError = true, srv) => {
|
|
|
124
125
|
// > error before req was dispatched
|
|
125
126
|
const creq = new cds.Request({ req, res: req.res, user: req.user || new cds.User.Anonymous() })
|
|
126
127
|
for (const each of srv._handlers._error) each.handler.call(srv, err, creq)
|
|
127
|
-
} else {
|
|
128
|
+
} else if (ctx._tx?._done !== 'rolled back') {
|
|
128
129
|
// > error after req was dispatched, e.g., serialization error in okra
|
|
129
130
|
const creq = /* odataReq.req || */ new cds.Request({ req, res: req.res, user: ctx.user, tenant: ctx.tenant })
|
|
130
131
|
for (const each of srv._handlers._error) each.handler.call(srv, err, creq)
|
|
@@ -18,7 +18,8 @@ const _loadStreamExtensionIfNeeded = () => {
|
|
|
18
18
|
const streamExtension = _loadStreamExtensionIfNeeded()
|
|
19
19
|
|
|
20
20
|
function hasStreamInsert(insert, model) {
|
|
21
|
-
if (!model) return
|
|
21
|
+
if (!model) return false
|
|
22
|
+
|
|
22
23
|
const name = insert.into.ref ? insert.into.ref[0] : insert.into
|
|
23
24
|
const into = model.definitions[ensureNoDraftsSuffix(name)]
|
|
24
25
|
if (!into) return false
|
|
@@ -38,9 +39,7 @@ function hasStreamInsert(insert, model) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
function hasStreamUpdate(update, model) {
|
|
41
|
-
if (!model)
|
|
42
|
-
return true
|
|
43
|
-
}
|
|
42
|
+
if (!model) return false
|
|
44
43
|
|
|
45
44
|
const entity = model.definitions[ensureNoDraftsSuffix((update.entity.ref && update.entity.ref[0]) || update.entity)]
|
|
46
45
|
if (!entity) return false
|
package/libx/rest/RestAdapter.js
CHANGED
|
@@ -194,12 +194,12 @@ const RestAdapter = function (srv) {
|
|
|
194
194
|
|
|
195
195
|
// -----------------------------------------------------------------------------------------
|
|
196
196
|
// error handling
|
|
197
|
-
router.use((err, req, res, next) => {
|
|
197
|
+
router.use(async (err, req, res, next) => {
|
|
198
198
|
// REVISIT: should not be neccessary!
|
|
199
199
|
// request may fail during processing or during commit -> both caught here
|
|
200
200
|
|
|
201
201
|
// REVISIT: rollback needed if error occured before commit attempted -> how to distinguish?
|
|
202
|
-
cds.context?.tx?.rollback(err).catch(() => {}) // REVISIT: silently ?!?
|
|
202
|
+
await cds.context?.tx?.rollback(err).catch(() => {}) // REVISIT: silently ?!?
|
|
203
203
|
|
|
204
204
|
next(err)
|
|
205
205
|
})
|
|
@@ -39,13 +39,16 @@ const _log = err => {
|
|
|
39
39
|
module.exports = (err, req, res, next) => {
|
|
40
40
|
const { _srv: srv } = req
|
|
41
41
|
|
|
42
|
+
// REVISIT: invoking service.on('error') handlers needs a cleanup with new protocol adapters!!!
|
|
42
43
|
// invoke srv.on('error', function (err, req) { ... }) here in special situations
|
|
43
44
|
let ctx = cds.context
|
|
44
45
|
if (!ctx) {
|
|
45
46
|
// > error before req was dispatched
|
|
46
47
|
ctx = new cds.Request({ req, res: req.res, user: req.user || new cds.User.Anonymous() })
|
|
48
|
+
for (const each of srv._handlers._error) each.handler.call(srv, err, ctx)
|
|
49
|
+
} else if (ctx._tx?._done !== 'rolled back') {
|
|
50
|
+
for (const each of srv._handlers._error) each.handler.call(srv, err, ctx)
|
|
47
51
|
}
|
|
48
|
-
for (const each of srv._handlers._error) each.handler.call(srv, err, ctx)
|
|
49
52
|
|
|
50
53
|
// log the error (4xx -> warn)
|
|
51
54
|
_log(err)
|