@sap/cds-compiler 3.3.2 → 3.4.2
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 +33 -0
- package/bin/cdsc.js +3 -1
- package/doc/CHANGELOG_BETA.md +17 -0
- package/lib/api/main.js +147 -18
- package/lib/api/validate.js +8 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/keywords.js +104 -0
- package/lib/base/message-registry.js +137 -68
- package/lib/base/messages.js +59 -48
- package/lib/base/model.js +1 -0
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +13 -8
- package/lib/checks/defaultValues.js +3 -1
- package/lib/checks/elements.js +1 -1
- package/lib/checks/parameters.js +4 -2
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/sql-snippets.js +12 -10
- package/lib/checks/validator.js +14 -4
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/checks.js +30 -20
- package/lib/compiler/define.js +89 -25
- package/lib/compiler/extend.js +33 -28
- package/lib/compiler/finalize-parse-cdl.js +14 -9
- package/lib/compiler/populate.js +30 -8
- package/lib/compiler/propagator.js +23 -28
- package/lib/compiler/resolve.js +11 -5
- package/lib/compiler/shared.js +66 -48
- package/lib/compiler/tweak-assocs.js +2 -3
- package/lib/compiler/utils.js +11 -0
- package/lib/edm/annotations/genericTranslation.js +7 -4
- package/lib/edm/csn2edm.js +1 -1
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +3565 -3544
- package/lib/json/csnVersion.js +13 -13
- package/lib/json/from-csn.js +140 -158
- package/lib/json/to-csn.js +23 -5
- package/lib/language/.eslintrc.json +4 -0
- package/lib/language/antlrParser.js +7 -10
- package/lib/language/docCommentParser.js +1 -2
- package/lib/language/errorStrategy.js +54 -27
- package/lib/language/genericAntlrParser.js +115 -84
- package/lib/language/language.g4 +29 -25
- package/lib/language/multiLineStringParser.js +75 -63
- package/lib/main.js +1 -0
- package/lib/model/csnRefs.js +4 -3
- package/lib/model/csnUtils.js +39 -7
- package/lib/model/sortViews.js +7 -3
- package/lib/modelCompare/compare.js +49 -15
- package/lib/modelCompare/filter.js +83 -0
- package/lib/optionProcessor.js +5 -1
- package/lib/render/manageConstraints.js +9 -5
- package/lib/render/toCdl.js +120 -62
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +6 -2
- package/lib/render/utils/common.js +7 -0
- package/lib/sql-identifier.js +7 -0
- package/lib/transform/db/assertUnique.js +27 -38
- package/lib/transform/db/expansion.js +11 -4
- package/lib/transform/db/temporal.js +3 -1
- package/lib/transform/db/transformExists.js +7 -1
- package/lib/transform/db/views.js +42 -13
- package/lib/transform/draft/db.js +2 -2
- package/lib/transform/forOdataNew.js +7 -3
- package/lib/transform/forRelationalDB.js +12 -6
- package/lib/transform/localized.js +1 -1
- package/lib/transform/odata/typesExposure.js +2 -1
- package/lib/transform/parseExpr.js +245 -0
- package/lib/transform/transformUtilsNew.js +23 -14
- package/lib/transform/translateAssocsToJoins.js +12 -12
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
- package/lib/utils/term.js +5 -5
- package/package.json +2 -2
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,39 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
## Version 3.4.2 - 2022-11-11
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Don't propagate `@cds.external` (The CDS Importer adds `@cds.external` for all
|
|
15
|
+
imported definitions beginning with cds-dk@6.3.0, see CAP release log).
|
|
16
|
+
- for.odata: Ignore all `@cds.external` definitions.
|
|
17
|
+
- to.sql: For sql dialect `h2`, don't turn a Decimal with length 0 into a Decfloat.
|
|
18
|
+
- Extending a projection with an aspect could result in incorrect auto-redirection.
|
|
19
|
+
- Annotations of aspects were not properly propagated to projections under some order-specific circumstances.
|
|
20
|
+
|
|
21
|
+
## Version 3.4.0 - 2022-10-26
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- to.sql: Add support for sql dialect `h2`, which renders SQL for H2 2.x.
|
|
26
|
+
- Projections can now be extended by annotation-only aspects, e.g. `extend P with MyAspect;`.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Properly report an error for bare `$self` references,
|
|
31
|
+
except in the `on` condition of unmanaged associations.
|
|
32
|
+
- Do not dump with references to CDS variables like `$now` in `expand`/`inline`.
|
|
33
|
+
- Properly report an error when trying to `cast` a column to an association.
|
|
34
|
+
- to.cdl: Identifiers that are always keywords in special functions are now escaped.
|
|
35
|
+
- to.edm(x):
|
|
36
|
+
+ Nested annotation was not applied if outer annotation has value zero.
|
|
37
|
+
+ Fix `AppliesTo=ComplexType, TypeDefinition` term definition directive.
|
|
38
|
+
- to.sql/hdi/hdbcds:
|
|
39
|
+
+ Properly report an error for `exists` with `$self.managed-association`
|
|
40
|
+
+ For sql dialect `hana`, add an implicit alias when using `:param` in the select list
|
|
41
|
+
+ Handle `$self` and magic variables during expansion of nested projections
|
|
42
|
+
|
|
10
43
|
## Version 3.3.2 - 2022-09-30
|
|
11
44
|
|
|
12
45
|
### Fixed
|
package/bin/cdsc.js
CHANGED
|
@@ -153,7 +153,9 @@ function cdsc_main() {
|
|
|
153
153
|
cmdLine.args.files = [ cmdLine.args.file ];
|
|
154
154
|
}
|
|
155
155
|
else if (cmdLine.command === 'parseOnly') {
|
|
156
|
+
// Remap command and command-specific options.
|
|
156
157
|
cmdLine.command = 'toCsn';
|
|
158
|
+
cmdLine.options.toCsn = cmdLine.options.parseOnly;
|
|
157
159
|
cmdLine.options.parseOnly = true;
|
|
158
160
|
cmdLine.args.files = [ cmdLine.args.file ];
|
|
159
161
|
}
|
|
@@ -521,7 +523,7 @@ function executeCommandLine(command, options, args) {
|
|
|
521
523
|
log(); // newline
|
|
522
524
|
});
|
|
523
525
|
if (options.showMessageId && hasAtLeastOneExplanation)
|
|
524
|
-
log(`${colorTerm.
|
|
526
|
+
log(`${colorTerm.asHelp('help')}: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`);
|
|
525
527
|
}
|
|
526
528
|
return model;
|
|
527
529
|
}
|
package/doc/CHANGELOG_BETA.md
CHANGED
|
@@ -8,6 +8,23 @@ 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 3.4.0 - 2022-MM-DD
|
|
12
|
+
|
|
13
|
+
### Added `aspectWithoutElements`
|
|
14
|
+
|
|
15
|
+
- Aspects can now be defined without elements, e.g. `aspect A;`. This allows the definition of annotation-only aspects.
|
|
16
|
+
Views can be extended by such an aspect. For example:
|
|
17
|
+
```cds
|
|
18
|
+
entity V as projection on SomeEntity;
|
|
19
|
+
@anno aspect A;
|
|
20
|
+
extend V with A;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Added `sqlMigration`
|
|
24
|
+
|
|
25
|
+
- to.sql.migration: Offer something similar to to.hdi.migration, but for general SQL. Don't offer a complete out-of-the-box schema evolution, instead only
|
|
26
|
+
allow lossless, easy to revert actions like adding a column or extending a string length.
|
|
27
|
+
|
|
11
28
|
## Version 3.3.0 - 2022-09-29
|
|
12
29
|
|
|
13
30
|
### Removed `nestedProjections`
|
package/lib/api/main.js
CHANGED
|
@@ -12,6 +12,7 @@ const forOdataNew = lazyload('../transform/forOdataNew.js');
|
|
|
12
12
|
const toSql = lazyload('../render/toSql');
|
|
13
13
|
const toCdl = require('../render/toCdl');
|
|
14
14
|
const modelCompare = lazyload('../modelCompare/compare');
|
|
15
|
+
const diffFilter = lazyload('../modelCompare/filter');
|
|
15
16
|
const sortViews = lazyload('../model/sortViews');
|
|
16
17
|
const csnUtils = lazyload('../model/csnUtils');
|
|
17
18
|
const timetrace = lazyload('../utils/timetrace');
|
|
@@ -33,7 +34,7 @@ const { cloneCsnNonDict } = require('../model/csnUtils');
|
|
|
33
34
|
const { toHdbcdsSource } = require('../render/toHdbcds');
|
|
34
35
|
const { ModelError } = require('../base/error');
|
|
35
36
|
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
36
|
-
const { checkRemovedDeprecatedFlags } = require('../base/model');
|
|
37
|
+
const { checkRemovedDeprecatedFlags, isBetaEnabled } = require('../base/model');
|
|
37
38
|
const { csn2edm, csn2edmAll } = require('../edm/csn2edm');
|
|
38
39
|
|
|
39
40
|
const relevantGeneralOptions = [ /* for future generic options */ ];
|
|
@@ -92,13 +93,17 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
|
|
|
92
93
|
const { error, warning, throwWithAnyError } = messages.makeMessageFunction(csn, options, module);
|
|
93
94
|
|
|
94
95
|
for (const name of relevantOptionNames ) {
|
|
95
|
-
if (options[name] !== csn.meta.options[name])
|
|
96
|
-
error('wrong-pretransformed-csn', null, {
|
|
96
|
+
if (options[name] !== csn.meta.options[name]) {
|
|
97
|
+
error('wrong-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
|
|
98
|
+
'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
|
|
99
|
+
}
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
for (const name of warnAboutMismatch ) {
|
|
100
|
-
if (options[name] !== csn.meta.options[name])
|
|
101
|
-
warning('options-mismatch-pretransformed-csn', null, {
|
|
103
|
+
if (options[name] !== csn.meta.options[name]) {
|
|
104
|
+
warning('options-mismatch-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
|
|
105
|
+
'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
|
|
106
|
+
}
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
throwWithAnyError();
|
|
@@ -361,6 +366,119 @@ function remapName(key, csn, filter = () => true) {
|
|
|
361
366
|
return key;
|
|
362
367
|
}
|
|
363
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Return all changes in artifacts between two given models.
|
|
371
|
+
* Note: Only supports changes in artifacts compiled/rendered as db-CSN/SQL.
|
|
372
|
+
*
|
|
373
|
+
* @param {CSN.Model} csn A clean input CSN representing the desired "after-image"
|
|
374
|
+
* @param {HdiOptions} options Options
|
|
375
|
+
* @param {CSN.Model} beforeImage A db-transformed CSN representing the "before-image", or null in case no such image
|
|
376
|
+
* is known, i.e. for the very first migration step
|
|
377
|
+
* @returns {object} An object with three properties:
|
|
378
|
+
* - afterImage: A db-transformed CSN representing the "after-image"
|
|
379
|
+
* - drops: An array of SQL statements to drop views/tables
|
|
380
|
+
* - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
|
|
381
|
+
*/
|
|
382
|
+
function sqlMigration(csn, options, beforeImage) {
|
|
383
|
+
const internalOptions = prepareOptions.to.sql(options);
|
|
384
|
+
const { error, throwWithError } = messages.makeMessageFunction(csn, options, 'to.sql.migration');
|
|
385
|
+
|
|
386
|
+
if (!isBetaEnabled(internalOptions, 'sqlMigration'))
|
|
387
|
+
throw new Error('Function `to.sql.migration` requires beta-flag `sqlMigration`');
|
|
388
|
+
|
|
389
|
+
// Prepare after-image.
|
|
390
|
+
const afterImage = forSql(csn, options);
|
|
391
|
+
// Compare both images.
|
|
392
|
+
const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
|
|
393
|
+
const diffFilterObj = diffFilter[options.sqlDialect];
|
|
394
|
+
|
|
395
|
+
if (diffFilterObj) {
|
|
396
|
+
diff.extensions.forEach(ex => diffFilterObj.extension(ex, error));
|
|
397
|
+
diff.migrations.forEach(migration => diffFilterObj.migration(migration, error));
|
|
398
|
+
Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const drops = {
|
|
402
|
+
creates: {},
|
|
403
|
+
final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
|
|
404
|
+
previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ artifact['@cds.persistence.name'] };`;
|
|
405
|
+
return previous;
|
|
406
|
+
}, {}),
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const cleanup = [];
|
|
410
|
+
// Delete artifacts that are already present in csn
|
|
411
|
+
if (beforeImage?.definitions) {
|
|
412
|
+
Object.keys(beforeImage.definitions).forEach((artifactName) => {
|
|
413
|
+
const beforeArtifact = beforeImage.definitions[artifactName];
|
|
414
|
+
const diffArtifact = diff.definitions[artifactName];
|
|
415
|
+
// TODO: exists, abstract? isPersistedOnDb?
|
|
416
|
+
if (diffArtifact && diffArtifact['@cds.persistence.name'] && !diffArtifact['@cds.persistence.skip'] &&
|
|
417
|
+
(diffArtifact.query || diffArtifact.projection) &&
|
|
418
|
+
(diffArtifact[modelCompare.isChanged] === true || // we know it changed because we compared two views
|
|
419
|
+
diffArtifact[modelCompare.isChanged] === undefined)) { // if it was removed in the after, then we don't have the flag
|
|
420
|
+
drops.creates[artifactName] = `DROP VIEW ${ diffArtifact['@cds.persistence.name'] };`;
|
|
421
|
+
} // TODO: What happens with a changed kind -> entity becomes a view?
|
|
422
|
+
else if (diffArtifact &&
|
|
423
|
+
diffArtifact['@cds.persistence.skip'] !== true &&
|
|
424
|
+
diffArtifact.kind === beforeArtifact.kind && // detect action -> entity
|
|
425
|
+
csnUtils.isPersistedAsView(diffArtifact) === csnUtils.isPersistedAsView(beforeArtifact) // detect view -> entity
|
|
426
|
+
) { // don't render again, but need info for primary key extension
|
|
427
|
+
diffArtifact['@cds.persistence.skip'] = true;
|
|
428
|
+
cleanup.push(() => delete diffArtifact['@cds.persistence.skip']);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Convert the diff to SQL.
|
|
434
|
+
if (!internalOptions.beta)
|
|
435
|
+
internalOptions.beta = {};
|
|
436
|
+
|
|
437
|
+
internalOptions.beta.sqlExtensions = true;
|
|
438
|
+
|
|
439
|
+
// eslint-disable-next-line no-unused-vars
|
|
440
|
+
const { deletions, migrations, ...hdbkinds } = toSql.toSqlDdl(diff, internalOptions);
|
|
441
|
+
|
|
442
|
+
cleanup.forEach(fn => fn());
|
|
443
|
+
// TODO: Handle `ADD CONSTRAINT` etc!
|
|
444
|
+
const sortOrder = sortViews({ sql: {}, csn: afterImage });
|
|
445
|
+
|
|
446
|
+
const dropSqls = [];
|
|
447
|
+
const createAndAlterSqls = [];
|
|
448
|
+
// Turn the structured result into just a flat dictionary of "artifact name": "sql"
|
|
449
|
+
const flatSqlDict = Object.values(hdbkinds).reduce((prev, curr) => {
|
|
450
|
+
forEach(curr, (name, value) => {
|
|
451
|
+
prev[name] = value;
|
|
452
|
+
});
|
|
453
|
+
return prev;
|
|
454
|
+
}, Object.create(null));
|
|
455
|
+
|
|
456
|
+
// Sort all the SQL statements according to the overall order
|
|
457
|
+
for (const { name } of sortOrder) {
|
|
458
|
+
if (drops.final[name])
|
|
459
|
+
dropSqls.push(drops.final[name]);
|
|
460
|
+
else if (drops.creates[name])
|
|
461
|
+
dropSqls.push(drops.creates[name]);
|
|
462
|
+
|
|
463
|
+
// No else-if, since we have drop-creates for views!
|
|
464
|
+
if (flatSqlDict[name])
|
|
465
|
+
createAndAlterSqls.push(flatSqlDict[name]);
|
|
466
|
+
else if (migrations[name])
|
|
467
|
+
createAndAlterSqls.push(...migrations[name].map(m => m.sql));
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// We need to drop the things without dependants first - so inversely sorted
|
|
471
|
+
dropSqls.reverse();
|
|
472
|
+
|
|
473
|
+
throwWithError();
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
afterImage,
|
|
477
|
+
drops: dropSqls,
|
|
478
|
+
createsAndAlters: createAndAlterSqls,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
364
482
|
/**
|
|
365
483
|
* Return all changes in artifacts between two given models.
|
|
366
484
|
* Note: Only supports changes in entities (not views etc.) compiled/rendered as HANA-CSN/SQL.
|
|
@@ -369,17 +487,7 @@ function remapName(key, csn, filter = () => true) {
|
|
|
369
487
|
* @param {HdiOptions} options Options
|
|
370
488
|
* @param {CSN.Model} beforeImage A HANA-transformed CSN representing the "before-image", or null in case no such image
|
|
371
489
|
* is known, i.e. for the very first migration step
|
|
372
|
-
* @returns {
|
|
373
|
-
* - definitions: An array of objects with all artifacts in the after-image. Each object specifies
|
|
374
|
-
* the artifact filename, the suffix, and the corresponding SQL statement to create
|
|
375
|
-
* the artifact.
|
|
376
|
-
* - deletions: An array of objects with the deleted artifacts. Each object specifies the artifact
|
|
377
|
-
* filename and the suffix.
|
|
378
|
-
* - migrations: An array of objects with the changed (migrated) artifacts. Each object specifies the
|
|
379
|
-
* artifact filename, the suffix, and the changeset (an array of changes, each specifying
|
|
380
|
-
* whether it incurs potential data loss, and its respective SQL statement(s), with
|
|
381
|
-
* multiple statements concatenated as a multi-line string in case the change e.g.
|
|
382
|
-
* consists of a column drop and add).
|
|
490
|
+
* @returns {migration} The migration result
|
|
383
491
|
*/
|
|
384
492
|
function hdiMigration(csn, options, beforeImage) {
|
|
385
493
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
@@ -387,11 +495,14 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
387
495
|
// Prepare after-image.
|
|
388
496
|
const afterImage = forHdi(csn, options);
|
|
389
497
|
|
|
390
|
-
// Compare both images.
|
|
391
498
|
const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
|
|
392
499
|
|
|
393
500
|
// Convert the diff to SQL.
|
|
394
|
-
internalOptions.
|
|
501
|
+
if (!internalOptions.beta)
|
|
502
|
+
internalOptions.beta = {};
|
|
503
|
+
|
|
504
|
+
internalOptions.beta.sqlExtensions = true;
|
|
505
|
+
|
|
395
506
|
const { deletions, migrations, ...hdbkinds } = toSql.toSqlDdl(diff, internalOptions);
|
|
396
507
|
|
|
397
508
|
return {
|
|
@@ -449,6 +560,8 @@ function createSqlMigrations(migrations, afterImage) {
|
|
|
449
560
|
|
|
450
561
|
hdi.migration = hdiMigration;
|
|
451
562
|
|
|
563
|
+
sql.migration = sqlMigration;
|
|
564
|
+
|
|
452
565
|
/**
|
|
453
566
|
* Process the given CSN into HDBCDS artifacts.
|
|
454
567
|
*
|
|
@@ -922,3 +1035,19 @@ function lazyload(moduleName) {
|
|
|
922
1035
|
*
|
|
923
1036
|
* @typedef {object} edms
|
|
924
1037
|
*/
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* - afterImage: The desired after-image in db-CSN format
|
|
1041
|
+
* - definitions: An array of objects with all artifacts in the after-image. Each object specifies
|
|
1042
|
+
* the artifact filename, the suffix, and the corresponding SQL statement to create
|
|
1043
|
+
* the artifact.
|
|
1044
|
+
* - deletions: An array of objects with the deleted artifacts. Each object specifies the artifact
|
|
1045
|
+
* filename and the suffix.
|
|
1046
|
+
* - migrations: An array of objects with the changed (migrated) artifacts. Each object specifies the
|
|
1047
|
+
* artifact filename, the suffix, and the changeset (an array of changes, each specifying
|
|
1048
|
+
* whether it incurs potential data loss, and its respective SQL statement(s), with
|
|
1049
|
+
* multiple statements concatenated as a multi-line string in case the change e.g.
|
|
1050
|
+
* consists of a column drop and add).
|
|
1051
|
+
*
|
|
1052
|
+
* @typedef {object} migration
|
|
1053
|
+
*/
|
package/lib/api/validate.js
CHANGED
|
@@ -78,7 +78,7 @@ const validators = {
|
|
|
78
78
|
expected: () => 'type array',
|
|
79
79
|
found: val => `type ${ typeof val }`,
|
|
80
80
|
},
|
|
81
|
-
sqlDialect: generateStringValidator([ 'sqlite', 'hana', 'plain', 'postgres' ]),
|
|
81
|
+
sqlDialect: generateStringValidator([ 'sqlite', 'hana', 'plain', 'postgres', 'h2' ]),
|
|
82
82
|
sqlMapping: generateStringValidator([ 'plain', 'quoted', 'hdbcds' ]),
|
|
83
83
|
odataVersion: generateStringValidator([ 'v2', 'v4' ]),
|
|
84
84
|
odataFormat: generateStringValidator([ 'flat', 'structured' ]),
|
|
@@ -161,8 +161,13 @@ function validate(options, moduleName, customValidators = {}, combinationValidat
|
|
|
161
161
|
forEach(options, (optionName, optionValue) => {
|
|
162
162
|
const validator = customValidators[optionName] || validators[optionName] || booleanValidator;
|
|
163
163
|
|
|
164
|
-
if (!validator.validate(optionValue))
|
|
165
|
-
error('invalid-option', null, {
|
|
164
|
+
if (!validator.validate(optionValue)) {
|
|
165
|
+
error('invalid-option', null, {
|
|
166
|
+
prop: optionName,
|
|
167
|
+
value: validator.expected(optionValue),
|
|
168
|
+
othervalue: validator.found(optionValue),
|
|
169
|
+
}, 'Expected option $(PROP) to have $(VALUE). Found: $(OTHERVALUE)');
|
|
170
|
+
}
|
|
166
171
|
});
|
|
167
172
|
throwWithAnyError();
|
|
168
173
|
}
|
package/lib/base/dictionaries.js
CHANGED
|
@@ -19,7 +19,7 @@ function dictAdd( dict, name, entry, duplicateCallback ) {
|
|
|
19
19
|
duplicateCallback( name, found.name.location, found );
|
|
20
20
|
}
|
|
21
21
|
found.$duplicates.push( entry );
|
|
22
|
-
if (Array.isArray(entry.$duplicates))
|
|
22
|
+
if (Array.isArray( entry.$duplicates ))
|
|
23
23
|
found.$duplicates.push( ...entry.$duplicates )
|
|
24
24
|
else if (duplicateCallback && name) // do not complain with empty name ''
|
|
25
25
|
duplicateCallback( name, entry.name.location, entry );
|
|
@@ -31,7 +31,7 @@ function dictForEach( dict, callback ) {
|
|
|
31
31
|
// TODO: probably define an extra dictForEachArray()
|
|
32
32
|
for (const name in dict) {
|
|
33
33
|
const entry = dict[name];
|
|
34
|
-
if (Array.isArray(entry)) {
|
|
34
|
+
if (Array.isArray( entry )) {
|
|
35
35
|
entry.forEach( callback );
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
@@ -53,8 +53,8 @@ function dictAddArray( dict, name, entry, messageCallback ) {
|
|
|
53
53
|
dict[name] = entry; // also ok if array (redefined)
|
|
54
54
|
return entry;
|
|
55
55
|
}
|
|
56
|
-
if (Array.isArray(entry)) {
|
|
57
|
-
if (Array.isArray(found)) {
|
|
56
|
+
if (Array.isArray( entry )) {
|
|
57
|
+
if (Array.isArray( found )) {
|
|
58
58
|
dict[name] = [ ...found, ...entry ];
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
@@ -65,7 +65,7 @@ function dictAddArray( dict, name, entry, messageCallback ) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
68
|
-
if (Array.isArray(found)) {
|
|
68
|
+
if (Array.isArray( found )) {
|
|
69
69
|
dict[name] = [ ...found, entry ];
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
@@ -84,7 +84,7 @@ function dictAddArray( dict, name, entry, messageCallback ) {
|
|
|
84
84
|
// Push `entry` to the array value with key `name` in the dictionary `dict`.
|
|
85
85
|
function pushToDict( dict, name, entry ) {
|
|
86
86
|
if (dict[name])
|
|
87
|
-
dict[name].push(entry);
|
|
87
|
+
dict[name].push( entry );
|
|
88
88
|
else
|
|
89
89
|
dict[name] = [entry];
|
|
90
90
|
}
|
package/lib/base/keywords.js
CHANGED
|
@@ -842,5 +842,109 @@ module.exports = {
|
|
|
842
842
|
'WHERE',
|
|
843
843
|
'WINDOW',
|
|
844
844
|
'WITH'
|
|
845
|
+
],
|
|
846
|
+
// H2 keywords, used for smart quoting in to-sql.plain.postgres
|
|
847
|
+
// Taken from http://www.h2database.com/html/advanced.html#keywords
|
|
848
|
+
h2: [
|
|
849
|
+
'ALL',
|
|
850
|
+
'AND',
|
|
851
|
+
'ANY',
|
|
852
|
+
'ARRAY',
|
|
853
|
+
'AS',
|
|
854
|
+
'ASYMMETRIC',
|
|
855
|
+
'AUTHORIZATION',
|
|
856
|
+
'BETWEEN',
|
|
857
|
+
'BOTH',
|
|
858
|
+
'CASE',
|
|
859
|
+
'CAST',
|
|
860
|
+
'CHECK',
|
|
861
|
+
'CONSTRAINT',
|
|
862
|
+
'CROSS',
|
|
863
|
+
'CURRENT_CATALOG',
|
|
864
|
+
'CURRENT_DATE',
|
|
865
|
+
'CURRENT_PATH',
|
|
866
|
+
'CURRENT_ROLE',
|
|
867
|
+
'CURRENT_SCHEMA',
|
|
868
|
+
'CURRENT_TIME',
|
|
869
|
+
'CURRENT_TIMESTAMP',
|
|
870
|
+
'CURRENT_USER',
|
|
871
|
+
'DAY',
|
|
872
|
+
'DEFAULT',
|
|
873
|
+
'DISTINCT',
|
|
874
|
+
'ELSE',
|
|
875
|
+
'END',
|
|
876
|
+
'EXCEPT',
|
|
877
|
+
'EXISTS',
|
|
878
|
+
'FALSE',
|
|
879
|
+
'FETCH',
|
|
880
|
+
'FOR',
|
|
881
|
+
'FOREIGN',
|
|
882
|
+
'FROM',
|
|
883
|
+
'FULL',
|
|
884
|
+
'GROUP',
|
|
885
|
+
'GROUPS',
|
|
886
|
+
'HAVING',
|
|
887
|
+
'HOUR',
|
|
888
|
+
'IF',
|
|
889
|
+
'ILIKE',
|
|
890
|
+
'IN',
|
|
891
|
+
'INNER',
|
|
892
|
+
'INTERSECT',
|
|
893
|
+
'INTERVAL',
|
|
894
|
+
'IS',
|
|
895
|
+
'JOIN',
|
|
896
|
+
'KEY',
|
|
897
|
+
'LEADING',
|
|
898
|
+
'LEFT',
|
|
899
|
+
'LIKE',
|
|
900
|
+
'LIMIT',
|
|
901
|
+
'LOCALTIME',
|
|
902
|
+
'LOCALTIMESTAMP',
|
|
903
|
+
'MINUS',
|
|
904
|
+
'MINUTE',
|
|
905
|
+
'MONTH',
|
|
906
|
+
'NATURAL',
|
|
907
|
+
'NOT',
|
|
908
|
+
'NULL',
|
|
909
|
+
'OFFSET',
|
|
910
|
+
'ON',
|
|
911
|
+
'OR',
|
|
912
|
+
'ORDER',
|
|
913
|
+
'OVER',
|
|
914
|
+
'PARTITION',
|
|
915
|
+
'PRIMARY',
|
|
916
|
+
'QUALIFY',
|
|
917
|
+
'RANGE',
|
|
918
|
+
'REGEXP',
|
|
919
|
+
'RIGHT',
|
|
920
|
+
'ROW',
|
|
921
|
+
'ROWNUM',
|
|
922
|
+
'ROWS',
|
|
923
|
+
'SECOND',
|
|
924
|
+
'SELECT',
|
|
925
|
+
'SESSION_USER',
|
|
926
|
+
'SET',
|
|
927
|
+
'SOME',
|
|
928
|
+
'SYMMETRIC',
|
|
929
|
+
'SYSTEM_USER',
|
|
930
|
+
'TABLE',
|
|
931
|
+
'TO',
|
|
932
|
+
'TOP',
|
|
933
|
+
'TRAILING',
|
|
934
|
+
'TRUE',
|
|
935
|
+
'UESCAPE',
|
|
936
|
+
'UNION',
|
|
937
|
+
'UNIQUE',
|
|
938
|
+
'UNKNOWN',
|
|
939
|
+
'USER',
|
|
940
|
+
'USING',
|
|
941
|
+
'VALUE',
|
|
942
|
+
'VALUES',
|
|
943
|
+
'WHEN',
|
|
944
|
+
'WHERE',
|
|
945
|
+
'WINDOW',
|
|
946
|
+
'WITH',
|
|
947
|
+
'YEAR',
|
|
948
|
+
'_ROWID_'
|
|
845
949
|
]
|
|
846
950
|
}
|