@sap/cds-compiler 4.6.2 → 4.7.6
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 +47 -0
- package/bin/cds_update_identifiers.js +6 -2
- package/bin/cdsc.js +1 -1
- package/doc/CHANGELOG_ARCHIVE.md +9 -9
- package/doc/CHANGELOG_BETA.md +6 -0
- package/lib/api/main.js +56 -9
- package/lib/api/options.js +6 -3
- package/lib/api/validate.js +20 -29
- package/lib/base/message-registry.js +27 -3
- package/lib/base/messages.js +8 -3
- package/lib/base/model.js +2 -0
- package/lib/checks/dbFeatureFlags.js +28 -0
- package/lib/checks/elements.js +81 -13
- package/lib/checks/enricher.js +3 -2
- package/lib/checks/validator.js +38 -4
- package/lib/compiler/assert-consistency.js +4 -4
- package/lib/compiler/checks.js +5 -4
- package/lib/compiler/define.js +2 -2
- package/lib/compiler/generate.js +2 -1
- package/lib/compiler/propagator.js +3 -11
- package/lib/compiler/shared.js +2 -1
- package/lib/compiler/tweak-assocs.js +43 -24
- package/lib/edm/annotations/edmJson.js +3 -0
- package/lib/edm/annotations/genericTranslation.js +156 -106
- package/lib/edm/annotations/preprocessAnnotations.js +11 -14
- package/lib/edm/csn2edm.js +27 -24
- package/lib/edm/edm.js +8 -8
- package/lib/edm/edmPreprocessor.js +135 -37
- package/lib/edm/edmUtils.js +20 -7
- package/lib/gen/Dictionary.json +1 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +9 -11
- package/lib/gen/languageParser.js +5942 -5446
- package/lib/json/to-csn.js +7 -114
- package/lib/language/genericAntlrParser.js +106 -48
- package/lib/model/cloneCsn.js +203 -0
- package/lib/model/csnRefs.js +11 -3
- package/lib/model/csnUtils.js +42 -85
- package/lib/optionProcessor.js +2 -2
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +133 -88
- package/lib/render/toHdbcds.js +1 -5
- package/lib/render/toSql.js +7 -9
- package/lib/render/utils/common.js +9 -16
- package/lib/transform/addTenantFields.js +277 -102
- package/lib/transform/db/applyTransformations.js +14 -9
- package/lib/transform/db/backlinks.js +2 -1
- package/lib/transform/db/constraints.js +60 -82
- package/lib/transform/db/expansion.js +6 -6
- package/lib/transform/db/featureFlags.js +5 -0
- package/lib/transform/db/flattening.js +4 -4
- package/lib/transform/db/killAnnotations.js +1 -0
- package/lib/transform/db/rewriteCalculatedElements.js +2 -2
- package/lib/transform/db/transformExists.js +12 -0
- package/lib/transform/db/views.js +5 -2
- package/lib/transform/draft/odata.js +20 -20
- package/lib/transform/effective/associations.js +2 -1
- package/lib/transform/effective/main.js +3 -2
- package/lib/transform/effective/types.js +6 -3
- package/lib/transform/forOdata.js +39 -24
- package/lib/transform/forRelationalDB.js +34 -27
- package/lib/transform/localized.js +29 -9
- package/lib/transform/odata/flattening.js +419 -0
- package/lib/transform/odata/toFinalBaseType.js +95 -15
- package/lib/transform/odata/typesExposure.js +9 -7
- package/lib/transform/transformUtils.js +7 -6
- package/lib/transform/translateAssocsToJoins.js +3 -3
- package/lib/utils/objectUtils.js +14 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,52 @@ Note: `beta` fixes, changes and features are usually not listed in this ChangeLo
|
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
## Version 4.7.6 - 2024-02-29
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- OData: Restored compatibility with the Java runtime.
|
|
16
|
+
Drafts generation was applied twice.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Version 4.7.4 - 2024-02-27
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- OData: Fixed infinite recursion in draft handling for nested recursive compositions.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Version 4.7.2 - 2024-02-26
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Restored compatibility with `@sap/cds-dk` for Java runtime
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Version 4.7.0 - 2024-02-23
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- compiler: Virtual elements can now be referenced in expressions in annotation
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Update OData vocabularies: 'Authorization', 'Common', 'Hierarchy', 'UI'.
|
|
42
|
+
- to.edm(x): `@cds.odata.valuelist` renders all non-key elements of the value help list as `ValueListProperty`.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- CDL parser: a `select` after two or more `(`s in an expression or condition
|
|
47
|
+
could cause some constructs in that query, such as `virtual`, to be not properly parsed.
|
|
48
|
+
- compiler: published associations with filters sometimes had the filter applied twice
|
|
49
|
+
if used in inline aspect compositions
|
|
50
|
+
- to.sql|hdi|hdbcds[.migration]:
|
|
51
|
+
+ With `withHanaAssociations`: `false`, remove the association elements from the final CSN in order to correctly detect them during migration scenarios and
|
|
52
|
+
with generated `hdbcds`.
|
|
53
|
+
+ Skip expensive processing (for calculated elements and nested projections) if the model doesn't use it.
|
|
54
|
+
+ Don't greedily set alias on subqueries if not required.
|
|
55
|
+
+ Remove bound actions and turn all non-database relevant artifacts into dummies to simplify and shrink CSN.
|
|
56
|
+
|
|
11
57
|
## Version 4.6.2 - 2024-02-02
|
|
12
58
|
|
|
13
59
|
### Fixed
|
|
@@ -15,6 +61,7 @@ The compiler behavior concerning `beta` features can change at any time without
|
|
|
15
61
|
- compiler: Fix incorrect error about type properties if deprecated flag `ignoreSpecifiedQueryElements` is set.
|
|
16
62
|
- Update OData vocabularies: 'Authorization', 'Common'.
|
|
17
63
|
|
|
64
|
+
|
|
18
65
|
## Version 4.6.0 - 2024-01-26
|
|
19
66
|
|
|
20
67
|
### Added
|
|
@@ -32,6 +32,9 @@ const path = require('path');
|
|
|
32
32
|
const cliArgs = process.argv.slice(2);
|
|
33
33
|
const filepath = cliArgs[0];
|
|
34
34
|
|
|
35
|
+
if (filepath === '--help' || filepath === '-h')
|
|
36
|
+
exitError();
|
|
37
|
+
|
|
35
38
|
if (cliArgs.length !== 1)
|
|
36
39
|
exitError(`Expected exactly one argument, ${cliArgs.length} given`);
|
|
37
40
|
|
|
@@ -123,10 +126,11 @@ function replaceSliceInSource( source, startIndex, endIndex, replaceWith ) {
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
/**
|
|
126
|
-
* @param {string} msg
|
|
129
|
+
* @param {string} [msg]
|
|
127
130
|
*/
|
|
128
131
|
function exitError( msg ) {
|
|
129
|
-
|
|
132
|
+
if (msg)
|
|
133
|
+
console.error(msg);
|
|
130
134
|
usage();
|
|
131
135
|
process.exit(1);
|
|
132
136
|
}
|
package/bin/cdsc.js
CHANGED
|
@@ -559,7 +559,7 @@ function executeCommandLine( command, options, args ) {
|
|
|
559
559
|
}
|
|
560
560
|
else if (!options.parseOnly) { // no output if parseOnly but not rawOutput
|
|
561
561
|
const csn = compactModel(xsn, options);
|
|
562
|
-
if (command === 'toCsn' && options.
|
|
562
|
+
if (command === 'toCsn' && options.tenantDiscriminator)
|
|
563
563
|
addTenantFields(csn, options);
|
|
564
564
|
if (command === 'toCsn' && options.withLocalized)
|
|
565
565
|
addLocalizationViews(csn, options);
|
package/doc/CHANGELOG_ARCHIVE.md
CHANGED
|
@@ -104,7 +104,7 @@ The compiler behaviour concerning `beta` features can change at any time without
|
|
|
104
104
|
### Added
|
|
105
105
|
|
|
106
106
|
- Support arbitrary paths after `$user` - similar to `$session`.
|
|
107
|
-
- Support scale `floating` and `variable` for `cds.Decimal` in CDL and CSN. Backend specific handling is
|
|
107
|
+
- Support scale `floating` and `variable` for `cds.Decimal` in CDL and CSN. Backend specific handling is described in their sections.
|
|
108
108
|
- Allow select item wildcard (`*`) in a `select`/`projection` at any position, not just the first.
|
|
109
109
|
|
|
110
110
|
- to.edm(x):
|
|
@@ -585,7 +585,7 @@ synchronously.
|
|
|
585
585
|
+ Localized convenience views are no longer generated by the core compiler but added by the `for.odata`
|
|
586
586
|
and `to.sql/hdi/hdbcds` processing on demand.
|
|
587
587
|
+ Minimize name clashes when calculating names for auto-exposed entities,
|
|
588
|
-
extends the v1 option `dependentAutoexposed` to sub artifacts of
|
|
588
|
+
extends the v1 option `dependentAutoexposed` to sub artifacts of entities (see “Added”).
|
|
589
589
|
+ Ambiguities when redirecting associations now always lead to compile errors;
|
|
590
590
|
you might want to use the new annotation `@cds.redirection.target` to solve them.
|
|
591
591
|
+ The association `up_` in the calculated entity for managed compositions is now managed.
|
|
@@ -1046,7 +1046,7 @@ synchronously.
|
|
|
1046
1046
|
|
|
1047
1047
|
- OData: Allow the relational comparison of structures or managed associations in an ON condition as described in
|
|
1048
1048
|
version 1.32.0 - 2020-07-10 (forHana).
|
|
1049
|
-
- Allow `Struct:elem` with and without
|
|
1049
|
+
- Allow `Struct:elem` with and without preceding `type of` as type reference.
|
|
1050
1050
|
|
|
1051
1051
|
### Fixed
|
|
1052
1052
|
|
|
@@ -2426,7 +2426,7 @@ Fixes
|
|
|
2426
2426
|
|
|
2427
2427
|
Features
|
|
2428
2428
|
* Allow entities to have parameters. They can be referred to inside the query with
|
|
2429
|
-
`:Param`.
|
|
2429
|
+
`:Param`. Entities with parameters are not allowed in `toSql` for dialect "sqlite".
|
|
2430
2430
|
When generating for HANA, parameters cannot be used in combination with associations:
|
|
2431
2431
|
an entity with parameters cannot have associations, and an association must not point
|
|
2432
2432
|
to an entity with parameters.
|
|
@@ -2446,7 +2446,7 @@ Changes
|
|
|
2446
2446
|
_The severity of these messages will be increased if implicit redirections
|
|
2447
2447
|
will have been performed by the core compiler._
|
|
2448
2448
|
* `toHana` and `toSql` now reject entities that only contain unmanaged associations.
|
|
2449
|
-
Such
|
|
2449
|
+
Such entities would lead to a deployment error later.
|
|
2450
2450
|
* SQL name mapping modes `quoted` and `hdbcds` are only allowed when generating for HANA.
|
|
2451
2451
|
* In the csn, the csn language version is now stored in the top level attribute `$version`.
|
|
2452
2452
|
The version information via `version.csn` is deprecated and will be removed in a future
|
|
@@ -2685,7 +2685,7 @@ Fixes
|
|
|
2685
2685
|
## Version 1.0.33
|
|
2686
2686
|
|
|
2687
2687
|
Features
|
|
2688
|
-
* Allow to extend query
|
|
2688
|
+
* Allow to extend query entities with actions.
|
|
2689
2689
|
* Allow `select distinct`.
|
|
2690
2690
|
* With `--tnt-flavor` only: allow to specify (a restricted version of) service include via syntax.
|
|
2691
2691
|
* (Work in progress): New option `{ dialect: 'hana'|'sqlite' }` for `toSql()`, allowing generation
|
|
@@ -2874,7 +2874,7 @@ Fixes
|
|
|
2874
2874
|
recognized and led to the generation of incorrect HANA CDS models.
|
|
2875
2875
|
* We now also allow query entities and their elements to use as type, relaxing
|
|
2876
2876
|
a check introduces with v1.0.26.
|
|
2877
|
-
It needs to be seen whether we allow
|
|
2877
|
+
It needs to be seen whether we allow entities as type only for actions.
|
|
2878
2878
|
|
|
2879
2879
|
## Version 1.0.27
|
|
2880
2880
|
|
|
@@ -2972,7 +2972,7 @@ Fixes
|
|
|
2972
2972
|
|
|
2973
2973
|
Changes
|
|
2974
2974
|
* The CSN element property `notNull` is not inherited anymore
|
|
2975
|
-
if the `select`/`projection` items whose path
|
|
2975
|
+
if the `select`/`projection` items whose path referring the source element
|
|
2976
2976
|
navigates along associations or compositions.
|
|
2977
2977
|
* Annotation assignments which are placed after the name of `context` or `service` definitions
|
|
2978
2978
|
must now use the `@(...)` syntax variant if a value is supplied,
|
|
@@ -3197,7 +3197,7 @@ Features
|
|
|
3197
3197
|
|
|
3198
3198
|
Fixes
|
|
3199
3199
|
* Views are now rendered as EntitySet/EntityType in edmx
|
|
3200
|
-
* Abstract
|
|
3200
|
+
* Abstract entities do not appear as EntitySet/EntityType in the generated edmx
|
|
3201
3201
|
* `--to-hana` now correctly handles type casts in view definitions
|
|
3202
3202
|
* In the generated edmx for OData V2, inside a `ReferentialConstraint`, the elements `Dependent` and `Principal` now have the correct order
|
|
3203
3203
|
* Remove attribute `nullable` for function import parameters in edmx generation for OData V2
|
package/doc/CHANGELOG_BETA.md
CHANGED
|
@@ -8,6 +8,12 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
|
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
**Don't use `beta` fixes, changes and features in productive mode.**
|
|
10
10
|
|
|
11
|
+
## Version 4.x.x - 2024-mm-dd
|
|
12
|
+
|
|
13
|
+
### Added `v5preview`
|
|
14
|
+
|
|
15
|
+
Sneak preview into incompatible changes that are about to be shipped with compiler version 5.
|
|
16
|
+
|
|
11
17
|
## Version 4.6.0 - 2024-01-26
|
|
12
18
|
|
|
13
19
|
### Added `vectorType`
|
package/lib/api/main.js
CHANGED
|
@@ -23,10 +23,11 @@ const toHdbcds = lazyload('../render/toHdbcds');
|
|
|
23
23
|
const baseError = lazyload('../base/error');
|
|
24
24
|
const csnToEdm = lazyload('../edm/csn2edm');
|
|
25
25
|
const trace = lazyload('./trace');
|
|
26
|
+
const cloneCsn = lazyload('../model/cloneCsn');
|
|
26
27
|
|
|
27
28
|
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
28
|
-
const { checkRemovedDeprecatedFlags } = require('../base/model');
|
|
29
29
|
const { makeMessageFunction } = require('../base/messages');
|
|
30
|
+
const { sortCsnForTests } = require('../model/cloneCsn');
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -138,7 +139,8 @@ function isPreTransformed( csn, transformation ) {
|
|
|
138
139
|
*/
|
|
139
140
|
function odataInternal( csn, internalOptions, messageFunctions ) {
|
|
140
141
|
internalOptions.transformation = 'odata';
|
|
141
|
-
|
|
142
|
+
let oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions, messageFunctions);
|
|
143
|
+
oDataCsn = sortCsnForTests(oDataCsn, internalOptions);
|
|
142
144
|
messageFunctions.setModel(oDataCsn);
|
|
143
145
|
attachTransformerCharacteristics(oDataCsn, 'odata', internalOptions, relevantOdataOptions, warnAboutMismatchOdata);
|
|
144
146
|
return oDataCsn;
|
|
@@ -187,7 +189,7 @@ function csnForSql( csn, internalOptions, messageFunctions ) {
|
|
|
187
189
|
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
188
190
|
csn, internalOptions, messageFunctions
|
|
189
191
|
);
|
|
190
|
-
return
|
|
192
|
+
return cloneCsn.sortCsnForTests(transformedCsn, internalOptions);
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
/**
|
|
@@ -202,7 +204,7 @@ function csnForSql( csn, internalOptions, messageFunctions ) {
|
|
|
202
204
|
*/
|
|
203
205
|
function forSql( csn, options, messageFunctions ) {
|
|
204
206
|
const internalOptions = prepareOptions.to.sql(options);
|
|
205
|
-
return csnForSql(csn, internalOptions, messageFunctions);
|
|
207
|
+
return csnForSql(csn, internalOptions, messageFunctions); // already sorted for test mode
|
|
206
208
|
}
|
|
207
209
|
|
|
208
210
|
/**
|
|
@@ -220,7 +222,7 @@ function forHdi( csn, options, messageFunctions ) {
|
|
|
220
222
|
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
221
223
|
csn, internalOptions, messageFunctions
|
|
222
224
|
);
|
|
223
|
-
return
|
|
225
|
+
return cloneCsn.sortCsnForTests(transformedCsn, internalOptions);
|
|
224
226
|
}
|
|
225
227
|
/**
|
|
226
228
|
* Transform a CSN like to.hdbcds
|
|
@@ -237,7 +239,7 @@ function forHdbcds( csn, options, messageFunctions ) {
|
|
|
237
239
|
const hanaCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
238
240
|
csn, internalOptions, messageFunctions
|
|
239
241
|
);
|
|
240
|
-
return
|
|
242
|
+
return cloneCsn.sortCsnForTests(hanaCsn, internalOptions);
|
|
241
243
|
}
|
|
242
244
|
|
|
243
245
|
/**
|
|
@@ -252,9 +254,17 @@ function forHdbcds( csn, options, messageFunctions ) {
|
|
|
252
254
|
function forEffective( csn, options, messageFunctions ) {
|
|
253
255
|
const internalOptions = prepareOptions.to.sql(options);
|
|
254
256
|
internalOptions.transformation = 'effective';
|
|
257
|
+
if (options.tenantDiscriminator) {
|
|
258
|
+
messageFunctions.error('api-invalid-option', null, {
|
|
259
|
+
'#': 'forbidden',
|
|
260
|
+
option: 'tenantDiscriminator',
|
|
261
|
+
module: 'for.effective',
|
|
262
|
+
});
|
|
263
|
+
messageFunctions.throwWithAnyError();
|
|
264
|
+
}
|
|
255
265
|
|
|
256
266
|
const eCsn = effective.effectiveCsn(csn, internalOptions, messageFunctions);
|
|
257
|
-
return
|
|
267
|
+
return cloneCsn.sortCsnForTests(eCsn, internalOptions);
|
|
258
268
|
}
|
|
259
269
|
|
|
260
270
|
/**
|
|
@@ -270,6 +280,8 @@ function sql( csn, options, messageFunctions ) {
|
|
|
270
280
|
const internalOptions = prepareOptions.to.sql(options);
|
|
271
281
|
internalOptions.transformation = 'sql';
|
|
272
282
|
|
|
283
|
+
handleTenantDiscriminator(options, internalOptions, messageFunctions);
|
|
284
|
+
|
|
273
285
|
// we need the CSN for view sorting
|
|
274
286
|
const transformedCsn = csnForSql(csn, internalOptions, messageFunctions);
|
|
275
287
|
messageFunctions.setModel(transformedCsn);
|
|
@@ -294,6 +306,8 @@ function hdi( csn, options, messageFunctions ) {
|
|
|
294
306
|
trace.traceApi('to.hdi', options);
|
|
295
307
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
296
308
|
|
|
309
|
+
handleTenantDiscriminator(options, internalOptions, messageFunctions);
|
|
310
|
+
|
|
297
311
|
// we need the CSN for view sorting
|
|
298
312
|
const sqlCSN = forHdi(csn, options, messageFunctions);
|
|
299
313
|
messageFunctions.setModel(sqlCSN);
|
|
@@ -398,6 +412,7 @@ function remapName( key, csn, filter = () => true ) {
|
|
|
398
412
|
function sqlMigration( csn, options, messageFunctions, beforeImage ) {
|
|
399
413
|
trace.traceApi('to.sql.migration', options);
|
|
400
414
|
const internalOptions = prepareOptions.to.sql(options);
|
|
415
|
+
handleTenantDiscriminator(options, internalOptions, messageFunctions);
|
|
401
416
|
const { error, throwWithError } = messageFunctions;
|
|
402
417
|
|
|
403
418
|
// Prepare after-image.
|
|
@@ -550,6 +565,7 @@ function sqlMigration( csn, options, messageFunctions, beforeImage ) {
|
|
|
550
565
|
function hdiMigration( csn, options, messageFunctions, beforeImage ) {
|
|
551
566
|
trace.traceApi('to.hdi.migration', options);
|
|
552
567
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
568
|
+
handleTenantDiscriminator(options, internalOptions, messageFunctions);
|
|
553
569
|
|
|
554
570
|
// Prepare after-image.
|
|
555
571
|
const afterImage = forHdi(csn, options, messageFunctions);
|
|
@@ -639,6 +655,15 @@ function hdbcds( csn, options, messageFunctions ) {
|
|
|
639
655
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
640
656
|
internalOptions.transformation = 'hdbcds';
|
|
641
657
|
|
|
658
|
+
if (options.tenantDiscriminator) {
|
|
659
|
+
messageFunctions.error('api-invalid-option', null, {
|
|
660
|
+
'#': 'forbidden',
|
|
661
|
+
option: 'tenantDiscriminator',
|
|
662
|
+
module: 'to.hdbcds',
|
|
663
|
+
});
|
|
664
|
+
messageFunctions.throwWithAnyError();
|
|
665
|
+
}
|
|
666
|
+
|
|
642
667
|
const hanaCsn = forHdbcds(csn, internalOptions, messageFunctions);
|
|
643
668
|
messageFunctions.setModel(hanaCsn);
|
|
644
669
|
const result = toHdbcds.toHdbcdsSource(hanaCsn, internalOptions, messageFunctions);
|
|
@@ -838,7 +863,6 @@ odata2.all = odataall;
|
|
|
838
863
|
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
839
864
|
* @returns {object} { <protocol>: { <serviceName>: { edmx: <XML representation>, edm: <JSON representation> } } }
|
|
840
865
|
*/
|
|
841
|
-
// @ts-ignore
|
|
842
866
|
function odataall( csn, options = {}, messageFunctions ) {
|
|
843
867
|
trace.traceApi('to.odata.all', options);
|
|
844
868
|
const internalOptions = prepareOptions.to.odata(options);
|
|
@@ -1028,7 +1052,7 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
1028
1052
|
try {
|
|
1029
1053
|
const messageFunctions = messages.makeMessageFunction(csn, options, _name);
|
|
1030
1054
|
if (options.deprecated)
|
|
1031
|
-
checkRemovedDeprecatedFlags( options, messageFunctions );
|
|
1055
|
+
baseModel.checkRemovedDeprecatedFlags( options, messageFunctions );
|
|
1032
1056
|
|
|
1033
1057
|
checkOutdatedOptions( options, messageFunctions );
|
|
1034
1058
|
csn = ensureClientCsn( csn, options, messageFunctions, _name );
|
|
@@ -1195,6 +1219,29 @@ function lazyload( moduleName ) {
|
|
|
1195
1219
|
});
|
|
1196
1220
|
}
|
|
1197
1221
|
|
|
1222
|
+
/**
|
|
1223
|
+
* Error when tenantDiscriminator and withHanaAssociations is set by the user.
|
|
1224
|
+
*
|
|
1225
|
+
* Set withHanaAssociations to false when tenantDiscriminator is used.
|
|
1226
|
+
*
|
|
1227
|
+
* @param {object} options Options set by the user
|
|
1228
|
+
* @param {object} internalOptions Options clone after we processed it
|
|
1229
|
+
* @param {object} messageFunctions Message functions
|
|
1230
|
+
*/
|
|
1231
|
+
function handleTenantDiscriminator( options, internalOptions, messageFunctions ) {
|
|
1232
|
+
if (options.tenantDiscriminator && options.withHanaAssociations) {
|
|
1233
|
+
messageFunctions.error('api-invalid-combination', null, {
|
|
1234
|
+
option: 'tenantDiscriminator',
|
|
1235
|
+
prop: 'withHanaAssociations',
|
|
1236
|
+
});
|
|
1237
|
+
|
|
1238
|
+
messageFunctions.throwWithAnyError();
|
|
1239
|
+
}
|
|
1240
|
+
else if (internalOptions.tenantDiscriminator) {
|
|
1241
|
+
internalOptions.withHanaAssociations = false;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1198
1245
|
|
|
1199
1246
|
/**
|
|
1200
1247
|
* Option format used by the old API, where they are grouped thematically.
|
package/lib/api/options.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { validate, generateStringValidator } = require('./validate');
|
|
4
|
+
const { makeMessageFunction } = require('../base/messages');
|
|
4
5
|
|
|
5
6
|
// TODO: there should be just one place where the options are defined with
|
|
6
7
|
// their types (not also in validate.js or whatever).
|
|
@@ -67,7 +68,7 @@ const privateOptions = [
|
|
|
67
68
|
'noRecompile',
|
|
68
69
|
'internalMsg',
|
|
69
70
|
'disableHanaComments', // in case of issues with hana comment rendering
|
|
70
|
-
'
|
|
71
|
+
'tenantDiscriminator', // not published yet
|
|
71
72
|
'localizedWithoutCoalesce', // deprecated version of 'localizedLanguageFallback', TODO(v5): Remove option
|
|
72
73
|
];
|
|
73
74
|
|
|
@@ -104,14 +105,16 @@ function translateOptions( input = {}, defaults = {}, hardRequire = {},
|
|
|
104
105
|
|
|
105
106
|
// Validate the filtered input options
|
|
106
107
|
// only "new-style" options are here
|
|
108
|
+
const messageFunctions = makeMessageFunction(null, options, moduleName);
|
|
107
109
|
validate(options,
|
|
108
|
-
|
|
110
|
+
messageFunctions,
|
|
109
111
|
// TODO: is there a better place to specify the type of option values?
|
|
110
112
|
Object.assign( {
|
|
111
113
|
localizedLanguageFallback: generateStringValidator([ 'none', 'coalesce' ]),
|
|
112
114
|
sqlChangeMode: generateStringValidator([ 'alter', 'drop' ]),
|
|
113
115
|
}, customValidators ),
|
|
114
|
-
combinationValidators
|
|
116
|
+
combinationValidators,
|
|
117
|
+
moduleName);
|
|
115
118
|
|
|
116
119
|
// Overwrite with the hardRequire options - like src: sql in to.sql()
|
|
117
120
|
Object.assign(options, hardRequire);
|
package/lib/api/validate.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { makeMessageFunction } = require('../base/messages');
|
|
4
3
|
const { forEach } = require('../utils/objectUtils');
|
|
5
4
|
|
|
6
5
|
/* eslint-disable arrow-body-style */
|
|
@@ -128,6 +127,7 @@ const validators = {
|
|
|
128
127
|
found: val => (typeof val === 'string' ? val : `type ${ typeof val }`),
|
|
129
128
|
},
|
|
130
129
|
assertIntegrityType: generateStringValidator([ 'DB', 'RT' ]),
|
|
130
|
+
tenantDiscriminator: { validate: () => true }, // do it ourselves
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
// Note: if `validate()` returns true, it means the option is _invalid_!
|
|
@@ -152,47 +152,38 @@ const allCombinationValidators = {
|
|
|
152
152
|
|
|
153
153
|
const alwaysRunValidators = [ 'beta-no-test', 'sql-dialect-and-localized' ];
|
|
154
154
|
|
|
155
|
-
/* eslint-disable jsdoc/no-undefined-types */
|
|
156
155
|
/**
|
|
157
156
|
* Run the validations for each option.
|
|
158
157
|
* Use a custom validator or "default" custom validator, fallback to Boolean validator.
|
|
159
158
|
*
|
|
160
159
|
* @param {object} options Flat options object to validate
|
|
161
|
-
* @param {
|
|
160
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
162
161
|
* @param {object} [customValidators] Map of custom validators to use
|
|
163
162
|
* @param {string[]} [combinationValidators] Validate option combinations
|
|
164
163
|
* @returns {void}
|
|
165
164
|
* @throws {CompilationError} Throws in case of invalid option usage
|
|
166
165
|
*/
|
|
167
|
-
function validate( options,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
throwWithAnyError();
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const message = makeMessageFunction(null, options, moduleName);
|
|
166
|
+
function validate( options, messageFunctions, customValidators = {}, combinationValidators = [] ) {
|
|
167
|
+
const { error, throwWithError } = messageFunctions;
|
|
168
|
+
|
|
169
|
+
forEach(options, (optionName, optionValue) => {
|
|
170
|
+
const validator = customValidators[optionName] || validators[optionName] || booleanValidator;
|
|
171
|
+
|
|
172
|
+
if (!validator.validate(optionValue)) {
|
|
173
|
+
error('api-invalid-option', null, {
|
|
174
|
+
'#': 'value',
|
|
175
|
+
prop: optionName,
|
|
176
|
+
value: validator.expected(optionValue),
|
|
177
|
+
othervalue: validator.found(optionValue),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
throwWithError();
|
|
189
182
|
|
|
190
183
|
for (const combinationValidatorName of combinationValidators.concat(alwaysRunValidators))
|
|
191
|
-
allCombinationValidators[combinationValidatorName](options,
|
|
192
|
-
|
|
193
|
-
message.throwWithAnyError();
|
|
184
|
+
allCombinationValidators[combinationValidatorName](options, messageFunctions);
|
|
185
|
+
throwWithError();
|
|
194
186
|
}
|
|
195
|
-
/* eslint-enable jsdoc/no-undefined-types */
|
|
196
187
|
|
|
197
188
|
|
|
198
189
|
module.exports = { validate, generateStringValidator };
|
|
@@ -234,7 +234,9 @@ const centralMessageTexts = {
|
|
|
234
234
|
deprecated: 'Option $(NAME) is no longer supported! Use latest API options instead',
|
|
235
235
|
magicVars: 'Option $(PROP) is no longer supported! Use $(OTHERPROP) instead. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
|
|
236
236
|
value: 'Expected option $(PROP) to have $(VALUE). Found: $(OTHERVALUE)',
|
|
237
|
+
value2: 'Expected option $(OPTION) to have value $(VALUE) or $(RAWVALUE); found: $(OTHERVALUE)',
|
|
237
238
|
type: 'Expected option $(OPTION) to be of type $(VALUE). Found: $(OTHERVALUE)',
|
|
239
|
+
forbidden: 'Option $(OPTION) can\'t be used with API function $(MODULE)'
|
|
238
240
|
},
|
|
239
241
|
|
|
240
242
|
'api-invalid-variable-replacement': {
|
|
@@ -674,6 +676,7 @@ const centralMessageTexts = {
|
|
|
674
676
|
std: 'Rewriting the ON-condition not supported here', // unused: merge with 'rewrite-not-supported'
|
|
675
677
|
'sub-element': 'Rewriting the ON-condition of unmanaged association in sub element is not supported'
|
|
676
678
|
},
|
|
679
|
+
'rewrite-undefined-key': 'Expected element $(ID) to be available in $(TARGET), as it is required to match the foreign key of $(NAME)',
|
|
677
680
|
|
|
678
681
|
'type-unexpected-typeof': {
|
|
679
682
|
std: 'Unexpected $(KEYWORD) for the type reference here',
|
|
@@ -854,6 +857,7 @@ const centralMessageTexts = {
|
|
|
854
857
|
'ref-invalid-include': {
|
|
855
858
|
std: 'A type, entity, aspect or event with direct elements is expected here',
|
|
856
859
|
bare : 'An aspect without elements is expected here',
|
|
860
|
+
param: 'A type, entity, aspect or event without parameters is expected here',
|
|
857
861
|
},
|
|
858
862
|
'ref-invalid-type': {
|
|
859
863
|
std: 'A type or an element is expected here',
|
|
@@ -894,8 +898,8 @@ const centralMessageTexts = {
|
|
|
894
898
|
},
|
|
895
899
|
|
|
896
900
|
'query-undefined-element': {
|
|
897
|
-
std: '
|
|
898
|
-
redirected: '
|
|
901
|
+
std: 'Target $(TARGET) of $(NAME) is missing element $(ID); please use $(KEYWORD) with an explicit ON-condition',
|
|
902
|
+
redirected: 'Target $(TARGET) of $(NAME) is missing element $(ID); please add an ON-condition to $(KEYWORD)',
|
|
899
903
|
},
|
|
900
904
|
'query-unexpected-assoc-hdbcds': 'Publishing a managed association in a view is not possible for “hdbcds” naming mode',
|
|
901
905
|
'query-unexpected-structure-hdbcds': 'Publishing a structured element in a view is not possible for “hdbcds” naming mode',
|
|
@@ -1136,7 +1140,27 @@ const centralMessageTexts = {
|
|
|
1136
1140
|
'wrongval': 'Unexpected value for $(OP) in $(ANNO)',
|
|
1137
1141
|
'wrongval_meta': 'Expected value for $(OP) to be a $(META) in $(ANNO)',
|
|
1138
1142
|
'wrongval_meta_list': 'Expected value for $(OP) to be a $(META) or $(RAWVALUES) in $(ANNO)',
|
|
1139
|
-
}
|
|
1143
|
+
},
|
|
1144
|
+
'odata-anno-xpr-ref': {
|
|
1145
|
+
'std': '$(ANNO) can\'t be propagated to $(NAME) because path $(ELEMREF) is not resolvable via type reference $(CODE)',
|
|
1146
|
+
'flatten_builtin': 'Expected path $(ELEMREF) in $(ANNO) to resolve to a builtin type while flattening $(NAME)',
|
|
1147
|
+
'notaparam': 'Unexpected path $(ELEMREF) for parameter entity in $(ANNO)',
|
|
1148
|
+
'notaneelement': 'Unexpected path $(ELEMREF) for type entity in $(ANNO)'
|
|
1149
|
+
},
|
|
1150
|
+
// tenenat isolation via discriminator column:
|
|
1151
|
+
'tenant-invalid-alias-name': {
|
|
1152
|
+
std: 'Can\'t have a table alias named $(NAME) in a tenant-dependent entity',
|
|
1153
|
+
implicit: 'Provide an explicit table alias name; do not use $(NAME)',
|
|
1154
|
+
mixin: 'Can\'t define a mixin named $(NAME) in a tenant-dependent entity',
|
|
1155
|
+
},
|
|
1156
|
+
'tenant-invalid-composition': {
|
|
1157
|
+
std: 'Can\'t define a composition of a tenant-independent entity $(TARGET) in a tenant-dependent entity',
|
|
1158
|
+
type: 'Can\'t use type $(TYPE) with a composition of a tenant-independent entity in a tenant-dependent entity',
|
|
1159
|
+
},
|
|
1160
|
+
'tenant-invalid-target': {
|
|
1161
|
+
std: 'Can\'t define an association to a tenant-dependent entity $(TARGET) in a tenant-independent entity',
|
|
1162
|
+
type: 'Can\'t use type $(TYPE) with an association to a tenant-dependent entity in a tenant-independent entity',
|
|
1163
|
+
},
|
|
1140
1164
|
// -----------------------------------------------------------------------------------
|
|
1141
1165
|
// OData Message section ends here, no messages below this line
|
|
1142
1166
|
// -----------------------------------------------------------------------------------
|
package/lib/base/messages.js
CHANGED
|
@@ -814,6 +814,7 @@ function transformElementRef( arg ) {
|
|
|
814
814
|
return quoted( arg );
|
|
815
815
|
// Can be used by CSN backends or compiler to create a simple path such as E:elem
|
|
816
816
|
return quoted(
|
|
817
|
+
(arg.param ? ':' : '') +
|
|
817
818
|
ref.map(
|
|
818
819
|
item => (typeof item !== 'string'
|
|
819
820
|
? `${ item.id }${item.args ? '(…)' : ''}${item.where ? '[…]' : ''}`
|
|
@@ -833,8 +834,8 @@ function transformArg( arg, r, args, texts ) {
|
|
|
833
834
|
if (arg.ref) {
|
|
834
835
|
// Can be used by CSN backends to create a simple path such as E:elem
|
|
835
836
|
if (arg.ref.length > 1)
|
|
836
|
-
return quoted(`${ arg.ref[0] }:${ arg.ref.slice(1).join('.') }`);
|
|
837
|
-
return quoted(arg.ref);
|
|
837
|
+
return quoted(`${ pathId(arg.ref[0]) }:${ arg.ref.slice(1).map(pathId).join('.') }`);
|
|
838
|
+
return quoted(pathId(arg.ref[0]));
|
|
838
839
|
}
|
|
839
840
|
if (!arg.name)
|
|
840
841
|
return quoted( arg.name );
|
|
@@ -848,6 +849,10 @@ function transformArg( arg, r, args, texts ) {
|
|
|
848
849
|
return artName( arg, prop );
|
|
849
850
|
}
|
|
850
851
|
|
|
852
|
+
function pathId( item ) {
|
|
853
|
+
return (typeof item === 'string') ? item : item.id;
|
|
854
|
+
}
|
|
855
|
+
|
|
851
856
|
// TODO: very likely delete this function
|
|
852
857
|
function searchName( art, id, variant ) {
|
|
853
858
|
if (!variant) {
|
|
@@ -1479,7 +1484,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1479
1484
|
|
|
1480
1485
|
let result = '';
|
|
1481
1486
|
const csnDictionaries = [
|
|
1482
|
-
'args', 'params', 'enum', 'mixin', 'elements', 'actions', 'definitions',
|
|
1487
|
+
'args', 'params', 'enum', 'mixin', 'elements', 'actions', 'definitions', 'vocabularies',
|
|
1483
1488
|
];
|
|
1484
1489
|
// Properties that (currently) end the semantic location.
|
|
1485
1490
|
const queryPropsLast = [ 'where', 'groupBy', 'having', 'orderBy', 'limit', 'offset' ];
|
package/lib/base/model.js
CHANGED
|
@@ -27,6 +27,7 @@ const queryOps = {
|
|
|
27
27
|
const availableBetaFlags = {
|
|
28
28
|
// enabled by --beta-mode
|
|
29
29
|
annotationExpressions: true,
|
|
30
|
+
odataPathsInAnnotationExpressions: true,
|
|
30
31
|
odataAnnotationExpressions: true,
|
|
31
32
|
assocsWithParams: true, // beta, because runtimes don't support it, yet.
|
|
32
33
|
hanaAssocRealCardinality: true,
|
|
@@ -39,6 +40,7 @@ const availableBetaFlags = {
|
|
|
39
40
|
tenantVariable: true,
|
|
40
41
|
calcAssoc: true,
|
|
41
42
|
vectorType: true,
|
|
43
|
+
v5preview: true,
|
|
42
44
|
// disabled by --beta-mode
|
|
43
45
|
nestedServices: false,
|
|
44
46
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { setProp } = require('../base/model');
|
|
4
|
+
const { featureFlags } = require('../transform/db/featureFlags');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {string} flag
|
|
9
|
+
*
|
|
10
|
+
* @returns {Function} Function to correctly set the given flag
|
|
11
|
+
*/
|
|
12
|
+
function setFeatureFlag( flag ) {
|
|
13
|
+
return function setFlag() {
|
|
14
|
+
if (!this.csn.meta)
|
|
15
|
+
setProp(this.csn, 'meta', {});
|
|
16
|
+
if (!this.csn.meta[featureFlags])
|
|
17
|
+
this.csn.meta[featureFlags] = {};
|
|
18
|
+
|
|
19
|
+
this.csn.meta[featureFlags][flag] = true;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Export a applyTransformations callback object that sets the feature flags if certain properties are present
|
|
24
|
+
module.exports = {
|
|
25
|
+
value: setFeatureFlag('$calculatedElements'),
|
|
26
|
+
expand: setFeatureFlag('$expandInline'),
|
|
27
|
+
inline: setFeatureFlag('$expandInline'),
|
|
28
|
+
};
|