@sap/cds 5.8.3 → 5.9.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 +193 -77
- package/app/fiori/preview.js +16 -11
- package/app/fiori/routes.js +15 -8
- package/app/index.js +1 -1
- package/bin/build/buildTaskFactory.js +3 -3
- package/bin/build/buildTaskProviderFactory.js +1 -1
- package/bin/build/constants.js +1 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
- package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +8 -2
- package/bin/build/provider/hana/2migration.js +27 -24
- package/bin/build/provider/hana/index.js +17 -18
- package/bin/build/provider/hana/migrationtable.js +9 -10
- package/bin/build/provider/java-cf/index.js +4 -5
- package/bin/build/provider/node-cf/index.js +99 -6
- package/bin/cds.js +17 -18
- package/bin/deploy/to-hana/cfUtil.js +16 -19
- package/bin/deploy/to-hana/hana.js +7 -24
- package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
- package/bin/mtx/in-cds.js +2 -2
- package/bin/serve.js +10 -3
- package/bin/utils/modules.js +7 -0
- package/bin/version.js +56 -3
- package/lib/compile/cdsc.js +7 -2
- package/lib/compile/etc/_localized.js +36 -25
- package/lib/compile/etc/csv.js +8 -8
- package/lib/compile/for/drafts.js +9 -0
- package/lib/compile/for/java.js +16 -0
- package/lib/compile/for/nodejs.js +12 -0
- package/lib/compile/index.js +3 -0
- package/lib/compile/minify.js +16 -2
- package/lib/compile/parse.js +2 -2
- package/lib/compile/resolve.js +35 -18
- package/lib/compile/to/json.js +3 -1
- package/lib/compile/to/sql.js +2 -2
- package/lib/compile/to/srvinfo.js +4 -2
- package/lib/connect/index.js +1 -1
- package/lib/core/entities.js +15 -14
- package/lib/core/index.js +39 -36
- package/lib/core/reflect.js +4 -2
- package/lib/deploy.js +114 -127
- package/lib/env/defaults.js +1 -0
- package/lib/env/index.js +165 -165
- package/lib/env/presets.js +1 -0
- package/lib/env/requires.js +120 -49
- package/lib/index.js +1 -0
- package/lib/log/format/kibana.js +2 -2
- package/lib/ql/SELECT.js +10 -0
- package/lib/ql/parse.js +1 -0
- package/lib/req/cds-context.js +4 -1
- package/lib/req/context.js +50 -56
- package/lib/req/event.js +1 -6
- package/lib/req/locale.js +6 -5
- package/lib/req/request.js +2 -0
- package/lib/req/user.js +7 -5
- package/lib/serve/Service-api.js +10 -7
- package/lib/serve/Service-dispatch.js +9 -11
- package/lib/serve/Service-methods.js +30 -41
- package/lib/serve/Transaction.js +10 -7
- package/lib/serve/adapters.js +7 -5
- package/lib/serve/index.js +24 -12
- package/lib/utils/data.js +1 -1
- package/lib/utils/index.js +27 -30
- package/lib/utils/resources/index.js +101 -0
- package/lib/utils/resources/tar.js +71 -0
- package/lib/utils/resources/utils.js +11 -0
- package/libx/_runtime/audit/Service.js +36 -39
- package/libx/_runtime/audit/generic/personal/access.js +3 -4
- package/libx/_runtime/audit/generic/personal/modification.js +3 -4
- package/libx/_runtime/audit/utils/v2.js +1 -2
- package/libx/_runtime/auth/index.js +126 -84
- package/libx/_runtime/auth/strategies/JWT.js +12 -19
- package/libx/_runtime/auth/strategies/dummy.js +1 -5
- package/libx/_runtime/auth/strategies/dwc.js +11 -9
- package/libx/_runtime/auth/strategies/mock.js +0 -4
- package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
- package/libx/_runtime/auth/utils.js +22 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +51 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
- package/libx/_runtime/cds-services/services/Service.js +40 -0
- package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
- package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
- package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
- package/libx/_runtime/cds-services/util/assert.js +20 -14
- package/libx/_runtime/cds.js +9 -1
- package/libx/_runtime/common/aspects/any.js +5 -0
- package/libx/_runtime/common/aspects/entity.js +25 -7
- package/libx/_runtime/common/aspects/utils.js +2 -2
- package/libx/_runtime/common/composition/data.js +6 -0
- package/libx/_runtime/common/composition/insert.js +3 -2
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +4 -4
- package/libx/_runtime/common/constants/draft.js +29 -26
- package/libx/_runtime/common/error/constants.js +2 -2
- package/libx/_runtime/common/error/frontend.js +7 -15
- package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
- package/libx/_runtime/common/generic/auth/constants.js +20 -0
- package/libx/_runtime/common/generic/auth/expand.js +54 -0
- package/libx/_runtime/common/generic/auth/index.js +32 -0
- package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
- package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
- package/libx/_runtime/common/generic/auth/requires.js +34 -0
- package/libx/_runtime/common/generic/auth/restrict.js +296 -0
- package/libx/_runtime/common/generic/auth/utils.js +213 -0
- package/libx/_runtime/common/generic/crud.js +14 -10
- package/libx/_runtime/common/generic/etag.js +1 -1
- package/libx/_runtime/common/generic/input.js +35 -35
- package/libx/_runtime/common/generic/sorting.js +2 -3
- package/libx/_runtime/common/generic/temporal.js +2 -2
- package/libx/_runtime/common/i18n/messages.properties +1 -1
- package/libx/_runtime/common/toggles/handler.js +21 -0
- package/libx/_runtime/common/utils/copy.js +10 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
- package/libx/_runtime/common/utils/csn.js +63 -1
- package/libx/_runtime/common/utils/dollar.js +10 -1
- package/libx/_runtime/common/utils/draft.js +46 -7
- package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
- package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
- package/libx/_runtime/common/utils/generateOnCond.js +5 -2
- package/libx/_runtime/common/utils/quotingStyles.js +2 -0
- package/libx/_runtime/common/utils/resolveStructured.js +25 -9
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
- package/libx/_runtime/common/utils/structured.js +33 -37
- package/libx/_runtime/common/utils/template.js +17 -8
- package/libx/_runtime/common/utils/templateProcessor.js +28 -28
- package/libx/_runtime/db/data-conversion/post-processing.js +118 -412
- package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
- package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
- package/libx/_runtime/db/generic/index.js +1 -3
- package/libx/_runtime/db/generic/input.js +5 -10
- package/libx/_runtime/db/generic/rewrite.js +5 -2
- package/libx/_runtime/db/generic/structured.js +2 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +1 -1
- package/libx/_runtime/db/query/update.js +9 -14
- package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +8 -8
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
- package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
- package/libx/_runtime/db/utils/columns.js +3 -3
- package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
- package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
- package/libx/_runtime/extensibility/mps/index.js +5 -0
- package/libx/_runtime/extensibility/mps/service.js +111 -0
- package/libx/_runtime/extensibility/mps/tar.js +42 -0
- package/libx/_runtime/extensibility/mps/utils.js +11 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
- package/libx/_runtime/extensibility/uiflex/index.js +54 -0
- package/libx/_runtime/extensibility/uiflex/service.js +276 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +4 -4
- package/libx/_runtime/fiori/generic/new.js +3 -3
- package/libx/_runtime/fiori/generic/patch.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +58 -66
- package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
- package/libx/_runtime/fiori/utils/handler.js +6 -13
- package/libx/_runtime/fiori/utils/where.js +6 -5
- package/libx/_runtime/hana/Service.js +4 -10
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +1 -1
- package/libx/_runtime/hana/driver.js +2 -2
- package/libx/_runtime/hana/execute.js +27 -74
- package/libx/_runtime/hana/pool.js +1 -1
- package/libx/_runtime/hana/streaming.js +2 -1
- package/libx/_runtime/index.js +6 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
- package/libx/_runtime/messaging/Outbox.js +2 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
- package/libx/_runtime/messaging/common-utils/connections.js +5 -7
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
- package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
- package/libx/_runtime/messaging/file-based.js +5 -5
- package/libx/_runtime/messaging/message-queuing.js +14 -12
- package/libx/_runtime/messaging/outbox/utils.js +18 -19
- package/libx/_runtime/messaging/redis-messaging.js +91 -0
- package/libx/_runtime/messaging/service.js +8 -6
- package/libx/_runtime/remote/Service.js +44 -8
- package/libx/_runtime/remote/utils/client.js +24 -19
- package/libx/_runtime/remote/utils/data.js +11 -11
- package/libx/_runtime/sqlite/Service.js +6 -9
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
- package/libx/_runtime/types/api.js +10 -2
- package/libx/common/utils/ucsn.js +109 -0
- package/libx/gql/resolvers/crud/update.js +5 -0
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
- package/libx/gql/schema/typeDefMap.js +2 -2
- package/libx/odata/afterburner.js +110 -16
- package/libx/odata/cqn2odata.js +24 -27
- package/libx/odata/grammar.pegjs +9 -1
- package/libx/odata/parseToCqn.js +39 -0
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +9 -1
- package/libx/rest/middleware/input.js +54 -0
- package/libx/rest/middleware/operation.js +14 -1
- package/libx/rest/middleware/parse.js +11 -7
- package/package.json +2 -2
- package/server.js +34 -19
- package/srv/audit-log.cds +2 -2
- package/srv/flex.cds +8 -2
- package/srv/flex.js +1 -1
- package/srv/mps.cds +23 -0
- package/srv/mps.js +1 -0
- package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
- package/libx/_runtime/common/generic/auth.js +0 -874
- package/libx/_runtime/common/toggles/alpha.js +0 -43
- package/libx/_runtime/db/generic/arrayed.js +0 -33
- package/libx/_runtime/fiori/uiflex/index.js +0 -35
- package/libx/_runtime/fiori/uiflex/service.js +0 -150
- package/libx/rest/utils/data.js +0 -60
package/lib/compile/resolve.js
CHANGED
|
@@ -2,6 +2,7 @@ const { resolve, join, sep } = require('path')
|
|
|
2
2
|
const { readdirSync } = require('fs')
|
|
3
3
|
const suffixes = [ '.csn', '.cds', sep+'index.csn', sep+'index.cds', sep+'csn.json' ]
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
/**
|
|
6
7
|
* Resolves given model references to an array of absolute filenames.
|
|
7
8
|
* For the model references, all these are accepted:
|
|
@@ -16,18 +17,20 @@ module.exports = exports = function cds_resolve (model, o={}) { // NOSONAR
|
|
|
16
17
|
|
|
17
18
|
if (!model || model === '--') return
|
|
18
19
|
if (model._resolved) return model
|
|
19
|
-
if (model === '*') return
|
|
20
|
-
if (Array.isArray(model))
|
|
21
|
-
[... new Set(model)] .reduce ((prev,next) => prev.concat (this.resolve(next,o)||[]), [])
|
|
22
|
-
|
|
20
|
+
if (model === '*') return _resolve_all(o,this)
|
|
21
|
+
if (Array.isArray(model)) {
|
|
22
|
+
const resolved = [... new Set(model)] .reduce ((prev,next) => prev.concat (this.resolve(next,o)||[]), [])
|
|
23
|
+
return o.dry || o === false ? resolved : _resolved (resolved)
|
|
24
|
+
}
|
|
25
|
+
if (model.endsWith('/*')) return _resolve_subdirs_in(model,o,this)
|
|
23
26
|
|
|
24
|
-
const cwd = o.root ||
|
|
27
|
+
const cwd = o.root || this.root, local = resolve (cwd,model)
|
|
25
28
|
const context = _paths(cwd), {cached} = context
|
|
26
29
|
let id = model.startsWith('.') ? local : model
|
|
27
|
-
if (id in cached
|
|
30
|
+
if (id in cached) return cached[id]
|
|
28
31
|
|
|
29
32
|
// expand @sap/cds by cds.home
|
|
30
|
-
if (id.startsWith('@sap/cds/')) id =
|
|
33
|
+
if (id.startsWith('@sap/cds/')) id = this.home + id.slice(8)
|
|
31
34
|
|
|
32
35
|
// fetch file with .cds/.csn suffix as is
|
|
33
36
|
if (/\.(csn|cds)$/.test(id)) try {
|
|
@@ -58,27 +61,41 @@ module.exports = exports = function cds_resolve (model, o={}) { // NOSONAR
|
|
|
58
61
|
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
|
|
61
65
|
exports.cache = {}
|
|
62
66
|
|
|
63
67
|
|
|
68
|
+
const _required = cds => Object.values(cds.env.requires) .map (r => r.model) .filter(x=>x)
|
|
64
69
|
const _resolve = require('module')._resolveFilename
|
|
65
70
|
|
|
66
|
-
function _resolve_all (cds
|
|
67
|
-
const {roots
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
function _resolve_all (o,cds) {
|
|
72
|
+
const {roots} = cds.env; if (o.dry || o === false) return [ ...roots, ..._required(cds) ]
|
|
73
|
+
const cached = exports.cache['*']; if (cached) return cached
|
|
74
|
+
exports.cache['*'] = [] // important to avoid endless recursion on '*'
|
|
75
|
+
const sources = cds.resolve (roots,o) || []
|
|
76
|
+
if (!(sources.length === 1 && sources[0].endsWith('csn.json'))) // REVISIT: why is that? -> pre-compiled gen/csn.json?
|
|
77
|
+
sources.push (...cds.resolve (_required(cds),o)||[])
|
|
78
|
+
return exports.cache['*'] = _resolved (sources)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function _resolve_subdirs_in (pattern='fts/*',o,cds) {
|
|
82
|
+
const cached = exports.cache[pattern]; if (cached && !o.dry && o !== false) return cached
|
|
83
|
+
const folder = pattern.slice(0,-2), dir = resolve (cds.root, folder)
|
|
84
|
+
try {
|
|
85
|
+
const dirs = readdirSync(dir) .map (e => folder+'/'+e+'/') .filter (cds.utils.isdir)
|
|
86
|
+
if (o.dry || o === false) return dirs
|
|
87
|
+
return exports.cache[pattern] = cds.resolve (dirs,o) || undefined
|
|
88
|
+
} catch(e) {
|
|
89
|
+
if (e.code === 'ENOENT')
|
|
90
|
+
return exports.cache[pattern] = undefined
|
|
91
|
+
}
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
function _paths (dir) {
|
|
78
|
-
const
|
|
95
|
+
const cached = exports.cache[dir]; if (cached) return cached
|
|
79
96
|
const a = dir.split(sep), n = a.length, nm = sep+'node_modules'
|
|
80
97
|
const paths = [ dir, ...a.map ((_,i,a)=> a.slice(0,n-i).join(sep)+nm) ]
|
|
81
|
-
return cache[dir] = { paths, cached:{} }
|
|
98
|
+
return exports.cache[dir] = { paths, cached:{} }
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
function _resolved (array) {
|
package/lib/compile/to/json.js
CHANGED
|
@@ -8,12 +8,14 @@ module.exports = (csn,o={}) => JSON.stringify (csn, (_,v) => {
|
|
|
8
8
|
|
|
9
9
|
else if (v.grant && v.where) try {
|
|
10
10
|
// Add a parsed _where clause for @restrict.{grant,where} annotations
|
|
11
|
+
// Note: This has moved to cds.compile.for.java meanwhile, but is kept
|
|
12
|
+
// here for compatibility, at least temporarily.
|
|
11
13
|
return {...v, _where: JSON.stringify (cds.parse.xpr(v.where)) }
|
|
12
14
|
} catch(e){/* ignored */}
|
|
13
15
|
|
|
14
16
|
else if (v.kind === "service" && !v['@source'] && v.$location && v.$location.file) {
|
|
15
17
|
// Preserve original sources for services so we can use them for finding
|
|
16
|
-
// sibling implementation
|
|
18
|
+
// sibling implementation files when reloaded from csn.json.
|
|
17
19
|
const file = (o.cwd !== o.src) ? path.relative(o.src, path.join(o.cwd, v.$location.file)) : v.$location.file
|
|
18
20
|
return { '@source': file.replace(/\\/g,'/'), ...v }
|
|
19
21
|
}
|
package/lib/compile/to/sql.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const cds = require ('../..')
|
|
1
|
+
const cds = require ('../..')
|
|
2
2
|
const cdsc = require ('../cdsc')
|
|
3
3
|
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ function cds_compile_to_sql (csn,_o) {
|
|
|
6
6
|
csn = _extended(cds.minify(csn))
|
|
7
7
|
const o = cdsc._options.for.sql(_o) //> used twice below...
|
|
8
8
|
const all = cdsc.to.sql(csn,o) .map (each => each.replace(/^-- .+\n/,'')) //> strip comments
|
|
9
|
-
const sql =
|
|
9
|
+
const sql = cds.compile._localized.unfold_ddl(all, csn, o)
|
|
10
10
|
if (o.as === 'str') return `\n${sql.join('\n\n')}\n`
|
|
11
11
|
return sql
|
|
12
12
|
}
|
|
@@ -74,8 +74,10 @@ module.exports = (model, options={}) => {
|
|
|
74
74
|
if (file) {
|
|
75
75
|
const yaml = cds.load.yaml(file)
|
|
76
76
|
for (let {cds} of Array.isArray(yaml) ? yaml : [yaml]) {
|
|
77
|
-
if (cds
|
|
78
|
-
|
|
77
|
+
if (!cds) continue
|
|
78
|
+
return cds['odataV4.endpoint.path'] || cds['odataV2.endpoint.path'] // https://cap.cloud.sap/docs/java/application-services#configure-base-path
|
|
79
|
+
|| cds['odata-v4.endpoint.path'] || cds['odata-v2.endpoint.path'] // older/intermediate config, keep for backward compatibility
|
|
80
|
+
|
|
79
81
|
}
|
|
80
82
|
return 'odata/v4/'
|
|
81
83
|
}
|
package/lib/connect/index.js
CHANGED
|
@@ -38,7 +38,7 @@ connect.to = async (datasource, options) => {
|
|
|
38
38
|
// check if required service definition exists
|
|
39
39
|
const required = cds.requires[datasource]
|
|
40
40
|
if (required && required.model && datasource !== 'db' && !m.definitions[required.service||datasource]) {
|
|
41
|
-
LOG.
|
|
41
|
+
LOG.error(`No service definition found for '${required.service || datasource}', as required by 'cds.requires.${datasource}':`, required)
|
|
42
42
|
throw new Error (`No service definition found for '${required.service || datasource}'`)
|
|
43
43
|
}
|
|
44
44
|
// construct new service instance
|
package/lib/core/entities.js
CHANGED
|
@@ -34,23 +34,24 @@ class Association extends type {
|
|
|
34
34
|
return !c || c.max === 1 || (!c.max && !c.targetMax) || c.targetMax === 1
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
set
|
|
38
|
-
get
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
set foreignKeys(k) { this.set('foreignKeys', k) }
|
|
38
|
+
get foreignKeys() {
|
|
39
|
+
const keys = this.keys; if (!keys) return this.foreignKeys = undefined
|
|
40
|
+
const foreignKeys = {}
|
|
41
|
+
for (const k of keys) {
|
|
42
|
+
const el = k.ref.reduce((target,n)=> target.elements[n], this._target)
|
|
43
|
+
const as = k.as || k.ref[k.ref.length-1]
|
|
44
|
+
foreignKeys [as] = el
|
|
45
|
+
}
|
|
46
|
+
return this.foreignKeys = foreignKeys
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
set
|
|
47
|
-
get
|
|
48
|
-
if (this.
|
|
49
|
-
|
|
50
|
-
const keys = [],
|
|
51
|
-
tks = this._target.keys
|
|
49
|
+
set keys(k) { super.keys = k }
|
|
50
|
+
get keys() {
|
|
51
|
+
if (this.on || this.is2many || !this._target) return this._keys = undefined
|
|
52
|
+
const keys=[], tks = this._target.keys
|
|
52
53
|
for (let k in tks) keys.push({ ref: [tks[k].name] })
|
|
53
|
-
return
|
|
54
|
+
return this.keys = keys
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
package/lib/core/index.js
CHANGED
|
@@ -8,8 +8,9 @@ const classes = Object.assign (
|
|
|
8
8
|
require('./entities'),
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
/** Type system roots -> can be used with instanceof */
|
|
13
|
+
const roots = _roots ({
|
|
13
14
|
context: {},
|
|
14
15
|
type: {},
|
|
15
16
|
scalar: {type:'type'},
|
|
@@ -27,9 +28,28 @@ const roots = _bootstrap ({
|
|
|
27
28
|
service: {type:'context'},
|
|
28
29
|
})
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Turns the given CSN definitions into linked definitions with classes.
|
|
33
|
+
* @type <T>(csn:T) => T
|
|
34
|
+
*/
|
|
35
|
+
function _roots (defs) {
|
|
36
|
+
const linked = { any: classes.any.prototype }
|
|
37
|
+
for (const t in defs) {
|
|
38
|
+
if (t in classes) {
|
|
39
|
+
linked[t] = classes[t].prototype
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
const c = class extends classes[defs[t].type || 'any'] {}
|
|
43
|
+
linked[t] = Object.defineProperty (c.prototype, 'name', {value:t})
|
|
44
|
+
classes[t] = Object.defineProperty (c, 'name', {value:t})
|
|
45
|
+
}
|
|
46
|
+
return linked
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/** Construct builtin.types as dictionary of all roots and common types */
|
|
51
|
+
const types = _common ({ __proto__: roots,
|
|
52
|
+
UUID: {type:'string',length:36,isUUID:true},
|
|
33
53
|
Boolean: {type:'boolean'},
|
|
34
54
|
Integer: {type:'number'},
|
|
35
55
|
Integer16: {type:'Integer'},
|
|
@@ -47,41 +67,24 @@ const common = { __proto__:roots,
|
|
|
47
67
|
Binary: {type:'string'},
|
|
48
68
|
LargeString: {type:'string'},
|
|
49
69
|
LargeBinary: {type:'string'},
|
|
50
|
-
}
|
|
70
|
+
})
|
|
51
71
|
|
|
52
72
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
73
|
+
* Link all definitions, essentially by: d.__proto__ = resolved (d.type),
|
|
74
|
+
* and prefixes all common types with a namespace 'cds'.
|
|
75
|
+
* @type <T>(csn:T) => T & roots
|
|
55
76
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
77
|
+
function _common (defs) {
|
|
78
|
+
const prefixed = {__proto__:defs}
|
|
79
|
+
for (let [name,d] of Object.entries(defs)) {
|
|
80
|
+
defs[name] = Object.defineProperty({ ...d, __proto__: defs[d.type] }, 'name', {value:name})
|
|
81
|
+
Object.defineProperty (prefixed['cds.'+name] = defs[name], '_type', {value:'cds.'+name})
|
|
82
|
+
}
|
|
83
|
+
for (let name of ['Association','Composition']) {
|
|
84
|
+
Object.defineProperty (prefixed['cds.'+name] = defs[name], '_type', {value:'cds.'+name})
|
|
85
|
+
}
|
|
86
|
+
return prefixed
|
|
61
87
|
}
|
|
62
88
|
|
|
63
|
-
// Prefix all common types with a namespace 'cds'
|
|
64
|
-
for (let t of Object.keys(common)) types['cds.'+t] = types[t]
|
|
65
|
-
types['cds.Association'] = types.Association
|
|
66
|
-
types['cds.Composition'] = types.Composition
|
|
67
89
|
|
|
68
90
|
module.exports = { types, classes }
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Turns the given CSN definitions into linked definitions.
|
|
73
|
-
* @type <T>(csn:T) => T
|
|
74
|
-
*/
|
|
75
|
-
function _bootstrap (csn) {
|
|
76
|
-
const defs = { any: classes.any.prototype }
|
|
77
|
-
for (const t in csn) {
|
|
78
|
-
if (t in classes) {
|
|
79
|
-
defs[t] = classes[t].prototype
|
|
80
|
-
continue
|
|
81
|
-
}
|
|
82
|
-
const c = class extends classes[csn[t].type || 'any'] {}
|
|
83
|
-
defs[t] = Object.defineProperty(c.prototype, 'name', { value: t })
|
|
84
|
-
classes[t] = Object.defineProperty(c, 'name', { value: t })
|
|
85
|
-
}
|
|
86
|
-
return defs
|
|
87
|
-
}
|
package/lib/core/reflect.js
CHANGED
|
@@ -95,7 +95,7 @@ class LinkedCSN extends any {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
const _unresolved = (x,unknown=any) => ({name:x, __proto__:unknown.prototype, _unresolved:true})
|
|
98
|
+
const _unresolved = (x,unknown=any) => ({ name:x, __proto__:unknown.prototype, _unresolved:true })
|
|
99
99
|
const _builtin = x => types[x] || typeof x === 'string' && x.startsWith('cds.hana.') && any.prototype
|
|
100
100
|
const _infer = require('./infer'), _not_inferred = _unresolved('<query>',entity)
|
|
101
101
|
const _set = (o,p,v) => Object.defineProperty (o,p,{value:v,enumerable:false,configurable:1,writable:1})
|
|
@@ -107,4 +107,6 @@ const _is = x => {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/** @returns {LinkedCSN} */
|
|
110
|
-
module.exports = x => x instanceof any ? x : new LinkedCSN(
|
|
110
|
+
module.exports = x => x instanceof any ? x : new LinkedCSN (
|
|
111
|
+
typeof x === 'string' ? global.cds.parse(x) : x
|
|
112
|
+
)
|
package/lib/deploy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const cds = require('./index'), { local } = cds.utils
|
|
1
|
+
const cds = require('./index'), { local, inspect } = cds.utils
|
|
2
2
|
const DEBUG = cds.debug('deploy')
|
|
3
|
-
|
|
3
|
+
/* eslint-disable no-console */
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Implementation of `cds.deploy` common to all databases.
|
|
@@ -11,8 +11,8 @@ let LOG
|
|
|
11
11
|
exports = module.exports = function cds_deploy (model,options) { return {
|
|
12
12
|
|
|
13
13
|
/** @param {cds.Service} db */
|
|
14
|
-
async to (db, o=options||{}) {
|
|
15
|
-
LOG = cds.log('deploy')
|
|
14
|
+
async to (db, o = options || cds.options || {}) {
|
|
15
|
+
const LOG = o.silent || !cds.log('deploy')._info ? ()=>{} : console.log
|
|
16
16
|
|
|
17
17
|
if (model && !model.definitions) {
|
|
18
18
|
model = await cds.load (model) .then (cds.minify)
|
|
@@ -31,25 +31,22 @@ exports = module.exports = function cds_deploy (model,options) { return {
|
|
|
31
31
|
if (!cds.db) cds.db = cds.services.db = db
|
|
32
32
|
if (!db.model) db.model = model
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
34
|
+
// create tables & views...
|
|
35
|
+
const any = await exports.create (db,model,o)
|
|
36
|
+
if (!any) return db
|
|
38
37
|
|
|
39
38
|
// fill in initial data...
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const {credentials} = db.options, file =
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
else console.log (`/> successfully deployed to sqlite in-memory db\n`)
|
|
49
|
-
}
|
|
50
|
-
|
|
39
|
+
await exports.init (db,model, file => LOG(
|
|
40
|
+
`\x1b[2m > init from ${local(file)} \x1b[0m`
|
|
41
|
+
))
|
|
42
|
+
|
|
43
|
+
// done
|
|
44
|
+
const {credentials:c} = db.options, file = c && (c.database || c.url)
|
|
45
|
+
if (file !== ':memory:') LOG (`/> successfully deployed to ./${file}\n`)
|
|
46
|
+
else LOG (`/> successfully deployed to sqlite in-memory db\n`)
|
|
51
47
|
return db
|
|
52
48
|
},
|
|
49
|
+
|
|
53
50
|
// continue to support cds.deploy() as well...
|
|
54
51
|
then(n,e) { return this.to (cds.db||'db') .then (n,e) },
|
|
55
52
|
catch(e) { return this.to (cds.db||'db') .catch (e) },
|
|
@@ -57,9 +54,10 @@ exports = module.exports = function cds_deploy (model,options) { return {
|
|
|
57
54
|
|
|
58
55
|
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
const { fs, path, isdir, isfile, read } = cds.utils
|
|
57
|
+
const { fs, path, read } = cds.utils
|
|
62
58
|
const { readdir } = fs.promises
|
|
59
|
+
const isdir = (..._) => fs.isdir(path.join(..._))
|
|
60
|
+
const isfile = (..._) => fs.isfile(path.join(..._))
|
|
63
61
|
|
|
64
62
|
exports.include_external_entities_in = function (model) {
|
|
65
63
|
if (model._mocked) return model; else Object.defineProperty(model,'_mocked',{value:true})
|
|
@@ -101,125 +99,114 @@ exports.exclude_external_entities_in = function (csn) { // NOSONAR
|
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return Promise.all (inits)
|
|
102
|
+
exports.create = async function (db, csn=db.model, o) {
|
|
103
|
+
if (!db.deploy || o.lean) {
|
|
104
|
+
const creates = cds.compile.to.sql (csn,o); if (!creates || creates.length === 0) return
|
|
105
|
+
const drops = creates.map (each => {
|
|
106
|
+
let [, kind, entity] = each.match(/^CREATE (TABLE|VIEW) "?([^\s"(]+)/im) || []
|
|
107
|
+
return `DROP ${kind} IF EXISTS ${entity};`
|
|
108
|
+
}).reverse()
|
|
109
|
+
if (o.dry) {
|
|
110
|
+
console.log(); for (let each of drops) console.log(each)
|
|
111
|
+
console.log(); for (let each of creates) console.log(each,'\n')
|
|
112
|
+
return
|
|
113
|
+
} else await db.tx (async tx => {
|
|
114
|
+
await tx.run(drops)
|
|
115
|
+
await tx.run(creates)
|
|
116
|
+
return true
|
|
117
|
+
})
|
|
118
|
+
} else return db.deploy (csn,o)
|
|
122
119
|
}
|
|
123
120
|
|
|
124
|
-
function init_from_csv (db, csn, SILENT) {
|
|
125
|
-
return init_from_ (['data','csv'], _csvs, db, csn, SILENT, (entity, src) => {
|
|
126
|
-
let [ cols, ...rows ] = cds.parse.csv (src)
|
|
127
|
-
return rows && rows[0] && INSERT.into (entity) .columns (cols) .rows (rows)
|
|
128
|
-
});
|
|
129
121
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
122
|
+
exports.init = (db, csn=db.model, log=()=>{}) => db.tx (async tx => {
|
|
123
|
+
cds.context = tx //> registers tx as root transaction
|
|
124
|
+
const resources = await exports.resources(csn), inits=[], err = new Error
|
|
125
|
+
for (let [file,e] of Object.entries(resources)) {
|
|
126
|
+
if (e === '*') { // init.js/ts
|
|
127
|
+
const x = require(file); if (!x) continue
|
|
128
|
+
log (file)
|
|
129
|
+
inits.push (!x.then && typeof x === 'function' ? x(db) : x)
|
|
130
|
+
} else { // from .csv or .json
|
|
131
|
+
const INSERT_into = _from_csv_or_json [path.extname(file)]
|
|
132
|
+
const src = await read(file,'utf8'); if (!src) continue
|
|
133
|
+
const q = INSERT_into (e,src); if (!q) continue
|
|
134
|
+
log (file,e)
|
|
135
|
+
inits.push (tx.run(q) .catch (e => { throw Object.assign (e,{
|
|
136
|
+
message: 'in cds.deploy(): ' + e.message +'\n'+ inspect(q),
|
|
137
|
+
})}))
|
|
138
|
+
}
|
|
134
139
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
await Promise.all (inits)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
exports.resources = async function (csn) {
|
|
145
|
+
if (!csn || !csn.definitions) csn = await cds.load (csn||'*') .then (cds.minify)
|
|
146
|
+
const folders = await exports.resources.folders(csn)
|
|
147
|
+
const found={}, ts = process.env.CDS_TYPESCRIPT
|
|
148
|
+
for (let folder of folders) {
|
|
149
|
+
// fetching init.js files
|
|
150
|
+
const init_js = ts && isfile(folder,'init.ts') || isfile(folder,'init.js')
|
|
151
|
+
if (init_js) found[init_js] = '*'
|
|
152
|
+
// fetching .csv and .json files
|
|
153
|
+
for (let each of ['data','csv']) {
|
|
154
|
+
const subdir = isdir(folder,each); if (!subdir) continue
|
|
155
|
+
const files = await readdir (subdir)
|
|
156
|
+
for (let fx of files) {
|
|
157
|
+
if (fx[0] === '-') continue
|
|
158
|
+
const ext = path.extname(fx); if (ext in _from_csv_or_json) {
|
|
159
|
+
const f = fx.slice(0,-ext.length)
|
|
160
|
+
if (/[._]texts$/.test(f) && files.some(g => g.startsWith(f+'_'))) {
|
|
161
|
+
// ignores 'Books_texts.csv/json' if there is any 'Books_texts_LANG.csv/json'
|
|
162
|
+
DEBUG && DEBUG (`ignoring '${fx}' in favor of translated ones`); continue
|
|
163
|
+
}
|
|
164
|
+
const e = _entity4(f,csn); if (_skip(e)) continue
|
|
165
|
+
found[path.join(subdir,fx)] = e.name
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
147
169
|
}
|
|
170
|
+
return found
|
|
148
171
|
}
|
|
149
172
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (translated.length > 0) {
|
|
158
|
-
DEBUG && DEBUG (`ignoring '${file}' in favor of [${translated}]`) // eslint-disable-line
|
|
159
|
-
return true
|
|
160
|
-
}
|
|
161
|
-
}
|
|
173
|
+
|
|
174
|
+
exports.resources.folders = async function (csn) {
|
|
175
|
+
if (!csn || !csn.definitions) csn = await cds.load (csn||'*') .then (cds.minify)
|
|
176
|
+
const folders = new Set (csn.$sources.map (path.dirname) .filter (f => f !== cds.home))
|
|
177
|
+
if (cds.env.folders.db) folders.add (path.resolve(cds.root, cds.env.folders.db))
|
|
178
|
+
if (cds.env.features.test_data) folders.add (path.resolve(cds.root,'test/'))
|
|
179
|
+
return folders
|
|
162
180
|
}
|
|
163
181
|
|
|
164
|
-
async function init_from_ (locations, filter, db, csn, SILENT, INSERT_into) { // NOSONAR
|
|
165
182
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
183
|
+
const _entity4 = (file,csn) => {
|
|
184
|
+
const name = file.replace(/-/g,'.')
|
|
185
|
+
const entity = csn.definitions [name]
|
|
186
|
+
if (!entity) {
|
|
187
|
+
if (/(.+)[._]texts_?/.test(name)) { // 'Books.texts', 'Books.texts_de'
|
|
188
|
+
const base = csn.definitions [RegExp.$1]
|
|
189
|
+
return base && _entity4 (base.elements.texts.target,csn)
|
|
172
190
|
}
|
|
191
|
+
else return DEBUG && DEBUG (`warning: ${name} not in model`)
|
|
173
192
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
193
|
+
// We also support insert into simple views if they have no projection
|
|
194
|
+
const p = entity.query && entity.query.SELECT || entity.projection
|
|
195
|
+
if (p && !p.columns && p.from.ref && p.from.ref.length === 1) {
|
|
196
|
+
if (csn.definitions [p.from.ref[0]]) return entity
|
|
179
197
|
}
|
|
198
|
+
return entity.name ? entity : { name, __proto__:entity }
|
|
199
|
+
}
|
|
180
200
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
for (let folder of folders) {
|
|
186
|
-
const files = await readdir (folder)
|
|
187
|
-
for (let each of files.filter (filter)) {
|
|
188
|
-
let name = each.replace(/-/g,'.').slice(0, -path.extname(each).length)
|
|
189
|
-
let entity = _entity4 (name)
|
|
190
|
-
if (!entity) { DEBUG && DEBUG (`warning: ${name} not in model`); continue }
|
|
191
|
-
if (entity['@cds.persistence.skip'] === true) continue
|
|
192
|
-
const file = path.join(folder,each)
|
|
193
|
-
const src = await read (file,'utf8'); if (!src) continue
|
|
194
|
-
const q = INSERT_into (entity,src)
|
|
195
|
-
if (!q) { DEBUG && DEBUG (`skipping empty ${local(file)}`); continue }
|
|
196
|
-
SILENT || console.log (`\x1b[2m > filling ${entity.name} from ${local(file)} \x1b[0m`) // eslint-disable-line
|
|
197
|
-
inits.push (tx.run(q).catch(e=>{ const ex = new Error
|
|
198
|
-
e.stack = e.message +'\n'+ require('util').inspect(q) + err.stack.slice(5)
|
|
199
|
-
.replace (/deploy\.js:\d+:/, ex.stack.slice(5).match(/deploy\.js:\d+:/)[0])
|
|
200
|
-
throw e
|
|
201
|
-
}))
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
await Promise.all(inits)
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
function _entity4 (name) {
|
|
208
|
-
let entity = csn.definitions [name]
|
|
209
|
-
if (!entity) {
|
|
210
|
-
if (/(.+)[._]texts_?/.test (name)) { // 'Books.texts', 'Books.texts_de'
|
|
211
|
-
const base = csn.definitions [RegExp.$1]
|
|
212
|
-
return base && _entity4 (base.elements.texts.target)
|
|
213
|
-
}
|
|
214
|
-
else return
|
|
215
|
-
}
|
|
216
|
-
// We also support insert into simple views if they have no projection
|
|
217
|
-
const p = entity.query && entity.query.SELECT || entity.projection
|
|
218
|
-
if (p && !p.columns && p.from.ref && p.from.ref.length === 1) {
|
|
219
|
-
if (csn.definitions [p.from.ref[0]]) return entity
|
|
220
|
-
}
|
|
221
|
-
return entity.name ? entity : { name, __proto__:entity }
|
|
222
|
-
}
|
|
201
|
+
const INSERT_from_csv = (entity, csv) => {
|
|
202
|
+
let [ cols, ...rows ] = cds.parse.csv (csv)
|
|
203
|
+
if (rows.length > 0) return INSERT.into (entity) .columns (cols) .rows (rows)
|
|
204
|
+
}
|
|
223
205
|
|
|
206
|
+
const INSERT_from_json = (entity, json) => {
|
|
207
|
+
let records = JSON.parse (json)
|
|
208
|
+
if (records.length > 0) return INSERT.into (entity) .entries (records)
|
|
224
209
|
}
|
|
225
|
-
|
|
210
|
+
|
|
211
|
+
const _from_csv_or_json = { '.json': INSERT_from_json, '.csv': INSERT_from_csv, }
|
|
212
|
+
const _skip = e => !e || e['@cds.persistence.skip'] === true
|
package/lib/env/defaults.js
CHANGED
|
@@ -6,6 +6,7 @@ module.exports = {
|
|
|
6
6
|
requires: require('./requires'),
|
|
7
7
|
|
|
8
8
|
features: {
|
|
9
|
+
folders: 'fts/*', // where to find feature toggles -> switch on by default when released
|
|
9
10
|
cls: major > 12 || major == 12 && minor >= 18,
|
|
10
11
|
live_reload: !production,
|
|
11
12
|
fiori_preview: !production,
|