@sap/cds 7.9.3 → 8.0.3

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 (278) hide show
  1. package/CHANGELOG.md +126 -3655
  2. package/_i18n/i18n_en_US_saptrc.properties +113 -0
  3. package/_i18n/i18n_zh_CN.properties +7 -4
  4. package/app/index.css +129 -0
  5. package/app/index.html +16 -64
  6. package/app/index.js +14 -9
  7. package/bin/args.js +34 -0
  8. package/bin/serve.js +18 -24
  9. package/bin/test.js +97 -0
  10. package/common.cds +5 -12
  11. package/eslint.config.mjs +133 -0
  12. package/lib/auth/basic-auth.js +16 -20
  13. package/lib/auth/dummy-auth.js +1 -1
  14. package/lib/auth/ias-auth.js +9 -41
  15. package/lib/auth/index.js +1 -14
  16. package/lib/auth/jwt-auth.js +10 -40
  17. package/lib/compile/cds-compile.js +1 -2
  18. package/lib/compile/cdsc.js +21 -26
  19. package/lib/compile/etc/_localized.js +1 -6
  20. package/lib/compile/etc/csv.js +1 -1
  21. package/lib/compile/etc/properties.js +1 -1
  22. package/lib/compile/for/java.js +1 -1
  23. package/lib/compile/for/lean_drafts.js +4 -6
  24. package/lib/compile/for/nodejs.js +1 -1
  25. package/lib/compile/parse.js +4 -0
  26. package/lib/compile/resolve.js +4 -4
  27. package/lib/compile/to/edm-files.js +16 -23
  28. package/lib/compile/to/hana.js +27 -0
  29. package/lib/compile/to/json.js +1 -1
  30. package/lib/compile/to/sql.js +5 -1
  31. package/lib/compile/to/yaml.js +3 -3
  32. package/lib/dbs/cds-deploy.js +4 -2
  33. package/lib/env/cds-env.js +10 -14
  34. package/lib/env/cds-requires.js +29 -13
  35. package/lib/env/defaults.js +46 -16
  36. package/lib/env/plugins.js +1 -1
  37. package/lib/env/schemas/cds-rc.js +8 -4
  38. package/lib/env/schemas/index.js +7 -7
  39. package/lib/env/serviceBindings.js +1 -1
  40. package/lib/index.js +12 -10
  41. package/lib/lazy.js +1 -1
  42. package/lib/linked/classes.js +36 -8
  43. package/lib/linked/entities.js +2 -10
  44. package/lib/linked/models.js +2 -1
  45. package/lib/linked/validate.js +292 -0
  46. package/lib/log/cds-error.js +0 -6
  47. package/lib/log/cds-log.js +3 -3
  48. package/lib/log/format/json.js +1 -1
  49. package/lib/log/service/index.js +0 -1
  50. package/lib/plugins.js +2 -2
  51. package/lib/ql/Query.js +2 -10
  52. package/lib/ql/SELECT.js +1 -1
  53. package/lib/ql/Whereable.js +3 -2
  54. package/lib/req/cds-context.js +14 -25
  55. package/lib/req/context.js +23 -25
  56. package/lib/req/request.js +1 -34
  57. package/lib/req/user.js +47 -35
  58. package/lib/srv/bindings.js +1 -1
  59. package/lib/srv/cds-connect.js +4 -4
  60. package/lib/srv/cds-serve.js +2 -2
  61. package/lib/srv/factory.js +1 -1
  62. package/lib/srv/middlewares/cds-context.js +11 -22
  63. package/lib/srv/middlewares/ctx-model.js +2 -3
  64. package/lib/srv/middlewares/errors.js +41 -8
  65. package/lib/srv/middlewares/index.js +3 -3
  66. package/lib/srv/middlewares/trace.js +0 -2
  67. package/lib/srv/protocols/hcql.js +15 -10
  68. package/lib/srv/protocols/http.js +44 -49
  69. package/lib/srv/protocols/index.js +1 -23
  70. package/lib/srv/protocols/odata-v4.js +12 -74
  71. package/lib/srv/protocols/rest.js +1 -13
  72. package/lib/srv/srv-api.js +0 -20
  73. package/lib/srv/srv-dispatch.js +3 -2
  74. package/lib/srv/srv-handlers.js +22 -11
  75. package/lib/srv/srv-methods.js +2 -2
  76. package/lib/srv/srv-models.js +3 -36
  77. package/lib/test/expect.js +343 -0
  78. package/lib/test/index.js +2 -0
  79. package/lib/test/reporter.js +176 -0
  80. package/lib/utils/axios.js +10 -9
  81. package/lib/utils/cds-test.js +85 -36
  82. package/lib/utils/cds-utils.js +54 -7
  83. package/lib/utils/check-version.js +0 -4
  84. package/lib/utils/colors.js +49 -0
  85. package/lib/utils/data.js +5 -4
  86. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -7
  87. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +3 -30
  88. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +6 -12
  89. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -3
  90. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +0 -1
  91. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +4 -7
  92. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +12 -6
  93. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +2 -4
  94. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +1 -0
  95. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  96. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
  97. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +1 -3
  98. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
  99. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/AbstractEdmStructuredType.js +1 -2
  100. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -0
  101. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +1 -1
  102. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +9 -43
  103. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +0 -1
  104. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +8 -3
  105. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +4 -2
  106. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +1 -3
  107. package/libx/_runtime/cds-services/util/assert.js +1 -1
  108. package/libx/_runtime/cds.js +10 -3
  109. package/libx/_runtime/common/Service.js +12 -32
  110. package/libx/_runtime/common/aspects/any.js +1 -0
  111. package/libx/_runtime/common/code-ext/execute.js +1 -1
  112. package/libx/_runtime/common/code-ext/worker.js +0 -1
  113. package/libx/_runtime/common/composition/data.js +0 -1
  114. package/libx/_runtime/common/composition/delete.js +0 -1
  115. package/libx/_runtime/common/composition/insert.js +2 -2
  116. package/libx/_runtime/common/composition/tree.js +0 -1
  117. package/libx/_runtime/common/composition/update.js +3 -3
  118. package/libx/_runtime/common/error/frontend.js +21 -12
  119. package/libx/_runtime/common/error/log.js +36 -0
  120. package/libx/_runtime/common/error/utils.js +2 -5
  121. package/libx/_runtime/common/generic/auth/autoexpose.js +18 -17
  122. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  123. package/libx/_runtime/common/generic/auth/readOnly.js +1 -2
  124. package/libx/_runtime/common/generic/auth/restrict.js +23 -42
  125. package/libx/_runtime/common/generic/auth/restrictions.js +2 -7
  126. package/libx/_runtime/common/generic/auth/utils.js +91 -88
  127. package/libx/_runtime/common/generic/crud.js +6 -5
  128. package/libx/_runtime/common/generic/etag.js +7 -12
  129. package/libx/_runtime/common/generic/input.js +70 -68
  130. package/libx/_runtime/common/generic/paging.js +1 -0
  131. package/libx/_runtime/common/generic/sorting.js +1 -0
  132. package/libx/_runtime/common/generic/temporal.js +8 -2
  133. package/libx/_runtime/common/i18n/index.js +1 -1
  134. package/libx/_runtime/common/i18n/messages.properties +3 -1
  135. package/libx/_runtime/common/utils/binary.js +8 -2
  136. package/libx/_runtime/common/utils/compareJson.js +5 -1
  137. package/libx/_runtime/common/utils/copy.js +6 -11
  138. package/libx/_runtime/common/utils/cqn2cqn4sql.js +16 -14
  139. package/libx/_runtime/common/utils/differ.js +3 -6
  140. package/libx/_runtime/common/utils/keys.js +77 -18
  141. package/libx/_runtime/common/utils/postProcess.js +12 -15
  142. package/libx/_runtime/common/utils/propagateForeignKeys.js +0 -1
  143. package/libx/_runtime/common/utils/resolveView.js +2 -3
  144. package/libx/_runtime/common/utils/restrictions.js +45 -17
  145. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -8
  146. package/libx/_runtime/common/utils/stream.js +3 -16
  147. package/libx/_runtime/common/utils/streamProp.js +8 -18
  148. package/libx/_runtime/common/utils/structured.js +1 -1
  149. package/libx/_runtime/common/utils/ucsn.js +0 -2
  150. package/libx/_runtime/db/Service.js +0 -72
  151. package/libx/_runtime/db/data-conversion/post-processing.js +0 -1
  152. package/libx/_runtime/db/expand/expandCQNToJoin.js +9 -9
  153. package/libx/_runtime/db/expand/rawToExpanded.js +0 -8
  154. package/libx/_runtime/db/generic/input.js +3 -8
  155. package/libx/_runtime/db/generic/rewrite.js +1 -0
  156. package/libx/_runtime/db/query/read.js +2 -2
  157. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +0 -1
  158. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
  159. package/libx/_runtime/db/utils/columns.js +2 -6
  160. package/libx/_runtime/fiori/lean-draft.js +138 -56
  161. package/libx/_runtime/hana/Service.js +0 -1
  162. package/libx/_runtime/hana/driver.js +1 -1
  163. package/libx/_runtime/hana/dynatrace.js +1 -2
  164. package/libx/_runtime/hana/pool.js +11 -21
  165. package/libx/_runtime/hana/streaming.js +0 -1
  166. package/libx/_runtime/messaging/common-utils/AMQPClient.js +0 -1
  167. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +1 -1
  168. package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +1 -1
  169. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -1
  170. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -33
  171. package/libx/_runtime/messaging/event-broker.js +0 -12
  172. package/libx/_runtime/messaging/file-based.js +3 -3
  173. package/libx/_runtime/messaging/http-utils/token.js +1 -1
  174. package/libx/_runtime/messaging/kafka.js +2 -2
  175. package/libx/_runtime/messaging/redis-messaging.js +0 -1
  176. package/libx/_runtime/remote/Service.js +25 -25
  177. package/libx/_runtime/remote/utils/client.js +4 -5
  178. package/libx/_runtime/remote/utils/cloudSdkProvider.js +0 -3
  179. package/libx/_runtime/remote/utils/data.js +0 -1
  180. package/libx/_runtime/sqlite/Service.js +1 -2
  181. package/libx/_runtime/ucl/Service.js +37 -78
  182. package/libx/common/assert/index.js +22 -21
  183. package/libx/common/assert/type-relaxed.js +39 -0
  184. package/libx/common/assert/utils.js +3 -2
  185. package/libx/common/assert/validation.js +3 -8
  186. package/libx/common/utils/index.js +5 -0
  187. package/libx/common/utils/path.js +51 -0
  188. package/libx/odata/ODataAdapter.js +126 -0
  189. package/libx/odata/index.js +15 -2
  190. package/libx/odata/middleware/batch.js +261 -72
  191. package/libx/odata/middleware/body-parser.js +33 -0
  192. package/libx/odata/middleware/create.js +44 -59
  193. package/libx/odata/middleware/delete.js +23 -12
  194. package/libx/odata/middleware/error.js +30 -6
  195. package/libx/odata/middleware/metadata.js +38 -26
  196. package/libx/odata/middleware/operation.js +93 -69
  197. package/libx/odata/middleware/parse.js +6 -8
  198. package/libx/odata/middleware/read.js +117 -93
  199. package/libx/odata/middleware/service-document.js +22 -19
  200. package/libx/odata/middleware/stream.js +54 -56
  201. package/libx/odata/middleware/update.js +79 -87
  202. package/libx/odata/parse/afterburner.js +191 -175
  203. package/libx/odata/parse/cqn2odata.js +8 -8
  204. package/libx/odata/parse/grammar.peggy +27 -20
  205. package/libx/odata/parse/multipartToJson.js +17 -9
  206. package/libx/odata/parse/parser.js +1 -1
  207. package/libx/odata/utils/etag.js +14 -6
  208. package/libx/odata/utils/index.js +84 -12
  209. package/libx/odata/utils/metadata.js +161 -0
  210. package/libx/odata/utils/postProcess.js +89 -0
  211. package/libx/odata/utils/readAfterWrite.js +134 -17
  212. package/libx/odata/utils/result.js +36 -142
  213. package/libx/outbox/index.js +4 -3
  214. package/libx/rest/RestAdapter.js +115 -182
  215. package/libx/rest/middleware/create.js +28 -24
  216. package/libx/rest/middleware/delete.js +7 -10
  217. package/libx/rest/middleware/error.js +19 -16
  218. package/libx/rest/middleware/operation.js +48 -41
  219. package/libx/rest/middleware/parse.js +128 -126
  220. package/libx/rest/middleware/read.js +20 -27
  221. package/libx/rest/middleware/update.js +26 -31
  222. package/package.json +17 -8
  223. package/server.js +4 -2
  224. package/tasks/enterprise-messaging-deploy.js +1 -1
  225. package/apis/cds.d.ts +0 -3
  226. package/apis/core.d.ts +0 -21
  227. package/apis/cqn.d.ts +0 -18
  228. package/apis/csn.d.ts +0 -21
  229. package/apis/events.d.ts +0 -18
  230. package/apis/internal/inference.d.ts +0 -18
  231. package/apis/linked.d.ts +0 -18
  232. package/apis/log.d.ts +0 -20
  233. package/apis/models.d.ts +0 -18
  234. package/apis/ql.d.ts +0 -18
  235. package/apis/reflect.d.ts +0 -32
  236. package/apis/server.d.ts +0 -18
  237. package/apis/services.d.ts +0 -22
  238. package/bin/cds-serve.js +0 -56
  239. package/lib/compile/to/gql.js +0 -15
  240. package/lib/srv/protocols/_legacy.js +0 -44
  241. package/lib/utils/jest.js +0 -43
  242. package/libx/_runtime/auth/index.js +0 -193
  243. package/libx/_runtime/auth/strategies/JWT.js +0 -37
  244. package/libx/_runtime/auth/strategies/basic.js +0 -20
  245. package/libx/_runtime/auth/strategies/dummy.js +0 -14
  246. package/libx/_runtime/auth/strategies/ias-auth.js +0 -1
  247. package/libx/_runtime/auth/strategies/mock.js +0 -77
  248. package/libx/_runtime/auth/strategies/xssecUtils.js +0 -93
  249. package/libx/_runtime/auth/strategies/xsuaa.js +0 -38
  250. package/libx/_runtime/common/perf/index.js +0 -19
  251. package/libx/_runtime/common/utils/ensureIEEE754.js +0 -29
  252. package/libx/_runtime/fiori/draft.js +0 -2
  253. package/libx/_runtime/fiori/generic/activate.js +0 -190
  254. package/libx/_runtime/fiori/generic/before.js +0 -201
  255. package/libx/_runtime/fiori/generic/cancel.js +0 -19
  256. package/libx/_runtime/fiori/generic/delete.js +0 -21
  257. package/libx/_runtime/fiori/generic/edit.js +0 -157
  258. package/libx/_runtime/fiori/generic/index.js +0 -25
  259. package/libx/_runtime/fiori/generic/new.js +0 -82
  260. package/libx/_runtime/fiori/generic/patch.js +0 -101
  261. package/libx/_runtime/fiori/generic/prepare.js +0 -57
  262. package/libx/_runtime/fiori/generic/read.js +0 -1340
  263. package/libx/_runtime/fiori/generic/readOverDraft.js +0 -146
  264. package/libx/_runtime/fiori/utils/csn.js +0 -13
  265. package/libx/_runtime/fiori/utils/delete.js +0 -114
  266. package/libx/_runtime/fiori/utils/handler.js +0 -264
  267. package/libx/_runtime/fiori/utils/lockInfo.js +0 -27
  268. package/libx/_runtime/fiori/utils/req.js +0 -23
  269. package/libx/_runtime/fiori/utils/stream.js +0 -36
  270. package/libx/_runtime/fiori/utils/where.js +0 -254
  271. package/libx/_runtime/index.js +0 -22
  272. package/libx/odata/utils/handler.js +0 -120
  273. package/libx/odata/utils/metaInfo.js +0 -410
  274. package/libx/odata/utils/path.js +0 -75
  275. package/libx/rest/RestRequest.js +0 -32
  276. package/libx/rest/index.js +0 -3
  277. package/libx/rest/readme.md +0 -1
  278. /package/libx/common/assert/{type.js → type-strict.js} +0 -0
