@sap/cds-compiler 3.0.0 → 3.1.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 +104 -9
- package/bin/.eslintrc.json +2 -1
- package/bin/cdsc.js +28 -16
- package/doc/API.md +11 -0
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +24 -2
- package/doc/CHANGELOG_DEPRECATED.md +21 -1
- package/lib/api/main.js +92 -40
- package/lib/api/options.js +2 -3
- package/lib/base/keywords.js +64 -1
- package/lib/base/message-registry.js +33 -5
- package/lib/base/messages.js +54 -65
- package/lib/base/model.js +2 -0
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/checks/actionsFunctions.js +8 -7
- package/lib/checks/selectItems.js +96 -14
- package/lib/checks/types.js +5 -8
- package/lib/checks/validator.js +1 -2
- package/lib/compiler/assert-consistency.js +65 -13
- package/lib/compiler/base.js +6 -4
- package/lib/compiler/builtins.js +93 -4
- package/lib/compiler/checks.js +1 -1
- package/lib/compiler/define.js +28 -23
- package/lib/compiler/extend.js +20 -11
- package/lib/compiler/finalize-parse-cdl.js +5 -9
- package/lib/compiler/index.js +2 -0
- package/lib/compiler/populate.js +37 -32
- package/lib/compiler/propagator.js +11 -6
- package/lib/compiler/resolve.js +15 -19
- package/lib/compiler/shared.js +54 -18
- package/lib/compiler/tweak-assocs.js +5 -11
- package/lib/compiler/utils.js +15 -6
- package/lib/edm/annotations/genericTranslation.js +12 -2
- package/lib/edm/annotations/preprocessAnnotations.js +18 -15
- package/lib/edm/csn2edm.js +18 -17
- package/lib/edm/edm.js +22 -13
- package/lib/edm/edmAnnoPreprocessor.js +349 -0
- package/lib/edm/edmInboundChecks.js +85 -0
- package/lib/edm/edmPreprocessor.js +336 -665
- package/lib/edm/edmUtils.js +86 -45
- package/lib/gen/Dictionary.json +29 -9
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -2
- package/lib/gen/languageLexer.js +3 -0
- package/lib/gen/languageParser.js +4332 -4496
- package/lib/inspect/.eslintrc.json +4 -0
- package/lib/inspect/index.js +14 -0
- package/lib/inspect/inspectModelStatistics.js +81 -0
- package/lib/inspect/inspectPropagation.js +189 -0
- package/lib/inspect/inspectUtils.js +44 -0
- package/lib/json/from-csn.js +19 -20
- package/lib/json/to-csn.js +11 -8
- package/lib/language/genericAntlrParser.js +150 -92
- package/lib/language/language.g4 +47 -74
- package/lib/main.d.ts +1 -0
- package/lib/model/api.js +1 -1
- package/lib/model/csnRefs.js +56 -29
- package/lib/model/csnUtils.js +29 -14
- package/lib/model/revealInternalProperties.js +6 -4
- package/lib/modelCompare/compare.js +3 -0
- package/lib/optionProcessor.js +81 -38
- package/lib/render/toCdl.js +57 -32
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +31 -11
- package/lib/render/utils/common.js +3 -4
- package/lib/transform/db/associations.js +43 -35
- package/lib/transform/db/cdsPersistence.js +0 -1
- package/lib/transform/db/flattening.js +3 -4
- package/lib/transform/db/transformExists.js +7 -5
- package/lib/transform/draft/db.js +1 -1
- package/lib/transform/forHanaNew.js +11 -2
- package/lib/transform/forOdataNew.js +4 -4
- package/lib/transform/localized.js +15 -11
- package/lib/transform/odata/typesExposure.js +14 -5
- package/lib/utils/file.js +28 -18
- package/lib/utils/moduleResolve.js +0 -1
- package/package.json +3 -4
- package/share/messages/syntax-expected-integer.md +9 -8
- package/lib/checks/unknownMagic.js +0 -41
package/lib/optionProcessor.js
CHANGED
|
@@ -19,10 +19,7 @@ optionProcessor
|
|
|
19
19
|
.option(' --color <mode>', ['auto', 'always', 'never'])
|
|
20
20
|
.option('-o, --out <dir>')
|
|
21
21
|
.option(' --cds-home <dir>')
|
|
22
|
-
.option(' --lint-mode')
|
|
23
22
|
.option(' --fuzzy-csn-error')
|
|
24
|
-
.option(' --trace-parser')
|
|
25
|
-
.option(' --trace-parser-amb')
|
|
26
23
|
.option(' --trace-fs')
|
|
27
24
|
.option(' --error <id-list>')
|
|
28
25
|
.option(' --warn <id-list>')
|
|
@@ -35,7 +32,6 @@ optionProcessor
|
|
|
35
32
|
.option(' --beta <list>')
|
|
36
33
|
.option(' --deprecated <list>')
|
|
37
34
|
.option(' --direct-backend')
|
|
38
|
-
.option(' --parse-only')
|
|
39
35
|
.option(' --fallback-parser <type>', ['cdl', 'csn', 'csn!'])
|
|
40
36
|
.option(' --test-mode')
|
|
41
37
|
.option(' --test-sort-csn')
|
|
@@ -78,7 +74,6 @@ optionProcessor
|
|
|
78
74
|
never:
|
|
79
75
|
-o, --out <dir> Place generated files in directory <dir>, default is "-" for <stdout>
|
|
80
76
|
--cds-home <dir> When set, modules starting with '@sap/cds/' are searched in <dir>
|
|
81
|
-
--lint-mode Generate nothing, just produce messages if any (for use by editors)
|
|
82
77
|
--fuzzy-csn-error Report free-style CSN properties as errors
|
|
83
78
|
-- Indicate the end of options (helpful if source names start with "-")
|
|
84
79
|
|
|
@@ -87,8 +82,6 @@ optionProcessor
|
|
|
87
82
|
--default-string-length <length> Default 'length' for 'cds.String'
|
|
88
83
|
|
|
89
84
|
Diagnostic options
|
|
90
|
-
--trace-parser Trace parser
|
|
91
|
-
--trace-parser-amb Trace parser ambiguities
|
|
92
85
|
--trace-fs Trace file system access caused by "using from"
|
|
93
86
|
|
|
94
87
|
Severity options
|
|
@@ -109,10 +102,12 @@ optionProcessor
|
|
|
109
102
|
hanaAssocRealCardinality
|
|
110
103
|
mapAssocToJoinCardinality
|
|
111
104
|
ignoreAssocPublishingInUnion
|
|
105
|
+
odataOpenType
|
|
106
|
+
optionalActionFunctionParameters
|
|
112
107
|
--deprecated <list> Comma separated list of deprecated options.
|
|
113
108
|
Valid values are:
|
|
109
|
+
autoCorrectOrderBySourceRefs
|
|
114
110
|
eagerPersistenceForGeneratedEntities
|
|
115
|
-
--parse-only Stop compilation after parsing and write result to <stdout>
|
|
116
111
|
--fallback-parser <type> If the language cannot be deduced by the file's extensions, use this
|
|
117
112
|
parser as a fallback. Valid values are:
|
|
118
113
|
cdl : Use CDL parser
|
|
@@ -141,15 +136,18 @@ optionProcessor
|
|
|
141
136
|
toCsn [options] <files...> (default) Generate original model as CSN
|
|
142
137
|
parseCdl [options] <file> Generate a CSN that is close to the CDL source.
|
|
143
138
|
explain <message-id> Explain a compiler message.
|
|
139
|
+
parseOnly [options] <files...> (internal) Stop compilation after parsing, write messages to <stderr>,
|
|
140
|
+
per default no output.
|
|
144
141
|
toRename [options] <files...> (internal) Generate SQL DDL rename statements
|
|
145
142
|
manageConstraints [options] <files...> (internal) Generate ALTER TABLE statements to
|
|
146
143
|
add / modify referential constraints.
|
|
144
|
+
inspect [options] <files...> (internal) Inspect the given CDS files.
|
|
147
145
|
`);
|
|
148
146
|
|
|
149
147
|
// ----------- toHana -----------
|
|
150
148
|
optionProcessor.command('H, toHana')
|
|
151
149
|
.option('-h, --help')
|
|
152
|
-
.option('-n, --
|
|
150
|
+
.option('-n, --sql-mapping <style>', ['plain', 'quoted', 'hdbcds'], { aliases: ['--names'] })
|
|
153
151
|
.option(' --render-virtual')
|
|
154
152
|
.option(' --joinfk')
|
|
155
153
|
.option('-u, --user <user>')
|
|
@@ -159,6 +157,7 @@ optionProcessor.command('H, toHana')
|
|
|
159
157
|
.option(' --integrity-not-enforced')
|
|
160
158
|
.option(' --assert-integrity <mode>', ['true', 'false', 'individual'])
|
|
161
159
|
.option(' --assert-integrity-type <type>', ['RT', 'DB'], { ignoreCase: true })
|
|
160
|
+
.option(' --disable-hana-comments')
|
|
162
161
|
.help(`
|
|
163
162
|
Usage: cdsc toHana [options] <files...>
|
|
164
163
|
|
|
@@ -166,7 +165,7 @@ optionProcessor.command('H, toHana')
|
|
|
166
165
|
|
|
167
166
|
Options
|
|
168
167
|
-h, --help Show this help text
|
|
169
|
-
-n, --
|
|
168
|
+
-n, --sql-mapping <style> Naming style for generated entity and element names:
|
|
170
169
|
plain : (default) Produce HANA entity and element names in
|
|
171
170
|
uppercase and flattened with underscores. Do not generate
|
|
172
171
|
structured types.
|
|
@@ -193,11 +192,12 @@ optionProcessor.command('H, toHana')
|
|
|
193
192
|
RT : (default) No database constraint for an association
|
|
194
193
|
if not explicitly demanded via annotation
|
|
195
194
|
DB : Create database constraints for associations
|
|
195
|
+
--disable-hana-comments Disable rendering of doc comments as SAP HANA comments.
|
|
196
196
|
`);
|
|
197
197
|
|
|
198
198
|
optionProcessor.command('O, toOdata')
|
|
199
199
|
.option('-h, --help')
|
|
200
|
-
.option('-v, --odata-version <version>', ['v2', 'v4', 'v4x'])
|
|
200
|
+
.option('-v, --odata-version <version>', ['v2', 'v4', 'v4x'], { aliases: ['--version'] })
|
|
201
201
|
.option('-x, --xml')
|
|
202
202
|
.option('-j, --json')
|
|
203
203
|
.option(' --odata-containment')
|
|
@@ -207,7 +207,7 @@ optionProcessor.command('O, toOdata')
|
|
|
207
207
|
.option(' --odata-v2-partial-constr')
|
|
208
208
|
.option('-c, --csn')
|
|
209
209
|
.option('-f, --odata-format <format>', ['flat', 'structured'])
|
|
210
|
-
.option('-n, --
|
|
210
|
+
.option('-n, --sql-mapping <style>', ['plain', 'quoted', 'hdbcds'], { aliases: [ '--names' ] })
|
|
211
211
|
.option('-s, --service-names <list>')
|
|
212
212
|
.help(`
|
|
213
213
|
Usage: cdsc toOdata [options] <files...>
|
|
@@ -232,13 +232,13 @@ optionProcessor.command('O, toOdata')
|
|
|
232
232
|
--odata-foreign-keys Render foreign keys in structured format (V4 only)
|
|
233
233
|
--odata-v2-partial-constr Render referential constraints also for partial principal key tuple
|
|
234
234
|
(Not spec compliant and V2 only)
|
|
235
|
-
-n, --
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
235
|
+
-n, --sql-mapping <style> Annotate artifacts and elements with "@cds.persistence.name", which is
|
|
236
|
+
the corresponding database name (see "--sql-mapping" for "toHana or "toSql")
|
|
237
|
+
plain : (default) Names in uppercase and flattened with underscores
|
|
238
|
+
quoted : Names in original case as in CDL. Entity names with dots,
|
|
239
|
+
but element names flattened with underscores
|
|
240
|
+
hdbcds : Names as HANA CDS would generate them from the same CDS
|
|
241
|
+
source (like "quoted", but using element names with dots)
|
|
242
242
|
-s, --service-names <list> List of comma-separated service names to be rendered
|
|
243
243
|
(default) empty, all services are rendered
|
|
244
244
|
`);
|
|
@@ -256,10 +256,10 @@ optionProcessor.command('C, toCdl')
|
|
|
256
256
|
|
|
257
257
|
optionProcessor.command('Q, toSql')
|
|
258
258
|
.option('-h, --help')
|
|
259
|
-
.option('-n, --
|
|
259
|
+
.option('-n, --sql-mapping <style>', ['plain', 'quoted', 'hdbcds'], { aliases: [ '--names' ] })
|
|
260
|
+
.option('-d, --sql-dialect <dialect>', ['hana', 'sqlite', 'plain', 'postgres'], { aliases: [ '--dialect' ] })
|
|
260
261
|
.option(' --render-virtual')
|
|
261
262
|
.option(' --joinfk')
|
|
262
|
-
.option('-d, --dialect <dialect>', ['hana', 'sqlite', 'plain', 'postgres'])
|
|
263
263
|
.option('-u, --user <user>')
|
|
264
264
|
.option('-l, --locale <locale>')
|
|
265
265
|
.option('-s, --src <style>', ['sql', 'hdi'])
|
|
@@ -269,6 +269,7 @@ optionProcessor.command('Q, toSql')
|
|
|
269
269
|
.option(' --assert-integrity <mode>', ['true', 'false', 'individual'])
|
|
270
270
|
.option(' --assert-integrity-type <type>', ['RT', 'DB'], { ignoreCase: true })
|
|
271
271
|
.option(' --constraints-in-create-table')
|
|
272
|
+
.option(' --disable-hana-comments')
|
|
272
273
|
.help(`
|
|
273
274
|
Usage: cdsc toSql [options] <files...>
|
|
274
275
|
|
|
@@ -276,7 +277,7 @@ optionProcessor.command('Q, toSql')
|
|
|
276
277
|
|
|
277
278
|
Options
|
|
278
279
|
-h, --help Show this help text
|
|
279
|
-
-n, --
|
|
280
|
+
-n, --sql-mapping <style> Naming style for generated entity and element names:
|
|
280
281
|
plain : (default) Produce SQL table and view names in
|
|
281
282
|
flattened with underscores format (no quotes required)
|
|
282
283
|
quoted : Produce SQL table and view names in original case as in
|
|
@@ -289,7 +290,7 @@ optionProcessor.command('Q, toSql')
|
|
|
289
290
|
combination with "hana" dialect.
|
|
290
291
|
--render-virtual Render virtual elements in views and draft tables
|
|
291
292
|
--joinfk Create JOINs for foreign key accesses
|
|
292
|
-
-d, --dialect <dialect>
|
|
293
|
+
-d, --sql-dialect <dialect> SQL dialect to be generated:
|
|
293
294
|
plain : (default) Common SQL - no assumptions about DB restrictions
|
|
294
295
|
hana : SQL with HANA specific language features
|
|
295
296
|
sqlite : Common SQL for sqlite
|
|
@@ -316,32 +317,34 @@ optionProcessor.command('Q, toSql')
|
|
|
316
317
|
--constraints-in-create-table If set, the foreign key constraints will be rendered as
|
|
317
318
|
part of the "CREATE TABLE" statements rather than as separate
|
|
318
319
|
"ALTER TABLE ADD CONSTRAINT" statements
|
|
320
|
+
--disable-hana-comments Disable rendering of doc comments as SAP HANA comments.
|
|
319
321
|
`);
|
|
320
322
|
|
|
321
323
|
optionProcessor.command('toRename')
|
|
322
324
|
.option('-h, --help')
|
|
323
|
-
.option('-n, --
|
|
325
|
+
.option('-n, --sql-mapping <style>', ['quoted', 'hdbcds'], { aliases: ['--names'] })
|
|
324
326
|
.help(`
|
|
325
327
|
Usage: cdsc toRename [options] <files...>
|
|
326
328
|
|
|
327
329
|
(internal, subject to change): Generate SQL stored procedure containing DDL statements to
|
|
328
330
|
"storedProcedure.sql" that allows to rename existing tables and their columns so that they
|
|
329
|
-
match the result of "toHana" or "toSql" with the "--
|
|
331
|
+
match the result of "toHana" or "toSql" with the "--sql-mapping plain" option.
|
|
330
332
|
|
|
331
333
|
Options
|
|
332
334
|
-h, --help Display this help text
|
|
333
|
-
-n, --
|
|
335
|
+
-n, --sql-mapping <style>
|
|
336
|
+
Assume existing tables were generated with "--sql-mapping <style>":
|
|
334
337
|
quoted : Assume existing SQL tables and views were named in original
|
|
335
338
|
case as in CDL (with dots), but column names were flattened
|
|
336
|
-
with underscores (e.g. resulting from "toHana --
|
|
339
|
+
with underscores (e.g. resulting from "toHana --sql-mapping quoted")
|
|
337
340
|
hdbcds : (default) Assume existing SQL tables, views and columns were
|
|
338
341
|
generated by HANA CDS from the same CDS source (or resulting
|
|
339
|
-
from "toHana --
|
|
342
|
+
from "toHana --sql-mapping hdbcds")
|
|
340
343
|
`);
|
|
341
344
|
|
|
342
345
|
optionProcessor.command('manageConstraints')
|
|
343
346
|
.option('-h, --help')
|
|
344
|
-
.option('-n, --
|
|
347
|
+
.option('-n, --sql-mapping <style>', ['plain', 'quoted', 'hdbcds'], { aliases: ['--names'] })
|
|
345
348
|
.option('-s, --src <style>', ['sql', 'hdi'])
|
|
346
349
|
.option(' --drop')
|
|
347
350
|
.option(' --alter')
|
|
@@ -357,7 +360,8 @@ optionProcessor.command('manageConstraints')
|
|
|
357
360
|
|
|
358
361
|
Options
|
|
359
362
|
-h, --help Display this help text
|
|
360
|
-
-n, --
|
|
363
|
+
-n, --sql-mapping <style>
|
|
364
|
+
Assume existing tables were generated with "--sql-mapping <style>":
|
|
361
365
|
plain : (default) Assume SQL tables were flattened and dots were
|
|
362
366
|
replaced by underscores
|
|
363
367
|
quoted : Assume existing SQL tables and views were named in original
|
|
@@ -379,8 +383,9 @@ optionProcessor.command('manageConstraints')
|
|
|
379
383
|
|
|
380
384
|
optionProcessor.command('toCsn')
|
|
381
385
|
.option('-h, --help')
|
|
382
|
-
.option('-f, --flavor <flavor>', ['client', 'gensrc', 'universal'])
|
|
386
|
+
.option('-f, --csn-flavor <flavor>', ['client', 'gensrc', 'universal'], { aliases: ['--flavor'] })
|
|
383
387
|
.option(' --with-localized')
|
|
388
|
+
.option(' --with-locations')
|
|
384
389
|
.help(`
|
|
385
390
|
Usage: cdsc toCsn [options] <files...>
|
|
386
391
|
|
|
@@ -388,13 +393,15 @@ optionProcessor.command('toCsn')
|
|
|
388
393
|
|
|
389
394
|
Options
|
|
390
395
|
-h, --help Show this help text
|
|
391
|
-
-f, --flavor <flavor> Generate CSN in one of two flavors:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
396
|
+
-f, --csn-flavor <flavor> Generate CSN in one of two flavors:
|
|
397
|
+
client : (default) Standard CSN consumable by clients and backends
|
|
398
|
+
gensrc : CSN specifically for use as a source, e.g. for
|
|
399
|
+
combination with additional "extend" or "annotate"
|
|
400
|
+
statements, but not suitable for consumption by clients or
|
|
401
|
+
backends
|
|
402
|
+
universal: in development (BETA)
|
|
403
|
+
--with-locations Add $location to CSN artifacts. In contrast to \`--enrich-csn\`,
|
|
404
|
+
$location is an object with 'file', 'line' and 'col' properties.
|
|
398
405
|
|
|
399
406
|
Internal options (for testing only, may be changed/removed at any time)
|
|
400
407
|
--with-localized Add localized convenience views to the CSN output.
|
|
@@ -413,6 +420,26 @@ optionProcessor.command('parseCdl')
|
|
|
413
420
|
-h, --help Show this help text
|
|
414
421
|
`);
|
|
415
422
|
|
|
423
|
+
optionProcessor.command('parseOnly')
|
|
424
|
+
.option('-h, --help')
|
|
425
|
+
.option(' --trace-parser')
|
|
426
|
+
.option(' --trace-parser-amb')
|
|
427
|
+
.positionalArgument('<file>')
|
|
428
|
+
.help(`
|
|
429
|
+
Usage: cdsc parseOnly [options] <files...>
|
|
430
|
+
|
|
431
|
+
(internal): Stop compilation after parsing and write messages to <stderr>.
|
|
432
|
+
Per default, nothing is printed. With \`--raw-output +\`, XSN is printed
|
|
433
|
+
to <stdout>.
|
|
434
|
+
|
|
435
|
+
Options
|
|
436
|
+
-h, --help Show this help text
|
|
437
|
+
|
|
438
|
+
Diagnostic options
|
|
439
|
+
--trace-parser Trace parser
|
|
440
|
+
--trace-parser-amb Trace parser ambiguities
|
|
441
|
+
`);
|
|
442
|
+
|
|
416
443
|
optionProcessor.command('explain')
|
|
417
444
|
.option('-h, --help')
|
|
418
445
|
.positionalArgument('<message-id>')
|
|
@@ -428,6 +455,22 @@ optionProcessor.command('explain')
|
|
|
428
455
|
-h, --help Show this help text
|
|
429
456
|
`);
|
|
430
457
|
|
|
458
|
+
optionProcessor.command('inspect')
|
|
459
|
+
.option('-h, --help')
|
|
460
|
+
.option(' --statistics')
|
|
461
|
+
.option(' --propagation <art>')
|
|
462
|
+
.positionalArgument('<files...>')
|
|
463
|
+
.help(`
|
|
464
|
+
Usage: cdsc inspect [options] <files...>
|
|
465
|
+
|
|
466
|
+
(internal): Inspect the CSN model compiled from the provided CDS files.
|
|
467
|
+
|
|
468
|
+
Options
|
|
469
|
+
-h, --help Show this help text
|
|
470
|
+
--statistics Print model statistics
|
|
471
|
+
--propagation <art> Show propagation sources for <art>
|
|
472
|
+
`);
|
|
473
|
+
|
|
431
474
|
module.exports = {
|
|
432
475
|
optionProcessor
|
|
433
476
|
};
|
package/lib/render/toCdl.js
CHANGED
|
@@ -142,11 +142,10 @@ function csnToCdl(csn, options) {
|
|
|
142
142
|
let result = renderAnnotationAssignmentsAndDocComment(ext, env);
|
|
143
143
|
|
|
144
144
|
if (ext.includes && ext.includes.length > 0) {
|
|
145
|
-
// Includes can't be combined with anything in braces {}.
|
|
146
|
-
// are possible through CSN, but in CDL, only one include at once is possible.
|
|
145
|
+
// Includes can't be combined with anything in braces {}.
|
|
147
146
|
const affix = isElementExtend ? 'element ' : '';
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
const includes = ext.includes.map(inc => quotePathIfRequired(inc)).join(', ');
|
|
148
|
+
result += `${env.indent}extend ${affix}${extName} with ${includes};\n`;
|
|
150
149
|
return result;
|
|
151
150
|
}
|
|
152
151
|
|
|
@@ -358,17 +357,21 @@ function csnToCdl(csn, options) {
|
|
|
358
357
|
case 'context':
|
|
359
358
|
case 'service':
|
|
360
359
|
return renderContextOrService(artifactName, art, env);
|
|
360
|
+
|
|
361
361
|
case 'type':
|
|
362
362
|
case 'aspect':
|
|
363
363
|
case 'annotation': // annotation in 'csn.definitions' for compiler v1 compatibility
|
|
364
364
|
return renderTypeOrAnnotation(artifactName, art, env);
|
|
365
|
+
|
|
365
366
|
case 'action':
|
|
366
367
|
case 'function':
|
|
367
368
|
return renderActionOrFunction(artifactName, art, env);
|
|
369
|
+
|
|
368
370
|
case 'event':
|
|
369
371
|
return renderEvent(artifactName, art, env);
|
|
372
|
+
|
|
370
373
|
default:
|
|
371
|
-
throw new ModelError(`Unknown artifact kind: ${art.kind}`);
|
|
374
|
+
throw new ModelError(`to.cdl: Unknown artifact kind: ${art.kind}`);
|
|
372
375
|
}
|
|
373
376
|
}
|
|
374
377
|
|
|
@@ -426,14 +429,16 @@ function csnToCdl(csn, options) {
|
|
|
426
429
|
*/
|
|
427
430
|
function renderEntity(artifactName, art, env) {
|
|
428
431
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
432
|
+
result += env.indent + (art.abstract ? 'abstract ' : '');
|
|
433
|
+
result += `entity ${renderArtifactName(artifactName)}`;
|
|
434
|
+
|
|
435
|
+
if (art.params)
|
|
436
|
+
result += renderParameters(art, env);
|
|
437
|
+
|
|
434
438
|
if (art.includes)
|
|
435
439
|
result += renderIncludes(art.includes);
|
|
436
440
|
result += ' {\n';
|
|
441
|
+
const childEnv = increaseIndent(env);
|
|
437
442
|
for (const name in art.elements) {
|
|
438
443
|
const element = art.elements[name];
|
|
439
444
|
result += renderElement(name, element, childEnv);
|
|
@@ -664,8 +669,11 @@ function csnToCdl(csn, options) {
|
|
|
664
669
|
if (path.ref[0].args)
|
|
665
670
|
result += `(${renderArgs(path.ref[0], ':', env)})`;
|
|
666
671
|
|
|
667
|
-
if (path.ref[0].where)
|
|
668
|
-
|
|
672
|
+
if (path.ref[0].where) {
|
|
673
|
+
const cardinality = path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : '';
|
|
674
|
+
const expr = renderExpr(path.ref[0].where, env, true, true);
|
|
675
|
+
result += `[${cardinality}${expr}]`;
|
|
676
|
+
}
|
|
669
677
|
|
|
670
678
|
// Add any path steps (possibly with parameters and filters) that may follow after that
|
|
671
679
|
if (path.ref.length > 1)
|
|
@@ -841,14 +849,9 @@ function csnToCdl(csn, options) {
|
|
|
841
849
|
const syntax = (art.projection) ? 'projection' : 'entity';
|
|
842
850
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
843
851
|
result += `${env.indent}${art.abstract ? 'abstract ' : ''}${syntax === 'projection' ? 'entity' : syntax} ${renderArtifactName(artifactName)}`;
|
|
844
|
-
if (art.params)
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
result += `(\n${parameters}\n${env.indent}) as `;
|
|
848
|
-
}
|
|
849
|
-
else {
|
|
850
|
-
result += ' as ';
|
|
851
|
-
}
|
|
852
|
+
if (art.params)
|
|
853
|
+
result += renderParameters(art, env);
|
|
854
|
+
result += ' as ';
|
|
852
855
|
result += renderQuery(getNormalizedQuery(art).query, true, syntax, env, [ 'definitions', artifactName, 'query' ], art.elements);
|
|
853
856
|
result += ';\n';
|
|
854
857
|
result += renderQueryElementAnnotations(artifactName, art, env);
|
|
@@ -959,9 +962,10 @@ function csnToCdl(csn, options) {
|
|
|
959
962
|
if (limit.rows !== undefined)
|
|
960
963
|
limitStr += `limit ${renderExpr(limit.rows, limitEnv)}`;
|
|
961
964
|
|
|
962
|
-
if (limit.offset !== undefined)
|
|
963
|
-
|
|
964
|
-
|
|
965
|
+
if (limit.offset !== undefined) {
|
|
966
|
+
const offsetIndent = (limitStr === '') ? '' : `\n${increaseIndent(limitEnv).indent}`;
|
|
967
|
+
limitStr += `${offsetIndent}offset ${renderExpr(limit.offset, limitEnv)}`;
|
|
968
|
+
}
|
|
965
969
|
return limitStr;
|
|
966
970
|
}
|
|
967
971
|
|
|
@@ -1040,10 +1044,9 @@ function csnToCdl(csn, options) {
|
|
|
1040
1044
|
* @return {string}
|
|
1041
1045
|
*/
|
|
1042
1046
|
function renderActionOrFunction(actionName, act, env) {
|
|
1043
|
-
let result =
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
result += (parameters === '') ? '()' : `(\n${parameters}\n${env.indent})`;
|
|
1047
|
+
let result = renderAnnotationAssignmentsAndDocComment(act, env) + env.indent + act.kind;
|
|
1048
|
+
result += ` ${renderArtifactName(actionName)}`;
|
|
1049
|
+
result += renderParameters(act, env);
|
|
1047
1050
|
if (act.returns) {
|
|
1048
1051
|
const actEnv = envAddPath(env, [ 'returns' ]);
|
|
1049
1052
|
result += ` returns ${renderTypeReferenceAndProps(act.returns, actEnv)}`;
|
|
@@ -1053,6 +1056,23 @@ function csnToCdl(csn, options) {
|
|
|
1053
1056
|
return result;
|
|
1054
1057
|
}
|
|
1055
1058
|
|
|
1059
|
+
/**
|
|
1060
|
+
* Render art.params, i.e. list of parameter in parentheses. If there is only one
|
|
1061
|
+
* parameter, a single line is used, otherwise an indented list is used.
|
|
1062
|
+
* If there are no params, an empty list `()` is returned.
|
|
1063
|
+
*
|
|
1064
|
+
* @param {CSN.Artifact} art
|
|
1065
|
+
* @param {CdlRenderEnvironment} env
|
|
1066
|
+
* @returns {string}
|
|
1067
|
+
*/
|
|
1068
|
+
function renderParameters(art, env) {
|
|
1069
|
+
const childEnv = increaseIndent(env);
|
|
1070
|
+
const parameters = Object.keys(art.params || {}).map(name => renderParameter(name, art.params[name], childEnv));
|
|
1071
|
+
if (parameters.length === 0)
|
|
1072
|
+
return '()';
|
|
1073
|
+
return `(\n${parameters.join(',\n')}\n${env.indent})`;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1056
1076
|
/**
|
|
1057
1077
|
* Render an action or function parameter 'par' with name 'parName'. Return the resulting source string (no trailing LF).
|
|
1058
1078
|
*
|
|
@@ -1075,7 +1095,7 @@ function csnToCdl(csn, options) {
|
|
|
1075
1095
|
* @param {string} artifactName
|
|
1076
1096
|
* @param {CSN.Artifact} art
|
|
1077
1097
|
* @param {CdlRenderEnvironment} env
|
|
1078
|
-
* @param {String} [artType] - used for rendering csn.vocabularies, as the annotations there do not have a kind.
|
|
1098
|
+
* @param {String} [artType] - used for rendering csn.vocabularies, as the annotations there do not have a kind.
|
|
1079
1099
|
* @return {string}
|
|
1080
1100
|
*/
|
|
1081
1101
|
function renderTypeOrAnnotation(artifactName, art, env, artType) {
|
|
@@ -1085,9 +1105,11 @@ function csnToCdl(csn, options) {
|
|
|
1085
1105
|
result += renderIncludes(art.includes);
|
|
1086
1106
|
|
|
1087
1107
|
if (!art.type && art.elements) // For nicer output, no colon if unnamed structure is used.
|
|
1088
|
-
result += ` ${renderTypeReferenceAndProps(art, env)}
|
|
1108
|
+
result += ` ${renderTypeReferenceAndProps(art, env)}`;
|
|
1089
1109
|
else
|
|
1090
|
-
result += ` : ${renderTypeReferenceAndProps(art, env)}
|
|
1110
|
+
result += ` : ${renderTypeReferenceAndProps(art, env)}`;
|
|
1111
|
+
// for aspects, but since types don't have `actions` this does not hurt
|
|
1112
|
+
result += `${renderActionsAndFunctions(art, env)};\n`;
|
|
1091
1113
|
return result;
|
|
1092
1114
|
}
|
|
1093
1115
|
|
|
@@ -1373,7 +1395,9 @@ function csnToCdl(csn, options) {
|
|
|
1373
1395
|
}
|
|
1374
1396
|
if (s.where) {
|
|
1375
1397
|
// Filter, possibly with cardinality
|
|
1376
|
-
|
|
1398
|
+
const cardinality = s.cardinality ? (`${s.cardinality.max}: `) : '';
|
|
1399
|
+
const expr = renderExpr(s.where, env, inline, true);
|
|
1400
|
+
result += `[${cardinality}${expr}]`;
|
|
1377
1401
|
}
|
|
1378
1402
|
|
|
1379
1403
|
return result;
|
|
@@ -1516,7 +1540,8 @@ function csnToCdl(csn, options) {
|
|
|
1516
1540
|
* @return {string}
|
|
1517
1541
|
*/
|
|
1518
1542
|
function renderForeignKey(fKey, env) {
|
|
1519
|
-
|
|
1543
|
+
const alias = fKey.as ? (` as ${fKey.as}`) : '';
|
|
1544
|
+
return renderExpr(fKey, env) + alias;
|
|
1520
1545
|
}
|
|
1521
1546
|
|
|
1522
1547
|
/**
|
package/lib/render/toHdbcds.js
CHANGED
|
@@ -839,7 +839,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
839
839
|
* @param {object} [elements] For leading query, the elements of the artifact
|
|
840
840
|
* @returns {string} The rendered query
|
|
841
841
|
*/
|
|
842
|
-
function renderQuery(query, isLeadingQuery, env, path = [], elements) {
|
|
842
|
+
function renderQuery(query, isLeadingQuery, env, path = [], elements = null) {
|
|
843
843
|
let result = '';
|
|
844
844
|
env.skipKeys = !isLeadingQuery;
|
|
845
845
|
// Set operator, like UNION, INTERSECT, ...
|
package/lib/render/toSql.js
CHANGED
|
@@ -117,14 +117,18 @@ function toSqlDdl(csn, options) {
|
|
|
117
117
|
*/
|
|
118
118
|
addColumns: {
|
|
119
119
|
fromElementStrings(tableName, eltStrings) {
|
|
120
|
+
if (options.sqlDialect === 'sqlite') // SQLite can only alter one column at a time
|
|
121
|
+
return eltStrings.map(eltString => `ALTER TABLE ${tableName} ADD ${eltString};`);
|
|
122
|
+
|
|
120
123
|
const elts = options.sqlDialect === 'hana' ? `(${eltStrings.join(', ')})` : `${eltStrings.join(', ')}`;
|
|
121
124
|
return [ `ALTER TABLE ${tableName} ADD ${elts};` ];
|
|
122
125
|
},
|
|
123
126
|
fromElementsObj(artifactName, tableName, elementsObj, env, duplicateChecker) {
|
|
124
127
|
// Only extend with 'ADD' for elements/associations
|
|
125
128
|
// TODO: May also include 'RENAME' at a later stage
|
|
129
|
+
const alterEnv = activateAlterMode(env);
|
|
126
130
|
const elements = Object.entries(elementsObj)
|
|
127
|
-
.map(([ name, elt ]) => renderElement(artifactName, name, elt, duplicateChecker, null,
|
|
131
|
+
.map(([ name, elt ]) => renderElement(artifactName, name, elt, duplicateChecker, null, alterEnv))
|
|
128
132
|
.filter(s => s !== '');
|
|
129
133
|
|
|
130
134
|
if (elements.length)
|
|
@@ -138,10 +142,10 @@ function toSqlDdl(csn, options) {
|
|
|
138
142
|
TODO duplicity check
|
|
139
143
|
*/
|
|
140
144
|
addAssociations(artifactName, tableName, elementsObj, env) {
|
|
141
|
-
return Object.entries(elementsObj)
|
|
145
|
+
return options.sqlDialect === 'hana' ? Object.entries(elementsObj)
|
|
142
146
|
.map(([ name, elt ]) => renderAssociationElement(name, elt, env))
|
|
143
147
|
.filter(s => s !== '')
|
|
144
|
-
.map(eltStr => `ALTER TABLE ${tableName} ADD ASSOCIATION (${eltStr});`);
|
|
148
|
+
.map(eltStr => `ALTER TABLE ${tableName} ADD ASSOCIATION (${eltStr});`) : [];
|
|
145
149
|
},
|
|
146
150
|
/*
|
|
147
151
|
Render key addition as HANA SQL.
|
|
@@ -159,7 +163,7 @@ function toSqlDdl(csn, options) {
|
|
|
159
163
|
Render association removals as HANA SQL.
|
|
160
164
|
*/
|
|
161
165
|
dropAssociation(tableName, sqlId) {
|
|
162
|
-
return [ `ALTER TABLE ${tableName} DROP ASSOCIATION ${sqlId};` ];
|
|
166
|
+
return options.sqlDialect === 'hana' ? [ `ALTER TABLE ${tableName} DROP ASSOCIATION ${sqlId};` ] : [];
|
|
163
167
|
},
|
|
164
168
|
/*
|
|
165
169
|
Render primary-key removals as HANA SQL.
|
|
@@ -200,7 +204,7 @@ function toSqlDdl(csn, options) {
|
|
|
200
204
|
Render comment string.
|
|
201
205
|
*/
|
|
202
206
|
comment(comment) {
|
|
203
|
-
return comment && renderStringForSql(comment, options.sqlDialect) || 'NULL';
|
|
207
|
+
return comment && renderStringForSql(getHanaComment({ doc: comment }), options.sqlDialect) || 'NULL';
|
|
204
208
|
},
|
|
205
209
|
/*
|
|
206
210
|
Alter SQL snippet for entity.
|
|
@@ -434,7 +438,7 @@ function toSqlDdl(csn, options) {
|
|
|
434
438
|
function getEltStr(defVariant, eltName) {
|
|
435
439
|
return defVariant.target
|
|
436
440
|
? renderAssociationElement(eltName, defVariant, env)
|
|
437
|
-
: renderElement(artifactName, eltName, defVariant, null, null, env);
|
|
441
|
+
: renderElement(artifactName, eltName, defVariant, null, null, activateAlterMode(env));
|
|
438
442
|
}
|
|
439
443
|
function getEltStrNoProps(defVariant, eltName, ...props) {
|
|
440
444
|
const defNoProps = Object.assign({}, defVariant);
|
|
@@ -461,7 +465,7 @@ function toSqlDdl(csn, options) {
|
|
|
461
465
|
// Change entity properties
|
|
462
466
|
if (migration.properties) {
|
|
463
467
|
for (const [ prop, def ] of Object.entries(migration.properties)) {
|
|
464
|
-
if (prop === 'doc') {
|
|
468
|
+
if (prop === 'doc' && !options.disableHanaComments) { // def.new may be `null`
|
|
465
469
|
const alterComment = render.alterEntityComment(tableName, def.new);
|
|
466
470
|
addMigration(resultObj, artifactName, false, alterComment);
|
|
467
471
|
}
|
|
@@ -527,7 +531,7 @@ function toSqlDdl(csn, options) {
|
|
|
527
531
|
}
|
|
528
532
|
}
|
|
529
533
|
|
|
530
|
-
if (def.old.doc !== def.new.doc) {
|
|
534
|
+
if (!options.disableHanaComments && def.old.doc !== def.new.doc) {
|
|
531
535
|
const eltStrOldNoDoc = getEltStrNoProps(def.old, eltName, 'doc');
|
|
532
536
|
const eltStrNewNoDoc = getEltStrNoProps(def.new, eltName, 'doc');
|
|
533
537
|
if (eltStrOldNoDoc === eltStrNewNoDoc) { // only `doc` changed
|
|
@@ -753,7 +757,7 @@ function toSqlDdl(csn, options) {
|
|
|
753
757
|
duplicateChecker.addElement(quotedElementName, elm.$location, elementName);
|
|
754
758
|
|
|
755
759
|
let result = `${env.indent + quotedElementName} ${renderTypeReference(artifactName, elementName, elm)
|
|
756
|
-
}${renderNullability(elm, true)}`;
|
|
760
|
+
}${renderNullability(elm, true, env.alterMode)}`;
|
|
757
761
|
if (elm.default)
|
|
758
762
|
result += ` DEFAULT ${renderExpr(elm.default, env)}`;
|
|
759
763
|
|
|
@@ -1395,9 +1399,15 @@ function toSqlDdl(csn, options) {
|
|
|
1395
1399
|
*
|
|
1396
1400
|
* @param {object} obj Object to render for
|
|
1397
1401
|
* @param {boolean} treatKeyAsNotNull Whether to render KEY as not null
|
|
1402
|
+
* @param {boolean} deltaMode Look for a $notNull and use that with precedence over notNull
|
|
1398
1403
|
* @returns {string} NULL/NOT NULL or ''
|
|
1399
1404
|
*/
|
|
1400
|
-
function renderNullability(obj, treatKeyAsNotNull = false) {
|
|
1405
|
+
function renderNullability(obj, treatKeyAsNotNull = false, deltaMode = false) {
|
|
1406
|
+
if (deltaMode && obj.$notNull !== undefined) { // can be set via compare.js if it goes from "not null" to implicit "null"
|
|
1407
|
+
return obj.$notNull ? ' NOT NULL' : ' NULL';
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
|
|
1401
1411
|
if (obj.notNull === undefined && !(obj.key && treatKeyAsNotNull)) {
|
|
1402
1412
|
// Attribute not set at all
|
|
1403
1413
|
return '';
|
|
@@ -1492,6 +1502,7 @@ function toSqlDdl(csn, options) {
|
|
|
1492
1502
|
}
|
|
1493
1503
|
else if (x.ref[0] === '$now') { // TODO: Can there be cases where $now is followed by something?
|
|
1494
1504
|
switch (options.sqlDialect) {
|
|
1505
|
+
case 'plain':
|
|
1495
1506
|
case 'sqlite':
|
|
1496
1507
|
case 'hana':
|
|
1497
1508
|
return 'CURRENT_TIMESTAMP';
|
|
@@ -1531,7 +1542,7 @@ function toSqlDdl(csn, options) {
|
|
|
1531
1542
|
return 'SESSION_CONTEXT(\'LOCALE\')';
|
|
1532
1543
|
return '\'en\''; // default language
|
|
1533
1544
|
}
|
|
1534
|
-
// Basically: Second path step was invalid, do nothing - should not happen
|
|
1545
|
+
// Basically: Second path step was invalid, do nothing - should not happen.
|
|
1535
1546
|
return null;
|
|
1536
1547
|
}
|
|
1537
1548
|
/**
|
|
@@ -1654,6 +1665,15 @@ function toSqlDdl(csn, options) {
|
|
|
1654
1665
|
function increaseIndent(env) {
|
|
1655
1666
|
return Object.assign({}, env, { indent: `${env.indent} ` });
|
|
1656
1667
|
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Returns a copy of 'env' with alterMode set to true
|
|
1670
|
+
*
|
|
1671
|
+
* @param {object} env Render environment
|
|
1672
|
+
* @returns {object} Render environment with alterMode
|
|
1673
|
+
*/
|
|
1674
|
+
function activateAlterMode(env) {
|
|
1675
|
+
return Object.assign({ alterMode: true }, env);
|
|
1676
|
+
}
|
|
1657
1677
|
}
|
|
1658
1678
|
|
|
1659
1679
|
/**
|
|
@@ -286,8 +286,8 @@ const cdsToSqlTypes = {
|
|
|
286
286
|
'cds.LargeString': 'text',
|
|
287
287
|
'cds.hana.CLOB': 'text',
|
|
288
288
|
'cds.LargeBinary': 'bytea',
|
|
289
|
-
'cds.Binary': '
|
|
290
|
-
'cds.hana.BINARY': '
|
|
289
|
+
'cds.Binary': 'bytea',
|
|
290
|
+
'cds.hana.BINARY': 'bytea',
|
|
291
291
|
'cds.Double': 'double precision',
|
|
292
292
|
'cds.hana.TINYINT': 'INTEGER',
|
|
293
293
|
},
|
|
@@ -358,11 +358,10 @@ function hasHanaComment(obj, options) {
|
|
|
358
358
|
* Return the comment of the given artifact or element.
|
|
359
359
|
* Uses the first block (everything up to the first empty line (double \n)).
|
|
360
360
|
* Remove leading/trailing whitespace.
|
|
361
|
-
* Does not escape any characters.
|
|
361
|
+
* Does not escape any characters, use e.g. `getEscapedHanaComment()` for HDBCDS.
|
|
362
362
|
*
|
|
363
363
|
* @param {CSN.Artifact|CSN.Element} obj
|
|
364
364
|
* @returns {string}
|
|
365
|
-
* @todo Warning/info to user?
|
|
366
365
|
*/
|
|
367
366
|
function getHanaComment(obj) {
|
|
368
367
|
return obj.doc.split('\n\n')[0].trim();
|