@sap/cds 5.8.4 → 5.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 (244) hide show
  1. package/CHANGELOG.md +174 -77
  2. package/app/fiori/preview.js +16 -11
  3. package/app/index.js +1 -1
  4. package/bin/build/buildTaskFactory.js +3 -3
  5. package/bin/build/buildTaskProviderFactory.js +1 -1
  6. package/bin/build/constants.js +1 -1
  7. package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
  8. package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
  9. package/bin/build/provider/buildTaskProviderInternal.js +8 -2
  10. package/bin/build/provider/hana/2migration.js +27 -24
  11. package/bin/build/provider/hana/index.js +17 -18
  12. package/bin/build/provider/hana/migrationtable.js +9 -10
  13. package/bin/build/provider/java-cf/index.js +4 -5
  14. package/bin/build/provider/node-cf/index.js +99 -6
  15. package/bin/cds.js +17 -18
  16. package/bin/deploy/to-hana/cfUtil.js +16 -19
  17. package/bin/deploy/to-hana/hana.js +7 -24
  18. package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
  19. package/bin/mtx/in-cds.js +2 -2
  20. package/bin/serve.js +10 -3
  21. package/bin/utils/modules.js +7 -0
  22. package/bin/version.js +56 -3
  23. package/lib/compile/cdsc.js +26 -3
  24. package/lib/compile/etc/_localized.js +36 -25
  25. package/lib/compile/etc/csv.js +8 -8
  26. package/lib/compile/for/drafts.js +9 -0
  27. package/lib/compile/for/java.js +16 -0
  28. package/lib/compile/for/nodejs.js +12 -0
  29. package/lib/compile/for/odata.js +1 -1
  30. package/lib/compile/index.js +3 -0
  31. package/lib/compile/minify.js +16 -2
  32. package/lib/compile/parse.js +2 -2
  33. package/lib/compile/resolve.js +35 -18
  34. package/lib/compile/to/json.js +3 -1
  35. package/lib/compile/to/sql.js +2 -2
  36. package/lib/compile/to/srvinfo.js +4 -2
  37. package/lib/connect/index.js +1 -1
  38. package/lib/core/entities.js +15 -14
  39. package/lib/core/index.js +39 -36
  40. package/lib/core/reflect.js +4 -2
  41. package/lib/deploy.js +114 -127
  42. package/lib/env/defaults.js +1 -0
  43. package/lib/env/index.js +165 -165
  44. package/lib/env/presets.js +1 -0
  45. package/lib/env/requires.js +120 -49
  46. package/lib/index.js +1 -0
  47. package/lib/log/format/kibana.js +2 -2
  48. package/lib/ql/SELECT.js +10 -0
  49. package/lib/ql/parse.js +1 -0
  50. package/lib/req/cds-context.js +4 -1
  51. package/lib/req/context.js +50 -56
  52. package/lib/req/event.js +1 -6
  53. package/lib/req/locale.js +6 -5
  54. package/lib/req/request.js +2 -0
  55. package/lib/req/user.js +7 -5
  56. package/lib/serve/Service-api.js +10 -7
  57. package/lib/serve/Service-dispatch.js +9 -11
  58. package/lib/serve/Service-methods.js +30 -41
  59. package/lib/serve/Transaction.js +10 -7
  60. package/lib/serve/adapters.js +7 -5
  61. package/lib/serve/index.js +24 -12
  62. package/lib/utils/data.js +1 -1
  63. package/lib/utils/index.js +27 -30
  64. package/lib/utils/resources/index.js +101 -0
  65. package/lib/utils/resources/tar.js +71 -0
  66. package/lib/utils/resources/utils.js +11 -0
  67. package/libx/_runtime/audit/Service.js +36 -39
  68. package/libx/_runtime/audit/generic/personal/access.js +3 -4
  69. package/libx/_runtime/audit/generic/personal/modification.js +3 -4
  70. package/libx/_runtime/audit/utils/v2.js +1 -2
  71. package/libx/_runtime/auth/index.js +126 -84
  72. package/libx/_runtime/auth/strategies/JWT.js +12 -19
  73. package/libx/_runtime/auth/strategies/dummy.js +1 -5
  74. package/libx/_runtime/auth/strategies/dwc.js +11 -9
  75. package/libx/_runtime/auth/strategies/mock.js +0 -4
  76. package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
  77. package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
  78. package/libx/_runtime/auth/utils.js +22 -1
  79. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
  80. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
  81. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
  82. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
  83. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
  84. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
  85. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
  86. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
  87. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
  88. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
  89. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
  90. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
  91. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
  92. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
  93. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
  94. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
  95. package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +50 -0
  96. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
  97. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
  98. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
  99. package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
  100. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
  101. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
  102. package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
  103. package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
  104. package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
  105. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
  106. package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
  107. package/libx/_runtime/cds-services/services/Service.js +40 -0
  108. package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
  109. package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
  110. package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
  111. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
  112. package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
  113. package/libx/_runtime/cds-services/util/assert.js +20 -14
  114. package/libx/_runtime/cds.js +9 -1
  115. package/libx/_runtime/common/aspects/any.js +5 -0
  116. package/libx/_runtime/common/aspects/entity.js +25 -7
  117. package/libx/_runtime/common/aspects/utils.js +2 -2
  118. package/libx/_runtime/common/composition/data.js +6 -0
  119. package/libx/_runtime/common/composition/insert.js +3 -2
  120. package/libx/_runtime/common/composition/tree.js +4 -10
  121. package/libx/_runtime/common/composition/update.js +4 -4
  122. package/libx/_runtime/common/constants/draft.js +29 -26
  123. package/libx/_runtime/common/error/constants.js +2 -2
  124. package/libx/_runtime/common/error/frontend.js +7 -15
  125. package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
  126. package/libx/_runtime/common/generic/auth/constants.js +20 -0
  127. package/libx/_runtime/common/generic/auth/expand.js +54 -0
  128. package/libx/_runtime/common/generic/auth/index.js +32 -0
  129. package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
  130. package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
  131. package/libx/_runtime/common/generic/auth/requires.js +34 -0
  132. package/libx/_runtime/common/generic/auth/restrict.js +296 -0
  133. package/libx/_runtime/common/generic/auth/utils.js +213 -0
  134. package/libx/_runtime/common/generic/crud.js +8 -6
  135. package/libx/_runtime/common/generic/etag.js +1 -1
  136. package/libx/_runtime/common/generic/input.js +35 -35
  137. package/libx/_runtime/common/generic/sorting.js +2 -3
  138. package/libx/_runtime/common/generic/temporal.js +2 -2
  139. package/libx/_runtime/common/i18n/messages.properties +1 -1
  140. package/libx/_runtime/common/toggles/handler.js +21 -0
  141. package/libx/_runtime/common/utils/copy.js +10 -1
  142. package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
  143. package/libx/_runtime/common/utils/csn.js +63 -1
  144. package/libx/_runtime/common/utils/dollar.js +10 -1
  145. package/libx/_runtime/common/utils/draft.js +46 -7
  146. package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
  147. package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
  148. package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
  149. package/libx/_runtime/common/utils/generateOnCond.js +4 -1
  150. package/libx/_runtime/common/utils/quotingStyles.js +2 -0
  151. package/libx/_runtime/common/utils/resolveStructured.js +25 -9
  152. package/libx/_runtime/common/utils/resolveView.js +4 -1
  153. package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
  154. package/libx/_runtime/common/utils/structured.js +33 -37
  155. package/libx/_runtime/common/utils/template.js +17 -8
  156. package/libx/_runtime/common/utils/templateProcessor.js +28 -28
  157. package/libx/_runtime/db/data-conversion/post-processing.js +118 -417
  158. package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
  159. package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
  160. package/libx/_runtime/db/generic/index.js +1 -3
  161. package/libx/_runtime/db/generic/input.js +5 -10
  162. package/libx/_runtime/db/generic/rewrite.js +5 -2
  163. package/libx/_runtime/db/generic/structured.js +2 -2
  164. package/libx/_runtime/db/query/delete.js +2 -2
  165. package/libx/_runtime/db/query/insert.js +1 -1
  166. package/libx/_runtime/db/query/update.js +9 -14
  167. package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
  168. package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
  169. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
  170. package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
  171. package/libx/_runtime/db/utils/columns.js +3 -3
  172. package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
  173. package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
  174. package/libx/_runtime/extensibility/mps/index.js +5 -0
  175. package/libx/_runtime/extensibility/mps/service.js +111 -0
  176. package/libx/_runtime/extensibility/mps/tar.js +42 -0
  177. package/libx/_runtime/extensibility/mps/utils.js +11 -0
  178. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
  179. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
  180. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
  181. package/libx/_runtime/extensibility/uiflex/index.js +54 -0
  182. package/libx/_runtime/extensibility/uiflex/service.js +276 -0
  183. package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
  184. package/libx/_runtime/fiori/generic/activate.js +2 -2
  185. package/libx/_runtime/fiori/generic/before.js +4 -4
  186. package/libx/_runtime/fiori/generic/new.js +3 -3
  187. package/libx/_runtime/fiori/generic/patch.js +1 -1
  188. package/libx/_runtime/fiori/generic/read.js +58 -66
  189. package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
  190. package/libx/_runtime/fiori/utils/handler.js +6 -13
  191. package/libx/_runtime/fiori/utils/where.js +6 -5
  192. package/libx/_runtime/hana/Service.js +4 -10
  193. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +1 -1
  194. package/libx/_runtime/hana/driver.js +2 -2
  195. package/libx/_runtime/hana/execute.js +27 -74
  196. package/libx/_runtime/hana/pool.js +1 -1
  197. package/libx/_runtime/hana/streaming.js +2 -1
  198. package/libx/_runtime/index.js +6 -6
  199. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
  200. package/libx/_runtime/messaging/Outbox.js +2 -2
  201. package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
  202. package/libx/_runtime/messaging/common-utils/connections.js +5 -7
  203. package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
  204. package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
  205. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
  206. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
  207. package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
  208. package/libx/_runtime/messaging/file-based.js +5 -5
  209. package/libx/_runtime/messaging/message-queuing.js +14 -12
  210. package/libx/_runtime/messaging/outbox/utils.js +18 -19
  211. package/libx/_runtime/messaging/redis-messaging.js +91 -0
  212. package/libx/_runtime/messaging/service.js +8 -6
  213. package/libx/_runtime/remote/Service.js +44 -8
  214. package/libx/_runtime/remote/utils/client.js +20 -13
  215. package/libx/_runtime/remote/utils/data.js +11 -11
  216. package/libx/_runtime/sqlite/Service.js +6 -9
  217. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
  218. package/libx/_runtime/types/api.js +10 -2
  219. package/libx/common/utils/ucsn.js +109 -0
  220. package/libx/gql/resolvers/crud/update.js +5 -0
  221. package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
  222. package/libx/gql/schema/typeDefMap.js +2 -2
  223. package/libx/odata/afterburner.js +110 -16
  224. package/libx/odata/grammar.pegjs +9 -1
  225. package/libx/odata/parseToCqn.js +39 -0
  226. package/libx/odata/parser.js +1 -1
  227. package/libx/rest/RestAdapter.js +9 -1
  228. package/libx/rest/middleware/input.js +54 -0
  229. package/libx/rest/middleware/operation.js +14 -1
  230. package/libx/rest/middleware/parse.js +11 -7
  231. package/package.json +1 -1
  232. package/server.js +34 -19
  233. package/srv/audit-log.cds +2 -2
  234. package/srv/flex.cds +8 -2
  235. package/srv/flex.js +1 -1
  236. package/srv/mps.cds +23 -0
  237. package/srv/mps.js +1 -0
  238. package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
  239. package/libx/_runtime/common/generic/auth.js +0 -874
  240. package/libx/_runtime/common/toggles/alpha.js +0 -43
  241. package/libx/_runtime/db/generic/arrayed.js +0 -33
  242. package/libx/_runtime/fiori/uiflex/index.js +0 -35
  243. package/libx/_runtime/fiori/uiflex/service.js +0 -150
  244. package/libx/rest/utils/data.js +0 -60
