@sap/cds 5.5.3 → 5.6.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.
- package/CHANGELOG.md +134 -1
- package/apis/services.d.ts +27 -1
- package/app/index.js +22 -11
- package/bin/build/buildTaskFactory.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +1 -1
- package/bin/build/provider/fiori/index.js +1 -1
- package/bin/build/provider/hana/2migration.js +8 -7
- package/bin/build/provider/java-cf/index.js +1 -1
- package/bin/deploy/to-hana/hana.js +1 -17
- package/common.cds +8 -0
- package/lib/compile/index.js +1 -1
- package/lib/compile/to/sql.js +22 -2
- package/lib/connect/bindings.js +2 -1
- package/lib/connect/index.js +1 -1
- package/lib/core/infer.js +1 -1
- package/lib/core/reflect.js +3 -1
- package/lib/env/index.js +175 -41
- package/lib/env/requires.js +24 -3
- package/lib/i18n/localize.js +33 -5
- package/lib/index.js +7 -6
- package/lib/log/format/kibana.js +6 -2
- package/lib/ql/DELETE.js +1 -1
- package/lib/ql/INSERT.js +1 -1
- package/lib/ql/Query.js +13 -10
- package/lib/ql/SELECT.js +15 -8
- package/lib/ql/UPDATE.js +1 -1
- package/lib/ql/Whereable.js +5 -0
- package/lib/req/context.js +87 -37
- package/lib/req/{impl.js → request.js} +1 -1
- package/lib/req/{res.js → response.js} +0 -0
- package/lib/serve/Service-api.js +1 -1
- package/lib/serve/Service-dispatch.js +12 -2
- package/lib/serve/Service-handlers.js +21 -7
- package/lib/serve/Service-methods.js +1 -1
- package/lib/serve/Transaction.js +7 -6
- package/lib/serve/index.js +1 -1
- package/lib/utils/axios.js +7 -0
- package/lib/utils/data.js +1 -1
- package/libx/_runtime/audit/Service.js +18 -18
- package/libx/_runtime/audit/generic/personal/access.js +1 -1
- package/libx/_runtime/audit/generic/personal/modification.js +3 -2
- package/libx/_runtime/audit/generic/personal/utils.js +23 -63
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +6 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +37 -35
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +3 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +13 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +84 -34
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +10 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +9 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +8 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +13 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +11 -95
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ResourcePathParser.js +17 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +6 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +3 -34
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +3 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +48 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +10 -5
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/update.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +1 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +9 -2
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +20 -21
- package/libx/_runtime/cds-services/services/utils/columns.js +6 -1
- package/libx/_runtime/cds-services/services/utils/compareJson.js +1 -8
- package/libx/_runtime/cds-services/services/utils/differ.js +7 -26
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -4
- package/libx/_runtime/cds-services/util/assert.js +29 -13
- package/libx/_runtime/cds.js +2 -1
- package/libx/_runtime/common/aspects/Association.js +72 -0
- package/libx/_runtime/common/aspects/any.js +8 -45
- package/libx/_runtime/common/aspects/entity.js +0 -1
- package/libx/_runtime/common/aspects/relation.js +40 -0
- package/libx/_runtime/common/aspects/utils.js +73 -1
- package/libx/_runtime/common/auth/strategies/utils/uaa.js +10 -14
- package/libx/_runtime/common/composition/data.js +3 -2
- package/libx/_runtime/common/composition/delete.js +3 -1
- package/libx/_runtime/common/composition/tree.js +23 -18
- package/libx/_runtime/common/composition/utils.js +34 -8
- package/libx/_runtime/common/error/frontend.js +6 -1
- package/libx/_runtime/common/generic/auth.js +15 -13
- package/libx/_runtime/common/generic/crud.js +2 -2
- package/libx/_runtime/common/generic/etag.js +11 -8
- package/libx/_runtime/common/generic/input.js +3 -3
- package/libx/_runtime/common/generic/paging.js +9 -5
- package/libx/_runtime/common/generic/put.js +3 -2
- package/libx/_runtime/common/generic/sorting.js +3 -3
- package/libx/_runtime/common/generic/temporal.js +3 -3
- package/libx/_runtime/common/toggles/alpha.js +1 -1
- package/libx/_runtime/common/utils/cqn.js +20 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +125 -139
- package/libx/_runtime/common/utils/csn.js +50 -52
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +41 -176
- package/libx/_runtime/common/utils/generateOnCond.js +40 -70
- package/libx/_runtime/common/utils/{enrichWithKeysFromWhere.js → keys.js} +29 -28
- package/libx/_runtime/common/utils/postProcessing.js +3 -0
- package/libx/_runtime/common/utils/propagateForeignKeys.js +84 -0
- package/libx/_runtime/common/utils/resolveStructured.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +19 -9
- package/libx/_runtime/common/utils/rewriteAsterisks.js +94 -0
- package/libx/_runtime/common/utils/search2cqn4sql.js +9 -8
- package/libx/_runtime/common/utils/template.js +54 -46
- package/libx/_runtime/db/Service.js +9 -2
- package/libx/_runtime/db/expand/expandCQNToJoin.js +10 -24
- package/libx/_runtime/db/expand/rawToExpanded.js +2 -1
- package/libx/_runtime/db/generic/create.js +1 -0
- package/libx/_runtime/db/generic/input.js +7 -11
- package/libx/_runtime/db/generic/integrity.js +2 -2
- package/libx/_runtime/db/generic/rewrite.js +2 -5
- package/libx/_runtime/db/generic/update.js +1 -0
- package/libx/_runtime/db/query/read.js +10 -5
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +6 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +7 -2
- package/libx/_runtime/db/sql-builder/annotations.js +1 -0
- package/libx/_runtime/db/utils/columns.js +14 -43
- package/libx/_runtime/db/utils/deep.js +5 -7
- package/libx/_runtime/fiori/generic/activate.js +3 -2
- package/libx/_runtime/fiori/generic/before.js +2 -2
- package/libx/_runtime/fiori/generic/cancel.js +3 -2
- package/libx/_runtime/fiori/generic/delete.js +3 -2
- package/libx/_runtime/fiori/generic/edit.js +2 -2
- package/libx/_runtime/fiori/generic/new.js +2 -2
- package/libx/_runtime/fiori/generic/patch.js +2 -2
- package/libx/_runtime/fiori/generic/prepare.js +2 -2
- package/libx/_runtime/fiori/generic/read.js +17 -63
- package/libx/_runtime/fiori/generic/readOverDraft.js +4 -4
- package/libx/_runtime/fiori/uiflex/extensibility/index.cds +15 -0
- package/libx/_runtime/fiori/uiflex/extensibility/index.js +148 -0
- package/libx/_runtime/fiori/uiflex/handler/transformREAD.js +119 -0
- package/libx/_runtime/fiori/uiflex/handler/transformRESULT.js +43 -0
- package/libx/_runtime/fiori/uiflex/handler/transformWRITE.js +62 -0
- package/libx/_runtime/fiori/uiflex/index.js +35 -0
- package/libx/_runtime/fiori/uiflex/utils.js +78 -0
- package/libx/_runtime/fiori/utils/handler.js +3 -13
- package/libx/_runtime/fiori/utils/where.js +6 -1
- package/libx/_runtime/hana/Service.js +5 -2
- package/libx/_runtime/hana/execute.js +1 -1
- package/libx/_runtime/hana/pool.js +12 -11
- package/libx/_runtime/hana/search2cqn4sql.js +34 -43
- package/libx/_runtime/hana/searchToContains.js +3 -3
- package/libx/_runtime/index.js +5 -2
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +1 -1
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +16 -3
- package/libx/_runtime/messaging/common-utils/connections.js +11 -14
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +1 -1
- package/libx/_runtime/messaging/message-queuing.js +18 -0
- package/libx/_runtime/remote/Service.js +14 -2
- package/libx/_runtime/remote/utils/client-types.d.ts +7 -0
- package/libx/_runtime/remote/utils/client.js +117 -23
- package/libx/_runtime/sqlite/Service.js +4 -3
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +1 -3
- package/libx/_runtime/sqlite/execute.js +1 -1
- package/libx/gql/GraphQLAdapter.js +33 -0
- package/libx/gql/constants/adapter.js +69 -0
- package/libx/gql/constants/cds.js +18 -0
- package/libx/gql/constants/graphql.js +33 -0
- package/libx/gql/resolvers/crud/create.js +15 -0
- package/libx/gql/resolvers/crud/delete.js +24 -0
- package/libx/gql/resolvers/crud/index.js +6 -0
- package/libx/gql/resolvers/crud/read.js +25 -0
- package/libx/gql/resolvers/crud/update.js +31 -0
- package/libx/gql/resolvers/crud/utils/index.js +36 -0
- package/libx/gql/resolvers/field.js +5 -0
- package/libx/gql/resolvers/index.js +7 -0
- package/libx/gql/resolvers/mutation.js +23 -0
- package/libx/gql/resolvers/parse/ast/enrich.js +51 -0
- package/libx/gql/resolvers/parse/ast/fragment.js +11 -0
- package/libx/gql/resolvers/parse/ast/fromObject.js +39 -0
- package/libx/gql/resolvers/parse/ast/index.js +3 -0
- package/libx/gql/resolvers/parse/ast/meta.js +4 -0
- package/libx/gql/resolvers/parse/ast/variable.js +7 -0
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +42 -0
- package/libx/gql/resolvers/parse/ast2cqn/entries.js +31 -0
- package/libx/gql/resolvers/parse/ast2cqn/index.js +8 -0
- package/libx/gql/resolvers/parse/ast2cqn/limit.js +6 -0
- package/libx/gql/resolvers/parse/ast2cqn/orderBy.js +24 -0
- package/libx/gql/resolvers/parse/ast2cqn/utils/index.js +3 -0
- package/libx/gql/resolvers/parse/ast2cqn/where.js +70 -0
- package/libx/gql/resolvers/parse/utils/index.js +8 -0
- package/libx/gql/resolvers/query.js +13 -0
- package/libx/gql/resolvers/root.js +34 -0
- package/libx/gql/schema/generate.js +18 -0
- package/libx/gql/schema/index.js +5 -0
- package/libx/gql/schema/mutation.js +76 -0
- package/libx/gql/schema/query.js +108 -0
- package/libx/gql/schema/typeDefMap.js +45 -0
- package/libx/gql/schema/utils/index.js +54 -0
- package/libx/gql/utils/index.js +12 -0
- package/libx/{_runtime/odata/cqn2odata.js → odata/cqn2odata/index.js} +39 -100
- package/libx/odata/index.js +80 -0
- package/libx/odata/odata2cqn/afterburner.js +170 -0
- package/libx/{_runtime/odata/odata2cqn.pegjs → odata/odata2cqn/grammar.pegjs} +102 -123
- package/libx/odata/odata2cqn/index.js +3 -0
- package/libx/odata/odata2cqn/parser.js +1 -0
- package/libx/odata/utils/index.js +64 -0
- package/libx/rest/RestAdapter.js +101 -0
- package/libx/rest/RestRequest.js +30 -0
- package/libx/rest/index.js +3 -0
- package/libx/rest/middleware/auth.js +22 -0
- package/libx/rest/middleware/content.js +15 -0
- package/libx/rest/middleware/create.js +40 -0
- package/libx/rest/middleware/delete.js +20 -0
- package/libx/rest/middleware/error.js +56 -0
- package/libx/rest/middleware/operation.js +39 -0
- package/libx/rest/middleware/parse.js +90 -0
- package/libx/rest/middleware/read.js +29 -0
- package/libx/rest/middleware/update.js +42 -0
- package/libx/rest/utils/data.js +65 -0
- package/package.json +4 -1
- package/server.js +42 -29
- package/lib/req/cls.js +0 -39
- package/libx/_runtime/cds-services/services/utils/diff.js +0 -53
- package/libx/_runtime/cds-services/util/auditlog.js +0 -247
- package/libx/_runtime/cds-services/util/xsenv.js +0 -51
- package/libx/_runtime/common/utils/backlinks.js +0 -83
- package/libx/_runtime/common/utils/rewriteAsterisk.js +0 -72
- package/libx/_runtime/odata/index.js +0 -55
- package/libx/_runtime/odata/odata2cqn.js +0 -1
- package/libx/_runtime/odata/readToCqn.js +0 -129
- package/libx/_runtime/remote/cqn2odata/index.js +0 -2
|
@@ -39,25 +39,18 @@ const validationChecks = (event, data, target) => {
|
|
|
39
39
|
const _enrichErrorDetails = (isPrimitive, error) => {
|
|
40
40
|
const element = error.target ? ` '${error.target}' ` : ' '
|
|
41
41
|
const typeDetails = isPrimitive ? '.' : ` according to type definition '${error.type}'.`
|
|
42
|
-
|
|
42
|
+
const value = typeof error.value === 'string' ? `'${error.value}'` : error.value
|
|
43
|
+
if (element && element.match(/\w/)) return `Value ${value} of element${element}is invalid${typeDetails}`
|
|
44
|
+
return `Value ${value} is invalid${typeDetails}`
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
// REVISIT: use i18n
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
const _getTypeError = (operation, type, errorDetails) => {
|
|
49
|
+
const typeErrors = errorDetails.map(error => _enrichErrorDetails(cds.builtin.types[type], error))
|
|
50
|
+
const msg = `Failed to validate return value ${type ? `of type '${type}' ` : ''}for custom ${operation.kind} '${
|
|
51
|
+
operation.name
|
|
49
52
|
}': ${typeErrors.join(' ')}`
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const _getTypeError = (context, operation, type, errorDetails) => {
|
|
53
|
-
return getError(
|
|
54
|
-
_buildErrorMessage(
|
|
55
|
-
context,
|
|
56
|
-
operation,
|
|
57
|
-
type,
|
|
58
|
-
errorDetails.map(error => _enrichErrorDetails(cds.builtin.types[type], error))
|
|
59
|
-
)
|
|
60
|
-
)
|
|
53
|
+
return getError(msg)
|
|
61
54
|
}
|
|
62
55
|
|
|
63
56
|
const _buildTypeErrorObject = (type, value) => {
|
|
@@ -79,14 +72,13 @@ const _checkSingle = (type, check, data) => {
|
|
|
79
72
|
* Validate the return type values of custom operations (actions and functions) for primitive or complex values as
|
|
80
73
|
* single values or arrays.
|
|
81
74
|
*
|
|
82
|
-
* @param {Context} context
|
|
83
75
|
* @param {Operation} operation
|
|
84
76
|
* @param {object} data
|
|
85
77
|
* @throws Will throw an error with error code 500 if the validation fails. Contains a detailed error message of the
|
|
86
78
|
* type and name of the custom operation, the invalid values, their names and their expected types.
|
|
87
79
|
* @returns {boolean} Returns true if return type validation has passed.
|
|
88
80
|
*/
|
|
89
|
-
const validateReturnType = (
|
|
81
|
+
const validateReturnType = (operation, data) => {
|
|
90
82
|
// array of or single return type
|
|
91
83
|
// in case of modeled return type: { type: 'bookModel.Books', _type: csnDefinition }
|
|
92
84
|
// in case of inline return type: { elements: ... } and no explicit name of return type
|
|
@@ -114,14 +106,21 @@ const validateReturnType = (context, operation, data) => {
|
|
|
114
106
|
// Determine entity from bound or unbound action/function
|
|
115
107
|
const returnTypeCsnDefinition = returnType._type || returnType
|
|
116
108
|
|
|
117
|
-
|
|
109
|
+
// REVISIT: remove exception with cds^6
|
|
110
|
+
// mtx returns object instead of string (as in modell) -> skip validation
|
|
111
|
+
if (returnTypeCsnDefinition.type !== 'cds.String') {
|
|
112
|
+
checkResult = checkStatic(returnTypeCsnDefinition, data, true)
|
|
113
|
+
}
|
|
118
114
|
}
|
|
119
115
|
|
|
120
|
-
if (checkResult.length !== 0) {
|
|
121
|
-
throw _getTypeError(
|
|
116
|
+
if (checkResult && checkResult.length !== 0) {
|
|
117
|
+
throw _getTypeError(operation, returnType.type, checkResult)
|
|
122
118
|
}
|
|
123
119
|
|
|
124
120
|
return true
|
|
125
121
|
}
|
|
126
122
|
|
|
127
|
-
module.exports = {
|
|
123
|
+
module.exports = {
|
|
124
|
+
validationChecks,
|
|
125
|
+
validateReturnType
|
|
126
|
+
}
|
|
@@ -127,7 +127,12 @@ const computeColumnsToBeSearched = (cqn, entity = { _searchableColumns: [] }) =>
|
|
|
127
127
|
cqn.SELECT.columns.forEach(column => {
|
|
128
128
|
if (column.func) {
|
|
129
129
|
// exclude $count by SELECT of number of Items in a Collection
|
|
130
|
-
if (
|
|
130
|
+
if (
|
|
131
|
+
cqn.SELECT.columns.length === 1 &&
|
|
132
|
+
column.func === 'count' &&
|
|
133
|
+
(column.as === '_counted_' || column.as === '$count')
|
|
134
|
+
)
|
|
135
|
+
return
|
|
131
136
|
toBeSearched.push(column)
|
|
132
137
|
return
|
|
133
138
|
}
|
|
@@ -141,15 +141,8 @@ const _addKeysToEntryIfNotExists = (keys, newEntry) => {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
const isSelfManaged = element => {
|
|
145
|
-
if (element.on && element.on.length > 2) {
|
|
146
|
-
return element.on[0].ref[0] === '$self' || element.on[2].ref[0] === '$self'
|
|
147
|
-
}
|
|
148
|
-
return false
|
|
149
|
-
}
|
|
150
|
-
|
|
151
144
|
const _isUnManaged = element => {
|
|
152
|
-
return element.on && !
|
|
145
|
+
return element.on && !element._isSelfManaged
|
|
153
146
|
}
|
|
154
147
|
|
|
155
148
|
const _skip = (entity, prop) => entity.elements[prop]._target._hasPersistenceSkip
|
|
@@ -7,8 +7,9 @@ const { selectDeepUpdateData } = require('../../../common/composition')
|
|
|
7
7
|
const { ensureDraftsSuffix } = require('../../../fiori/utils/handler')
|
|
8
8
|
|
|
9
9
|
const { DRAFT_COLUMNS } = require('../../../common/constants/draft')
|
|
10
|
-
const cqn2cqn4sql = require('../../../common/utils/cqn2cqn4sql')
|
|
10
|
+
const { cqn2cqn4sql, convertPathExpressionToWhere } = require('../../../common/utils/cqn2cqn4sql')
|
|
11
11
|
const { revertData } = require('../../../common/utils/resolveView')
|
|
12
|
+
const { removeIsActiveEntityRecursively } = require('../../../fiori/utils/where')
|
|
12
13
|
|
|
13
14
|
module.exports = class {
|
|
14
15
|
constructor(srv) {
|
|
@@ -32,31 +33,11 @@ module.exports = class {
|
|
|
32
33
|
return columns
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
_createWhereCondition(entity, data) {
|
|
36
|
-
return Object.keys(entity.keys).reduce((prev, curr) => {
|
|
37
|
-
if (!DRAFT_COLUMNS.includes(curr)) {
|
|
38
|
-
prev[curr] = data[curr]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return prev
|
|
42
|
-
}, {})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
36
|
_diffDelete(req) {
|
|
46
37
|
const { DELETE } = (req._ && req._.query) || req.query
|
|
47
38
|
const query = SELECT.from(DELETE.from).columns(this._createSelectColumnsForDelete(req.target))
|
|
48
39
|
if (DELETE.where) query.where(...DELETE.where)
|
|
49
40
|
|
|
50
|
-
// REVISIT: should be done in cqn2cqn4sql
|
|
51
|
-
if (req.target._isDraftEnabled && query.SELECT.from.ref.some(r => r.where)) {
|
|
52
|
-
query.SELECT.from.ref.forEach((r, i) => {
|
|
53
|
-
if (!r.where) return
|
|
54
|
-
const j = r.where.findIndex(w => w.ref && w.ref.some(r => r === 'IsActiveEntity'))
|
|
55
|
-
if (j === -1) return
|
|
56
|
-
r.where.splice(Math.max(j - 1, 0), 4)
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
41
|
return cds
|
|
61
42
|
.tx(req)
|
|
62
43
|
.run(query)
|
|
@@ -92,14 +73,14 @@ module.exports = class {
|
|
|
92
73
|
|
|
93
74
|
async _diffPatch(req, providedData) {
|
|
94
75
|
if (cds.db) {
|
|
76
|
+
const { target, alias, where = [] } = convertPathExpressionToWhere(req.query.UPDATE.entity, this._srv.model, {})
|
|
77
|
+
|
|
78
|
+
const draftRef = { ref: [ensureDraftsSuffix(target)], as: alias }
|
|
79
|
+
|
|
95
80
|
// SELECT because req.query in custom handler does not have access to _drafts
|
|
96
81
|
req._.partialPersistentState = await cds
|
|
97
82
|
.tx(req)
|
|
98
|
-
.run(
|
|
99
|
-
SELECT.from(ensureDraftsSuffix(req.target.name))
|
|
100
|
-
.where(this._createWhereCondition(req.target, req.data))
|
|
101
|
-
.limit(1)
|
|
102
|
-
)
|
|
83
|
+
.run(SELECT.from(draftRef).where(removeIsActiveEntityRecursively(where)).limit(1))
|
|
103
84
|
|
|
104
85
|
return compareJson(providedData || req.data, req._.partialPersistentState, req.target)
|
|
105
86
|
}
|
|
@@ -2,7 +2,6 @@ const cds = require('../../../cds')
|
|
|
2
2
|
|
|
3
3
|
const { SELECT } = cds.ql
|
|
4
4
|
|
|
5
|
-
const { foreignKeyPropagations } = require('../../../common/utils/foreignKeyPropagations')
|
|
6
5
|
const { checkReferenceIntegrity } = require('../../util/assert')
|
|
7
6
|
const { processDeep, processDeepAsync } = require('../../util/dataProcessUtils')
|
|
8
7
|
|
|
@@ -74,9 +73,8 @@ const _getSelectCQN = (req, columns) => {
|
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
function _fillForeignKeysWithNull(managedAssocToOneElement, row) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
row[key.parentFieldName] = null
|
|
76
|
+
for (const key of managedAssocToOneElement._foreignKeys) {
|
|
77
|
+
if (key.parentElement) row[key.parentElement.name] = null
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
const cds = require('../../cds')
|
|
1
2
|
const { all, resolve } = require('../../common/utils/thenable')
|
|
2
3
|
const { getDependents } = require('../../common/utils/csn')
|
|
3
4
|
|
|
4
5
|
// REVISIT: replace with cds.Request
|
|
5
6
|
const getEntry = require('../../common/error/entry')
|
|
7
|
+
const crypto = require('crypto')
|
|
6
8
|
|
|
7
9
|
const ISO_DATE_PART1 =
|
|
8
10
|
'[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)'
|
|
@@ -174,11 +176,12 @@ const checkComplexType = ([key, value], elements, ignoreNonModelledData) => {
|
|
|
174
176
|
return found || ignoreNonModelledData
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
const _checkStaticElementByKey = (
|
|
178
|
-
const
|
|
179
|
+
const _checkStaticElementByKey = (definition, key, value, result, ignoreNonModelledData) => {
|
|
180
|
+
const elementsOrParameters = definition.elements || definition.params
|
|
181
|
+
const elementOrParameter = elementsOrParameters[key]
|
|
179
182
|
|
|
180
|
-
if (!
|
|
181
|
-
if (!checkComplexType([key, value],
|
|
183
|
+
if (!elementOrParameter) {
|
|
184
|
+
if (!checkComplexType([key, value], elementsOrParameters, ignoreNonModelledData)) {
|
|
182
185
|
result.push(assertError(ASSERT_VALID_ELEMENT, { name: key }))
|
|
183
186
|
}
|
|
184
187
|
|
|
@@ -186,17 +189,17 @@ const _checkStaticElementByKey = (entity, key, value, result, ignoreNonModelledD
|
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
let check
|
|
189
|
-
if (
|
|
192
|
+
if (elementOrParameter.type === 'cds.UUID' && definition.name === 'ProvisioningService.tenant') {
|
|
190
193
|
// > old SCP accounts don't have UUID ids
|
|
191
194
|
check = CDS_TYPE_CHECKS['cds.String']
|
|
192
195
|
} else {
|
|
193
|
-
check = CDS_TYPE_CHECKS[
|
|
196
|
+
check = CDS_TYPE_CHECKS[elementOrParameter.type]
|
|
194
197
|
}
|
|
195
198
|
|
|
196
|
-
if (check && !check(value,
|
|
199
|
+
if (check && !check(value, elementOrParameter)) {
|
|
197
200
|
// code, entity, element, value
|
|
198
|
-
const args = [typeof value === 'string' ? '"' + value + '"' : value,
|
|
199
|
-
result.push(assertError({ code: ASSERT_DATA_TYPE, args },
|
|
201
|
+
const args = [typeof value === 'string' ? '"' + value + '"' : value, elementOrParameter.type]
|
|
202
|
+
result.push(assertError({ code: ASSERT_DATA_TYPE, args }, elementOrParameter, value, key))
|
|
200
203
|
}
|
|
201
204
|
|
|
202
205
|
return result
|
|
@@ -294,14 +297,14 @@ const checkInputConstraints = ({ element, value, errors, key, pathSegments, even
|
|
|
294
297
|
return errors
|
|
295
298
|
}
|
|
296
299
|
|
|
297
|
-
const checkStatic = (
|
|
300
|
+
const checkStatic = (definition, data, ignoreNonModelledData = false) => {
|
|
298
301
|
if (!Array.isArray(data)) data = [data]
|
|
299
302
|
|
|
300
303
|
return data.reduce((result, row) => {
|
|
301
304
|
return Object.entries(row)
|
|
302
305
|
.filter(([key, value]) => value !== null && value !== undefined)
|
|
303
306
|
.reduce((result, [key, value]) => {
|
|
304
|
-
return _checkStaticElementByKey(
|
|
307
|
+
return _checkStaticElementByKey(definition, key, value, result, ignoreNonModelledData)
|
|
305
308
|
}, result)
|
|
306
309
|
}, [])
|
|
307
310
|
}
|
|
@@ -320,6 +323,20 @@ const _checkExistsWhere = (entity, whereList, run) => {
|
|
|
320
323
|
}
|
|
321
324
|
}
|
|
322
325
|
|
|
326
|
+
if (cds.context) {
|
|
327
|
+
const hash = crypto.createHash('sha1').update(JSON.stringify(cqn)).digest('base64') // fastest hash
|
|
328
|
+
if (!cds.context.__alreadyExecutedIntegrityChecks) cds.context.__alreadyExecutedIntegrityChecks = new Map()
|
|
329
|
+
if (cds.context.__alreadyExecutedIntegrityChecks.has(hash)) {
|
|
330
|
+
return cds.context.__alreadyExecutedIntegrityChecks.get(hash)
|
|
331
|
+
} else {
|
|
332
|
+
const promise = run(cqn).then(exists => {
|
|
333
|
+
return exists.length !== 0
|
|
334
|
+
})
|
|
335
|
+
// we store the promise object in the map, it won't get executed twice when calling await Promise.all([promise, promise])
|
|
336
|
+
cds.context.__alreadyExecutedIntegrityChecks.set(hash, promise)
|
|
337
|
+
return promise
|
|
338
|
+
}
|
|
339
|
+
}
|
|
323
340
|
return run(cqn).then(exists => {
|
|
324
341
|
return exists.length !== 0
|
|
325
342
|
})
|
|
@@ -553,9 +570,8 @@ const checkKeys = (entity, data) => {
|
|
|
553
570
|
const entityKeys = Object.keys(entity.keys)
|
|
554
571
|
return data.reduce((result, row) => {
|
|
555
572
|
for (const key of entityKeys) {
|
|
556
|
-
if (
|
|
573
|
+
if (row[key] === undefined && entity.elements[key].type !== 'cds.Association')
|
|
557
574
|
result.push(assertError(ASSERT_NOT_NULL, entity.elements[key]))
|
|
558
|
-
}
|
|
559
575
|
}
|
|
560
576
|
return result
|
|
561
577
|
}, [])
|
package/libx/_runtime/cds.js
CHANGED
|
@@ -5,8 +5,9 @@ module.exports = cds
|
|
|
5
5
|
/*
|
|
6
6
|
* csn aspects
|
|
7
7
|
*/
|
|
8
|
-
const { any, entity } = cds.builtin.classes
|
|
8
|
+
const { any, entity, Association } = cds.builtin.classes
|
|
9
9
|
cds.extend(any).with(require('./common/aspects/any'))
|
|
10
|
+
cds.extend(Association).with(require('./common/aspects/Association'))
|
|
10
11
|
cds.extend(entity).with(require('./common/aspects/entity'))
|
|
11
12
|
|
|
12
13
|
/*
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// global.cds is used on purpose here!
|
|
2
|
+
const cds = global.cds
|
|
3
|
+
|
|
4
|
+
const ODATA_CONTAINED = '@odata.contained'
|
|
5
|
+
|
|
6
|
+
const { isSelfManaged, isBacklink, getAnchor, getBacklink } = require('./utils')
|
|
7
|
+
const { foreignKeyPropagations } = require('../utils/foreignKeyPropagations')
|
|
8
|
+
|
|
9
|
+
module.exports = class {
|
|
10
|
+
get _isAssociationStrict() {
|
|
11
|
+
return (
|
|
12
|
+
this.own('__isAssociationStrict') ||
|
|
13
|
+
this.set('__isAssociationStrict', !!(this.isAssociation && !this.isComposition))
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get _isAssociationEffective() {
|
|
18
|
+
return (
|
|
19
|
+
this.own('__isAssociationEffective') ||
|
|
20
|
+
this.set(
|
|
21
|
+
'__isAssociationEffective',
|
|
22
|
+
this._isAssociationStrict && (!this[ODATA_CONTAINED] || this.name === 'DraftAdministrativeData')
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get _isCompositionEffective() {
|
|
28
|
+
return (
|
|
29
|
+
this.own('__isCompositionEffective') ||
|
|
30
|
+
this.set(
|
|
31
|
+
'__isCompositionEffective',
|
|
32
|
+
this.isComposition ||
|
|
33
|
+
(this._isAssociationStrict && this[ODATA_CONTAINED] && this.name !== 'DraftAdministrativeData')
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get _isContained() {
|
|
39
|
+
return (
|
|
40
|
+
this.own('__isContained') ||
|
|
41
|
+
this.set(
|
|
42
|
+
'__isContained',
|
|
43
|
+
this.name !== 'DraftAdministrativeData_DraftUUID' &&
|
|
44
|
+
((this.isAssociation && this[ODATA_CONTAINED]) || (this.isComposition && cds.env.effective.odata.containment))
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get _isSelfManaged() {
|
|
50
|
+
return this.own('__isSelfManaged') || this.set('__isSelfManaged', isSelfManaged(this))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get _isBacklink() {
|
|
54
|
+
return this.own('__isBacklink') || this.set('__isBacklink', isBacklink(this))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get _isCompositionBacklink() {
|
|
58
|
+
return this.own('__isCompositionBacklink') || this.set('__isCompositionBacklink', isBacklink(this, true))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get _anchor() {
|
|
62
|
+
return this.own('__anchor') || this.set('__anchor', getAnchor(this))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get _backlink() {
|
|
66
|
+
return this.own('__backlink') || this.set('__backlink', getBacklink(this))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get _foreignKeys() {
|
|
70
|
+
return this.own('__foreignKeys') || this.set('__foreignKeys', foreignKeyPropagations(this))
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,54 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
const cds = global.cds
|
|
3
|
-
|
|
4
|
-
const ODATA_CONTAINED = '@odata.contained'
|
|
5
|
-
|
|
6
|
-
const { isMandatory, isReadOnly } = require('./utils')
|
|
1
|
+
const { getRelations, isMandatory, isReadOnly } = require('./utils')
|
|
7
2
|
|
|
3
|
+
// NOTE: Please only add things which are relevant to _any_ type,
|
|
4
|
+
// use specialized types otherwise (entity, Association, ...).
|
|
8
5
|
module.exports = class {
|
|
9
|
-
get _isAssociationStrict() {
|
|
10
|
-
return (
|
|
11
|
-
this.own('__isAssociationStrict') ||
|
|
12
|
-
this.set('__isAssociationStrict', !!(this.isAssociation && !this.isComposition))
|
|
13
|
-
)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
get _isAssociationEffective() {
|
|
17
|
-
return (
|
|
18
|
-
this.own('__isAssociationEffective') ||
|
|
19
|
-
this.set(
|
|
20
|
-
'__isAssociationEffective',
|
|
21
|
-
this._isAssociationStrict && (!this[ODATA_CONTAINED] || this.name === 'DraftAdministrativeData')
|
|
22
|
-
)
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
get _isCompositionEffective() {
|
|
27
|
-
return (
|
|
28
|
-
this.own('__isCompositionEffective') ||
|
|
29
|
-
this.set(
|
|
30
|
-
'__isCompositionEffective',
|
|
31
|
-
this.isComposition ||
|
|
32
|
-
(this._isAssociationStrict && this[ODATA_CONTAINED] && this.name !== 'DraftAdministrativeData')
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
6
|
get _isStructured() {
|
|
38
7
|
return this.own('__isStructured') || this.set('__isStructured', !!this.elements && this.kind !== 'entity')
|
|
39
8
|
}
|
|
40
9
|
|
|
41
|
-
get _isContained() {
|
|
42
|
-
return (
|
|
43
|
-
this.own('__isContained') ||
|
|
44
|
-
this.set(
|
|
45
|
-
'__isContained',
|
|
46
|
-
this.name !== 'DraftAdministrativeData_DraftUUID' &&
|
|
47
|
-
((this.isAssociation && this[ODATA_CONTAINED]) || (this.isComposition && cds.env.effective.odata.containment))
|
|
48
|
-
)
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
10
|
get _isMandatory() {
|
|
53
11
|
return this.own('__isMandatory') || this.set('__isMandatory', !this.isAssociation && isMandatory(this))
|
|
54
12
|
}
|
|
@@ -56,4 +14,9 @@ module.exports = class {
|
|
|
56
14
|
get _isReadOnly() {
|
|
57
15
|
return this.own('__isReadOnly') || this.set('__isReadOnly', !this.key && isReadOnly(this))
|
|
58
16
|
}
|
|
17
|
+
|
|
18
|
+
// REVISIT: Where to put?
|
|
19
|
+
get _relations() {
|
|
20
|
+
return this.own('__relations') || this.set('__relations', getRelations(this))
|
|
21
|
+
}
|
|
59
22
|
}
|
|
@@ -44,7 +44,6 @@ module.exports = class {
|
|
|
44
44
|
// lazily require on first use
|
|
45
45
|
getSearchableColumns =
|
|
46
46
|
getSearchableColumns || require('../../cds-services/services/utils/columns').getSearchableColumns
|
|
47
|
-
|
|
48
47
|
return this.own('__searchableColumns') || this.set('__searchableColumns', getSearchableColumns(this))
|
|
49
48
|
}
|
|
50
49
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const { getOnCond } = require('../utils/generateOnCond')
|
|
2
|
+
|
|
3
|
+
let initializing = false
|
|
4
|
+
|
|
5
|
+
module.exports = class Relation {
|
|
6
|
+
constructor(csn, path = []) {
|
|
7
|
+
if (!initializing) throw new Error(`Do not new a relation, use 'Relation.to()' instead`)
|
|
8
|
+
Object.defineProperty(this, 'csn', { get: () => csn })
|
|
9
|
+
Object.defineProperty(this, 'path', {
|
|
10
|
+
get: () => path,
|
|
11
|
+
set: _ => {
|
|
12
|
+
path = _
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
if (csn.target) Object.defineProperty(this, 'target', { get: () => csn.target })
|
|
16
|
+
initializing = false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static to(from, name) {
|
|
20
|
+
initializing = true
|
|
21
|
+
if (!name) return new Relation(from)
|
|
22
|
+
return from._elements[name] && new Relation(from._elements[name], [...from.path, name])
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_has(prop) {
|
|
26
|
+
return Reflect.has(this, prop) && !this._elements[prop]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get _elements() {
|
|
30
|
+
if (this.csn.elements) return this.csn.elements
|
|
31
|
+
if (this.csn._target && this.csn._target.elements) return this.csn._target.elements
|
|
32
|
+
// if (csn.targetAspect) relation.elements = model.definitions[csn.targetAspect].elements
|
|
33
|
+
// if (csn.kind = 'type') relation.elements = model.definitions[csn.type].element
|
|
34
|
+
return {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
join(fromAlias = '', toAlias = '') {
|
|
38
|
+
return getOnCond(this.csn, this.path, { select: fromAlias, join: toAlias })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const Relation = require('./relation')
|
|
2
|
+
|
|
1
3
|
const CommonFieldControl = e => {
|
|
2
4
|
const cfr = e['@Common.FieldControl']
|
|
3
5
|
return cfr && cfr['#']
|
|
@@ -65,10 +67,80 @@ const hasSensitiveData = entity => {
|
|
|
65
67
|
return val
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
const _exposeRelation = relation => Object.defineProperty({}, '_', { get: () => relation })
|
|
71
|
+
|
|
72
|
+
const _relationHandler = relation => ({
|
|
73
|
+
get: (target, name) => {
|
|
74
|
+
const path = name.split(',')
|
|
75
|
+
const prop = path.join('_')
|
|
76
|
+
if (!target[prop]) {
|
|
77
|
+
if (path.length === 1) {
|
|
78
|
+
// REVISIT: property 'join' must not be used in CSN to make this working
|
|
79
|
+
if (relation._has(prop)) return relation[prop]
|
|
80
|
+
const newRelation = Relation.to(relation, prop)
|
|
81
|
+
if (newRelation) {
|
|
82
|
+
target[prop] = new Proxy(_exposeRelation(newRelation), _relationHandler(newRelation))
|
|
83
|
+
}
|
|
84
|
+
return target[prop]
|
|
85
|
+
}
|
|
86
|
+
target[prop] = path.reduce((r, p) => r[p] || r.csn._relations[p], relation)
|
|
87
|
+
target[prop].path = path
|
|
88
|
+
}
|
|
89
|
+
return target[prop]
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const getRelations = e => {
|
|
94
|
+
const newRelation = Relation.to(e)
|
|
95
|
+
return new Proxy(_exposeRelation(newRelation), _relationHandler(newRelation))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const _hasJoinCondition = e => e.isAssociation && e.on && e.on.length > 2
|
|
99
|
+
|
|
100
|
+
const _isSelfRef = e => e.ref && e.ref[0] === '$self'
|
|
101
|
+
|
|
102
|
+
const _getBacklinkName = on => {
|
|
103
|
+
const i = on.findIndex(_isSelfRef)
|
|
104
|
+
if (i === -1) return
|
|
105
|
+
let ref
|
|
106
|
+
if (on[i + 1] && on[i + 1] === '=') ref = on[i + 2].ref
|
|
107
|
+
if (on[i - 1] && on[i - 1] === '=') ref = on[i - 2].ref
|
|
108
|
+
return ref && ref[ref.length - 1]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const isSelfManaged = e => {
|
|
112
|
+
if (!_hasJoinCondition(e)) return
|
|
113
|
+
return !!e.on.find(_isSelfRef)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const isBacklink = (e, checkComposition) => getAnchor(e, checkComposition) && true
|
|
117
|
+
|
|
118
|
+
const _isUnManagedAssociation = (e, checkComposition) =>
|
|
119
|
+
e.isAssociation && (!checkComposition || e._isCompositionEffective) && _hasJoinCondition(e)
|
|
120
|
+
|
|
121
|
+
const getAnchor = (e, checkComposition) => {
|
|
122
|
+
if (!(e._isAssociationStrict && (e.keys || e.on))) return
|
|
123
|
+
for (const anchor of Object.values(e._target.associations || {})) {
|
|
124
|
+
if (!_isUnManagedAssociation(anchor, checkComposition)) continue
|
|
125
|
+
if (_getBacklinkName(anchor.on) === e.name && anchor.target === e.parent.name) return anchor
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const getBacklink = (e, checkComposition) => {
|
|
130
|
+
if (!_isUnManagedAssociation(e, checkComposition)) return
|
|
131
|
+
const backlinkName = _getBacklinkName(e.on)
|
|
132
|
+
if (backlinkName) return e._target && e._target.elements && e._target.elements[backlinkName]
|
|
133
|
+
}
|
|
134
|
+
|
|
68
135
|
module.exports = {
|
|
69
136
|
isMandatory,
|
|
70
137
|
isReadOnly,
|
|
71
138
|
getETag,
|
|
72
139
|
hasPersonalData,
|
|
73
|
-
hasSensitiveData
|
|
140
|
+
hasSensitiveData,
|
|
141
|
+
getRelations,
|
|
142
|
+
isSelfManaged,
|
|
143
|
+
isBacklink,
|
|
144
|
+
getAnchor,
|
|
145
|
+
getBacklink
|
|
74
146
|
}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
const cds = require('../../../../cds')
|
|
2
2
|
|
|
3
|
-
const _require = require('../../../utils/require')
|
|
4
|
-
|
|
5
3
|
const getCredentials = uaa => {
|
|
6
|
-
uaa =
|
|
4
|
+
uaa =
|
|
5
|
+
uaa && uaa.credentials
|
|
6
|
+
? uaa
|
|
7
|
+
: cds.env.requires.uaa && cds.env.requires.uaa.credentials
|
|
8
|
+
? cds.env.requires.uaa
|
|
9
|
+
: cds.env.requires.xsuaa && cds.env.requires.xsuaa.credentials
|
|
10
|
+
? cds.env.requires.xsuaa
|
|
11
|
+
: {}
|
|
7
12
|
|
|
8
|
-
if (!uaa.credentials)
|
|
9
|
-
|
|
10
|
-
const vcap = cds.env.requires.uaa && cds.env.requires.uaa.vcap
|
|
11
|
-
uaa.credentials = _require('@sap/xsenv').serviceCredentials(vcap || { label: 'xsuaa' })
|
|
12
|
-
} catch (e) {
|
|
13
|
-
const msg =
|
|
14
|
-
'Unable to get xsuaa credentials. Please make sure your app is bound to a single xsuaa service instance or that you provide vcap information in the requires.uaa section.'
|
|
15
|
-
// REVISIT: switch to verror
|
|
16
|
-
throw Object.assign(new Error(msg), { original: e })
|
|
17
|
-
}
|
|
18
|
-
}
|
|
13
|
+
if (!uaa.credentials)
|
|
14
|
+
throw Object.assign(new Error('No or malformed uaa credentials'), { credentials: uaa.credentials })
|
|
19
15
|
|
|
20
16
|
return uaa.credentials
|
|
21
17
|
}
|
|
@@ -4,8 +4,9 @@ const { getEntityNameFromUpdateCQN } = require('../utils/cqn')
|
|
|
4
4
|
|
|
5
5
|
const { ensureNoDraftsSuffix } = require('../utils/draft')
|
|
6
6
|
const { getDBTable } = require('../utils/resolveView')
|
|
7
|
-
const cqn2cqn4sql = require('../utils/cqn2cqn4sql')
|
|
7
|
+
const { cqn2cqn4sql } = require('../utils/cqn2cqn4sql')
|
|
8
8
|
const cds = require('../../cds')
|
|
9
|
+
const { SELECT } = cds.ql
|
|
9
10
|
|
|
10
11
|
/*
|
|
11
12
|
* own utils
|
|
@@ -192,7 +193,7 @@ const _select = ({
|
|
|
192
193
|
}) => {
|
|
193
194
|
const entity = definitions && definitions[entityName]
|
|
194
195
|
const from = ctUtils.addDraftSuffix(draft, entity.name)
|
|
195
|
-
const selectCQN =
|
|
196
|
+
const selectCQN = SELECT.from(from)
|
|
196
197
|
if (alias) selectCQN.SELECT.from.as = alias
|
|
197
198
|
const selectAll = includeAllColumns || (includeAllRootColumns && root)
|
|
198
199
|
selectCQN.SELECT.columns = _columns(entity, data, compositionTree, selectAll)
|
|
@@ -20,8 +20,10 @@ const _recursivelyAliasRefs = (something, newAlias, oldAlias, subselect = false)
|
|
|
20
20
|
if (oldAlias && something.ref[0] === oldAlias) something.ref[0] = newAlias
|
|
21
21
|
else if (!subselect) something.ref.unshift(newAlias)
|
|
22
22
|
} else {
|
|
23
|
-
for (const key in something)
|
|
23
|
+
for (const key in something) {
|
|
24
|
+
if (key === 'from') continue // Workaround: Deep delete to be rewritten
|
|
24
25
|
_recursivelyAliasRefs(something[key], newAlias, oldAlias, subselect || key === 'SELECT')
|
|
26
|
+
}
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
}
|