@sap/cds 5.4.6 → 5.5.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 (228) hide show
  1. package/CHANGELOG.md +208 -2
  2. package/apis/ql.d.ts +17 -15
  3. package/app/index.js +1 -1
  4. package/bin/build/buildTaskEngine.js +26 -42
  5. package/bin/build/buildTaskFactory.js +6 -10
  6. package/bin/build/buildTaskHandler.js +2 -4
  7. package/bin/build/buildTaskProvider.js +3 -1
  8. package/bin/build/buildTaskProviderFactory.js +9 -15
  9. package/bin/build/constants.js +15 -3
  10. package/bin/build/index.js +5 -4
  11. package/bin/build/mtaUtil.js +8 -11
  12. package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
  13. package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
  14. package/bin/build/provider/buildTaskProviderInternal.js +16 -42
  15. package/bin/build/provider/fiori/index.js +13 -24
  16. package/bin/build/provider/hana/2migration.js +17 -15
  17. package/bin/build/provider/hana/2tabledata.js +52 -48
  18. package/bin/build/provider/hana/index.js +27 -25
  19. package/bin/build/provider/hana/migrationtable.js +91 -67
  20. package/bin/build/provider/java-cf/index.js +14 -24
  21. package/bin/build/provider/mtx/index.js +12 -14
  22. package/bin/build/provider/node-cf/index.js +18 -32
  23. package/bin/cds.js +5 -5
  24. package/bin/serve.js +29 -23
  25. package/bin/version.js +0 -1
  26. package/lib/compile/etc/_localized.js +4 -9
  27. package/lib/compile/for/sql.js +5 -2
  28. package/lib/compile/parse.js +25 -17
  29. package/lib/compile/to/srvinfo.js +2 -1
  30. package/lib/connect/bindings.js +2 -1
  31. package/lib/connect/index.js +48 -49
  32. package/lib/core/classes.js +1 -1
  33. package/lib/core/reflect.js +10 -2
  34. package/lib/deploy.js +26 -23
  35. package/lib/env/defaults.js +13 -6
  36. package/lib/env/index.js +73 -78
  37. package/lib/env/requires.js +38 -19
  38. package/lib/index.js +9 -10
  39. package/lib/lazy.js +2 -2
  40. package/lib/log/index.js +33 -45
  41. package/lib/log/service/index.js +2 -2
  42. package/lib/ql/CREATE.js +14 -9
  43. package/lib/ql/DELETE.js +6 -5
  44. package/lib/ql/DROP.js +12 -9
  45. package/lib/ql/INSERT.js +40 -16
  46. package/lib/ql/Query.js +67 -40
  47. package/lib/ql/SELECT.js +162 -127
  48. package/lib/ql/UPDATE.js +74 -42
  49. package/lib/ql/Whereable.js +77 -87
  50. package/lib/ql/index.js +36 -24
  51. package/lib/ql/parse.js +35 -0
  52. package/lib/req/context.js +44 -8
  53. package/lib/req/locale.js +7 -7
  54. package/lib/serve/Service-api.js +21 -14
  55. package/lib/serve/Service-dispatch.js +28 -12
  56. package/lib/serve/Transaction.js +22 -10
  57. package/lib/serve/index.js +16 -11
  58. package/lib/utils/axios.js +23 -16
  59. package/lib/utils/data.js +35 -0
  60. package/lib/utils/tests.js +27 -18
  61. package/libx/_runtime/audit/generic/personal/access.js +81 -0
  62. package/libx/_runtime/audit/generic/personal/constants.js +4 -0
  63. package/libx/_runtime/audit/generic/personal/index.js +50 -0
  64. package/libx/_runtime/audit/generic/personal/modification.js +138 -0
  65. package/libx/_runtime/audit/generic/personal/utils.js +186 -0
  66. package/libx/_runtime/audit/utils/v2.js +10 -4
  67. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
  68. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
  69. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
  70. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
  71. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
  72. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
  73. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
  74. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
  75. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
  76. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
  77. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
  78. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
  79. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
  80. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
  81. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
  82. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
  83. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
  84. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
  85. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
  86. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
  87. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
  88. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
  89. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
  90. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
  91. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  92. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
  93. package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
  94. package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
  95. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
  96. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
  97. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
  98. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
  99. package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
  100. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
  101. package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
  102. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
  103. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
  104. package/libx/_runtime/cds-services/services/Service.js +40 -5
  105. package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
  106. package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
  107. package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
  108. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
  109. package/libx/_runtime/common/composition/data.js +44 -55
  110. package/libx/_runtime/common/composition/delete.js +97 -71
  111. package/libx/_runtime/common/composition/index.js +2 -1
  112. package/libx/_runtime/common/composition/insert.js +34 -11
  113. package/libx/_runtime/common/composition/tree.js +119 -92
  114. package/libx/_runtime/common/composition/update.js +4 -1
  115. package/libx/_runtime/common/composition/utils.js +1 -3
  116. package/libx/_runtime/common/constants/draft.js +12 -1
  117. package/libx/_runtime/common/generic/auth.js +6 -22
  118. package/libx/_runtime/common/generic/crud.js +14 -13
  119. package/libx/_runtime/common/generic/input.js +23 -26
  120. package/libx/_runtime/common/generic/put.js +1 -1
  121. package/libx/_runtime/common/generic/sorting.js +16 -16
  122. package/libx/_runtime/common/i18n/index.js +1 -1
  123. package/libx/_runtime/common/i18n/messages.properties +4 -0
  124. package/libx/_runtime/common/utils/backlinks.js +12 -5
  125. package/libx/_runtime/common/utils/cqn.js +6 -1
  126. package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
  127. package/libx/_runtime/common/utils/csn.js +47 -4
  128. package/libx/_runtime/common/utils/data.js +0 -37
  129. package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
  130. package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
  131. package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
  132. package/libx/_runtime/common/utils/generateOnCond.js +11 -12
  133. package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
  134. package/libx/_runtime/common/utils/path.js +35 -0
  135. package/libx/_runtime/common/utils/postProcessing.js +86 -0
  136. package/libx/_runtime/common/utils/quotingStyles.js +37 -26
  137. package/libx/_runtime/common/utils/resolveView.js +223 -171
  138. package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
  139. package/libx/_runtime/common/utils/structured.js +6 -12
  140. package/libx/_runtime/common/utils/template.js +10 -5
  141. package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
  142. package/libx/_runtime/common/utils/templateProcessor.js +22 -30
  143. package/libx/_runtime/common/utils/union.js +31 -0
  144. package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
  145. package/libx/_runtime/db/Service.js +1 -1
  146. package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
  147. package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
  148. package/libx/_runtime/db/expand/index.js +3 -3
  149. package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
  150. package/libx/_runtime/db/generic/index.js +1 -1
  151. package/libx/_runtime/db/generic/input.js +5 -7
  152. package/libx/_runtime/db/generic/integrity.js +1 -1
  153. package/libx/_runtime/db/generic/rewrite.js +2 -10
  154. package/libx/_runtime/db/generic/update.js +13 -5
  155. package/libx/_runtime/db/generic/virtual.js +22 -58
  156. package/libx/_runtime/db/query/delete.js +7 -4
  157. package/libx/_runtime/db/query/insert.js +6 -4
  158. package/libx/_runtime/db/query/read.js +13 -20
  159. package/libx/_runtime/db/query/run.js +4 -1
  160. package/libx/_runtime/db/query/update.js +5 -4
  161. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
  162. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
  163. package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
  164. package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
  165. package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
  166. package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
  167. package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
  168. package/libx/_runtime/db/utils/deep.js +8 -0
  169. package/libx/_runtime/db/utils/generateAliases.js +2 -1
  170. package/libx/_runtime/fiori/generic/activate.js +19 -15
  171. package/libx/_runtime/fiori/generic/before.js +3 -11
  172. package/libx/_runtime/fiori/generic/cancel.js +1 -1
  173. package/libx/_runtime/fiori/generic/delete.js +3 -1
  174. package/libx/_runtime/fiori/generic/edit.js +12 -2
  175. package/libx/_runtime/fiori/generic/new.js +5 -5
  176. package/libx/_runtime/fiori/generic/patch.js +0 -18
  177. package/libx/_runtime/fiori/generic/read.js +241 -189
  178. package/libx/_runtime/fiori/utils/delete.js +36 -7
  179. package/libx/_runtime/fiori/utils/handler.js +43 -44
  180. package/libx/_runtime/fiori/utils/where.js +30 -15
  181. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
  182. package/libx/_runtime/hana/execute.js +2 -2
  183. package/libx/_runtime/hana/localized.js +4 -4
  184. package/libx/_runtime/hana/pool.js +29 -14
  185. package/libx/_runtime/hana/search2cqn4sql.js +2 -1
  186. package/libx/_runtime/hana/searchToContains.js +18 -14
  187. package/libx/_runtime/index.js +0 -5
  188. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
  189. package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
  190. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
  191. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
  192. package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
  193. package/libx/_runtime/messaging/service.js +7 -6
  194. package/libx/_runtime/odata/cqn2odata.js +110 -43
  195. package/libx/_runtime/odata/index.js +26 -48
  196. package/libx/_runtime/odata/odata2cqn.js +1 -6154
  197. package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
  198. package/libx/_runtime/odata/readToCqn.js +94 -64
  199. package/libx/_runtime/remote/Service.js +74 -21
  200. package/libx/_runtime/remote/cqn2odata/index.js +1 -5
  201. package/libx/_runtime/remote/utils/client.js +24 -101
  202. package/libx/_runtime/remote/utils/dataConversion.js +27 -12
  203. package/libx/_runtime/sqlite/Service.js +3 -5
  204. package/libx/_runtime/sqlite/execute.js +23 -24
  205. package/libx/_runtime/sqlite/localized.js +12 -7
  206. package/libx/_runtime/types/api.js +10 -0
  207. package/package.json +1 -1
  208. package/server.js +16 -2
  209. package/lib/ql/grammar.pegjs +0 -208
  210. package/lib/ql/parser.js +0 -1
  211. package/lib/ql/rt/DELETE.js +0 -29
  212. package/lib/ql/rt/INSERT.js +0 -23
  213. package/lib/ql/rt/Query.js +0 -84
  214. package/lib/ql/rt/SELECT.js +0 -174
  215. package/lib/ql/rt/UPDATE.js +0 -119
  216. package/lib/ql/rt/_helpers.js +0 -91
  217. package/lib/ql/rt/index.js +0 -32
  218. package/libx/_runtime/audit/generic/personal.js +0 -260
  219. package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
  220. package/libx/_runtime/cds-services/statements/Create.js +0 -57
  221. package/libx/_runtime/cds-services/statements/Delete.js +0 -33
  222. package/libx/_runtime/cds-services/statements/Drop.js +0 -42
  223. package/libx/_runtime/cds-services/statements/Insert.js +0 -201
  224. package/libx/_runtime/cds-services/statements/Select.js +0 -826
  225. package/libx/_runtime/cds-services/statements/Update.js +0 -181
  226. package/libx/_runtime/cds-services/statements/Where.js +0 -726
  227. package/libx/_runtime/cds-services/statements/index.js +0 -25
  228. package/libx/_runtime/common/generic/resolve-mock.js +0 -9
