@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,726 +0,0 @@
1
- const cds = require('../../cds')
2
- const BaseStatement = require('./BaseStatement')
3
- const { ensureNoDraftsSuffix } = require('../../common/utils/draft')
4
- const { unexpectedFunctionCallError, invalidFunctionArgumentError } = require('../util/errors')
5
-
6
- const MODEL = Symbol.for('sap.cds.model')
7
- const fnChain = Symbol.for('sap.cds.fnChain')
8
- const ON = Symbol.for('cqn.from.on')
9
-
10
- const OPERATIONS = ['=', '>', '<', '!=', '<>', '>=', '<=', 'like', 'between', 'in', 'not in']
11
- const VALUES = [null, undefined, true, false]
12
-
13
- class Where extends BaseStatement {
14
- get cqn() {
15
- return this.SELECT || this.UPDATE || this.DELETE
16
- }
17
-
18
- /**
19
- * Build 'where' cqn object. Can be chained and will always connect the chained where with an 'and'.
20
- *
21
- * Possible uses:
22
- * where('ID', '<operator>', <value>)
23
- * where('ID', 'between', <value>, <value>)
24
- * where('Association.name', '<operator>', <value>)
25
- * where('lower(column)', '<operator>', <value>)
26
- * where(<object>)
27
- * Fluid usage with alternating string value arguments
28
- * where(arg1, arg2, arg3, ...)
29
- * Array with partial CQNs
30
- * where([arg1, arg2, arg3, ...])
31
- *
32
- * @param {...any} args
33
- * @example
34
- * where('ID', '>', 7411)
35
- * where({ ID: 7411})
36
- * where({ or: [{ ID: 7411}, { ID: 2511}]})
37
- * Fluid usage:
38
- * where(`name like`, 'foo', `and ( ratio between`, 0.1, `and`, 0.3, `or ratio >`, 0.9, ')')
39
- * Array with partial CQNs
40
- * where([{ref: ['x']}, '=', {val: 1}])
41
- *
42
- * @returns {object} this object instance for chaining.
43
- * @throws Error - If .having() called before .where() or if no valid first argument provided
44
- */
45
- where(...args) {
46
- if (args.length === 0) return this // ignore attempts to add nothing
47
- const { cqn } = this
48
- if (cqn.having) throw unexpectedFunctionCallError('.having()', '.where()')
49
- if (cqn.where) return this._andWhere(...args)
50
- cqn.where = []
51
- this[fnChain] = this[fnChain].concat('.where()')
52
- return this._where(...args)
53
- }
54
-
55
- /**
56
- * .and can only be used after .join has been called.
57
- *
58
- * @param {string | object} arg1 Can be object if argument is passed as an object or can be a string when an identifier is directly passed.
59
- * @param {*} [arg2] Can be a value or an operator if the 3rd argument is the value.
60
- * @param [arg3] Value or CQN if second argument is operator.
61
- * @param [arg4] Value in case the second argument is the 'between' operator; Otherwise ignored.
62
- * @param {...any} args
63
- * @returns {object} this object instance for chaining.
64
- * @throws Error - If called without calling join or where before.
65
- */
66
- and(...args) {
67
- if (args.length === 0) return this
68
- this[fnChain] = this[fnChain].concat('.and()')
69
- return this._logicOperation('and', ...args)
70
- }
71
-
72
- /**
73
- * .byId filters on the column 'id'. It can only be used if .where has not been called yet.
74
- *
75
- * @param {string} arg1 is the value on which the filtering should be performed.
76
- * @returns {object} this object instance for chaining
77
- */
78
- byId(arg1) {
79
- this[fnChain] = this[fnChain].concat('.byId()')
80
- return this.where('id', '=', arg1)
81
- }
82
-
83
- /**
84
- * @param {string | object} arg1 Can be object if argument is passed as an object or can be a string when an identifier is directly passed.
85
- * @param {*} [arg2] Can be a value or an operator if the 3rd argument is the value.
86
- * @param [arg3] Value or CQN if second argument is operator.
87
- * @param [arg4] Value in case the second argument is the 'between' operator; Otherwise ignored.
88
- * @param {...any} args
89
- * @returns {object} this object instance for chaining.
90
- * @throws Error - If called without calling join or where before.
91
- */
92
- or(...args) {
93
- this[fnChain] = this[fnChain].concat('.or()')
94
- return this._logicOperation('or', ...args)
95
- }
96
-
97
- _andWhere(...args) {
98
- return this._setAndOrBracket('and', 'where', ...args)
99
- }
100
-
101
- _setAndOrBracket(operator, clause, ...args) {
102
- if (operator === 'and') {
103
- this.cqn[clause].unshift('(')
104
- this.cqn[clause].push(')')
105
- }
106
- this.cqn[clause].push(operator)
107
- return this._condition(clause, ...args)
108
- }
109
-
110
- _logicOperation(operator, ...args) {
111
- const cqn = this.cqn
112
- const isJoin = cqn.from && Object.prototype.hasOwnProperty.call(cqn.from, 'join')
113
- const isWhere = cqn.where && cqn.where.length > 0
114
- const isHaving = cqn.having && cqn.having.length > 0
115
- const clause = (isHaving && 'having') || (isWhere && 'where') || (isJoin && ON)
116
-
117
- if (clause) return this._setAndOrBracket(operator, clause, ...args)
118
-
119
- throw unexpectedFunctionCallError(operator, this[fnChain])
120
- }
121
-
122
- _getList(arr) {
123
- const list = []
124
- for (const element of arr) {
125
- if (typeof element === 'object' && element !== null) list.push(element)
126
- else list.push({ val: element })
127
- }
128
-
129
- return { list: list }
130
- }
131
-
132
- _fluidValue(val) {
133
- if (val === null) {
134
- return { val: null }
135
- }
136
- if (val === undefined || val.xpr || val.ref || val.val || val.func || val.list) return val
137
- if (Array.isArray(val)) {
138
- return this._getList(val)
139
- }
140
-
141
- if (isNaN(val)) {
142
- if (val[0] === "'" && val[val.length - 1] === "'") {
143
- return { val: val.slice(1, -1) }
144
- }
145
- }
146
-
147
- return { val: val }
148
- }
149
-
150
- _replacePlaceholders(xpr, placeholderMap) {
151
- xpr.forEach((each, i) => {
152
- if (each.SELECT && each.SELECT.from && each.SELECT.from.ref && each.SELECT.from.ref[0] === '$placeholder') {
153
- xpr[i] = placeholderMap[each.SELECT.from.ref[1]]
154
- }
155
- if (each.xpr) this._replacePlaceholders(each.xpr, placeholderMap)
156
- })
157
- }
158
-
159
- // fluid usage uses cds-compiler
160
- _fluidUsage(...args) {
161
- const placeholderMap = {}
162
- let placeholderNum = 0
163
- let expr = ''
164
- const values = []
165
-
166
- // 1. construct a full expr string with ? for values collected in values
167
- args.forEach((element, index) => {
168
- if (index % 2 === 0) {
169
- expr = expr.concat(element)
170
- } else {
171
- if (element && element.SELECT) {
172
- const placeholder = ` (SELECT FROM $placeholder:_${++placeholderNum}) `
173
- placeholderMap['_' + placeholderNum] = element
174
- expr = expr.concat(placeholder)
175
- } else {
176
- expr = expr.concat(' ? ')
177
- values.push(element)
178
- }
179
- }
180
- })
181
- // 2. parse the expr string
182
- const { xpr } = cds.parse.expr(expr)
183
-
184
- // 3. replace {params} in there with collected values
185
- const _replaceParamsIn = xpr => {
186
- const result = []
187
- for (const element of xpr) {
188
- if (element.xpr) result.push({ xpr: _replaceParamsIn(element.xpr) })
189
- else {
190
- const v = element.param ? this._fluidValue(values.shift()) : element
191
- result.push(v)
192
- }
193
- }
194
- return result
195
- }
196
- const result = _replaceParamsIn(xpr)
197
-
198
- // 4. replace sub-selects
199
- this._replacePlaceholders(result, placeholderMap)
200
-
201
- return result
202
- }
203
-
204
- _simpleArguments(...args) {
205
- if (args.length < 3 || args.length > 4) return
206
-
207
- // eslint-disable-next-line no-useless-escape
208
- if (typeof args[0] !== 'string' || /[\=\s\(\)]/.test(args[0])) return
209
-
210
- if (typeof args[1] !== 'string' || !OPERATIONS.includes(args[1].toLowerCase())) return
211
-
212
- if (
213
- typeof args[2] !== 'string' &&
214
- typeof args[2] !== 'number' &&
215
- !VALUES.includes(args[2]) &&
216
- !(args[2] instanceof RegExp) &&
217
- !Array.isArray(args[2])
218
- )
219
- return
220
-
221
- if (
222
- args[3] !== undefined &&
223
- typeof args[3] !== 'string' &&
224
- typeof args[3] !== 'number' &&
225
- !VALUES.includes(args[3])
226
- ) {
227
- return false
228
- }
229
-
230
- return true
231
- }
232
-
233
- _copyCondition(kind, arr) {
234
- if (arr.length === 0) {
235
- throw invalidFunctionArgumentError(this[fnChain], [])
236
- }
237
-
238
- if (this.cqn[kind].length !== 0) {
239
- this.cqn[kind].push('(', ...arr, ')')
240
- } else {
241
- this.cqn[kind].push(...arr)
242
- }
243
- return this
244
- }
245
-
246
- _conditionObject(kind, obj) {
247
- obj.or && this.cqn[kind].length !== 0
248
- ? this.cqn[kind].push('(', ...this._parseObjectArgument(obj), ')')
249
- : this.cqn[kind].push(...this._parseObjectArgument(obj))
250
- return this
251
- }
252
-
253
- _condition(kind, ...args) {
254
- // copy existing array with partial CQNs
255
- if (Array.isArray(args[0])) {
256
- return this._copyCondition(kind, args[0])
257
- }
258
-
259
- // single object
260
- if (typeof args[0] === 'object') {
261
- return this._conditionObject(kind, ...args)
262
- }
263
-
264
- // simple comparison "ref op val"
265
- if (this._simpleArguments(...args)) {
266
- this.cqn[kind].push(...this._parseSimpleArguments(...args))
267
- return this
268
- }
269
-
270
- // fluid usage is used by dafault
271
- if (this.cqn[kind].length !== 0) {
272
- this.cqn[kind].push('(', ...this._fluidUsage(...args), ')')
273
- } else {
274
- this.cqn[kind].push(...this._fluidUsage(...args))
275
- }
276
- return this
277
- }
278
-
279
- _where(...args) {
280
- return this._condition('where', ...args)
281
- }
282
-
283
- _parseValOrRef(str) {
284
- if (str === '*' || this._isNumber(str)) {
285
- return { val: str }
286
- }
287
-
288
- const valString = str.match(/^'(.*)'$/)
289
- if (valString) {
290
- return { val: valString[1] }
291
- }
292
-
293
- return this._buildRef(str.trim())
294
- }
295
-
296
- _isNumber(obj) {
297
- return !isNaN(obj)
298
- }
299
-
300
- _valOrCqn(arg) {
301
- if (this._isCqn(arg)) {
302
- return arg
303
- }
304
- if (Array.isArray(arg)) {
305
- return this._getList(arg)
306
- }
307
- return { val: arg }
308
- }
309
-
310
- _isCqn(arg) {
311
- return arg && (arg.xpr || Object.prototype.hasOwnProperty.call(arg, 'val') || arg.ref || arg.func || arg.SELECT)
312
- }
313
-
314
- _getTableNamesFrom(fromObj) {
315
- if (typeof fromObj === 'string') {
316
- // delete with string in from
317
- return [fromObj]
318
- }
319
-
320
- if (fromObj.name) {
321
- // delete with entity in from
322
- return [fromObj.name]
323
- }
324
-
325
- // select
326
- return this._extractRefs(fromObj)
327
- }
328
-
329
- _extractRefs(from) {
330
- const hasOwnProperty = Object.prototype.hasOwnProperty
331
-
332
- if (hasOwnProperty.call(from, 'join')) {
333
- // cqn with join in from
334
- return this._refs(from.args)
335
- }
336
-
337
- if (hasOwnProperty.call(from, 'SET')) {
338
- // cqn UNION
339
- return from.as ? [from.as] : []
340
- }
341
-
342
- return from.as ? [from.ref[0], from.as] : [from.ref[0]]
343
- }
344
-
345
- _refs(refs) {
346
- const arr = []
347
-
348
- for (const element of refs) {
349
- if (Object.prototype.hasOwnProperty.call(element, 'join')) {
350
- // multiple join are nested, se we need to find all the table names in there as well
351
- arr.push(...this._extractRefs(element))
352
- } else {
353
- arr.push(element.ref[0])
354
-
355
- if (element.as) {
356
- arr.push(element.as)
357
- }
358
- }
359
- }
360
-
361
- return arr
362
- }
363
-
364
- _getTableNamesEntity(entityObj) {
365
- if (typeof entityObj === 'string') {
366
- // update with string in entity
367
- return entityObj
368
- }
369
-
370
- if (entityObj.name) {
371
- // update with entity in entity
372
- return ensureNoDraftsSuffix(entityObj.name)
373
- }
374
- }
375
-
376
- _getTableNames() {
377
- const tableNames = []
378
- const cqn = this.cqn
379
-
380
- if (cqn.from) {
381
- // select and delete
382
- tableNames.push(...this._getTableNamesFrom(cqn.from))
383
- } else if (cqn.entity) {
384
- // update
385
- tableNames.push(this._getTableNamesEntity(cqn.entity))
386
- }
387
-
388
- return tableNames
389
- }
390
-
391
- _matchTableColumn(name = '') {
392
- const matches = name.match(/^(?:"(\w+(?:\.\w+)*)"|(\w+))\.(?:"(\w+(?:\.\w+)*)"|(\w+))$/)
393
-
394
- if (matches) {
395
- return matches.filter(this._filterForTableAndColumn)
396
- }
397
- }
398
-
399
- _matchInline(name) {
400
- return name.replace(/{/g, '').replace(/}/g, '').split(/\./)
401
- }
402
-
403
- _filterForTableAndColumn(element, index) {
404
- return index && element != null
405
- }
406
-
407
- _parseInlineAssociation(element, tableNames) {
408
- if (element.includes('.{')) {
409
- return { ref: this._matchInline(element) }
410
- }
411
-
412
- const parts = element.split(/\./)
413
- if (parts && this[MODEL]) {
414
- for (const table of tableNames) {
415
- // inline or column name with dot
416
- if (this._isAssociation(table, parts[0])) {
417
- return { ref: parts }
418
- }
419
- }
420
- }
421
- }
422
-
423
- _buildWithTableName(element) {
424
- const tableNames = this._getTableNames()
425
- const matched = this._matchTableColumn(element)
426
-
427
- if (matched && tableNames.indexOf(matched[0]) !== -1) {
428
- return { ref: [matched[0], matched[1]] }
429
- }
430
-
431
- if (element.includes('.')) {
432
- return this._parseInlineAssociation(element, tableNames)
433
- }
434
- }
435
-
436
- _buildRef(element) {
437
- const ref = this._buildWithTableName(element)
438
-
439
- if (ref) {
440
- return ref
441
- }
442
-
443
- return { ref: [element] }
444
- }
445
-
446
- _buildValOrRef(element) {
447
- if (typeof element === 'string') {
448
- const ref = this._buildWithTableName(element)
449
- if (ref) {
450
- return ref
451
- }
452
- }
453
-
454
- return this._valOrCqn(element)
455
- }
456
-
457
- _refOrCqn(arg) {
458
- if (!this._isCqn(arg)) {
459
- return this._buildRef(arg)
460
- }
461
-
462
- return arg
463
- }
464
-
465
- _comparison(...args) {
466
- if (args.length > 2) {
467
- return args[1]
468
- }
469
-
470
- return '='
471
- }
472
-
473
- _value(...args) {
474
- if (args.length > 2) {
475
- return args[2]
476
- }
477
-
478
- return args[1]
479
- }
480
-
481
- _parseSimpleObjectArguments(...args) {
482
- const ref = this._refOrCqn(args[0])
483
- const comparison = this._comparison(...args)
484
- const value = this._value(...args)
485
-
486
- if (args.length === 1) {
487
- return [ref]
488
- }
489
-
490
- if (value != null) {
491
- // skip null / undefined
492
- if (value instanceof RegExp) {
493
- return [ref, 'regexp', { val: String(value) }]
494
- }
495
-
496
- if (value.SELECT) {
497
- return [ref, comparison, value]
498
- }
499
- }
500
-
501
- if (args.length === 4) {
502
- return [ref, comparison, { val: value }, 'and', { val: args[3] }]
503
- }
504
-
505
- return [ref, comparison, this._buildValOrRef(value)]
506
- }
507
-
508
- _isNestedObject(object) {
509
- return object && typeof object === 'object' && !Array.isArray(object) && !(object instanceof RegExp)
510
- }
511
-
512
- _isAndOr(key) {
513
- return key === 'or' || key === 'and'
514
- }
515
-
516
- _validateObjectArgument(object) {
517
- if (!object || Object.keys(object).length === 0) {
518
- throw invalidFunctionArgumentError(this[fnChain], object)
519
- }
520
- }
521
-
522
- _parseObjectArgument(object, inAnd) {
523
- this._validateObjectArgument(object)
524
-
525
- if (this._isCqn(object)) {
526
- return [object]
527
- }
528
-
529
- const arrayReturn = []
530
- const keys = Object.keys(object)
531
- for (let i = 0; i < keys.length; i++) {
532
- const key = keys[i]
533
- if (this._isAndOr(key)) {
534
- Array.isArray(object[key])
535
- ? this._andOrAsArray(key, object[key], arrayReturn, keys.length === 1)
536
- : this._andOrAsObject(key, object[key], arrayReturn, i === keys.length - 1)
537
- } else if (/^(:?not )?exists$/.test(key)) {
538
- arrayReturn.push(key, object[key])
539
- } else if (this._isNestedObject(object[key])) {
540
- this._addLogicOperatorIfNeeded(arrayReturn)
541
- arrayReturn.push(...this._parseNestedObject(key, object[key]))
542
- } else {
543
- this._addLogicOperatorIfNeeded(arrayReturn)
544
- const comparison = Array.isArray(object[key]) ? 'in' : '='
545
- arrayReturn.push(...this._parseSimpleObjectArguments(key, comparison, object[key]))
546
- }
547
- }
548
-
549
- if (inAnd && object.or) {
550
- arrayReturn.unshift('(')
551
- arrayReturn.push(')')
552
- }
553
-
554
- return arrayReturn
555
- }
556
-
557
- _parseSimpleArguments(...args) {
558
- const ref = this._buildRef(args[0])
559
- const op = args[1]
560
- const value = args[2]
561
-
562
- if (value != null && value instanceof RegExp) {
563
- return [ref, 'regexp', { val: String(value) }]
564
- }
565
-
566
- if (args.length === 4) {
567
- return [ref, op, { val: value }, 'and', { val: args[3] }]
568
- }
569
-
570
- return [ref, op, this._buildValOrRef(value)]
571
- }
572
-
573
- _andOrAsArray(key, array, arrayReturn, isOne) {
574
- this._addLogicOperatorIfNeeded(arrayReturn)
575
-
576
- if (key === 'or' && !isOne) {
577
- arrayReturn.push('(')
578
- }
579
- arrayReturn.push(...this._parseObjectArgument(array[0]))
580
- for (let i = 1, length = array.length; i < length; i++) {
581
- if (this._isAndOr(Object.keys(array[i])[0])) {
582
- arrayReturn.push(key, '(', ...this._parseObjectArgument(array[i]), ')')
583
- } else {
584
- arrayReturn.push(key, ...this._parseObjectArgument(array[i]))
585
- }
586
- }
587
-
588
- if (key === 'or' && !isOne) {
589
- arrayReturn.push(')')
590
- }
591
- }
592
-
593
- _andOrAsObject(key, obj, arrayReturn, isLast) {
594
- if (key === 'or' && !isLast) {
595
- arrayReturn.unshift('(')
596
- arrayReturn.push(key, ...this._parseObjectArgument(obj), ')')
597
- } else {
598
- arrayReturn.push(key, ...this._parseObjectArgument(obj, key === 'and'))
599
- }
600
- }
601
-
602
- _addLogicOperatorIfNeeded(array) {
603
- const length = array.length
604
-
605
- if (length === 0) {
606
- return
607
- }
608
-
609
- const lastEntry = array[length - 1]
610
-
611
- if (lastEntry !== 'and' && lastEntry !== 'or') {
612
- array.push('and')
613
- }
614
- }
615
-
616
- _parseNestedObject(parentKey, object) {
617
- const keys = Object.keys(object)
618
-
619
- if (this._isCqn(object)) {
620
- if (object.SELECT) {
621
- return this._parseSimpleObjectArguments(parentKey, 'in', object)
622
- }
623
-
624
- return this._parseSimpleObjectArguments(parentKey, object)
625
- }
626
-
627
- switch (keys.length) {
628
- case 1:
629
- return this._parseSimpleObjectArguments(parentKey, keys[0], object[keys[0]])
630
- case 2:
631
- return this._parseSimpleObjectArguments(parentKey, keys[0], object[keys[0]], object[keys[1]])
632
- default:
633
- throw invalidFunctionArgumentError(this[fnChain], object)
634
- }
635
- }
636
-
637
- _isAssociation(entityName, associationName) {
638
- const name = typeof entityName === 'object' ? ensureNoDraftsSuffix(entityName.name) : entityName
639
- const entity = this[MODEL].definitions[name]
640
- if (entity) {
641
- return entity.elements[associationName] && entity.elements[associationName]._isAssociationStrict
642
- }
643
- throw invalidFunctionArgumentError(this[fnChain], entity)
644
- }
645
-
646
- _isFunction(element) {
647
- if (element === null) {
648
- return false
649
- }
650
-
651
- if (typeof element === 'string') {
652
- return element.includes('(')
653
- }
654
-
655
- return false
656
- }
657
-
658
- _parseFunction(func) {
659
- if (typeof func === 'string') {
660
- return this._parseFunctionFromString(func)
661
- }
662
- }
663
-
664
- _splitArgs(argsString) {
665
- let bracketCounter = 0
666
-
667
- const commaIndex = []
668
-
669
- for (let i = 0; i < argsString.length; i++) {
670
- if (argsString.charAt(i) === '(') {
671
- bracketCounter++
672
- } else if (argsString.charAt(i) === ')') {
673
- bracketCounter--
674
- } else if (argsString.charAt(i) === ',' && bracketCounter === 0) {
675
- commaIndex.push(i)
676
- }
677
- }
678
-
679
- if (commaIndex.length > 0) {
680
- const args = []
681
- let lastIndex = 0
682
-
683
- for (const index of commaIndex) {
684
- args.push(argsString.substring(lastIndex, index))
685
- lastIndex = index + 1
686
- }
687
- args.push(argsString.substring(lastIndex, argsString.length))
688
- return args
689
- }
690
-
691
- return []
692
- }
693
-
694
- _fnArgs(str) {
695
- if (str.match(/^([^(]*)\((.*)\)$/)) {
696
- return this._parseFunctionFromString(str)
697
- } else {
698
- return this._parseValOrRef(str)
699
- }
700
- }
701
-
702
- _parseFunctionArgs(argsString, fnArgs = []) {
703
- if (argsString === '') {
704
- return []
705
- }
706
-
707
- const parts = this._splitArgs(argsString)
708
- if (parts.length > 0) {
709
- for (const part of parts) {
710
- fnArgs.push(this._fnArgs(part))
711
- }
712
- } else {
713
- fnArgs.push(this._fnArgs(argsString))
714
- }
715
- return fnArgs
716
- }
717
-
718
- _parseFunctionFromString(aggregation, cqnPartial = {}) {
719
- const fnArray = aggregation.match(/^([^(]*)\((.*)\)$/)
720
- cqnPartial.func = fnArray[1].toLowerCase()
721
- cqnPartial.args = fnArray[2] === '*' ? ['*'] : this._parseFunctionArgs(fnArray[2]) // * should not be wrapped as val here
722
- return cqnPartial
723
- }
724
- }
725
-
726
- module.exports = Where