@sap/cds 6.0.2 → 6.1.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 (134) hide show
  1. package/CHANGELOG.md +153 -19
  2. package/apis/cds.d.ts +11 -7
  3. package/apis/log.d.ts +48 -0
  4. package/apis/ql.d.ts +72 -15
  5. package/bin/build/buildTaskHandler.js +5 -2
  6. package/bin/build/constants.js +4 -1
  7. package/bin/build/provider/buildTaskHandlerEdmx.js +11 -39
  8. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +13 -32
  9. package/bin/build/provider/buildTaskHandlerInternal.js +56 -4
  10. package/bin/build/provider/buildTaskProviderInternal.js +22 -14
  11. package/bin/build/provider/hana/index.js +8 -7
  12. package/bin/build/provider/java/index.js +18 -8
  13. package/bin/build/provider/mtx/index.js +7 -4
  14. package/bin/build/provider/mtx/resourcesTarBuilder.js +64 -35
  15. package/bin/build/provider/mtx-extension/index.js +57 -0
  16. package/bin/build/provider/mtx-sidecar/index.js +46 -18
  17. package/bin/build/provider/nodejs/index.js +34 -13
  18. package/bin/build/util.js +6 -4
  19. package/bin/deploy/to-hana/cfUtil.js +7 -2
  20. package/bin/deploy/to-hana/hana.js +6 -3
  21. package/bin/serve.js +8 -13
  22. package/lib/compile/{index.js → cds-compile.js} +0 -0
  23. package/lib/compile/extend.js +15 -5
  24. package/lib/compile/minify.js +1 -15
  25. package/lib/compile/parse.js +1 -1
  26. package/lib/compile/resolve.js +2 -2
  27. package/lib/compile/to/srvinfo.js +6 -4
  28. package/lib/{deploy.js → dbs/cds-deploy.js} +8 -8
  29. package/lib/env/{index.js → cds-env.js} +1 -17
  30. package/lib/env/{requires.js → cds-requires.js} +24 -3
  31. package/lib/env/defaults.js +7 -1
  32. package/lib/env/schemas/cds-package.json +11 -0
  33. package/lib/env/schemas/cds-rc.json +605 -0
  34. package/lib/index.js +20 -17
  35. package/lib/log/{errors.js → cds-error.js} +1 -1
  36. package/lib/log/{index.js → cds-log.js} +0 -0
  37. package/lib/ql/SELECT.js +1 -1
  38. package/lib/ql/{index.js → cds-ql.js} +0 -0
  39. package/lib/req/cds-context.js +1 -1
  40. package/lib/req/context.js +35 -7
  41. package/lib/req/locale.js +5 -1
  42. package/lib/{serve → srv}/adapters.js +23 -19
  43. package/lib/{connect → srv}/bindings.js +0 -0
  44. package/lib/{connect/index.js → srv/cds-connect.js} +1 -1
  45. package/lib/{serve/index.js → srv/cds-serve.js} +1 -1
  46. package/lib/{serve → srv}/factory.js +2 -3
  47. package/lib/{serve/Service-api.js → srv/srv-api.js} +14 -6
  48. package/lib/{serve/Service-dispatch.js → srv/srv-dispatch.js} +3 -2
  49. package/lib/{serve/Service-handlers.js → srv/srv-handlers.js} +10 -0
  50. package/lib/{serve/Service-methods.js → srv/srv-methods.js} +10 -8
  51. package/lib/srv/srv-models.js +206 -0
  52. package/lib/{serve/Transaction.js → srv/srv-tx.js} +6 -1
  53. package/lib/utils/{tests.js → cds-test.js} +2 -2
  54. package/lib/utils/cds-utils.js +146 -0
  55. package/lib/utils/index.js +2 -136
  56. package/lib/utils/jest.js +43 -0
  57. package/lib/utils/resources/index.js +14 -24
  58. package/lib/utils/resources/tar.js +18 -41
  59. package/libx/_runtime/auth/index.js +13 -10
  60. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +9 -20
  61. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -4
  62. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +19 -7
  63. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +8 -11
  64. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -4
  65. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +2 -2
  66. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +6 -19
  67. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -4
  68. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +2 -2
  69. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +8 -10
  70. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +38 -4
  71. package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +2 -6
  72. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +8 -5
  73. package/libx/_runtime/cds-services/services/utils/differ.js +4 -0
  74. package/libx/_runtime/cds-services/util/errors.js +1 -29
  75. package/libx/_runtime/common/constants/events.js +1 -3
  76. package/libx/_runtime/common/i18n/messages.properties +2 -1
  77. package/libx/_runtime/common/perf/index.js +10 -15
  78. package/libx/_runtime/common/utils/cqn2cqn4sql.js +0 -1
  79. package/libx/_runtime/common/utils/entityFromCqn.js +8 -5
  80. package/libx/_runtime/common/utils/template.js +1 -1
  81. package/libx/_runtime/db/Service.js +2 -14
  82. package/libx/_runtime/db/expand/expandCQNToJoin.js +28 -25
  83. package/libx/_runtime/db/generic/input.js +4 -0
  84. package/libx/_runtime/db/sql-builder/SelectBuilder.js +37 -18
  85. package/libx/_runtime/extensibility/activate.js +47 -47
  86. package/libx/_runtime/extensibility/add.js +19 -13
  87. package/libx/_runtime/extensibility/addExtension.js +17 -13
  88. package/libx/_runtime/extensibility/defaults.js +25 -30
  89. package/libx/_runtime/extensibility/linter/allowlist_checker.js +373 -0
  90. package/libx/_runtime/extensibility/linter/annotations_checker.js +113 -0
  91. package/libx/_runtime/extensibility/linter/checker_base.js +20 -0
  92. package/libx/_runtime/extensibility/linter/namespace_checker.js +180 -0
  93. package/libx/_runtime/extensibility/linter.js +32 -0
  94. package/libx/_runtime/extensibility/push.js +78 -21
  95. package/libx/_runtime/extensibility/service.js +29 -12
  96. package/libx/_runtime/extensibility/token.js +56 -0
  97. package/libx/_runtime/extensibility/validation.js +6 -9
  98. package/libx/_runtime/fiori/generic/activate.js +0 -4
  99. package/libx/_runtime/fiori/generic/edit.js +1 -9
  100. package/libx/_runtime/fiori/generic/new.js +3 -28
  101. package/libx/_runtime/fiori/generic/patch.js +6 -7
  102. package/libx/_runtime/fiori/generic/prepare.js +11 -18
  103. package/libx/_runtime/fiori/generic/read.js +11 -1
  104. package/libx/_runtime/fiori/utils/handler.js +0 -17
  105. package/libx/_runtime/hana/Service.js +0 -1
  106. package/libx/_runtime/hana/conversion.js +12 -1
  107. package/libx/_runtime/hana/customBuilder/CustomFunctionBuilder.js +4 -3
  108. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +5 -0
  109. package/libx/_runtime/hana/pool.js +6 -10
  110. package/libx/_runtime/hana/search2Contains.js +0 -5
  111. package/libx/_runtime/hana/search2cqn4sql.js +1 -0
  112. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +18 -19
  113. package/libx/_runtime/messaging/file-based.js +1 -0
  114. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  115. package/libx/_runtime/messaging/service.js +11 -6
  116. package/libx/_runtime/remote/utils/client.js +6 -2
  117. package/libx/_runtime/remote/utils/data.js +5 -0
  118. package/libx/_runtime/sqlite/Service.js +0 -1
  119. package/libx/odata/afterburner.js +79 -2
  120. package/libx/odata/cqn2odata.js +9 -7
  121. package/libx/odata/grammar.pegjs +161 -77
  122. package/libx/odata/index.js +9 -3
  123. package/libx/odata/parser.js +1 -1
  124. package/libx/odata/utils.js +39 -5
  125. package/libx/rest/RestAdapter.js +1 -2
  126. package/libx/rest/middleware/delete.js +4 -5
  127. package/libx/rest/middleware/parse.js +3 -2
  128. package/package.json +3 -3
  129. package/server.js +1 -1
  130. package/srv/extensibility-service.cds +6 -3
  131. package/srv/model-provider.cds +3 -1
  132. package/srv/model-provider.js +84 -104
  133. package/srv/mtx.js +7 -1
  134. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +0 -240
