@sap/cds 6.8.4 → 7.0.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 +66 -4
- package/README.md +0 -1
- package/bin/cds-serve.js +50 -3
- package/bin/deploy/to-hana.js +1 -0
- package/bin/serve.js +16 -20
- package/lib/auth/basic-auth.js +6 -4
- package/lib/auth/index.js +4 -3
- package/lib/auth/jwt-auth.js +2 -5
- package/lib/compile/cds-compile.js +34 -89
- package/lib/compile/cdsc.js +11 -0
- package/lib/compile/etc/properties.js +2 -2
- package/lib/compile/for/lean_drafts.js +36 -69
- package/lib/compile/for/nodejs.js +2 -1
- package/lib/compile/load.js +3 -3
- package/lib/compile/minify.js +2 -0
- package/lib/compile/to/csn.js +74 -0
- package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
- package/lib/compile/to/json.js +1 -1
- package/lib/compile/to/sql.js +8 -6
- package/lib/dbs/cds-deploy.js +174 -114
- package/lib/env/cds-env.js +64 -79
- package/lib/env/cds-requires.js +11 -28
- package/lib/env/defaults.js +13 -3
- package/lib/env/plugins.js +1 -12
- package/lib/env/presets.js +25 -21
- package/lib/index.js +121 -147
- package/lib/{core/reflect.js → linked/models.js} +2 -2
- package/lib/{core/infer.js → linked/queries.js} +2 -0
- package/lib/{core/index.js → linked/types.js} +2 -1
- package/lib/log/cds-error.js +13 -7
- package/lib/log/format/cf.js +1 -1
- package/lib/plugins.js +49 -0
- package/lib/ql/Query.js +0 -9
- package/lib/ql/STREAM.js +0 -1
- package/lib/req/context.js +2 -7
- package/lib/req/request.js +6 -2
- package/lib/req/response.js +23 -10
- package/lib/srv/middlewares/ctx-model.js +2 -2
- package/lib/srv/middlewares/errors.js +1 -1
- package/lib/srv/protocols/_legacy.js +1 -0
- package/lib/srv/protocols/graphql.js +7 -16
- package/lib/srv/protocols/index.js +59 -45
- package/lib/srv/protocols/odata-v2-proxy.js +2 -70
- package/lib/srv/protocols/odata-v4.js +9 -4
- package/lib/srv/srv-api.js +9 -3
- package/lib/srv/srv-dispatch.js +12 -9
- package/lib/srv/srv-models.js +4 -21
- package/lib/srv/srv-tx.js +15 -12
- package/lib/utils/cds-test.js +14 -9
- package/lib/utils/cds-utils.js +2 -12
- package/lib/utils/check-version.js +17 -0
- package/{bin/build → lib/utils}/csv-reader.js +23 -24
- package/libx/_runtime/auth/index.js +27 -23
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriTokenizer.js +5 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
- package/libx/_runtime/cds-services/services/Service.js +79 -107
- package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
- package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
- package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
- package/libx/_runtime/cds-services/util/assert.js +65 -2
- package/libx/_runtime/common/composition/data.js +1 -0
- package/libx/_runtime/common/generic/auth/expand.js +1 -1
- package/libx/_runtime/common/generic/auth/restrict.js +5 -10
- package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
- package/libx/_runtime/common/generic/auth/utils.js +1 -2
- package/libx/_runtime/common/generic/crud.js +32 -16
- package/libx/_runtime/common/generic/etag.js +133 -104
- package/libx/_runtime/common/generic/input.js +6 -21
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/stream.js +52 -0
- package/libx/_runtime/common/generic/temporal.js +25 -8
- package/libx/_runtime/common/i18n/messages.properties +0 -2
- package/libx/_runtime/common/utils/cqn.js +1 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
- package/libx/_runtime/common/utils/csn.js +0 -51
- package/libx/_runtime/common/utils/etag.js +30 -0
- package/libx/_runtime/common/utils/keys.js +1 -1
- package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
- package/libx/_runtime/common/utils/path.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
- package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
- package/libx/_runtime/common/utils/stream.js +140 -0
- package/libx/_runtime/common/utils/streamProp.js +29 -12
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
- package/libx/_runtime/db/generic/index.js +0 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +2 -2
- package/libx/_runtime/db/query/read.js +2 -2
- package/libx/_runtime/db/query/run.js +2 -2
- package/libx/_runtime/db/query/update.js +2 -2
- package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
- package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
- package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
- package/libx/_runtime/fiori/draft.js +2 -0
- package/libx/_runtime/fiori/generic/activate.js +8 -9
- package/libx/_runtime/fiori/generic/before.js +30 -20
- package/libx/_runtime/fiori/generic/cancel.js +5 -3
- package/libx/_runtime/fiori/generic/delete.js +5 -3
- package/libx/_runtime/fiori/generic/edit.js +7 -7
- package/libx/_runtime/fiori/generic/index.js +10 -16
- package/libx/_runtime/fiori/generic/new.js +5 -3
- package/libx/_runtime/fiori/generic/patch.js +11 -8
- package/libx/_runtime/fiori/generic/prepare.js +13 -6
- package/libx/_runtime/fiori/generic/read.js +12 -6
- package/libx/_runtime/fiori/lean-draft.js +207 -152
- package/libx/_runtime/fiori/utils/delete.js +10 -5
- package/libx/_runtime/fiori/utils/req.js +17 -5
- package/libx/_runtime/fiori/utils/stream.js +36 -0
- package/libx/_runtime/hana/Service.js +12 -9
- package/libx/_runtime/hana/conversion.js +10 -15
- package/libx/_runtime/hana/driver.js +2 -0
- package/libx/_runtime/hana/execute.js +28 -6
- package/libx/_runtime/hana/pool.js +36 -122
- package/libx/_runtime/hana/search2cqn4sql.js +34 -36
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/remote/Service.js +20 -1
- package/libx/_runtime/remote/utils/client.js +3 -5
- package/libx/_runtime/sqlite/Service.js +4 -6
- package/libx/_runtime/sqlite/conversion.js +3 -13
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
- package/libx/_runtime/sqlite/execute.js +5 -16
- package/libx/odata/afterburner.js +22 -6
- package/libx/odata/grammar.pegjs +6 -1
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +16 -9
- package/libx/rest/RestRequest.js +1 -1
- package/libx/rest/middleware/input.js +2 -1
- package/libx/rest/middleware/operation.js +1 -0
- package/libx/rest/middleware/parse.js +3 -2
- package/libx/rest/middleware/payload.js +9 -8
- package/libx/rest/middleware/read.js +1 -0
- package/package.json +9 -16
- package/server.js +1 -1
- package/app/fiori/preview.js +0 -270
- package/app/fiori/routes.js +0 -59
- package/bin/build/buildTaskEngine.js +0 -360
- package/bin/build/buildTaskFactory.js +0 -283
- package/bin/build/buildTaskHandler.js +0 -241
- package/bin/build/buildTaskProvider.js +0 -22
- package/bin/build/buildTaskProviderFactory.js +0 -175
- package/bin/build/cds.js +0 -5
- package/bin/build/constants.js +0 -66
- package/bin/build/index.js +0 -58
- package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
- package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
- package/bin/build/provider/buildTaskProviderInternal.js +0 -383
- package/bin/build/provider/fiori/index.js +0 -171
- package/bin/build/provider/hana/2migration.js +0 -179
- package/bin/build/provider/hana/index.js +0 -505
- package/bin/build/provider/hana/migrationtable.js +0 -472
- package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
- package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
- package/bin/build/provider/hana/template/.hdinamespace +0 -4
- package/bin/build/provider/hana/template/package.json +0 -12
- package/bin/build/provider/hana/template/undeploy.json +0 -5
- package/bin/build/provider/java/index.js +0 -111
- package/bin/build/provider/java-cf/index.js +0 -1
- package/bin/build/provider/mtx/index.js +0 -268
- package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
- package/bin/build/provider/mtx-extension/index.js +0 -131
- package/bin/build/provider/mtx-sidecar/index.js +0 -137
- package/bin/build/provider/node-cf/index.js +0 -1
- package/bin/build/provider/nodejs/index.js +0 -192
- package/bin/build/util.js +0 -299
- package/bin/cds.js +0 -125
- package/bin/deploy/to-hana/cfUtil.js +0 -355
- package/bin/deploy/to-hana/gitUtil.js +0 -57
- package/bin/deploy/to-hana/hana.js +0 -306
- package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
- package/bin/deploy/to-hana/index.js +0 -16
- package/bin/deploy/to-hana/mtaUtil.js +0 -170
- package/bin/mtx/in-cds.js +0 -17
- package/bin/plugins.js +0 -32
- package/bin/run.js +0 -24
- package/bin/utils/log.js +0 -24
- package/bin/version.js +0 -178
- package/libx/_runtime/audit/Service.js +0 -222
- package/libx/_runtime/audit/generic/personal/access.js +0 -61
- package/libx/_runtime/audit/generic/personal/index.js +0 -56
- package/libx/_runtime/audit/generic/personal/modification.js +0 -132
- package/libx/_runtime/audit/generic/personal/utils.js +0 -186
- package/libx/_runtime/audit/utils/log.js +0 -23
- package/libx/_runtime/audit/utils/v2.js +0 -176
- package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
- package/libx/_runtime/db/generic/integrity.js +0 -455
- package/srv/audit-log.cds +0 -87
- package/srv/mtx.cds +0 -2
- package/srv/mtx.js +0 -8
- /package/lib/{core → linked}/classes.js +0 -0
- /package/lib/{core → linked}/entities.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,67 @@
|
|
|
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
|
+
## Version 7.0.1 - 2023-07-03
|
|
8
8
|
|
|
9
9
|
### Fixed
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- Feature toggle detection in single tenant mode
|
|
12
|
+
- Log output for OData $batch requests
|
|
13
|
+
- Avoid "catastrophic backtracking" issue in okra's tokenizer
|
|
14
|
+
- Transaction marked as committed too early
|
|
15
|
+
|
|
16
|
+
## Version 7.0.0 - 2023-06-21
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Handling of expand with multiple `*` (e.g. $expand=*,*) in new parser. When using `*` in an expand the new OData parser now removes all unneeded `*`.
|
|
21
|
+
- Tests run with `cds.test()` now also load `cds-plugins`
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Result of `READ` events is now always an array. Previously, it could be `null/undefined` (now empty array), single object (now array with one entry) or array.
|
|
26
|
+
- OData: `PUT`/`PATCH` requests resulting in a new entity (i.e., the `UPSERT` effectively was an `INSERT`) return status code 201
|
|
27
|
+
- Draft: Draft activate requests resulting in an `UPDATE` return status code 200
|
|
28
|
+
- ETags are validated via `WHERE EXISTS` clause attached to query on `GET`, `PUT`/`PATCH`, and `DELETE`
|
|
29
|
+
- OData: `PUT`/`PATCH` with `if-match` header prevents `UPSERT`, i.e., only an existing entity can be updated by such a request
|
|
30
|
+
- Runtime support for `@sap/instance-manager` is removed in favor of the `cds-mtxs` Service Manager client.
|
|
31
|
+
- In multitenant mode, the HANA pool uses the `cds-mtxs` credentials cache
|
|
32
|
+
- Draft handlers are registered for all entities.
|
|
33
|
+
- Decimals in client input are validated in runtime's assert framework (previously OData adapter)
|
|
34
|
+
- `cds build` and `cds deploy --to hana` have moved to `@sap/cds-dk`. Upgrade `@sap/cds-dk` to version 7 to continue using these commands.
|
|
35
|
+
- Changed the behavior of `SELECT` queries for single entities to return `undefined` instead of `null` when no record is found.
|
|
36
|
+
- Fiori preview has moved to new `@sap/cds-fiori` module.
|
|
37
|
+
- Numbers are now always used as placeholders in SQL, except for `SELECT 1 From...`, `LIMIT` and the comparison of two numeric values (e.g. `1 eq 1`).
|
|
38
|
+
- Only new major version 3 of SAP Cloud SDK is from now on supported. Please make sure to upgrade. Version 2 is not maintained anymore.
|
|
39
|
+
- `@protocol` annotation can be used to serve multiple protocols per service.
|
|
40
|
+
- Per default, services are served with a protocol-specific prefix (for example '/odata/v4' for a service using the OData V4 protocol). To also serve without this prefix, as it was the case in older @sap/cds versions, the flag `cds.env.features.serve_on_root` can be set to `true`. Alternatively, the `@path` annotation can be used to explicitely specify an absolute path (with a leading `/`).
|
|
41
|
+
- `cds.requires.middlewares` is enabled by default.
|
|
42
|
+
- The order of csv files that `cds deploy --to sqlite` uses now reflects the dependency order of cds models. This is needed if `UPSERT` is used to create a logically correct deployment.
|
|
43
|
+
- `cds.fiori.lean_draft` is activated by default. You can still set it to `false` as fallback.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- UUID typed key properties are no longer automatically filled during UPSERT
|
|
48
|
+
- OData: When undefined in the payload, requests for actions with not nullable array-type parameters result in a client-side error
|
|
49
|
+
- Missing `GROUP BY` in request with $apply in combination with aggregate on restricted entity
|
|
50
|
+
- When `@sap/cds` was not installed underneath project root, cds-plugins where not found
|
|
51
|
+
- Support for multiline texts in `properties` files
|
|
52
|
+
- Error when reading auth protected entities with infix filter in expand
|
|
53
|
+
- Glitch in transaction handling in case of concurrent async before handlers
|
|
54
|
+
- Detection of feature toggles in single-tenant mode
|
|
55
|
+
|
|
56
|
+
### Removed
|
|
57
|
+
|
|
58
|
+
- Deprecated `req.run()` function, use `cds.run()` instead.
|
|
59
|
+
- Deprecated compat mode `cds.env.features.cds_tx_protection = false`
|
|
60
|
+
- Deprecated referential integrity checks at runtime
|
|
61
|
+
- Support for inofficial feature flag `cds.env.features.bigjs`
|
|
62
|
+
- Support for inofficial feature flag `cds.features.parameterized_numbers`
|
|
63
|
+
- Support for `cds-mtx`
|
|
64
|
+
- Support for Node 14
|
|
65
|
+
- Internal `req.getUriInfo()` and `req.getUrlObject()`
|
|
66
|
+
- `cds deploy --to hana` is now part of `@sap/cds-dk`.
|
|
67
|
+
- Beta `AuditLogService` and out-of-the-box audit logging. Use plugin `@cap-js/audit-logging` instead.
|
|
12
68
|
|
|
13
69
|
## Version 6.8.3 - 2023-06-13
|
|
14
70
|
|
|
@@ -48,6 +104,9 @@ For example, similar OData requests `Entity?$expand=items($expand=item($expand=t
|
|
|
48
104
|
- `cds build` ignores invalid entries in `undeploy.json`
|
|
49
105
|
- New `minorUnit` element in `sap.common.Currencies` for how many fractions the minor unit takes (e.g. `0`, or `2`). See https://www.npmjs.com/package/@sap/cds-common-content for matching content.
|
|
50
106
|
- Support for `$user.<attr> is null` and `$user.<attr> is not null` in `@restrict.where`. `is null` matches `null` and `[]`, `is not null` matches arrays with at least one entry as well as `!= null` if no array.
|
|
107
|
+
- Plugins are now also fetched from `devDependencies`, unless `NODE_ENV === 'production'`
|
|
108
|
+
- Plugins can now provide `cds` configurations in their package.json.
|
|
109
|
+
- Support in OData entities with special letters (like ó,â,ü) in names.
|
|
51
110
|
|
|
52
111
|
### Changed
|
|
53
112
|
|
|
@@ -66,6 +125,10 @@ The fix relies on the `@sap-cloud-sdk/connectivity` npm package to be installed.
|
|
|
66
125
|
- Fixes in lean-draft
|
|
67
126
|
- Fixed an issue where the combined `$search` and `$expand` query and localized data was returning empty results on SAP HANA
|
|
68
127
|
- Tests using `cds.test` no longer crash with a segmentation fault if `injectGlobals: false` is set in the Jest configuration.
|
|
128
|
+
- Handlers registered with `cds.on('shutdown')` are now called with an `err` argument in case the shutdown happened in response to uncaught exceptions or unhandled rejected Promises.
|
|
129
|
+
- Log output on uncaught exceptions or unhandled rejected Promises now is done via `cds.log` instead of `console`.
|
|
130
|
+
- New config option `cds.env.server.force_exit_timeout` allows to configure the timeout in ms after which we force-exit the server (default: 1111) if it didn't do so as expected after a prior `server.close()`. Values `false` or `0` disable force-exit.
|
|
131
|
+
- Require custom auth relative to project root when using pluggable middlewares
|
|
69
132
|
|
|
70
133
|
## Version 6.7.2 - 2023-04-24
|
|
71
134
|
|
|
@@ -273,6 +336,7 @@ cds env requires/cds.xt.ModelProviderService
|
|
|
273
336
|
- `cds.context.http` is now available for webhook-based requests
|
|
274
337
|
- `cds build` for SAP HANA migration tables now only saves model entities annotated with `@cds.persistence.journal` as `last-dev` version.
|
|
275
338
|
- `cds deploy` now uses the `VCAP_SERVICES` environment variable (if set), and skips `cf` operations in this case
|
|
339
|
+
- Support for timestamp precision greater than 3 digits of fractional seconds
|
|
276
340
|
|
|
277
341
|
### Changed
|
|
278
342
|
|
|
@@ -489,8 +553,6 @@ Content-Length: 145
|
|
|
489
553
|
- `cds deploy` and `cds run/serve/watch` no longer print terminal escape sequences (`x1b...`) if they run non-interactively.
|
|
490
554
|
- Some fields in entities like `path` generated invalid sql
|
|
491
555
|
|
|
492
|
-
### Removed
|
|
493
|
-
|
|
494
556
|
## Version 6.1.3 - 2022-09-13
|
|
495
557
|
|
|
496
558
|
### Added
|
package/README.md
CHANGED
package/bin/cds-serve.js
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
const cds = require('../lib') //> ensure we are the first to load @sap/cds locally
|
|
3
|
+
const cli = {
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
exec (...argv) {
|
|
6
|
+
if (!argv.length) argv = process.argv.slice(2)
|
|
7
|
+
const task = require ('./serve')
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
let args = []
|
|
10
|
+
try {
|
|
11
|
+
args = this.args(task, argv)
|
|
12
|
+
} catch (err) { process.exitCode = 1; return console.error(err) }
|
|
13
|
+
|
|
14
|
+
return task.apply (this, args)
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// TODO replace w/ common arg parser from node
|
|
18
|
+
args (task, argv) {
|
|
19
|
+
|
|
20
|
+
const { options:o=[], flags:f=[], shortcuts:s=[] } = task
|
|
21
|
+
const _global = /^--(profile|production|sql|odata|build-.*|cdsc-.*|odata-.*|folders-.*)$/
|
|
22
|
+
const _flags = { '--production':true }
|
|
23
|
+
const options = {}, args = []
|
|
24
|
+
let k,a, env = null
|
|
25
|
+
|
|
26
|
+
if (argv.length) for (let i=0; i < argv.length; ++i) {
|
|
27
|
+
if ((a = argv[i])[0] !== '-') args.push(a)
|
|
28
|
+
else if ((k = s.indexOf(a)) >= 0) k < o.length ? add(o[k],argv[++i]) : add(f[k-o.length])
|
|
29
|
+
else if ((k = o.indexOf(a)) >= 0) add(o[k],argv[++i])
|
|
30
|
+
else if ((k = f.indexOf(a)) >= 0) add(f[k])
|
|
31
|
+
else if (_global.test(a)) add_global(a, _flags[a] || argv[++i])
|
|
32
|
+
else throw 'Invalid option: '+ a
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function add (k,v) { options[k.slice(2)] = v || true }
|
|
36
|
+
function add_global (k,v='') {
|
|
37
|
+
if (k === '--production') return process.env.NODE_ENV = 'production'
|
|
38
|
+
if (k === '--profile') return process.env.CDS_ENV = v.split(',')
|
|
39
|
+
if (k === '--odata') v = { flavor:v }
|
|
40
|
+
let e=env || (env={}), path = k.slice(2).split('-')
|
|
41
|
+
while (path.length > 1) { let p = path.shift(); e = e[p]||(e[p]={}) }
|
|
42
|
+
add (k, e[path[0]] = v)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (env) cds.env.add (env)
|
|
46
|
+
return [ args, options ]
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = Object.assign ((..._) => cli.exec(..._), cli)
|
|
51
|
+
if (!module.parent) cli.exec()
|
|
52
|
+
|
|
53
|
+
/* eslint no-console:off */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
throw new Error('This application uses @sap/cds version >= 7, which is not compatible with the installed @sap/cds-dk version 6. Either update @sap/cds-dk to version 7 or downgrade @sap/cds to version 6 instead.')
|
package/bin/serve.js
CHANGED
|
@@ -154,6 +154,9 @@ async function serve (all=[], o={}) {
|
|
|
154
154
|
if (o.watch) return _watch.call(this, o.project,o) // cds serve --watch <project>
|
|
155
155
|
if (o.project) _chdir_to (o.project) // cds run --project <project>
|
|
156
156
|
|
|
157
|
+
// Ensure loading plugins before calling cds.env!
|
|
158
|
+
await cds.plugins
|
|
159
|
+
|
|
157
160
|
const TRACE = cds.debug('trace')
|
|
158
161
|
// if (TRACE) {
|
|
159
162
|
// TRACE?.time('load express '); require('express') // eslint-disable-line cds/no-missing-dependencies
|
|
@@ -166,7 +169,7 @@ async function serve (all=[], o={}) {
|
|
|
166
169
|
if (!o.silent) _prepare_logging ()
|
|
167
170
|
|
|
168
171
|
// The following things are meant for dev mode, which can be overruled by feature flagse...
|
|
169
|
-
const {features
|
|
172
|
+
const {features} = cds.env
|
|
170
173
|
{
|
|
171
174
|
// handle --with-mocks resp. --mocked
|
|
172
175
|
if (features.with_mocks) o.mocked = _with_mocks(o)
|
|
@@ -180,16 +183,8 @@ async function serve (all=[], o={}) {
|
|
|
180
183
|
// live reload, in cooperation with cds watch
|
|
181
184
|
if (features.live_reload) require('../app/etc/livereload')
|
|
182
185
|
|
|
183
|
-
// add dev helper for Fiori URLs
|
|
184
|
-
if (fiori.routes) require('../app/fiori/routes')
|
|
185
|
-
|
|
186
|
-
// add fiori preview links to default index.html
|
|
187
|
-
if (fiori.preview) require('../app/fiori/preview')
|
|
188
|
-
|
|
189
186
|
}
|
|
190
187
|
|
|
191
|
-
// activate plugins
|
|
192
|
-
await require("./plugins")(log)
|
|
193
188
|
TRACE?.timeEnd('cds bootstrap ')
|
|
194
189
|
|
|
195
190
|
// bootstrap server from project-local server.js or from @sap/cds/server.js
|
|
@@ -209,27 +204,28 @@ async function serve (all=[], o={}) {
|
|
|
209
204
|
_resolve (server)
|
|
210
205
|
}
|
|
211
206
|
|
|
207
|
+
const LOG = cds.log('cli|server')
|
|
212
208
|
cds.shutdown = _shutdown //> for programmatic invocation
|
|
213
|
-
process.on('unhandledRejection', (
|
|
214
|
-
process.on('uncaughtException', (e) => _shutdown (
|
|
209
|
+
process.on('unhandledRejection', (e,p) => _shutdown (e, LOG.error('❗️Uncaught',p)))
|
|
210
|
+
process.on('uncaughtException', (e) => _shutdown (e, LOG.error('❗️Uncaught',e)))
|
|
215
211
|
process.on('SIGINT', cds.watched ? _shutdown : (s,n)=>_shutdown(s,n,console.log())) //> newline after ^C
|
|
216
212
|
process.on('SIGHUP', _shutdown)
|
|
217
213
|
process.on('SIGHUP2', _shutdown)
|
|
218
214
|
process.on('SIGTERM', _shutdown)
|
|
219
215
|
|
|
220
216
|
async function _shutdown (signal,n) {
|
|
221
|
-
|
|
222
|
-
await Promise.all(cds.listeners('shutdown').map(fn => fn()))
|
|
217
|
+
let err = typeof signal === 'object' ? signal : LOG.debug('⚡️',signal,n, 'received by cds serve')
|
|
218
|
+
await Promise.all(cds.listeners('shutdown').map(fn => fn(err)))
|
|
223
219
|
server.close(()=>{/* it's ok if closed already */}) // first, we try stopping server and process the nice way
|
|
224
|
-
|
|
220
|
+
let { force_exit_timeout: force_exit } = cds.env.server // after ~1 sec, we force-exit it, unless in test mode
|
|
221
|
+
if (force_exit && !global.it) setTimeout(process.exit,force_exit).unref()
|
|
225
222
|
}
|
|
226
223
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
process.on('
|
|
232
|
-
process.on('beforeExit', ()=> DEBUG ('⚡️','cds serve - process.beforeExit'))
|
|
224
|
+
if (LOG._debug) {
|
|
225
|
+
cds.on('shutdown', () => LOG.debug ('⚡️','cds serve - cds.shutdown'))
|
|
226
|
+
server.on('close', () => LOG.debug ('⚡️','cds serve - server.close(d)'))
|
|
227
|
+
process.on('exit', () => LOG.debug ('⚡️','cds serve - process.exit'))
|
|
228
|
+
process.on('beforeExit', ()=> LOG.debug ('⚡️','cds serve - process.beforeExit'))
|
|
233
229
|
}
|
|
234
230
|
|
|
235
231
|
if (process.platform === 'win32') {
|
package/lib/auth/basic-auth.js
CHANGED
|
@@ -6,18 +6,19 @@ module.exports = function basic_auth (options) {
|
|
|
6
6
|
|
|
7
7
|
/** @type { import('express').Handler } express_handler */
|
|
8
8
|
return async function basic_auth (req, res, next) {
|
|
9
|
+
// REVISIT: passport also adds a login function with different meaning -> we need to be able to recognize ours -> req._login for now
|
|
9
10
|
// allow subsequent code to request a user login
|
|
10
|
-
req.
|
|
11
|
+
req._login = login
|
|
11
12
|
// get basic authorization header
|
|
12
13
|
let auth = req.headers.authorization
|
|
13
14
|
// enforce login if requested
|
|
14
|
-
if (!auth) return login_required ? req.
|
|
15
|
+
if (!auth || !auth.match(/^basic/i)) return login_required ? req._login('Logged in user required!') : next()
|
|
15
16
|
// decode user credentials from autorization header
|
|
16
17
|
let [id,pwd] = Buffer.from(auth.slice(6),'base64').toString().split(':')
|
|
17
18
|
// verify user credentials and set req.user
|
|
18
19
|
let u = req.user = await users.verify (id, pwd)
|
|
19
20
|
// re-request login in case of wrong credentials
|
|
20
|
-
if (u.failed) return req.
|
|
21
|
+
if (u.failed) return req._login (u)
|
|
21
22
|
// support for feature toggles via req.headers.features
|
|
22
23
|
if (req.headers.features) u = req.user = { ...u, features: req.headers.features } // NOTE: need to clone u
|
|
23
24
|
// done...
|
|
@@ -27,7 +28,8 @@ module.exports = function basic_auth (options) {
|
|
|
27
28
|
|
|
28
29
|
function login (reason='') {
|
|
29
30
|
const req=this, res=req.res
|
|
30
|
-
|
|
31
|
+
// REVISIT: this json response is needed to be OData compliant. however, we should probably throw an error anyway so that a custom error middleware can get invoked.
|
|
32
|
+
res.set('WWW-Authenticate', `Basic realm="Users"`).status(401).json({ error: { code: '401', message: 'Unauthorized' } })
|
|
31
33
|
LOG.info (req.method, decodeURIComponent(req.path), '>', res.statusCode, res.statusMessage, ...(!reason ? [] : ['-', reason]))
|
|
32
34
|
}
|
|
33
35
|
}
|
package/lib/auth/index.js
CHANGED
|
@@ -18,14 +18,15 @@ require = _require // eslint-disable-line no-global-assign
|
|
|
18
18
|
*/
|
|
19
19
|
function auth_factory (options) {
|
|
20
20
|
const o = { ...options, ...cds.requires.auth }
|
|
21
|
-
let kind = o.kind || o.strategy
|
|
21
|
+
let kind = o.impl ? 'custom' : o.kind || o.strategy
|
|
22
22
|
let middleware = cds.auth[kind]
|
|
23
23
|
if (middleware) {
|
|
24
24
|
cds.log().info ('using auth strategy:', { kind }, '\n')
|
|
25
25
|
} else {
|
|
26
|
-
let impl = o.impl
|
|
26
|
+
let impl = kind === 'custom' ? cds.resolve (o.impl)?.[0] : path.resolve (__dirname, kind)
|
|
27
27
|
try { impl = require.resolve (impl) } catch {
|
|
28
|
-
|
|
28
|
+
const e = o.impl ? `Cannot find custom impl at: ${o.impl}` : `Cannot find unknown auth kind: ${o.kind}`
|
|
29
|
+
throw cds.error(e)
|
|
29
30
|
}
|
|
30
31
|
cds.log().info ('using auth strategy:', { kind, impl: local(impl) }, '\n')
|
|
31
32
|
middleware = require(impl)
|
package/lib/auth/jwt-auth.js
CHANGED
|
@@ -10,11 +10,8 @@ module.exports = function jwt_auth(config) {
|
|
|
10
10
|
// warn if no credentials
|
|
11
11
|
if (!config.credentials) {
|
|
12
12
|
LOG._warn &&
|
|
13
|
-
LOG.warn(`
|
|
14
|
-
|
|
15
|
-
This is NOT recommended in production!
|
|
16
|
-
`)
|
|
17
|
-
|
|
13
|
+
LOG.warn(`Authentication kind "${config.kind}" configured, but no XSUAA instance bound to application.
|
|
14
|
+
This is NOT recommended in production!`)
|
|
18
15
|
return (req,res,next) => next()
|
|
19
16
|
}
|
|
20
17
|
|
|
@@ -1,41 +1,38 @@
|
|
|
1
|
-
const cds = require ('../index')
|
|
2
|
-
const cdsc = require ('./cdsc')
|
|
3
|
-
const {lazified} = require ('../lazy'); require = lazified (module) // eslint-disable-line
|
|
4
|
-
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* This is the central API facade to call compiler functions.
|
|
8
3
|
*/
|
|
9
4
|
const compile = module.exports = Object.assign (cds_compile, {
|
|
10
5
|
|
|
11
|
-
for:
|
|
12
|
-
java
|
|
13
|
-
nodejs
|
|
14
|
-
drafts
|
|
15
|
-
lean_drafts
|
|
16
|
-
odata
|
|
17
|
-
sql
|
|
18
|
-
}
|
|
6
|
+
for: new class {
|
|
7
|
+
get java(){ return super.java = require('./for/java') }
|
|
8
|
+
get nodejs() { return super.nodejs = require('./for/nodejs') }
|
|
9
|
+
get drafts() { return super.drafts = require('./for/drafts') }
|
|
10
|
+
get lean_drafts() { return super.lean_drafts = require('./for/lean_drafts') }
|
|
11
|
+
get odata() { return super.odata = require('./for/odata') }
|
|
12
|
+
get sql() { return super.sql = require('./for/sql') }
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
to: new class {
|
|
16
|
+
get csn() { return super.csn = require('./to/csn') }
|
|
17
|
+
get cdl() { return super.cdl = require('./to/cdl') }
|
|
18
|
+
get gql() { return super.gql = require('./to/gql') }
|
|
19
|
+
get yml() { return super.yml = require('./to/yaml') }
|
|
20
|
+
get yaml() { return super.yaml = require('./to/yaml') }
|
|
21
|
+
get json() { return super.json = require('./to/json') }
|
|
22
|
+
get edm() { return super.edm = require('./to/edm') }
|
|
23
|
+
get edmx() { return super.edmx = compile.to.edm.x }
|
|
24
|
+
get sql() { return super.sql = require('./to/sql') }
|
|
25
|
+
get hdbcds() { return super.hdbcds = compile.to.sql.hdbcds }
|
|
26
|
+
get hdbtable() { return super.hdbtable = compile.to.sql.hdbtable }
|
|
27
|
+
get hdbtabledata() { return super.hdbtabledata = require('./to/hdbtabledata') }
|
|
28
|
+
get serviceinfo() { return super.serviceinfo = require('./to/srvinfo') } //> REVISIT: move to CLI
|
|
29
|
+
get graphql() { return super.graphql = require('./to/gql') } //> REVISIT: move to gql CLI plugin
|
|
30
|
+
},
|
|
19
31
|
|
|
20
|
-
to: lazified ({
|
|
21
|
-
csn: cds_compile,
|
|
22
|
-
cdl: require('./to/cdl'),
|
|
23
|
-
gql: require('./to/gql'),
|
|
24
|
-
graphql: require('./to/gql'),
|
|
25
|
-
yml: require('./to/yaml'),
|
|
26
|
-
yaml: require('./to/yaml'),
|
|
27
|
-
json: require('./to/json'),
|
|
28
|
-
edm: require('./to/edm'), edmx: lazy => compile.to.edm.x,
|
|
29
|
-
sql: require('./to/sql'),
|
|
30
|
-
hdbcds: lazy => compile.to.sql.hdbcds,
|
|
31
|
-
hdbtable: lazy => compile.to.sql.hdbtable,
|
|
32
|
-
serviceinfo: require('./to/srvinfo'), //> REVISIT: move to CLI
|
|
33
|
-
}),
|
|
34
|
-
|
|
35
|
-
_localized: require('./etc/_localized'),
|
|
36
32
|
})
|
|
37
33
|
|
|
38
34
|
|
|
35
|
+
|
|
39
36
|
/**
|
|
40
37
|
* This is the central frontend function to compile sources to CSN.
|
|
41
38
|
* @param {string|string[]|{}} model one of:
|
|
@@ -49,70 +46,18 @@ const compile = module.exports = Object.assign (cds_compile, {
|
|
|
49
46
|
* @returns {{ namespace?:string, definitions:{}, extensions?:[], meta:{ flavor:_flavor }}} CSN
|
|
50
47
|
*/
|
|
51
48
|
function cds_compile (model, options, _flavor) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (files) {
|
|
58
|
-
if (o.sync) return _fluent (_finalize (cdsc.compileSync(files,cwd,o))) //> compile files synchroneously
|
|
59
|
-
else return _fluent (cdsc.compile(files,cwd,o) .then (_finalize)) //> compile files asynchroneously
|
|
60
|
-
}
|
|
61
|
-
else return _fluent (_finalize (cdsc.compileSources(model,o))) //> compile CDL sources
|
|
62
|
-
function _finalize (csn) {
|
|
63
|
-
if (o.min) csn = cds.minify(csn)
|
|
64
|
-
// REVISIT: experimental implementation to detect external APIs
|
|
65
|
-
for (let each in csn.definitions) {
|
|
66
|
-
const d = csn.definitions[each]
|
|
67
|
-
if (d.kind === 'service' && cds.requires[each]?.external && (!o.mocked || cds.requires[each].credentials)) {
|
|
68
|
-
Object.defineProperty (d,'@cds.external', { value: cds.requires[each].kind || true })
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (!csn.meta) csn.meta = {}
|
|
72
|
-
csn.meta.flavor = o.flavor
|
|
73
|
-
return csn
|
|
74
|
-
}
|
|
49
|
+
const csn = compile.to.csn (model, options, _flavor)
|
|
50
|
+
return Object.defineProperties (csn, { // fluent
|
|
51
|
+
for : {configurable:true, get:()=> new Proxy ({api:compile.for,csn},_handlers)},
|
|
52
|
+
to : {configurable:true, get:()=> new Proxy ({api:compile.to, csn},_handlers)},
|
|
53
|
+
})
|
|
75
54
|
}
|
|
76
55
|
|
|
77
|
-
|
|
78
|
-
const _is_csn = (x) => (x.definitions || x.extensions) && !x.$builtins
|
|
79
|
-
const _is_files = (m,root) => {
|
|
80
|
-
if (Array.isArray(m) || /^file:/.test(m) && (m = m.slice(5)))
|
|
81
|
-
return cds.resolve(m,{root}) || cds.error ( `Couldn't find a CDS model for '${m}' in ${root||cds.root}`,{ code:'MODEL_NOT_FOUND', model: m })
|
|
82
|
-
}
|
|
83
|
-
const _assert_flavor = (m,_flavor,options) => {
|
|
84
|
-
if (!m.meta) return true; const f = _flavor || _flavor4 (options)
|
|
85
|
-
return !f || f === m.meta.flavor || cds.error (`cds.compile(...,{flavor:'${f}'}) called on csn with different meta.flavor='${m.meta.flavor}'`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const _flavors = {
|
|
89
|
-
'parsed': { level:1, cdsc_options: { parseCdl:true } },
|
|
90
|
-
'xtended': { level:2, cdsc_options: { csnFlavor:'gensrc' } },
|
|
91
|
-
'inferred': { level:3 },
|
|
92
|
-
}
|
|
93
|
-
const _flavor4 = (o) => {
|
|
94
|
-
const f = typeof o === 'string' ? o : o && o.flavor
|
|
95
|
-
return !f || f in _flavors ? f : cds.error (`Option 'flavor' must be one of ${Object.keys(_flavors)}; got: '${f}'`)
|
|
96
|
-
}
|
|
97
|
-
const _options4 = (_o, _flavor) => {
|
|
98
|
-
const flavor = _flavor ? _flavor4(_flavor) : _flavor4(_o) || 'inferred'
|
|
99
|
-
const spec = _flavors[flavor]
|
|
100
|
-
const o = { ..._o, flavor, ...spec.cdsc_options, ...cds.env.cdsc, cdsHome: cds.home } // cdsHome is for the compiler resolving @sap/cds/... files
|
|
101
|
-
if (o.docs) o.docComment = true
|
|
102
|
-
if (o.locations) o.withLocations = true
|
|
103
|
-
if (!o.messages) o.messages = []
|
|
104
|
-
return o
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const _fluent = (x) => Object.defineProperties (x, {
|
|
108
|
-
'for' : {configurable:true, get:()=> new Proxy ({api:compile.for,x},_handlers)},
|
|
109
|
-
'to' : {configurable:true, get:()=> new Proxy ({api:compile.to, x},_handlers)},
|
|
110
|
-
})
|
|
111
56
|
const _handlers = {
|
|
112
57
|
ownKeys: ({api}) => Reflect.ownKeys (api),
|
|
113
|
-
get: ({api,
|
|
58
|
+
get: ({api,csn},p) => {
|
|
59
|
+
delete csn.for; delete csn.to //> cleanup the decorated CSN or Promise
|
|
114
60
|
let fn = api[p]; if (!fn) return
|
|
115
|
-
|
|
116
|
-
return o => 'then' in x ? x.then(m => api[p](m,o)) : api[p](x,o)
|
|
61
|
+
return o => 'then' in csn ? csn.then(m => fn(m,o)) : fn(csn,o)
|
|
117
62
|
}
|
|
118
63
|
}
|
package/lib/compile/cdsc.js
CHANGED
|
@@ -101,6 +101,17 @@ const _options = {for: Object.assign (_options4, {
|
|
|
101
101
|
|
|
102
102
|
})}
|
|
103
103
|
|
|
104
|
+
|
|
105
|
+
const { inspect } = require('util')
|
|
106
|
+
compile.CompilationError.prototype [inspect.custom] = function() {
|
|
107
|
+
// return this.stack
|
|
108
|
+
return 'Errors by cds.compile ...'+ this.messages.map (e => {
|
|
109
|
+
let {file,line,col} = e.$location
|
|
110
|
+
return `\nin ${file}:${line}:${col} — ${e.severity}: ${e.message}`
|
|
111
|
+
}).join('') + this.stack.slice(this.message.length+7)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
104
115
|
/**
|
|
105
116
|
* Return a derivate of cdsc, with the most prominent
|
|
106
117
|
* @type { import('@sap/cds-compiler') }
|
|
@@ -17,8 +17,8 @@ function read (res, ext = '.properties') {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function parse (props) {
|
|
20
|
-
const lines = props.split(
|
|
21
|
-
const rows = lines.filter(each => !!each.trim()).map(each => {
|
|
20
|
+
const lines = props.split(/(?<![\\\r])\r?\n/)
|
|
21
|
+
const rows = lines.filter(each => !!each.trim()).map(each => each.replace(/\\\r?\n/, '')).map(each => {
|
|
22
22
|
const index = each.indexOf('=')
|
|
23
23
|
if (index < 0) return [each, '']
|
|
24
24
|
return [each.slice(0, index).trim(), each.slice(index + 1).trim()]
|
|
@@ -19,58 +19,10 @@ function _isCompositionBacklink(e) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const IGNORED_ENTITY_ANNOTATIONS = new Set([
|
|
23
|
-
'@readonly',
|
|
24
|
-
'@insertonly',
|
|
25
|
-
'@restrict',
|
|
26
|
-
])
|
|
27
|
-
|
|
28
|
-
const IGNORED_ELEMENT_ANNOTATIONS = [
|
|
29
|
-
'@assert.range',
|
|
30
|
-
'@assert.enum',
|
|
31
|
-
'@assert.format',
|
|
32
|
-
'@assert.target',
|
|
33
|
-
'@mandatory',
|
|
34
|
-
'@Core.Immutable',
|
|
35
|
-
'@readonly',
|
|
36
|
-
'@Core.Computed',
|
|
37
|
-
'@Common.FieldControl.Readonly',
|
|
38
|
-
'@Common.FieldControl.Mandatory',
|
|
39
|
-
'@FieldControl.Mandatory',
|
|
40
|
-
'@FieldControl.ReadOnly',
|
|
41
|
-
'@Common.FieldControl',
|
|
42
|
-
'@PersonalData.DataSubjectRole',
|
|
43
|
-
'@PersonalData.EntitySemantics',
|
|
44
|
-
'@PersonalData.IsPotentiallyPersonal',
|
|
45
|
-
'@PersonalData.IsPotentiallySensitive',
|
|
46
|
-
'@PersonalData.FieldSemantics'
|
|
47
|
-
// These are still needed:
|
|
48
|
-
// '@odata.etag',
|
|
49
|
-
// '@cds.on.update',
|
|
50
|
-
// '@cds.on.insert',
|
|
51
|
-
]
|
|
52
|
-
|
|
53
22
|
module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
54
|
-
|
|
55
|
-
'IsActiveEntity',
|
|
56
|
-
'HasDraftEntity',
|
|
57
|
-
'HasActiveEntity',
|
|
58
|
-
'DraftAdministrativeData',
|
|
59
|
-
'DraftAdministrativeData_DraftUUID',
|
|
60
|
-
'SiblingEntity'
|
|
61
|
-
])
|
|
62
|
-
function _redirect(assoc, target, keys) {
|
|
23
|
+
function _redirect(assoc, target) {
|
|
63
24
|
assoc.target = target.name
|
|
64
25
|
assoc._target = target
|
|
65
|
-
if (keys) assoc.on = _onCondition(assoc.name, keys)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function _onCondition(left, keys, right) {
|
|
69
|
-
const on = []
|
|
70
|
-
for (let k in keys)
|
|
71
|
-
DRAFT_ELEMENTS.has(k) || on.push({ ref: [left, k] }, '=', { ref: right ? [right, k] : [k] }, 'and')
|
|
72
|
-
on.pop()
|
|
73
|
-
return on
|
|
74
26
|
}
|
|
75
27
|
|
|
76
28
|
function _isDraft(def) {
|
|
@@ -99,33 +51,52 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
|
99
51
|
DraftIsProcessedByMe : Boolean; // REVISIT: these are calculated fields, aren't they?
|
|
100
52
|
}
|
|
101
53
|
`).definitions
|
|
102
|
-
function
|
|
54
|
+
function addDraftEntity(active, model) {
|
|
103
55
|
const _draftEntity = active.name + '.drafts'
|
|
104
56
|
const d = model.definitions[_draftEntity]
|
|
105
57
|
if (d) return d
|
|
106
58
|
// We need to construct a fake draft entity definition
|
|
107
|
-
|
|
59
|
+
// We cannot use new cds.entity because runtime aspects would be missing
|
|
60
|
+
const draft = {
|
|
61
|
+
__proto__: active,
|
|
62
|
+
name: _draftEntity,
|
|
63
|
+
elements: { ...active.elements, ...Draft.elements },
|
|
64
|
+
query: undefined
|
|
65
|
+
}
|
|
108
66
|
Object.defineProperty(model.definitions, _draftEntity, { value: draft })
|
|
109
67
|
Object.defineProperty(active, 'drafts', { value: draft })
|
|
110
68
|
Object.defineProperty(draft, 'actives', { value: active })
|
|
111
69
|
Object.defineProperty(draft, 'isDraft', { value: true })
|
|
112
|
-
draft['@cds.persistence.table'] = _draftEntity
|
|
113
70
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
71
|
+
// Positive list would be bigger (search, requires, fiori, ...)
|
|
72
|
+
if (draft['@readonly']) draft['@readonly'] = undefined
|
|
73
|
+
if (draft['@insertonly']) draft['@insertonly'] = undefined
|
|
74
|
+
if (draft['@restrict']) draft['@restrict'] = undefined
|
|
75
|
+
|
|
117
76
|
// Recursively add drafts for compositions
|
|
118
77
|
for (const each in draft.elements) {
|
|
119
78
|
const e = draft.elements[each]
|
|
120
79
|
const newEl = Object.create(e)
|
|
121
|
-
if (e.isComposition || (e.isAssociation && e['@odata.draft.enclosed']) || _isCompositionBacklink(e)) {
|
|
80
|
+
if (e.isComposition || (e.isAssociation && e['@odata.draft.enclosed']) || ((!active['@Common.DraftRoot.ActivationAction'] || e._target === active) && _isCompositionBacklink(e))) {
|
|
122
81
|
if (e._target['@odata.draft.enabled'] === false) continue // happens for texts if @fiori.draft.enabled is not set
|
|
123
|
-
_redirect(newEl,
|
|
82
|
+
_redirect(newEl, addDraftEntity(e._target, model))
|
|
124
83
|
}
|
|
125
84
|
newEl.parent = draft
|
|
126
|
-
|
|
127
|
-
|
|
85
|
+
|
|
86
|
+
for (const key in newEl) {
|
|
87
|
+
if (
|
|
88
|
+
key.startsWith('@assert') ||
|
|
89
|
+
key.startsWith('@FieldControl') ||
|
|
90
|
+
key.startsWith('@Common.FieldControl') ||
|
|
91
|
+
key.startsWith('@PersonalData') ||
|
|
92
|
+
key === '@mandatory' ||
|
|
93
|
+
key === '@readonly' ||
|
|
94
|
+
key === '@Core.Computed' ||
|
|
95
|
+
key === '@Core.Immutable'
|
|
96
|
+
)
|
|
97
|
+
newEl[key] = undefined
|
|
128
98
|
}
|
|
99
|
+
|
|
129
100
|
draft.elements[each] = newEl
|
|
130
101
|
}
|
|
131
102
|
return draft
|
|
@@ -133,16 +104,12 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
|
133
104
|
for (const name in csn.definitions) {
|
|
134
105
|
const def = csn.definitions[name]
|
|
135
106
|
if (!_isDraft(def)) continue
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
'DraftAdministrativeData'
|
|
142
|
-
].forEach(s => {
|
|
143
|
-
def.elements[s].virtual = true
|
|
144
|
-
})
|
|
107
|
+
def.elements.IsActiveEntity.virtual = true
|
|
108
|
+
def.elements.HasDraftEntity.virtual = true
|
|
109
|
+
def.elements.HasActiveEntity.virtual = true
|
|
110
|
+
def.elements.DraftAdministrativeData_DraftUUID.virtual = true
|
|
111
|
+
def.elements.DraftAdministrativeData.virtual = true
|
|
145
112
|
// will insert drafts entities, so that others can use `.drafts` even without incoming draft requests
|
|
146
|
-
|
|
113
|
+
addDraftEntity(def, csn)
|
|
147
114
|
}
|
|
148
115
|
}
|