@sap/cds 6.8.4 → 7.0.1

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 (217) hide show
  1. package/CHANGELOG.md +66 -4
  2. package/README.md +0 -1
  3. package/bin/cds-serve.js +50 -3
  4. package/bin/deploy/to-hana.js +1 -0
  5. package/bin/serve.js +16 -20
  6. package/lib/auth/basic-auth.js +6 -4
  7. package/lib/auth/index.js +4 -3
  8. package/lib/auth/jwt-auth.js +2 -5
  9. package/lib/compile/cds-compile.js +34 -89
  10. package/lib/compile/cdsc.js +11 -0
  11. package/lib/compile/etc/properties.js +2 -2
  12. package/lib/compile/for/lean_drafts.js +36 -69
  13. package/lib/compile/for/nodejs.js +2 -1
  14. package/lib/compile/load.js +3 -3
  15. package/lib/compile/minify.js +2 -0
  16. package/lib/compile/to/csn.js +74 -0
  17. package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
  18. package/lib/compile/to/json.js +1 -1
  19. package/lib/compile/to/sql.js +8 -6
  20. package/lib/dbs/cds-deploy.js +174 -114
  21. package/lib/env/cds-env.js +64 -79
  22. package/lib/env/cds-requires.js +11 -28
  23. package/lib/env/defaults.js +13 -3
  24. package/lib/env/plugins.js +1 -12
  25. package/lib/env/presets.js +25 -21
  26. package/lib/index.js +121 -147
  27. package/lib/{core/reflect.js → linked/models.js} +2 -2
  28. package/lib/{core/infer.js → linked/queries.js} +2 -0
  29. package/lib/{core/index.js → linked/types.js} +2 -1
  30. package/lib/log/cds-error.js +13 -7
  31. package/lib/log/format/cf.js +1 -1
  32. package/lib/plugins.js +49 -0
  33. package/lib/ql/Query.js +0 -9
  34. package/lib/ql/STREAM.js +0 -1
  35. package/lib/req/context.js +2 -7
  36. package/lib/req/request.js +6 -2
  37. package/lib/req/response.js +23 -10
  38. package/lib/srv/middlewares/ctx-model.js +2 -2
  39. package/lib/srv/middlewares/errors.js +1 -1
  40. package/lib/srv/protocols/_legacy.js +1 -0
  41. package/lib/srv/protocols/graphql.js +7 -16
  42. package/lib/srv/protocols/index.js +59 -45
  43. package/lib/srv/protocols/odata-v2-proxy.js +2 -70
  44. package/lib/srv/protocols/odata-v4.js +9 -4
  45. package/lib/srv/srv-api.js +9 -3
  46. package/lib/srv/srv-dispatch.js +12 -9
  47. package/lib/srv/srv-models.js +4 -21
  48. package/lib/srv/srv-tx.js +15 -12
  49. package/lib/utils/cds-test.js +14 -9
  50. package/lib/utils/cds-utils.js +2 -12
  51. package/lib/utils/check-version.js +17 -0
  52. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  53. package/libx/_runtime/auth/index.js +27 -23
  54. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  59. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  63. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriTokenizer.js +5 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  68. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  71. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  72. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  73. package/libx/_runtime/cds-services/services/Service.js +79 -107
  74. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  75. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  76. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  77. package/libx/_runtime/cds-services/util/assert.js +65 -2
  78. package/libx/_runtime/common/composition/data.js +1 -0
  79. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  80. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  81. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  82. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  83. package/libx/_runtime/common/generic/crud.js +32 -16
  84. package/libx/_runtime/common/generic/etag.js +133 -104
  85. package/libx/_runtime/common/generic/input.js +6 -21
  86. package/libx/_runtime/common/generic/put.js +1 -1
  87. package/libx/_runtime/common/generic/stream.js +52 -0
  88. package/libx/_runtime/common/generic/temporal.js +25 -8
  89. package/libx/_runtime/common/i18n/messages.properties +0 -2
  90. package/libx/_runtime/common/utils/cqn.js +1 -1
  91. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  92. package/libx/_runtime/common/utils/csn.js +0 -51
  93. package/libx/_runtime/common/utils/etag.js +30 -0
  94. package/libx/_runtime/common/utils/keys.js +1 -1
  95. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  96. package/libx/_runtime/common/utils/path.js +1 -1
  97. package/libx/_runtime/common/utils/resolveView.js +2 -1
  98. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  99. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  100. package/libx/_runtime/common/utils/stream.js +140 -0
  101. package/libx/_runtime/common/utils/streamProp.js +29 -12
  102. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  103. package/libx/_runtime/db/generic/index.js +0 -2
  104. package/libx/_runtime/db/query/delete.js +2 -2
  105. package/libx/_runtime/db/query/insert.js +2 -2
  106. package/libx/_runtime/db/query/read.js +2 -2
  107. package/libx/_runtime/db/query/run.js +2 -2
  108. package/libx/_runtime/db/query/update.js +2 -2
  109. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  110. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  111. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  112. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  113. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  114. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  115. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  116. package/libx/_runtime/fiori/draft.js +2 -0
  117. package/libx/_runtime/fiori/generic/activate.js +8 -9
  118. package/libx/_runtime/fiori/generic/before.js +30 -20
  119. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  120. package/libx/_runtime/fiori/generic/delete.js +5 -3
  121. package/libx/_runtime/fiori/generic/edit.js +7 -7
  122. package/libx/_runtime/fiori/generic/index.js +10 -16
  123. package/libx/_runtime/fiori/generic/new.js +5 -3
  124. package/libx/_runtime/fiori/generic/patch.js +11 -8
  125. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  126. package/libx/_runtime/fiori/generic/read.js +12 -6
  127. package/libx/_runtime/fiori/lean-draft.js +207 -152
  128. package/libx/_runtime/fiori/utils/delete.js +10 -5
  129. package/libx/_runtime/fiori/utils/req.js +17 -5
  130. package/libx/_runtime/fiori/utils/stream.js +36 -0
  131. package/libx/_runtime/hana/Service.js +12 -9
  132. package/libx/_runtime/hana/conversion.js +10 -15
  133. package/libx/_runtime/hana/driver.js +2 -0
  134. package/libx/_runtime/hana/execute.js +28 -6
  135. package/libx/_runtime/hana/pool.js +36 -122
  136. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  137. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  138. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  139. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  140. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  141. package/libx/_runtime/remote/Service.js +20 -1
  142. package/libx/_runtime/remote/utils/client.js +3 -5
  143. package/libx/_runtime/sqlite/Service.js +4 -6
  144. package/libx/_runtime/sqlite/conversion.js +3 -13
  145. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  146. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  147. package/libx/_runtime/sqlite/execute.js +5 -16
  148. package/libx/odata/afterburner.js +22 -6
  149. package/libx/odata/grammar.pegjs +6 -1
  150. package/libx/odata/parser.js +1 -1
  151. package/libx/rest/RestAdapter.js +16 -9
  152. package/libx/rest/RestRequest.js +1 -1
  153. package/libx/rest/middleware/input.js +2 -1
  154. package/libx/rest/middleware/operation.js +1 -0
  155. package/libx/rest/middleware/parse.js +3 -2
  156. package/libx/rest/middleware/payload.js +9 -8
  157. package/libx/rest/middleware/read.js +1 -0
  158. package/package.json +9 -16
  159. package/server.js +1 -1
  160. package/app/fiori/preview.js +0 -270
  161. package/app/fiori/routes.js +0 -59
  162. package/bin/build/buildTaskEngine.js +0 -360
  163. package/bin/build/buildTaskFactory.js +0 -283
  164. package/bin/build/buildTaskHandler.js +0 -241
  165. package/bin/build/buildTaskProvider.js +0 -22
  166. package/bin/build/buildTaskProviderFactory.js +0 -175
  167. package/bin/build/cds.js +0 -5
  168. package/bin/build/constants.js +0 -66
  169. package/bin/build/index.js +0 -58
  170. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  171. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  172. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  173. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  174. package/bin/build/provider/fiori/index.js +0 -171
  175. package/bin/build/provider/hana/2migration.js +0 -179
  176. package/bin/build/provider/hana/index.js +0 -505
  177. package/bin/build/provider/hana/migrationtable.js +0 -472
  178. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  179. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  180. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  181. package/bin/build/provider/hana/template/package.json +0 -12
  182. package/bin/build/provider/hana/template/undeploy.json +0 -5
  183. package/bin/build/provider/java/index.js +0 -111
  184. package/bin/build/provider/java-cf/index.js +0 -1
  185. package/bin/build/provider/mtx/index.js +0 -268
  186. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  187. package/bin/build/provider/mtx-extension/index.js +0 -131
  188. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  189. package/bin/build/provider/node-cf/index.js +0 -1
  190. package/bin/build/provider/nodejs/index.js +0 -192
  191. package/bin/build/util.js +0 -299
  192. package/bin/cds.js +0 -125
  193. package/bin/deploy/to-hana/cfUtil.js +0 -355
  194. package/bin/deploy/to-hana/gitUtil.js +0 -57
  195. package/bin/deploy/to-hana/hana.js +0 -306
  196. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  197. package/bin/deploy/to-hana/index.js +0 -16
  198. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  199. package/bin/mtx/in-cds.js +0 -17
  200. package/bin/plugins.js +0 -32
  201. package/bin/run.js +0 -24
  202. package/bin/utils/log.js +0 -24
  203. package/bin/version.js +0 -178
  204. package/libx/_runtime/audit/Service.js +0 -222
  205. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  206. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  207. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  208. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  209. package/libx/_runtime/audit/utils/log.js +0 -23
  210. package/libx/_runtime/audit/utils/v2.js +0 -176
  211. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  212. package/libx/_runtime/db/generic/integrity.js +0 -455
  213. package/srv/audit-log.cds +0 -87
  214. package/srv/mtx.cds +0 -2
  215. package/srv/mtx.js +0 -8
  216. /package/lib/{core → linked}/classes.js +0 -0
  217. /package/lib/{core → linked}/entities.js +0 -0
