@sap/cds 7.8.1 → 7.9.0

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.
Files changed (137) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/_i18n/i18n_ar.properties +3 -0
  3. package/_i18n/i18n_cs.properties +3 -0
  4. package/_i18n/i18n_da.properties +3 -0
  5. package/_i18n/i18n_es_MX.properties +3 -0
  6. package/_i18n/i18n_fi.properties +3 -0
  7. package/_i18n/i18n_hu.properties +6 -0
  8. package/_i18n/i18n_ko.properties +3 -0
  9. package/_i18n/i18n_ms.properties +3 -0
  10. package/_i18n/i18n_nl.properties +3 -0
  11. package/_i18n/i18n_no.properties +3 -0
  12. package/_i18n/i18n_ro.properties +3 -0
  13. package/_i18n/i18n_sv.properties +3 -0
  14. package/_i18n/i18n_th.properties +3 -0
  15. package/_i18n/i18n_tr.properties +6 -0
  16. package/_i18n/i18n_zh_TW.properties +3 -0
  17. package/bin/serve.js +5 -5
  18. package/lib/auth/basic-auth.js +1 -1
  19. package/lib/compile/cdsc.js +33 -6
  20. package/lib/compile/etc/_localized.js +14 -7
  21. package/lib/compile/for/lean_drafts.js +9 -0
  22. package/lib/compile/to/edm-files.js +116 -0
  23. package/lib/compile/to/edm.js +8 -1
  24. package/lib/compile/to/hdbtabledata.js +3 -3
  25. package/lib/compile/to/sql.js +4 -2
  26. package/lib/compile/to/yaml.js +22 -21
  27. package/lib/dbs/cds-deploy.js +5 -6
  28. package/lib/env/cds-env.js +7 -0
  29. package/lib/env/cds-requires.js +20 -1
  30. package/lib/env/defaults.js +21 -5
  31. package/lib/env/schemas/cds-package.js +1 -1
  32. package/lib/env/schemas/cds-rc.js +85 -4
  33. package/lib/index.js +1 -1
  34. package/lib/linked/classes.js +2 -2
  35. package/lib/linked/entities.js +10 -0
  36. package/lib/linked/models.js +1 -1
  37. package/lib/plugins.js +1 -1
  38. package/lib/ql/INSERT.js +17 -3
  39. package/lib/ql/Query.js +4 -0
  40. package/lib/ql/infer.js +1 -1
  41. package/lib/req/request.js +1 -1
  42. package/lib/srv/cds-serve.js +1 -0
  43. package/lib/srv/middlewares/cds-context.js +1 -1
  44. package/lib/srv/protocols/odata-v4.js +5 -6
  45. package/lib/srv/srv-models.js +9 -2
  46. package/lib/utils/cds-test.js +2 -0
  47. package/lib/utils/cds-utils.js +9 -4
  48. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
  49. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
  50. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  51. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -1
  52. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +3 -6
  53. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +22 -10
  54. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +4 -4
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +4 -3
  56. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +1 -1
  57. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +4 -1
  58. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  59. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +38 -1
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +2 -2
  61. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +32 -21
  62. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +1 -1
  63. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +1 -2
  64. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +0 -10
  65. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +3 -1
  66. package/libx/_runtime/cds-services/services/utils/compareJson.js +2 -274
  67. package/libx/_runtime/{cds-services/services → common}/Service.js +39 -29
  68. package/libx/_runtime/common/generic/auth/autoexpose.js +41 -0
  69. package/libx/_runtime/common/generic/auth/index.js +2 -0
  70. package/libx/_runtime/common/generic/auth/readOnly.js +0 -11
  71. package/libx/_runtime/common/generic/auth/restrict.js +6 -5
  72. package/libx/_runtime/common/generic/auth/utils.js +1 -1
  73. package/libx/_runtime/common/generic/crud.js +5 -8
  74. package/libx/_runtime/common/generic/etag.js +8 -6
  75. package/libx/_runtime/common/generic/sorting.js +2 -2
  76. package/libx/_runtime/common/i18n/messages.properties +1 -0
  77. package/libx/_runtime/{cds-services/services → common}/utils/columns.js +4 -4
  78. package/libx/_runtime/common/utils/compareJson.js +274 -0
  79. package/libx/_runtime/common/utils/cqn2cqn4sql.js +1 -1
  80. package/libx/_runtime/{cds-services/services → common}/utils/differ.js +8 -8
  81. package/libx/_runtime/common/utils/ensureIEEE754.js +29 -0
  82. package/libx/_runtime/common/utils/{postProcessing.js → postProcess.js} +1 -3
  83. package/libx/_runtime/common/utils/resolveView.js +0 -16
  84. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -1
  85. package/libx/_runtime/common/utils/search2cqn4sql.js +1 -1
  86. package/libx/_runtime/common/utils/streamProp.js +9 -2
  87. package/libx/_runtime/common/utils/ucsn.js +1 -1
  88. package/libx/_runtime/db/expand/expandCQNToJoin.js +5 -3
  89. package/libx/_runtime/db/generic/rewrite.js +7 -13
  90. package/libx/_runtime/fiori/generic/activate.js +1 -1
  91. package/libx/_runtime/fiori/generic/edit.js +1 -1
  92. package/libx/_runtime/fiori/generic/prepare.js +1 -1
  93. package/libx/_runtime/fiori/lean-draft.js +151 -46
  94. package/libx/_runtime/fiori/utils/handler.js +1 -1
  95. package/libx/_runtime/hana/execute.js +6 -2
  96. package/libx/_runtime/hana/search2cqn4sql.js +1 -1
  97. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
  98. package/libx/_runtime/messaging/event-broker.js +212 -0
  99. package/libx/_runtime/remote/Service.js +9 -32
  100. package/libx/_runtime/remote/utils/client.js +13 -21
  101. package/libx/_runtime/sqlite/convertAssocToOneManaged.js +7 -1
  102. package/libx/_runtime/sqlite/execute.js +8 -3
  103. package/libx/_runtime/ucl/Service.js +259 -0
  104. package/libx/common/assert/index.js +6 -11
  105. package/libx/common/assert/validation.js +6 -1
  106. package/libx/odata/index.js +47 -25
  107. package/libx/odata/middleware/batch.js +8 -7
  108. package/libx/odata/middleware/create.js +42 -16
  109. package/libx/odata/middleware/delete.js +18 -11
  110. package/libx/odata/middleware/metadata.js +15 -14
  111. package/libx/odata/middleware/operation.js +30 -40
  112. package/libx/odata/middleware/parse.js +2 -3
  113. package/libx/odata/middleware/read.js +59 -52
  114. package/libx/odata/middleware/service-document.js +7 -7
  115. package/libx/odata/middleware/stream.js +26 -24
  116. package/libx/odata/middleware/update.js +53 -92
  117. package/libx/odata/parse/afterburner.js +45 -47
  118. package/libx/odata/parse/grammar.peggy +3 -3
  119. package/libx/odata/parse/multipartToJson.js +10 -22
  120. package/libx/odata/parse/parser.js +1 -1
  121. package/libx/odata/utils/etag.js +13 -0
  122. package/libx/odata/utils/handler.js +120 -0
  123. package/libx/odata/utils/index.js +15 -2
  124. package/libx/odata/utils/metaInfo.js +410 -0
  125. package/libx/odata/utils/path.js +5 -2
  126. package/libx/odata/utils/readAfterWrite.js +23 -0
  127. package/libx/odata/utils/result.js +4 -5
  128. package/libx/rest/RestAdapter.js +4 -13
  129. package/libx/rest/middleware/parse.js +40 -7
  130. package/package.json +1 -1
  131. package/server.js +2 -1
  132. package/libx/_runtime/cds-services/util/dataProcessUtils.js +0 -93
  133. package/libx/_runtime/common/utils/thenable.js +0 -51
  134. package/libx/_runtime/rest/service.js +0 -2
  135. package/libx/odata/parse/parseToCqn.js +0 -39
  136. package/libx/rest/middleware/input.js +0 -54
  137. package/libx/rest/middleware/payload.js +0 -13
