@sap/cds 5.8.2 → 5.9.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.
- package/CHANGELOG.md +214 -78
- package/app/fiori/preview.js +16 -11
- package/app/fiori/routes.js +3 -0
- package/app/index.js +1 -1
- package/bin/build/buildTaskFactory.js +3 -3
- package/bin/build/buildTaskProviderFactory.js +1 -1
- package/bin/build/constants.js +1 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
- package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +8 -2
- package/bin/build/provider/hana/2migration.js +27 -24
- package/bin/build/provider/hana/index.js +17 -18
- package/bin/build/provider/hana/migrationtable.js +9 -10
- package/bin/build/provider/java-cf/index.js +4 -5
- package/bin/build/provider/node-cf/index.js +99 -6
- package/bin/cds.js +20 -17
- package/bin/deploy/to-hana/cfUtil.js +16 -19
- package/bin/deploy/to-hana/hana.js +7 -24
- package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
- package/bin/mtx/in-cds.js +2 -2
- package/bin/serve.js +12 -5
- package/bin/utils/modules.js +7 -0
- package/bin/version.js +56 -3
- package/lib/compile/cdsc.js +26 -3
- package/lib/compile/etc/_localized.js +36 -25
- package/lib/compile/etc/csv.js +8 -8
- package/lib/compile/for/drafts.js +9 -0
- package/lib/compile/for/java.js +16 -0
- package/lib/compile/for/nodejs.js +12 -0
- package/lib/compile/for/odata.js +1 -1
- package/lib/compile/index.js +3 -0
- package/lib/compile/minify.js +16 -2
- package/lib/compile/parse.js +2 -2
- package/lib/compile/resolve.js +35 -18
- package/lib/compile/to/json.js +3 -1
- package/lib/compile/to/sql.js +2 -2
- package/lib/compile/to/srvinfo.js +4 -2
- package/lib/connect/index.js +1 -1
- package/lib/core/entities.js +15 -14
- package/lib/core/index.js +39 -36
- package/lib/core/reflect.js +4 -2
- package/lib/deploy.js +114 -127
- package/lib/env/defaults.js +1 -0
- package/lib/env/index.js +165 -165
- package/lib/env/presets.js +1 -0
- package/lib/env/requires.js +120 -49
- package/lib/index.js +1 -0
- package/lib/log/format/kibana.js +2 -2
- package/lib/ql/SELECT.js +10 -0
- package/lib/ql/parse.js +1 -0
- package/lib/req/cds-context.js +4 -1
- package/lib/req/context.js +50 -56
- package/lib/req/event.js +1 -6
- package/lib/req/locale.js +6 -5
- package/lib/req/request.js +2 -0
- package/lib/req/user.js +7 -5
- package/lib/serve/Service-api.js +10 -7
- package/lib/serve/Service-dispatch.js +9 -11
- package/lib/serve/Service-methods.js +30 -41
- package/lib/serve/Transaction.js +10 -7
- package/lib/serve/adapters.js +7 -5
- package/lib/serve/index.js +24 -12
- package/lib/utils/data.js +1 -1
- package/lib/utils/index.js +27 -30
- package/lib/utils/resources/index.js +101 -0
- package/lib/utils/resources/tar.js +71 -0
- package/lib/utils/resources/utils.js +11 -0
- package/libx/_runtime/audit/Service.js +36 -39
- package/libx/_runtime/audit/generic/personal/access.js +3 -4
- package/libx/_runtime/audit/generic/personal/modification.js +3 -4
- package/libx/_runtime/audit/utils/v2.js +1 -2
- package/libx/_runtime/auth/index.js +126 -84
- package/libx/_runtime/auth/strategies/JWT.js +12 -19
- package/libx/_runtime/auth/strategies/dummy.js +1 -5
- package/libx/_runtime/auth/strategies/dwc.js +11 -9
- package/libx/_runtime/auth/strategies/mock.js +0 -4
- package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
- package/libx/_runtime/auth/utils.js +22 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +13 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +50 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
- package/libx/_runtime/cds-services/services/Service.js +40 -0
- package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
- package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
- package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
- package/libx/_runtime/cds-services/util/assert.js +20 -14
- package/libx/_runtime/cds.js +9 -1
- package/libx/_runtime/common/aspects/any.js +5 -0
- package/libx/_runtime/common/aspects/entity.js +25 -7
- package/libx/_runtime/common/aspects/utils.js +2 -2
- package/libx/_runtime/common/composition/data.js +6 -0
- package/libx/_runtime/common/composition/insert.js +3 -2
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +4 -4
- package/libx/_runtime/common/constants/draft.js +29 -26
- package/libx/_runtime/common/error/constants.js +2 -2
- package/libx/_runtime/common/error/frontend.js +7 -15
- package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
- package/libx/_runtime/common/generic/auth/constants.js +20 -0
- package/libx/_runtime/common/generic/auth/expand.js +54 -0
- package/libx/_runtime/common/generic/auth/index.js +32 -0
- package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
- package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
- package/libx/_runtime/common/generic/auth/requires.js +34 -0
- package/libx/_runtime/common/generic/auth/restrict.js +296 -0
- package/libx/_runtime/common/generic/auth/utils.js +213 -0
- package/libx/_runtime/common/generic/crud.js +14 -10
- package/libx/_runtime/common/generic/etag.js +1 -1
- package/libx/_runtime/common/generic/input.js +35 -35
- package/libx/_runtime/common/generic/sorting.js +2 -3
- package/libx/_runtime/common/generic/temporal.js +2 -2
- package/libx/_runtime/common/i18n/index.js +2 -31
- package/libx/_runtime/common/i18n/messages.properties +1 -1
- package/libx/_runtime/common/toggles/handler.js +21 -0
- package/libx/_runtime/common/utils/copy.js +10 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
- package/libx/_runtime/common/utils/csn.js +63 -1
- package/libx/_runtime/common/utils/dollar.js +10 -1
- package/libx/_runtime/common/utils/draft.js +46 -7
- package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
- package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
- package/libx/_runtime/common/utils/generateOnCond.js +9 -6
- package/libx/_runtime/common/utils/quotingStyles.js +2 -0
- package/libx/_runtime/common/utils/resolveStructured.js +25 -9
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
- package/libx/_runtime/common/utils/structured.js +33 -37
- package/libx/_runtime/common/utils/template.js +17 -8
- package/libx/_runtime/common/utils/templateProcessor.js +28 -28
- package/libx/_runtime/db/data-conversion/post-processing.js +118 -417
- package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
- package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
- package/libx/_runtime/db/generic/index.js +1 -3
- package/libx/_runtime/db/generic/input.js +5 -10
- package/libx/_runtime/db/generic/rewrite.js +5 -2
- package/libx/_runtime/db/generic/structured.js +2 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +1 -1
- package/libx/_runtime/db/query/update.js +9 -14
- package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
- package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
- package/libx/_runtime/db/utils/columns.js +3 -3
- package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
- package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
- package/libx/_runtime/extensibility/mps/index.js +5 -0
- package/libx/_runtime/extensibility/mps/service.js +111 -0
- package/libx/_runtime/extensibility/mps/tar.js +42 -0
- package/libx/_runtime/extensibility/mps/utils.js +11 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
- package/libx/_runtime/extensibility/uiflex/index.js +54 -0
- package/libx/_runtime/extensibility/uiflex/service.js +276 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +4 -4
- package/libx/_runtime/fiori/generic/new.js +3 -3
- package/libx/_runtime/fiori/generic/patch.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +58 -66
- package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
- package/libx/_runtime/fiori/utils/handler.js +6 -13
- package/libx/_runtime/fiori/utils/where.js +6 -5
- package/libx/_runtime/hana/Service.js +4 -10
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +2 -2
- package/libx/_runtime/hana/driver.js +2 -2
- package/libx/_runtime/hana/execute.js +29 -75
- package/libx/_runtime/hana/pool.js +1 -1
- package/libx/_runtime/hana/streaming.js +2 -1
- package/libx/_runtime/index.js +6 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
- package/libx/_runtime/messaging/Outbox.js +2 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
- package/libx/_runtime/messaging/common-utils/connections.js +5 -7
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
- package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
- package/libx/_runtime/messaging/file-based.js +5 -5
- package/libx/_runtime/messaging/message-queuing.js +14 -12
- package/libx/_runtime/messaging/outbox/utils.js +18 -19
- package/libx/_runtime/messaging/redis-messaging.js +91 -0
- package/libx/_runtime/messaging/service.js +8 -6
- package/libx/_runtime/remote/Service.js +44 -8
- package/libx/_runtime/remote/utils/client.js +25 -13
- package/libx/_runtime/remote/utils/data.js +11 -11
- package/libx/_runtime/sqlite/Service.js +6 -9
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
- package/libx/_runtime/types/api.js +10 -2
- package/libx/common/utils/ucsn.js +109 -0
- package/libx/gql/resolvers/crud/create.js +6 -1
- package/libx/gql/resolvers/crud/delete.js +6 -1
- package/libx/gql/resolvers/crud/read.js +6 -1
- package/libx/gql/resolvers/crud/update.js +9 -1
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
- package/libx/gql/schema/typeDefMap.js +2 -2
- package/libx/odata/afterburner.js +110 -16
- package/libx/odata/grammar.pegjs +9 -1
- package/libx/odata/parseToCqn.js +39 -0
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +9 -1
- package/libx/rest/middleware/input.js +54 -0
- package/libx/rest/middleware/operation.js +14 -1
- package/libx/rest/middleware/parse.js +11 -7
- package/package.json +1 -1
- package/server.js +34 -19
- package/srv/audit-log.cds +2 -2
- package/srv/flex.cds +8 -2
- package/srv/flex.js +1 -1
- package/srv/mps.cds +23 -0
- package/srv/mps.js +1 -0
- package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
- package/libx/_runtime/common/generic/auth.js +0 -874
- package/libx/_runtime/common/toggles/alpha.js +0 -43
- package/libx/_runtime/db/generic/arrayed.js +0 -33
- package/libx/_runtime/fiori/uiflex/index.js +0 -35
- package/libx/_runtime/fiori/uiflex/service.js +0 -150
- package/libx/rest/utils/data.js +0 -60
|
@@ -8,7 +8,7 @@ const { ensureNoDraftsSuffix, ensureDraftsSuffix, ensureUnlocalized } = require(
|
|
|
8
8
|
const { isAsteriskColumn } = require('../../common/utils/rewriteAsterisks')
|
|
9
9
|
const { getCQNUnionFrom } = require('../../common/utils/union')
|
|
10
10
|
|
|
11
|
-
const {
|
|
11
|
+
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
12
12
|
|
|
13
13
|
const { filterKeys } = require('../../fiori/utils/handler')
|
|
14
14
|
|
|
@@ -20,6 +20,7 @@ const SKIP_MAPPING = Symbol.for('sap.cds.skipMapping')
|
|
|
20
20
|
const IDENTIFIER = Symbol.for('sap.cds.identifier')
|
|
21
21
|
const IS_ACTIVE = Symbol.for('sap.cds.isActive')
|
|
22
22
|
const IS_UNION_DRAFT = Symbol.for('sap.cds.isUnionDraft')
|
|
23
|
+
const CLEANUP_KEYS = Symbol.for('sap.cds.cleanupKeys')
|
|
23
24
|
|
|
24
25
|
function getCqnCopy(readToOneCQN) {
|
|
25
26
|
// REVISIT: Use query.clone() instead
|
|
@@ -31,6 +32,7 @@ function getCqnCopy(readToOneCQN) {
|
|
|
31
32
|
if (readToOneCQN[IDENTIFIER] !== undefined) readToOneCQNCopy[IDENTIFIER] = readToOneCQN[IDENTIFIER]
|
|
32
33
|
if (readToOneCQN[IS_ACTIVE] !== undefined) readToOneCQNCopy[IS_ACTIVE] = readToOneCQN[IS_ACTIVE]
|
|
33
34
|
if (readToOneCQN[IS_UNION_DRAFT] !== undefined) readToOneCQNCopy[IS_UNION_DRAFT] = readToOneCQN[IS_UNION_DRAFT]
|
|
35
|
+
if (readToOneCQN[CLEANUP_KEYS] !== undefined) readToOneCQNCopy[CLEANUP_KEYS] = readToOneCQN[CLEANUP_KEYS]
|
|
34
36
|
return readToOneCQNCopy
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -533,7 +535,6 @@ class JoinCQNFromExpanded {
|
|
|
533
535
|
}
|
|
534
536
|
}
|
|
535
537
|
}
|
|
536
|
-
|
|
537
538
|
// only as second step handle expand to many, or else keys might still be unknown
|
|
538
539
|
this._toMany({
|
|
539
540
|
entity,
|
|
@@ -611,11 +612,7 @@ class JoinCQNFromExpanded {
|
|
|
611
612
|
}
|
|
612
613
|
|
|
613
614
|
_isNavigationToOne(activeTable, target) {
|
|
614
|
-
return (
|
|
615
|
-
target &&
|
|
616
|
-
((activeTable && target.type === 'cds.Composition') || target.type === 'cds.Association') &&
|
|
617
|
-
target.is2one
|
|
618
|
-
)
|
|
615
|
+
return target && ((activeTable && target.isComposition) || target._isAssociationStrict) && target.is2one
|
|
619
616
|
}
|
|
620
617
|
|
|
621
618
|
_getTarget(entity, column, parentAlias) {
|
|
@@ -649,7 +646,7 @@ class JoinCQNFromExpanded {
|
|
|
649
646
|
const activeTableRequired =
|
|
650
647
|
readToOneCQN[IS_UNION_DRAFT] || // > REVISIT: blocks expanding comp2one
|
|
651
648
|
readToOneCQN[IS_ACTIVE] ||
|
|
652
|
-
(element && element.
|
|
649
|
+
(element && element._isAssociationStrict && !element['@odata.draft.enclosed']) ||
|
|
653
650
|
!this._csn.definitions[target]._isDraftEnabled
|
|
654
651
|
|
|
655
652
|
const colTarget = target && ensureUnlocalized(target)
|
|
@@ -677,9 +674,9 @@ class JoinCQNFromExpanded {
|
|
|
677
674
|
|
|
678
675
|
const expandedEntity = this._getEntityForTable(target)
|
|
679
676
|
if (readToOneCQN[IS_UNION_DRAFT] && expandedEntity.drafts) {
|
|
680
|
-
const cols = column.expand.filter(c => !c.expand && !
|
|
677
|
+
const cols = column.expand.filter(c => !c.expand && !(c.ref[0] in DRAFT_COLUMNS_MAP)).map(c => c.ref[0])
|
|
681
678
|
const ks = Object.keys(expandedEntity.keys).filter(
|
|
682
|
-
c => !expandedEntity.keys[c].isAssociation && !
|
|
679
|
+
c => !expandedEntity.keys[c].isAssociation && !(c in DRAFT_COLUMNS_MAP)
|
|
683
680
|
)
|
|
684
681
|
const user = (cds.context && cds.context.user && cds.context.user.id) || 'anonymous'
|
|
685
682
|
const unionFrom = getCQNUnionFrom(cols, expandedEntity.name, expandedEntity.name + '.drafts', ks, user)
|
|
@@ -746,8 +743,19 @@ class JoinCQNFromExpanded {
|
|
|
746
743
|
return col
|
|
747
744
|
})
|
|
748
745
|
|
|
746
|
+
const targetEntity = this._getEntityForTable(target)
|
|
747
|
+
if (
|
|
748
|
+
'IsActiveEntity' in targetEntity.elements &&
|
|
749
|
+
this._isNotIncludedIn(givenColumns)('IsActiveEntity') &&
|
|
750
|
+
typeof activeTableRequired === 'boolean'
|
|
751
|
+
) {
|
|
752
|
+
const col = this._createCalculatedBooleanColumn('IsActiveEntity', activeTableRequired)
|
|
753
|
+
col[CLEANUP_KEYS] = true
|
|
754
|
+
givenColumns.push(col)
|
|
755
|
+
}
|
|
756
|
+
|
|
749
757
|
this._expandedToFlat({
|
|
750
|
-
entity:
|
|
758
|
+
entity: targetEntity,
|
|
751
759
|
givenColumns,
|
|
752
760
|
readToOneCQN,
|
|
753
761
|
tableAlias,
|
|
@@ -959,6 +967,12 @@ class JoinCQNFromExpanded {
|
|
|
959
967
|
|
|
960
968
|
if (!column[SKIP_MAPPING]) {
|
|
961
969
|
mappings[column[IDENTIFIER] || identifier] = as
|
|
970
|
+
// REVISIT: remove flag cds.env.features.auto_fetch_expand_keys after two month grace period
|
|
971
|
+
if (column[CLEANUP_KEYS] && !cds.env.features.auto_fetch_expand_keys) {
|
|
972
|
+
delete aliasedElement[CLEANUP_KEYS]
|
|
973
|
+
if (!mappings[CLEANUP_KEYS]) mappings[CLEANUP_KEYS] = {}
|
|
974
|
+
mappings[CLEANUP_KEYS][column[IDENTIFIER] || identifier] = as
|
|
975
|
+
}
|
|
962
976
|
}
|
|
963
977
|
|
|
964
978
|
return aliasedElement
|
|
@@ -983,7 +997,7 @@ class JoinCQNFromExpanded {
|
|
|
983
997
|
if (splitted.length > 1 && entity.elements[splitted[0]]) return true
|
|
984
998
|
|
|
985
999
|
// Draft column
|
|
986
|
-
return
|
|
1000
|
+
return ref[0] in DRAFT_COLUMNS_MAP
|
|
987
1001
|
}
|
|
988
1002
|
|
|
989
1003
|
_toMany({
|
|
@@ -1031,12 +1045,14 @@ class JoinCQNFromExpanded {
|
|
|
1031
1045
|
readToOneCQN.columns.push({
|
|
1032
1046
|
val: readToOneCQN[IS_ACTIVE],
|
|
1033
1047
|
as: 'IsActiveEntity',
|
|
1034
|
-
cast: { type: 'cds.Boolean' }
|
|
1048
|
+
cast: { type: 'cds.Boolean' },
|
|
1049
|
+
[CLEANUP_KEYS]: true
|
|
1035
1050
|
})
|
|
1036
1051
|
} else {
|
|
1037
1052
|
readToOneCQN.columns.push({
|
|
1038
1053
|
as: `${tableAlias}_${name}`,
|
|
1039
|
-
ref: [tableAlias, name]
|
|
1054
|
+
ref: [tableAlias, name],
|
|
1055
|
+
[CLEANUP_KEYS]: true
|
|
1040
1056
|
})
|
|
1041
1057
|
}
|
|
1042
1058
|
}
|
|
@@ -1092,7 +1108,7 @@ class JoinCQNFromExpanded {
|
|
|
1092
1108
|
|
|
1093
1109
|
const expandActive =
|
|
1094
1110
|
readToOneCQN[IS_ACTIVE] ||
|
|
1095
|
-
(element.
|
|
1111
|
+
(element._isAssociationStrict && !element['@odata.draft.enclosed']) ||
|
|
1096
1112
|
!this._csn.definitions[colTarget]._isDraftEnabled
|
|
1097
1113
|
const ref = this._getJoinRef(entity.elements, colRef[0], expandActive, defaultLanguageThis)
|
|
1098
1114
|
const tableAlias = this._createAlias(toManyTree.concat(colRef).join(':'))
|
|
@@ -1135,7 +1151,7 @@ class JoinCQNFromExpanded {
|
|
|
1135
1151
|
cqn = this._adaptWhereOrderBy(cqn, tableAlias)
|
|
1136
1152
|
|
|
1137
1153
|
if (isUnion) {
|
|
1138
|
-
const cols = column.expand.filter(c => !c.expand && !
|
|
1154
|
+
const cols = column.expand.filter(c => !c.expand && !(c.ref[0] in DRAFT_COLUMNS_MAP)).map(c => c.ref[0])
|
|
1139
1155
|
// ensure the join columns are selected
|
|
1140
1156
|
for (const each of joinColumns) {
|
|
1141
1157
|
const col = each.ref[each.ref.length - 1]
|
|
@@ -1146,7 +1162,7 @@ class JoinCQNFromExpanded {
|
|
|
1146
1162
|
if (each.expand) {
|
|
1147
1163
|
const assoc = expandedEntity.associations[each.ref[0]]
|
|
1148
1164
|
if (assoc.is2one) {
|
|
1149
|
-
const fks = Object.values(expandedEntity.elements).filter(ele => ele
|
|
1165
|
+
const fks = Object.values(expandedEntity.elements).filter(ele => ele._foreignKey4 === assoc.name)
|
|
1150
1166
|
cols.push(...fks.map(fk => fk.name))
|
|
1151
1167
|
}
|
|
1152
1168
|
}
|
|
@@ -1154,7 +1170,7 @@ class JoinCQNFromExpanded {
|
|
|
1154
1170
|
|
|
1155
1171
|
if (!cqn[IS_ACTIVE]) {
|
|
1156
1172
|
const ks = Object.keys(expandedEntity.keys).filter(
|
|
1157
|
-
c => !expandedEntity.keys[c].isAssociation && !
|
|
1173
|
+
c => !expandedEntity.keys[c].isAssociation && !(c in DRAFT_COLUMNS_MAP)
|
|
1158
1174
|
)
|
|
1159
1175
|
const user = (cds.context && cds.context.user && cds.context.user.id) || 'anonymous'
|
|
1160
1176
|
const unionFrom = getCQNUnionFrom(cols, ref.replace(/_drafts$/, ''), ref, ks, user)
|
|
@@ -1189,30 +1205,12 @@ class JoinCQNFromExpanded {
|
|
|
1189
1205
|
|
|
1190
1206
|
_getJoinRef(elements, column, isActive, defaultLanguage) {
|
|
1191
1207
|
const assoc = elements[column]
|
|
1192
|
-
if (typeof isActive !== 'boolean' || isActive || assoc.
|
|
1208
|
+
if (typeof isActive !== 'boolean' || isActive || !assoc.isComposition) {
|
|
1193
1209
|
return defaultLanguage ? ensureUnlocalized(assoc.target) : assoc.target
|
|
1194
1210
|
}
|
|
1195
1211
|
return assoc.target + '_drafts'
|
|
1196
1212
|
}
|
|
1197
1213
|
|
|
1198
|
-
/**
|
|
1199
|
-
* Get the list of key columns in ref format.
|
|
1200
|
-
* Add the table alias to avoid ambiguity issues.
|
|
1201
|
-
*
|
|
1202
|
-
* @param tableAlias
|
|
1203
|
-
* @param isActive
|
|
1204
|
-
* @param expandedEntity
|
|
1205
|
-
* @returns {Array}
|
|
1206
|
-
* @private
|
|
1207
|
-
*/
|
|
1208
|
-
_getKeyColumnForTarget(tableAlias, isActive, expandedEntity) {
|
|
1209
|
-
return getAllKeys(expandedEntity)
|
|
1210
|
-
.filter(column => typeof isActive !== 'boolean' || column !== 'IsActiveEntity')
|
|
1211
|
-
.map(column => {
|
|
1212
|
-
return { ref: [tableAlias, column] }
|
|
1213
|
-
})
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
1214
|
_getLimitInSelect(cqn, columns, limit, orderBy, expandedEntity) {
|
|
1217
1215
|
const select = {
|
|
1218
1216
|
SELECT: {
|
|
@@ -1391,7 +1389,10 @@ class JoinCQNFromExpanded {
|
|
|
1391
1389
|
value = entry[`${parentAlias}_${key}`] || entry[`${parentAlias}_${key}`.toUpperCase()]
|
|
1392
1390
|
}
|
|
1393
1391
|
|
|
1394
|
-
if (
|
|
1392
|
+
if (
|
|
1393
|
+
value === undefined &&
|
|
1394
|
+
((cds.env.effective.odata && cds.env.effective.odata.structs) || cds.env.features.ucsn_struct_conversion)
|
|
1395
|
+
) {
|
|
1395
1396
|
// here, it should be a structured key
|
|
1396
1397
|
const keys = Object.keys(entry).filter(k => k.startsWith(key + '_'))
|
|
1397
1398
|
if (keys.length) {
|
|
@@ -1572,7 +1573,7 @@ class JoinCQNFromExpanded {
|
|
|
1572
1573
|
return entry =>
|
|
1573
1574
|
!columns.some(
|
|
1574
1575
|
column =>
|
|
1575
|
-
(typeof column === 'object' && column.ref && column.ref[1] === entry) ||
|
|
1576
|
+
(typeof column === 'object' && column.ref && column.ref[column.ref.length - 1] === entry) ||
|
|
1576
1577
|
('val' in column && column.as === entry)
|
|
1577
1578
|
)
|
|
1578
1579
|
}
|
|
@@ -1605,12 +1606,15 @@ class JoinCQNFromExpanded {
|
|
|
1605
1606
|
_addMissingKeyColumns(columns, tableAlias, keys, isActive, entity) {
|
|
1606
1607
|
for (const key of keys.filter(this._isNotIncludedIn(columns))) {
|
|
1607
1608
|
if (key === 'IsActiveEntity' && typeof isActive === 'boolean') {
|
|
1608
|
-
|
|
1609
|
+
const col = this._createCalculatedBooleanColumn(key, isActive)
|
|
1610
|
+
col[CLEANUP_KEYS] = true
|
|
1611
|
+
columns.push(col)
|
|
1609
1612
|
} else if (!entity.elements[key].elements) {
|
|
1610
1613
|
// > don't add if complex key
|
|
1611
1614
|
columns.push({
|
|
1612
1615
|
ref: [tableAlias, key],
|
|
1613
|
-
as: `${tableAlias}_${key}
|
|
1616
|
+
as: `${tableAlias}_${key}`,
|
|
1617
|
+
[CLEANUP_KEYS]: true
|
|
1614
1618
|
})
|
|
1615
1619
|
}
|
|
1616
1620
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
2
|
+
const DRAFT_COLUMNS_ARRAY = Object.keys(DRAFT_COLUMNS_MAP)
|
|
3
|
+
|
|
1
4
|
const EXPAND = Symbol.for('sap.cds.expand')
|
|
2
5
|
const GET_KEY_VALUE = Symbol.for('sap.cds.getKeyValue')
|
|
3
6
|
const TO_MANY = Symbol.for('sap.cds.toMany')
|
|
4
7
|
const TO_ACTIVE = Symbol.for('sap.cds.toActive')
|
|
5
|
-
const
|
|
8
|
+
const CLEANUP_KEYS = Symbol.for('sap.cds.cleanupKeys')
|
|
6
9
|
|
|
7
10
|
class RawToExpanded {
|
|
8
11
|
constructor(configs, queries, one, rootEntity) {
|
|
@@ -22,8 +25,13 @@ class RawToExpanded {
|
|
|
22
25
|
async toExpanded() {
|
|
23
26
|
const { queries, mappings } = this._configs
|
|
24
27
|
|
|
28
|
+
const conversionMapper = new Map()
|
|
29
|
+
for (const each of queries) {
|
|
30
|
+
if (each._conversionMapper) for (const [k, v] of [...each._conversionMapper]) conversionMapper.set(k, v)
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
for (let i = 0, length = this._queries.length; i < length; i++) {
|
|
26
|
-
const {
|
|
34
|
+
const { _toManyTree: toManyTree = [] } = queries[i]
|
|
27
35
|
const result = await this._queries[i]
|
|
28
36
|
if (toManyTree.length === 0) {
|
|
29
37
|
this._parseMainResult(result, mappings, conversionMapper, toManyTree)
|
|
@@ -39,6 +47,10 @@ class RawToExpanded {
|
|
|
39
47
|
for (const entry of result) {
|
|
40
48
|
const parsed = this._parseRaw({ mappings, toManyTree, conversionMapper, entry })
|
|
41
49
|
|
|
50
|
+
if (mappings[CLEANUP_KEYS]) {
|
|
51
|
+
for (const key of Object.keys(mappings[CLEANUP_KEYS])) delete parsed[key]
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
if (parsed) {
|
|
43
55
|
this._result.push(parsed)
|
|
44
56
|
}
|
|
@@ -50,7 +62,7 @@ class RawToExpanded {
|
|
|
50
62
|
const el = mapping[key]
|
|
51
63
|
// if we expand automatically in groupby we have no other columns than objects
|
|
52
64
|
if (typeof el !== 'string') return false
|
|
53
|
-
if (result[el] !== null && !
|
|
65
|
+
if (result[el] !== null && !DRAFT_COLUMNS_ARRAY.some(col => el.endsWith(`_${col}`))) {
|
|
54
66
|
return false
|
|
55
67
|
}
|
|
56
68
|
}
|
|
@@ -99,7 +111,12 @@ class RawToExpanded {
|
|
|
99
111
|
else expandedItems = expandedItems.filter(ele => ele.IsActiveEntity === rootIsActiveEntity)
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
row[key] =
|
|
114
|
+
row[key] = !mapping[CLEANUP_KEYS]
|
|
115
|
+
? expandedItems
|
|
116
|
+
: expandedItems.map(item => {
|
|
117
|
+
for (const key of Object.keys(mapping[CLEANUP_KEYS])) delete item[key]
|
|
118
|
+
return item
|
|
119
|
+
})
|
|
103
120
|
} else if (typeof mapping === 'object') {
|
|
104
121
|
// > Will be true in case of 1:1 expands
|
|
105
122
|
// check if the expanded entry doesn't exists
|
|
@@ -122,11 +139,14 @@ class RawToExpanded {
|
|
|
122
139
|
else if (rootIsActiveEntity) row[key] = parsed && parsed.IsActiveEntity !== false ? parsed : null
|
|
123
140
|
else row[key] = parsed && parsed.IsActiveEntity === rootIsActiveEntity ? parsed : null
|
|
124
141
|
}
|
|
142
|
+
if (mapping[CLEANUP_KEYS]) {
|
|
143
|
+
for (const key in mapping[CLEANUP_KEYS]) delete parsed[key]
|
|
144
|
+
}
|
|
125
145
|
} else {
|
|
126
146
|
// > No expand convert the result directly.
|
|
127
147
|
const rawValue = entry[mapping]
|
|
128
148
|
// Assume a DB will not return undefined, but always null
|
|
129
|
-
|
|
149
|
+
this._convertValue(rawValue, conversionMapper.get(mapping), mapping, row, key)
|
|
130
150
|
|
|
131
151
|
isEntityNull = this._isNull(isEntityNull, rawValue)
|
|
132
152
|
}
|
|
@@ -164,12 +184,13 @@ class RawToExpanded {
|
|
|
164
184
|
* @returns {*}
|
|
165
185
|
* @private
|
|
166
186
|
*/
|
|
167
|
-
_convertValue(value, converter) {
|
|
187
|
+
_convertValue(value, converter, key, row, unaliasedKey) {
|
|
168
188
|
if (converter) {
|
|
169
|
-
|
|
189
|
+
converter(value, key, row, unaliasedKey)
|
|
190
|
+
return
|
|
170
191
|
}
|
|
171
192
|
|
|
172
|
-
|
|
193
|
+
row[unaliasedKey || key] = value
|
|
173
194
|
}
|
|
174
195
|
|
|
175
196
|
_parseExpandResult(result, mappings, conversionMapper, toManyTree) {
|
|
@@ -10,7 +10,6 @@ const UPDATE = require('./update')
|
|
|
10
10
|
const DELETE = require('./delete')
|
|
11
11
|
// after
|
|
12
12
|
const structured = require('./structured')
|
|
13
|
-
const arrayed = require('./arrayed')
|
|
14
13
|
|
|
15
14
|
/*
|
|
16
15
|
* this module is required by cds-pg. -> in case of incompatible changes, we should let them know.
|
|
@@ -24,6 +23,5 @@ module.exports = {
|
|
|
24
23
|
READ,
|
|
25
24
|
UPDATE,
|
|
26
25
|
DELETE,
|
|
27
|
-
structured
|
|
28
|
-
arrayed
|
|
26
|
+
structured
|
|
29
27
|
}
|
|
@@ -25,7 +25,7 @@ const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
|
25
25
|
const _isManaged = (category, event) =>
|
|
26
26
|
(category === '@cds.on.insert' && event === 'CREATE') || (category === '@cds.on.update' && event === 'UPDATE')
|
|
27
27
|
|
|
28
|
-
const _shouldGenerateUUID = element => element.key && !DRAFT_COLUMNS_MAP[element.name] && element.
|
|
28
|
+
const _shouldGenerateUUID = element => element.key && !DRAFT_COLUMNS_MAP[element.name] && element.isUUID
|
|
29
29
|
|
|
30
30
|
const _processComplexCategory = ({ row, key, val, category, req, element }) => {
|
|
31
31
|
const categoryArgs = category.args
|
|
@@ -55,7 +55,7 @@ const _processComplexCategory = ({ row, key, val, category, req, element }) => {
|
|
|
55
55
|
if ('val' in dfault) row[key] = dfault.val
|
|
56
56
|
else if ('ref' in dfault && dfault.ref[0] === '$now') {
|
|
57
57
|
row[key] =
|
|
58
|
-
categoryArgs.
|
|
58
|
+
categoryArgs._type === 'cds.DateTime'
|
|
59
59
|
? new Date(req.timestamp).toISOString().replace(/\.\d\d\d/, '')
|
|
60
60
|
: req.timestamp
|
|
61
61
|
}
|
|
@@ -80,9 +80,9 @@ const _processCategory = ({ category, row, key, element, val, req }) => {
|
|
|
80
80
|
|
|
81
81
|
for (const keyName in element._target.keys) {
|
|
82
82
|
const k = element._target.keys[keyName]
|
|
83
|
-
if (k.
|
|
83
|
+
if (k.isAssociation || k.name === 'IsActiveEntity') continue
|
|
84
84
|
|
|
85
|
-
if (k.
|
|
85
|
+
if (!k.isUUID && !(k.name in val)) {
|
|
86
86
|
req.error(400, 'ASSERT_NOT_NULL', key + '[' + k + ']', [key + '[' + k + ']'])
|
|
87
87
|
return
|
|
88
88
|
}
|
|
@@ -139,12 +139,7 @@ const _pickCRUD = element => {
|
|
|
139
139
|
return { categories } // > no need to continue
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
if (
|
|
143
|
-
element.notNull &&
|
|
144
|
-
element['@assert.notNull'] !== false &&
|
|
145
|
-
!element.default &&
|
|
146
|
-
element.type !== 'cds.Association'
|
|
147
|
-
) {
|
|
142
|
+
if (element.notNull && element['@assert.notNull'] !== false && !element.default && !element._isAssociationStrict) {
|
|
148
143
|
categories.push('!default')
|
|
149
144
|
}
|
|
150
145
|
|
|
@@ -12,8 +12,11 @@ const _isLinked = req => {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function handler(req) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
if (typeof req.query === 'string') return
|
|
16
|
+
|
|
17
|
+
if (!this.model) {
|
|
18
|
+
// best-effort rewrite of path in from
|
|
19
|
+
req.query = cqn2cqn4sql(req.query, { definitions: {} }, { service: this })
|
|
17
20
|
return
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -73,14 +73,14 @@ const _flatToStructured = (structuredType, data, prefixes = [], subData = data)
|
|
|
73
73
|
* @returns {Promise}
|
|
74
74
|
*/
|
|
75
75
|
module.exports = function (result, req) {
|
|
76
|
+
// REVISIT if result has a property length that is 0 we will return here
|
|
76
77
|
if (!this.model || result == null || result.length === 0) return
|
|
77
78
|
|
|
78
|
-
if (!Array.isArray(result)) result = [result]
|
|
79
|
-
|
|
80
79
|
// REVISIT: No entity for sets/unions outside of common draft scenarios
|
|
81
80
|
const entity = getEntityFromCQN(req, this)
|
|
82
81
|
if (!entity) return
|
|
83
82
|
|
|
83
|
+
if (!Array.isArray(result)) result = [result]
|
|
84
84
|
const structuredTypes = _getStructuredTypes(entity)
|
|
85
85
|
for (let i = 0; i < result.length; i++) {
|
|
86
86
|
const d = result[i]
|
|
@@ -7,7 +7,7 @@ const deleteFn = (executeDeleteCQN, executeUpdateCQN) => async (model, dbc, quer
|
|
|
7
7
|
const isoTs = timestampToISO(timestamp)
|
|
8
8
|
|
|
9
9
|
let result
|
|
10
|
-
if (hasDeepDelete(model, query)) {
|
|
10
|
+
if (model && hasDeepDelete(model, query)) {
|
|
11
11
|
let cqns = await getDeepDeleteCQNs(model, req)
|
|
12
12
|
|
|
13
13
|
// the delete chunks, i.e., how many deletes can be processed in parallel
|
|
@@ -25,7 +25,7 @@ const deleteFn = (executeDeleteCQN, executeUpdateCQN) => async (model, dbc, quer
|
|
|
25
25
|
result = results[results.length - 1]
|
|
26
26
|
} else {
|
|
27
27
|
result = await executeDeleteCQN(model, dbc, query, user, locale, isoTs)
|
|
28
|
-
if (result) {
|
|
28
|
+
if (result && model) {
|
|
29
29
|
const updateCQNs = await getSetNullParentForeignKeyCQNs(model, req)
|
|
30
30
|
for (const cqn of updateCQNs) {
|
|
31
31
|
await executeUpdateCQN(model, dbc, cqn, user, locale, isoTs)
|
|
@@ -6,7 +6,7 @@ const insert = executeInsertCQN => async (model, dbc, query, req) => {
|
|
|
6
6
|
const { user, locale, timestamp } = req
|
|
7
7
|
const isoTs = timestampToISO(timestamp)
|
|
8
8
|
|
|
9
|
-
if (hasDeepInsert(model, query)) {
|
|
9
|
+
if (model && hasDeepInsert(model, query)) {
|
|
10
10
|
const cqns = getFlatArray(getDeepInsertCQNs(model, query))
|
|
11
11
|
|
|
12
12
|
// return array of individual results
|
|
@@ -12,7 +12,8 @@ const _includesCompositionTarget = (cqns, target) => {
|
|
|
12
12
|
|
|
13
13
|
const _getFilteredCqns = (cqns, model) => {
|
|
14
14
|
// right to left processing necessary!
|
|
15
|
-
|
|
15
|
+
// no need to process first (= root)
|
|
16
|
+
for (let i = cqns.length - 1; i > 0; i--) {
|
|
16
17
|
const cqn = cqns[i]
|
|
17
18
|
|
|
18
19
|
const entity = model && cqn.UPDATE && model.definitions[cqn.UPDATE.entity]
|
|
@@ -26,21 +27,15 @@ const _getFilteredCqns = (cqns, model) => {
|
|
|
26
27
|
let moreThanManaged = Object.keys(cqn.UPDATE.data).some(
|
|
27
28
|
k => entity.elements[k]['@cds.on.update'] === undefined || !cqn.UPDATE.data[k].startsWith('$')
|
|
28
29
|
)
|
|
29
|
-
|
|
30
30
|
if (moreThanManaged) continue
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (_includesCompositionTarget(cqns, comp.target)) {
|
|
38
|
-
moreThanManaged = true
|
|
39
|
-
break
|
|
40
|
-
}
|
|
32
|
+
const comps = Object.values(entity.associations || {}).filter(assoc => assoc._isCompositionEffective)
|
|
33
|
+
for (const comp of comps) {
|
|
34
|
+
if (_includesCompositionTarget(cqns, comp.target)) {
|
|
35
|
+
moreThanManaged = true
|
|
36
|
+
break
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
|
-
|
|
44
39
|
if (moreThanManaged) continue
|
|
45
40
|
|
|
46
41
|
// remove current cqn
|
|
@@ -54,7 +49,7 @@ const update = executeUpdateCQN => async (model, dbc, req) => {
|
|
|
54
49
|
const { query, user, locale, timestamp } = req
|
|
55
50
|
const isoTs = timestampToISO(timestamp)
|
|
56
51
|
|
|
57
|
-
if (hasDeepUpdate(model, query)) {
|
|
52
|
+
if (model && hasDeepUpdate(model, query)) {
|
|
58
53
|
// REVISIT: _activeData gets set in case of draftActivate for performance, but this is a layer violation
|
|
59
54
|
let selectData = req._ && req._.query && req._.query._activeData
|
|
60
55
|
|
|
@@ -71,7 +66,7 @@ const update = executeUpdateCQN => async (model, dbc, req) => {
|
|
|
71
66
|
const chunks = []
|
|
72
67
|
for (const each of cqns) chunks.push(each.filter(e => e.DELETE).length)
|
|
73
68
|
|
|
74
|
-
// remove queries that only want to update @cds.on.update properties
|
|
69
|
+
// remove child queries that only want to update @cds.on.update properties
|
|
75
70
|
cqns = _getFilteredCqns(getFlatArray(cqns), model)
|
|
76
71
|
|
|
77
72
|
if (cqns.length === 0) return 0
|
|
@@ -102,8 +102,9 @@ class CreateBuilder extends BaseBuilder {
|
|
|
102
102
|
if (structuredType[property].elements) {
|
|
103
103
|
this._flattenStructuredElement(`${prefix}_${property}`, structuredType[property].elements, flattenedElements)
|
|
104
104
|
} else if (
|
|
105
|
-
structuredType[property].
|
|
106
|
-
(structuredType[property].keys ||
|
|
105
|
+
structuredType[property].isAssociation &&
|
|
106
|
+
(structuredType[property].keys ||
|
|
107
|
+
(Array.isArray(structuredType[property].foreignKeys) && structuredType[property].foreignKeys))
|
|
107
108
|
) {
|
|
108
109
|
// OLD CSN
|
|
109
110
|
flattenedElements.push(...this._association(`${prefix}_${property}`, structuredType[property]))
|
|
@@ -118,7 +119,7 @@ class CreateBuilder extends BaseBuilder {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
_association(associationName, element) {
|
|
121
|
-
const keys = element.
|
|
122
|
+
const keys = element.keys || (Array.isArray(element.foreignKeys) && element.foreignKeys) // OLD CSN
|
|
122
123
|
if (keys) {
|
|
123
124
|
return keys.map(key => {
|
|
124
125
|
const ref = key.ref ? key.ref[0] : key // OLD CSN
|
|
@@ -67,6 +67,12 @@ class InsertBuilder extends BaseBuilder {
|
|
|
67
67
|
|
|
68
68
|
const entityName = this._into()
|
|
69
69
|
|
|
70
|
+
// table alias as string
|
|
71
|
+
if (this._obj.INSERT.into.as) {
|
|
72
|
+
this._outputObj.sql.push('AS')
|
|
73
|
+
this._outputObj.sql.push(this._obj.INSERT.into.as)
|
|
74
|
+
}
|
|
75
|
+
|
|
70
76
|
// side effect: sets this.uuidKeys if found any
|
|
71
77
|
this._findUuidKeys(entityName)
|
|
72
78
|
|
|
@@ -89,6 +95,7 @@ class InsertBuilder extends BaseBuilder {
|
|
|
89
95
|
this._entries(annotatedColumns)
|
|
90
96
|
}
|
|
91
97
|
|
|
98
|
+
// INSERT INTO ... WITH ... AS SELECT FROM ...
|
|
92
99
|
if (this._obj.INSERT.as) {
|
|
93
100
|
this._as(this._obj.INSERT.as)
|
|
94
101
|
}
|
|
@@ -116,6 +123,12 @@ class InsertBuilder extends BaseBuilder {
|
|
|
116
123
|
return this._obj.INSERT.into
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
if (this._obj.INSERT.into.ref) {
|
|
127
|
+
const dbName = this._getDatabaseName(this._obj.INSERT.into.ref[0])
|
|
128
|
+
this._outputObj.sql.push(this._quoteElement(dbName))
|
|
129
|
+
return this._obj.INSERT.into.ref[0]
|
|
130
|
+
}
|
|
131
|
+
|
|
119
132
|
const dbName = this._getDatabaseName(this._obj.INSERT.into.name)
|
|
120
133
|
this._outputObj.sql.push(this._quoteElement(dbName))
|
|
121
134
|
return this._obj.INSERT.into.name
|
|
@@ -139,7 +152,7 @@ class InsertBuilder extends BaseBuilder {
|
|
|
139
152
|
const uuidKeys = []
|
|
140
153
|
if (this._csn && this._csn.definitions[entityName] && this._csn.definitions[entityName].keys) {
|
|
141
154
|
for (const key of Object.values(this._csn.definitions[entityName].keys)) {
|
|
142
|
-
if (key.
|
|
155
|
+
if (key.isUUID) {
|
|
143
156
|
uuidKeys.push(key.name)
|
|
144
157
|
}
|
|
145
158
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
|
|
3
3
|
const BaseBuilder = require('./BaseBuilder')
|
|
4
|
-
const {
|
|
4
|
+
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* SelectBuilder is used to take a CQN object as an input and to build a SQL Select string from it.
|
|
@@ -81,6 +81,7 @@ class SelectBuilder extends BaseBuilder {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
this._columns(noQuoting)
|
|
84
|
+
|
|
84
85
|
this._from()
|
|
85
86
|
|
|
86
87
|
if (this._obj.SELECT.where && this._obj.SELECT.where.length) {
|
|
@@ -331,7 +332,7 @@ class SelectBuilder extends BaseBuilder {
|
|
|
331
332
|
_quoteDraftSpecificColumns(element) {
|
|
332
333
|
if (this._quotingStyle === 'plain' && element.ref) {
|
|
333
334
|
element.ref = element.ref.map(el => {
|
|
334
|
-
if (
|
|
335
|
+
if (el in DRAFT_COLUMNS_MAP) {
|
|
335
336
|
return this._quote(el)
|
|
336
337
|
}
|
|
337
338
|
|
|
@@ -25,12 +25,12 @@ typeConversionMap.set('cds.LargeBinary', 'BLOB')
|
|
|
25
25
|
* @private
|
|
26
26
|
*/
|
|
27
27
|
const convertDataType = (element, csn, options) => {
|
|
28
|
-
const converted = options.typeConversion.get(element.
|
|
28
|
+
const converted = options.typeConversion.get(element._type)
|
|
29
29
|
|
|
30
30
|
if (!converted) {
|
|
31
31
|
// no type in map
|
|
32
|
-
const newType = csn.definitions[element.
|
|
33
|
-
return newType ? convertDataType(newType, csn, options) : element.
|
|
32
|
+
const newType = csn.definitions[element._type]
|
|
33
|
+
return newType ? convertDataType(newType, csn, options) : element._type
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
if (typeof converted === 'string') {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
const resolveStructured = require('../../common/utils/resolveStructured')
|
|
3
3
|
|
|
4
|
-
const {
|
|
4
|
+
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* This method gets all columns for an entity.
|
|
@@ -21,8 +21,8 @@ const getColumns = (entity, { _4db, onlyKeys } = { _4db: true, onlyKeys: false }
|
|
|
21
21
|
const element = elements[elementName]
|
|
22
22
|
if (onlyKeys && !element.key) continue
|
|
23
23
|
if (element.isAssociation) continue
|
|
24
|
-
if (_4db && entity._isDraftEnabled &&
|
|
25
|
-
if (cds.env.effective.odata.structs && element.elements) {
|
|
24
|
+
if (_4db && entity._isDraftEnabled && elementName in DRAFT_COLUMNS_MAP) continue
|
|
25
|
+
if ((cds.env.effective.odata.structs || cds.env.features.ucsn_struct_conversion) && element.elements) {
|
|
26
26
|
columnNames.push(...resolveStructured({ structName: elementName, structProperties: [] }, element.elements, false))
|
|
27
27
|
continue
|
|
28
28
|
}
|
|
@@ -4,7 +4,7 @@ const { ensureNoDraftsSuffix } = require('../../common/utils/draft.js')
|
|
|
4
4
|
|
|
5
5
|
const _convertDateTimeElement = (value, element) => {
|
|
6
6
|
value = new Date(value).toISOString()
|
|
7
|
-
if (element.
|
|
7
|
+
if (element._type === 'cds.DateTime') value = value.replace(/\.\d\d\d/, '')
|
|
8
8
|
return value
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -38,7 +38,7 @@ const _convertColumns = (data, elements, model, queryColumns) => {
|
|
|
38
38
|
// check all columns
|
|
39
39
|
for (let i = 0, length = queryColumns.length; i < length; i++) {
|
|
40
40
|
const col = queryColumns[i]
|
|
41
|
-
if (elements[col] && _isToConvert(elements[col].
|
|
41
|
+
if (elements[col] && _isToConvert(elements[col]._type)) {
|
|
42
42
|
const dataArray = Array.isArray(data[0]) ? data : [data]
|
|
43
43
|
for (const d of dataArray) {
|
|
44
44
|
const elementValue = d[i]
|