@sap/cds 5.9.8 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +252 -20
- package/apis/services.d.ts +1 -1
- package/app/fiori/preview.js +2 -6
- package/app/index.js +3 -3
- package/bin/build/buildTaskEngine.js +17 -15
- package/bin/build/buildTaskFactory.js +29 -19
- package/bin/build/buildTaskHandler.js +27 -11
- package/bin/build/buildTaskProvider.js +2 -4
- package/bin/build/buildTaskProviderFactory.js +11 -16
- package/bin/build/constants.js +14 -6
- package/bin/build/csv-reader.js +2 -1
- package/bin/build/index.js +12 -18
- package/bin/build/provider/buildTaskHandlerEdmx.js +3 -39
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +149 -0
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -3
- package/bin/build/provider/buildTaskProviderInternal.js +108 -239
- package/bin/build/provider/fiori/index.js +2 -2
- package/bin/build/provider/hana/2migration.js +11 -11
- package/bin/build/provider/hana/2tabledata.js +3 -3
- package/bin/build/provider/hana/index.js +89 -99
- package/bin/build/provider/hana/migrationtable.js +4 -3
- package/bin/build/provider/java/index.js +101 -0
- package/bin/build/provider/java-cf/index.js +1 -101
- package/bin/build/provider/mtx/index.js +83 -41
- package/bin/build/provider/mtx/resourcesTarBuilder.js +68 -0
- package/bin/build/provider/mtx-sidecar/index.js +80 -0
- package/bin/build/provider/node-cf/index.js +1 -308
- package/bin/build/provider/nodejs/index.js +189 -0
- package/bin/build/util.js +19 -31
- package/bin/cds.js +5 -3
- package/bin/deploy/to-hana/cfUtil.js +31 -6
- package/bin/deploy/to-hana/gitUtil.js +5 -3
- package/bin/deploy/to-hana/hana.js +9 -10
- package/bin/{build → deploy/to-hana}/mtaUtil.js +10 -9
- package/bin/mtx/in-cds.js +19 -7
- package/bin/serve.js +56 -21
- package/bin/utils/log.js +13 -30
- package/bin/version.js +4 -3
- package/common.cds +61 -16
- package/lib/compile/cdsc.js +3 -2
- package/lib/compile/etc/_localized.js +15 -14
- package/lib/compile/for/drafts.js +3 -4
- package/lib/compile/for/java.js +13 -10
- package/lib/compile/for/nodejs.js +8 -8
- package/lib/compile/for/odata.js +7 -12
- package/lib/compile/for/sql.js +5 -6
- package/lib/compile/index.js +5 -4
- package/lib/compile/load.js +9 -11
- package/lib/compile/minify.js +8 -5
- package/lib/compile/parse.js +4 -2
- package/lib/compile/resolve.js +18 -15
- package/lib/compile/to/edm.js +0 -1
- package/lib/compile/to/gql.js +3 -2
- package/lib/compile/to/json.js +24 -17
- package/lib/connect/bindings.js +3 -2
- package/lib/connect/index.js +5 -5
- package/lib/core/classes.js +74 -2
- package/lib/core/entities.js +52 -3
- package/lib/core/reflect.js +2 -1
- package/lib/deploy.js +11 -8
- package/lib/env/defaults.js +4 -3
- package/lib/env/index.js +71 -31
- package/lib/env/presets.js +1 -14
- package/lib/env/requires.js +70 -20
- package/lib/env/serviceBindings.js +147 -0
- package/lib/i18n/localize.js +22 -23
- package/lib/index.js +148 -144
- package/lib/log/errors.js +55 -12
- package/lib/log/format/kibana.js +1 -1
- package/lib/log/index.js +4 -0
- package/lib/ql/SELECT.js +7 -2
- package/lib/ql/Whereable.js +8 -2
- package/lib/ql/index.js +2 -2
- package/lib/req/assert.js +71 -0
- package/lib/req/cds-context.js +38 -70
- package/lib/req/context.js +34 -21
- package/lib/req/request.js +12 -18
- package/lib/req/response.js +6 -2
- package/lib/req/user.js +30 -22
- package/lib/serve/Service-api.js +17 -12
- package/lib/serve/Service-dispatch.js +5 -9
- package/lib/serve/Service-methods.js +4 -3
- package/lib/serve/Transaction.js +24 -21
- package/lib/serve/adapters.js +15 -5
- package/lib/serve/factory.js +23 -20
- package/lib/serve/index.js +51 -54
- package/lib/utils/axios.js +8 -12
- package/lib/utils/index.js +3 -3
- package/lib/utils/resources/index.js +1 -44
- package/lib/utils/resources/tar.js +2 -1
- package/lib/utils/tests.js +13 -15
- package/libx/_runtime/.eslintrc +1 -1
- package/libx/_runtime/audit/Service.js +6 -4
- package/libx/_runtime/audit/generic/personal/access.js +19 -43
- package/libx/_runtime/audit/generic/personal/index.js +40 -34
- package/libx/_runtime/audit/generic/personal/modification.js +11 -9
- package/libx/_runtime/audit/generic/personal/utils.js +13 -6
- package/libx/_runtime/audit/utils/v2.js +6 -3
- package/libx/_runtime/auth/index.js +71 -66
- package/libx/_runtime/auth/strategies/JWT.js +3 -2
- package/libx/_runtime/auth/strategies/mock.js +54 -53
- package/libx/_runtime/auth/strategies/xssecUtils.js +3 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +3 -2
- package/libx/_runtime/auth/utils.js +2 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +127 -41
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +93 -73
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +10 -45
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +9 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +60 -53
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +8 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +29 -41
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +13 -13
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectToCQN.js +0 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +24 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityContainer.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +4 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +5 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/ResponseHeaderSetter.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DebugSerializingCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/PresetResponseHeadersCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/SerializingCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/SetResponseHeadersCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ErrorJsonSerializer.js +3 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/TrustedResourceJsonSerializer.js +3 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +36 -25
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +100 -91
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +382 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/oDataConfiguration.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +5 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +77 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +3 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +91 -69
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +27 -6
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +7 -17
- package/libx/_runtime/cds-services/services/Service.js +17 -76
- package/libx/_runtime/cds-services/services/utils/columns.js +6 -4
- package/libx/_runtime/cds-services/services/utils/compareJson.js +1 -53
- package/libx/_runtime/cds-services/services/utils/differ.js +15 -19
- package/libx/_runtime/cds-services/util/assert.js +107 -34
- package/libx/_runtime/cds.js +1 -31
- package/libx/_runtime/common/aspects/Association.js +40 -54
- package/libx/_runtime/common/aspects/any.js +61 -6
- package/libx/_runtime/common/aspects/entity.js +19 -79
- package/libx/_runtime/common/composition/data.js +2 -2
- package/libx/_runtime/common/composition/delete.js +8 -7
- package/libx/_runtime/common/composition/tree.js +10 -10
- package/libx/_runtime/common/composition/update.js +3 -2
- package/libx/_runtime/common/constants/events.js +15 -0
- package/libx/_runtime/common/error/entry.js +9 -3
- package/libx/_runtime/common/error/frontend.js +13 -19
- package/libx/_runtime/common/error/index.js +8 -3
- package/libx/_runtime/common/generic/auth/capabilities.js +2 -1
- package/libx/_runtime/common/generic/auth/constants.js +1 -4
- package/libx/_runtime/common/generic/auth/requires.js +1 -1
- package/libx/_runtime/common/generic/auth/restrict.js +12 -28
- package/libx/_runtime/common/generic/auth/restrictions.js +12 -4
- package/libx/_runtime/common/generic/auth/utils.js +2 -1
- package/libx/_runtime/common/generic/crud.js +9 -60
- package/libx/_runtime/common/generic/etag.js +41 -7
- package/libx/_runtime/common/generic/input.js +128 -66
- package/libx/_runtime/common/generic/paging.js +9 -3
- package/libx/_runtime/common/generic/put.js +2 -2
- package/libx/_runtime/common/generic/sorting.js +7 -3
- package/libx/_runtime/common/generic/temporal.js +0 -5
- package/libx/_runtime/common/i18n/messages.properties +2 -1
- package/libx/_runtime/common/utils/binary.js +69 -0
- package/libx/_runtime/common/utils/cqn.js +39 -14
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +93 -59
- package/libx/_runtime/common/utils/csn.js +87 -85
- package/libx/_runtime/common/utils/dollar.js +8 -7
- package/libx/_runtime/common/utils/draft.js +1 -1
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +23 -7
- package/libx/_runtime/common/utils/generateOnCond.js +2 -1
- package/libx/_runtime/common/utils/keys.js +30 -13
- package/libx/_runtime/common/utils/postProcessing.js +6 -1
- package/libx/_runtime/common/utils/quotingStyles.js +0 -23
- package/libx/_runtime/common/utils/resolveStructured.js +23 -26
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -0
- package/libx/_runtime/common/utils/search2cqn4sql.js +4 -13
- package/libx/_runtime/common/utils/searchToLike.js +9 -13
- package/libx/_runtime/common/utils/streamProp.js +35 -0
- package/libx/_runtime/common/utils/structured.js +12 -18
- package/libx/_runtime/common/utils/template.js +3 -5
- package/libx/_runtime/common/utils/templateProcessor.js +22 -14
- package/libx/_runtime/common/utils/unionCqnTemplate.js +4 -14
- package/libx/_runtime/db/Service.js +2 -1
- package/libx/_runtime/db/expand/expand-v2.js +2 -2
- package/libx/_runtime/db/expand/expandCQNToJoin.js +7 -6
- package/libx/_runtime/db/generic/input.js +14 -17
- package/libx/_runtime/db/generic/integrity.js +1 -2
- package/libx/_runtime/db/generic/update.js +14 -1
- package/libx/_runtime/db/query/read.js +0 -1
- package/libx/_runtime/db/query/update.js +1 -1
- package/libx/_runtime/db/sql-builder/BaseBuilder.js +1 -1
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +5 -31
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
- package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +0 -9
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +11 -10
- package/libx/_runtime/db/sql-builder/UpdateBuilder.js +2 -2
- package/libx/_runtime/db/sql-builder/annotations.js +1 -2
- package/libx/_runtime/db/utils/coloredTxCommands.js +5 -0
- package/libx/_runtime/db/utils/columns.js +1 -1
- package/libx/_runtime/db/utils/propagateForeignKeys.js +10 -2
- package/libx/_runtime/extensibility/activate.js +69 -0
- package/libx/_runtime/extensibility/add.js +41 -0
- package/libx/_runtime/extensibility/addExtension.js +68 -0
- package/libx/_runtime/extensibility/defaults.js +39 -0
- package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformREAD.js +0 -0
- package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformRESULT.js +2 -2
- package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformWRITE.js +2 -2
- package/libx/_runtime/extensibility/push.js +61 -0
- package/libx/_runtime/extensibility/service.js +21 -0
- package/libx/_runtime/extensibility/{uiflex/utils.js → utils.js} +39 -3
- package/libx/_runtime/extensibility/validation.js +53 -0
- package/libx/_runtime/extensibility/views.js +12 -0
- package/libx/_runtime/fiori/generic/activate.js +6 -4
- package/libx/_runtime/fiori/generic/before.js +17 -29
- package/libx/_runtime/fiori/generic/cancel.js +2 -4
- package/libx/_runtime/fiori/generic/delete.js +2 -4
- package/libx/_runtime/fiori/generic/edit.js +3 -7
- package/libx/_runtime/fiori/generic/index.js +31 -0
- package/libx/_runtime/fiori/generic/new.js +2 -4
- package/libx/_runtime/fiori/generic/patch.js +4 -8
- package/libx/_runtime/fiori/generic/prepare.js +2 -4
- package/libx/_runtime/fiori/generic/read.js +137 -162
- package/libx/_runtime/fiori/generic/readOverDraft.js +10 -4
- package/libx/_runtime/fiori/utils/handler.js +10 -5
- package/libx/_runtime/fiori/utils/where.js +1 -4
- package/libx/_runtime/hana/Service.js +14 -7
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +1 -1
- package/libx/_runtime/hana/dynatrace.js +2 -2
- package/libx/_runtime/hana/localized.js +7 -6
- package/libx/_runtime/hana/pool.js +9 -6
- package/libx/_runtime/hana/search.js +2 -3
- package/libx/_runtime/hana/{searchToContains.js → search2Contains.js} +5 -2
- package/libx/_runtime/hana/search2cqn4sql.js +20 -17
- package/libx/_runtime/index.js +2 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +11 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -3
- package/libx/_runtime/messaging/common-utils/appId.js +9 -0
- package/libx/_runtime/messaging/common-utils/authorizedRequest.js +2 -18
- package/libx/_runtime/messaging/common-utils/connections.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -2
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +305 -231
- package/libx/_runtime/messaging/enterprise-messaging-utils/cloudEvents.js +2 -2
- package/libx/_runtime/messaging/enterprise-messaging-utils/options-management.js +15 -8
- package/libx/_runtime/messaging/enterprise-messaging-utils/options-messaging.js +57 -14
- package/libx/_runtime/messaging/enterprise-messaging.js +14 -19
- package/libx/_runtime/messaging/file-based.js +2 -1
- package/libx/_runtime/messaging/http-utils/token.js +18 -6
- package/libx/_runtime/messaging/message-queuing-utils/options-management.js +22 -12
- package/libx/_runtime/messaging/message-queuing-utils/options-messaging.js +27 -14
- package/libx/_runtime/messaging/message-queuing.js +138 -85
- package/libx/_runtime/messaging/outbox/utils.js +13 -7
- package/libx/_runtime/messaging/redis-messaging.js +0 -1
- package/libx/_runtime/messaging/service.js +4 -1
- package/libx/_runtime/remote/Service.js +24 -18
- package/libx/_runtime/remote/utils/client.js +84 -46
- package/libx/_runtime/remote/utils/data.js +23 -6
- package/libx/_runtime/sqlite/Service.js +14 -13
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +2 -0
- package/libx/_runtime/sqlite/customBuilder/CustomSelectBuilder.js +1 -0
- package/libx/_runtime/sqlite/execute.js +3 -9
- package/libx/_runtime/types/api.js +23 -11
- package/libx/common/utils/ucsn.js +15 -9
- package/libx/odata/afterburner.js +109 -29
- package/libx/odata/cqn2odata.js +48 -9
- package/libx/odata/grammar.pegjs +261 -157
- package/libx/odata/index.js +21 -9
- package/libx/odata/parseToCqn.js +8 -5
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +13 -3
- package/libx/rest/RestAdapter.js +173 -113
- package/libx/rest/RestRequest.js +3 -2
- package/libx/rest/middleware/create.js +8 -6
- package/libx/rest/middleware/delete.js +6 -13
- package/libx/rest/middleware/error.js +1 -1
- package/libx/rest/middleware/input.js +6 -6
- package/libx/rest/middleware/operation.js +8 -3
- package/libx/rest/middleware/parse.js +3 -3
- package/libx/rest/middleware/payload.js +12 -0
- package/libx/rest/middleware/read.js +12 -2
- package/libx/rest/middleware/update.js +3 -3
- package/package.json +4 -6
- package/server.js +3 -44
- package/srv/extensibility-service.cds +56 -0
- package/srv/extensibility-service.js +1 -0
- package/srv/extensions.cds +8 -0
- package/srv/model-provider.cds +59 -0
- package/srv/model-provider.js +163 -0
- package/srv/mtx.cds +2 -0
- package/srv/mtx.js +22 -0
- package/srv/outbox.cds +2 -0
- package/tasks/enterprise-messaging-deploy.js +19 -12
- package/lib/serve/Service-compat.js +0 -36
- package/libx/_runtime/audit/generic/personal/constants.js +0 -4
- package/libx/_runtime/auth/strategies/dwc.js +0 -45
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +0 -56
- package/libx/_runtime/cds-services/adapter/rest/Rest.js +0 -183
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +0 -67
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -82
- package/libx/_runtime/cds-services/adapter/rest/handlers/delete.js +0 -39
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +0 -63
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +0 -52
- package/libx/_runtime/cds-services/adapter/rest/handlers/update.js +0 -81
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +0 -56
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +0 -33
- package/libx/_runtime/cds-services/adapter/rest/to.js +0 -8
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +0 -50
- package/libx/_runtime/cds-services/adapter/rest/utils/data.js +0 -117
- package/libx/_runtime/cds-services/adapter/rest/utils/header-checks.js +0 -14
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +0 -30
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +0 -250
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +0 -26
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +0 -200
- package/libx/_runtime/common/aspects/utils.js +0 -152
- package/libx/_runtime/common/toggles/handler.js +0 -21
- package/libx/_runtime/common/utils/extensibilityUtils.js +0 -18
- package/libx/_runtime/extensibility/mps/index.js +0 -5
- package/libx/_runtime/extensibility/mps/service.js +0 -111
- package/libx/_runtime/extensibility/mps/tar.js +0 -42
- package/libx/_runtime/extensibility/mps/utils.js +0 -11
- package/libx/_runtime/extensibility/uiflex/index.js +0 -54
- package/libx/_runtime/extensibility/uiflex/service.js +0 -276
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +0 -20
- package/libx/_runtime/remote/utils/client-types.d.ts +0 -7
- package/libx/gql/GraphQLAdapter.js +0 -33
- package/libx/gql/constants/adapter.js +0 -69
- package/libx/gql/constants/cds.js +0 -18
- package/libx/gql/constants/graphql.js +0 -33
- package/libx/gql/readme.md +0 -1
- package/libx/gql/resolvers/crud/create.js +0 -20
- package/libx/gql/resolvers/crud/delete.js +0 -29
- package/libx/gql/resolvers/crud/index.js +0 -6
- package/libx/gql/resolvers/crud/read.js +0 -30
- package/libx/gql/resolvers/crud/update.js +0 -42
- package/libx/gql/resolvers/crud/utils/index.js +0 -36
- package/libx/gql/resolvers/field.js +0 -5
- package/libx/gql/resolvers/index.js +0 -7
- package/libx/gql/resolvers/mutation.js +0 -23
- package/libx/gql/resolvers/parse/ast/enrich.js +0 -52
- package/libx/gql/resolvers/parse/ast/fragment.js +0 -11
- package/libx/gql/resolvers/parse/ast/fromObject.js +0 -39
- package/libx/gql/resolvers/parse/ast/index.js +0 -3
- package/libx/gql/resolvers/parse/ast/meta.js +0 -4
- package/libx/gql/resolvers/parse/ast/variable.js +0 -7
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +0 -44
- package/libx/gql/resolvers/parse/ast2cqn/entries.js +0 -31
- package/libx/gql/resolvers/parse/ast2cqn/index.js +0 -8
- package/libx/gql/resolvers/parse/ast2cqn/limit.js +0 -6
- package/libx/gql/resolvers/parse/ast2cqn/orderBy.js +0 -24
- package/libx/gql/resolvers/parse/ast2cqn/utils/index.js +0 -3
- package/libx/gql/resolvers/parse/ast2cqn/where.js +0 -70
- package/libx/gql/resolvers/parse/utils/index.js +0 -8
- package/libx/gql/resolvers/query.js +0 -13
- package/libx/gql/resolvers/root.js +0 -34
- package/libx/gql/schema/generate.js +0 -18
- package/libx/gql/schema/index.js +0 -5
- package/libx/gql/schema/mutation.js +0 -76
- package/libx/gql/schema/query.js +0 -108
- package/libx/gql/schema/typeDefMap.js +0 -45
- package/libx/gql/schema/utils/index.js +0 -54
- package/libx/gql/utils/index.js +0 -12
- package/libx/rest/middleware/auth.js +0 -20
- package/libx/rest/middleware/content.js +0 -19
- package/srv/flex.cds +0 -21
- package/srv/flex.js +0 -1
- package/srv/mps.cds +0 -23
- package/srv/mps.js +0 -1
- package/srv/outbox.js +0 -0
|
@@ -1,97 +1,121 @@
|
|
|
1
1
|
const cds = require('../../../../cds')
|
|
2
|
-
const { SELECT } = cds.ql
|
|
3
2
|
const { isCustomOperation } = require('./request')
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const keys = opReturnType.keys
|
|
14
|
-
|
|
15
|
-
for (const row of result) {
|
|
16
|
-
for (const entry in row) {
|
|
17
|
-
if (keys[entry] || entry.match(/^\*/)) continue
|
|
3
|
+
const {
|
|
4
|
+
uri: {
|
|
5
|
+
UriResource: {
|
|
6
|
+
ResourceKind: { COMPLEX_PROPERTY, PRIMITIVE_PROPERTY }
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
} = require('../okra/odata-server')
|
|
10
|
+
const { DRAFT_COLUMNS_MAP } = require('../../../../common/constants/draft')
|
|
11
|
+
const { SELECT } = cds.ql
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
const _keysOf = (row, target) => {
|
|
14
|
+
const keyElements = Object.values(target.keys || {})
|
|
15
|
+
// > singleton
|
|
16
|
+
if (!keyElements.length) return
|
|
17
|
+
const keys = {}
|
|
18
|
+
for (const key of keyElements) {
|
|
19
|
+
if (key._isAssociationStrict || key.name in DRAFT_COLUMNS_MAP) {
|
|
20
|
+
continue
|
|
22
21
|
}
|
|
22
|
+
keys[key.name] = key.elements ? { val: JSON.stringify(row[key.name]) } : row[key.name]
|
|
23
23
|
}
|
|
24
|
+
return keys
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
27
|
+
const getSimpleSelectCQN = (target, data, columns) => {
|
|
28
|
+
const keys = _keysOf(data, target)
|
|
29
|
+
// don't use `ql.where()` to get `where` in `from` for location header
|
|
30
|
+
const cqn = keys ? SELECT.one(target, keys) : /* singleton */ SELECT.one(target)
|
|
30
31
|
|
|
31
|
-
if (
|
|
32
|
-
|
|
32
|
+
if (columns) {
|
|
33
|
+
cqn.columns(...columns)
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
if (target.query && target.query.SELECT && target.query.SELECT.orderBy) {
|
|
37
|
+
cqn.SELECT.orderBy = target.query.SELECT.orderBy
|
|
38
|
+
}
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
const val1 = first[key]
|
|
40
|
-
const val2 = second[key]
|
|
41
|
-
if (Array.isArray(val1) || Buffer.isBuffer(val1)) return val1.every((_, i) => _compareKeys(val1, val2)(i))
|
|
42
|
-
if (val1 && typeof val1 === 'object') return Object.keys(val1).every(_compareKeys(val1, val2))
|
|
43
|
-
return val1 === val2
|
|
40
|
+
return cqn
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
43
|
+
/*
|
|
44
|
+
* merge CQNs
|
|
45
|
+
*/
|
|
46
|
+
const _mergeExpandCQNs = cqns => {
|
|
47
|
+
const cols = cqns[0].SELECT.columns
|
|
48
|
+
for (const cqn of cqns.slice(1)) {
|
|
49
|
+
for (const col of cqn.SELECT.columns) {
|
|
50
|
+
if (!col.expand) continue
|
|
51
|
+
const idx = cols.findIndex(ele => {
|
|
52
|
+
if (!col.ref) return
|
|
53
|
+
if (ele.ref) return ele.ref[0] === col.ref[0]
|
|
54
|
+
if (ele.as) return ele.as === col.ref[0]
|
|
55
|
+
})
|
|
56
|
+
if (idx === -1) {
|
|
57
|
+
cols.push(col)
|
|
58
|
+
} else {
|
|
59
|
+
const colExists = cols[idx]
|
|
60
|
+
if (colExists.as && colExists.val === null) {
|
|
61
|
+
cols[idx] = col
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
if (col.as && col.val === null) continue
|
|
65
|
+
const mergedExpandCQN = _mergeExpandCQNs([
|
|
66
|
+
{ SELECT: { columns: colExists.expand } },
|
|
67
|
+
{ SELECT: { columns: col.expand } }
|
|
68
|
+
])
|
|
69
|
+
colExists.expand = mergedExpandCQN.SELECT.columns
|
|
70
|
+
}
|
|
69
71
|
}
|
|
70
|
-
where.pop() // last 'and'
|
|
71
|
-
where.push(')')
|
|
72
|
-
if (!selectQuery.SELECT.where) selectQuery.where(where)
|
|
73
|
-
else selectQuery.or(where)
|
|
74
72
|
}
|
|
75
|
-
|
|
73
|
+
return cqns[0]
|
|
74
|
+
}
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
const _getExpandColumn = (data, element) => {
|
|
77
|
+
const key = element.name
|
|
78
|
+
if (!(key in data)) return
|
|
79
|
+
data = data[key]
|
|
80
|
+
if ((Array.isArray(data) && data.length === 0) || data == null) {
|
|
81
|
+
// performance tweak, keep in mind it is only for compositions
|
|
82
|
+
return { val: null, as: key }
|
|
81
83
|
}
|
|
82
|
-
|
|
84
|
+
const cqn = Array.isArray(data)
|
|
85
|
+
? _mergeExpandCQNs(data.map(data => getDeepSelect({ target: element._target, data })))
|
|
86
|
+
: getDeepSelect({ target: element._target, data })
|
|
87
|
+
return { ref: [key], expand: cqn.SELECT.columns }
|
|
83
88
|
}
|
|
84
89
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
const _getColumns = (target, data, prefix = []) => {
|
|
91
|
+
const columns = []
|
|
92
|
+
for (const each in target.elements) {
|
|
93
|
+
if (each in DRAFT_COLUMNS_MAP) continue
|
|
94
|
+
const element = target.elements[each]
|
|
95
|
+
if (element.elements && data[each]) {
|
|
96
|
+
prefix.push(element.name)
|
|
97
|
+
columns.push(..._getColumns(element, data[each], prefix))
|
|
98
|
+
prefix.pop()
|
|
99
|
+
} else if (element.isComposition && !prefix.length) {
|
|
100
|
+
const col = _getExpandColumn(data, element, prefix)
|
|
101
|
+
if (col) columns.push(col)
|
|
102
|
+
} else if (!element.isAssociation) {
|
|
103
|
+
columns.push({ ref: [...prefix, each] })
|
|
93
104
|
}
|
|
94
105
|
}
|
|
106
|
+
return columns
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/*
|
|
110
|
+
* recursively builds a select cqn for deep read after write
|
|
111
|
+
* (depth determined by req.data)
|
|
112
|
+
*/
|
|
113
|
+
const getDeepSelect = req => {
|
|
114
|
+
// REVISIT: Why do we do such expensive deep reads after write at all ???
|
|
115
|
+
const { target, data } = req
|
|
116
|
+
const columns = _getColumns(target, data)
|
|
117
|
+
|
|
118
|
+
return getSimpleSelectCQN(target, data, columns)
|
|
95
119
|
}
|
|
96
120
|
|
|
97
121
|
const getActionOrFunctionReturnType = (pathSegments, definitions) => {
|
|
@@ -108,21 +132,6 @@ const getActionOrFunctionReturnType = (pathSegments, definitions) => {
|
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
|
|
111
|
-
const actionAndFunctionQueries = async (req, odataReq, result, srv, opReturnType) => {
|
|
112
|
-
_cleanupResult(result, opReturnType)
|
|
113
|
-
|
|
114
|
-
// REVISIT consider $expand columns as inline content for $select
|
|
115
|
-
if (odataReq.getQueryOptions().$select) {
|
|
116
|
-
_selectForFunction(odataReq.getQueryOptions().$select.split(','), result, opReturnType)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// REVISIT: we need to read directly from db for this, which might not be there!
|
|
120
|
-
if (odataReq.getQueryOptions().$expand && cds.db) {
|
|
121
|
-
result = await _expandForFunction(odataReq.getUriInfo(), result, req, srv, opReturnType)
|
|
122
|
-
}
|
|
123
|
-
return result
|
|
124
|
-
}
|
|
125
|
-
|
|
126
135
|
const resolveStructuredName = (pathSegments, index, nameArr = []) => {
|
|
127
136
|
if (pathSegments[index].getKind() === COMPLEX_PROPERTY) {
|
|
128
137
|
const prop = pathSegments[index].getProperty()
|
|
@@ -147,9 +156,9 @@ const isReturnMinimal = req => {
|
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
module.exports = {
|
|
150
|
-
_expand,
|
|
151
159
|
resolveStructuredName,
|
|
152
|
-
actionAndFunctionQueries,
|
|
153
160
|
getActionOrFunctionReturnType,
|
|
154
|
-
isReturnMinimal
|
|
161
|
+
isReturnMinimal,
|
|
162
|
+
getDeepSelect,
|
|
163
|
+
getSimpleSelectCQN
|
|
155
164
|
}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
const cds = require('../../../../cds')
|
|
2
|
+
const LOG = cds.log('odata')
|
|
3
|
+
const { appURL } = require('../../../../common/utils/vcap')
|
|
4
|
+
const { resolveFromSelect, targetFromPath } = require('../../../../common/utils/cqn')
|
|
5
|
+
const { setEntityContained } = require('../../../../common/utils/csn')
|
|
6
|
+
const { getNavigationIfStruct } = require('../../../../common/utils/structured')
|
|
7
|
+
const getTemplate = require('../../../../common/utils/template')
|
|
8
|
+
const templateProcessor = require('../../../../common/utils/templateProcessor')
|
|
9
|
+
|
|
10
|
+
const _ignoreColumns = (columns, options) => {
|
|
11
|
+
if (!(Array.isArray(columns) && columns.some(c => c === '*' || c.as || c.ref))) return true
|
|
12
|
+
// REVISIT expand=* => list all expanded properties (as by okra's implementation)
|
|
13
|
+
// OData spec is clarified (https://github.tools.sap/cap/cds/pull/1183#pullrequestreview-1775872)
|
|
14
|
+
if (options && !options.$select && options.$expand === '*') return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const _getNestedQueryOptions = (ref, expand, expandString) => {
|
|
18
|
+
const isNested = expandString.match(new RegExp(`${ref}(?=\\()`))
|
|
19
|
+
// if no "ref(" i.e. "ref" without open bracket => no nested options => shift and return
|
|
20
|
+
if (!(isNested && Array.isArray(expand) && expand.length)) return { _expand: expandString.replace(ref, '') }
|
|
21
|
+
// if "ref(" found, shift to the first position after "("
|
|
22
|
+
expandString = expandString.slice(isNested.index + ref.length + 1)
|
|
23
|
+
// i.e. we found 1 open bracket already
|
|
24
|
+
let openBrackets = 1
|
|
25
|
+
let head = ''
|
|
26
|
+
// if expandString is '$top=10;$expand=foo($select=*),bar($select=buz));$select=a,b)',
|
|
27
|
+
// then outterQueryOptions is '$top=10;$expand=foo,bar;$select=a,b'
|
|
28
|
+
let outterQueryOptions = ''
|
|
29
|
+
let nestedExpand = ''
|
|
30
|
+
|
|
31
|
+
// parse until the last even closing bracket
|
|
32
|
+
while (openBrackets) {
|
|
33
|
+
const bracketFound = expandString.match(/\(|\)/)
|
|
34
|
+
head = expandString.substring(0, bracketFound.index)
|
|
35
|
+
expandString = expandString.slice(bracketFound.index + 1)
|
|
36
|
+
nestedExpand = `${nestedExpand}${head}${bracketFound[0]}`
|
|
37
|
+
// every time we have only 1 opened bracket and find another one,
|
|
38
|
+
// everything to the left is related to outter query options
|
|
39
|
+
if (openBrackets === 1 && bracketFound[0] === '(') {
|
|
40
|
+
outterQueryOptions = `${outterQueryOptions}${head}`
|
|
41
|
+
}
|
|
42
|
+
openBrackets = bracketFound[0] === '(' ? openBrackets + 1 : openBrackets - 1
|
|
43
|
+
}
|
|
44
|
+
outterQueryOptions = `${outterQueryOptions}${head}`
|
|
45
|
+
|
|
46
|
+
// outterQueryOptions also contain $expand, but without nested options i.e. can safely be split by ";"
|
|
47
|
+
const $select = outterQueryOptions.split(';').find(s => s.startsWith('$select'))
|
|
48
|
+
|
|
49
|
+
const expandIndex = nestedExpand.indexOf('$expand=')
|
|
50
|
+
// last symbol is a pair to open bracket in "ref(" => slice(..., -1)
|
|
51
|
+
const $expand = expandIndex === -1 ? '' : nestedExpand.slice(expandIndex + '$expand='.length, -1)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
$select: $select && $select.replace('$select=', ''),
|
|
55
|
+
$expand,
|
|
56
|
+
_expand: expandString
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const _columnsFromQuery = (columns, target, options) => {
|
|
61
|
+
// must use query.columns as it includes columns from $apply except of $apply=expand()
|
|
62
|
+
// must use query options to get nested $selects inside $expand() as they are mixed into query columns
|
|
63
|
+
// example: GET /Foo?$select=bar&$expand=bar => @odata.context: $metadata#Foo(bar,bar())
|
|
64
|
+
// REVISIT tbd if having expand column in $select could be integrated into query in grammar.pegjs
|
|
65
|
+
// REVISIT support $apply=expand()
|
|
66
|
+
if (_ignoreColumns(columns, options)) return ''
|
|
67
|
+
const context = []
|
|
68
|
+
const _select = options.$select ? options.$select.split(',') : []
|
|
69
|
+
let _expand = options.$expand || ''
|
|
70
|
+
|
|
71
|
+
const hasAsterisk = _select.indexOf('*') > -1
|
|
72
|
+
if (hasAsterisk) context.push('*')
|
|
73
|
+
|
|
74
|
+
for (const c of columns) {
|
|
75
|
+
if (!c) continue
|
|
76
|
+
const ref = c.ref && c.ref.join('/')
|
|
77
|
+
if (!hasAsterisk && !c.expand) {
|
|
78
|
+
if (c.as) context.push(c.as)
|
|
79
|
+
else if (ref) context.push(ref)
|
|
80
|
+
} else if (c.expand) {
|
|
81
|
+
if (!hasAsterisk && _select.indexOf(ref) > -1) context.push(ref)
|
|
82
|
+
|
|
83
|
+
const nextTarget = getNavigationIfStruct(target, c.ref)
|
|
84
|
+
if (nextTarget && nextTarget._target && nextTarget._target.elements) {
|
|
85
|
+
const nestedOptions = _getNestedQueryOptions(ref, c.expand, _expand)
|
|
86
|
+
_expand = nestedOptions._expand
|
|
87
|
+
context.push(`${ref}(${_columnsFromQuery(c.expand, nextTarget._target, nestedOptions)})`)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (context.length) return context.join(',')
|
|
92
|
+
else if (hasAsterisk) return '*'
|
|
93
|
+
return ''
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const _processFn = columns => {
|
|
97
|
+
return ({ row, key, element, pathSegments }) => {
|
|
98
|
+
if (!(key in row) || row[key] === null) return
|
|
99
|
+
let cur = columns
|
|
100
|
+
if (element.parent._isStructured) {
|
|
101
|
+
const prefix = pathSegments.join('/')
|
|
102
|
+
key = `${prefix}/${key}`
|
|
103
|
+
} else {
|
|
104
|
+
for (let p of pathSegments) {
|
|
105
|
+
if (!cur[p]) cur[p] = {}
|
|
106
|
+
cur = cur[p]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!cur[key]) cur[key] = {}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const _columnsFromData = (data, definition, service) => {
|
|
114
|
+
const columns = {}
|
|
115
|
+
const template = getTemplate('odata-context', service, definition, { pick: element => element.isAssociation })
|
|
116
|
+
if (!template || !template.elements.size) return ''
|
|
117
|
+
const arrayData = Array.isArray(data) ? data : data ? [data] : []
|
|
118
|
+
for (const row of arrayData) {
|
|
119
|
+
templateProcessor({ processFn: _processFn(columns), row, template, pathOptions: { pathSegments: [] } })
|
|
120
|
+
}
|
|
121
|
+
return _stringifyColumnsFromData(columns)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const _stringifyColumnsFromData = columns =>
|
|
125
|
+
Object.keys(columns)
|
|
126
|
+
.map(key => `${key}(${_stringifyColumnsFromData(columns[key])})`)
|
|
127
|
+
.join(',')
|
|
128
|
+
|
|
129
|
+
const _listColumns = ({ columns, data, isUpsert, returnType, event, /* express */ _req, service }) => {
|
|
130
|
+
// query options ($select, $expand, etc) as strings
|
|
131
|
+
const queryOptions = _req.query
|
|
132
|
+
let columnsStr
|
|
133
|
+
if (!isUpsert && event in { CREATE: 1 }) {
|
|
134
|
+
columnsStr = _columnsFromData(data, returnType, service)
|
|
135
|
+
} else {
|
|
136
|
+
columnsStr = _columnsFromQuery(columns, returnType, queryOptions)
|
|
137
|
+
}
|
|
138
|
+
return columnsStr && `(${columnsStr})`
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const _getContextUrlPrefix = ({ _req, path, target }) => {
|
|
142
|
+
if (cds.env.odata.contextAbsoluteUrl) {
|
|
143
|
+
try {
|
|
144
|
+
if (typeof cds.env.odata.contextAbsoluteUrl === 'string') {
|
|
145
|
+
const userDefinedURL = new URL(cds.env.odata.contextAbsoluteUrl, cds.env.odata.contextAbsoluteUrl).toString()
|
|
146
|
+
return (!userDefinedURL.endsWith('/') && `${userDefinedURL}/`) || userDefinedURL
|
|
147
|
+
}
|
|
148
|
+
} catch (e) {
|
|
149
|
+
e.message = `cds.odata.contextAbsoluteUrl could not be parsed as URL: ${cds.env.odata.contextAbsoluteUrl}`
|
|
150
|
+
LOG._warn && LOG.warn(e)
|
|
151
|
+
}
|
|
152
|
+
const reqURL = _req && _req.get && _req.get('host') && `${_req.protocol || 'https'}://${_req.get('host')}`
|
|
153
|
+
const baseAppURL = appURL || reqURL || ''
|
|
154
|
+
const serviceUrl = `${(_req && _req.baseUrl) || ''}/`
|
|
155
|
+
return baseAppURL && new URL(serviceUrl, baseAppURL).toString()
|
|
156
|
+
}
|
|
157
|
+
return target && target.params ? '../'.repeat(path.length) : '../'.repeat(path.length - 1)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const _findEdmNameFor = (definition, namespace, fullyQualified = false) => {
|
|
161
|
+
let name
|
|
162
|
+
if (!definition) return ''
|
|
163
|
+
if (definition._isStructured) {
|
|
164
|
+
const structured = [definition.name]
|
|
165
|
+
while (definition.parent) {
|
|
166
|
+
definition = definition.parent
|
|
167
|
+
structured.unshift(definition.name)
|
|
168
|
+
}
|
|
169
|
+
name = structured.join('_')
|
|
170
|
+
} else {
|
|
171
|
+
name = definition.name
|
|
172
|
+
}
|
|
173
|
+
if (!name.startsWith(`${namespace}.`)) return name
|
|
174
|
+
return fullyQualified ? name : name.replace(new RegExp(`^${namespace}\\.`), '')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const _opResultName = ({ service, returnType, operation, isServiceEntity }) => {
|
|
178
|
+
const { namespace } = service
|
|
179
|
+
if (returnType.name) {
|
|
180
|
+
const resultName = _findEdmNameFor(returnType, namespace)
|
|
181
|
+
if (returnType.name.startsWith(`${namespace}.`)) {
|
|
182
|
+
if (isServiceEntity) return resultName.replace(/\./g, '_')
|
|
183
|
+
return `${namespace}.${resultName.replace(/\./g, '_')}`
|
|
184
|
+
}
|
|
185
|
+
return resultName
|
|
186
|
+
}
|
|
187
|
+
// bound action / function returns inline structure
|
|
188
|
+
if (operation.parent) {
|
|
189
|
+
const boundEntityName = _findEdmNameFor(operation.parent, namespace, true).replace(/\./g, '_')
|
|
190
|
+
// REVISIT exactly this return type name is generated in edm by compiler
|
|
191
|
+
return `${namespace}.return_${boundEntityName}_${_findEdmNameFor(operation, namespace)}`
|
|
192
|
+
}
|
|
193
|
+
// unbound action / function returns inline structure
|
|
194
|
+
// REVISIT exactly this return type name is generated in edm by compiler
|
|
195
|
+
return `${namespace}.return_${_findEdmNameFor(operation, namespace, true).replace(/\./g, '_')}`
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const _isNavToDraftAdmin = path => path.length > 1 && path[path.length - 1] === 'DraftAdministrativeData'
|
|
199
|
+
|
|
200
|
+
const _getCanonicalUrl = (path, target, model) => {
|
|
201
|
+
const toManySegment =
|
|
202
|
+
path.length > 1 && Array.isArray(path[path.length - 1].where) && path[path.length - 1].where.length && path.pop()
|
|
203
|
+
if (target.params) path.push('Set')
|
|
204
|
+
const odataUrl = cds.odata.urlify({ SELECT: { from: { ref: path } } }, { model, kind: 'odata' })
|
|
205
|
+
let contextPath = odataUrl.path && odataUrl.path.match(/^([^?]*)\??/)[1]
|
|
206
|
+
if (toManySegment) {
|
|
207
|
+
contextPath += `/${toManySegment.id}`
|
|
208
|
+
path.push(toManySegment)
|
|
209
|
+
}
|
|
210
|
+
return contextPath
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const _getReturnTypeUrl = options => {
|
|
214
|
+
const {
|
|
215
|
+
service,
|
|
216
|
+
isCollection,
|
|
217
|
+
returnType,
|
|
218
|
+
operation,
|
|
219
|
+
path,
|
|
220
|
+
target,
|
|
221
|
+
propertyName,
|
|
222
|
+
isServiceEntity,
|
|
223
|
+
isTargetComposition
|
|
224
|
+
} = options
|
|
225
|
+
const { namespace } = service
|
|
226
|
+
if (operation) {
|
|
227
|
+
const resultName = _opResultName(options)
|
|
228
|
+
if (isServiceEntity) return resultName
|
|
229
|
+
return isCollection ? `Collection(${resultName})` : resultName
|
|
230
|
+
}
|
|
231
|
+
if (isTargetComposition || propertyName || target.params || _isNavToDraftAdmin(path)) {
|
|
232
|
+
return _getCanonicalUrl(path, target, service.model)
|
|
233
|
+
}
|
|
234
|
+
if (isServiceEntity) return _findEdmNameFor(returnType, namespace).replace(/\./g, '_')
|
|
235
|
+
return isCollection ? `Collection(${returnType.name})` : returnType.name
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const _isSingleEntity = options => {
|
|
239
|
+
const { isCollection, propertyName, returnType, isServiceEntity, isTargetComposition } = options
|
|
240
|
+
if (isCollection || (returnType && returnType._isSingleton) || propertyName) return false
|
|
241
|
+
return isServiceEntity || isTargetComposition
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const _getContextUrl = options => {
|
|
245
|
+
if (!options.returnType) return ''
|
|
246
|
+
const contextUrlPrefix = _getContextUrlPrefix(options)
|
|
247
|
+
const returnTypeUrl = _getReturnTypeUrl(options)
|
|
248
|
+
const columnsStringified = _listColumns(options)
|
|
249
|
+
const $entity = _isSingleEntity(options) ? '/$entity' : ''
|
|
250
|
+
return `${contextUrlPrefix}$metadata#${returnTypeUrl}${columnsStringified}${$entity}`
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const _getAdditionalContextUrl = (query, service, data, eventType, _req, isUpsert) => {
|
|
254
|
+
if (Array.isArray(query)) {
|
|
255
|
+
const additionalContextUrls = []
|
|
256
|
+
for (let i = 1; i < query.length; i++) {
|
|
257
|
+
additionalContextUrls.push(
|
|
258
|
+
_getContextUrl(
|
|
259
|
+
Object.assign(_getQueryInfo(query[i], service, data, eventType), { _req, service, data, isUpsert })
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
return additionalContextUrls
|
|
264
|
+
}
|
|
265
|
+
return []
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const _partialCopyColumn = c => {
|
|
269
|
+
if (c.expand) {
|
|
270
|
+
const copy = { expand: Array.isArray(c.expand) ? c.expand.map(_partialCopyColumn) : c.expand }
|
|
271
|
+
if (c.ref) copy.ref = [...c.ref]
|
|
272
|
+
return copy
|
|
273
|
+
}
|
|
274
|
+
if (c.ref) return { ref: [...c.ref] }
|
|
275
|
+
if (c.as) return { as: c.as }
|
|
276
|
+
return c
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const _partialCopyColumns = query => {
|
|
280
|
+
if (query.SELECT) {
|
|
281
|
+
// stop digging into subSelects as soon as columns found, as deeper columns will be shadowed by these
|
|
282
|
+
if (!query.SELECT.columns && query.SELECT.from.SELECT) return _partialCopyColumns(query.SELECT.from)
|
|
283
|
+
if (query.SELECT.columns) return query.SELECT.columns.map(_partialCopyColumn)
|
|
284
|
+
}
|
|
285
|
+
return []
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const _getPathInfo = (query, model) => {
|
|
289
|
+
const queryFrom =
|
|
290
|
+
(query.SELECT && resolveFromSelect(query)) ||
|
|
291
|
+
(query.INSERT && query.INSERT.into) ||
|
|
292
|
+
(query.UPDATE && query.UPDATE.entity) ||
|
|
293
|
+
(query.DELETE && query.DELETE.from)
|
|
294
|
+
const { last, target, path, isTargetComposition } = targetFromPath(queryFrom, model)
|
|
295
|
+
const operation = (last.kind === 'action' || last.kind === 'function') && last
|
|
296
|
+
let returnType, isCollection, propertyName, unbound
|
|
297
|
+
if (operation) {
|
|
298
|
+
// last segment is bound action/function => must not be in ref
|
|
299
|
+
queryFrom && queryFrom.ref && queryFrom.ref.pop()
|
|
300
|
+
unbound = !operation.parent
|
|
301
|
+
if (operation.returns) {
|
|
302
|
+
returnType = setEntityContained(operation.returns.items || operation.returns, model)
|
|
303
|
+
isCollection = !!operation.returns.items
|
|
304
|
+
}
|
|
305
|
+
// no propertyName as operations do not (yet?) support navigation
|
|
306
|
+
} else {
|
|
307
|
+
returnType = target
|
|
308
|
+
isCollection = Array.isArray(query) || (query.SELECT && !query.SELECT.one)
|
|
309
|
+
propertyName = !isCollection && last.kind !== 'entity' && last.name
|
|
310
|
+
}
|
|
311
|
+
const isStream = last['@Core.MediaType']
|
|
312
|
+
return {
|
|
313
|
+
path,
|
|
314
|
+
target,
|
|
315
|
+
last,
|
|
316
|
+
operation,
|
|
317
|
+
returnType,
|
|
318
|
+
isCollection,
|
|
319
|
+
propertyName,
|
|
320
|
+
isStream,
|
|
321
|
+
unbound,
|
|
322
|
+
isTargetComposition
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const _getEvent = (eventType, namespace, data, { last, target }) => {
|
|
327
|
+
if (last && (last.kind === 'action' || last.kind === 'function')) {
|
|
328
|
+
// BOUND
|
|
329
|
+
if (last.parent) eventType = last.name
|
|
330
|
+
// UNBOUND
|
|
331
|
+
eventType = last.name.replace(`${namespace}.`, '')
|
|
332
|
+
}
|
|
333
|
+
// draft
|
|
334
|
+
if (target && target._isDraftEnabled) {
|
|
335
|
+
if (eventType === 'CREATE') return 'NEW'
|
|
336
|
+
else if (eventType === 'draftEdit') return 'EDIT'
|
|
337
|
+
else if (eventType === 'UPDATE') return 'PATCH'
|
|
338
|
+
else if (eventType === 'DELETE' && data.IsActiveEntity !== true) return 'CANCEL'
|
|
339
|
+
}
|
|
340
|
+
return eventType
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const _getQueryInfo = (query, service, data, eventType) => {
|
|
344
|
+
const { namespace, model } = service
|
|
345
|
+
const _pathInfo = _getPathInfo(Array.isArray(query) ? query[0] : query, model)
|
|
346
|
+
const { returnType } = _pathInfo
|
|
347
|
+
|
|
348
|
+
// store original columns before they are polluted by drafts, db and so on
|
|
349
|
+
const columns = _partialCopyColumns(Array.isArray(query) ? query[0] : query)
|
|
350
|
+
const isServiceEntity =
|
|
351
|
+
_findEdmNameFor(returnType, namespace) in model.entities(namespace) && !returnType._isContained
|
|
352
|
+
const event = _getEvent(eventType, namespace, data, _pathInfo)
|
|
353
|
+
return Object.assign(_pathInfo, {
|
|
354
|
+
columns,
|
|
355
|
+
isServiceEntity,
|
|
356
|
+
event
|
|
357
|
+
})
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
module.exports = (query, eventType, service, data, /* express req */ _req, isUpsert) => {
|
|
361
|
+
const queryInfo = _getQueryInfo(query, service, data, eventType)
|
|
362
|
+
|
|
363
|
+
const { isCollection, isStream, propertyName, unbound, event, returnType, isServiceEntity } = queryInfo
|
|
364
|
+
|
|
365
|
+
const contextUrl = _getContextUrl(Object.assign(queryInfo, { _req, service, data, isUpsert }))
|
|
366
|
+
|
|
367
|
+
const additionalContextUrl = _getAdditionalContextUrl(query, service, data, eventType, _req, isUpsert)
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
event,
|
|
371
|
+
unbound,
|
|
372
|
+
metadata: {
|
|
373
|
+
isCollection,
|
|
374
|
+
isStream,
|
|
375
|
+
propertyName,
|
|
376
|
+
contextUrl,
|
|
377
|
+
returnType,
|
|
378
|
+
isServiceEntity,
|
|
379
|
+
additionalContextUrl
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
@@ -21,10 +21,7 @@ const _getEntitySets = (edm, namespace) => {
|
|
|
21
21
|
const _getConcurrent = (namespace, element, csn) => {
|
|
22
22
|
// autoexposed entities now used . in csn and _ in edm
|
|
23
23
|
const e = findCsnTargetFor(element, csn, namespace)
|
|
24
|
-
|
|
25
|
-
return Object.values(e.elements).some(val => {
|
|
26
|
-
return val['@odata.etag']
|
|
27
|
-
})
|
|
24
|
+
return !!e._etag
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
const oDataConfiguration = (edm, csn) => {
|
|
@@ -40,27 +40,26 @@ const applyOmitValuesPreference = (response, omitValuesPreference) => {
|
|
|
40
40
|
*
|
|
41
41
|
* **REVISIT**: The handling of delta payloads and instance annotations is not currently
|
|
42
42
|
* implemented, as the runtime does not yet support those features.
|
|
43
|
-
* In the future, you might want to use the `
|
|
43
|
+
* In the future, you might want to use the `elementInfo.pathSegments` argument for the
|
|
44
44
|
* implementation of delta payloads.
|
|
45
45
|
*
|
|
46
|
-
* @param {import('../../../../types/api').
|
|
46
|
+
* @param {import('../../../../types/api').templateElementInfo} elementInfo
|
|
47
47
|
* @param {import('../../../../cds-services/adapter/odata-v4/ODataRequest')} request
|
|
48
48
|
* @param {Map<string, boolean> | null} omitValuesPreference
|
|
49
49
|
* @param {object | undefined} previousRow
|
|
50
50
|
*/
|
|
51
|
-
const omitValue = (
|
|
51
|
+
const omitValue = (elementInfo, request, omitValuesPreference, previousRow) => {
|
|
52
52
|
const preferHeader = request.headers.prefer
|
|
53
53
|
if (!preferHeader || !omitValuesPreference) return
|
|
54
54
|
|
|
55
|
-
const { row, key, element
|
|
55
|
+
const { row, key, element } = elementInfo
|
|
56
56
|
const defaultValue = element.default && element.default.val ? element.default.val : null
|
|
57
57
|
const responseValue = row[key]
|
|
58
58
|
const isDefaultValue = responseValue === defaultValue
|
|
59
59
|
|
|
60
60
|
if (isDefaultValue) {
|
|
61
61
|
// Don't omit the response value if the request is an update operation and it has changed it
|
|
62
|
-
|
|
63
|
-
if (request.event === 'UPDATE' && isRoot) {
|
|
62
|
+
if (request.event === 'UPDATE') {
|
|
64
63
|
if (previousRow === undefined) return
|
|
65
64
|
if (responseValue !== previousRow[key]) return
|
|
66
65
|
}
|