@@ -15,7 +15,7 @@ module.exports = (csn,o={}) => {
15
15
  // Note: This has moved to cds.compile.for.java meanwhile, but is kept
16
16
  // here for compatibility, at least temporarily.
17
17
  return {...v, _where: JSON.stringify (cds.parse.xpr(v.where)) }
18
- } catch(e){/* ignored */}
18
+ } catch {/* ignored */}
19
19
 
20
20
  else if (v.kind === "service" && !v['@source'] && v.$location?.file) {
21
21
  // Preserve original sources for services so we can use them for finding
@@ -16,12 +16,15 @@ function cds_compile_to_sql (csn,_o) {
16
16
  return sql
17
17
  }
18
18
 
19
-
20
19
  function cds_compile_to_hdbtable (csn,o) {
21
20
  const all = cdsc.to.hdi (cds.minify(csn),o)
22
21
  return _2many(all)
23
22
  }
24
23
 
24
+ function cds_compile_to_hana(csn, o, beforeCsn) {
25
+ return require('./hana')(cds.minify(csn), o, beforeCsn)
26
+ }
27
+
25
28
  function cds_compile_to_deltaSql (csn, o, beforeCsn) {
26
29
  const options = cdsc._options.for.sql(o)
27
30
  if (typeof beforeCsn === 'string') beforeCsn = JSON.parse(beforeCsn)
@@ -53,6 +56,7 @@ function* _2many (all,_file=f=>f) {
53
56
  module.exports = Object.assign (cds_compile_to_sql, {
54
57
  hdbcds: cds_compile_to_hdbcds,
55
58
  hdbtable: cds_compile_to_hdbtable,
59
+ hana: cds_compile_to_hana,
56
60
  delta: cds_compile_to_deltaSql,
57
61
  sqlite: { keywords: sqliteKeywords },
58
62
  postgres: { keywords: postgresKeywords },
@@ -1,6 +1,6 @@
1
1
  // A simple YAML serializer
2
2
  module.exports = function _2yaml (object, {limit=111}={}) {
3
- return $(object,'',1).toString().replace(/^\n/,'')
3
+ return $(object,'',1)?.toString().replace(/^\n/,'')
4
4
  function $(o, indent, count, _visited) {
5
5
  if (o == null) return o
6
6
  if (o.toJSON) o = o.toJSON()
@@ -11,7 +11,7 @@ module.exports = function _2yaml (object, {limit=111}={}) {
11
11
  }
12
12
  if (typeof o === 'object') {
13
13
  const visited = new Set (_visited)
14
- if (visited.has(o)) return console.error('circular reference to',o)
14
+ if (visited.has(o)) return console.error('circular reference to',o) // eslint-disable-line no-console
15
15
  else visited.add(o)
16
16
  let s = ''
17
17
  for (let k in o) {
@@ -31,7 +31,7 @@ module.exports = function _2yaml (object, {limit=111}={}) {
31
31
  let s = o.trim()
32
32
  return !s || /^[\^@#:,=!<>*|]/.test(s) ? '"'+ o.replace(/\\/g,'\\\\') +'"' : s
33
33
  }
34
- if (typeof o === 'function') return ''
34
+ if (typeof o === 'function') return
35
35
  else return o
36
36
  }
37
37
  }
@@ -6,10 +6,12 @@ const TRACE = cds.debug('trace')
6
6
 
7
7
  /** Fluent API: cds.deploy(model).to(db) */
8
8
  const deploy = module.exports = function cds_deploy (model, options, csvs) {
9
+
9
10
  return { async to (/** @type {import('../../lib/srv/srv-api')} */ db, o = options||{}) {
11
+ /* eslint-disable no-console */
10
12
 
11
13
  // prepare logging
12
- const [ GREY, RESET ] = !!process.stdout.isTTY && !!process.stderr.isTTY && !process.env.NO_COLOR ? ['\x1b[2m', '\x1b[0m' ] : ['','']
14
+ const [ GREY, RESET ] = process.stdout.isTTY && !process.env.NO_COLOR || process.env.FORCE_COLOR ? ['\x1b[2m', '\x1b[0m' ] : ['','']
13
15
  const LOG = !o.silent && !o.dry && cds.log('deploy')._info ? console.log : undefined
14
16
 
15
17
  // prepare model
@@ -290,7 +292,7 @@ deploy.resources = async function (csn, opts) {
290
292
  }
291
293
  const e = _entity4(f,csn); if (!e || e['@cds.persistence.skip'] === true) continue
292
294
  if (cds.env.features.deploy_data_onconflict === 'replace' && !/[._]texts_/.test(f)) {
293
- const seenBefore = Object.entries(found).find(([_, entity]) => entity === e.name )
295
+ const seenBefore = Object.entries(found).find(([,entity]) => entity === e.name )
294
296
  if (seenBefore) {
295
297
  DEBUG?.(`Conflict for '${e.name}': replacing '${local(seenBefore[0])}' with '${local(path.join(subdir,fx))}'`)
296
298
  continue
@@ -91,13 +91,6 @@ class Config {
91
91
  if (this.features && this.features.emulate_vcap_services) {
92
92
  this._emulate_vcap_services()
93
93
  }
94
-
95
- // new odata adapter shall include new parser, cds.assert(), and decimals as strings
96
- if (this.features?.odata_new_adapter) {
97
- this.features.odata_new_parser = true
98
- this.features.cds_assert = true
99
- this.features.string_decimals = true
100
- }
101
94
  }
102
95
 
103
96
  /**
@@ -227,7 +220,7 @@ class Config {
227
220
  if (val) try {
228
221
  // CDS_CONFIG={ /* json */}
229
222
  config = JSON.parse (val)
230
- } catch (e) {
223
+ } catch {
231
224
  // CDS_CONFIG=/path/to/config.json *OR* CDS_CONFIG=/path/to/config/dir
232
225
  if (typeof val === "string") {
233
226
  // Load from JSON file or directory; No profile support!
@@ -391,13 +384,16 @@ class Config {
391
384
  _fetch ({ type: conf.dialect || conf.kind })
392
385
 
393
386
  function _fetch (predicate) {
387
+ const filters = []
394
388
  for (let k in predicate) {
395
389
  const v = predicate[k]; if (!v) continue
396
390
  const filter = k === 'tag' ? e => _array(e,'tags').includes(v) : e => e[k] === v
397
- for (let stype in vcaps) {
398
- const found = _array(vcaps,stype) .find (filter)
399
- if (found) return found
400
- }
391
+ filters.push(filter)
392
+ }
393
+ if (filters.length === 0) return false
394
+ for (let stype in vcaps) {
395
+ const found = _array(vcaps,stype).find(e => filters.every(f => f(e)))
396
+ if (found) return found
401
397
  }
402
398
  }
403
399
 
@@ -491,8 +487,8 @@ function _merge (dst, src, _profiles) {
491
487
  }
492
488
 
493
489
  function _value4 (val) {
494
- if (val && val[0] === '{') try { return JSON.parse(val) } catch(e) {/* ignored */}
495
- if (val && val[0] === '[') try { return JSON.parse(val) } catch(e) {/* ignored */}
490
+ if (val && val[0] === '{') try { return JSON.parse(val) } catch {/* ignored */}
491
+ if (val && val[0] === '[') try { return JSON.parse(val) } catch {/* ignored */}
496
492
  if (val === 'true') return true
497
493
  if (val === 'false') return false
498
494
  if (!isNaN(val)) return parseFloat(val)
@@ -2,7 +2,7 @@ const _runtime = '@sap/cds/libx/_runtime'
2
2
 
3
3
  exports = module.exports = {
4
4
 
5
- middlewares: true,
5
+ middlewares: true, // REVISIT: odata-v2-adapter uses this
6
6
  db: undefined, "[schevo]": { db: { schema_evolution: 'auto' }, },
7
7
  messaging: undefined,
8
8
  multitenancy: undefined,
@@ -23,8 +23,7 @@ exports = module.exports = {
23
23
  const dict = Object.create (this)
24
24
  for (let [name,e] of Object.entries (this)) if (e.service) {
25
25
  if (e.service in dict && !e.override && e.service !== name) {
26
- console.error (`Datasource name '${e.service}' conflicts with 'service' definition referred to in 'cds.requires.${name}':`, e) // eslint-disable-line no-console
27
- throw new Error (`Datasource name '${e.service}' conflicts with service definition`)
26
+ throw new Error (`Datasource name '${e.service}' conflicts with service definition, referred to in 'cds.requires.${name}'`)
28
27
  }
29
28
  else dict[e.service] = { ...e, name }
30
29
  }
@@ -33,8 +32,8 @@ exports = module.exports = {
33
32
  }
34
33
 
35
34
 
36
- const admin = [ 'cds.Subscriber', 'admin' ]
37
- const builder = [ 'cds.ExtensionDeveloper', 'cds.UIFlexDeveloper' ]
35
+ const admin = [ 'admin' ]
36
+ const builder = [ 'cds.ExtensionDeveloper' ]
38
37
  const _authentication_strategies = {
39
38
 
40
39
  "basic-auth": {
@@ -81,6 +80,7 @@ const _authentication_strategies = {
81
80
 
82
81
  for (let each of Object.values(_authentication_strategies)) {
83
82
  Object.defineProperty (each, 'strategy', {get() {
83
+ // eslint-disable-next-line no-console
84
84
  if (process.env.NODE_ENV !== 'production') console.trace('WARNING: auth.strategy is deprecated, use auth.kind instead')
85
85
  return { jwt: 'JWT', mocked: 'mock' }[this.kind] || this.kind
86
86
  }})
@@ -116,6 +116,17 @@ const _services = {
116
116
 
117
117
  }
118
118
 
119
+ const better_sqlite = '@cap-js/sqlite'
120
+ const better_hana = '@cap-js/hana'
121
+
122
+ const legacy_sqlite = `${_runtime}/sqlite/Service.js`
123
+ const legacy_hana = `${_runtime}/hana/Service.js`
124
+
125
+ const _resolve = (preferred, fallback) => {
126
+ try { return require.resolve(preferred) && preferred }
127
+ catch { return fallback }
128
+ }
129
+
119
130
 
120
131
  const _databases = {
121
132
 
@@ -125,9 +136,9 @@ const _databases = {
125
136
  },
126
137
 
127
138
  "sqlite": {
128
- '[legacy-sqlite]': { impl: `${_runtime}/sqlite/Service.js` },
129
- '[better-sqlite]': { impl: '@cap-js/sqlite' },
130
- impl: `${_runtime}/sqlite/Service.js`,
139
+ '[legacy-sqlite!]': { impl: legacy_sqlite },
140
+ '[better-sqlite!]': { impl: better_sqlite },
141
+ impl: _resolve (better_sqlite, legacy_sqlite),
131
142
  credentials: { url: 'db.sqlite' },
132
143
  },
133
144
  "better-sqlite": {
@@ -136,21 +147,21 @@ const _databases = {
136
147
  kind: 'sqlite'
137
148
  },
138
149
  "legacy-sqlite": {
139
- impl: `${_runtime}/sqlite/Service.js`,
150
+ impl: legacy_sqlite,
140
151
  credentials: { url: 'db.sqlite' },
141
152
  kind: 'sqlite'
142
153
  },
143
154
 
144
155
  "hana": {
145
- '[legacy-hana]': { impl: `${_runtime}/hana/Service.js` },
146
- '[better-hana]': { impl: '@cap-js/hana' },
147
- impl: `${_runtime}/hana/Service.js`,
156
+ '[legacy-hana]': { impl: legacy_hana },
157
+ '[better-hana]': { impl: better_hana },
158
+ impl: _resolve (better_hana, legacy_hana),
148
159
  },
149
160
  "hana-cloud": {
150
161
  kind: 'hana', "deploy-format": "hdbtable",
151
162
  },
152
163
  "legacy-hana": {
153
- impl: `${_runtime}/hana/Service.js`,
164
+ impl: legacy_hana,
154
165
  kind: 'hana'
155
166
  },
156
167
 
@@ -268,6 +279,11 @@ const _platform_services = {
268
279
  label: 'destination'
269
280
  }
270
281
  },
282
+ connectivity: {
283
+ vcap: {
284
+ label: 'connectivity'
285
+ }
286
+ },
271
287
 
272
288
  approuter: undefined,
273
289
 
@@ -2,12 +2,46 @@ const production = process.env.NODE_ENV === 'production'
2
2
 
3
3
  const defaults = module.exports = {
4
4
 
5
+ /**
6
+ * For our own tests to replace hard-coded checks for CDS_ENV === 'better-sqlite'
7
+ * which don't work anymore with cds8 where that is the default.
8
+ */
9
+ get _better_sqlite() {
10
+ if (process.env.CDS_ENV === 'better-sqlite') return true
11
+ let conf = this.requires.db || this.requires.kinds.sql
12
+ if (conf?.impl === '@cap-js/sqlite') return true
13
+ else return false
14
+ },
15
+
16
+ "[attic!]": {
17
+ features: {
18
+ pre_compile_edmxs: false,
19
+ odata_new_adapter: false,
20
+ odata_new_parser: false,
21
+ },
22
+ requires: {
23
+ kinds: {
24
+ sqlite: { impl: '@sap/cds/libx/_runtime/sqlite/Service.js' },
25
+ hana: { impl: '@sap/cds/libx/_runtime/hana/Service.js' },
26
+ },
27
+ },
28
+ },
29
+
30
+ "[noa]": {
31
+ features: {
32
+ odata_new_adapter: true,
33
+ odata_new_parser: true,
34
+ },
35
+ },
36
+
5
37
  production,
6
38
 
7
39
  requires: require('./cds-requires'),
8
40
 
9
41
  server: {
10
42
  force_exit_timeout: 1111,
43
+ cors: !production, // CORS middleware is off in production
44
+ index: !production, // index page is off in production
11
45
  port: 4004,
12
46
  },
13
47
 
@@ -20,8 +54,11 @@ const defaults = module.exports = {
20
54
 
21
55
  features: {
22
56
  folders: 'fts/*', // where to find feature toggles -> switch on by default when released
57
+ sql_simple_queries: 0,
23
58
  pre_compile_edmxs: false,
24
- odata_new_adapter: false, // switch default with cds^8
59
+ odata_new_adapter: true,
60
+ odata_new_parser: true,
61
+ get cds_validate() { return this.odata_new_adapter },
25
62
  live_reload: !production,
26
63
  in_memory_db: !production,
27
64
  test_data: !production,
@@ -31,31 +68,26 @@ const defaults = module.exports = {
31
68
  // skip_unused: 'all',
32
69
  skip_unused: true,
33
70
  deploy_data_onconflict: 'insert',
34
- one_model: true,
35
71
  localized: true,
36
72
  assert_integrity: false,
37
- cds_tx_inheritance: true,
38
- serve_on_root: false,
39
73
  precise_timestamps: false,
40
- string_decimals: false, // switch default with cds^8
74
+ ieee754compatible: undefined,
75
+ // compat for db
76
+ get string_decimals() { return this.ieee754compatible }
41
77
  },
42
78
 
43
79
  fiori: {
44
80
  preview: !production,
45
81
  routes: !production,
46
82
  lean_draft: true,
47
- wrap_multiple_errors: true, // switch default with cds^8
83
+ wrap_multiple_errors: true,
48
84
  draft_lock_timeout: true,
49
- draft_deletion_timeout: false, // switch default with cds^8
85
+ draft_deletion_timeout: true,
50
86
  draft_compat: undefined,
51
- '[better-sqlite]': { lean_draft: true },
52
- '[better-hana]': { lean_draft: true },
53
- '[lean-draft]': { lean_draft: true },
54
87
  '[draft-compat]': { draft_compat: true },
55
88
  },
56
89
 
57
90
  ql: {
58
- quirks_mode: true, // IMPORTANT: Remove that for cds^7 !!
59
91
  },
60
92
 
61
93
  log: {
@@ -152,13 +184,11 @@ const defaults = module.exports = {
152
184
  * - `false` → always skipped.
153
185
  * - `true` → never skipped.
154
186
  */
155
- transitive_localized_views: true,
156
- '[java]': {
157
- transitive_localized_views: false
158
- },
159
- native_hana_associations: true,
187
+ transitive_localized_views: undefined,
188
+ native_hana_associations: undefined,
160
189
  names: 'plain', // or 'quoted', or 'hdbcds'
161
190
  dialect: 'sqlite' // or 'plain' or 'hana'
191
+ // dialect: undefined, // or 'sqlite', 'hana', 'postgres', 'h2', ...
162
192
  },
163
193
 
164
194
  hana: {
@@ -1,7 +1,7 @@
1
1
  // REVISIT: we should have a real modular plugin technique for cds.env
2
2
  module.exports = function add_mtx_env (env) {
3
3
 
4
- const mtx_env = require('@sap/cds-mtxs/env') // eslint-disable-line cds/no-missing-dependencies
4
+ const mtx_env = require('@sap/cds-mtxs/env')
5
5
  if (mtx_env) {
6
6
  const {requires} = env, {kinds} = requires
7
7
  Object.assign (env, mtx_env, {requires})
@@ -261,10 +261,6 @@ module.exports = {
261
261
  }
262
262
  ]
263
263
  },
264
- middlewares: {
265
- type: 'boolean',
266
- description: 'Enables new middlewares support (experimental).'
267
- },
268
264
  multitenancy: {
269
265
  oneOf: [
270
266
  {
@@ -760,6 +756,14 @@ module.exports = {
760
756
  description: 'Number of fields to be added at most.',
761
757
  minimum: 1
762
758
  },
759
+ 'fields': {
760
+ type: 'array',
761
+ description: 'Fields that are allowed to be extended.',
762
+ uniqueItems: true,
763
+ items: {
764
+ type: 'string'
765
+ }
766
+ },
763
767
  'new-entities': {
764
768
  type: 'integer',
765
769
  description: 'Number of entities to be added at most',
@@ -1,12 +1,12 @@
1
1
  const { join } = require('path')
2
2
 
3
3
  module.exports = new class {
4
- async default4(name) {
5
- const file = join(__dirname, name.replace(/\.\w+$/, ''))
6
- try {
7
- return structuredClone(require(file))
8
- } catch (err) {
9
- throw new Error(`ENOENT: Could not load schema '${name}' from ${file}`)
10
- }
4
+ async default4(name) {
5
+ const file = join(__dirname, name.replace(/\.\w+$/, ''))
6
+ try {
7
+ return structuredClone(require(file))
8
+ } catch {
9
+ throw new Error(`ENOENT: Could not load schema '${name}' from ${file}`)
11
10
  }
11
+ }
12
12
  }
@@ -25,7 +25,7 @@ const DEFAULT_META_DATA_PROPERTIES = { type: true, provider: true }
25
25
  function parseJsonSafe(str) {
26
26
  try {
27
27
  return JSON.parse(str)
28
- } catch (error) {
28
+ } catch {
29
29
  return undefined
30
30
  }
31
31
  }
package/lib/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  if (process.env.CDS_STRICT_NODE_VERSION !== 'false') require ('./utils/check-version')
2
2
  !(global.__cds_loaded_from ??= new Set).add(__filename) // track from where we loaded cds
3
3
 
4
- /** @typedef { import('../apis/linked.js').LinkedCSN } Linked */
5
4
  /** @typedef { import('./srv/srv-api') } Service */
6
5
 
7
6
  const { EventEmitter } = require('node:events')
@@ -45,6 +44,7 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
45
44
  get linked() { return super.linked = require('./linked/models') }
46
45
  get infer() { return super.infer = require('./ql/infer') }
47
46
  get builtin() { return super.builtin = require('./linked/types') }
47
+ get validate() { return super.validate = require('./linked/validate') }
48
48
  get Association() { return super.Association = this.builtin.classes.Association }
49
49
  get Composition() { return super.Composition = this.builtin.classes.Composition }
50
50
  get entity() { return super.entity = this.builtin.classes.entity }
@@ -84,16 +84,16 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
84
84
  get DatabaseService() { return super.DatabaseService = require('../libx/_runtime/db/Service.js') }
85
85
  get RemoteService() { return super.RemoteService = require('../libx/_runtime/remote/Service.js') }
86
86
 
87
- // Contexts and Transactions
88
- get _context() { return super._context = require('./req/cds-context') }
89
- get context() { return this._context._for(this) }
90
- set context(_) { this._context._for(this,_) }
87
+ /** Contexts and Transactions @type {import('./req/context.js')} */
88
+ get context() { return this._context.getStore() }
89
+ set context(x) { this._context.enterWith(x) }
91
90
  get spawn() { return super.spawn = this._context.spawn }
91
+ get _context() { return super._context = require('./req/cds-context') }
92
92
 
93
93
  // Helpers
94
94
  get utils() { return super.utils = require('./utils/cds-utils') }
95
95
  get error() { return super.error = require('./log/cds-error') }
96
- get exec() { return super.exec = require('../bin/cds-serve') }
96
+ get exec() { return super.exec = require('../bin/serve').exec }
97
97
  get test() { return super.test = require('./utils/cds-test') }
98
98
  get log() { return super.log = require('./log/cds-log') }
99
99
  get debug() { return super.debug = this.log.debug }
@@ -108,7 +108,6 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
108
108
  tx (..._) { return (this.db || this.txs).tx(..._) }
109
109
  run (..._) { return (this.db || typeof _[0] === 'function' && this.txs || this.error._no_primary_db).run(..._) }
110
110
  foreach (..._) { return (this.db || this.error._no_primary_db).foreach(..._) }
111
- stream (..._) { return (this.db || this.error._no_primary_db).stream(..._) }
112
111
  read (..._) { return (this.db || this.error._no_primary_db).read(..._) }
113
112
  create (..._) { return (this.db || this.error._no_primary_db).create(..._) }
114
113
  insert (..._) { return (this.db || this.error._no_primary_db).insert(..._) }
@@ -119,7 +118,6 @@ const cds = module.exports = global.cds = new class cds extends EventEmitter {
119
118
 
120
119
  // legacy and to be moved stuff -> hidden for tools in cds.__proto__
121
120
  /** @deprecated */ transaction (..._) { return (this.db||this.error._no_primary_db).transaction(..._) }
122
- /** @deprecated */ get build() { return super.build = this.error._outdated_dk }
123
121
  /** @deprecated */ get in() { return super.in = cwd => !cwd ? this : {__proto__:this, cwd, env: this.env.for('cds',cwd) } }
124
122
  }
125
123
 
@@ -137,8 +135,12 @@ extend (global) .with (class {
137
135
  static get CXL() { return cds.parse.CXL }
138
136
  })
139
137
 
140
- // install jest util if jest is defined
141
- if (process.env.CDS_JEST_MEM_FIX && typeof jest !== 'undefined') require('./utils/jest.js')
138
+ // ensure cds.test is loaded for running tests w/ node --test
139
+ 'describe' in global || ['describe','before','beforeAll','afterAll'].forEach (p => {
140
+ Object.defineProperty (global,p, { configurable:1, set(v){Object.defineProperty(global,p,{value:v})},
141
+ get(){ return cds.test, global[p] }
142
+ })
143
+ })
142
144
 
143
145
  // Allow for import cds from '@sap/cds' without esModuleInterop
144
146
  // FIXME: remove this flag in the next release. Only serves as fallback switch if people report issues with value:cds
package/lib/lazy.js CHANGED
@@ -42,7 +42,7 @@ const lazify_module = (module) => {
42
42
  extend(module).with({ set exports(all) {
43
43
  extend(module).with({ exports: lazify(all) })
44
44
  }})
45
- return (id) => (lazy) => module.require(id)
45
+ return (id) => (lazy) => module.require(id) // eslint-disable-line no-unused-vars
46
46
  }
47
47
 
48
48
  const is_lazy = (x) => typeof x === 'function' && /^(function\s?)?\(?lazy[,)\t =]/.test(x)
@@ -7,7 +7,7 @@ class any { is (kind) { return this.kind === kind || kind === 'any' }
7
7
  set name(n) { this.set('name', n, false) }
8
8
  set kind(k) { this.set('kind', k, true) }
9
9
  get kind() { return this.set('kind', this.parent ? 'element' : 'type') }
10
- valueOf() { return this.name || this }
10
+ toString(){ return !this.type ? this : this.type.startsWith('cds.') ? this.type.slice(4) : this.type }
11
11
 
12
12
  own (property, ifAbsent) {
13
13
  const pd = Reflect.getOwnPropertyDescriptor (this, property)
@@ -40,8 +40,14 @@ class type extends any { is(kind) { return kind === 'type' || super.is(kind) }
40
40
  class boolean extends scalar {}
41
41
  class Boolean extends boolean {}
42
42
 
43
- class string extends scalar {}
44
- class UUID extends string {}
43
+ class string extends scalar {
44
+ toString(){
45
+ return this.length ? `${super.toString()}(${this.length})` : super.toString()
46
+ }
47
+ }
48
+ class UUID extends string {
49
+ toString(){ return 'UUID' }
50
+ }
45
51
  class String extends string {}
46
52
  class LargeString extends String {}
47
53
  class Binary extends string {}
@@ -56,7 +62,11 @@ class type extends any { is(kind) { return kind === 'type' || super.is(kind) }
56
62
  class Int64 extends Integer {}
57
63
  class Float extends number {}
58
64
  class Double extends Float {}
59
- class Decimal extends Float {}
65
+ class Decimal extends Float {
66
+ toString(){
67
+ return this.precision ? this.scale ? `Decimal(${this.precision},${this.scale})` : `Decimal(${this.precision})` : 'Decimal'
68
+ }
69
+ }
60
70
 
61
71
  class date extends scalar {}
62
72
  class Date extends date {}
@@ -64,8 +74,17 @@ class type extends any { is(kind) { return kind === 'type' || super.is(kind) }
64
74
  class DateTime extends date {}
65
75
  class Timestamp extends DateTime {}
66
76
 
67
- class array extends type { is(kind) { return kind === 'array' || super.is(kind) }}
68
- class struct extends type { is(kind) { return kind === 'struct' || super.is(kind) }
77
+ class array extends type {
78
+ toString(){ return 'array of ' + this.items.toString() }
79
+ is(kind) { return kind === 'array' || super.is(kind) }
80
+ }
81
+ class struct extends type {
82
+ toString(){
83
+ const elements = []
84
+ for (let each in this.elements) elements.push(each)
85
+ return `{ ${elements.join(', ')} }`
86
+ }
87
+ is(kind) { return kind === 'struct' || super.is(kind) }
69
88
 
70
89
  /**
71
90
  * Gets the foreign key data for a given managed association from inbound data
@@ -167,11 +186,20 @@ class LinkedDefinitions {
167
186
  *[Symbol.iterator](){ for (let e in this) yield this[e] }
168
187
  forEach(f){ let i=0; for (let k in this) f(this[k],i++,this) }
169
188
  filter(f){ let i=0, r=[]; for (let k in this) f(this[k],i++,this) && r.push(this[k]); return r }
189
+ find(f){ for (let k in this) if (f(this[k])) return this[k] }
170
190
  map(f){ let i=0, r=[]; for (let k in this) r.push(f(this[k],i++,this)); return r }
171
191
  some(f){ for (let k in this) if (f(this[k])) return true }
172
- find(f){ for (let k in this) if (f(this[k])) return this[k] }
192
+ every(f){ for (let k in this) if (!f(this[k])) return false }
173
193
  }
174
194
 
195
+ // Protect LinkedDefinitions methods from erroneously being used as linked definitions/elements
196
+ Object.entries(Object.getOwnPropertyDescriptors(LinkedDefinitions.prototype)).forEach(([p,pd]) => p === 'constructor' || Object.defineProperties(pd.value, {
197
+ own: {get(){ throw new Error(`'${p}' is not a linked definition but a method inherited from LinkedDefinitions`) }},
198
+ name: {get(){ throw new Error(`'${p}' is not a linked definition but a method inherited from LinkedDefinitions`) }},
199
+ kind: {get(){ throw new Error(`'${p}' is not a linked definition but a method inherited from LinkedDefinitions`) }},
200
+ type: {get(){ throw new Error(`'${p}' is not a linked definition but a method inherited from LinkedDefinitions`) }},
201
+ _type: {get(){ throw new Error(`'${p}' is not a linked definition but a method inherited from LinkedDefinitions`) }},
202
+ }))
175
203
 
176
204
  module.exports = {
177
205
 
@@ -179,7 +207,7 @@ module.exports = {
179
207
 
180
208
  any, type, aspect, struct, array,
181
209
  scalar, boolean, string, number, date,
182
- service, event, action,
210
+ service, event, action, function: action,
183
211
  context,
184
212
 
185
213
  UUID, Boolean, String,
@@ -32,15 +32,6 @@ class entity extends struct {
32
32
  return derived[kind] = any
33
33
  }
34
34
 
35
- get drafts() {
36
- if (cds.env.fiori.lean_draft) return null
37
- // Remove this getter when old draft is removed
38
- return this.own('_drafts') || this.set('_drafts', this.elements?.HasDraftEntity && {
39
- name: this.name + '_drafts', keys: this.keys,
40
- toString(){ return this.name.replace(/\./g,'_') }
41
- })
42
- }
43
-
44
35
  toJSON() {
45
36
  return this.own('query') ? {...this} : super.toJSON(this)
46
37
  }
@@ -67,7 +58,8 @@ class Association extends type {
67
58
  for (const k of keys) {
68
59
  const el = k.ref.reduce((target,n)=> target.elements[n], this._target)
69
60
  const as = k.as || k.ref.at(-1)
70
- foreignKeys[as] = Object.create (el, { name:{value:as} }) //, parent:{value:this} })
61
+ foreignKeys[as] = Object.create (el, { name:{value:as}, notNull: {value:true} }) //, parent:{value:this} })
62
+ // For structures, foreign keys must be provided, (autogenerated) UUIDs are skipped for validation
71
63
  // REVISIT: We should change the line above to set parent correctly, as in the commented tail part.
72
64
  // But that breaks code in _runtime which expects it to be the wrong parent.
73
65
  }
@@ -5,8 +5,9 @@ const _kinds = {
5
5
  context:1,
6
6
  service:1,
7
7
  entity:1,
8
+ event:1,
8
9
  action:1,
9
- event:1
10
+ function:1,
10
11
  }
11
12
 
12
13