@sap/cds 7.6.4 → 7.7.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 +39 -1
- package/_i18n/i18n.properties +3 -0
- package/app/index.js +14 -8
- package/bin/serve.js +51 -19
- package/common.cds +16 -0
- package/lib/auth/ias-auth.js +2 -2
- package/lib/auth/index.js +1 -1
- package/lib/auth/jwt-auth.js +1 -1
- package/lib/compile/cdsc.js +23 -11
- package/lib/compile/for/nodejs.js +2 -2
- package/lib/compile/for/odata.js +4 -0
- package/lib/compile/load.js +7 -2
- package/lib/compile/to/sql.js +3 -0
- package/lib/dbs/cds-deploy.js +197 -220
- package/lib/env/defaults.js +2 -1
- package/lib/index.js +8 -2
- package/lib/linked/types.js +1 -0
- package/lib/log/format/json.js +4 -1
- package/lib/plugins.js +2 -2
- package/lib/ql/SELECT.js +8 -8
- package/lib/req/context.js +22 -13
- package/lib/req/request.js +10 -4
- package/lib/srv/cds-connect.js +9 -3
- package/lib/srv/cds-serve.js +5 -3
- package/lib/srv/middlewares/ctx-model.js +1 -1
- package/lib/srv/protocols/odata-v4.js +38 -9
- package/lib/srv/srv-api.js +98 -140
- package/lib/srv/srv-models.js +2 -2
- package/lib/srv/srv-tx.js +1 -0
- package/lib/utils/cds-utils.js +32 -23
- package/lib/utils/data.js +1 -1
- package/lib/utils/tar.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +0 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +18 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +7 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/index.js +5 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +71 -25
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +10 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +6 -1
- package/libx/_runtime/cds-services/util/assert.js +50 -240
- package/libx/_runtime/cds.js +5 -0
- package/libx/_runtime/common/aspects/any.js +53 -45
- package/libx/_runtime/common/generic/input.js +14 -10
- package/libx/_runtime/common/generic/paging.js +1 -1
- package/libx/_runtime/common/utils/cqn.js +1 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +1 -1
- package/libx/_runtime/common/utils/keys.js +1 -1
- package/libx/_runtime/common/utils/quotingStyles.js +1 -1
- package/libx/_runtime/common/utils/resolveStructured.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +5 -12
- package/libx/_runtime/common/utils/stream.js +2 -16
- package/libx/_runtime/common/utils/streamProp.js +16 -6
- package/libx/_runtime/common/utils/ucsn.js +1 -0
- package/libx/_runtime/db/expand/expandCQNToJoin.js +1 -1
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
- package/libx/_runtime/db/utils/columns.js +6 -1
- package/libx/_runtime/fiori/generic/activate.js +11 -3
- package/libx/_runtime/fiori/generic/edit.js +8 -2
- package/libx/_runtime/fiori/lean-draft.js +94 -30
- package/libx/_runtime/hana/execute.js +2 -5
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +12 -22
- package/libx/_runtime/messaging/service.js +6 -2
- package/libx/common/assert/index.js +232 -0
- package/libx/common/assert/type.js +109 -0
- package/libx/common/assert/utils.js +125 -0
- package/libx/common/assert/validation.js +109 -0
- package/libx/odata/index.js +5 -5
- package/libx/odata/middleware/create.js +83 -0
- package/libx/odata/middleware/delete.js +38 -0
- package/libx/odata/middleware/error.js +8 -0
- package/libx/odata/{metadata.js → middleware/metadata.js} +8 -6
- package/libx/odata/middleware/operation.js +78 -0
- package/libx/odata/middleware/parse.js +11 -0
- package/libx/odata/{read.js → middleware/read.js} +42 -20
- package/libx/odata/{service-document.js → middleware/service-document.js} +2 -1
- package/libx/odata/middleware/stream.js +237 -0
- package/libx/odata/middleware/update.js +165 -0
- package/libx/odata/{afterburner.js → parse/afterburner.js} +79 -29
- package/libx/odata/{cqn2odata.js → parse/cqn2odata.js} +5 -3
- package/libx/odata/{parseToCqn.js → parse/parseToCqn.js} +3 -6
- package/libx/odata/{utils.js → utils/index.js} +95 -9
- package/libx/outbox/index.js +2 -1
- package/libx/rest/RestAdapter.js +0 -1
- package/libx/rest/middleware/operation.js +6 -4
- package/libx/rest/middleware/parse.js +20 -2
- package/package.json +1 -1
- package/server.js +43 -71
- package/libx/odata/create.js +0 -44
- package/libx/odata/delete.js +0 -25
- package/libx/odata/error.js +0 -12
- package/libx/odata/update.js +0 -110
- /package/libx/odata/{grammar.peggy → parse/grammar.peggy} +0 -0
- /package/libx/odata/{parser.js → parse/parser.js} +0 -0
- /package/libx/odata/{result.js → utils/result.js} +0 -0
package/server.js
CHANGED
|
@@ -1,119 +1,91 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const express = require('express'), fs = require('fs'), path = require('path')
|
|
4
|
-
|
|
1
|
+
const express = require('express')// eslint-disable-line cds/no-missing-dependencies
|
|
2
|
+
const cds = require('./lib')
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* Standard express.js bootstrapping, constructing an express `application`
|
|
8
6
|
* and launching a corresponding http server using `app.listen()`.
|
|
9
|
-
* Project-specific `./server.js` can overload this and react to these
|
|
10
|
-
* events:
|
|
11
|
-
*
|
|
12
|
-
* - cds.on('bootstrap',(app)) - emitted before any middleware is added
|
|
13
|
-
* - cds.on('loaded',(model)) - emitted when a model was loaded
|
|
14
|
-
* - cds.on('connect',(srv)) - emitted when a service was connected
|
|
15
|
-
* - cds.on('serving',(srv)) - emitted when a service was served
|
|
16
|
-
* - cds.on('listening',({server,url})) - emitted when the server is listening
|
|
17
|
-
*
|
|
18
7
|
* @param {object} options - canonicalized options from `cds serve` cli
|
|
19
|
-
* @param {boolean} options.in_memory - true if we need to bootstrap an in-memory database
|
|
20
8
|
* @param {string} options.service - name of service to be served; default: 'all'
|
|
21
9
|
* @param {string} options.from - filenames of models to load; default: '*'
|
|
22
|
-
* @param {
|
|
23
|
-
* @param {express.Handler} options.
|
|
24
|
-
* @param {express.Handler} options.
|
|
25
|
-
* @
|
|
10
|
+
* @param {boolean} options.in_memory - true if we need to bootstrap an in-memory database
|
|
11
|
+
* @param {express.Handler} options.favicon - handler for /favicon.ico requests
|
|
12
|
+
* @param {express.Handler} options.index - handler for generated /index.html
|
|
13
|
+
* @param {express.Application} options.app - optional pre-constructed express app
|
|
14
|
+
* @returns {Promise<import('http').Server>} A Promise resolving to Node.js http server as returned by express' `app.listen()`.
|
|
26
15
|
*/
|
|
27
16
|
module.exports = async function cds_server (options) {
|
|
28
17
|
|
|
29
|
-
|
|
18
|
+
// prepare express app
|
|
30
19
|
const o = { ...options, __proto__:defaults }
|
|
31
|
-
|
|
32
20
|
const app = cds.app = o.app || express()
|
|
33
|
-
|
|
34
|
-
cds.emit ('bootstrap',app) //> hook for project-local server.js
|
|
21
|
+
cds.emit ('bootstrap', app)
|
|
35
22
|
|
|
36
|
-
// mount static resources and
|
|
37
|
-
if (o.cors)
|
|
38
|
-
if (o.static) app.use (
|
|
23
|
+
// mount static resources and cors middleware
|
|
24
|
+
if (o.cors) app.use (o.cors) //> if not in prod
|
|
25
|
+
if (o.static) app.use (express.static (o.static)) //> defaults to ./app
|
|
39
26
|
if (o.favicon) app.use ('/favicon.ico', o.favicon) //> if none in ./app
|
|
40
27
|
if (o.index) app.get ('/',o.index) //> if none in ./app
|
|
41
28
|
|
|
42
|
-
// load
|
|
43
|
-
const csn = await cds.load(o.from||'*',o) .then (cds.minify)
|
|
44
|
-
cds.model = cds.compile.for.nodejs(csn)
|
|
29
|
+
// load and prepare models
|
|
30
|
+
const csn = await cds.load(o.from||'*',o) .then (cds.minify)
|
|
31
|
+
cds.model = cds.compile.for.nodejs (csn)
|
|
45
32
|
|
|
46
|
-
// connect to essential framework services
|
|
33
|
+
// connect to essential framework services
|
|
47
34
|
if (cds.requires.db) cds.db = await cds.connect.to ('db') .then (_init)
|
|
48
35
|
if (cds.requires.messaging) await cds.connect.to ('messaging')
|
|
49
36
|
|
|
50
37
|
// serve all services declared in models
|
|
51
38
|
await cds.serve (o.service,o) .in (app)
|
|
52
|
-
await cds.emit ('served', cds.services)
|
|
39
|
+
await cds.emit ('served', cds.services)
|
|
53
40
|
|
|
54
41
|
// start http server
|
|
55
|
-
const port =
|
|
42
|
+
const port = o.port !== undefined ? o.port : ( process.env.PORT || cds.env.server?.port || 4004 )
|
|
56
43
|
return app.server = app.listen (port)
|
|
57
44
|
|
|
58
|
-
//
|
|
45
|
+
// cds.deploy in-memory db, if enabled
|
|
59
46
|
async function _init (db) {
|
|
60
47
|
if (!o.in_memory || cds.requires.multitenancy) return db
|
|
61
|
-
const fts = cds.requires.toggles && cds.resolve (features.folders)
|
|
48
|
+
const fts = cds.requires.toggles && cds.resolve (cds.env.features.folders)
|
|
62
49
|
const m = !fts ? csn : await cds.load([o.from||'*',...fts],o) .then (cds.minify)
|
|
63
50
|
return cds.deploy(m).to(db,o)
|
|
64
51
|
}
|
|
65
|
-
|
|
66
52
|
}
|
|
67
53
|
|
|
68
54
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Default options, which can be overidden by options passed to cds.server().
|
|
57
|
+
*/
|
|
72
58
|
const defaults = {
|
|
73
|
-
|
|
74
|
-
cors,
|
|
75
|
-
|
|
76
59
|
get static() {
|
|
77
|
-
|
|
78
|
-
if (dir && !fs.existsSync(path.resolve(cds.root, dir))) return undefined
|
|
79
|
-
return dir
|
|
60
|
+
return cds.utils.isdir (cds.env.folders.app)
|
|
80
61
|
},
|
|
81
|
-
|
|
82
|
-
// default generic index.html page
|
|
83
62
|
get index() {
|
|
84
63
|
const index = require ('./app/index.js')
|
|
85
64
|
return (_,res) => res.send (index.html)
|
|
86
65
|
},
|
|
87
|
-
|
|
88
|
-
// default favicon
|
|
89
66
|
get favicon() {
|
|
90
67
|
const favicon = require.resolve ('./app/favicon.ico')
|
|
91
68
|
return express.static (favicon, {maxAge:'14d'})
|
|
69
|
+
},
|
|
70
|
+
get cors() {
|
|
71
|
+
return process.env.NODE_ENV === 'production' ? null : (req, res, next) => {
|
|
72
|
+
const { origin } = req.headers
|
|
73
|
+
if (origin) {
|
|
74
|
+
res.set('access-control-allow-origin', origin)
|
|
75
|
+
if (req.method === 'OPTIONS') return res.set('access-control-allow-methods', 'GET,HEAD,PUT,PATCH,POST,DELETE').end()
|
|
76
|
+
}
|
|
77
|
+
next()
|
|
78
|
+
}
|
|
92
79
|
}
|
|
93
80
|
}
|
|
94
81
|
|
|
95
82
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
function cors (req, res, next) { // REVISIT: should that move into middlewares?
|
|
106
|
-
const { origin } = req.headers
|
|
107
|
-
if (origin) res.set('access-control-allow-origin', origin)
|
|
108
|
-
if (origin && req.method === 'OPTIONS')
|
|
109
|
-
return res.set('access-control-allow-methods', 'GET,HEAD,PUT,PATCH,POST,DELETE').end()
|
|
110
|
-
next()
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function express_static (dir) {
|
|
114
|
-
return express.static (path.resolve (cds.root,dir))
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// -------------------------------------------------------------------------
|
|
119
|
-
if (!module.parent) module.exports ({from:process.argv[2]})
|
|
83
|
+
/**
|
|
84
|
+
* Helper to delegate to imported UIs. Usage:
|
|
85
|
+
* @example app.serve('/bookshop').from('@capire/bookshop','app/vue')
|
|
86
|
+
*/
|
|
87
|
+
express.application.serve = function (endpoint) { return { from: (pkg,folder) => {
|
|
88
|
+
folder = !folder ? pkg : cds.utils.path.resolve (require.resolve(pkg+'/package.json',{paths:[cds.root]}),'..',folder)
|
|
89
|
+
this.use (endpoint, express.static(folder))
|
|
90
|
+
if (!endpoint.endsWith('/webapp')) (this._app_links ??= []) .push (endpoint)
|
|
91
|
+
}}}
|
package/libx/odata/create.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
const cds = require('../../')
|
|
2
|
-
const { odataError } = require('./utils')
|
|
3
|
-
const { INSERT } = require('../../lib/ql/cds-ql')
|
|
4
|
-
const { readAfterWrite } = require('../_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite')
|
|
5
|
-
const metaInfo = require('../_runtime/cds-services/adapter/odata-v4/utils/metaInfo')
|
|
6
|
-
const { toODataResult } = require('./result')
|
|
7
|
-
|
|
8
|
-
module.exports = srv =>
|
|
9
|
-
function create(req, res, next) {
|
|
10
|
-
const query = cds.odata.parse(req.url, { service: srv, baseUrl: req.baseUrl })
|
|
11
|
-
|
|
12
|
-
const {
|
|
13
|
-
SELECT: { one }
|
|
14
|
-
} = query
|
|
15
|
-
|
|
16
|
-
if (one) {
|
|
17
|
-
const singleton = query.target._isSingleton
|
|
18
|
-
const error = odataError('405', `Method ${req.method} not allowed for ${singleton ? 'SINGLETON' : 'ENTITY'}`)
|
|
19
|
-
return res.status(405).json(error)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const queryPathXpr = query.SELECT?.from
|
|
23
|
-
|
|
24
|
-
const insertQuery = INSERT.into(queryPathXpr).entries(req.body)
|
|
25
|
-
|
|
26
|
-
const cdsReq = new cds.Request({ query: insertQuery })
|
|
27
|
-
return srv
|
|
28
|
-
.dispatch(cdsReq)
|
|
29
|
-
.then(async result => {
|
|
30
|
-
if (cdsReq._.readAfterWrite) {
|
|
31
|
-
// TODO see if in old odata impl for other checks that should happen
|
|
32
|
-
result = await readAfterWrite(cdsReq, srv, { operation: { result } })
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (result == null) {
|
|
36
|
-
res.status(204)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const info = metaInfo(insertQuery, 'CREATE', srv, req.body, req, false)
|
|
40
|
-
|
|
41
|
-
return res.status(201).send(toODataResult(result, info))
|
|
42
|
-
})
|
|
43
|
-
.catch(next)
|
|
44
|
-
}
|
package/libx/odata/delete.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
const cds = require('../../')
|
|
2
|
-
const { odataError } = require('./utils')
|
|
3
|
-
|
|
4
|
-
module.exports = srv =>
|
|
5
|
-
function deleete(req, res, next) {
|
|
6
|
-
const query = cds.odata.parse(req.url, { service: srv, baseUrl: req.baseUrl })
|
|
7
|
-
|
|
8
|
-
let {
|
|
9
|
-
SELECT: { one }
|
|
10
|
-
} = query
|
|
11
|
-
|
|
12
|
-
if (!one) {
|
|
13
|
-
return res.status(405).json(odataError('405', `Method DELETE not allowed for ENTITY.COLLECTION`))
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const _target = query.SELECT && query.SELECT.from
|
|
17
|
-
const deleteQuery = DELETE.from(_target)
|
|
18
|
-
|
|
19
|
-
return srv
|
|
20
|
-
.run(deleteQuery)
|
|
21
|
-
.then(() => {
|
|
22
|
-
return res.send(204)
|
|
23
|
-
})
|
|
24
|
-
.catch(next)
|
|
25
|
-
}
|
package/libx/odata/error.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const { normalizeError } = require('../_runtime/common/error/frontend')
|
|
2
|
-
const { odataError } = require('./utils')
|
|
3
|
-
|
|
4
|
-
module.exports = _srv => (err, req, res, _next) => {
|
|
5
|
-
const { error, statusCode } = normalizeError(err, req)
|
|
6
|
-
|
|
7
|
-
if (statusCode >= 400 && statusCode < 500) {
|
|
8
|
-
return res.status(statusCode).json(odataError(`${err.code}`, error.message))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return res.status(500).send('Internal Server Error')
|
|
12
|
-
}
|
package/libx/odata/update.js
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
const cds = require('../../')
|
|
2
|
-
const metaInfo = require('../_runtime/cds-services/adapter/odata-v4/utils/metaInfo')
|
|
3
|
-
const { readAfterWrite } = require('../_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite')
|
|
4
|
-
const { where2obj } = require('../_runtime/common/utils/cqn')
|
|
5
|
-
const { toODataResult } = require('./result')
|
|
6
|
-
const { odataError } = require('./utils')
|
|
7
|
-
|
|
8
|
-
const _isUpsertAllowed = ({ target, data, event }) => {
|
|
9
|
-
return (
|
|
10
|
-
!(cds.env.runtime && cds.env.runtime.allow_upsert === false) &&
|
|
11
|
-
!(target && target._isDraftEnabled && (!cds.env.fiori.lean_draft || (!data.IsActiveEntity && event === 'PATCH')))
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const _isNavigationWithKeyInParent = (keys, data, pathExpression, model) => {
|
|
16
|
-
// keys not in data
|
|
17
|
-
if (keys && Object.keys(keys).some(key => key in data)) {
|
|
18
|
-
return false
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const nav = pathExpression.ref && pathExpression.ref.length !== 0 && pathExpression.ref[1]
|
|
22
|
-
const parent = pathExpression.ref && pathExpression.ref[0].id
|
|
23
|
-
|
|
24
|
-
// not a navigation
|
|
25
|
-
if (!parent || !nav) {
|
|
26
|
-
return false
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const navID = typeof nav === 'string' ? nav : nav.id
|
|
30
|
-
const navElement = model.definitions[parent].elements[navID]
|
|
31
|
-
|
|
32
|
-
// not a containment
|
|
33
|
-
if (!navElement._isContained) {
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const where = pathExpression.ref[0].where
|
|
38
|
-
return parent && navElement && where
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
module.exports = srv =>
|
|
42
|
-
function update(req, res, next) {
|
|
43
|
-
const query = cds.odata.parse(req.url, { service: srv, baseUrl: req.baseUrl })
|
|
44
|
-
|
|
45
|
-
const {
|
|
46
|
-
SELECT: { one }
|
|
47
|
-
} = query
|
|
48
|
-
|
|
49
|
-
if (!one) {
|
|
50
|
-
return res.status(405).json(odataError('405', `Method ${req.method} not allowed for ENTITY.COLLECTION`))
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const queryPathXpr = query.SELECT && query.SELECT.from
|
|
54
|
-
|
|
55
|
-
const isPrimitive = query._propertyAccess
|
|
56
|
-
const data = isPrimitive ? { [query._propertyAccess]: req.body.value } : req.body
|
|
57
|
-
|
|
58
|
-
const updateQuery = UPDATE.entity(queryPathXpr).with(data)
|
|
59
|
-
|
|
60
|
-
// we need the cds request, so we can access req._.readAfterWrite
|
|
61
|
-
const cdsReq = new cds.Request({ query: updateQuery })
|
|
62
|
-
|
|
63
|
-
const info = metaInfo(query, 'UPDATE', srv, data, req, false)
|
|
64
|
-
|
|
65
|
-
if (!isPrimitive && queryPathXpr.ref?.[queryPathXpr.ref.length - 1].where) {
|
|
66
|
-
Object.assign(data, where2obj(queryPathXpr.ref?.[queryPathXpr.ref.length - 1].where))
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return srv
|
|
70
|
-
.dispatch(cdsReq)
|
|
71
|
-
.then(async result => {
|
|
72
|
-
if (!isPrimitive && cdsReq._.readAfterWrite) {
|
|
73
|
-
// TODO see if in old odata impl for other checks that should happen
|
|
74
|
-
result = await readAfterWrite(cdsReq, srv, { operation: { result } })
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (result == null) {
|
|
78
|
-
res.status(204)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return res.send(toODataResult(result, info))
|
|
82
|
-
})
|
|
83
|
-
.catch(async e => {
|
|
84
|
-
// UPSERT
|
|
85
|
-
const is404 = e.code === 404 || e.status === 404 || e.statusCode === 404
|
|
86
|
-
if (is404 && !isPrimitive && _isUpsertAllowed({ target: query.target, data: req.body, event: req.method })) {
|
|
87
|
-
// PUT / PATCH with if-match header means "only if already exists", i.e., no insert if not
|
|
88
|
-
if (req.headers['if-match']) throw Object.assign(new Error('412'), { statusCode: 412 })
|
|
89
|
-
|
|
90
|
-
if (_isNavigationWithKeyInParent(query.target.keys, data, queryPathXpr, srv.model)) {
|
|
91
|
-
// REVISIT better error message
|
|
92
|
-
return res.status(422).json(odataError('422', `Unprocessable Entity`))
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// REVISIT: up_XX needs to be looked up -> composition of aspect
|
|
96
|
-
const insertQuery = INSERT.into(queryPathXpr).entries(data)
|
|
97
|
-
const cdsReq = new cds.Request({ query: insertQuery })
|
|
98
|
-
let result = await srv.dispatch(cdsReq)
|
|
99
|
-
|
|
100
|
-
if (cdsReq._.readAfterWrite) {
|
|
101
|
-
// TODO see if in old odata impl for other checks that should happen
|
|
102
|
-
result = await readAfterWrite(cdsReq, srv, { operation: { result } })
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return res.status(201).send(toODataResult(result, info))
|
|
106
|
-
}
|
|
107
|
-
throw e
|
|
108
|
-
})
|
|
109
|
-
.catch(next)
|
|
110
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|