@@ -178,6 +178,10 @@ const _pickDraft = element => {
178
178
 
179
179
  if (element.virtual) categories.push('virtual')
180
180
 
181
+ if (element.default && !DRAFT_COLUMNS_MAP[element.name]) {
182
+ categories.push({ category: 'default', args: element })
183
+ }
184
+
181
185
  // REVISIT: element._foreignKeys.length seems to be a very broad check
182
186
  if (element.isAssociation && element._foreignKeys.length) {
183
187
  categories.push({ category: 'propagateForeignKeys' })
@@ -98,9 +98,7 @@ class SelectBuilder extends BaseBuilder {
98
98
  this._orderBy(noQuoting)
99
99
  }
100
100
 
101
- if (this._obj.SELECT.limit || this._obj.SELECT.one) {
102
- this._limit()
103
- }
101
+ this._limit()
104
102
 
105
103
  if (this._obj.SELECT.forUpdate) {
106
104
  this._forUpdate()
@@ -322,11 +320,8 @@ class SelectBuilder extends BaseBuilder {
322
320
 
323
321
  _where() {
324
322
  const entityName = this._obj.SELECT.from.ref && this._obj.SELECT.from.ref[0]
325
- const where = new this.ExpressionBuilder(
326
- this._obj.SELECT.where,
327
- entityName ? { ...this._options, entityName } : this._options,
328
- this._csn
329
- ).build()
323
+ const options = entityName ? { ...this._options, entityName } : this._options
324
+ const where = new this.ExpressionBuilder(this._obj.SELECT.where, options, this._csn).build()
330
325
  this._outputObj.sql.push('WHERE', where.sql)
331
326
  this._outputObj.values.push(...where.values)
332
327
  }
@@ -415,6 +410,34 @@ class SelectBuilder extends BaseBuilder {
415
410
  this._outputObj.sql.push(sqls.join(', '))
416
411
  }
417
412
 
413
+ _addRows() {
414
+ if (this._obj.SELECT.limit) {
415
+ if (this._obj.SELECT.limit.rows !== undefined) {
416
+ // limit (no placeholder for statement caching)
417
+ this._outputObj.sql.push('LIMIT', this._obj.SELECT.limit.rows.val)
418
+ } else {
419
+ // rows parameter is mandatory for SQL
420
+ throw new Error('Rows parameter is missing in SELECT.limit(rows, offset)')
421
+ }
422
+ }
423
+ }
424
+
425
+ _addOne() {
426
+ this._outputObj.sql.push('LIMIT', 1)
427
+ }
428
+
429
+ _addOffset() {
430
+ // offset
431
+ if (this._obj.SELECT.limit && this._obj.SELECT.limit.offset !== undefined) {
432
+ if (typeof this._obj.SELECT.limit.offset.val === 'number' && !this._parameterizedNumbers) {
433
+ this._outputObj.sql.push('OFFSET', this._obj.SELECT.limit.offset.val)
434
+ } else {
435
+ this._outputObj.sql.push('OFFSET', '?')
436
+ this._outputObj.values.push(this._obj.SELECT.limit.offset.val)
437
+ }
438
+ }
439
+ }
440
+
418
441
  /**
419
442
  * sql limit clause will be generated without placeholders.
420
443
  * reason is optimizing paging queries. number of rows does not change.
@@ -423,17 +446,13 @@ class SelectBuilder extends BaseBuilder {
423
446
  * offset will still use placeholders, as it'll change during the paging queries.
424
447
  */
425
448
  _limit() {
426
- // limit (no placeholder for statement caching)
427
- this._outputObj.sql.push('LIMIT', this._obj.SELECT.one ? 1 : this._obj.SELECT.limit.rows.val)
428
- // offset
429
- if (this._obj.SELECT.limit && this._obj.SELECT.limit.offset) {
430
- if (typeof this._obj.SELECT.limit.offset.val === 'number' && !this._parameterizedNumbers) {
431
- this._outputObj.sql.push('OFFSET', this._obj.SELECT.limit.offset.val)
432
- } else {
433
- this._outputObj.sql.push('OFFSET', '?')
434
- this._outputObj.values.push(this._obj.SELECT.limit.offset.val)
435
- }
449
+ if (this._obj.SELECT.one) {
450
+ this._addOne()
451
+ } else {
452
+ this._addRows()
436
453
  }
454
+
455
+ this._addOffset()
437
456
  }
438
457
 
439
458
  _parameters() {
@@ -1,69 +1,69 @@
1
1
  const cds = require('../cds')
2
2
 
3
3
  const handleDefaults = require('./defaults')
4
+ const Extensions = 'cds.xt.Extensions'
4
5
 
5
- const _calculateExtensions = async function (ID, tag, tenant) {
6
+ // REVISIT: Reuse ratio = 0
7
+ const _calculateExtensions = async function (ID, tag) {
6
8
  let active, inactive
7
- await cds.tx({ tenant }, async tx => {
8
- if (tag || ID) {
9
- const inactiveCqn = SELECT.from('cds.xt.Extensions').where({ activated: 'propertyBag' })
10
- if (ID) {
11
- inactiveCqn.where('ID !=', ID)
12
- } else {
13
- inactiveCqn.where('tag !=', tag)
14
- }
15
- inactive = await tx.run(inactiveCqn)
16
- const activeCqn = SELECT.from('cds.xt.Extensions').where({ activated: 'database' })
17
- if (ID) {
18
- activeCqn.or({ ID })
19
- } else {
20
- if (tag) activeCqn.or({ tag })
21
- }
22
- active = await tx.run(activeCqn)
23
- if (inactive.length) {
24
- const deleteCqn = DELETE.from('cds.xt.Extensions').where(inactiveCqn.SELECT.where)
25
- await tx.run(deleteCqn)
26
- }
9
+ if (tag || ID) {
10
+ const inactiveCqn = SELECT.from(Extensions).where({ activated: 'propertyBag' })
11
+ if (ID) {
12
+ inactiveCqn.where('ID !=', ID)
27
13
  } else {
28
- // activate all
29
- inactive = []
30
- active = await tx.run(SELECT.from('cds.xt.Extensions'))
14
+ inactiveCqn.where('(tag !=', tag, 'or tag =', null, ')')
31
15
  }
32
- })
16
+ inactive = await cds.db.run(inactiveCqn)
17
+ const activeCqn = SELECT.from(Extensions).where({ activated: 'database' })
18
+ if (ID) {
19
+ activeCqn.or({ ID })
20
+ } else if (tag) {
21
+ activeCqn.or({ tag })
22
+ }
23
+ active = await cds.db.run(activeCqn)
24
+ if (inactive.length) {
25
+ const deleteCqn = DELETE.from(Extensions).where(inactiveCqn.SELECT.where)
26
+ await cds.db.run(deleteCqn)
27
+ }
28
+ } else {
29
+ // activate all
30
+ inactive = []
31
+ active = await cds.db.run(SELECT.from(Extensions))
32
+ }
33
33
 
34
34
  return { active, inactive }
35
35
  }
36
36
 
37
- const _restoreExtensions = async function (tenant, active, inactive) {
38
- await cds.tx({ tenant }, async tx => {
39
- // delete all extensions
40
- await tx.run(DELETE.from('cds.xt.Extensions'))
41
- // active
42
- active.forEach(row => {
43
- row.csn = row.csn.replace(/,"@cds.extension":true/g, '')
44
- row.activated = 'database'
45
- row.timestamp = '$now'
46
- })
47
- await tx.run(INSERT.into('cds.xt.Extensions').entries(active))
48
- // inactive
49
- if (inactive.length) {
50
- for (const na of inactive) {
51
- for (const extension of JSON.parse(na.csn).extensions) {
52
- await handleDefaults(extension, tx)
53
- }
37
+ // REVISIT: Reuse ratio = 0
38
+ const _restoreExtensions = async function (active, inactive, appCsn) {
39
+ // delete all extensions
40
+ await cds.db.run(DELETE.from(Extensions))
41
+ // active
42
+ active.forEach(row => {
43
+ row.csn = row.csn.replace(/,"@cds.extension":true/g, '')
44
+ row.activated = 'database'
45
+ row.timestamp = '$now'
46
+ })
47
+ await cds.db.run(INSERT.into(Extensions).entries(active))
48
+ // inactive
49
+ if (inactive.length) {
50
+ for (const na of inactive) {
51
+ for (const extension of JSON.parse(na.csn).extensions) {
52
+ await handleDefaults(extension, appCsn, cds.db)
54
53
  }
55
- await tx.run(INSERT.into('cds.xt.Extensions').entries(inactive))
56
54
  }
57
- })
55
+ await cds.db.run(INSERT.into(Extensions).entries(inactive))
56
+ }
58
57
  }
59
58
 
60
- const activate = async function (ID, tag, tenant) {
61
- const { active, inactive } = await _calculateExtensions(ID, tag, tenant)
59
+ // REVISIT: Review with Vitaly: (1) Delete Inactives > (2) DS.extend(t) > (3) Delete All > (4) Restore All ???
60
+ const activate = async function (ID, tag, tenant, appCsn) {
61
+ const { active, inactive } = await _calculateExtensions(ID, tag)
62
62
 
63
63
  const { 'cds.xt.DeploymentService': ds } = cds.services
64
64
  await ds.extend(tenant)
65
65
 
66
- await _restoreExtensions(tenant, active, inactive)
66
+ await _restoreExtensions(active, inactive, appCsn)
67
67
  }
68
68
 
69
69
  module.exports = activate
@@ -11,21 +11,24 @@ const add = async function (req) {
11
11
  if (!extension || !extension.length) req.reject(400, 'Missing extension')
12
12
  if (!activate) activate = 'database'
13
13
  if (!tag) tag = null
14
- const tenant = req.tenant || (req.user.is('internal-user') && req.data.tenant)
14
+ const tenant = (req.user.is('internal-user') && req.data.tenant) || req.tenant
15
15
 
16
- const csn = _isCSN(extension) ? JSON.parse(extension) : cds.parse.cdl(extension)
17
- if (csn.requires) delete csn.requires
18
- await validateExtension(csn, tenant, req)
16
+ const extCsn = _isCSN(extension) ? JSON.parse(extension) : cds.parse.cdl(extension)
17
+ if (extCsn.requires) delete extCsn.requires
19
18
 
19
+ const { 'cds.xt.ModelProviderService': mps } = cds.services
20
+ const csn = await mps.getCsn(tenant, ['*'])
21
+ validateExtension(extCsn, csn, req)
22
+
23
+ if (tenant) cds.context = { tenant }
20
24
  const ID = cds.utils.uuid()
21
- await cds.tx({ tenant }, async tx => {
22
- await tx.run(INSERT.into('cds.xt.Extensions').entries([{ ID, tag, csn: JSON.stringify(csn), activated: activate }]))
23
- if (activate === 'propertyBag' && csn.extensions) csn.extensions.forEach(async ext => await handleDefaults(ext, tx))
24
- })
25
-
26
- if (activate === 'database') {
27
- await activateExt(ID, tag, tenant)
28
- }
25
+ await cds.db.run(
26
+ INSERT.into('cds.xt.Extensions').entries([{ ID, tag, csn: JSON.stringify(extCsn), activated: activate }])
27
+ )
28
+ const njCsn = cds.compile.for.nodejs(csn)
29
+ if (activate === 'propertyBag' && extCsn.extensions)
30
+ extCsn.extensions.forEach(async ext => await handleDefaults(ext, njCsn))
31
+ if (activate === 'database') await activateExt(ID, tag, tenant, njCsn)
29
32
  }
30
33
 
31
34
  const promote = async function (req) {
@@ -35,7 +38,10 @@ const promote = async function (req) {
35
38
  const tenant = req.tenant || (req.user.is('internal-user') && req.data.tenant) || ''
36
39
  if (activate !== 'database') req.reject(400, 'Promote to propertyBag is not supported')
37
40
 
38
- await activateExt(null, tag, tenant)
41
+ const { 'cds.xt.ModelProviderService': mps } = cds.services
42
+ const njCsn = await mps.getCsn(tenant, ['*'], 'nodejs')
43
+ if (tenant) cds.context = { tenant }
44
+ await activateExt(null, tag, tenant, njCsn)
39
45
  }
40
46
 
41
47
  module.exports = { add, promote }
@@ -18,9 +18,9 @@ const _addAnnotation = extension => {
18
18
  })
19
19
  }
20
20
 
21
- const _addViews = csn => {
21
+ const _addViews = (csn, appCsn) => {
22
22
  csn.extensions.forEach(extension => {
23
- const target = cds.model.definitions[extension.extend]
23
+ const target = appCsn.definitions[extension.extend]
24
24
  const views_ = []
25
25
  const view = resolveViews(target, views_)
26
26
  extension.extend = view && view.name
@@ -41,28 +41,32 @@ const _addViews = csn => {
41
41
  })
42
42
  }
43
43
 
44
- const _addExtension = async function (csn, req) {
45
- const tx = cds.tx(req)
46
- await tx.run(
44
+ const _addExtension = async function (csn, appCsn, req) {
45
+ if (req.tenant) cds.context = { tenant: req.tenant }
46
+ await cds.db.run(
47
47
  INSERT.into('cds.xt.Extensions').entries([
48
48
  { ID: cds.utils.uuid(), tag: 'uiflex', csn: JSON.stringify(csn), activated: 'propertyBag' }
49
49
  ])
50
50
  )
51
51
 
52
- // defaults
53
52
  for (const ext of req.data.extensions) {
54
53
  const extension = JSON.parse(ext)
55
- await handleDefaults(extension, tx, false)
54
+ await handleDefaults(extension, appCsn, false)
56
55
  }
57
56
  }
58
57
 
59
58
  const addExtension = async function (req) {
60
- const csn = _getCsn(req)
61
- validateCsn(csn, req)
62
- validateExtensionFields(csn, req)
63
- _addViews(csn, cds)
64
- await validateExtension(csn, req.tenant, req)
65
- await _addExtension(csn, req)
59
+ const { 'cds.xt.ModelProviderService': mps } = cds.services
60
+ const csn = await mps.getCsn(req.tenant, ['*'])
61
+ const extCsn = _getCsn(req)
62
+ const njCsn = cds.compile.for['nodejs'](csn)
63
+ // REVISIT: Optimize the validations
64
+ // REVISIT: Why do we need njCsn?
65
+ validateCsn(extCsn, njCsn, req)
66
+ validateExtensionFields(extCsn, njCsn, req)
67
+ _addViews(extCsn, njCsn)
68
+ validateExtension(extCsn, csn, req)
69
+ await _addExtension(extCsn, njCsn, req)
66
70
  }
67
71
 
68
72
  module.exports = addExtension
@@ -1,38 +1,33 @@
1
1
  const cds = require('../cds')
2
-
3
- const { ensureDraftsSuffix } = require('../common/utils/draft')
4
2
  const resolveViews = require('./views')
5
- const { EXT_BACK_PACK } = require('./utils')
6
-
7
- const _needsQuotations = t => t instanceof cds.builtin.classes.string || t instanceof cds.builtin.classes.date
8
-
9
- const _getDraftTable = view => {
10
- return cds.model.definitions[view]._isDraftEnabled ? ensureDraftsSuffix(view) : undefined
11
- }
12
-
13
- const handleDefaults = async (extension, tx, checkDb = true) => {
14
- const target = cds.model.definitions[extension.extend]
15
- const dbEntity = resolveViews(target).name
16
-
17
- if (checkDb && target.name !== dbEntity) return // only db entities
18
-
19
- const draft = _getDraftTable(extension.extend)
20
- const ext = Object.keys(extension.elements)
21
- .filter(key => extension.elements[key].default)
3
+ const builtin = cds.builtin.types
4
+ const needsQuotes = Symbol()
5
+ builtin.string[needsQuotes] = true
6
+ builtin.date[needsQuotes] = true
7
+
8
+ const handleDefaults = async (extension, { definitions }, checkDb = true) => {
9
+ const target = definitions[extension.extend]
10
+ const entity = resolveViews(target)
11
+ if (checkDb && target !== entity) return // only db entities
12
+
13
+ const elements = extension.elements
14
+ const defaults = Object.keys(elements)
15
+ .filter(key => elements[key].default)
22
16
  .map(key => {
23
- const element = extension.elements[key]
24
- // .type as ui flex extensions are not linked
25
- const t = cds.model.definitions[element.type] || cds.builtin.types[element.type]
26
- const value = t && _needsQuotations(t) ? `"${element.default.val}"` : element.default.val
27
- return `"${key}":${value}`
17
+ const e = elements[key],
18
+ { val } = e.default
19
+ const t = definitions[e.type] || builtin[e.type]
20
+ return `"${key}":${t && t[needsQuotes] ? `"${val}"` : val}`
28
21
  })
29
22
 
30
- if (ext.length !== 0) {
31
- const extStr = ext.join(',')
32
- const changed = `'{${extStr},' || substr(${EXT_BACK_PACK}, 2, length(${EXT_BACK_PACK})-1)`
33
- const assign = `${EXT_BACK_PACK} = CASE WHEN ${EXT_BACK_PACK} IS NULL THEN '{${extStr}}' ELSE ${changed} END`
34
- await tx.run(UPDATE(dbEntity).with(assign))
35
- if (draft) await tx.run(UPDATE(draft).with(assign))
23
+ if (defaults.length) {
24
+ const newDefaults = defaults.join(',')
25
+ const newBagpack = `extensions__ = CASE
26
+ WHEN extensions__ is null THEN '{${newDefaults}}'
27
+ ELSE '{${newDefaults},' || substr(extensions__, 2, length(extensions__)-1)
28
+ END`
29
+ await Promise.all([UPDATE(entity).with(newBagpack), entity.drafts && UPDATE(entity.drafts).with(newBagpack)])
30
+ // NOTE: We don't need the model definitions for `entity` in cds.db.model to run these queries
36
31
  }
37
32
  }
38
33