@sap/cds 5.8.4 → 5.9.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.
Files changed (248) hide show
  1. package/CHANGELOG.md +198 -77
  2. package/app/fiori/preview.js +16 -11
  3. package/app/fiori/routes.js +15 -8
  4. package/app/index.js +1 -1
  5. package/bin/build/buildTaskFactory.js +3 -3
  6. package/bin/build/buildTaskProviderFactory.js +1 -1
  7. package/bin/build/constants.js +1 -1
  8. package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
  9. package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
  10. package/bin/build/provider/buildTaskProviderInternal.js +8 -2
  11. package/bin/build/provider/hana/2migration.js +27 -24
  12. package/bin/build/provider/hana/index.js +17 -18
  13. package/bin/build/provider/hana/migrationtable.js +9 -10
  14. package/bin/build/provider/java-cf/index.js +4 -5
  15. package/bin/build/provider/node-cf/index.js +99 -6
  16. package/bin/cds.js +17 -18
  17. package/bin/deploy/to-hana/cfUtil.js +16 -19
  18. package/bin/deploy/to-hana/hana.js +7 -24
  19. package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
  20. package/bin/mtx/in-cds.js +2 -2
  21. package/bin/serve.js +10 -3
  22. package/bin/utils/modules.js +7 -0
  23. package/bin/version.js +56 -3
  24. package/lib/compile/cdsc.js +7 -2
  25. package/lib/compile/etc/_localized.js +37 -25
  26. package/lib/compile/etc/csv.js +8 -8
  27. package/lib/compile/for/drafts.js +9 -0
  28. package/lib/compile/for/java.js +16 -0
  29. package/lib/compile/for/nodejs.js +12 -0
  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/bindings.js +1 -1
  38. package/lib/connect/index.js +3 -4
  39. package/lib/core/entities.js +15 -14
  40. package/lib/core/index.js +39 -36
  41. package/lib/core/reflect.js +4 -2
  42. package/lib/deploy.js +114 -127
  43. package/lib/env/defaults.js +1 -0
  44. package/lib/env/index.js +165 -165
  45. package/lib/env/presets.js +1 -0
  46. package/lib/env/requires.js +121 -50
  47. package/lib/index.js +2 -0
  48. package/lib/log/format/kibana.js +2 -2
  49. package/lib/ql/SELECT.js +10 -0
  50. package/lib/ql/parse.js +1 -0
  51. package/lib/req/cds-context.js +4 -1
  52. package/lib/req/context.js +50 -56
  53. package/lib/req/event.js +1 -6
  54. package/lib/req/locale.js +6 -5
  55. package/lib/req/request.js +2 -0
  56. package/lib/req/user.js +7 -5
  57. package/lib/serve/Service-api.js +10 -7
  58. package/lib/serve/Service-dispatch.js +9 -11
  59. package/lib/serve/Service-methods.js +30 -41
  60. package/lib/serve/Transaction.js +10 -7
  61. package/lib/serve/adapters.js +11 -9
  62. package/lib/serve/factory.js +14 -9
  63. package/lib/serve/index.js +28 -15
  64. package/lib/utils/data.js +1 -1
  65. package/lib/utils/index.js +27 -30
  66. package/lib/utils/resources/index.js +101 -0
  67. package/lib/utils/resources/tar.js +71 -0
  68. package/lib/utils/resources/utils.js +11 -0
  69. package/libx/_runtime/audit/Service.js +36 -39
  70. package/libx/_runtime/audit/generic/personal/access.js +3 -4
  71. package/libx/_runtime/audit/generic/personal/modification.js +3 -4
  72. package/libx/_runtime/audit/utils/v2.js +1 -2
  73. package/libx/_runtime/auth/index.js +126 -84
  74. package/libx/_runtime/auth/strategies/JWT.js +12 -19
  75. package/libx/_runtime/auth/strategies/dummy.js +1 -5
  76. package/libx/_runtime/auth/strategies/dwc.js +11 -9
  77. package/libx/_runtime/auth/strategies/mock.js +0 -4
  78. package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
  79. package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
  80. package/libx/_runtime/auth/utils.js +22 -1
  81. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
  82. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +8 -3
  83. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
  84. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
  85. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
  86. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
  87. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
  88. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
  89. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
  90. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
  91. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
  92. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
  93. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
  94. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
  95. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
  96. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
  97. package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +56 -0
  98. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
  99. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
  100. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
  101. package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
  102. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
  103. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
  104. package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
  105. package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
  106. package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
  107. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
  108. package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
  109. package/libx/_runtime/cds-services/services/Service.js +40 -0
  110. package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
  111. package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
  112. package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
  113. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
  114. package/libx/_runtime/cds-services/util/assert.js +20 -14
  115. package/libx/_runtime/cds.js +9 -1
  116. package/libx/_runtime/common/aspects/any.js +5 -0
  117. package/libx/_runtime/common/aspects/entity.js +25 -7
  118. package/libx/_runtime/common/aspects/utils.js +2 -2
  119. package/libx/_runtime/common/composition/data.js +6 -0
  120. package/libx/_runtime/common/composition/insert.js +3 -2
  121. package/libx/_runtime/common/composition/tree.js +4 -10
  122. package/libx/_runtime/common/composition/update.js +4 -4
  123. package/libx/_runtime/common/constants/draft.js +29 -26
  124. package/libx/_runtime/common/error/constants.js +2 -2
  125. package/libx/_runtime/common/error/frontend.js +7 -15
  126. package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
  127. package/libx/_runtime/common/generic/auth/constants.js +20 -0
  128. package/libx/_runtime/common/generic/auth/expand.js +54 -0
  129. package/libx/_runtime/common/generic/auth/index.js +32 -0
  130. package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
  131. package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
  132. package/libx/_runtime/common/generic/auth/requires.js +34 -0
  133. package/libx/_runtime/common/generic/auth/restrict.js +298 -0
  134. package/libx/_runtime/common/generic/auth/restrictions.js +85 -0
  135. package/libx/_runtime/common/generic/auth/utils.js +213 -0
  136. package/libx/_runtime/common/generic/crud.js +8 -6
  137. package/libx/_runtime/common/generic/etag.js +1 -1
  138. package/libx/_runtime/common/generic/input.js +35 -35
  139. package/libx/_runtime/common/generic/sorting.js +2 -3
  140. package/libx/_runtime/common/generic/temporal.js +2 -2
  141. package/libx/_runtime/common/i18n/messages.properties +1 -1
  142. package/libx/_runtime/common/toggles/handler.js +21 -0
  143. package/libx/_runtime/common/utils/copy.js +10 -1
  144. package/libx/_runtime/common/utils/cqn2cqn4sql.js +111 -35
  145. package/libx/_runtime/common/utils/csn.js +63 -1
  146. package/libx/_runtime/common/utils/dollar.js +10 -1
  147. package/libx/_runtime/common/utils/draft.js +46 -7
  148. package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
  149. package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
  150. package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
  151. package/libx/_runtime/common/utils/generateOnCond.js +4 -1
  152. package/libx/_runtime/common/utils/quotingStyles.js +2 -0
  153. package/libx/_runtime/common/utils/resolveStructured.js +25 -9
  154. package/libx/_runtime/common/utils/resolveView.js +4 -1
  155. package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
  156. package/libx/_runtime/common/utils/structured.js +33 -37
  157. package/libx/_runtime/common/utils/template.js +17 -8
  158. package/libx/_runtime/common/utils/templateProcessor.js +28 -28
  159. package/libx/_runtime/db/data-conversion/post-processing.js +118 -412
  160. package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
  161. package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
  162. package/libx/_runtime/db/generic/index.js +1 -3
  163. package/libx/_runtime/db/generic/input.js +5 -10
  164. package/libx/_runtime/db/generic/rewrite.js +5 -2
  165. package/libx/_runtime/db/generic/structured.js +2 -2
  166. package/libx/_runtime/db/query/delete.js +2 -2
  167. package/libx/_runtime/db/query/insert.js +1 -1
  168. package/libx/_runtime/db/query/update.js +9 -14
  169. package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
  170. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +8 -8
  171. package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
  172. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
  173. package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
  174. package/libx/_runtime/db/utils/columns.js +3 -3
  175. package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
  176. package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
  177. package/libx/_runtime/extensibility/mps/index.js +5 -0
  178. package/libx/_runtime/extensibility/mps/service.js +111 -0
  179. package/libx/_runtime/extensibility/mps/tar.js +42 -0
  180. package/libx/_runtime/extensibility/mps/utils.js +11 -0
  181. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
  182. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
  183. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
  184. package/libx/_runtime/extensibility/uiflex/index.js +54 -0
  185. package/libx/_runtime/extensibility/uiflex/service.js +276 -0
  186. package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
  187. package/libx/_runtime/fiori/generic/activate.js +2 -2
  188. package/libx/_runtime/fiori/generic/before.js +4 -4
  189. package/libx/_runtime/fiori/generic/new.js +3 -3
  190. package/libx/_runtime/fiori/generic/patch.js +1 -1
  191. package/libx/_runtime/fiori/generic/read.js +58 -66
  192. package/libx/_runtime/fiori/generic/readOverDraft.js +74 -16
  193. package/libx/_runtime/fiori/utils/handler.js +6 -13
  194. package/libx/_runtime/fiori/utils/where.js +6 -5
  195. package/libx/_runtime/hana/Service.js +4 -10
  196. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +1 -1
  197. package/libx/_runtime/hana/driver.js +2 -2
  198. package/libx/_runtime/hana/execute.js +45 -75
  199. package/libx/_runtime/hana/pool.js +1 -1
  200. package/libx/_runtime/hana/streaming.js +2 -1
  201. package/libx/_runtime/index.js +6 -6
  202. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
  203. package/libx/_runtime/messaging/Outbox.js +2 -2
  204. package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
  205. package/libx/_runtime/messaging/common-utils/connections.js +5 -7
  206. package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
  207. package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
  208. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
  209. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
  210. package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
  211. package/libx/_runtime/messaging/file-based.js +5 -5
  212. package/libx/_runtime/messaging/message-queuing.js +14 -12
  213. package/libx/_runtime/messaging/outbox/utils.js +18 -19
  214. package/libx/_runtime/messaging/redis-messaging.js +91 -0
  215. package/libx/_runtime/messaging/service.js +8 -6
  216. package/libx/_runtime/remote/Service.js +44 -8
  217. package/libx/_runtime/remote/utils/client.js +24 -19
  218. package/libx/_runtime/remote/utils/data.js +11 -11
  219. package/libx/_runtime/sqlite/Service.js +6 -9
  220. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
  221. package/libx/_runtime/types/api.js +10 -2
  222. package/libx/common/utils/ucsn.js +109 -0
  223. package/libx/gql/resolvers/crud/update.js +5 -0
  224. package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
  225. package/libx/gql/schema/typeDefMap.js +2 -2
  226. package/libx/odata/afterburner.js +110 -16
  227. package/libx/odata/cqn2odata.js +24 -27
  228. package/libx/odata/grammar.pegjs +9 -1
  229. package/libx/odata/parseToCqn.js +39 -0
  230. package/libx/odata/parser.js +1 -1
  231. package/libx/rest/RestAdapter.js +9 -1
  232. package/libx/rest/middleware/input.js +54 -0
  233. package/libx/rest/middleware/operation.js +14 -1
  234. package/libx/rest/middleware/parse.js +11 -7
  235. package/package.json +2 -2
  236. package/server.js +34 -19
  237. package/srv/audit-log.cds +2 -2
  238. package/srv/flex.cds +8 -2
  239. package/srv/flex.js +1 -1
  240. package/srv/mps.cds +23 -0
  241. package/srv/mps.js +1 -0
  242. package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
  243. package/libx/_runtime/common/generic/auth.js +0 -874
  244. package/libx/_runtime/common/toggles/alpha.js +0 -43
  245. package/libx/_runtime/db/generic/arrayed.js +0 -33
  246. package/libx/_runtime/fiori/uiflex/index.js +0 -35
  247. package/libx/_runtime/fiori/uiflex/service.js +0 -150
  248. package/libx/rest/utils/data.js +0 -60