package/CHANGELOG.md CHANGED
@@ -4,6 +4,50 @@
4
4
  - The format is based on [Keep a Changelog](http://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## Version 7.9.0 - 2024-04-30
8
+
9
+ ### Added
10
+
11
+ - Option `cds.env.sql.transitive_localized_views: false` to skip generating transitive localized views for entities which don't have own localized elements, but only associations to such. Supported for Java and new database services in Node.js (ignored for old ones).
12
+ - Option `cds.env.sql.native_hana_associations: false` to skip generating native HANA associations.
13
+ - Running `cds compile --to sql` with `@cap-js/sqlite` installed now uses `session_context('$user.locale')` in generated DDL statements instead of generating static localized views for 'en', 'fr', and 'de' (same for `cds.deploy`).
14
+ - `api`: export reserved keywords for postgres via `cds.compiler.to.sql.keywords.postgres`
15
+ - Kind `legacy-hana` and profile `better-hana` for local testing scenarios.
16
+ - Support for PDF files (MIME type `application/pdf`) when the `cds.env.features.odata_new_adapter` flag is set to `true`
17
+ - Lean draft: Support for filtered compositions (remain in the document)
18
+ - Support for `COUNT_DISTINCT` as OData data aggregation default method
19
+ - Better support for `profiles` in cds schema for `package.json` and `.cdsrc.json`
20
+ - Performance improvement for generating `@odata.context` url if `cds.features.odata_new_parser` is enabled
21
+ - Alpha support for SAP Event Broker-based messaging (kind `event-broker`)
22
+
23
+ ### Changed
24
+
25
+ - Deprecated *INSERT.into(...) **.as** (SELECT...)* → use *INSERT.into(...) **.entries** (SELECT...)* instead.
26
+ - Default value of `cds.env.log.mask_headers` changed to `['/authorization/i', '/cookie/i', '/cert/i', '/ssl/i']` (adding `'/cert/i'` and `'/ssl/i'`)
27
+ - Error messages for entities annotated with '@cds.autoexpose'
28
+ - For Java apps `cds.sql.transitive_localized_views` now defaults to `false` to create less database views.
29
+ - For Java apps `cdsc.betterSqliteSessionVariables` now defaults to `true` to enable session variables on H2 and SQLite by default.
30
+
31
+ ### Fixed
32
+
33
+ - `cds.compile.to.yaml` produced invalid YAML for compacted lines
34
+ - Handling of If-None-Match header for non-existing entity
35
+ - Revert json schema for cds schemas to `draft-07` to prevent VS Code warnings about unsupported schema features.
36
+ - Remote services: JSON representation of error shall include `request` and `response`
37
+ - Aliasing of associated entity column in case of expand by CQN build with joins.
38
+ - `$apply` scenarios when used alongside `cds.env.features.odata_new_adapter = true` and the new database layer
39
+ - ETag handling combined with where restrictions
40
+ - `cds compile --to hdbtabledata` now correctly supports CSV files using format `.texts_<lang>.csv`. Before the `include_filter` wasn't set in the generated `.hdbtabledata` files.
41
+ - `cds` commands no longer crash when executed in the `@sap/cds` installation dir.
42
+ - `cds.infer`: exposed association of query is inferred as `cds.Association` and not as it's target
43
+
44
+ ## Version 7.8.2 - 2024-04-22
45
+
46
+ ### Fixed
47
+
48
+ - `.find` and `.filter` in `linked.entities()` now returns values instead of names
49
+ - `cds.app.serve.from(pkg,folder)` did not consider `pkg` for serving static resources
50
+
7
51
  ## Version 7.8.1 - 2024-04-11
8
52
 
9
53
  ### Fixed
@@ -70,6 +70,9 @@ LanguageCode=\u0631\u0645\u0632 \u0627\u0644\u0644\u063A\u0629
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=\u0631\u0645\u0632 \u0627\u0644\u062F\u0648\u0644\u0629 \u0627\u0644\u0645\u062D\u062F\u062F \u062D\u0633\u0628 ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=\u0631\u0645\u0632 \u0627\u0644\u0645\u0646\u0637\u0642\u0629 \u0627\u0644\u0632\u0645\u0646\u064A\u0629
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=\u0645\u0639\u0631\u0641 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=K\u00F3d jazyka
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=K\u00F3d jazyka zadan\u00FD dle ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=K\u00F3d \u010Dasov\u00E9ho p\u00E1sma
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=ID u\u017Eivatele
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Sprogkode
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=Sprogkode som angivet af ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Tidszonekode
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=Bruger-ID
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=C\u00F3digo de idioma
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=C\u00F3digo de idioma seg\u00FAn especificado por ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=C\u00F3digo de zona horaria
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=ID de usuario
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Kielikoodi
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=ISO 639-1:n mukainen kielikoodi
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Aikavy\u00F6hykekoodi
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=K\u00E4ytt\u00E4j\u00E4tunnus
75
78
 
@@ -49,6 +49,9 @@ CurrencyCode.Description=P\u00E9nznem k\u00F3dja ISO 4217 szerint
49
49
  #XTIT: Currency Symbol
50
50
  CurrencySymbol=P\u00E9nznem szimb\u00F3luma
51
51
 
52
+ #XTIT: Currency Minor Unit Fractions (Answer to: "How many fractions has a currency's minor unit?", e.g. "0" or "2")
53
+ CurrencyMinorUnit=P\u00E9nznem seg\u00E9degys\u00E9g-h\u00E1nyadok
54
+
52
55
  #XTIT: Country/Region
53
56
  Country=Orsz\u00E1g/r\u00E9gi\u00F3
54
57
 
@@ -67,6 +70,9 @@ LanguageCode=Nyelvk\u00F3d
67
70
  #XTIT: Language Code Description
68
71
  LanguageCode.Description=P\u00E9nznem k\u00F3dja ISO 639-1 szerint
69
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Id\u0151z\u00F3na k\u00F3dja
75
+
70
76
  #XTIT: User Identifier
71
77
  UserID=Felhaszn\u00E1l\u00F3azonos\u00EDt\u00F3
72
78
 
@@ -70,6 +70,9 @@ LanguageCode=\uC5B8\uC5B4 \uCF54\uB4DC
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=ISO 639-1\uC5D0\uC11C \uC9C0\uC815\uD55C \uC5B8\uC5B4 \uCF54\uB4DC
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=\uC2DC\uAC04\uB300 \uCF54\uB4DC
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=\uC0AC\uC6A9\uC790 ID
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Kod Bahasa
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=Kod bahasa seperti yang dinyatakan dalam ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Kod Zon Waktu
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=ID Pengguna
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Taalcode
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=Taalcode zoals gespecificeerd door ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Code tijdzone
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=Gebruikers-ID
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Spr\u00E5kkode
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=Spr\u00E5kkode som definert i ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Kode for tidssone
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=Bruker-ID
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Cod de limb\u0103
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=Cod de limb\u0103 a\u0219a cum este specificat de ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Cod fus orar
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=ID utilizator
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=Spr\u00E5kkod
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=Spr\u00E5kkod enligt ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Tidszonskod
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=Anv\u00E4ndar-ID
75
78
 
@@ -70,6 +70,9 @@ LanguageCode=\u0E23\u0E2B\u0E31\u0E2A\u0E20\u0E32\u0E29\u0E32
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=\u0E23\u0E2B\u0E31\u0E2A\u0E20\u0E32\u0E29\u0E32\u0E15\u0E32\u0E21\u0E17\u0E35\u0E48\u0E23\u0E30\u0E1A\u0E38\u0E43\u0E19 ISO 639-1
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=\u0E23\u0E2B\u0E31\u0E2A\u0E40\u0E02\u0E15\u0E40\u0E27\u0E25\u0E32
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=ID \u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49
75
78
 
@@ -49,6 +49,9 @@ CurrencyCode.Description=ISO 4217'ye g\u00F6re belirtilen para birimi kodu
49
49
  #XTIT: Currency Symbol
50
50
  CurrencySymbol=Para birimi sembol\u00FC
51
51
 
52
+ #XTIT: Currency Minor Unit Fractions (Answer to: "How many fractions has a currency's minor unit?", e.g. "0" or "2")
53
+ CurrencyMinorUnit=Para biriminin k\u00FC\u00E7\u00FCk birim kesirleri
54
+
52
55
  #XTIT: Country/Region
53
56
  Country=\u00DClke/b\u00F6lge
54
57
 
@@ -67,6 +70,9 @@ LanguageCode=Dil kodu
67
70
  #XTIT: Language Code Description
68
71
  LanguageCode.Description=ISO 639-1'e g\u00F6re belirtilen dil kodu
69
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=Saat dilimi kodu
75
+
70
76
  #XTIT: User Identifier
71
77
  UserID=Kullan\u0131c\u0131 tan\u0131t\u0131c\u0131s\u0131
72
78
 
@@ -70,6 +70,9 @@ LanguageCode=\u8A9E\u8A00\u4EE3\u78BC
70
70
  #XTIT: Language Code Description
71
71
  LanguageCode.Description=\u5DF2\u6309 ISO 639-1 \u6307\u5B9A\u516C\u53F8\u4EE3\u78BC
72
72
 
73
+ #XTIT Time zone code
74
+ TimeZoneCode=\u6642\u5340\u4EE3\u78BC
75
+
73
76
  #XTIT: User Identifier
74
77
  UserID=\u4F7F\u7528\u8005 ID
75
78
 
package/bin/serve.js CHANGED
@@ -300,26 +300,26 @@ function _prepare_logging () { // NOSONAR
300
300
  // print config deprecation warnings
301
301
  if (cds.env.features.deprecated !== 'off') {
302
302
  cds.once ('listening', () => {
303
- // Remove with cds 8
303
+ // Remove with cds^8
304
304
  if (cds.env.drafts?.cancellationTimeout)
305
305
  cds.utils.deprecated({
306
306
  old: 'cds.drafts.cancellationTimeout',
307
307
  use: 'cds.fiori.draft_lock_timeout with adapted value'
308
308
  })
309
309
 
310
- // Remove with cds 8
310
+ // Remove with cds^8
311
311
  if (!cds.env.fiori.lean_draft)
312
312
  cds.utils.deprecated({ old: 'cds.fiori.lean_draft' })
313
313
 
314
- // Remove with cds 8
314
+ // Remove with cds^8
315
315
  if (!cds.requires.middlewares)
316
316
  cds.utils.deprecated({ old: 'cds.requires.middlewares' })
317
317
 
318
- // Remove with cds 8
318
+ // Remove with cds^8
319
319
  if (cds.env.features.serve_on_root)
320
320
  cds.utils.deprecated({ old: 'cds.features.serve_on_root', use: '@path annotation or adapt your consumers' })
321
321
 
322
- // Remove with cds 8
322
+ // Remove with cds^8
323
323
  if (cds.env.features.stream_compat)
324
324
  cds.utils.deprecated({ old: 'cds.features.stream_compat' })
325
325
  })
@@ -31,7 +31,7 @@ module.exports = function basic_auth (options) {
31
31
  function login (reason='') {
32
32
  const req=this, res=req.res
33
33
  // REVISIT: this json response is needed to be OData compliant. however, we should probably throw an error anyway so that a custom error middleware can get invoked.
34
- res.set('WWW-Authenticate', `Basic realm="Users"`).status(401).json({ error: { code: '401', message: 'Unauthorized' } })
34
+ res.set('www-authenticate', `Basic realm="Users"`).status(401).json({ error: { code: '401', message: 'Unauthorized' } })
35
35
  LOG.info (req.method, decodeURIComponent(req.path), '>', res.statusCode, res.statusMessage, ...(!reason ? [] : ['-', reason]))
36
36
  }
37
37
  }
@@ -61,21 +61,48 @@ const _options = {for: Object.assign (_options4, {
61
61
  })
62
62
  },
63
63
 
64
- sql(o,_env) {
64
+ sql (_o, _env, _conf = cds.requires.db || cds.requires.kinds.sql) {
65
65
  // REVISIT: compiler requires to only provide assertIntegrityType if defined
66
- let { assert_integrity } = cds.env.features
67
- let constraints = assert_integrity && { assertIntegrityType: assert_integrity.toUpperCase() }
68
- return _options4 ({ ...constraints, ..._env||cds.env.sql, ...o }, {
66
+ if (_o?._4sql) return _o
67
+ const o = _options4 ({ ..._env||cds.env.sql, ..._o, _4sql: true }, {
69
68
  sql_mapping : 'names', //> legacy
70
69
  sqlDialect : 'dialect', //> legacy
71
70
  sqlMapping : 'names',
72
71
  dialect : 'sqlDialect',
73
72
  names : (o,v) => v !== 'plain' ? o.sqlMapping = v : undefined,
74
73
  })
74
+ if (_conf?.impl === '@cap-js/sqlite') {
75
+ o.fewerLocalizedViews = !cds.env.sql.transitive_localized_views
76
+ o.betterSqliteSessionVariables = true
77
+ // REVISIT: compiler only considers o.betterSqliteSessionVariables if o.sqlDialect == 'sqlite'.
78
+ // Yet, dialect: 'plain' is configured in cap/sflight -> below is a dirty hack which overrides that.
79
+ // We should rather have a proper way to configure the dialect in the cap/sflight project, and/or
80
+ // have a better way to handle o.betterSqliteSessionVariables in compiler, independent of dialect.
81
+ if (!_o?.dialect && (!cds.env.sql.dialect || cds.env.sql.dialect === 'plain')) o.sqlDialect = 'sqlite'
82
+ }
83
+ else if (_conf?.impl === '@cap-js/hana') {
84
+ o.fewerLocalizedViews = !cds.env.sql.transitive_localized_views
85
+ o.withHanaAssociations = cds.env.sql.native_hana_associations
86
+ }
87
+ else if (!cds.db && !cds.requires.db) { // e.g. for Java
88
+ o.fewerLocalizedViews = !cds.env.sql.transitive_localized_views
89
+ o.withHanaAssociations = cds.env.sql.native_hana_associations
90
+ if (_conf?.impl === '@cap-js/sqlite') {
91
+ o.betterSqliteSessionVariables = true
92
+ // REVISIT: compiler only considers o.betterSqliteSessionVariables if o.sqlDialect == 'sqlite'.
93
+ // Yet, dialect: 'plain' is configured in cap/sflight -> below is a dirty hack which overrides that.
94
+ // We should rather have a proper way to configure the dialect in the cap/sflight project, and/or
95
+ // have a better way to handle o.betterSqliteSessionVariables in compiler, independent of dialect.
96
+ if (!_o?.dialect && (!cds.env.sql.dialect || cds.env.sql.dialect === 'plain')) o.sqlDialect = 'sqlite'
97
+ }
98
+ }
99
+ // console.trace(o)
100
+ if (cds.env.features.assert_integrity) o.assertIntegrityType = cds.env.features.assert_integrity.toUpperCase()
101
+ return o
75
102
  },
76
103
 
77
104
  hana(o) {
78
- let cdsc = this.sql (o, cds.env.hana) // returns clone
105
+ let cdsc = this.sql (o, cds.env.hana, cds.requires.kinds.hana) // returns clone
79
106
  cdsc.sqlChangeMode ??= cdsc.journal && cdsc.journal['change-mode']
80
107
  cdsc.disableHanaComments ??= !cdsc.comments
81
108
  delete cdsc.journal // cleanup avoiding side effects
@@ -138,4 +165,4 @@ module.exports = exports = {__proto__:compile, _options,
138
165
  compile.to.cdl // smart* functions
139
166
  ),
140
167
  },
141
- }
168
+ }
@@ -11,14 +11,15 @@ const _been_here = Symbol('is _localized')
11
11
 
12
12
 
13
13
  /**
14
- * In case of, for each localized_<view> we get from the compiler,
15
- * create additional views localized_<locale>_<views>
14
+ * In case of old SQLite service, for each localized_<view> we get from the
15
+ * compiler, create additional views localized_<locale>_<views>
16
16
  */
17
17
  function unfold_ddl (ddl, csn, o={}) { // NOSONAR
18
+ if (o.betterSqliteSessionVariables) return ddl
19
+ if (o.fewerLocalizedViews) return ddl
18
20
  const _locales = _locales_4sql[o.dialect]; if (!_locales) return ddl
19
21
  const localized_views = ddl.filter (each => each.startsWith('CREATE VIEW localized_') || each.startsWith('DROP VIEW localized_'))
20
22
  // REVISIT: analyze ddl statements. Problem is with schevo calling this function containing only drops
21
- if (o.sqlDialect === 'sqlite' && o.betterSqliteSessionVariables) return ddl
22
23
  for (const localized_view of localized_views) {
23
24
  for (const locale of _locales) ddl.push (localized_view
24
25
  .replace (/localized_/g, `localized_${locale}_`)
@@ -45,9 +46,16 @@ function unfold_csn (m) { // NOSONAR
45
46
  DEBUG && DEBUG ('unfolding csn...')
46
47
  const pass2 = []
47
48
 
48
- const _conf = env.requires.db || env.requires.sql || env.requires.kinds && env.requires.kinds.sql
49
+ // REVISIT: Fixing $localized obtained from compiler when fewerLocalizedViews is set
50
+ const o = cds.compiler._options.for.sql()
51
+ if (o.fewerLocalizedViews) for (let each in m.definitions) {
52
+ const d = m.definitions [each]
53
+ if (d.$localized && d.elements && !d.elements.localized) delete d.$localized
54
+ }
55
+
56
+ const _conf = env.requires.db || env.requires.sql || env.requires.kinds.sql
49
57
  const _on_sqlite = _conf.kind === 'sqlite' || _conf.dialect === 'sqlite'
50
- const _locales = _on_sqlite && _locales_4sql.sqlite
58
+ const _locales = !o.fewerLocalizedViews && !o.betterSqliteSessionVariables && _on_sqlite && _locales_4sql.sqlite
51
59
 
52
60
  // Pass 1 - add localized.<locale> entities and views
53
61
  for (const each in cds.linked(m).definitions) {
@@ -60,7 +68,6 @@ function unfold_csn (m) { // NOSONAR
60
68
  if (_localized_entries !== false && _is_localized(d)) {
61
69
  _add_proxy4 (d,`localized.${each}`, x => pass2.push([x]))
62
70
  // if running on sqlite add additional localized.<locale>. views
63
- if (_conf?.impl === '@cap-js/sqlite') continue
64
71
  if (_locales) for (const locale of _locales) {
65
72
  _add_proxy4 (d,`localized.${locale}.${each}`, x => pass2.push([x,locale]))
66
73
  }
@@ -73,7 +80,7 @@ function unfold_csn (m) { // NOSONAR
73
80
  for (const each in x.elements) {
74
81
  const e = x.elements [each]
75
82
  if (e._target && _is_localized(e._target)) {
76
- const elements = overlayed || (overlayed = x.elements = {__proto__:x.elements})
83
+ const elements = overlayed ??= x.elements = {__proto__:x.elements}
77
84
  const target = locale ? `localized.${locale}.${e.target}` : `localized.${e.target}`
78
85
  const _target = m.definitions[target]
79
86
  if (_target) {
@@ -107,8 +107,16 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
107
107
  draft['@Capabilities.NavigationRestrictions.RestrictedProperties'] = undefined
108
108
 
109
109
  // Recursively add drafts for compositions
110
+ let _2manies
110
111
  for (const each in draft.elements) {
111
112
  const e = draft.elements[each]
113
+ // add @odata.draft.enclosed to filtered compositions
114
+ if (e.$enclosed) {
115
+ e['@odata.draft.enclosed'] = true
116
+ } else if (e.$filtered) { //> REVISIT: remove with cds^8
117
+ _2manies ??= Object.keys(draft.elements).map(k => draft.elements[k]).filter(c => c.isComposition && c.is2many)
118
+ if (_2manies.find(c => c.name !== e.name && c.target.replace(/\.drafts$/, '') === e.target)) e['@odata.draft.enclosed'] = true
119
+ }
112
120
  const newEl = Object.create(e)
113
121
  if (
114
122
  e.isComposition ||
@@ -135,6 +143,7 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
135
143
 
136
144
  draft.elements[each] = newEl
137
145
  }
146
+
138
147
  return draft
139
148
  }
140
149
 
@@ -0,0 +1,116 @@
1
+ const { Worker, parentPort, isMainThread, workerData } = require('node:worker_threads')
2
+ const cds = require('../../index.js'), { path, local, read, exists } = cds.utils
3
+ const TRACE = cds.debug('trace')
4
+ const LOG = cds.log('cds|edmx')
5
+ const OUT = process.env.cds_test_temp || path.join (cds.root,'_out')
6
+
7
+ // -----------------------------------------------------------------------
8
+ //
9
+ // Main Thread Part
10
+ //
11
+
12
+ if (isMainThread) {
13
+
14
+ module.exports = exports = (csn, tenant, features) => {
15
+ const defs = Object.entries(csn.definitions), protocols = cds.service.protocols
16
+ const services = defs.filter(([,d]) => d.kind === 'service' && 'odata' in protocols.for(d)).map(([k]) => k)
17
+ if (!services.length) return LOG.debug (`No service definitions found in given model(s).`)
18
+ let dir = path.join (OUT, tenant||'', features||'')
19
+ LOG.info ('generating edmx files to', { dir: local(dir) }, '\n')
20
+ return GENERATE ({ csn, dir, services })
21
+ }
22
+
23
+ const GENERATE = _generate_using_workers // for running in worker threads
24
+ // const GENERATE = _generate_edmxs // for running in main thread
25
+
26
+ // eslint-disable-next-line no-inner-declarations
27
+ async function _generate_using_workers (workerData) {
28
+ await new Promise((resolve, reject) => new Worker (__filename, { workerData })
29
+ .on('error', reject)
30
+ .on('message', msg => {
31
+ if (msg.error) return reject (new cds.error(msg.error))
32
+ if (msg === 'done') return resolve()
33
+ else LOG.debug (msg)
34
+ }))
35
+ exports.get = _read_generated_edmx4
36
+ }
37
+
38
+ // eslint-disable-next-line no-inner-declarations
39
+ function _read_generated_edmx4 (srv, kind='edmx', { tenant, features }={}) {
40
+ let dir = path.join (OUT, tenant||'', features||'')
41
+ let file = path.join (dir, srv.definition.name+'.'+kind)
42
+ if (!exists(file)) throw new Error (`No generated edm(x) file found at: ${file}`)
43
+ return read (file)
44
+ }
45
+
46
+ exports.dir = OUT
47
+ }
48
+
49
+
50
+
51
+ // -----------------------------------------------------------------------
52
+ //
53
+ // Worker Thread Part
54
+ //
55
+
56
+
57
+ if (!isMainThread) _generate_edmxs (workerData)
58
+ .catch (e => parentPort.postMessage({ error: e }))
59
+ .then (() => parentPort.postMessage('done'))
60
+
61
+
62
+ async function _generate_edmxs ({ csn, dir, services }) {
63
+
64
+ const { mkdir, writeFile } = cds.utils.fs.promises
65
+ await mkdir (dir, { recursive: true })
66
+ const cdsc = cds.compiler
67
+ const promises = []
68
+
69
+ TRACE?.time(`cdsc.generate edmxs`.padEnd(22))
70
+
71
+ // call cdsc.to.odata to generate edm/xs
72
+ let odataVersion = cds.env.odata.version
73
+ let suffixes = { edmx: '.edmx' }
74
+ let compile = cdsc.to.edmx // default is edmx only
75
+ if (!cds.env.features.odata_new_adapter) {
76
+ compile = cdsc.to.odata // edmx and edm.json
77
+ suffixes.edm = '.edm.json'
78
+ }
79
+
80
+ let result = compile.all (csn, { serviceNames: services, messages:[] })
81
+
82
+ // write edmx files to disk
83
+ for (let [name,x] of Object.entries(result[odataVersion])) {
84
+ for (let suffix in suffixes) {
85
+ let content = suffix === 'edmx'? x[suffix] : JSON.stringify (x[suffix], minify);
86
+ let file = path.join (dir, name + suffixes[suffix])
87
+ let p = writeFile (file, content)
88
+ .then (() => parentPort?.postMessage ({ generated: local(file) }))
89
+ promises.push(p)
90
+ }
91
+ }
92
+ await Promise.all (promises)
93
+ TRACE?.timeEnd(`cdsc.generate edmxs`.padEnd(22))
94
+ return true
95
+ }
96
+
97
+
98
+ function minify (k,v) {
99
+ if (k === '$ReferentialConstraint') return
100
+ if (k === '$Reference') return
101
+ if (k === '$OnDelete') return
102
+ if (k === '$MaxLength') return
103
+ if (k === '$Annotations') {
104
+ const v2 = {}
105
+ for (let a in v) {
106
+ const a1=v[a], a2 = {}
107
+ for (let p in a1) {
108
+ if (!/^@(UI|Common|Analytics|Core.Description|Core.Operation|Capabilities.Navigation|Measures|Validation)/.test(p)) a2[p] = a1[p]
109
+ }
110
+ if (Object.keys(a2).length) v2[a] = a2
111
+ }
112
+ return v2
113
+ }
114
+ // if (k === '$Type' && v === 'Edm.Guid') return
115
+ else return v
116
+ }
@@ -69,4 +69,11 @@ function* _many (suffix, all, callback = x=>x) {
69
69
  for (let file in all) yield [ callback(all[file]), { file, suffix } ]
70
70
  }
71
71
 
72
- module.exports = Object.assign (cds_compile_to_edm, { x: cds_compile_to_edmx })
72
+ module.exports = exports = cds_compile_to_edm
73
+ cds_compile_to_edm.x = cds_compile_to_edmx
74
+ if (cds.env.features.pre_compile_edmxs) {
75
+ cds_compile_to_edmx.files = require('./edm-files')
76
+ } else {
77
+ cds_compile_to_edmx.files = ()=> null
78
+ }
79
+ cds_compile_to_edmx.files.get = ()=> null
@@ -61,7 +61,7 @@ async function _tabledata4(dir, csvFile, model, baseDir, naming) {
61
61
 
62
62
  // add a locale filter for mono-lingual files that refer to generated text tables
63
63
  if (entity.elements.locale) {
64
- const locale = /_texts_(.+)\.csv$/.test(csvFile) ? RegExp.$1 : null
64
+ const locale = /[._]texts_(.+)\.csv$/.test(csvFile) ? RegExp.$1 : null
65
65
  if (locale) {
66
66
  const localeKey = getElementCdsPersistenceName(entity.elements.locale.name/*usually 'LOCALE'*/, naming, 'hana');
67
67
  _import.import_settings.include_filter.push({ [localeKey]: locale })
@@ -83,7 +83,7 @@ async function _tabledata4(dir, csvFile, model, baseDir, naming) {
83
83
  function _entity4(name, csn) {
84
84
  const entity = csn.definitions[name]
85
85
  if (!entity) {
86
- if (/(.+)[._]texts_?/.test(name)) { // 'Books_texts', 'Books_texts_de'
86
+ if (/(.+)[._]texts_?/.test(name)) { // 'Books_texts', 'Books_texts_de', 'Books.texts', 'Books.texts_de'
87
87
  const base = csn.definitions[RegExp.$1]
88
88
  if (base && base.elements && base.elements.texts) {
89
89
  return _entity4(base.elements.texts.target, csn)
@@ -119,7 +119,7 @@ function _csvDirs(sources) {
119
119
 
120
120
  function _csvs(filename, _, allFiles) {
121
121
  if (filename[0] === '-' || !filename.endsWith('.csv')) return false
122
- // ignores 'Books_texts.csv' if there is any 'Books_texts_LANG.csv'
122
+ // ignores 'Books_texts.csv'|'Books.texts.csv' if there is any 'Books_texts_LANG.csv'|'Books.texts_LANG.csv'
123
123
  if (/(.*)[._]texts\.csv$/.test(filename)) {
124
124
  const basename = RegExp.$1
125
125
  const monoLangFiles = allFiles.filter(file => new RegExp(basename + '_texts_').test(file))
@@ -1,6 +1,7 @@
1
1
  const cds = require ('../..')
2
2
  const cdsc = require ('../cdsc')
3
- const keywords = require("@sap/cds-compiler").to.sql.sqlite.keywords
3
+ const sqliteKeywords = cdsc.to.sql.sqlite.keywords
4
+ const postgresKeywords = cdsc.to.sql.postgres.keywords
4
5
  const { unfold_ddl } = require ('../etc/_localized')
5
6
  const TRACE = cds.debug('trace')
6
7
 
@@ -53,5 +54,6 @@ module.exports = Object.assign (cds_compile_to_sql, {
53
54
  hdbcds: cds_compile_to_hdbcds,
54
55
  hdbtable: cds_compile_to_hdbtable,
55
56
  delta: cds_compile_to_deltaSql,
56
- sqlite: { keywords },
57
+ sqlite: { keywords: sqliteKeywords },
58
+ postgres: { keywords: postgresKeywords },
57
59
  })