@sap/cds-dk 10.0.6 → 10.1.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 +107 -0
- package/bin/add.js +7 -23
- package/bin/bind.js +10 -0
- package/bin/build.js +20 -34
- package/bin/cds.js +1 -1
- package/bin/compile/index.js +15 -41
- package/bin/completion/completionFs.js +11 -8
- package/bin/completion/index.js +592 -80
- package/bin/completion/scripts/cds.fish +568 -0
- package/bin/completion/scripts/cds.ps1 +329 -0
- package/bin/completion/scripts/cds.sh +261 -0
- package/bin/completion/scripts/cds.zsh +230 -0
- package/bin/completion/templates/cds-tmpl.fish +65 -0
- package/bin/completion/templates/cds-tmpl.ps1 +208 -0
- package/bin/completion/templates/cds-tmpl.sh +93 -0
- package/bin/completion/templates/cds-tmpl.zsh +74 -0
- package/bin/deploy/index.js +7 -1
- package/bin/deploy/options.js +25 -0
- package/{lib → bin}/deploy/to-hana/hana.js +8 -8
- package/{lib → bin}/deploy/to-hana/hdiDeployUtil.js +1 -1
- package/bin/deploy/{to-hana.js → to-hana/index.js} +1 -1
- package/{lib → bin}/deploy/to-hana/mtaUtil.js +1 -1
- package/bin/deploy/to-sql.js +0 -2
- package/bin/export.js +35 -5
- package/bin/help/export.md +3 -0
- package/bin/help.js +1 -5
- package/bin/import.js +6 -0
- package/bin/init.js +5 -24
- package/bin/inspect.js +6 -0
- package/bin/login.js +26 -20
- package/bin/pull.js +19 -6
- package/bin/push.js +19 -6
- package/bin/up.js +14 -11
- package/{lib → bin}/upgrade/constants.js +1 -1
- package/bin/{upgrade.js → upgrade/index.js} +2 -2
- package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
- package/{lib → bin}/upgrade/preflight/index.js +1 -1
- package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
- package/{lib → bin}/upgrade/steps/install.js +1 -1
- package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
- package/{lib → bin}/upgrade/steps/removals.js +1 -1
- package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
- package/{lib → bin}/upgrade/steps/verify.js +1 -1
- package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
- package/{lib → bin}/upgrade/util/pom.js +2 -2
- package/{lib → bin}/upgrade/util/prompt.js +1 -1
- package/bin/util/containerize.js +8 -4
- package/bin/version.js +10 -1
- package/{lib → bin}/watch/hot-reload.js +1 -1
- package/bin/{watch.js → watch/index.js} +17 -9
- package/{lib → bin}/watch/livereload-connect.js +1 -1
- package/{lib → bin}/watch/vite-watch.js +1 -1
- package/{lib → bin}/watch/watched.js +2 -2
- package/lib/build/constants.js +1 -1
- package/lib/build/plugins/fiori/index.js +31 -2
- package/lib/build/plugins/internal.js +4 -2
- package/lib/build/plugins/mtx-sidecar/index.js +7 -8
- package/lib/build/plugins/nodejs/index.js +64 -7
- package/lib/compile/to_asyncapi.js +1 -1
- package/lib/env/schema.js +16 -0
- package/lib/env/schemas/cds-rc.js +1 -76
- package/lib/import/importapi.js +2 -3
- package/lib/import/message.js +0 -2
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +2 -2
- package/lib/init/merge.js +123 -280
- package/lib/init/plugin.js +3 -1
- package/lib/init/projectReader.js +22 -6
- package/lib/init/registries/xs-app.js +3 -5
- package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
- package/lib/init/template/ai/index.js +14 -2
- package/lib/init/template/ams/index.js +2 -2
- package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
- package/lib/init/template/app-frontend/index.js +4 -4
- package/lib/init/template/application-logging/index.js +2 -2
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/index.js +8 -3
- package/lib/init/template/attachments/files/package.json.hbs +1 -1
- package/lib/init/template/attachments/index.js +2 -2
- package/lib/init/template/audit-logging/index.js +2 -2
- package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
- package/lib/init/template/cloud-logging/index.js +2 -2
- package/lib/init/template/completion/completionSetup.js +36 -39
- package/lib/init/template/connectivity/index.js +2 -2
- package/lib/init/template/data/as-csv.js +15 -5
- package/lib/init/template/data/as-json.js +114 -42
- package/lib/init/template/data/index.js +16 -2
- package/lib/init/template/destination/index.js +2 -2
- package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
- package/lib/init/template/dynatrace/index.js +2 -2
- package/lib/init/template/enterprise-messaging/index.js +2 -2
- package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
- package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
- package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
- package/lib/init/template/extensibility/index.js +3 -3
- package/lib/init/template/github-actions/index.js +2 -2
- package/lib/init/template/hana/index.js +3 -2
- package/lib/init/template/hana-serverless/files/db/package.json +14 -0
- package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
- package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
- package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
- package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
- package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
- package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
- package/lib/init/template/hana-serverless/index.js +184 -0
- package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
- package/lib/init/template/html5-repo/index.js +18 -14
- package/lib/init/template/http/index.js +123 -26
- package/lib/init/template/ias/index.js +2 -2
- package/lib/init/template/kafka/index.js +2 -2
- package/lib/init/template/kyma/index.js +7 -5
- package/lib/init/template/malware-scanner/index.js +2 -2
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/multitenancy/index.js +18 -3
- package/lib/init/template/nodejs/index.js +4 -2
- package/lib/init/template/notifications/index.js +2 -2
- package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
- package/lib/init/template/portal/index.js +13 -8
- package/lib/init/template/postgres/index.js +2 -2
- package/lib/init/template/redis/index.js +2 -2
- package/lib/init/template/sample/files/db/currencies.cds +2 -0
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
- package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
- package/lib/init/template/workzone-standard/index.js +5 -5
- package/lib/init/template/xsuaa/index.js +20 -2
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/mtx/auth_manager.js +103 -37
- package/lib/mtx/params.js +3 -2
- package/lib/mtx/settings_manager.js +45 -28
- package/lib/mtx/tenant_action.js +0 -1
- package/lib/mtx/util/credentials.js +62 -0
- package/node_modules/@cap-js/openapi/lib/compile/csdl.js +3 -3
- package/node_modules/@cap-js/openapi/lib/compile/csdl2openapi.js +111 -103
- package/node_modules/@cap-js/openapi/lib/compile/diagram.js +4 -4
- package/node_modules/@cap-js/openapi/lib/compile/types.d.ts +3 -1
- package/node_modules/@cap-js/openapi/package.json +3 -3
- package/node_modules/@sap/cds/CHANGELOG.md +64 -0
- package/node_modules/@sap/cds/app/index.js +5 -4
- package/node_modules/@sap/cds/eslint.config.mjs +1 -0
- package/node_modules/@sap/cds/lib/compile/for/nodejs.js +1 -0
- package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
- package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
- package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
- package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
- package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
- package/node_modules/@sap/cds/lib/plugins.js +9 -5
- package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
- package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
- package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
- package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
- package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
- package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
- package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
- package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
- package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/authorizedRequest.js +3 -2
- package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
- package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
- package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
- package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
- package/node_modules/@sap/cds/libx/http/location.js +3 -3
- package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
- package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
- package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
- package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
- package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
- package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
- package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
- package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
- package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
- package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
- package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
- package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
- package/node_modules/@sap/cds/package.json +1 -1
- package/node_modules/@sap/cds-compiler/CHANGELOG.md +60 -8
- package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
- package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
- package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
- package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
- package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
- package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
- package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
- package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
- package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
- package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
- package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
- package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
- package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
- package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +41 -15
- package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
- package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
- package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
- package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
- package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
- package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
- package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
- package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
- package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
- package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
- package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +2 -0
- package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
- package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
- package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
- package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
- package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
- package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
- package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
- package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
- package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +3 -0
- package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +8 -2
- package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
- package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
- package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
- package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +6 -1
- package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +19 -8
- package/node_modules/@sap/cds-compiler/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/CHANGELOG.md +51 -0
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +32 -48
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +35 -16
- package/node_modules/@sap/cds-mtxs/cds-plugin.js +18 -0
- package/node_modules/@sap/cds-mtxs/lib/migration/migration.js +3 -408
- package/node_modules/@sap/cds-mtxs/lib/utils.js +19 -4
- package/node_modules/@sap/cds-mtxs/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +6 -7
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +5 -2
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +6 -5
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.cds +0 -11
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +34 -35
- package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +30 -24
- package/node_modules/@sap/cds-mtxs/srv/model-provider.js +19 -4
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +6 -3
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi.js +5 -3
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/srv-mgr.js +3 -2
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/tms.js +17 -0
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +18 -21
- package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
- package/node_modules/@sap/xsenv/package.json +10 -7
- package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
- package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
- package/node_modules/hdb/cfg/VERSION +1 -1
- package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
- package/node_modules/hdb/lib/protocol/Connection.js +1 -0
- package/node_modules/hdb/package.json +3 -2
- package/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/negotiator/package.json +16 -10
- package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
- package/node_modules/qs/CHANGELOG.md +15 -0
- package/node_modules/qs/README.md +19 -1
- package/node_modules/qs/dist/qs.js +21 -21
- package/node_modules/qs/eslint.config.mjs +1 -1
- package/node_modules/qs/lib/parse.js +3 -4
- package/node_modules/qs/lib/stringify.js +23 -8
- package/node_modules/qs/lib/utils.js +10 -3
- package/node_modules/qs/package.json +4 -4
- package/node_modules/qs/test/parse.js +192 -3
- package/node_modules/qs/test/stringify.js +317 -0
- package/node_modules/qs/test/utils.js +12 -0
- package/node_modules/sax/lib/sax.js +27 -9
- package/node_modules/sax/package.json +1 -1
- package/node_modules/type-is/node_modules/content-type/README.md +2 -0
- package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/type-is/node_modules/content-type/package.json +1 -1
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/package.json +5 -5
- package/bin/completion/scripts/cds-bash.sh +0 -20
- package/bin/completion/scripts/cds-fish.fish +0 -13
- package/bin/completion/scripts/cds-ps.ps1 +0 -19
- package/bin/completion/scripts/cds-zsh.sh +0 -13
- package/lib/deploy/index.js +0 -25
- package/lib/import/asyncapi/importAsyncAPI.js +0 -33
- package/lib/import/asyncapi/index.js +0 -18
- package/lib/import/asyncapi/parserContext.js +0 -372
- package/lib/import/asyncapi/utils.js +0 -49
- package/lib/init/template/nodejs/files/.gitignore.hbs +0 -34
- package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
- package/node_modules/@sap/cds-mtxs/lib/migration/extension-project-builder.js +0 -129
- package/node_modules/@sap/cds-mtxs/lib/migration/extension-project.js +0 -89
- package/node_modules/@sap/cds-mtxs/lib/migration/mtx-adapter.js +0 -230
- package/node_modules/negotiator/HISTORY.md +0 -114
- /package/{lib → bin}/upgrade/context.js +0 -0
- /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
- /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
- /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
- /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
- /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
- /package/{lib → bin}/watch/livereload-server.js +0 -0
- /package/{lib → bin}/watch/node-watch.js +0 -0
- /package/{lib → bin}/watch/open.js +0 -0
- /package/{lib → bin}/watch/watcher.js +0 -0
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} FunctionRendererContext
|
|
5
|
+
* @property {Function} renderArgs - Renders a function argument node to SQL string.
|
|
6
|
+
* @property {Function} error - Compiler error reporting function.
|
|
7
|
+
* @property {string[]} path - Current CSN path for error reporting.
|
|
8
|
+
* @property {{ embeddingDefaultModel: string, embeddingHanaDefaultRemoteSource: string }} vector - Vector embedding options.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {(this: FunctionRendererContext, signature: object) => string} DbFunction
|
|
13
|
+
*/
|
|
14
|
+
|
|
3
15
|
/**
|
|
4
16
|
* List of functions for which we provide a mapping to the respective SQL dialect.
|
|
5
17
|
* All functions are lowercase, the caller may treat the function name case-insensitive.
|
|
6
18
|
*
|
|
7
19
|
* The `this` context within the functions hold the `renderArgs` function.
|
|
8
20
|
*/
|
|
21
|
+
/** @type {Record<string, Record<string, DbFunction>>} */
|
|
9
22
|
const oDataFunctions = {
|
|
10
23
|
// https://www.sqlite.org/lang_corefunc.html
|
|
11
24
|
sqlite: {
|
|
@@ -116,7 +129,7 @@ const oDataFunctions = {
|
|
|
116
129
|
// let x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
117
130
|
// const isNegative = x.startsWith("'-"); // Check for leading '-'
|
|
118
131
|
// x = isNegative ? x.replace('-', '') : x; // remove for easier processing
|
|
119
|
-
// const sql = `((cast(substr(${x},2,instr(${x},'DT') - 2) as Integer) + (julianday('-4713-11-25T' || replace(replace(replace(substr(${x},instr(${x},'DT') + 2),'H',':'),'M',':'),'S','Z')) - 0.5)) * 86400)`;
|
|
132
|
+
// const sql = `((cast(substr(${ x },2,instr(${ x },'DT') - 2) as Integer) + (julianday('-4713-11-25T' || replace(replace(replace(substr(${ x },instr(${ x },'DT') + 2),'H',':'),'M',':'),'S','Z')) - 0.5)) * 86400)`;
|
|
120
133
|
// return isNegative ? `-(${sql})` : sql;
|
|
121
134
|
// },
|
|
122
135
|
},
|
|
@@ -260,7 +273,7 @@ const oDataFunctions = {
|
|
|
260
273
|
},
|
|
261
274
|
matchespattern(signature) {
|
|
262
275
|
// case … when only works as column expression (not in where)
|
|
263
|
-
// in the where clause, only "${x} LIKE_REGEXPR ${y}" works
|
|
276
|
+
// in the where clause, only "${ x } LIKE_REGEXPR ${ y }" works
|
|
264
277
|
const args = getArgs(signature);
|
|
265
278
|
checkArgs.call(this, 'matchespattern', args, 2);
|
|
266
279
|
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
@@ -556,6 +569,7 @@ const oDataFunctions = {
|
|
|
556
569
|
},
|
|
557
570
|
};
|
|
558
571
|
|
|
572
|
+
/** @type {Record<string, Record<string, DbFunction>>} */
|
|
559
573
|
const hanaFunctions = {
|
|
560
574
|
sqlite: {
|
|
561
575
|
/**
|
|
@@ -659,6 +673,11 @@ const hanaFunctions = {
|
|
|
659
673
|
checkArgs.call(this, 'years_between', args, 2);
|
|
660
674
|
return `floor((${ hanaFunctions.sqlite.months_between.call(this, signature) }) / 12)`;
|
|
661
675
|
},
|
|
676
|
+
|
|
677
|
+
//
|
|
678
|
+
// Note: Vector functions for SQLite (cosine_similarity, l2distance, l2normalize and vector_embedding) have the
|
|
679
|
+
// same parameters as on HANA because we provide them via UDFs
|
|
680
|
+
//
|
|
662
681
|
},
|
|
663
682
|
postgres: {
|
|
664
683
|
nano100_between(signature) {
|
|
@@ -697,6 +716,33 @@ const hanaFunctions = {
|
|
|
697
716
|
checkArgs.call(this, 'years_between', args, 2);
|
|
698
717
|
return `floor((${ hanaFunctions.postgres.months_between.call(this, signature) }) / 12)::INTEGER`;
|
|
699
718
|
},
|
|
719
|
+
|
|
720
|
+
//
|
|
721
|
+
// Vector functions for postgres vector support based on the https://github.com/pgvector/pgvector
|
|
722
|
+
//
|
|
723
|
+
cosine_similarity(signature) {
|
|
724
|
+
const args = getArgs(signature);
|
|
725
|
+
checkArgs.call(this, 'cosine_similarity', args, 2);
|
|
726
|
+
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
727
|
+
const y = this.renderArgs({ ...signature, args: [ args[1] ] });
|
|
728
|
+
|
|
729
|
+
return `1 - cosine_distance(${ x },${ y })`;
|
|
730
|
+
},
|
|
731
|
+
l2distance(signature) {
|
|
732
|
+
const args = getArgs(signature);
|
|
733
|
+
checkArgs.call(this, 'l2distance', args, 2);
|
|
734
|
+
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
735
|
+
const y = this.renderArgs({ ...signature, args: [ args[1] ] });
|
|
736
|
+
|
|
737
|
+
return `l2_distance(${ x },${ y })`;
|
|
738
|
+
},
|
|
739
|
+
l2normalize(signature) {
|
|
740
|
+
const args = getArgs(signature);
|
|
741
|
+
checkArgs.call(this, 'l2normalize', args, 1);
|
|
742
|
+
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
743
|
+
|
|
744
|
+
return `l2_normalize(${ x })`;
|
|
745
|
+
},
|
|
700
746
|
},
|
|
701
747
|
h2: {
|
|
702
748
|
nano100_between(signature) {
|
|
@@ -757,8 +803,18 @@ const hanaFunctions = {
|
|
|
757
803
|
checkArgs.call(this, 'years_between', args, 2);
|
|
758
804
|
return `floor((${ hanaFunctions.h2.months_between.call(this, signature) }) / 12)`;
|
|
759
805
|
},
|
|
806
|
+
|
|
807
|
+
//
|
|
808
|
+
// Note: Vector functions for H2 (cosine_similarity, l2distance, l2normalize, and vector_embedding) have the
|
|
809
|
+
// same parameters as on HANA because we provide them via UDFs
|
|
810
|
+
//
|
|
811
|
+
},
|
|
812
|
+
common: {
|
|
813
|
+
vector_embedding(signature) {
|
|
814
|
+
/** @type {FunctionRendererContext} */ const ctx = /** @type {any} */ (this);
|
|
815
|
+
return vectorEmbedding.call(ctx, signature);
|
|
816
|
+
},
|
|
760
817
|
},
|
|
761
|
-
common: {},
|
|
762
818
|
// identity functions + argument check
|
|
763
819
|
hana: {
|
|
764
820
|
nano100_between(signature) {
|
|
@@ -797,8 +853,67 @@ const hanaFunctions = {
|
|
|
797
853
|
checkArgs.call(this, 'years_between', args, 2);
|
|
798
854
|
return `years_between(${ this.renderArgs({ ...signature, args }) })`;
|
|
799
855
|
},
|
|
856
|
+
|
|
857
|
+
//
|
|
858
|
+
// Vector functions - only identity check
|
|
859
|
+
//
|
|
860
|
+
cosine_similarity(signature) {
|
|
861
|
+
const args = getArgs(signature);
|
|
862
|
+
checkArgs.call(this, 'cosine_similarity', args, 2);
|
|
863
|
+
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
864
|
+
const y = this.renderArgs({ ...signature, args: [ args[1] ] });
|
|
865
|
+
|
|
866
|
+
return `cosine_similarity(${ x },${ y })`;
|
|
867
|
+
},
|
|
868
|
+
l2distance(signature) {
|
|
869
|
+
const args = getArgs(signature);
|
|
870
|
+
checkArgs.call(this, 'l2distance', args, 2);
|
|
871
|
+
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
872
|
+
const y = this.renderArgs({ ...signature, args: [ args[1] ] });
|
|
873
|
+
|
|
874
|
+
return `l2distance(${ x },${ y })`;
|
|
875
|
+
},
|
|
876
|
+
l2normalize(signature) {
|
|
877
|
+
const args = getArgs(signature);
|
|
878
|
+
checkArgs.call(this, 'l2normalize', args, 1);
|
|
879
|
+
const x = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
880
|
+
|
|
881
|
+
return `l2normalize(${ x })`;
|
|
882
|
+
},
|
|
883
|
+
vector_embedding(signature) {
|
|
884
|
+
/** @type {FunctionRendererContext} */ const ctx = /** @type {any} */ (this);
|
|
885
|
+
const sql = vectorEmbedding.call(ctx, signature);
|
|
886
|
+
if (sql.match('SAP.'))
|
|
887
|
+
return sql;
|
|
888
|
+
// If the model does not start with SAP an additional fourth parameter
|
|
889
|
+
// is necessary specifying the remote source behind which SAP AI Core lies on HANA
|
|
890
|
+
return `${ sql.substring(0, sql.length - 1) }, ${ this.vector.embeddingHanaDefaultRemoteSource })`;
|
|
891
|
+
},
|
|
800
892
|
},
|
|
801
893
|
};
|
|
894
|
+
/**
|
|
895
|
+
* Arguments:
|
|
896
|
+
* 1. (mandatory) property for which to generate a vector
|
|
897
|
+
* 2. (optional) DOCUMENT / QUERY kind for embedding function. If not provided we default to 'DOCUMENT'
|
|
898
|
+
* 3. (optional) model. If not provided we default to a compiler setting or else the SAP NXY model
|
|
899
|
+
* @this {FunctionRendererContext}
|
|
900
|
+
* @param {object} signature
|
|
901
|
+
* @returns {string}
|
|
902
|
+
*/
|
|
903
|
+
function vectorEmbedding( signature ) {
|
|
904
|
+
const args = getArgs(signature);
|
|
905
|
+
// Default to kind DOCUMENT if no kind is specified
|
|
906
|
+
if (args.length === 1)
|
|
907
|
+
args.push('DOCUMENT');
|
|
908
|
+
// Default to the compiler option vectorEmbeddingDefaultModel if no model is specified
|
|
909
|
+
if (args.length === 2)
|
|
910
|
+
args.push(this.vector.embeddingDefaultModel);
|
|
911
|
+
checkArgs.call(this, 'vector_embedding', args, 3);
|
|
912
|
+
const field = this.renderArgs({ ...signature, args: [ args[0] ] });
|
|
913
|
+
const kind = this.renderArgs({ ...signature, args: [ args[1] ] });
|
|
914
|
+
const model = this.renderArgs({ ...signature, args: [ args[2] ] });
|
|
915
|
+
return `vector_embedding(${ field }, ${ kind }, ${ model })`;
|
|
916
|
+
}
|
|
802
917
|
|
|
803
918
|
/**
|
|
804
919
|
* Normalizes `signature.args` to a positional array, handling both
|
|
@@ -808,6 +923,13 @@ function getArgs( signature ) {
|
|
|
808
923
|
return Array.isArray(signature.args) ? signature.args : Object.values(signature.args);
|
|
809
924
|
}
|
|
810
925
|
|
|
926
|
+
/**
|
|
927
|
+
* @this {FunctionRendererContext}
|
|
928
|
+
* @param {string} funcName
|
|
929
|
+
* @param {any[]} receivedArgs
|
|
930
|
+
* @param {number} expectedLength
|
|
931
|
+
* @param {number | null} alternativeLength
|
|
932
|
+
*/
|
|
811
933
|
function checkArgs( funcName, receivedArgs, expectedLength, alternativeLength = null ) {
|
|
812
934
|
const expectedMismatch = receivedArgs.length < expectedLength;
|
|
813
935
|
const alternativeMismatch
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const msg = require('../base/messages');
|
|
17
17
|
const { CompilerAssertion } = require('../base/error');
|
|
18
|
+
const { isLeadingQuery } = require('../compiler/utils');
|
|
18
19
|
|
|
19
20
|
const $inferred = Symbol.for('cds.$inferred');
|
|
20
21
|
const $location = Symbol.for('cds.$location');
|
|
@@ -206,7 +207,7 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
206
207
|
|
|
207
208
|
function elements( dict, parent ) {
|
|
208
209
|
// do not display elements of leading query as they are the same as the view elements:
|
|
209
|
-
return (
|
|
210
|
+
return (isLeadingQuery( parent ))
|
|
210
211
|
? '{ ... }'
|
|
211
212
|
: dictionary( dict );
|
|
212
213
|
}
|
|
@@ -41,6 +41,7 @@ function applyTransformationsInternal( parent, prop, customTransformers, artifac
|
|
|
41
41
|
mixin: dictionary,
|
|
42
42
|
ref: pathRef,
|
|
43
43
|
$origin: () => {}, // no-op
|
|
44
|
+
$backlink: () => undefined,
|
|
44
45
|
'@': annotation,
|
|
45
46
|
};
|
|
46
47
|
|
|
@@ -68,6 +69,8 @@ function applyTransformationsInternal( parent, prop, customTransformers, artifac
|
|
|
68
69
|
* @param {object} node The value of node[_prop]
|
|
69
70
|
*/
|
|
70
71
|
function standard( _parent, _prop, node ) {
|
|
72
|
+
if (_prop === '$backlink') // above line in transformers doesn't seem to help...
|
|
73
|
+
return; // ...in the OData backend
|
|
71
74
|
if (!node || typeof node !== 'object' ||
|
|
72
75
|
!{}.propertyIsEnumerable.call( _parent, _prop ) ||
|
|
73
76
|
(options.skipIgnore && node.$ignore) ||
|
|
@@ -136,7 +136,9 @@ function getFKAccessFinalizer( csn, options, csnUtils, pathDelimiter, processOnI
|
|
|
136
136
|
if (obj[anno].ref)
|
|
137
137
|
transformer.ref(obj[anno], 'ref', obj[anno].ref, path.concat(anno));
|
|
138
138
|
const annoAfter = JSON.stringify(obj[anno]);
|
|
139
|
-
if (annoBefore !== annoAfter &&
|
|
139
|
+
if (annoBefore !== annoAfter &&
|
|
140
|
+
(options.transformation !== 'effective' || obj[anno]['=']) &&
|
|
141
|
+
!(obj[anno].ref && obj[anno].ref.every(s => typeof s === 'string')))
|
|
140
142
|
obj[anno]['='] = true;
|
|
141
143
|
});
|
|
142
144
|
}
|
|
@@ -219,7 +221,7 @@ function getFKAccessFinalizer( csn, options, csnUtils, pathDelimiter, processOnI
|
|
|
219
221
|
*/
|
|
220
222
|
function getTransformer() {
|
|
221
223
|
return {
|
|
222
|
-
ref: (refOwner, prop, ref, path, grandParent) => {
|
|
224
|
+
ref: (refOwner, prop, ref, path, grandParent, _opt, ctx) => {
|
|
223
225
|
// [<assoc base>.]<managed assoc>.<field>
|
|
224
226
|
if (ref.length > 1) {
|
|
225
227
|
const { links } = inspectRef(path);
|
|
@@ -249,6 +251,10 @@ function getFKAccessFinalizer( csn, options, csnUtils, pathDelimiter, processOnI
|
|
|
249
251
|
else {
|
|
250
252
|
refOwner.ref = [ ...ref.slice(0, i), newFkName ];
|
|
251
253
|
}
|
|
254
|
+
if (ctx?.annoExpr === refOwner)
|
|
255
|
+
ctx.annoExpr['='] = refOwner.ref.every(s => typeof s === 'string')
|
|
256
|
+
? refOwner.ref.join('.')
|
|
257
|
+
: true;
|
|
252
258
|
}
|
|
253
259
|
}
|
|
254
260
|
else {
|
|
@@ -175,12 +175,14 @@ function getBacklinkTransformer( csnUtils, messageFunctions, options, pathDelimi
|
|
|
175
175
|
* @returns {Array} New on-condition
|
|
176
176
|
*/
|
|
177
177
|
function transformDollarSelfComparison( assocOp, assoc, assocName, elem, elemName, art, artifactName, path ) {
|
|
178
|
-
// Check: The forward link <assocOp> must point back to this artifact
|
|
178
|
+
// Check: The forward link <assocOp> must point back to this artifact.
|
|
179
|
+
// Skip when `$backlink` is present: the core compiler already validated the (possibly
|
|
180
|
+
// redirected/included) target and provided the redirected keys/on
|
|
179
181
|
// FIXME: Unfortunately, we can currently only check this for non-views (because when a view selects
|
|
180
182
|
// a backlink association element from an entity, the forward link will point to the entity,
|
|
181
183
|
// not to the view).
|
|
182
184
|
// FIXME: This also means that corresponding key fields should be in the select list etc ...
|
|
183
|
-
if (!art.query && !art.projection && assoc.target && assoc.target !== artifactName) {
|
|
185
|
+
if (!elem.$backlink && !art.query && !art.projection && assoc.target && assoc.target !== artifactName) {
|
|
184
186
|
messageFunctions.error( null, path, { id: '$self', name: artifactName, target: assoc.target },
|
|
185
187
|
'Expected association using $(ID) to point back to $(NAME) but found $(TARGET)' );
|
|
186
188
|
}
|
|
@@ -199,6 +201,16 @@ function getBacklinkTransformer( csnUtils, messageFunctions, options, pathDelimi
|
|
|
199
201
|
return [];
|
|
200
202
|
}
|
|
201
203
|
|
|
204
|
+
// Prefer the `$backlink` helper (renaming-aware, target redirected to this artifact)
|
|
205
|
+
// over the backlink's own keys/on, so renamings are considered. Absent for
|
|
206
|
+
// same-entity backlinks, where the plain keys/on below are already correct.
|
|
207
|
+
const backlink = elem.$backlink;
|
|
208
|
+
|
|
209
|
+
if (Array.isArray(backlink))
|
|
210
|
+
return transformDollarSelfComparisonWithUnmanagedAssoc(assocOp, assoc, assocName, elemName, art, path, backlink);
|
|
211
|
+
if (backlink?.keys?.length)
|
|
212
|
+
return transformDollarSelfComparisonWithManagedAssoc(assocOp, assoc, assocName, elemName, art, path, backlink);
|
|
213
|
+
|
|
202
214
|
if (assoc.keys) {
|
|
203
215
|
// Transform comparison of $self to managed association into AND-combined foreign key comparisons
|
|
204
216
|
if (assoc.keys.length > 0)
|
|
@@ -230,16 +242,19 @@ function getBacklinkTransformer( csnUtils, messageFunctions, options, pathDelimi
|
|
|
230
242
|
* @param {string} elemName
|
|
231
243
|
* @param {CSN.Artifact} art
|
|
232
244
|
* @param {CSN.Path} path
|
|
245
|
+
* @param {object} [backlink] renaming-aware `elem.$backlink` (`{ keys }`) to use instead of `assoc.keys`
|
|
233
246
|
* @returns {Array} New on-condition
|
|
234
247
|
*/
|
|
235
|
-
function transformDollarSelfComparisonWithManagedAssoc( assocOp, assoc, originalAssocName, elemName, art, path) {
|
|
248
|
+
function transformDollarSelfComparisonWithManagedAssoc( assocOp, assoc, originalAssocName, elemName, art, path, backlink ) {
|
|
236
249
|
const conditions = [];
|
|
237
250
|
// if the element was structured then it was flattened => change of the delimiter from '.' to '_'
|
|
238
251
|
// this is done in the flattening, but as we do not alter the onCond itself there should be done here as well
|
|
239
252
|
const assocName = originalAssocName.replace(/\./g, pathDelimiter);
|
|
240
253
|
elemName = elemName.replace(/\./g, pathDelimiter);
|
|
241
254
|
|
|
242
|
-
assoc.keys
|
|
255
|
+
const keys = backlink?.keys ?? assoc.keys;
|
|
256
|
+
|
|
257
|
+
keys.forEach((k) => {
|
|
243
258
|
// Depending on naming conventions, the foreign key may two path steps (hdbcds) or be a single path step with a flattened name (plain, quoted)
|
|
244
259
|
// With to.hdbcds in conjunction with hdbcds naming, we need to NOT use the alias - else we get deployment errors
|
|
245
260
|
const keyName = k.as && doA2J ? [ k.as ] : k.ref;
|
|
@@ -282,15 +297,16 @@ function getBacklinkTransformer( csnUtils, messageFunctions, options, pathDelimi
|
|
|
282
297
|
* @param {string} elemName
|
|
283
298
|
* @param {CSN.Artifact} art
|
|
284
299
|
* @param {CSN.Path} path
|
|
300
|
+
* @param {Array} [backlink] renaming-aware `elem.$backlink` ON-condition to use instead of `assoc.on`
|
|
285
301
|
* @returns {Array} New on-condition
|
|
286
302
|
*/
|
|
287
|
-
function transformDollarSelfComparisonWithUnmanagedAssoc( assocOp, assoc, originalAssocName, elemName, art, path ) {
|
|
303
|
+
function transformDollarSelfComparisonWithUnmanagedAssoc( assocOp, assoc, originalAssocName, elemName, art, path, backlink ) {
|
|
288
304
|
// if the element was structured then it may have been flattened => change of the delimiter from '.' to '_'
|
|
289
305
|
// this is done in the flattening, but as we do not alter the onCond itself there should be done here as well
|
|
290
306
|
elemName = elemName.replace(/\./g, pathDelimiter);
|
|
291
307
|
const assocName = originalAssocName.replace(/\./g, pathDelimiter);
|
|
292
308
|
// clone the onCond for later use in the path transformation
|
|
293
|
-
const newOnCond = cloneCsnNonDict(assoc.on, options);
|
|
309
|
+
const newOnCond = cloneCsnNonDict(backlink ?? assoc.on, options);
|
|
294
310
|
applyTransformationsOnNonDictionary({ on: newOnCond }, 'on', {
|
|
295
311
|
ref: (parent, prop, ref) => {
|
|
296
312
|
let sourceSide = false;
|
|
@@ -592,6 +592,67 @@ function createReferentialConstraints( csn, options ) {
|
|
|
592
592
|
}
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
+
/**
|
|
596
|
+
* Add an `ON DELETE CASCADE` referential constraint on the `DraftAdministrativeData_DraftUUID`
|
|
597
|
+
* foreign key of each draft shadow table, so deleting a draft's `DRAFT.DraftAdministrativeData`
|
|
598
|
+
* row removes all its shadow rows.
|
|
599
|
+
*
|
|
600
|
+
* Runs after the draft shadow entities exist (they don't during `createReferentialConstraints`).
|
|
601
|
+
* Their `DraftAdministrativeData` association is unmanaged and points at the service view, so the
|
|
602
|
+
* regular pass skips it; this pass references the `DRAFT.DraftAdministrativeData` table directly.
|
|
603
|
+
*
|
|
604
|
+
* Opt-in via the `draftAdminDataConstraints` option and independent of the global
|
|
605
|
+
* `assertIntegrity` / `assertIntegrityType` switches.
|
|
606
|
+
*
|
|
607
|
+
* @param {CSN.Model} csn
|
|
608
|
+
* @param {CSN.Options} options
|
|
609
|
+
*/
|
|
610
|
+
function createDraftAdminDataConstraints( csn, options ) {
|
|
611
|
+
if (options.draftAdminDataConstraints !== true)
|
|
612
|
+
return;
|
|
613
|
+
|
|
614
|
+
const draftAdminData = 'DRAFT.DraftAdministrativeData';
|
|
615
|
+
if (!csn.definitions[draftAdminData])
|
|
616
|
+
return;
|
|
617
|
+
|
|
618
|
+
const delimiter = options.sqlMapping === 'hdbcds' ? '.' : '_';
|
|
619
|
+
const foreignKeyName = `DraftAdministrativeData${ delimiter }DraftUUID`;
|
|
620
|
+
|
|
621
|
+
const validated = !options.integrityNotValidated;
|
|
622
|
+
const enforced = !options.integrityNotEnforced;
|
|
623
|
+
|
|
624
|
+
forEach(csn.definitions, ( artifactName, artifact ) => {
|
|
625
|
+
if (artifact.kind !== 'entity' || artifact.query || artifact.projection)
|
|
626
|
+
return;
|
|
627
|
+
const foreignKey = artifact.elements?.[foreignKeyName];
|
|
628
|
+
const assoc = artifact.elements?.DraftAdministrativeData;
|
|
629
|
+
// only draft shadow tables have both the association and its flattened foreign key
|
|
630
|
+
if (!foreignKey || !assoc || assoc.type !== ASSOCIATION)
|
|
631
|
+
return;
|
|
632
|
+
|
|
633
|
+
const identifierPrefix = options.pre2134ReferentialConstraintNames ? '' : 'c__';
|
|
634
|
+
const identifier = `${ identifierPrefix }${ getResultingName(csn, options.sqlMapping, artifactName) }_DraftAdministrativeData`;
|
|
635
|
+
const mapKey = `${ getResultingName(csn, 'quoted', artifactName) }_DraftAdministrativeData`;
|
|
636
|
+
|
|
637
|
+
if (!('$tableConstraints' in artifact))
|
|
638
|
+
artifact.$tableConstraints = Object.create(null);
|
|
639
|
+
if (!artifact.$tableConstraints.referential)
|
|
640
|
+
artifact.$tableConstraints.referential = Object.create(null);
|
|
641
|
+
|
|
642
|
+
artifact.$tableConstraints.referential[mapKey] = {
|
|
643
|
+
identifier,
|
|
644
|
+
foreignKey: [ foreignKeyName ],
|
|
645
|
+
parentKey: [ 'DraftUUID' ],
|
|
646
|
+
dependentTable: artifactName,
|
|
647
|
+
parentTable: draftAdminData,
|
|
648
|
+
onDelete: 'CASCADE',
|
|
649
|
+
onDeleteRemark: options.testMode ? 'Draft shadow entries are deleted when their DraftAdministrativeData entry is deleted' : null,
|
|
650
|
+
validated,
|
|
651
|
+
enforced,
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
|
|
595
656
|
/**
|
|
596
657
|
* If the artifact has both, unique- and foreign key constraints, it is possible that the constraints have the same identifier.
|
|
597
658
|
* This would end in table which can't be activated.
|
|
@@ -616,4 +677,4 @@ function assertConstraintIdentifierUniqueness( artifact, artifactName, path, err
|
|
|
616
677
|
});
|
|
617
678
|
}
|
|
618
679
|
|
|
619
|
-
module.exports = { createReferentialConstraints, assertConstraintIdentifierUniqueness };
|
|
680
|
+
module.exports = { createReferentialConstraints, createDraftAdminDataConstraints, assertConstraintIdentifierUniqueness };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { CompilerAssertion } = require('../../base/error');
|
|
4
|
+
const { transformAnnotationExpression } = require('../../model/csnUtils');
|
|
5
|
+
const { expressionToCdlString } = require('../../render/toCdl');
|
|
4
6
|
const { forEach } = require('../../utils/objectUtils');
|
|
5
7
|
|
|
6
8
|
const directMappings = {
|
|
@@ -283,6 +285,43 @@ function sealAnnoMagic(csn) {
|
|
|
283
285
|
};
|
|
284
286
|
}
|
|
285
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Replace all annotation expression nodes with their CDL-like string representation.
|
|
290
|
+
*
|
|
291
|
+
* @param {CSN.Model} _csn
|
|
292
|
+
* @param {CSN.Options} options
|
|
293
|
+
* @param {object} messageFunctions
|
|
294
|
+
* @returns {object} Transformer object for applyTransformations
|
|
295
|
+
*/
|
|
296
|
+
function stringifyAnnotationExpressions( _csn, options, messageFunctions ) {
|
|
297
|
+
// exclude '#' so enum-symbol annotation values are kept as is
|
|
298
|
+
const expressionTransformers = {
|
|
299
|
+
ref: stringifyExpression,
|
|
300
|
+
xpr: stringifyExpression,
|
|
301
|
+
list: stringifyExpression,
|
|
302
|
+
val: stringifyExpression,
|
|
303
|
+
func: stringifyExpression,
|
|
304
|
+
SELECT: stringifyExpression,
|
|
305
|
+
SET: stringifyExpression,
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
'@': (parent, prop, _anno, path) => transformAnnotationExpression(parent, prop, expressionTransformers, path),
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
function stringifyExpression( expressionNode, _prop, _value, _path, parent, parentProp ) {
|
|
313
|
+
// Keep unchecked refs that already have textual representation.
|
|
314
|
+
if (expressionNode.ref && typeof expressionNode['='] === 'string') {
|
|
315
|
+
delete expressionNode.ref;
|
|
316
|
+
delete expressionNode.param;
|
|
317
|
+
delete expressionNode.cast;
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
parent[parentProp] = expressionToCdlString(expressionNode, options, messageFunctions);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
286
325
|
function isPartOfINAService(csn, artifactName) {
|
|
287
326
|
const parts = artifactName.split('.');
|
|
288
327
|
if (parts.length === 1)
|
|
@@ -339,4 +378,5 @@ function getOnConditionAsComparisonTuples(on, assocName) {
|
|
|
339
378
|
module.exports = {
|
|
340
379
|
remapODataAnnotations,
|
|
341
380
|
sealAnnoMagic,
|
|
381
|
+
stringifyAnnotationExpressions,
|
|
342
382
|
};
|
|
@@ -113,6 +113,7 @@ function effectiveCsn( model, options, messageFunctions ) {
|
|
|
113
113
|
options.remapOdataAnnotations ? annotations.remapODataAnnotations(csn) : {},
|
|
114
114
|
misc.removeDefinitionsAndProperties(csn, options),
|
|
115
115
|
options.deriveAnalyticalAnnotations ? annotations.sealAnnoMagic(csn) : {},
|
|
116
|
+
options.stringifyAnnoXpr ? annotations.stringifyAnnotationExpressions(csn, options, messageFunctions) : {},
|
|
116
117
|
], null);
|
|
117
118
|
|
|
118
119
|
if (options.addCdsPersistenceName) {
|
|
@@ -17,7 +17,7 @@ const validate = require('../checks/validator');
|
|
|
17
17
|
const { addTenantFields } = require('../transform/addTenantFields');
|
|
18
18
|
const { addLocalizationViewsWithJoins } = require('../transform/localized');
|
|
19
19
|
const { timetrace } = require('../utils/timetrace');
|
|
20
|
-
const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
|
|
20
|
+
const { createReferentialConstraints, createDraftAdminDataConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
|
|
21
21
|
const { setProp, forEach } = require('../utils/objectUtils');
|
|
22
22
|
const handleExists = require('./db/assocsToQueries/transformExists');
|
|
23
23
|
const { rewriteCalculatedElementsInViews, processCalculatedElementsInEntities } = require('./db/rewriteCalculatedElements');
|
|
@@ -340,6 +340,11 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
340
340
|
// no constraints for drafts
|
|
341
341
|
generateDrafts(csn, options, pathDelimiter, messageFunctions);
|
|
342
342
|
|
|
343
|
+
// the DraftAdministrativeData_DraftUUID foreign key still gets a cascade constraint;
|
|
344
|
+
// must run after generateDrafts, as the shadow tables don't exist before
|
|
345
|
+
if (options.sqlDialect !== 'plain' && options.sqlDialect !== 'h2')
|
|
346
|
+
createDraftAdminDataConstraints(csn, options);
|
|
347
|
+
|
|
343
348
|
// Set the final constraint paths and produce hana tc indexes if required
|
|
344
349
|
// See function comment for extensive information.
|
|
345
350
|
assertUnique.rewrite(csn, options, pathDelimiter);
|
|
@@ -24,6 +24,9 @@ function translateAssocsToJoinsCSN(csn, options) {
|
|
|
24
24
|
const compileOptions = { ...options, $skipNameCheck: true };
|
|
25
25
|
delete compileOptions.csnFlavor;
|
|
26
26
|
|
|
27
|
+
// DO NOT DELETE the `require('fs').writeFileSync(...)` lines in this function!
|
|
28
|
+
// Uncomment them to see the CSN input and output for A2J
|
|
29
|
+
// require('fs').writeFileSync('./a2j_in.csn', JSON.stringify(csn,null,2))
|
|
27
30
|
const model = recompileX(csn, compileOptions);
|
|
28
31
|
timetrace.stop('A2J: Recompiling model');
|
|
29
32
|
timetrace.start('A2J: Translating associations to joins');
|
|
@@ -49,7 +52,9 @@ function translateAssocsToJoinsCSN(csn, options) {
|
|
|
49
52
|
deduplicateMessages( options.messages );
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
const newCsn = compactModel(model, compileOptions);
|
|
56
|
+
// require('fs').writeFileSync('./a2j_out.csn', JSON.stringify(newCsn,null,2))
|
|
57
|
+
return newCsn;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
function translateAssocsToJoins(model, inputOptions = {}) {
|
|
@@ -610,8 +615,7 @@ function translateAssocsToJoins(model, inputOptions = {}) {
|
|
|
610
615
|
constructPathNode( [ tgtAlias, assoc.$flatTgtFKs[i] ] ) ],
|
|
611
616
|
});
|
|
612
617
|
}
|
|
613
|
-
|
|
614
|
-
return parenthesise((args.length > 1 ? { op: { val: 'and' }, args: [ ...args.map(parenthesise) ] } : args[0] ));
|
|
618
|
+
return parenthesise((args.length > 1 ? { op: { val: 'and' }, args } : args[0] ));
|
|
615
619
|
}
|
|
616
620
|
else if (assoc.on) {
|
|
617
621
|
if (env.assocStack === undefined) {
|
|
@@ -707,7 +711,7 @@ function translateAssocsToJoins(model, inputOptions = {}) {
|
|
|
707
711
|
|
|
708
712
|
function cloneOnCondExprStream(expr) {
|
|
709
713
|
const { args } = expr;
|
|
710
|
-
const result = { op: { val: expr.op.val }, args: [ ] };
|
|
714
|
+
const result = { op: { val: expr.op.val }, args: [ ], $parens: expr.$parens };
|
|
711
715
|
for (let i = 0; i < args.length; i++) {
|
|
712
716
|
const op = args[i].op?.val;
|
|
713
717
|
if (op === 'xpr' || op === 'ixpr' || op === 'nary') {
|
|
@@ -727,7 +731,7 @@ function translateAssocsToJoins(model, inputOptions = {}) {
|
|
|
727
731
|
args[i + 2].$check = false;
|
|
728
732
|
}
|
|
729
733
|
else {
|
|
730
|
-
result.args.push(createOnCondition(fwdAssoc, ...swapTableAliasesForFwdAssoc(fwdAssoc, srcAlias, tgtAlias)));
|
|
734
|
+
result.args.push(createOnCondition(backlinkOf(assoc, fwdAssoc), ...swapTableAliasesForFwdAssoc(fwdAssoc, srcAlias, tgtAlias)));
|
|
731
735
|
}
|
|
732
736
|
i += 2; // skip next two tokens and continue with loop
|
|
733
737
|
continue;
|
|
@@ -764,7 +768,7 @@ function translateAssocsToJoins(model, inputOptions = {}) {
|
|
|
764
768
|
return expr;
|
|
765
769
|
}
|
|
766
770
|
|
|
767
|
-
return createOnCondition(fwdAssoc, ...swapTableAliasesForFwdAssoc(fwdAssoc, srcAlias, tgtAlias));
|
|
771
|
+
return createOnCondition(backlinkOf(assoc, fwdAssoc), ...swapTableAliasesForFwdAssoc(fwdAssoc, srcAlias, tgtAlias));
|
|
768
772
|
}
|
|
769
773
|
|
|
770
774
|
// If this is an ordinary expression, clone it and mangle its arguments
|
|
@@ -1050,6 +1054,13 @@ function translateAssocsToJoins(model, inputOptions = {}) {
|
|
|
1050
1054
|
}
|
|
1051
1055
|
return undefined;
|
|
1052
1056
|
}
|
|
1057
|
+
|
|
1058
|
+
// Build the backlink ON from the renaming-aware `$backlink` rather than the
|
|
1059
|
+
// forward assoc's base-entity keys/on, if it is available.
|
|
1060
|
+
function backlinkOf( backlinkAssoc, fwdAssoc ) {
|
|
1061
|
+
const backlink = backlinkAssoc.$backlink;
|
|
1062
|
+
return backlink && (backlink.foreignKeys || backlink.on) ? backlink : fwdAssoc;
|
|
1063
|
+
}
|
|
1053
1064
|
} // createOnCondition
|
|
1054
1065
|
} // createJoinQA
|
|
1055
1066
|
|
|
@@ -1706,9 +1717,9 @@ function translateAssocsToJoins(model, inputOptions = {}) {
|
|
|
1706
1717
|
return newObj;
|
|
1707
1718
|
}
|
|
1708
1719
|
|
|
1720
|
+
// to-csn now auto-wraps AND args that are OR-terms (see json/to-csn.js `case 'and'`),
|
|
1721
|
+
// so A2J no longer needs to pre-wrap sub-expressions to preserve SQL precedence.
|
|
1709
1722
|
function parenthesise(expr) {
|
|
1710
|
-
if (typeof expr === 'object' && expr.op && expr.args)
|
|
1711
|
-
setProp(expr, '$parens', [ expr.$location ]);
|
|
1712
1723
|
return expr;
|
|
1713
1724
|
}
|
|
1714
1725
|
}
|
|
@@ -6,6 +6,57 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
8
8
|
|
|
9
|
+
## Version 4.0.3 - 2026-08-21
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `cds-mtx subscribe`, `unsubscribe`, and `upgrade` now take more than one tenant at once, e.g. `cds-mtx upgrade t1 t2` or `cds-mtx upgrade t1,t2`.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Login endpoints renamed to `/-/cds/login/grant` and `/-/cds/login/grant-metadata` with redirects from former paths.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- HANA credential health-check now detects the available driver via `require.resolve()` instead of reading `package.json`, fixing `MODULE_NOT_FOUND` for apps that follow the "Plug & Play" guidance and don't declare `hdb` or `@sap/hana-client` directly.
|
|
22
|
+
- Tenant upgrade now reports a clear per-tenant `422` error when a stored extension is incompatible with the changed base model, instead of aborting with an uncaught compilation error.
|
|
23
|
+
|
|
24
|
+
## Version 4.0.2 - 2026-08-07
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- `PUT /-/cds/extensibility/Extensions/<id>` with a status that is not active (0 or 1), now returns the correct entry.
|
|
29
|
+
- Extensions table is now resolved properly again when `cds.sql.names = quoted` is set.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- When updating from `@sap/cds-mtxs@<3.6.0`, you now need to upgrade your tenant database before you can add new extensions.
|
|
33
|
+
|
|
34
|
+
## Version 4.0.1 - 2026-06-23
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- Migration from `@sap/cds-mtx` has been removed.
|
|
39
|
+
- Annotation `@Common.FieldControl` is now also blocked for extensions.
|
|
40
|
+
- Annotations `@Capabilities.*` are now also blocked for extensions.
|
|
41
|
+
- The MTX sidecar now logs a warning if `cds.sql` is configured differently in both the project root and the sidecar. By setting `cds.env.requires['cds.xt.ModelProviderService']['use-root-sql-config'] === true`,
|
|
42
|
+
you can enforce the configuration of the project root.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- Default value 3 for `cds.requires.multitenancy.jobs.clusterSize` is now effective for upgrade. When using HANA TMS v2, the default for `clusterSize` is set to 1.
|
|
47
|
+
|
|
48
|
+
## Version 3.9.6 - 2026-08-07
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- Parallel single-tenant upgrades no longer fail with `tar: Cannot open: File exists` when extensibility is disabled.
|
|
53
|
+
- Deployment to tenant containers is more stable with a large number of service bindings provided via `VCAP_SERVICES_FILE_PATH`.
|
|
54
|
+
- More robust error handling for HDI deployment logs on read-only file system on Kyma.
|
|
55
|
+
- Configuration `cds.requires.multitenancy.retries` is now effective.
|
|
56
|
+
- Reading tenants no longer logs a spurious `Failed to parse metadata to JSON` error for tenants without metadata.
|
|
57
|
+
- A tenant's HANA connection pool now reliably recovers once valid credentials are restored, as cache-bypassing Service Manager lookups no longer overwrite the shared bindings cache with transiently invalid credentials.
|
|
58
|
+
- More robust handling of Service Manager errors.
|
|
59
|
+
|
|
9
60
|
## Version 3.9.5 - 2026-07-01
|
|
10
61
|
|
|
11
62
|
### Changed
|