@@ -1,5 +1,6 @@
1
- const cds = require('..')
2
- const { path, isfile } = cds.utils
1
+ const cds = require('..'), { path, isfile } = cds.utils
2
+ const paths = Array.from (new Set ([ cds.root, ...require.resolve.paths('x') ]))
3
+ const DEBUG = cds.debug('srv.factory'); DEBUG && DEBUG ({ 'cds.root':cds.root, paths })
3
4
 
4
5
  /** @typedef {import('./Service-api')} Service @type { (()=>Service) & (new()=>Service) } */
5
6
  const ServiceFactory = function (name, model, options) { //NOSONAR
@@ -8,6 +9,7 @@ const ServiceFactory = function (name, model, options) { //NOSONAR
8
9
  const serve = !cds.requires[name] || o.mocked
9
10
  const defs = !model ? {[name]:{}} : model.definitions || cds.error (`Invalid argument for 'model': ${model}`)
10
11
  const def = !name || name === 'db' ? {} : defs[name] || {}
12
+ DEBUG && DEBUG ({ name, definition:def, options:o })
11
13
 
12
14
  let it /* eslint-disable no-cond-assign */
13
15
  if (it = o.with) return _use (it) // from cds.serve (<options>)
@@ -27,21 +29,24 @@ const ServiceFactory = function (name, model, options) { //NOSONAR
27
29
 
28
30
  function _required() {
29
31
  const kind = o.kind = serve && def['@kind'] || o.kind || 'app-service'
30
- if (_required[kind]) return _required[kind]
32
+ if (_require[kind]) return _require[kind]
31
33
  const {impl} = cds.requires[kind] || cds.error (`No configuration found for 'cds.requires.${kind}'`)
32
- return _required[kind] = _require (impl || cds.error (`No 'impl' configured for 'cds.requires.${kind}'`))
34
+ DEBUG && DEBUG ('requires',{kind,impl})
35
+ return _require[kind] = _require (impl || cds.error (`No 'impl' configured for 'cds.requires.${kind}'`))
33
36
  }
34
37
  }
35
38
 
36
39
  const _require = (it,d) => {
37
- if (it.startsWith('@sap/cds/')) it = cds.home + it.slice(8) //> for local tests in @sap/cds dev
38
- else if (it.startsWith('./')) it = _relative (d, it.slice(2)) //> relative to <service>.cds
39
- else if (it.startsWith('//')) it = path.resolve (cds.root,it.slice(2)) //> relative to cds.root
40
- try { var resolved = require.resolve(it) } catch(e) {
40
+ DEBUG && d && DEBUG ('requires',{ service: d.name, source:_source(d), impl:it })
41
+ if (it.startsWith('@sap/cds/')) it = cds.home + it.slice(8) //> for local tests in @sap/cds dev
42
+ if (it.startsWith('./')) it = _relative (d,it.slice(2)) //> relative to <service>.cds
43
+ try { var resolved = require.resolve(it,{paths}) } catch(e) {
41
44
  try { resolved = require.resolve(it = path.resolve(cds.root,it)) } catch(e) { // for compatibility
45
+ DEBUG && DEBUG (`Failed loading service implementation from '${it}'`, { 'cds.root':cds.root, paths })
42
46
  throw cds.error(`Failed loading service implementation from '${it}'`)
43
47
  }
44
48
  }
49
+ DEBUG && DEBUG({resolved})
45
50
  return require(resolved)
46
51
  }
47
52
 
@@ -59,7 +64,7 @@ const sibling = (d) => {
59
64
  let found
60
65
  if (process.env.CDS_TYPESCRIPT === 'true') found = isfile(path.join(home, each, file + '.ts'))
61
66
  if (!found) found = isfile(path.join(home, each, file + '.js'))
62
- if (found) return found
67
+ if (found) return found //> equiv to '.'+found.slice(home.length)
63
68
  }
64
69
  }
65
70
 
@@ -1,13 +1,19 @@
1
- const { ProtocolAdapter } = require('./adapters')
2
- const { Service } = require('./factory')
3
1
  const cds = require ('..')
2
+ const { ProtocolAdapter } = cds.service.adapters
3
+ const { Service } = cds.service.factory
4
4
  const _ready = Symbol(), _pending = cds.services._pending || {}
5
5
 
6
6
  /** @param som - a service name or a model (name or csn) */
7
7
  function cds_serve (som, _options) { // NOSONAR
8
8
 
9
- if (Array.isArray(som) && som.length === 1) som = som[0]
10
- else if (typeof som === 'object' && !is_csn(som)) [som,_options] = [undefined,som]
9
+ if (som && typeof som === 'object' && !is_csn(som)) {
10
+ [som,_options] = [undefined,
11
+ som._is_service_instance ? { service:som, from:'*' } :
12
+ som._is_service_class ? { service:som, from:'*' } :
13
+ som
14
+ ]
15
+ }
16
+ else if (Array.isArray(som) && som.length === 1) som = som[0]
11
17
  const o = {..._options} // we must not modify inbound data
12
18
 
13
19
  // 1) Use fluent API to fill in remaining options...
@@ -40,26 +46,32 @@ function cds_serve (som, _options) { // NOSONAR
40
46
  // 4) Pass 1: Construct service provider instances...
41
47
  const all=[], provided = loaded.then (csn => { // NOSONAR
42
48
 
49
+ // Shortcut for directly passed service instances
50
+ if (o.service && o.service._is_service_instance) {
51
+ return all.push (o.service)
52
+ }
53
+
43
54
  // Shortcut for directly passed service classes
44
55
  if (o.service && o.service._is_service_class) {
45
56
  const Service = o.service, d = { name: o.service.name }
46
- return all.push (_new (Service, d,csn,o))
57
+ const srv = _new (Service, d,csn,o)
58
+ return all.push (srv)
47
59
  }
48
60
 
49
61
  // Get relevant service definitions from model...
50
- let {services} = csn = cds.linked (cds.compile.for.odata (csn))
51
- let specified = o.service
52
- if (specified && specified !== 'all') {
62
+ let {services} = csn = cds.compile.for.nodejs (csn)
63
+ const required = cds.requires
64
+ if (o.service && o.service !== 'all') {
53
65
  // skip services not chosen by o.service, if specified
54
- if (cds.requires[specified]) specified = cds.requires[specified].service || specified
55
- services = services.filter (s => s.name.endsWith (specified))
56
- if (!services.length) throw cds.error (`No such service: '${specified}'`)
66
+ const specified = o.service.split(/\s*,\s*/).map (s => required[s] && required[s].service || s )
67
+ services = services.filter (s => specified.some (n => s.name.endsWith(n)))
68
+ if (!services.length) throw cds.error (`No such service: '${o.service}'`)
57
69
  }
58
70
  services = services.filter (d => !(
59
71
  // skip all services marked to be ignored
60
72
  d['@cds.ignore'] || d['@cds.serve.ignore'] ||
61
73
  // skip external services, unless asked to mock them and unbound
62
- cds.requires[d.name] && (!o.mocked || cds.requires[d.name].credentials)
74
+ required[d.name] && (!o.mocked || required[d.name].credentials)
63
75
  ))
64
76
  if (services.length > 1 && o.at) {
65
77
  throw cds.error `You cannot specify 'path' for multiple services`
@@ -73,11 +85,12 @@ function cds_serve (som, _options) { // NOSONAR
73
85
  // Note: doing that in a second pass guarantees all own services are in
74
86
  // cds.services, so they'll be found when they cds.connect to each others.
75
87
  let ready = provided.then (()=> Promise.all (all.map (async srv => {
88
+ if (o.service && o.service._is_service_instance) return srv
76
89
  srv.init && await srv.prepend (srv.init)
77
90
  srv.options.impl && await srv.prepend (srv.options.impl)
78
91
  cds.services[srv.name] = cds.service.paths[srv.path] = srv
79
92
  cds.service.providers.push (srv)
80
- srv[_ready](srv)
93
+ if (srv[_ready]) srv[_ready](srv)
81
94
  return srv
82
95
  })))
83
96
 
@@ -93,7 +106,7 @@ function cds_serve (som, _options) { // NOSONAR
93
106
 
94
107
  for (let each of all) {
95
108
  each._edm = edms[each.name]
96
- ProtocolAdapter.serve(each).in(app)
109
+ ProtocolAdapter.serve(each,o.to).in(app)
97
110
  if (!o.silent) cds.emit ('serving',each)
98
111
  }
99
112
  })
@@ -105,7 +118,7 @@ function cds_serve (som, _options) { // NOSONAR
105
118
  if (all.length === 0) return resolve()
106
119
  let response={}
107
120
  for (let each of all) {
108
- response[each.name] = !each.definition ? each : ProtocolAdapter.serve(each).asRouter()
121
+ response[each.name] = !each.definition ? each : ProtocolAdapter.serve(each,o.to).asRouter()
109
122
  }
110
123
  if (all.length === 1 && all[0].name.endsWith (o.service)) {
111
124
  response = Object.assign (all[0], response)
package/lib/utils/data.js CHANGED
@@ -23,7 +23,7 @@ class DataUtil {
23
23
  async reset(db) {
24
24
  if (!db) db = await cds.connect.to('db')
25
25
  await this.delete(db)
26
- await cds.deploy(db.model).to(db, {ddl:false})
26
+ await cds.deploy.init(db)
27
27
  }
28
28
 
29
29
  autoReset(enabled) { this._autoReset = enabled; return this }
@@ -1,16 +1,17 @@
1
1
  const cwd = process.env._original_cwd || process.cwd()
2
2
  const path = require ('path'), { dirname, join, resolve, sep, relative } = path
3
- const fs = require ('fs'), { lstat, access, rm, rmdir, readdir, unlink } = fs.promises
4
- const rw = fs.constants.R_OK | fs.constants.W_OK
3
+ const fs = require('fs')
5
4
  const cds = global.cds
6
5
 
7
- module.exports = exports = {
8
- get uuid() { return $set (this, 'uuid', require('@sap/cds-foss').uuid) }
6
+ const all = module.exports = exports = { ...fs,
7
+ get inspect() { return $set (this, 'inspect', require('util').inspect) },
8
+ get uuid() { return $set (this, 'uuid', require('@sap/cds-foss').uuid) },
9
9
  }
10
10
 
11
- exports.local = (file) => '.' + sep + relative(cwd,file)
11
+ exports.fs = all
12
12
  exports.path = path
13
- exports.fs = fs
13
+
14
+ exports.local = (file) => '.' + sep + relative(cwd,file)
14
15
 
15
16
  exports.readdir = async function (x) {
16
17
  const d = resolve (cds.root,x)
@@ -54,45 +55,41 @@ exports.read = async function read (file, _encoding) {
54
55
  }
55
56
 
56
57
  exports.write = function write (file, data, o) {
57
- if (arguments.length === 1) return {to:f => write(f,file)}
58
- if (typeof data === 'object') data = JSON.stringify(data, null, ' '.repeat(o && o.spaces))
58
+ if (arguments.length === 1) return {to:(...path) => write(join(...path),file)}
59
+ if (typeof data === 'object' && !Buffer.isBuffer(data))
60
+ data = JSON.stringify(data, null, ' '.repeat(o && o.spaces))
59
61
  const f = resolve (cds.root,file)
60
- return mkdirp (dirname(f)).then (()=> fs.promises.writeFile (f,data))
62
+ return mkdirp (dirname(f)).then (()=> fs.promises.writeFile (f,data,o))
61
63
  }
62
64
 
63
- exports.mkdirp = async function mkdirp (dir) {
64
- const d = resolve (cds.root,dir)
65
- try { await access(d,rw) } catch(_) {
66
- await mkdirp (dirname(d))
67
- try { await fs.promises.mkdir(d) }
68
- catch(e) { if (e.code !== 'EEXIST' /*may still happen with parallel calls*/) throw e }
69
- }
65
+ exports.mkdirp = async function (...path) {
66
+ const d = resolve (cds.root,...path)
67
+ await fs.promises.mkdir (d,{recursive:true})
70
68
  return d
71
69
  }
72
70
 
73
- exports.rm = async function rm (x) {
74
- const y = resolve (cds.root,x)
75
- return unlink(y)
71
+ exports.rmdir = (...path) => {
72
+ const d = resolve (cds.root,...path)
73
+ return (fs.promises.rm || fs.promises.rmdir) (d, {recursive:true})
74
+ }
75
+
76
+ exports.rimraf = (...path) => {
77
+ const d = resolve (cds.root,...path)
78
+ return (fs.promises.rm || fs.promises.rmdir) (d, {recursive:true,force:true})
76
79
  }
77
80
 
78
- exports.rimraf = async function rimraf (dir) {
79
- if (rm) return rm (dir, {recursive:true,force:true}) //> added in Node 14
80
- const d = resolve(cds.root,dir)
81
- const entries = await readdir(d)
82
- await Promise.all (entries.map (async each => {
83
- const e = join (d,each)
84
- const ls = await lstat(e)
85
- return ls.isDirectory() ? rimraf(e) : unlink(e)
86
- }))
87
- return rmdir(d)
81
+ exports.rm = async function rm (x) {
82
+ const y = resolve (cds.root,x)
83
+ return (fs.promises.rm || fs.promises.unlink)(y)
88
84
  }
89
85
 
90
86
  exports.copy = async function copy (x,y) {
91
87
  const src = resolve (cds.root,x)
92
88
  const dst = resolve (cds.root,y)
89
+ if (fs.promises.cp) return fs.promises.cp (src,dst,{recursive:true})
93
90
  await mkdirp (dirname(dst))
94
91
  if (isdir(src)) {
95
- const entries = await readdir(src)
92
+ const entries = await fs.promises.readdir(src)
96
93
  return Promise.all (entries.map (async each => {
97
94
  const e = join (src,each)
98
95
  const f = join (src,each)
@@ -0,0 +1,101 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+
4
+ const cds = require('../../../libx/_runtime/cds')
5
+ const { packArchive, packArchiveCLI, unpackArchive, unpackArchiveCLI } = require('./tar')
6
+ const { exists } = require('./utils')
7
+
8
+ // use tar command line interface
9
+ const TAR_CLI = true
10
+ const TEMP_DIR = fs.realpathSync(require('os').tmpdir())
11
+
12
+ const findCsvFiles = async (folder, deep = false) => {
13
+ const files = await fs.promises.readdir(folder)
14
+ const result = []
15
+
16
+ for (const file of files) {
17
+ const filePath = path.join(folder, file)
18
+ if (deep && (await fs.promises.stat(filePath)).isDirectory()) {
19
+ const files = await findCsvFiles(filePath)
20
+ result.push(...files)
21
+ } else {
22
+ if (path.extname(file) === '.csv') {
23
+ result.push(filePath)
24
+ }
25
+ }
26
+ }
27
+
28
+ return result
29
+ }
30
+
31
+ const collectCsvFiles = async sources => {
32
+ const folders = sources.map(file => path.dirname(file))
33
+ const uniqueFolders = [...new Set(folders)].filter(folder => !/node_modules/.test(folder))
34
+ const db = (cds.env.folders && cds.env.folders.db) || 'db/'
35
+ let dbFolder = path.join(global.cds.root, db)
36
+ if (dbFolder.endsWith('/') || dbFolder.endsWith('\\')) dbFolder = dbFolder.slice(0, -1)
37
+ if (!uniqueFolders.includes(dbFolder)) uniqueFolders.push(dbFolder)
38
+
39
+ const result = []
40
+ for (const folder of uniqueFolders) {
41
+ const dataPath = path.join(folder, 'data')
42
+ const dataFiles = (await exists(dataPath)) ? await findCsvFiles(dataPath) : []
43
+ const csvPath = path.join(folder, 'csv')
44
+ const csvFiles = (await exists(csvPath)) ? await findCsvFiles(csvPath) : []
45
+ result.push(...dataFiles, ...csvFiles)
46
+ }
47
+
48
+ return result
49
+ }
50
+
51
+ const packTarArchive = async (files, root, flat = false, cli = true) => {
52
+ let tgzBuffer, temp
53
+
54
+ try {
55
+ temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
56
+ if (flat) {
57
+ const files_ = []
58
+ for (const file of files) {
59
+ const destination = path.join(temp, path.basename(file))
60
+ await fs.promises.copyFile(file, destination)
61
+ files_.push(destination)
62
+ }
63
+ files = files_
64
+ root = temp
65
+ }
66
+
67
+ const relativeFiles = files.map(file => path.relative(root, file))
68
+ if (cli) {
69
+ const output = path.relative(root, path.join(temp, `${cds.utils.uuid()}.tgz`))
70
+ tgzBuffer = await packArchiveCLI(relativeFiles, root, output)
71
+ } else {
72
+ tgzBuffer = await packArchive(relativeFiles, root)
73
+ }
74
+ } finally {
75
+ if (await exists(temp)) {
76
+ await (fs.promises.rm || fs.promises.rmdir)(temp, { recursive: true, force: true })
77
+ }
78
+ }
79
+
80
+ return tgzBuffer
81
+ }
82
+
83
+ const unpackTarArchive = async (buffer, folder, cli = true) => {
84
+ const temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
85
+ const tgz = path.join(temp, 'resources.tgz')
86
+ await fs.promises.writeFile(tgz, buffer, 'binary')
87
+
88
+ try {
89
+ cli ? await unpackArchiveCLI(tgz, folder) : await unpackArchive(tgz, folder)
90
+ } finally {
91
+ if (await exists(temp)) await (fs.promises.rm || fs.promises.rmdir)(temp, { recursive: true, force: true })
92
+ }
93
+ }
94
+
95
+ module.exports = {
96
+ TAR_CLI,
97
+ findCsvFiles,
98
+ collectCsvFiles,
99
+ packTarArchive,
100
+ unpackTarArchive
101
+ }
@@ -0,0 +1,71 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const tar = require('tar')
4
+ const exec = require('child_process').exec
5
+
6
+ const _createArchive = (files, root) => {
7
+ return tar.c(
8
+ {
9
+ gzip: true,
10
+ preservePaths: false,
11
+ cwd: root
12
+ },
13
+ files
14
+ )
15
+ }
16
+
17
+ const _createArchiveCLI = (files, root, output) => {
18
+ const cmd = 'cd ' + root + ' && tar -czf ' + output + ' ' + files.join(' ')
19
+
20
+ return new Promise((resolve, reject) => {
21
+ exec(cmd, err => {
22
+ if (err) reject(err)
23
+ else resolve()
24
+ })
25
+ })
26
+ }
27
+
28
+ const packArchive = (files, root) => {
29
+ _createArchive(files, root)
30
+ const stream = _createArchive(files, root)
31
+ return new Promise((resolve, reject) => {
32
+ const chunks = []
33
+ stream.on('data', data => chunks.push(data))
34
+ stream.on('error', error => reject(error))
35
+ stream.on('end', () => {
36
+ resolve(Buffer.concat(chunks))
37
+ })
38
+ })
39
+ }
40
+
41
+ const packArchiveCLI = async (files, root, output) => {
42
+ await _createArchiveCLI(files, root, output)
43
+
44
+ return fs.promises.readFile(path.join(root, output))
45
+ }
46
+
47
+ const unpackArchive = async (tgz, folder) => {
48
+ await tar.x({
49
+ file: tgz,
50
+ gzip: true,
51
+ C: folder
52
+ })
53
+ }
54
+
55
+ const unpackArchiveCLI = async (tgz, folder) => {
56
+ const cmd = 'tar -xzf ' + tgz + ' -C ' + folder
57
+
58
+ return new Promise((resolve, reject) => {
59
+ exec(cmd, err => {
60
+ if (err) reject(err)
61
+ else resolve()
62
+ })
63
+ })
64
+ }
65
+
66
+ module.exports = {
67
+ packArchive,
68
+ packArchiveCLI,
69
+ unpackArchive,
70
+ unpackArchiveCLI
71
+ }
@@ -0,0 +1,11 @@
1
+ const fs = require('fs')
2
+
3
+ const exists = async fileOrDir => {
4
+ try {
5
+ return await fs.promises.stat(fileOrDir)
6
+ } catch (_) {
7
+ return false
8
+ }
9
+ }
10
+
11
+ module.exports = { exists }
@@ -15,23 +15,23 @@ module.exports = class AuditLogService extends OutboxService {
15
15
  // call OutboxService's init, which handles outboxing
16
16
  await super.init()
17
17
 
18
- // register handlers
19
- this.on('dataAccessLog', this.dataAccessLog)
20
- this.on('dataModificationLog', this.dataModificationLog)
21
- this.on('securityLog', this.securityLog)
22
- this.on('configChangeLog', this.configChangeLog)
23
-
24
18
  // connect to audit log service
25
- // REVISIT for GA: throw error on connect issue instead of warn and this.ready?
26
19
  this.alc = await v2utils.connect(this.options.credentials)
27
- this.ready = !!this.alc
20
+
21
+ // register handlers, if connected
22
+ if (this.alc) {
23
+ this.on('dataAccessLog', this._dataAccessLog)
24
+ this.on('dataModificationLog', this._dataModificationLog)
25
+ this.on('securityLog', this._securityLog)
26
+ this.on('configChangeLog', this._configChangeLog)
27
+ }
28
28
  }
29
29
 
30
30
  async emit(first, second) {
31
31
  const { event, data } = typeof first === 'object' ? first : { event: first, data: second }
32
32
  if (!this.options.outbox) return this.send(event, data)
33
33
 
34
- if (this.ready && this[event]) {
34
+ if (this[event]) {
35
35
  try {
36
36
  // this will open a new tx -> preserve user
37
37
  await super.send(new cds.Request({ method: event, data, user: cds.context.user }))
@@ -45,14 +45,34 @@ module.exports = class AuditLogService extends OutboxService {
45
45
  }
46
46
 
47
47
  async send(event, data) {
48
- if (this.ready && this[event]) return super.send(event, data)
48
+ if (this[event]) return super.send(event, data)
49
+ }
50
+
51
+ /*
52
+ * api (await AuditLogService.<event>(data))
53
+ */
54
+
55
+ async dataAccessLog(data) {
56
+ return super.send('dataAccessLog', data)
49
57
  }
50
58
 
51
- async dataAccessLog(arg) {
52
- const accesses = arg.accesses || arg.data.accesses
59
+ async dataModificationLog(data) {
60
+ return super.send('dataModificationLog', data)
61
+ }
53
62
 
54
- if (!this.ready) throw new Error('AuditLogService not connected')
63
+ async securityLog(data) {
64
+ return super.send('securityLog', data)
65
+ }
66
+
67
+ async configChangeLog(data) {
68
+ return super.send('configChangeLog', data)
69
+ }
55
70
 
71
+ /*
72
+ * impl
73
+ */
74
+
75
+ async _dataAccessLog({ data: { accesses } }) {
56
76
  const { tenant, user } = _getTenantAndUser()
57
77
 
58
78
  // build the logs
@@ -73,11 +93,7 @@ module.exports = class AuditLogService extends OutboxService {
73
93
  }
74
94
 
75
95
  // REVISIT: modification.action not used in auditlog v2
76
- async dataModificationLog(arg) {
77
- const modifications = arg.modifications || arg.data.modifications
78
-
79
- if (!this.ready) throw new Error('AuditLogService not connected')
80
-
96
+ async _dataModificationLog({ data: { modifications } }) {
81
97
  const { tenant, user } = _getTenantAndUser()
82
98
 
83
99
  // build the logs
@@ -97,15 +113,7 @@ module.exports = class AuditLogService extends OutboxService {
97
113
  }
98
114
  }
99
115
 
100
- async securityLog(arg) {
101
- let { action, data } = arg
102
- if (arg.data && arg.data.action) {
103
- action = arg.data.action
104
- data = arg.data.data
105
- }
106
-
107
- if (!this.ready) throw new Error('AuditLogService not connected')
108
-
116
+ async _securityLog({ data: { action, data } }) {
109
117
  let { tenant, user } = _getTenantAndUser()
110
118
 
111
119
  // cds.context may not be proper on auth-related errors -> try to extract from data
@@ -132,18 +140,7 @@ module.exports = class AuditLogService extends OutboxService {
132
140
  }
133
141
 
134
142
  // REVISIT: action and success not used in auditlog v2
135
- async configChangeLog(arg) {
136
- let { action, success, configurations } = arg
137
- if (arg.data) {
138
- // eslint-disable-next-line no-unused-vars
139
- action = arg.data.action
140
- // eslint-disable-next-line no-unused-vars
141
- success = arg.data.success
142
- configurations = arg.data.configurations
143
- }
144
-
145
- if (!this.ready) throw new Error('AuditLogService not connected')
146
-
143
+ async _configChangeLog({ data: { action, success, configurations } }) {
147
144
  const { tenant, user } = _getTenantAndUser()
148
145
 
149
146
  // build the logs
@@ -13,7 +13,7 @@ const {
13
13
  resolveDataSubjectPromises
14
14
  } = require('./utils')
15
15
 
16
- let als
16
+ let auditLogService
17
17
 
18
18
  const _processorFnAccess = (accessLogs, model, req) => {
19
19
  return ({ row, key, element, plain }) => {
@@ -70,15 +70,14 @@ const _getDataAccessLogs = (data, req, tx) => {
70
70
  }
71
71
 
72
72
  const auditAccessHandler = async function (data, req) {
73
- als = als || (await cds.connect.to('audit-log'))
74
- if (!als.ready) return
73
+ auditLogService = auditLogService || (await cds.connect.to('audit-log'))
75
74
 
76
75
  const accessLogs = _getDataAccessLogs(data, req, this)
77
76
  // REVISIT: a function called resolveDataSubjectPromises should not also convert an object to an array
78
77
  let accesses = await resolveDataSubjectPromises(accessLogs)
79
78
  accesses = accesses.filter(ele => ele.attributes.length)
80
79
 
81
- if (accesses.length) await als.emit('dataAccessLog', { accesses })
80
+ if (accesses.length) await auditLogService.emit('dataAccessLog', { accesses })
82
81
  }
83
82
 
84
83
  module.exports = {
@@ -14,7 +14,7 @@ const {
14
14
  resolveDataSubjectPromises
15
15
  } = require('./utils')
16
16
 
17
- let als
17
+ let auditLogService
18
18
 
19
19
  const attachDiffToContextHandler = async function (req) {
20
20
  // store diff in audit data structure at context
@@ -112,15 +112,14 @@ const calcModificationLogsHandler4After = function (_, req) {
112
112
  }
113
113
 
114
114
  const emitModificationHandler = async function (_, req) {
115
- als = als || (await cds.connect.to('audit-log'))
116
- if (!als.ready) return
115
+ auditLogService = auditLogService || (await cds.connect.to('audit-log'))
117
116
 
118
117
  const modificationLogs = req.context._audit.modificationLogs.get(req.query)
119
118
  const modifications = Object.keys(modificationLogs)
120
119
  .map(k => modificationLogs[k])
121
120
  .filter(log => log.attributes.length)
122
121
 
123
- await als.emit('dataModificationLog', { modifications })
122
+ await auditLogService.emit('dataModificationLog', { modifications })
124
123
  }
125
124
 
126
125
  module.exports = {
@@ -9,8 +9,7 @@ function connect(credentials) {
9
9
  try {
10
10
  auditLogging = require('@sap/audit-logging')
11
11
  } catch (e) {
12
- LOG._warn &&
13
- LOG.warn('Unable to require module @sap/audit-logging. Make sure it is installed if audit logging is required.')
12
+ // not able to require lib -> no audit logging ootb
14
13
  return resolve()
15
14
  }
16
15
  try {