@@ -1,174 +0,0 @@
1
- const { CQL, CXL, cds, is_array, is_projection, is_function, _projection4, libx } = require('./_helpers')
2
- const $ = Object.assign
3
-
4
- // We'll extend and replace these below...
5
- const SELECT = libx.SELECT.from('X').constructor
6
- const select_columns = SELECT.prototype.columns
7
- const select_where = SELECT.prototype.where
8
- const select_having = SELECT.prototype.having
9
- const select_groupBy = SELECT.prototype.groupBy
10
- const select_orderBy = SELECT.prototype.orderBy
11
- const select_limit = SELECT.prototype.limit
12
-
13
-
14
- module.exports = cds.extend (SELECT) .with (class {
15
-
16
- static from(..._) { return (this.new).from(..._) }
17
- static _api() {
18
- return $((..._) => (this.new)._select_or_from(..._), {
19
- columns: (..._) => (this.new).columns(..._),
20
- from: (..._) => (this.new).from(..._),
21
- one: $((...x) => (this.new).one._select_or_from(...x),{
22
- columns: (..._) => (this.new).one.columns(..._),
23
- from: (..._) => (this.new).one.from(..._),
24
- }),
25
- distinct: $((...x) => (this.new).distinct._select_or_from(...x),{
26
- columns: (..._) => (this.new).distinct.columns(..._),
27
- from: (..._) => (this.new).distinct.from(..._),
28
- }),
29
- })
30
- }
31
-
32
- _select_or_from (cols, ...more) {
33
- if (!cols) return this
34
- else if (cols.name) return this.from (...arguments)
35
- else if (is_function(cols)) return select_columns.call (this, _projection4 (cols, this.entity))
36
- else if (is_array(cols)) return !cols[0] ? this : select_columns.call (this, cols)
37
- else if (!isNaN(cols)) return select_columns.apply (this,arguments) //> numbers can't be from
38
- else if (cols === '*') return select_columns.apply (this,arguments)
39
- else if (cols.raw) {
40
- let tts = [ ...cols ]; tts.raw = true //> because tt strings are sealed
41
- if (tts[0].startsWith('from ')) { //> it's a from, with an arbitrary long CQL tail...
42
- tts[0] = 'SELECT '+ tts[0]
43
- let {SELECT} = CQL(tts, ...more)
44
- Object.assign (this._, SELECT)
45
- return this
46
- } else if (tts[0].includes(':')) { //> it's a from (and needs to be handled, as it would become a cast instead)
47
- return this.from (String.raw(...arguments))
48
- } else if (tts[0][0] === '{') { //> it's a select
49
- tts[0] = 'SELECT from X '+ tts[0]
50
- let {SELECT} = CQL(tts, ...more)
51
- return select_columns.call (this, SELECT.columns)
52
- } else { //> still ambiguous...
53
- tts[0] = 'SELECT from X { '+ tts[0]; tts[tts.length-1] += ' }'
54
- let {SELECT:{columns:c}} = CQL(tts, ...more)
55
- if (c.length > 1 || !c[0].ref) return select_columns.call (this, c)
56
- else cols = c[0] //> goes on below...
57
- }
58
- }
59
- else if (typeof cols === 'string' && cols.includes(':')) {
60
- return select_columns.apply (this,arguments)
61
- }
62
-
63
-
64
- // it's still unclear whether it's a select or a from case
65
- // -> return a proxy assuming it's a from and switching to
66
- // columns on a subsequent call of .from, if any.
67
- const {one} = this._
68
- return Object.defineProperties (this.from(cols, ...more), {
69
- from: {configurable:true,value:(..._) => {
70
- delete this.from; delete this._.columns; delete this._.where
71
- if (!one) delete this._.one
72
- return this.from(..._).columns(cols, ...more)
73
- }},
74
- })
75
- }
76
-
77
- columns (cols, ...more) {
78
- if (!cols) return this
79
- if (is_function(cols)) return select_columns.call (this, _projection4 (cols, this.entity))
80
- if (is_array(cols)) return !cols[0] ? this : select_columns.call (this, cols)
81
- if (cols.raw) {
82
- let tts = [ ...cols ]; tts.raw = true //> because tt strings are sealed
83
- if (tts[0][0] === '{') {
84
- tts[0] = 'SELECT from X '+ tts[0]
85
- } else {
86
- tts[0] = 'SELECT from X { '+ tts[0]
87
- tts[tts.length-1] += ' }'
88
- }
89
- let {SELECT} = CQL(tts, ...more)
90
- cols = SELECT.columns
91
- }
92
- return select_columns.call (this, cols, ...more)
93
- }
94
-
95
- from (target, second, third) {
96
- this._.from = target === '*' || this._target_ref4 (...arguments)
97
- if (!target.raw && second) {
98
- if (is_projection(second)) this.columns(second)
99
- else this.byKey(second)
100
- if (third) this.columns(third)
101
- }
102
- // REVISIT: compatibility with overly eager impl in cds-runtime
103
- if (!this._.columns) this._addSelectColumns (target)
104
- return this
105
- }
106
-
107
- limit (rows,offset) {
108
- if (rows === undefined) return this
109
- if (typeof rows === 'object') this._.limit = rows
110
- else select_limit.call(this,rows,offset)
111
- return this
112
- }
113
-
114
- get distinct() {
115
- this._.distinct = true
116
- return this
117
- }
118
- get one() {
119
- this._.one = true
120
- return this
121
- }
122
-
123
- redirectTo (entity) {
124
- return this.clone().from(entity)
125
- }
126
-
127
- expand (ref, cols, exp = 'expand') {
128
- const { SELECT } = this,
129
- columns = SELECT.columns || (SELECT.columns = [])
130
- const col = { ref: ref.split('.'), [exp]: cols ? _projection4(cols) : ['*'] }
131
- columns.push(col)
132
- return this
133
- }
134
-
135
- inline (ref, cols) {
136
- return this.expand(ref, cols, 'inline')
137
- }
138
-
139
- where(...args) {
140
- if (!args[0]) return this
141
- if (args[0].raw) args = [CXL(...args).xpr]
142
- return select_where.apply(this,args)
143
- }
144
-
145
- having(...args) {
146
- if (args[0].raw) { this._.having = CXL(...args).xpr; return this }
147
- return select_having.apply(this,args)
148
- }
149
-
150
- groupBy (...args) {
151
- if (args[0].raw) {
152
- let tts = [ ...args ]; tts.raw = true //> because tt strings are sealed
153
- tts[0] = 'SELECT from X group by '+ tts[0]
154
- this._.groupBy = CQL(...tts).SELECT.groupBy
155
- return this
156
- }
157
- return select_groupBy.apply(this,args)
158
- }
159
-
160
- orderBy (...args) {
161
- if (args[0].raw) {
162
- let tts = [ ...args ]; tts.raw = true //> because tt strings are sealed
163
- tts[0] = 'SELECT from X order by '+ tts[0]
164
- this._.orderBy = CQL(...tts).SELECT.orderBy
165
- return this
166
- }
167
- return select_orderBy.apply(this,args)
168
- }
169
-
170
- foreach(callback) {
171
- return this.then((rows) => rows.map(callback))
172
- }
173
-
174
- })
@@ -1,119 +0,0 @@
1
- const { CXL, cds, libx } = require('./_helpers')
2
- const $ = Object.assign
3
-
4
- // We'll extend and replace these below...
5
- const UPDATE = libx.UPDATE('x').constructor
6
- const update_where = UPDATE.prototype.where
7
- const update_set = UPDATE.prototype.set
8
-
9
-
10
- module.exports = cds.extend (UPDATE) .with (class {
11
-
12
- static _api() {
13
- return $((..._) => (this.new).entity(..._), {
14
- entity: (..._) => (this.new).entity(..._),
15
- })
16
- }
17
-
18
- entity (target, key) {
19
- this._.entity = this._target_name4 (...arguments)
20
- if (key) this.byKey(key)
21
- return this
22
- }
23
-
24
- with (...args) {
25
- return this.set(...args)
26
- }
27
-
28
- set (...args) { // NOSONAR
29
- const {_} = this
30
-
31
- // A tagged template string
32
- if (args[0].raw) {
33
- _add (CXL(...args).xpr, args[0].raw)
34
- // for (let each of _comma_separated_exprs(String.raw(...args))) {
35
- // _add (cds.parse.expr(each).xpr, each)
36
- // }
37
- }
38
-
39
- // Alternating expr fragment / values args...
40
- else if (args.length > 1) {
41
- for (let i = 0; i < args.length; ++i) {
42
- const [, col, op] = /\s*([\w.]+)\s*([%*+-]?=)/.exec(args[i])
43
- _add ([ {ref:[col]}, op, { val: args[++i] } ])
44
- }
45
- }
46
-
47
- // A single expression string
48
- else if (typeof args[0] === 'string') {
49
- for (let each of _comma_separated_exprs(args[0])) {
50
- _add (cds.parse.expr(each).xpr, each)
51
- }
52
- }
53
-
54
- // A column - value / expr object
55
- else if (typeof args[0] === 'object') {
56
- update_set.call(this, ...args)
57
- }
58
-
59
- return this
60
-
61
- function _add (xpr, src) {
62
- if (!xpr) throw new Error (`Invalid UPDATE.set expression: ${src}`)
63
- const [lhs, op, ...rhs] = xpr
64
- if (!lhs.ref) throw new Error (`Invalid left-hand-side for UPDATE.set expression: ${lhs}`)
65
- const col = lhs.ref.join('.')
66
- const v = (
67
- op === '=' ? (rhs.length === 1 ? rhs[0] : { xpr: rhs }) :
68
- op.length === 2 && op[1] === '=' ? { xpr: [ lhs, op[0], ...rhs] } :
69
- cds.errror('Invalid operator in UPDATE.set expression: ' + op)
70
- )
71
- if (v.val) (_.data || (_.data={}))[col] = v.val
72
- else (_.with || (_.with={}))[col] = v
73
- }
74
- }
75
-
76
- where (...args) {
77
- if (!args[0]) return this
78
- if (args[0].raw) args = [CXL(...args).xpr]
79
- return update_where.apply(this,args)
80
- }
81
- })
82
-
83
-
84
- function _comma_separated_exprs(s) { // NOSONAR
85
- let all = [],
86
- start = 0,
87
- scope = 0,
88
- close = 0,
89
- stack = [close]
90
- for (let i = 0; i < s.length; ++i) {
91
- const c = s[i]
92
- if (c === ',' && !scope) {
93
- all.push(s.slice(start, i))
94
- start = i + 1
95
- } else if (c === "'") {
96
- while (i < s.length) {
97
- if (s[++i] === "'") {
98
- if (s[i + 1] === "'") ++i // NOSONAR
99
- else break
100
- }
101
- }
102
- } else if (c === '(') {
103
- scope++
104
- stack.unshift((close = ')'))
105
- } else if (c === '[') {
106
- scope++
107
- stack.unshift((close = ']'))
108
- } else if (c === '{') {
109
- scope++
110
- stack.unshift((close = '}'))
111
- } else if (c === close) {
112
- scope--
113
- stack.shift()
114
- close = stack[0]
115
- }
116
- }
117
- all.push(s.slice(start))
118
- return all
119
- }
@@ -1,91 +0,0 @@
1
- const is_projection = (x) => is_function(x) || is_array(x)
2
- const is_function = (x) => typeof x === 'function'
3
- const is_array = (x) => Array.isArray(x) && !x.raw
4
-
5
- const cds = require('../../index')
6
- const { CQL, CXL } = cds.parse
7
-
8
- module.exports = {
9
- libx: require('../../../libx/_runtime').statements,
10
- is_projection, is_array, is_function,
11
- _projection4, _predicate4,
12
- CQL, CXL, cds,
13
- }
14
-
15
-
16
- /* eslint no-unused-vars: off */
17
- function _projection4(x, entity) { // NOSONAR
18
- if (!x || x === '*') return ['*']
19
- if (is_projection(x[0])) x = x[0]
20
- if (is_array(x)) return x.map((c) => (c.ref ? c : { ref: c.split('.') }))
21
- if (typeof x === 'function') {
22
- const columns = []
23
- x(
24
- new Proxy(x, {
25
- // handle top-level projections or subselects such as
26
- // (foo)=>{ foo('*'), foo(SELECT...).as('bar') }
27
- apply: (_, __, args, ...more) => {
28
- if (!args.length) args = ['*']
29
- let [x] = is_array(args[0]) || args[0].raw ? args[0] : args
30
- if (x === '.*') x = '*'
31
- columns.push(x)
32
- return { as: (alias) => (x.as = alias) }
33
- },
34
- // handle top-level paths like (foo)=>{ foo.bar }
35
- get: (_, p) => {
36
- const col = { ref: [p] }
37
- columns.push(col)
38
- const nested = new Proxy(x, {
39
- // handle n-fold paths like (foo)=>{ foo.bar.car }
40
- get: (_, p) => {
41
- if (p === 'where') return (x) => ((col.where = _predicate4(x)), nested)
42
- if (p === 'as') return (alias) => ((col.as = alias), nested)
43
- else col.ref.push(p)
44
- return nested
45
- },
46
- // handle nested projections e.g. (foo)=>{ foo.bar (b=>{ ... }) }
47
- apply: (_, __, args) => {
48
- const [a, b] = args
49
- if (!a) col.expand = ['*']
50
- else if (a.raw) {
51
- if (a[0] === '*') col.expand = ['*']
52
- else if (a[0] === '.*') col.inline = ['*']
53
- else {
54
- let tts = [...a] //> tts are sealed
55
- tts[0] = 'SELECT '+ col.ref[col.ref.length-1] +' '+ tts[0]
56
- tts[tts.length-1] += ' from X'
57
- let {SELECT} = CQL(...tts)
58
- Object.assign (col, SELECT.columns[0])
59
- }
60
- }
61
- else if (a === '*') col.expand = ['*']
62
- else if (a === '.*') col.inline = ['*']
63
- else {
64
- let x = (col[/^\(?_\b/.test(a) ? 'inline' : 'expand'] = _projection4(args))
65
- if (b && b.levels)
66
- while (--b.levels) x.push({ ...col, expand: (x = [...x]) })
67
- }
68
- return nested
69
- },
70
- })
71
- return nested
72
- },
73
- })
74
- )
75
- return columns
76
- }
77
- else throw new Error('SELECT w/ invalid projection argument: ' + JSON.stringify(x))
78
- }
79
-
80
-
81
- /**
82
- * Helper to create a predicate from a feather object
83
- */
84
- function _predicate4 (o,...more) {
85
- if (o.raw) return CXL(o,...more).xpr
86
- const predicates = []
87
- for (let each in o) {
88
- predicates.push('and', { ref: each.split('.') }, '=', { val: o[each] })
89
- }
90
- return predicates.slice(1)
91
- }
@@ -1,32 +0,0 @@
1
- // Monkey-patched cds.ql implementations from cds-runtime
2
- module.exports = Object.assign (_deprecated_srv_ql, require('../../../libx/_runtime').statements, {
3
- Query: require('./Query'),
4
- SELECT: require('./SELECT')._api(),
5
- INSERT: require('./INSERT')._api(),
6
- UPDATE: require('./UPDATE')._api(),
7
- DELETE: require('./DELETE')._api(),
8
- })
9
-
10
-
11
- function _deprecated_srv_ql() {
12
- // eslint-disable-next-line no-console
13
- console.trace(`
14
- Method 'srv.ql(req)' is deprecated and superceded by 'cds.context'.
15
- Please use global SELECT instead of 'const { SELECT } = srv.ql(req)'.
16
- `)
17
- return module.exports
18
- }
19
-
20
-
21
- const {cds} = global
22
- if (cds.env.features.cls && cds.env.features.debug_queries) {
23
- const { AsyncResource } = require('async_hooks')
24
- const { Query } = module.exports
25
- const { then } = Query.prototype
26
- Object.defineProperty (Query,'then',{
27
- get(){
28
- const q = new AsyncResource('cds.Query')
29
- return (r,e) => q.runInAsyncScope (then,this,r,e)
30
- }
31
- })
32
- }
@@ -1,260 +0,0 @@
1
- const cds = require('../../cds')
2
-
3
- const getTemplate = require('../../common/utils/template')
4
- const templateProcessor = require('../../common/utils/templateProcessor')
5
-
6
- const WRITE = { CREATE: 1, UPDATE: 1, DELETE: 1 }
7
- const ASPECTS = { CREATE: '_auditCreate', READ: '_auditRead', UPDATE: '_auditUpdate', DELETE: '_auditDelete' }
8
-
9
- /*
10
- * common
11
- */
12
-
13
- const _getRootEntity = element => {
14
- let entity = element.parent
15
- while (entity.kind !== 'entity') entity = entity.parent
16
- return entity
17
- }
18
-
19
- // REVISIT: does this hash calc work for structured keys?
20
- const _getHash = (entity, row) => {
21
- return `${entity.name}(${Object.keys(entity.keys)
22
- .map(k => `${k}=${row[k]}`)
23
- .join(',')})`
24
- }
25
-
26
- const _addObjectID = (log, row, key) => {
27
- if (!log.dataObject.id.find(ele => ele.keyName === key)) log.dataObject.id.push({ keyName: key, value: row[key] })
28
- }
29
-
30
- // REVISIT: better solution for data subject calculation
31
- const _addDataSubject = (log, row, key, entity, element, model) => {
32
- let target = entity
33
- let prefix = ''
34
- if (element['@odata.foreignKey4']) {
35
- const assoc = entity.elements[element['@odata.foreignKey4']]
36
- target = model.definitions[assoc.target]
37
- prefix = assoc.name + '_'
38
- }
39
- if (!log.dataSubject.type) log.dataSubject.type = target.name
40
- const keyName = key.replace(prefix, '')
41
- if (!log.dataSubject.id.find(ele => ele.keyName === keyName)) {
42
- const value = row[key] || (row._old && row._old[key])
43
- log.dataSubject.id.push({ keyName, value })
44
- }
45
- }
46
-
47
- const _getPick = event => {
48
- return (element, target) => {
49
- if (!target[ASPECTS[event]]) return
50
-
51
- const categories = []
52
- if (!element.isAssociation && element.key) categories.push('ObjectID')
53
- if (!element.isAssociation && element['@PersonalData.FieldSemantics'] === 'DataSubjectID')
54
- categories.push('DataSubjectID')
55
- if (event in WRITE && element['@PersonalData.IsPotentiallyPersonal']) categories.push('IsPotentiallyPersonal')
56
- if (element['@PersonalData.IsPotentiallySensitive']) categories.push('IsPotentiallySensitive')
57
- if (categories.length) return { categories }
58
- }
59
- }
60
-
61
- /*
62
- * modification
63
- */
64
-
65
- const _getOldAndNew = (action, row, key, sensitive) => {
66
- let oldValue = action === 'Create' ? null : row._old && row._old[key]
67
- if (oldValue === undefined) oldValue = null
68
- let newValue = action === 'Delete' ? null : row[key]
69
- if (newValue === undefined) newValue = null
70
- return { oldValue, newValue }
71
- }
72
-
73
- const _processorFnModification = (modificationLogs, model) => {
74
- return (row, key, element, plain) => {
75
- if (!row._op) return
76
-
77
- const entity = _getRootEntity(element)
78
-
79
- const action = row._op[0].toUpperCase() + row._op.slice(1)
80
-
81
- // create or augment log entry
82
- const hash = _getHash(entity, row)
83
- let modificationLog = modificationLogs[hash]
84
- if (!modificationLog) {
85
- modificationLogs[hash] = {
86
- dataObject: { type: entity.name, id: [] },
87
- dataSubject: { id: [], role: entity['@PersonalData.DataSubjectRole'] },
88
- action,
89
- attributes: []
90
- }
91
- modificationLog = modificationLogs[hash]
92
- }
93
-
94
- // process categories
95
- for (const category of plain.categories) {
96
- if (category === 'ObjectID') {
97
- _addObjectID(modificationLog, row, key)
98
- } else if (category === 'DataSubjectID') {
99
- _addDataSubject(modificationLog, row, key, entity, element, model)
100
- } else if (category === 'IsPotentiallyPersonal') {
101
- if (!modificationLog.attributes.find(ele => ele.name === key)) {
102
- const { oldValue, newValue } = _getOldAndNew(action, row, key)
103
- if (oldValue !== newValue) modificationLog.attributes.push({ name: key, oldValue, newValue })
104
- }
105
- } else if (category === 'IsPotentiallySensitive') {
106
- if (!modificationLog.attributes.find(ele => ele.name === key)) {
107
- const { oldValue, newValue } = _getOldAndNew(action, row, key, true)
108
- if (oldValue !== newValue) modificationLog.attributes.push({ name: key, oldValue, newValue })
109
- }
110
- }
111
- }
112
- }
113
- }
114
-
115
- const _getDataModificationLogs = async (data, req, tx) => {
116
- const template = getTemplate(
117
- `personal_${req.event}`.toLowerCase(),
118
- Object.assign({ name: req.target._service.name, model: req._model }),
119
- req.target,
120
- { pick: _getPick(req.event) }
121
- )
122
-
123
- const modificationLogs = {}
124
- const processFn = _processorFnModification(modificationLogs, tx.model)
125
- templateProcessor({ processFn, row: req._diff, template })
126
-
127
- return modificationLogs
128
- }
129
-
130
- /*
131
- * access
132
- */
133
-
134
- const _processorFnAccess = (accessLogs, model) => {
135
- return (row, key, element, plain) => {
136
- const entity = _getRootEntity(element)
137
-
138
- // create or augment log entry
139
- const hash = _getHash(entity, row)
140
- let accessLog = accessLogs[hash]
141
- if (!accessLog) {
142
- accessLogs[hash] = {
143
- dataObject: { type: entity.name, id: [] },
144
- dataSubject: { id: [], role: entity['@PersonalData.DataSubjectRole'] },
145
- attributes: [],
146
- attachments: []
147
- }
148
- accessLog = accessLogs[hash]
149
- }
150
-
151
- // process categories
152
- for (const category of plain.categories) {
153
- if (category === 'ObjectID') {
154
- _addObjectID(accessLog, row, key)
155
- } else if (category === 'DataSubjectID') {
156
- _addDataSubject(accessLog, row, key, entity, element, model)
157
- } else if (category === 'IsPotentiallySensitive') {
158
- // add attribute
159
- if (!accessLog.attributes.find(ele => ele.name === key)) accessLog.attributes.push({ name: key })
160
- // REVISIT: attribute vs. attachment?
161
- }
162
- }
163
- }
164
- }
165
-
166
- const _getDataAccessLogs = (data, req, tx) => {
167
- const template = getTemplate(
168
- 'personal_read',
169
- Object.assign({ name: req.target._service.name, model: req._model }),
170
- req.target,
171
- { pick: _getPick('READ') }
172
- )
173
-
174
- const accessLogs = {}
175
- const processFn = _processorFnAccess(accessLogs, tx.model)
176
- const data_ = Array.isArray(data) ? data : [data]
177
- data_.forEach(row => {
178
- templateProcessor({ processFn, row, template })
179
- })
180
-
181
- return accessLogs
182
- }
183
-
184
- /*
185
- * handler registration
186
- */
187
-
188
- let als
189
-
190
- /*
191
- * Generic handlers for audit logging access to writing personal data
192
- */
193
-
194
- const _attachDiffToContextHandler = async function (req) {
195
- // REVISIT: what does this do?
196
- Object.defineProperty(req.query, '_selectAll', {
197
- enumerable: false,
198
- writable: false,
199
- configurable: true,
200
- value: true
201
- })
202
-
203
- // attach to root request
204
- req.context._diff = await req.diff()
205
- }
206
-
207
- const _auditModificationHandler = async function (data, req) {
208
- als = als || (await cds.connect.to('audit-log'))
209
- if (!als.ready) return
210
-
211
- const modificationLogs = await _getDataModificationLogs(data, req, this)
212
- const modifications = Object.keys(modificationLogs)
213
- .map(k => modificationLogs[k])
214
- .filter(ele => ele.attributes.length)
215
-
216
- if (modifications.length) await als.emit('dataModificationLog', { modifications })
217
- }
218
-
219
- /*
220
- * Generic handler for audit logging access to reading personal data
221
- */
222
-
223
- const _auditAccessHandler = async function (data, req) {
224
- als = als || (await cds.connect.to('audit-log'))
225
- if (!als.ready) return
226
-
227
- const accessLogs = await _getDataAccessLogs(data, req, this)
228
- const accesses = Object.keys(accessLogs).map(k => accessLogs[k])
229
-
230
- if (accesses.length) await als.emit('dataAccessLog', { accesses })
231
- }
232
-
233
- module.exports = function () {
234
- /*
235
- * data modification
236
- */
237
- // REVISIT: diff() doesn't work in srv after phase but foreign key propagation has not yet taken place in srv before phase
238
- // -> calc diff in db layer and attach to root request
239
- // -> REVISIT for GA: clear req._.partialPersistentState?
240
- _attachDiffToContextHandler._initial = true
241
- for (const entity of Object.values(this.entities).filter(e => e._auditCreate)) {
242
- cds.db.before('CREATE', entity, _attachDiffToContextHandler)
243
- this.after('CREATE', entity, _auditModificationHandler)
244
- }
245
- for (const entity of Object.values(this.entities).filter(e => e._auditUpdate)) {
246
- cds.db.before('UPDATE', entity, _attachDiffToContextHandler)
247
- this.after('UPDATE', entity, _auditModificationHandler)
248
- }
249
- for (const entity of Object.values(this.entities).filter(e => e._auditDelete)) {
250
- cds.db.before('DELETE', entity, _attachDiffToContextHandler)
251
- this.after('DELETE', entity, _auditModificationHandler)
252
- }
253
-
254
- /*
255
- * data access
256
- */
257
- for (const entity of Object.values(this.entities).filter(e => e._auditRead)) {
258
- this.after('READ', entity, _auditAccessHandler)
259
- }
260
- }