@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.
- package/CHANGELOG.md +79 -22
- package/app/index.js +1 -1
- package/lib/auth/index.js +3 -0
- package/lib/compile/extend.js +9 -4
- package/lib/compile/for/lean_drafts.js +3 -4
- package/lib/compile/load.js +11 -15
- package/lib/compile/minify.js +2 -4
- package/lib/compile/to/sql.js +6 -4
- package/lib/compile/to/srvinfo.js +25 -3
- package/lib/compile/to/yaml.js +1 -1
- package/lib/dbs/cds-deploy.js +7 -13
- package/lib/env/defaults.js +1 -10
- package/lib/env/schemas/cds-package.js +27 -0
- package/lib/env/schemas/cds-rc.js +693 -0
- package/lib/env/schemas/index.js +6 -4
- package/lib/i18n/localize.js +15 -1
- package/lib/index.js +40 -47
- package/lib/log/cds-error.js +6 -0
- package/lib/ql/Query.js +2 -1
- package/lib/ql/cds-ql.js +1 -2
- package/lib/ql/infer.js +0 -2
- package/lib/req/request.js +3 -6
- package/lib/srv/middlewares/trace.js +2 -2
- package/lib/srv/protocols/hcql.js +44 -30
- package/lib/srv/protocols/http.js +60 -0
- package/lib/srv/protocols/index.js +0 -7
- package/lib/srv/protocols/odata-v4.js +8 -2
- package/lib/srv/srv-api.js +129 -62
- package/lib/srv/srv-handlers.js +0 -1
- package/lib/srv/srv-models.js +1 -0
- package/lib/utils/cds-test.js +1 -1
- package/lib/utils/cds-utils.js +26 -0
- package/lib/utils/check-version.js +10 -13
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +22 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +3 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +89 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/boundToCQN.js +4 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +1 -24
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +1 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ApplyParser.js +3 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/TrustedResourceJsonSerializer.js +7 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +0 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +17 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +22 -2
- package/libx/_runtime/cds-services/services/utils/columns.js +1 -2
- package/libx/_runtime/common/aspects/Association.js +17 -9
- package/libx/_runtime/common/generic/crud.js +13 -22
- package/libx/_runtime/common/generic/etag.js +1 -1
- package/libx/_runtime/common/generic/input.js +9 -1
- package/libx/_runtime/common/generic/paging.js +3 -3
- package/libx/_runtime/common/generic/sorting.js +25 -15
- package/libx/_runtime/common/generic/stream.js +2 -16
- package/libx/_runtime/common/utils/copy.js +5 -0
- package/libx/_runtime/common/utils/cqn.js +1 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +4 -3
- package/libx/_runtime/common/utils/csn.js +0 -49
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +5 -5
- package/libx/_runtime/common/utils/generateOnCond.js +50 -25
- package/libx/_runtime/common/utils/resolveView.js +5 -44
- package/libx/_runtime/common/utils/rewriteAsterisks.js +17 -4
- package/libx/_runtime/common/utils/stream.js +16 -15
- package/libx/_runtime/common/utils/streamProp.js +25 -22
- package/libx/_runtime/db/Service.js +27 -8
- package/libx/_runtime/db/generic/input.js +6 -1
- package/libx/_runtime/db/generic/rewrite.js +3 -2
- package/libx/_runtime/db/query/read.js +15 -5
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +0 -11
- package/libx/_runtime/db/utils/columns.js +1 -0
- package/libx/_runtime/db/utils/stream.js +41 -0
- package/libx/_runtime/fiori/generic/read.js +2 -1
- package/libx/_runtime/fiori/generic/readOverDraft.js +1 -1
- package/libx/_runtime/fiori/lean-draft.js +216 -59
- package/libx/_runtime/hana/Service.js +1 -1
- package/libx/_runtime/hana/execute.js +53 -14
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +34 -15
- package/libx/_runtime/remote/Service.js +2 -1
- package/libx/_runtime/remote/utils/client.js +1 -1
- package/libx/_runtime/sqlite/Service.js +1 -1
- package/libx/_runtime/sqlite/execute.js +17 -5
- package/libx/odata/afterburner.js +58 -19
- package/libx/odata/cqn2odata.js +6 -8
- package/libx/odata/create.js +44 -0
- package/libx/odata/delete.js +25 -0
- package/libx/odata/error.js +8 -3
- package/libx/odata/metadata.js +6 -8
- package/libx/odata/service-document.js +1 -1
- package/libx/odata/update.js +110 -0
- package/libx/odata/utils.js +9 -6
- package/libx/outbox/index.js +48 -78
- package/libx/rest/RestAdapter.js +0 -3
- package/package.json +1 -1
- package/lib/env/schemas/cds-package.json +0 -17
- package/lib/env/schemas/cds-rc.json +0 -740
- package/lib/ql/STREAM.js +0 -90
package/libx/outbox/index.js
CHANGED
|
@@ -38,56 +38,6 @@ const hasPersistentOutbox = tenant => {
|
|
|
38
38
|
return true
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const isUnrecoverable = (service, error) => {
|
|
42
|
-
let unrecoverable = service.isUnrecoverableError && service.isUnrecoverableError(error)
|
|
43
|
-
if (unrecoverable === undefined) unrecoverable = error.unrecoverable
|
|
44
|
-
return unrecoverable || isStandardError(error)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const processDefault = async (messages, { toBeDeleted, toBeUpdated, options, service }) => {
|
|
48
|
-
/** throws if an emit failed due to a programming error
|
|
49
|
-
* returns false if an emit failed due to temporary issues **/
|
|
50
|
-
const run = async ({ ID, process }) => {
|
|
51
|
-
try {
|
|
52
|
-
await process()
|
|
53
|
-
toBeDeleted.push(ID)
|
|
54
|
-
} catch (e) {
|
|
55
|
-
if (isStandardError(e)) {
|
|
56
|
-
LOG.error(`${service.name}: Programming error detected:`, e)
|
|
57
|
-
toBeDeleted.push(ID)
|
|
58
|
-
throw new Error(`${service.name}: Programming error detected.`)
|
|
59
|
-
}
|
|
60
|
-
if (e.unrecoverable) {
|
|
61
|
-
LOG.error(`${service.name}: Unrecoverable error:`, e)
|
|
62
|
-
if (options.maxAttempts) {
|
|
63
|
-
const _msg = { ID, attempts: options.maxAttempts }
|
|
64
|
-
if (options.storeLastError !== false) _msg.lastError = e
|
|
65
|
-
toBeUpdated.push(_msg)
|
|
66
|
-
} else toBeDeleted.push(ID)
|
|
67
|
-
} else {
|
|
68
|
-
LOG.error(`${service.name}: Emit failed:`, e)
|
|
69
|
-
const _msg = { ID }
|
|
70
|
-
if (options.storeLastError !== false) _msg.lastError = e
|
|
71
|
-
toBeUpdated.push(_msg)
|
|
72
|
-
return false
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (options.parallel) {
|
|
77
|
-
const first = messages.next()?.value // First try to see if message can be emitted
|
|
78
|
-
if (first && (await run(first)) === false) return // No need to process the rest if the emit failed
|
|
79
|
-
const res = await Promise.allSettled([...messages].map(run))
|
|
80
|
-
const errors = res.filter(r => r.status === 'rejected').map(r => r.reason)
|
|
81
|
-
if (errors.length) {
|
|
82
|
-
throw new Error(`${service.name}: Programming errors detected.`)
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
for (const msg of messages) {
|
|
86
|
-
if ((await run(msg)) === false) break
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
41
|
const _safeJSONParse = string => {
|
|
92
42
|
try {
|
|
93
43
|
return string && JSON.parse(string)
|
|
@@ -142,36 +92,64 @@ const processMessages = async (service, tenant, _opts = {}) => {
|
|
|
142
92
|
const user = new cds.User.Privileged(userId)
|
|
143
93
|
if (!msg) continue
|
|
144
94
|
const res = {
|
|
145
|
-
process: () =>
|
|
146
|
-
cds._context.run({ user, tenant }, async () => {
|
|
147
|
-
try {
|
|
148
|
-
return await service.handle(msg)
|
|
149
|
-
} catch (e) {
|
|
150
|
-
if (isUnrecoverable(service, e)) e.unrecoverable = true
|
|
151
|
-
throw e
|
|
152
|
-
}
|
|
153
|
-
}),
|
|
154
95
|
ID: _message.ID,
|
|
155
96
|
msg,
|
|
156
|
-
user
|
|
157
|
-
opts
|
|
97
|
+
user
|
|
158
98
|
}
|
|
159
99
|
yield res
|
|
160
100
|
}
|
|
161
101
|
}
|
|
162
102
|
|
|
163
|
-
const process = service.options.outbox?.process || this.process || processDefault
|
|
164
103
|
const toBeDeleted = []
|
|
165
104
|
const toBeUpdated = []
|
|
166
105
|
try {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
106
|
+
const _handleWithErr = async ({ msg, user, ID }) => {
|
|
107
|
+
try {
|
|
108
|
+
await cds._context.run({ user, tenant }, async () => {
|
|
109
|
+
if (opts.handle) await opts.handle.call(service, msg)
|
|
110
|
+
else await service.handle(msg)
|
|
111
|
+
})
|
|
112
|
+
toBeDeleted.push(ID)
|
|
113
|
+
} catch (e) {
|
|
114
|
+
if (isStandardError(e)) {
|
|
115
|
+
LOG.error(`${service.name}: Programming error detected:`, e)
|
|
116
|
+
toBeDeleted.push(ID)
|
|
117
|
+
throw new Error(`${service.name}: Programming error detected.`)
|
|
118
|
+
}
|
|
119
|
+
if (e.unrecoverable) {
|
|
120
|
+
LOG.error(`${service.name}: Unrecoverable error:`, e)
|
|
121
|
+
if (opts.maxAttempts) {
|
|
122
|
+
const _msg = { ID, attempts: opts.maxAttempts }
|
|
123
|
+
if (opts.storeLastError !== false) _msg.lastError = e
|
|
124
|
+
toBeUpdated.push(_msg)
|
|
125
|
+
} else toBeDeleted.push(ID)
|
|
126
|
+
} else {
|
|
127
|
+
LOG.error(`${service.name}: Emit failed:`, e)
|
|
128
|
+
const _msg = { ID }
|
|
129
|
+
if (opts.storeLastError !== false) _msg.lastError = e
|
|
130
|
+
toBeUpdated.push(_msg)
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const messages = messagesGen()
|
|
136
|
+
// REVISIT: Maybe we can also support handleMany and provide the iterator (for batch processing)
|
|
137
|
+
if (opts.parallel) {
|
|
138
|
+
const first = messages.next()?.value // First try to see if message can be emitted
|
|
139
|
+
if (!(first && (await _handleWithErr(first)) === false)) { // No need to process the rest if the first emit failed
|
|
140
|
+
const res = await Promise.allSettled([...messages].map(_handleWithErr))
|
|
141
|
+
const errors = res.filter(r => r.status === 'rejected').map(r => r.reason)
|
|
142
|
+
if (errors.length) {
|
|
143
|
+
throw new Error(`${service.name}: Programming errors detected.`)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
for (const msg of messages) {
|
|
148
|
+
if ((await _handleWithErr(msg)) === false) break
|
|
149
|
+
}
|
|
150
|
+
}
|
|
173
151
|
} catch (e) {
|
|
174
|
-
|
|
152
|
+
letAppCrash = true
|
|
175
153
|
}
|
|
176
154
|
|
|
177
155
|
const queries = []
|
|
@@ -250,13 +228,6 @@ const writeInOutbox = async (name, msg, context) => {
|
|
|
250
228
|
return cds.tx(context).run(INSERT.into(messagesEntity).entries(outboxMsg))
|
|
251
229
|
}
|
|
252
230
|
|
|
253
|
-
// REVIST: Should we also support the following API?
|
|
254
|
-
// cds.outboxed(srv, {
|
|
255
|
-
// onInsert(msg){ ... }
|
|
256
|
-
// onForward(msg){ ... }
|
|
257
|
-
// onProcess(msgs){ ... }
|
|
258
|
-
// })
|
|
259
|
-
|
|
260
231
|
function unboxed(srv) {
|
|
261
232
|
return srv[$unboxed] || srv
|
|
262
233
|
}
|
|
@@ -303,8 +274,7 @@ function outboxed(srv, customOpts) {
|
|
|
303
274
|
else await originalSrv.emit(req)
|
|
304
275
|
} catch (e) {
|
|
305
276
|
LOG.error('Emit failed', { event: req.event, cause: e })
|
|
306
|
-
|
|
307
|
-
if (isUnrecoverable(originalSrv, e) && outboxOpts.crashOnError !== false) cds.exit(1)
|
|
277
|
+
if (isStandardError(e)) cds.exit(1)
|
|
308
278
|
}
|
|
309
279
|
})
|
|
310
280
|
}
|
package/libx/rest/RestAdapter.js
CHANGED
|
@@ -16,7 +16,6 @@ const payload_factory = require('./middleware/payload')
|
|
|
16
16
|
const error_factory = require('./middleware/error')
|
|
17
17
|
|
|
18
18
|
const { bufferToBase64 } = require('../_runtime/common/utils/binary')
|
|
19
|
-
const { alias2ref } = require('../_runtime/common/utils/csn')
|
|
20
19
|
const { getAccessRestrictions } = require('../_runtime/common/utils/restrictions')
|
|
21
20
|
|
|
22
21
|
const RestAdapter = function (srv) {
|
|
@@ -24,8 +23,6 @@ const RestAdapter = function (srv) {
|
|
|
24
23
|
const input = input_factory(srv)
|
|
25
24
|
const payload = payload_factory(srv)
|
|
26
25
|
|
|
27
|
-
alias2ref(srv)
|
|
28
|
-
|
|
29
26
|
const router = express.Router()
|
|
30
27
|
|
|
31
28
|
// -----------------------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"title": "JSON schema for CDS configuration in package.json",
|
|
3
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
-
"description": "This is a JSON schema representation of the CDS project configuration inside a project root level package.json",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"properties": {
|
|
7
|
-
"extends": {
|
|
8
|
-
"description": "Name of the application that shall be extended",
|
|
9
|
-
"type": "string"
|
|
10
|
-
},
|
|
11
|
-
"cds": {
|
|
12
|
-
"$ref": "cdsJsonSchema://schemas/cds-rc.json",
|
|
13
|
-
"description": "CDS configuration",
|
|
14
|
-
"default": {}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|