@@ -1,455 +0,0 @@
1
- const cds = require('../../cds')
2
- const { SELECT } = cds.ql
3
-
4
- const crypto = require('crypto')
5
-
6
- const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
7
- const { all, resolve } = require('../../common/utils/thenable')
8
- const { assertError } = require('../../cds-services/util/assert')
9
- const { processDeepAsync } = require('../../cds-services/util/dataProcessUtils')
10
-
11
- const ASSERT_REFERENCE_INTEGRITY = 'ASSERT_REFERENCE_INTEGRITY'
12
- const ASSERT_INTEGRITY_ANNOTATION = '@assert.integrity'
13
-
14
- const CRUD = { CREATE: 1, READ: 1, UPDATE: 1, DELETE: 1 }
15
- const C_UD = { CREATE: 1, INSERT: 1, UPDATE: 1, DELETE: 1 }
16
-
17
- /*
18
- * UTILS
19
- */
20
-
21
- const _requiresRuntimeCheck = def => {
22
- const val = String(def['@assert.integrity']).toLowerCase()
23
- if (val === 'rt') return true
24
- if (val === 'db' || val === 'false') return false
25
- if (val === 'true') {
26
- const { assert_integrity_type: ait } = cds.env.features
27
- if (ait && ait.match(/rt/i)) return true
28
- }
29
- }
30
-
31
- const _runtimeShallCheckIntegrityFor = (assoc, inclComps) => {
32
- const { parent } = assoc
33
-
34
- // disqualifications
35
- if (!assoc._isAssociationStrict && !inclComps) return
36
- if (!assoc.is2one) return
37
- if (assoc.on) return
38
- if (assoc._isCompositionBacklink) return
39
- if (parent['@cds.persistence.skip']) return
40
-
41
- // check @assert.integrity bottom-up and break on value (i.e., lowest spec wins)
42
- if ('@assert.integrity' in assoc) {
43
- const val = _requiresRuntimeCheck(assoc)
44
- if (val !== undefined) return val
45
- }
46
- if ('@assert.integrity' in parent) {
47
- const val = _requiresRuntimeCheck(parent)
48
- if (val !== undefined) return val
49
- }
50
- if (parent._service && '@assert.integrity' in parent._service) {
51
- const val = _requiresRuntimeCheck(parent._service)
52
- if (val !== undefined) return val
53
- }
54
-
55
- // here, no disqualification and no @assert.integrity specified -> global setting
56
- const { assert_integrity: ai, assert_integrity_type: ait } = cds.env.features
57
- if (ai && ait && ait.match(/db/i)) return false
58
- return true
59
- }
60
-
61
- /*
62
- * this modifies the csn on purpose for caching effect!
63
- * doing as aspect is difficult due to no global definitons per tenant
64
- */
65
- const _getDependents = (entity, model) => {
66
- if (entity.own('__dependents')) return entity.__dependents
67
-
68
- /** @type {Array|boolean} */
69
- let dependents = []
70
- for (const def of Object.values(model.definitions)) {
71
- if (def.kind !== 'entity') continue
72
- if (!def.associations) continue
73
-
74
- for (const assoc of Object.values(def.associations)) {
75
- if (assoc.target !== entity.name) continue
76
-
77
- if (_runtimeShallCheckIntegrityFor(assoc)) {
78
- dependents.push({ /* element: assoc, */ parent: assoc.parent, target: model.definitions[assoc.target] })
79
- }
80
- }
81
- }
82
-
83
- if (dependents.length === 0) dependents = false
84
- return entity.set('__dependents', dependents)
85
- }
86
-
87
- const _getElement = (entity, ref) => {
88
- if (ref.length > 1) return _getElement(entity.elements[ref[0]], ref.slice(1))
89
- return entity.elements[ref[0]]
90
- }
91
-
92
- const _getFullForeignKeyName = (elementName, foreignKeyName) => `${elementName}_${foreignKeyName}`
93
-
94
- const _getDataFromRef = (row, ref) => {
95
- if (row === undefined) return
96
- if (ref.length > 1) return _getDataFromRef(row[ref[0]], ref.slice(1))
97
- return row[ref[0]]
98
- }
99
-
100
- const _foreignKeyReducer = (key, foreignKeyName, row, element, ref) => {
101
- const fullForeignKeyName = _getFullForeignKeyName(element.name, foreignKeyName)
102
-
103
- if (ref.length > 1) {
104
- // ref includes assoc name, so we need to replace it by foreign key name
105
- const refWithFlatForeignKey = [...ref.slice(0, ref.length - 1), fullForeignKeyName]
106
- key[foreignKeyName] = _getDataFromRef(row, refWithFlatForeignKey)
107
- } else {
108
- key[foreignKeyName] = Object.prototype.hasOwnProperty.call(row, fullForeignKeyName) ? row[fullForeignKeyName] : null
109
- }
110
-
111
- return key
112
- }
113
-
114
- const _buildForeignKey = (element, row, ref) => {
115
- let foreignKey
116
-
117
- if (element.keys) {
118
- foreignKey = element.keys
119
- .map(obj => obj.ref[obj.ref.length - 1])
120
- .reduce((key, foreignKeyName) => {
121
- return _foreignKeyReducer(key, foreignKeyName, row, element, ref)
122
- }, {})
123
- }
124
-
125
- return foreignKey
126
- }
127
-
128
- const _checkExists = (entity, data, req, run) => {
129
- if (!Array.isArray(data)) {
130
- return _checkExists(entity, [data], req, run).then(result => {
131
- return result[0]
132
- })
133
- }
134
-
135
- const where = data.map(row => {
136
- return Object.keys(entity.keys).reduce((where, name) => {
137
- if (row[name] !== undefined && row[name] !== null) {
138
- if (where.length > 0) {
139
- where.push('and')
140
- }
141
- where.push({ ref: [name] }, '=', { val: row[name] })
142
- }
143
-
144
- return where
145
- }, [])
146
- })
147
- return _checkExistsWhere(entity, where, run)
148
- }
149
-
150
- const _checkCreateUpdate = (result, ref, rootEntity, checks, data, req, run) => {
151
- const resolvedElement = _getElement(rootEntity, ref)
152
-
153
- // REVISIT: incl comps?!
154
- if (!_runtimeShallCheckIntegrityFor(resolvedElement /* true */)) return result
155
-
156
- // REVISIT: reduce should only be used to build object from array, not for loops!
157
- return data.reduce((result, row) => {
158
- const foreignKey = _buildForeignKey(resolvedElement, row, ref)
159
- if (foreignKey === undefined || Object.values(foreignKey).every(v => v === null)) return result
160
-
161
- // REVISIT: if incl comps, skip check if target is in payload
162
- // if (resolvedElement.isComposition && resolvedElement.is2one && row[resolvedElement.name]) return result
163
-
164
- checks.push(
165
- _checkExists(resolvedElement._target, foreignKey, req, run).then(exists => {
166
- if (!exists) {
167
- result.push(assertError(ASSERT_REFERENCE_INTEGRITY, resolvedElement, foreignKey))
168
- }
169
- })
170
- )
171
-
172
- return result
173
- }, result)
174
- }
175
-
176
- const _buildWhereDelete = (result, key, element, data) => {
177
- return data
178
- .map(d => {
179
- return Object.keys(d).reduce((result, name) => {
180
- if (key.ref[0] === name) {
181
- if (result.length > 0) {
182
- result.push('and')
183
- }
184
- result.push({ ref: [_getFullForeignKeyName(element.name, key.ref[0])] }, '=', { val: d[name] })
185
- }
186
-
187
- return result
188
- }, result)
189
- })
190
- .reduce((accumulatedWhere, currentWhere, i) => {
191
- if (i > 0) accumulatedWhere.push('or')
192
- accumulatedWhere.push(...currentWhere)
193
- return accumulatedWhere
194
- }, [])
195
- }
196
-
197
- const _checkExistsWhere = (entity, whereList, run) => {
198
- const checks = whereList.map(where => {
199
- if (where.length === 0) return true
200
-
201
- const query = {
202
- SELECT: {
203
- columns: [{ val: 1, as: '_exists' }],
204
- from: { ref: [entity.name || entity] },
205
- where: where,
206
- limit: { rows: { val: 1 } }
207
- }
208
- }
209
-
210
- if (cds.context) {
211
- const hash = crypto.createHash('sha1').update(JSON.stringify(query)).digest('base64') // fastest hash
212
- if (!cds.context.__alreadyExecutedIntegrityChecks) cds.context.__alreadyExecutedIntegrityChecks = new Map()
213
-
214
- if (cds.context.__alreadyExecutedIntegrityChecks.has(hash)) {
215
- return cds.context.__alreadyExecutedIntegrityChecks.get(hash)
216
- }
217
-
218
- const promise = run(query).then(exists => exists.length !== 0)
219
-
220
- // we store the promise object in the map, it won't get executed twice when calling await Promise.all([promise, promise])
221
- cds.context.__alreadyExecutedIntegrityChecks.set(hash, promise)
222
- return promise
223
- }
224
-
225
- return run(query).then(exists => exists.length !== 0)
226
- })
227
-
228
- return all(checks)
229
- }
230
-
231
- const _checkDelete = (result, key, entity, checks, req, csn, run, data) => {
232
- const elements = csn.definitions[key].elements
233
- const source = csn.definitions[key].name
234
-
235
- const dependents = _getDependents(req.target, csn) || []
236
-
237
- const sourceDependent = dependents.find(dep => dep.parent.name === source)
238
- if (!sourceDependent) return result
239
-
240
- return Object.keys(elements).reduce((result, assoc) => {
241
- if (!elements[assoc].target || !elements[assoc].keys) return result
242
-
243
- const targetDependent = dependents.find(dep => dep.target.name === elements[assoc].target)
244
- if (!targetDependent) return result
245
-
246
- const where = elements[assoc].keys.reduce((buildWhere, key) => {
247
- return _buildWhereDelete(buildWhere, key, elements[assoc], data)
248
- }, [])
249
- checks.push(
250
- _checkExistsWhere(source, [where], run).then(exists => {
251
- if (exists.includes(true)) {
252
- result.push(assertError(ASSERT_REFERENCE_INTEGRITY, elements[assoc], req.data))
253
- }
254
- })
255
- )
256
- return result
257
- }, result)
258
- }
259
-
260
- function _filterStructured(element, structuredAssocs, prefix) {
261
- const elements = element.elements
262
- for (const subElement in elements) {
263
- if (_filterAssocs(elements[subElement], structuredAssocs, prefix)) {
264
- structuredAssocs.push([...prefix, elements[subElement].name])
265
- }
266
- }
267
- }
268
-
269
- const _filterAssocs = (element, structuredAssocs, prefix = []) => {
270
- if (element.elements) {
271
- _filterStructured(element, structuredAssocs, [...prefix, element.name])
272
- }
273
-
274
- return (
275
- // element._isAssociationStrict && // > comps handled by deep crud logic
276
- element.isAssociation &&
277
- !element.virtual &&
278
- !element.abstract &&
279
- element[ASSERT_INTEGRITY_ANNOTATION] !== false &&
280
- !element._target._hasPersistenceSkip
281
- )
282
- }
283
-
284
- const _checkReferenceIntegrity = (entity, data, req, csn, run) => {
285
- const service = entity._service
286
- if (entity[ASSERT_INTEGRITY_ANNOTATION] === false || (service && service[ASSERT_INTEGRITY_ANNOTATION] === false)) {
287
- return
288
- }
289
-
290
- if (!Array.isArray(data)) data = [data]
291
-
292
- const checks = []
293
- let result
294
- if (req.event === 'CREATE' || req.event === 'UPDATE') {
295
- const structuredAssocRefs = []
296
- const associationRefs = Object.keys(entity.elements)
297
- .filter(elementName => _filterAssocs(entity.elements[elementName], structuredAssocRefs))
298
- .map(name => [name])
299
- result = [...associationRefs, ...structuredAssocRefs].reduce((createUpdateResult, ref) => {
300
- return _checkCreateUpdate(createUpdateResult, ref, entity, checks, data, req, run)
301
- }, [])
302
- }
303
- if (req.event === 'DELETE') {
304
- // we are only interested in table-level references not all derived ones on view levels
305
- // TODO: why?
306
- while (entity.query && entity.query._target) {
307
- entity = csn.definitions[entity.query._target.name]
308
- }
309
-
310
- result = Object.keys(csn.definitions)
311
- .filter(
312
- key =>
313
- !csn.definitions[key]['@cds.persistence.skip'] &&
314
- csn.definitions[key].elements !== undefined &&
315
- // skip check for events, aspects and localized tables
316
- csn.definitions[key].kind !== 'event' &&
317
- csn.definitions[key].kind !== 'aspect' &&
318
- csn.definitions[key].kind !== 'type' &&
319
- !csn.definitions[key].name.startsWith('localized.')
320
- )
321
- .reduce((deleteResult, key) => {
322
- return _checkDelete(deleteResult, key, entity, checks, req, csn, run, data)
323
- }, [])
324
- }
325
-
326
- if (checks.length) {
327
- return Promise.all(checks).then(() => {
328
- return result
329
- })
330
- }
331
-
332
- return resolve(result || [])
333
- }
334
-
335
- const _checkIntegrityWrapper = (req, csn, run) => async (data, entity) => {
336
- if (cds.env.fiori.lean_draft && entity.name?.endsWith('.drafts')) return
337
- const errors = await _checkReferenceIntegrity(entity, data, req, csn, run)
338
- if (errors && errors.length !== 0) for (const err of errors) req.error(err)
339
- }
340
-
341
- const _isUncheckableInsert = query => query.INSERT && (query.INSERT.rows || query.INSERT.values || query.INSERT.as)
342
-
343
- const _checkIntegrityUtil = async (req, csn, run) => {
344
- if (!run) return
345
- if (typeof req.query === 'string' || req.target._unresolved) return
346
- if (_isUncheckableInsert(req.query)) return
347
-
348
- // REVISIT: integrity check needs context.data
349
- if (Object.keys(req.data).length === 0) {
350
- // REVISIT: We may need to double-check re req.data being undefined or empty
351
- if (req.query.DELETE) {
352
- req.data = req._beforeDeleteData || {}
353
- } else if (req.context && req.context.data && Object.keys(req.context.data).length > 0) {
354
- req.data = req.context.data
355
- }
356
- }
357
- if (Object.keys(req.data).length === 0) return
358
-
359
- await processDeepAsync(_checkIntegrityWrapper(req, csn, run), req.data, req.target, false, true)
360
- }
361
-
362
- /*
363
- * HANDLERS
364
- */
365
-
366
- const _skipIntegrityCheck = (req, tx) => {
367
- if (cds.env.features.assert_integrity === false) return true
368
- if (!tx.model) return true
369
- if (req.event in CRUD) {
370
- if (typeof req.query === 'string') return true
371
- if (!req.target || req.target._unresolved) return true
372
- }
373
- return false
374
- }
375
-
376
- /*
377
- * before delete
378
- */
379
- const _isPrimitiveKey = e => !e.is2one && !e.is2many
380
-
381
- async function beforeDelete(req) {
382
- if (_skipIntegrityCheck(req, this)) return
383
-
384
- // via protocol adapter with key predicates?
385
- if (Object.keys(req.data).length > 0) return
386
-
387
- const target = this.model.definitions[req.target.name]
388
- if (!target) return
389
-
390
- // only if target has dependents (i.e., is the target of a managed to one association)
391
- const dependents = _getDependents(target, this.model)
392
- if (!dependents) return
393
-
394
- const keys = Object.keys(target.keys).filter(k => _isPrimitiveKey(target.elements[k]) && k !== 'IsActiveEntity')
395
- let selectQuery = SELECT(keys).from(req.target.name)
396
-
397
- if (req.query.DELETE.where) {
398
- selectQuery = selectQuery.where(req.query.DELETE.where)
399
- }
400
-
401
- selectQuery = cqn2cqn4sql(selectQuery, this.model, { service: this })
402
- req._beforeDeleteData = await this._read(this.model, this.dbc, selectQuery, req.context || req)
403
- }
404
-
405
- beforeDelete._initial = true
406
-
407
- /*
408
- * perform check
409
- */
410
- const _performCheck = async (req, cur, csn, run) => {
411
- const prev = (cur.errors && cur.errors.length) || 0
412
-
413
- if (Array.isArray(cur.query)) {
414
- for (const each of cur.query) {
415
- const r = { query: each, target: each._target, event: each.cmd === 'INSERT' ? 'CREATE' : each.cmd }
416
- Object.setPrototypeOf(r, cur)
417
- await _checkIntegrityUtil(r, csn, run)
418
- if (r.errors && r.errors.length) r.errors.forEach(e => req.error(e))
419
- }
420
- } else {
421
- await _checkIntegrityUtil(cur, csn, run)
422
- }
423
-
424
- // only additional errors
425
- if (cur.errors && cur.errors.length > prev) {
426
- cur.errors.forEach(e => req.error(e))
427
- }
428
- }
429
-
430
- function performCheck(req) {
431
- if (_skipIntegrityCheck(req, this)) return
432
-
433
- const root = req.context || req
434
- const children = root._children
435
- if (!children || !(this.name in children)) return
436
-
437
- const relevant = children[this.name].filter(r => {
438
- if (r.event) return r.event in C_UD
439
- if (Array.isArray(r.query)) return r.query.some(q => q.cmd in C_UD)
440
- return r.query && r.query.cmd in C_UD
441
- })
442
-
443
- if (relevant.length === 0) return
444
-
445
- return Promise.all(
446
- relevant.map(r => _performCheck(req, r, this.model, query => this._read(this.model, this.dbc, query, root)))
447
- )
448
- }
449
-
450
- performCheck._initial = true
451
-
452
- module.exports = {
453
- beforeDelete,
454
- performCheck
455
- }
package/srv/audit-log.cds DELETED
@@ -1,87 +0,0 @@
1
- service AuditLogService {
2
-
3
- // Log read access to sensitive personal data
4
- event dataAccessLog {
5
- accesses : array of Access;
6
- // accessFilters : array of KeyValuePair;
7
- };
8
-
9
- // Log changes to personal data
10
- event dataModificationLog : {
11
- modifications : array of DataModification;
12
- };
13
-
14
- // config change
15
- event configChangeLog : {
16
- action : String @assert.range enum {
17
- Create;
18
- Update;
19
- Delete
20
- };
21
- // success : Boolean;
22
- configurations : array of ConfigChange;
23
- };
24
-
25
- // security message
26
- event securityLog : {
27
- action : String;
28
- data : String;
29
- };
30
-
31
- }
32
-
33
- // types
34
-
35
- define type KeyValuePair {
36
- keyName : String;
37
- value : String;
38
- };
39
-
40
- define type DataObject {
41
- type : String;
42
- id : array of KeyValuePair;
43
- };
44
-
45
- define type DataSubject {
46
- type : String;
47
- id : array of KeyValuePair;
48
- role : String;
49
- };
50
-
51
- define type Attribute {
52
- name : String;
53
- };
54
-
55
- define type Attachment {
56
- id : String;
57
- name : String;
58
- };
59
-
60
- define type Access {
61
- dataObject : DataObject;
62
- dataSubject : DataSubject;
63
- attributes : array of Attribute;
64
- attachments : array of Attachment;
65
- };
66
-
67
- define type ChangedAttribute {
68
- name : String;
69
- oldValue : String;
70
- newValue : String;
71
- };
72
-
73
- define type DataModification {
74
- dataObject : DataObject;
75
- dataSubject : DataSubject;
76
- action : String @assert.range enum {
77
- Create;
78
- Update;
79
- Delete;
80
- };
81
- attributes : array of ChangedAttribute;
82
- }
83
-
84
- define type ConfigChange {
85
- dataObject : DataObject;
86
- attributes : array of ChangedAttribute;
87
- };
package/srv/mtx.cds DELETED
@@ -1,2 +0,0 @@
1
- /** Dummy service for bootstrapping old MTX */
2
- @protocol:'none' service cds.xt.MTXServices {}
package/srv/mtx.js DELETED
@@ -1,8 +0,0 @@
1
- module.exports = ()=> {
2
- const cds = require ('../lib')
3
- if (cds.mtx) {
4
- const DEBUG = cds.debug('mtx')
5
- DEBUG && DEBUG ('bootstrapping old MTX...')
6
- return cds.mtx.in (cds.app) // old mtx
7
- }
8
- }
File without changes
File without changes