@@ -1,16 +1,21 @@
1
1
  const _runtime = '../../libx/_runtime'
2
2
 
3
- module.exports = {
4
- "db": undefined,
5
- "multitenancy": undefined,
6
- "app-service": {
7
- // this is the default implementation used for provided services
8
- impl: `${_runtime}/cds-services/services/Service.js`
9
- },
10
- "auth": {
3
+ exports = module.exports = {
4
+
5
+ db: undefined,
6
+ messaging: undefined,
7
+ multitenancy: undefined,
8
+
9
+ auth: {
11
10
  '[development]': { kind: 'mocked-auth' },
12
11
  '[production]': { kind: 'jwt-auth' }
13
12
  },
13
+
14
+ }
15
+
16
+
17
+ const _authentication_strategies = {
18
+
14
19
  "dummy-auth": {
15
20
  strategy: 'dummy',
16
21
  },
@@ -27,50 +32,66 @@ module.exports = {
27
32
  },
28
33
  "jwt-auth": {
29
34
  strategy: 'JWT',
35
+ vcap: { label: 'xsuaa' }
30
36
  },
31
- "xsuaa-auth": {
37
+ "xsuaa": {
32
38
  strategy: 'xsuaa',
39
+ vcap: { label: 'xsuaa' }
33
40
  },
34
- "dwc-auth": {
35
- strategy: 'dwc',
41
+
42
+ }
43
+
44
+
45
+ const _services = {
46
+
47
+ "app-service": {
48
+ // this is the default implementation used for provided services
49
+ impl: `${_runtime}/cds-services/services/Service.js`
36
50
  },
37
- destinations: {
38
- vcap: {
39
- label: 'destination'
40
- }
51
+ "rest": {
52
+ impl: `${_runtime}/remote/Service.js`
41
53
  },
42
- xsuaa: {
43
- vcap: {
44
- label: 'xsuaa'
45
- }
54
+ "odata": {
55
+ impl: `${_runtime}/remote/Service.js`
56
+ },
57
+ "odata-v2": { // REVISIT: we should introduce .version
58
+ impl: `${_runtime}/remote/Service.js`
59
+ },
60
+ "odata-v4": { // REVISIT: we should introduce .version
61
+ impl: `${_runtime}/remote/Service.js`
46
62
  },
47
- monitoring: undefined,
48
- logging: undefined,
49
- audit: undefined,
63
+
64
+ }
65
+
66
+
67
+ const _databases = {
68
+
50
69
  "sql": {
51
70
  '[development]': { kind: 'sqlite', credentials: { url: ':memory:' } },
52
71
  '[production]': { kind: 'hana' },
53
72
  },
54
73
  "sqlite": _compat_to_use({
55
- dialect: 'sqlite', credentials: { url: 'sqlite.db' },
74
+ credentials: { url: 'sqlite.db' },
56
75
  impl: `${_runtime}/sqlite/Service.js`,
57
76
  }),
58
77
  "hana": _compat_to_use ({
59
- dialect: 'hana',
60
78
  impl: `${_runtime}/hana/Service.js`,
61
79
  }),
62
- "rest": {
63
- impl: `${_runtime}/remote/Service.js`
64
- },
65
- "odata": {
66
- impl: `${_runtime}/remote/Service.js`
67
- },
68
- "odata-v2": {
69
- kind: 'odata'
70
- },
71
- "odata-v4": {
72
- kind: 'odata'
73
- },
80
+ "hana-cloud": _compat_to_use ({
81
+ kind: 'hana', "deploy-format": "hdbtable",
82
+ }),
83
+ "hana-mt": _compat_to_use ({
84
+ kind: 'hana', "deploy-format": "hdbtable",
85
+ "vcap": {
86
+ "label": "service-manager"
87
+ }
88
+ }),
89
+
90
+ }
91
+
92
+
93
+ const _messaging = {
94
+
74
95
  "local-messaging": {
75
96
  impl: `${_runtime}/messaging/service.js`,
76
97
  local: true
@@ -112,28 +133,78 @@ module.exports = {
112
133
  "composite-messaging": {
113
134
  impl: `${_runtime}/messaging/composite.js`
114
135
  },
115
- "audit-log": {
136
+ "mtx-messaging": {
137
+ kind: "local-messaging",
138
+ "[production]": {
139
+ kind: "redis-messaging"
140
+ }
141
+ },
142
+ "redis-messaging": {
143
+ impl: `${_runtime}/messaging/redis-messaging.js`,
144
+ vcap: { label: "redis-cache" },
145
+ outbox: {}
146
+ },
147
+
148
+ "persistent-outbox": {
149
+ model: "@sap/cds/srv/outbox",
150
+ maxAttempts: 20,
151
+ chunkSize: 100
152
+ },
153
+
154
+ }
155
+
156
+
157
+ const _multitenancy = {
158
+ }
159
+
160
+
161
+ const _extensibility = {
162
+
163
+ "uiflex": {
164
+ model: "@sap/cds/srv/flex"
165
+ },
166
+
167
+ }
168
+
169
+
170
+
171
+ const _platform_services = {
172
+
173
+ "audit-log-service": {
116
174
  impl: `${_runtime}/audit/Service.js`,
117
- // REVISIT: how to load model? -> see _prototypes below
118
175
  // model: 'AuditLogService.cds',
119
176
  outbox: {},
120
177
  vcap: { label: "auditlog" },
121
178
  },
122
179
 
123
- _prototypes: {
124
- "uiflex": {
125
- model: "@sap/cds/srv/flex"
126
- },
127
- "persistent-outbox": {
128
- model: "@sap/cds/srv/outbox",
129
- maxAttempts: 20,
130
- chunkSize: 100
131
- },
132
- }
180
+ "audit-log-to-console": {
181
+ kind: "audit-log-service",
182
+ credentials: { logToConsole: true }
183
+ },
184
+
185
+ destinations: {
186
+ vcap: {
187
+ label: 'destination'
188
+ }
189
+ },
190
+
191
+ approuter: undefined,
192
+
193
+ }
194
+
195
+
196
+ exports.kinds = {
197
+ ..._authentication_strategies,
198
+ ..._databases,
199
+ ..._services,
200
+ ..._messaging,
201
+ ..._multitenancy,
202
+ ..._extensibility,
203
+ ..._platform_services,
133
204
  }
134
205
 
135
206
 
136
207
  function _compat_to_use(o) { return Object.defineProperties (o,{
137
208
  // NOTE: Property .use is for compatibility only -> use .dialect instead!
138
- use: { get(){ return this.dialect }, enumerable:true },
209
+ use: { get(){ return this.dialect || this.kind }, configurable:true, enumerable:true },
139
210
  })}
package/lib/index.js CHANGED
@@ -81,6 +81,7 @@ if (global.cds) Object.assign(module,{exports:global.cds}) ; else {
81
81
  MessagingService: lazy => require('../libx/_runtime/messaging/service.js'),
82
82
  DatabaseService: lazy => require('../libx/_runtime/db/Service.js'),
83
83
  RemoteService: lazy => require('../libx/_runtime/rest/service.js'),
84
+ AuditLogService: lazy => require('../libx/_runtime/audit/Service.js'),
84
85
  odata: require('../libx/odata'),
85
86
 
86
87
  // Helpers
@@ -1,4 +1,4 @@
1
- const cds = require('../../')
1
+ const cds = require ('../../')
2
2
  const util = require('util')
3
3
 
4
4
  const _l2l = { 1: 'error', 2: 'warn', 3: 'info', 4: 'debug', 5: 'trace' }
@@ -8,7 +8,7 @@ const _l2l = { 1: 'error', 2: 'warn', 3: 'info', 4: 'debug', 5: 'trace' }
8
8
  */
9
9
  module.exports = (module, level, ...args) => {
10
10
  // config
11
- const { user: log_user, kibana_custom_fields } = cds.env.log
11
+ const { user: log_user , kibana_custom_fields } = cds.env.log
12
12
 
13
13
  // build the object to log
14
14
  const toLog = {
package/lib/ql/SELECT.js CHANGED
@@ -40,6 +40,16 @@ module.exports = class SELECT extends Whereable {
40
40
  if (cols === '*') return this.columns(...arguments)
41
41
  const c = _columns_or_not (cols)
42
42
  if (c) return this._add('columns',c)
43
+ if (typeof cols === 'string') {
44
+ try { parse.path(cols) }
45
+ catch(e) { //> it can't be a from
46
+ try { return this.columns(...arguments) }
47
+ catch(e) {
48
+ if (!e.message.startsWith('CDS compilation failed')) throw e
49
+ this._expected `Argument ${{cols}} to be a valid argument for SELECT.from or .columns`
50
+ }
51
+ }
52
+ }
43
53
  }
44
54
 
45
55
  // return a proxy assuming it's a from and switching to
package/lib/ql/parse.js CHANGED
@@ -7,6 +7,7 @@ module.exports = {
7
7
  CQL: (..._) => cds.parse.CQL (..._),
8
8
  CXL: (..._) => cds.parse.CXL (..._),
9
9
  cql: (..._) => cds.parse.cql (..._),
10
+ path: (..._) => cds.parse.path (..._),
10
11
  }
11
12
 
12
13
  const _simple = (x) => {
@@ -21,7 +21,10 @@ const { EventEmitter } = require('events')
21
21
  Reflect.defineProperty (cds,'context',{ enumerable:1,
22
22
  set(v) {
23
23
  const cr = current(); if (!cr) return
24
- const ctx = typeof v !== 'object' ? v : v.context || (v instanceof EventContext ? v : EventContext.for(v,false))
24
+ const ctx = (
25
+ v instanceof EventContext || typeof v !== 'object' ? v :
26
+ v.context || EventContext.for (v.req ? {_:v} : v)
27
+ )
25
28
  cr[_context] = ctx
26
29
  },
27
30
  get() {
@@ -1,5 +1,6 @@
1
1
  const cds = require ('../index'), { features } = cds.env, { uuid } = cds.utils
2
2
  const async_events = { succeeded:1, failed:1, done:1 }
3
+ const req_locale = require('./locale')
3
4
  const { EventEmitter } = require('events')
4
5
 
5
6
  /**
@@ -10,31 +11,23 @@ const { EventEmitter } = require('events')
10
11
  */
11
12
  class EventContext {
12
13
 
13
- toString() { return `${this.event} ${this.path}` }
14
-
15
- static for (data={}, base = cds.context) {
16
- if (data instanceof EventContext) return data
17
- if (base && features.cds_tx_inheritance) {
18
- let u = _inherit('user', u => typeof u === 'object' ? Object.create(u) : u)
19
- if (!u || !u.tenant) _inherit('tenant')
20
- if (!u || !u.locale) _inherit('locale')
21
- }
22
- function _inherit (p,fn) {
23
- if (p in data) return data[p]
24
- let pd = Reflect.getOwnPropertyDescriptor(base,p); if (!pd) return
25
- return data[p] = fn ? fn(pd.value) : pd.value
14
+ /** Creates a new instance that inherits from cds.context */
15
+ static for (_) {
16
+ const ctx = new this (_)
17
+ if (features.cds_tx_inheritance) {
18
+ const base = cds.context
19
+ if (base) ctx._set('_propagated', base)
26
20
  }
27
- // IMPORTANT: ensure user is first to be assigned to call setter_
28
- if (data.user) data = { user:1, ...data }
29
- return new this (data)
21
+ return ctx
30
22
  }
31
23
 
32
24
  constructor(_={}) {
33
- Object.assign (this, this._set('_',_))
25
+ Object.defineProperty (this, '_', { value:_, writable:true })
26
+ Object.assign (this, _)
34
27
  }
35
28
 
36
29
  _set (property, value) {
37
- Object.defineProperty (this, property, {value,writable:true})
30
+ Object.defineProperty (this, property, { value, writable:true })
38
31
  return value
39
32
  }
40
33
 
@@ -44,18 +37,16 @@ class EventContext {
44
37
  // Emitting and listening to succeeded / failed / done events
45
38
  //
46
39
 
47
- /** @returns {EventEmitter} */ get emitter() {
48
- return this._emitter || (this._emitter = this._propagated('emitter') || new EventEmitter)
40
+ get emitter() {
41
+ return this.context._emitter || (this.context._emitter = new EventEmitter)
49
42
  }
50
43
 
51
44
  async emit (event,...args) {
52
- if (!this._emitter) return
53
- if (event in async_events) {
54
- for (const each of this._emitter.listeners(event)) {
55
- await each.call(this,...args)
56
- }
57
- }
58
- else return this._emitter.emit (event,...args)
45
+ const emitter = this.context._emitter; if (!emitter) return
46
+ if (event in async_events)
47
+ for (const each of emitter.listeners(event))
48
+ await each.call (this, ...args)
49
+ else return emitter.emit (event,...args)
59
50
  }
60
51
 
61
52
  on (event, listener) {
@@ -75,48 +66,58 @@ class EventContext {
75
66
  // The following properties are inherited from root contexts, if exist...
76
67
  //
77
68
 
78
- set context(c) { if (c) this._set('context',c) }
69
+ set context(c) { if (c) this._set('context', this._set('_propagated', c)) }
79
70
  get context() { return this }
80
71
 
81
- set id(c) { if (c) super.id = c }
72
+ set id(id) {
73
+ if (id) super.id = id
74
+ }
82
75
  get id() {
83
- return this.id = this._propagated('id') || this.headers[ 'x-correlation-id' ] || uuid()
76
+ return super.id = this._propagated.id || this.headers[ 'x-correlation-id' ] || uuid()
84
77
  }
85
78
 
86
79
  set tenant(t) {
87
- if (t) super.tenant = this.user.tenant = t
80
+ if (t) super.tenant = t
88
81
  }
89
82
  get tenant() {
90
- return this.tenant = this.user.tenant || this._propagated('tenant')
83
+ return super.tenant = this._propagated.tenant
91
84
  }
92
85
 
93
86
  set user(u) {
94
- if (!u) return
95
- if (typeof u === 'string') u = new cds.User(u)
96
- if (this._.req) Object.defineProperty(u,'_req',{value:this._.req}) // REVISIT: The following is to support req.user.locale
97
- super.user = u
87
+ const user = super.user = u instanceof cds.User ? u : new cds.User(u)
88
+ for (let p of ['tenant','locale']) { // compatibility
89
+ if (u && u.hasOwnProperty(p)) this[p] = u[p] // eslint-disable-line no-prototype-builtins
90
+ else Object.defineProperty (user, p, { get: () => this[p] })
91
+ }
98
92
  }
99
93
  get user() {
100
- return this.user = this._propagated('user') || new cds.User
94
+ const u = this._propagated.user
95
+ return this.user = u ? {__proto__:u} : new cds.User.default
101
96
  }
102
97
 
103
98
  set locale(l) {
104
- if (l) super.locale = this.user.locale = l
99
+ if (l) super.locale = super._locale = l
105
100
  }
106
101
  get locale() {
107
- return this.locale = this.user.locale || this._propagated('locale')
102
+ return super.locale = this._propagated.locale || req_locale(this._.req)
103
+ }
104
+ get _locale() {
105
+ return super._locale = this._propagated._locale || req_locale.from_req(this._.req)
106
+ || this.hasOwnProperty('locale') && this.locale // eslint-disable-line no-prototype-builtins
108
107
  }
109
108
 
110
109
  get timestamp() {
111
- return super.timestamp = this._propagated('timestamp') || new Date
110
+ return super.timestamp = this._propagated.timestamp || new Date
112
111
  }
113
112
 
114
- set headers(h) { if (h) super.headers = h }
113
+ set headers(h) {
114
+ if (h) super.headers = h
115
+ }
115
116
  get headers() {
116
117
  if (this._ && this._.req && this._.req.headers) {
117
118
  return super.headers = this._.req.headers
118
119
  } else {
119
- const headers={}, outer = this._propagated('headers')
120
+ const headers={}, outer = this._propagated.headers
120
121
  if (outer) for (let each of EventContext.propagateHeaders) {
121
122
  if (each in outer) headers[each] = outer[each]
122
123
  }
@@ -125,27 +126,18 @@ class EventContext {
125
126
  }
126
127
 
127
128
 
128
- //
129
- // Connecting to transactions and request hierarchies
130
- //
131
-
132
- _propagated (p) {
133
- const ctx = this.context
134
- if (ctx !== this) return ctx[p]
135
- }
136
-
137
129
  set _tx(tx) {
138
130
  Object.defineProperty (this,'_tx',{value:tx}) //> allowed only once!
139
131
  const ctx = tx.context
140
132
  if (ctx && ctx !== this) {
141
- this.context = ctx
133
+ if (!this.hasOwnProperty('context')) this.context = ctx // eslint-disable-line no-prototype-builtins
134
+ ///////////////////////////////////////////////////////////////////
142
135
  // REVISIT: Eliminate req._children
143
- // only collect children if integrity checks are active
144
136
  if (features.assert_integrity !== false) {
145
- const reqs = ctx._children || (ctx._children = {})
137
+ const reqs = ctx._children || ctx._set('_children', {})
146
138
  const all = reqs[tx.name] || (reqs[tx.name] = [])
147
139
  all.push(this)
148
- }
140
+ } //////////////////////////////////////////////////////////////////
149
141
  }
150
142
  }
151
143
 
@@ -153,9 +145,11 @@ class EventContext {
153
145
  /** REVISIT: remove -> @deprecated */
154
146
  set _model(m){ super._model = m }
155
147
  get _model() {
156
- return super._model = this._tx && this._tx.model || this._propagated('_model')
148
+ return super._model = this._tx && this._tx.model || this._propagated._model
157
149
  }
158
150
  }
159
151
 
152
+
153
+ EventContext.prototype._set('_propagated', Object.seal({}))
160
154
  EventContext.propagateHeaders = [ 'x-correlation-id' ]
161
155
  module.exports = EventContext
package/lib/req/event.js CHANGED
@@ -4,12 +4,7 @@ const EventContext = require ('./context')
4
4
  * Instances of class cds.Event represent asynchronous messages as well as
5
5
  * synchronous requests. The latter are instances of subclass cds.Request.
6
6
  */
7
- class EventMessage extends EventContext {
8
- static for (eve) {
9
- if (eve instanceof this) return eve
10
- if (typeof eve === 'object') return new this(eve)
11
- }
12
- }
7
+ class EventMessage extends EventContext {}
13
8
 
14
9
  module.exports = exports = EventMessage
15
10
  exports.Context = EventContext
package/lib/req/locale.js CHANGED
@@ -7,15 +7,16 @@ const INCLUDE_LIST = i18n.preserved_locales.reduce((p,n)=>{
7
7
  en_US_x_sappsd: 'en_US_sappsd'
8
8
  })
9
9
 
10
- const from_req = req => req.query['sap-language'] || req.headers['x-sap-request-language'] || req.headers['accept-language']
10
+ const from_req = req => req && (
11
+ req.query && req.query['sap-language'] ||
12
+ req.headers && (req.headers['x-sap-request-language'] || req.headers['accept-language'])
13
+ )
11
14
 
12
15
  function req_locale (req) {
13
- if (!req) return i18n.default_language
14
- const locale = from_req(req)
15
- if (!locale) return i18n.default_language
16
+ const locale = from_req(req); if (!locale) return i18n.default_language
16
17
  const loc = locale.replace(/-/g,'_')
17
18
  return INCLUDE_LIST[loc]
18
- || /([a-z]+)/i.test(loc) && RegExp.$1.toLowerCase()
19
+ || /^([a-z]+)/i.test(loc) && RegExp.$1.toLowerCase()
19
20
  || i18n.default_language
20
21
  }
21
22
 
@@ -7,6 +7,8 @@ const { Responses, Errors } = require('./response')
7
7
  */
8
8
  class Request extends require('./event') {
9
9
 
10
+ toString() { return `${this.event} ${this.path}` }
11
+
10
12
  set method(m) { if (m) super.method = m }
11
13
  get method() {
12
14
  return this._set ('method', Crud2Http[this.event] || this.event)
package/lib/req/user.js CHANGED
@@ -1,5 +1,3 @@
1
- const req_locale = require('./locale')
2
-
3
1
  class User {
4
2
 
5
3
  constructor (_) {
@@ -9,9 +7,6 @@ class User {
9
7
  if (Array.isArray(_._roles)) this._roles = _._roles.reduce((p,n)=>{p[n]=1; return p},{})
10
8
  }
11
9
 
12
- get locale() { return super.locale = req_locale (this._req) }
13
- set locale(l) { if (l) super.locale = l }
14
-
15
10
  get attr() { return super.attr = {} }
16
11
 
17
12
  get _roles(){ return super._roles = {
@@ -24,6 +19,9 @@ class User {
24
19
 
25
20
  }
26
21
 
22
+ /**
23
+ * Subclass representing non-identified unauthenticated users.
24
+ */
27
25
  class Anonymous extends User {
28
26
  is (role) { return role === 'any' }
29
27
  get _roles() { return {} }
@@ -31,6 +29,9 @@ class Anonymous extends User {
31
29
  Anonymous.prototype._is_anonymous = true
32
30
  Anonymous.prototype.id = 'anonymous'
33
31
 
32
+ /**
33
+ * Subclass for executing code with superuser privileges.
34
+ */
34
35
  class Privileged extends User {
35
36
  constructor(_) { super(_||{}) }
36
37
  is() { return true }
@@ -38,4 +39,5 @@ class Privileged extends User {
38
39
  Privileged.prototype._is_privileged = true
39
40
  Privileged.prototype.id = 'privileged'
40
41
 
42
+ // exports -----------------
41
43
  module.exports = exports = Object.assign (User, { Anonymous, Privileged, default:Anonymous })
@@ -1,5 +1,6 @@
1
+ const cds = require('..'), { Event, Request } = cds
1
2
  const add_methods_to = require ('./Service-methods')
2
- const cds = require('..'), { unfold_csn: cds_localized } = cds.compile._localized
3
+ const { unfold_csn: cds_localized } = cds.compile._localized
3
4
 
4
5
 
5
6
  class Service extends require('./Service-handlers') {
@@ -15,7 +16,7 @@ class Service extends require('./Service-handlers') {
15
16
  */
16
17
  set model (csn) {
17
18
  if (csn) {
18
- super.model = cds_localized(cds.linked(cds.compile.for.odata(csn)))
19
+ super.model = cds.compile.for.nodejs(csn)
19
20
  add_methods_to (this)
20
21
  } else {
21
22
  super.model = undefined
@@ -27,7 +28,9 @@ class Service extends require('./Service-handlers') {
27
28
  */
28
29
  emit (event, data, headers) {
29
30
  const res = this._compat_sync (event, data, headers); if (res) return res
30
- const eve = cds.Event.for(event) || new cds.Event({ event, data, headers })
31
+ const eve = event instanceof Event ? event : new Event (
32
+ is_object(event) ? event : { event, data, headers }
33
+ )
31
34
  return this.dispatch (eve)
32
35
  }
33
36
 
@@ -35,9 +38,8 @@ class Service extends require('./Service-handlers') {
35
38
  * REST-style API to send synchronous requests...
36
39
  */
37
40
  send (method, path, data, headers) {
38
- const req = cds.Request.for(method) || (
39
- typeof path === 'object' ? new cds.Request({ method, data:path, headers:data }) :
40
- new cds.Request({ method, path, data, headers })
41
+ const req = method instanceof Request ? method : new Request (
42
+ is_object(method) ? method : is_object(path) ? { method, data:path, headers:data } : { method, path, data, headers }
41
43
  )
42
44
  return this.dispatch (req)
43
45
  }
@@ -51,7 +53,7 @@ class Service extends require('./Service-handlers') {
51
53
  * Querying API to send synchronous requests...
52
54
  */
53
55
  run (query, data) {
54
- const req = new cds.Request ({ query, data })
56
+ const req = new Request ({ query, data })
55
57
  return this.dispatch (req)
56
58
  }
57
59
  read (...args) { return is_query(args[0]) ? this.run(...args) : SELECT(...args).bind(this) }
@@ -113,3 +115,4 @@ const _reflect = (srv,filter) => !srv.model ? [] : srv.model.childrenOf (srv.nam
113
115
  const is_rest = x => x && typeof x === 'string' && x[0] === '/'
114
116
  const is_query = x => x && x.bind || is_array(x) && !x.raw
115
117
  const is_array = (x) => Array.isArray(x) && !x.raw
118
+ const is_object = (x) => typeof x === 'object'
@@ -13,12 +13,12 @@ exports.dispatch = async function dispatch (req) { //NOSONAR
13
13
 
14
14
  // Ensure we are in a proper transaction
15
15
  if (!this.context) {
16
- const txc = cds.context //> join an outer tx.context, if any, with a nested tx
17
- if (txc && !txc._done) return this.tx(txc).dispatch(req)
18
- else try { //> start a new top-level tx, which we need to commit/rollback
19
- const tx = cds.context = this.tx(req)
20
- return tx.dispatch(req) .then (tx.commit, tx.rollback)
21
- } finally { cds.context = txc }
16
+ const ctx = cds.context
17
+ if (ctx && ctx._tx && !ctx._done) { // join outer context with a nested tx -> we don't modify outer context
18
+ return this.tx(ctx).dispatch(req)
19
+ } else { // start a new root tx for subsequent continuation
20
+ return this.tx(tx => (cds.context=tx).dispatch(req))
21
+ }
22
22
  }
23
23
  // `this` is a tx from now on...
24
24
  if (!req._tx) req._tx = this
@@ -97,7 +97,7 @@ const _is_array = Array.isArray
97
97
  const _dummy = ()=>{} // REVISIT: required for some messaging tests which obviously still expect and call next()
98
98
 
99
99
  const _ensure_target = (srv,req) => {
100
- const q = req.query, p = req._.path; if (!q && !p) return
100
+ const q = req.query, p = req._.path || req._.entity; if (!q && !p) return
101
101
  if (srv.namespace) { // ensure fully-qualified names
102
102
  if (p) _ensure_fqn (req,'path',srv, p.startsWith('/') ? p.slice(1) : p)
103
103
  else if (q.SELECT) _ensure_fqn (q.SELECT,'from',srv)
@@ -105,10 +105,8 @@ const _ensure_target = (srv,req) => {
105
105
  else if (q.UPDATE) _ensure_fqn (q.UPDATE,'entity',srv)
106
106
  else if (q.DELETE) _ensure_fqn (q.DELETE,'from',srv)
107
107
  }
108
- if (typeof q === 'object') {
109
- const m = srv.model, defs = m && m.definitions || {}
110
- req.target = cds.infer(q,defs)
111
- }
108
+ const m = srv.model, defs = m && m.definitions || {}
109
+ req.target = typeof q === 'object' ? cds.infer(q,defs) : defs[req.path]
112
110
  }
113
111
 
114
112
  const _ensure_fqn = (x,p,srv, name = x[p]) => {