@sap/cds 6.7.2 → 6.8.2
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 +53 -1
- package/README.md +1 -0
- package/_i18n/i18n.properties +9 -6
- package/_i18n/i18n_ar.properties +6 -6
- package/_i18n/i18n_cs.properties +6 -6
- package/_i18n/i18n_da.properties +6 -6
- package/_i18n/i18n_de.properties +6 -6
- package/_i18n/i18n_en.properties +6 -6
- package/_i18n/i18n_es.properties +6 -6
- package/_i18n/i18n_fi.properties +6 -6
- package/_i18n/i18n_fr.properties +6 -6
- package/_i18n/i18n_hu.properties +6 -6
- package/_i18n/i18n_it.properties +6 -6
- package/_i18n/i18n_ja.properties +6 -6
- package/_i18n/i18n_ko.properties +6 -6
- package/_i18n/i18n_ms.properties +6 -6
- package/_i18n/i18n_nl.properties +6 -6
- package/_i18n/i18n_no.properties +6 -6
- package/_i18n/i18n_pl.properties +6 -6
- package/_i18n/i18n_pt.properties +6 -6
- package/_i18n/i18n_ro.properties +6 -6
- package/_i18n/i18n_ru.properties +6 -6
- package/_i18n/i18n_sv.properties +6 -6
- package/_i18n/i18n_th.properties +6 -6
- package/_i18n/i18n_tr.properties +8 -8
- package/_i18n/i18n_zh_CN.properties +3 -3
- package/_i18n/i18n_zh_TW.properties +6 -6
- package/apis/core.d.ts +30 -31
- package/apis/csn.d.ts +1 -1
- package/apis/ql.d.ts +69 -39
- package/apis/serve.d.ts +4 -3
- package/apis/services.d.ts +20 -7
- package/bin/build/buildTaskEngine.js +1 -1
- package/bin/build/index.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +9 -6
- package/bin/build/provider/hana/index.js +11 -4
- package/bin/build/provider/mtx-extension/index.js +13 -1
- package/bin/build/provider/mtx-sidecar/index.js +3 -3
- package/bin/build/provider/nodejs/index.js +23 -0
- package/bin/plugins.js +2 -1
- package/bin/version.js +3 -2
- package/common.cds +3 -2
- package/lib/auth/index.js +3 -0
- package/lib/auth/mocked-users.js +13 -0
- package/lib/compile/etc/_localized.js +3 -0
- package/lib/compile/for/lean_drafts.js +0 -1
- package/lib/core/entities.js +7 -3
- package/lib/dbs/cds-deploy.js +36 -12
- package/lib/env/cds-env.js +47 -14
- package/lib/env/cds-requires.js +16 -7
- package/lib/env/defaults.js +2 -2
- package/lib/env/schemas/cds-rc.json +1 -8
- package/lib/index.js +1 -1
- package/lib/ql/STREAM.js +89 -0
- package/lib/ql/cds-ql.js +2 -1
- package/lib/req/request.js +6 -2
- package/lib/req/user.js +1 -1
- package/lib/srv/middlewares/index.js +9 -7
- package/lib/srv/middlewares/trace.js +6 -5
- package/lib/srv/srv-api.js +1 -0
- package/lib/utils/cds-utils.js +1 -1
- package/lib/utils/tar.js +30 -31
- package/libx/_runtime/audit/Service.js +96 -37
- package/libx/_runtime/audit/generic/personal/utils.js +26 -13
- package/libx/_runtime/audit/utils/v2.js +21 -22
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/batch/BatchProcessor.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +10 -3
- package/libx/_runtime/cds-services/services/Service.js +2 -7
- package/libx/_runtime/cds-services/services/utils/differ.js +1 -1
- package/libx/_runtime/cds-services/util/assert.js +28 -5
- package/libx/_runtime/common/aspects/any.js +4 -1
- package/libx/_runtime/common/generic/auth/utils.js +30 -41
- package/libx/_runtime/common/generic/crud.js +1 -1
- package/libx/_runtime/common/i18n/messages.properties +1 -1
- package/libx/_runtime/common/utils/generateOnCond.js +18 -22
- package/libx/_runtime/db/expand/expandCQNToJoin.js +49 -41
- package/libx/_runtime/db/expand/rawToExpanded.js +3 -5
- package/libx/_runtime/db/generic/rewrite.js +3 -0
- package/libx/_runtime/db/utils/generateAliases.js +1 -1
- package/libx/_runtime/fiori/generic/activate.js +1 -1
- package/libx/_runtime/fiori/generic/before.js +18 -19
- package/libx/_runtime/fiori/generic/prepare.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +1 -1
- package/libx/_runtime/fiori/lean-draft.js +87 -53
- package/libx/_runtime/fiori/utils/handler.js +0 -6
- package/libx/_runtime/hana/customBuilder/CustomFunctionBuilder.js +1 -1
- package/libx/_runtime/hana/customBuilder/CustomReferenceBuilder.js +2 -1
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +0 -5
- package/libx/_runtime/hana/execute.js +18 -11
- package/libx/_runtime/hana/pool.js +26 -18
- package/libx/_runtime/hana/search2Contains.js +1 -1
- package/libx/_runtime/hana/search2cqn4sql.js +26 -18
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +23 -16
- package/libx/_runtime/messaging/outbox/utils.js +6 -1
- package/libx/_runtime/remote/Service.js +83 -48
- package/libx/_runtime/remote/utils/client.js +17 -19
- package/libx/_runtime/sqlite/execute.js +2 -0
- package/libx/rest/middleware/read.js +2 -1
- package/libx/rest/middleware/update.js +1 -1
- package/package.json +1 -1
|
@@ -54,7 +54,11 @@ const readAfterWrite = async (req, srv, { operation, isBefore } = { isBefore: fa
|
|
|
54
54
|
if (_isDraftAction(req)) query.where({ IsActiveEntity: req.event === 'draftActivate' })
|
|
55
55
|
} else if (req.event === 'NEW' || req.event === 'PATCH') {
|
|
56
56
|
const { result } = operation
|
|
57
|
-
|
|
57
|
+
if (req.query.UPDATE?.entity?.ref[0]?.where) {
|
|
58
|
+
query = SELECT.one(req.query.UPDATE.entity)
|
|
59
|
+
} else {
|
|
60
|
+
query = getSimpleSelectCQN(req.target, result)
|
|
61
|
+
}
|
|
58
62
|
} else if (req.event === 'UPDATE' && !hasDeepUpdate(srv.model, req.query)) {
|
|
59
63
|
query = Array.isArray(req.data) ? SELECT.from(req.query.UPDATE.entity) : SELECT.one(req.query.UPDATE.entity)
|
|
60
64
|
} else {
|
|
@@ -62,13 +66,14 @@ const readAfterWrite = async (req, srv, { operation, isBefore } = { isBefore: fa
|
|
|
62
66
|
}
|
|
63
67
|
Object.defineProperty(query.SELECT, '_4odata', { value: true })
|
|
64
68
|
_ensureKeysAreSelected(query)
|
|
69
|
+
|
|
65
70
|
// gracefully set location and no body if no read auth or not readable capability
|
|
66
71
|
let result
|
|
67
72
|
try {
|
|
68
73
|
const _req = new Request({ query, event: 'READ', _: req._, params: req.params })
|
|
69
74
|
result = await srv.dispatch(_req)
|
|
70
75
|
if (result && req.target._isDraftEnabled) removeDraftUUIDIfNecessary(req)(result)
|
|
71
|
-
if (result
|
|
76
|
+
if (result == null && !isBefore && (_isWriteWithResponse(req) || _isDraftAction(req))) {
|
|
72
77
|
// > something must be written and no READ error <=> @restrict or static where
|
|
73
78
|
_req.reject({
|
|
74
79
|
code: 404,
|
|
@@ -82,10 +87,12 @@ const readAfterWrite = async (req, srv, { operation, isBefore } = { isBefore: fa
|
|
|
82
87
|
_handleReadError(e, req)
|
|
83
88
|
result = null
|
|
84
89
|
}
|
|
90
|
+
|
|
85
91
|
// draft actions have own logic to set location header
|
|
86
|
-
if (result
|
|
92
|
+
if (result == null && _isWriteWithResponse(req) && !_isDraftAction(req)) {
|
|
87
93
|
setLocationHeader(req, srv)
|
|
88
94
|
}
|
|
95
|
+
|
|
89
96
|
return result
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -78,14 +78,9 @@ class ApplicationService extends cds.Service {
|
|
|
78
78
|
if (Array.isArray(data)) return data.map(d => _addIsActiveEntity(d, IsActiveEntity))
|
|
79
79
|
if (_key in data) data.IsActiveEntity = IsActiveEntity
|
|
80
80
|
}
|
|
81
|
-
this.on('READ', each, async (
|
|
81
|
+
this.on('READ', each, async (req, next) => {
|
|
82
82
|
const data = await next()
|
|
83
|
-
_addIsActiveEntity(data,
|
|
84
|
-
return data
|
|
85
|
-
})
|
|
86
|
-
this.on('READ', each, async (_, next) => {
|
|
87
|
-
const data = await next()
|
|
88
|
-
_addIsActiveEntity(data, false)
|
|
83
|
+
_addIsActiveEntity(data, !req.target?.isDraft)
|
|
89
84
|
return data
|
|
90
85
|
})
|
|
91
86
|
}
|
|
@@ -39,7 +39,7 @@ module.exports = class Differ {
|
|
|
39
39
|
_diffDelete(req) {
|
|
40
40
|
const { DELETE } = (req._ && req._.query) || req.query
|
|
41
41
|
const query = SELECT.from(DELETE.from).columns(this._createSelectColumnsForDelete(req.target))
|
|
42
|
-
if (DELETE.where) query.where(
|
|
42
|
+
if (DELETE.where) query.where(DELETE.where)
|
|
43
43
|
|
|
44
44
|
return cds
|
|
45
45
|
.tx(req)
|
|
@@ -112,10 +112,33 @@ const _checkISODateTime = value => (_checkString(value) && ISO_DATE_TIME_REGEX.t
|
|
|
112
112
|
|
|
113
113
|
const _checkISOTimestamp = value => (_checkString(value) && ISO_TIMESTAMP_REGEX.test(value)) || value instanceof Date
|
|
114
114
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
const _checkDateValue = (val, r1, r2) => {
|
|
116
|
+
const dateVal = new Date(val)
|
|
117
|
+
return (dateVal - new Date(r1)) * (dateVal - new Date(r2)) <= 0
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const _toDate = val => `2000-01-01T${val}Z`
|
|
121
|
+
|
|
122
|
+
const _checkInRange = (val, range, type) => {
|
|
123
|
+
switch (type) {
|
|
124
|
+
case 'cds.Date':
|
|
125
|
+
return _checkISODate(val) && _checkDateValue(val, range[0], range[1])
|
|
126
|
+
case 'cds.DateTime':
|
|
127
|
+
return _checkISODateTime(val) && _checkDateValue(val, range[0], range[1])
|
|
128
|
+
case 'cds.Timestamp':
|
|
129
|
+
return _checkISOTimestamp(val) && _checkDateValue(val, range[0], range[1])
|
|
130
|
+
case 'cds.Time':
|
|
131
|
+
return _checkISOTime(val) && _checkDateValue(_toDate(val), _toDate(range[0]), _toDate(range[1]))
|
|
132
|
+
default:
|
|
133
|
+
return (val - range[0]) * (val - range[1]) <= 0
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const _resolveCDSType = element => {
|
|
138
|
+
if (element.type.startsWith('cds.')) return element.type
|
|
139
|
+
if (!element.type) return
|
|
140
|
+
|
|
141
|
+
return _resolveCDSType(element.__proto__)
|
|
119
142
|
}
|
|
120
143
|
|
|
121
144
|
// process.env.CDS_ASSERT_FORMAT_FLAGS not official!
|
|
@@ -227,7 +250,7 @@ const _checkEnumElement = (element, value, errors, key, pathSegmentsInfo) => {
|
|
|
227
250
|
|
|
228
251
|
const _checkRangeElement = (element, value, errors, key, pathSegmentsInfo) => {
|
|
229
252
|
const rangeElements = element['@assert.range'] && !_getEnumElement(element) ? element['@assert.range'] : undefined
|
|
230
|
-
if (rangeElements && !_checkInRange(value, rangeElements)) {
|
|
253
|
+
if (rangeElements && !_checkInRange(value, rangeElements, _resolveCDSType(element))) {
|
|
231
254
|
const args = [value, ...element['@assert.range']]
|
|
232
255
|
errors.push(assertError({ code: ASSERT_RANGE, args }, element, value, key, pathSegmentsInfo))
|
|
233
256
|
}
|
|
@@ -40,11 +40,14 @@ const _relationHandler = relation => ({
|
|
|
40
40
|
if (newRelation) {
|
|
41
41
|
target[prop] = new Proxy(_exposeRelation(newRelation), _relationHandler(newRelation))
|
|
42
42
|
}
|
|
43
|
+
|
|
43
44
|
return target[prop]
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
+
|
|
47
|
+
target[prop] = path.reduce((relation, value) => relation[value] || relation.csn._relations[value], relation)
|
|
46
48
|
target[prop].path = path
|
|
47
49
|
}
|
|
50
|
+
|
|
48
51
|
return target[prop]
|
|
49
52
|
}
|
|
50
53
|
})
|
|
@@ -40,54 +40,51 @@ const _getCurrentSubClause = (next, restrict) => {
|
|
|
40
40
|
const escaped = next[0].replace(/\$/g, '\\$').replace(/\./g, '\\.')
|
|
41
41
|
const re1 = new RegExp(`([\\w\\.']*)\\s*=\\s*(${escaped})|(${escaped})\\s*=\\s*([\\w\\.']*)`)
|
|
42
42
|
const re2 = new RegExp(`([\\w\\.']*)\\s*in\\s*(${escaped})|(${escaped})\\s*in\\s*([\\w\\.']*)`)
|
|
43
|
-
const
|
|
43
|
+
const re3 = new RegExp(`(${escaped})\\s*is\\s*null`)
|
|
44
|
+
const re4 = new RegExp(`(${escaped})\\s*is\\s*not\\s*null`)
|
|
45
|
+
const clause =
|
|
46
|
+
restrict.where.match(re3) || restrict.where.match(re4) || restrict.where.match(re1) || restrict.where.match(re2)
|
|
44
47
|
|
|
45
48
|
if (clause) return clause
|
|
46
49
|
|
|
47
50
|
// NOTE: arrayed attr with "=" as operator is some kind of legacy case
|
|
48
|
-
throw new Error('user attribute array must be used with operator "=" or "
|
|
51
|
+
throw new Error('user attribute array must be used with operator "=", "in", "is null", or "is not null"')
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
const
|
|
54
|
+
const _isNull = (userAttrs, attr) =>
|
|
55
|
+
userAttrs[attr] == null || (Array.isArray(userAttrs[attr]) && userAttrs[attr].length === 0)
|
|
56
|
+
const _isNotNull = (userAttrs, attr) =>
|
|
57
|
+
userAttrs[attr] != null && Array.isArray(userAttrs[attr]) && userAttrs[attr].length > 0
|
|
58
|
+
|
|
59
|
+
const _processUserAttr = (next, restrict, userAttrs, attr) => {
|
|
52
60
|
const clause = _getCurrentSubClause(next, restrict)
|
|
53
61
|
const valOrRef = clause[1] || clause[4]
|
|
54
62
|
|
|
55
|
-
if (clause[0].match(/
|
|
56
|
-
|
|
63
|
+
if (clause[0].match(/ is\s*null/)) {
|
|
64
|
+
restrict.where = restrict.where.replace(clause[0], _isNull(userAttrs, attr) ? '1 = 1' : '1 = 2')
|
|
65
|
+
} else if (clause[0].match(/ is\s*not\s*null/)) {
|
|
66
|
+
restrict.where = restrict.where.replace(clause[0], _isNotNull(userAttrs, attr) ? '1 = 1' : '1 = 2')
|
|
67
|
+
} else {
|
|
68
|
+
if (_isNull(userAttrs, attr)) {
|
|
57
69
|
restrict.where = restrict.where.replace(clause[0], '1 = 2')
|
|
58
|
-
} else if (
|
|
59
|
-
|
|
70
|
+
} else if (clause[0].match(/ in /)) {
|
|
71
|
+
if (userAttrs[attr].length === 1) {
|
|
72
|
+
restrict.where = restrict.where.replace(clause[0], `${valOrRef} = '${userAttrs[attr][0]}'`)
|
|
73
|
+
} else {
|
|
74
|
+
restrict.where = restrict.where.replace(
|
|
75
|
+
clause[0],
|
|
76
|
+
`${valOrRef} in (${userAttrs[attr].map(ele => `'${ele}'`).join(', ')})`
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
} else if (valOrRef.startsWith("'") && userAttrs[attr].includes(valOrRef.split("'")[1])) {
|
|
80
|
+
restrict.where = restrict.where.replace(clause[0], `${valOrRef} = ${valOrRef}`)
|
|
60
81
|
} else {
|
|
61
82
|
restrict.where = restrict.where.replace(
|
|
62
83
|
clause[0],
|
|
63
|
-
|
|
84
|
+
`(${userAttrs[attr].map(ele => `${valOrRef} = '${ele}'`).join(' or ')})`
|
|
64
85
|
)
|
|
65
86
|
}
|
|
66
|
-
} else if (valOrRef.startsWith("'") && user[attr].includes(valOrRef.split("'")[1])) {
|
|
67
|
-
restrict.where = restrict.where.replace(clause[0], `${valOrRef} = ${valOrRef}`)
|
|
68
|
-
} else {
|
|
69
|
-
restrict.where = restrict.where.replace(
|
|
70
|
-
clause[0],
|
|
71
|
-
`(${user[attr].map(ele => `${valOrRef} = '${ele}'`).join(' or ')})`
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const _getShortcut = (attrs, attr) => {
|
|
77
|
-
// undefined
|
|
78
|
-
if (attrs[attr] === undefined) {
|
|
79
|
-
return '1 = 2'
|
|
80
87
|
}
|
|
81
|
-
|
|
82
|
-
// $UNRESTRICTED
|
|
83
|
-
if (
|
|
84
|
-
(typeof attrs[attr] === 'string' && attrs[attr].match(/\$UNRESTRICTED/i)) ||
|
|
85
|
-
(Array.isArray(attrs[attr]) && attrs[attr].some(a => a.match(/\$UNRESTRICTED/i)))
|
|
86
|
-
) {
|
|
87
|
-
return '1 = 1'
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return null
|
|
91
88
|
}
|
|
92
89
|
|
|
93
90
|
/*
|
|
@@ -120,15 +117,7 @@ const resolveUserAttrs = (restrict, req) => {
|
|
|
120
117
|
let attr = parts.shift()
|
|
121
118
|
|
|
122
119
|
while (attr) {
|
|
123
|
-
|
|
124
|
-
if (shortcut) {
|
|
125
|
-
const clause = _getCurrentSubClause(next, restrict)
|
|
126
|
-
restrict.where = restrict.where.replace(clause[0], shortcut)
|
|
127
|
-
skip = true
|
|
128
|
-
break
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (Array.isArray(attrs[attr])) {
|
|
120
|
+
if (attrs[attr] === undefined || Array.isArray(attrs[attr])) {
|
|
132
121
|
_processUserAttr(next, restrict, attrs, attr)
|
|
133
122
|
skip = true
|
|
134
123
|
break
|
|
@@ -43,6 +43,7 @@ exports.impl = cds.service.impl(function () {
|
|
|
43
43
|
// - INSERT has no where clause to do this in one roundtrip
|
|
44
44
|
// - SELECT returns [] -> really empty collection or invalid path?
|
|
45
45
|
let pathExistsQuery
|
|
46
|
+
|
|
46
47
|
const { ref } = (req.query.INSERT && req.query.INSERT.into) || (req.query.SELECT && req.query.SELECT.from) || {}
|
|
47
48
|
// REVISIT: why is copy necessary?
|
|
48
49
|
if (ref && ref.length > 1) pathExistsQuery = SELECT(1).from({ ref: deepCopyArray(ref.slice(0, -1)) })
|
|
@@ -59,7 +60,6 @@ exports.impl = cds.service.impl(function () {
|
|
|
59
60
|
|
|
60
61
|
// if no keys available, select all columns so we can delete the singleton with same content
|
|
61
62
|
if (keyColumns.length) selectSingleton.columns(keyColumns)
|
|
62
|
-
|
|
63
63
|
const singleton = await cds.tx(req).run(selectSingleton)
|
|
64
64
|
if (!singleton) req.reject(404)
|
|
65
65
|
|
|
@@ -85,7 +85,7 @@ CRUD_VIA_NAVIGATION_NOT_SUPPORTED=CRUD via navigations is not yet supported
|
|
|
85
85
|
|
|
86
86
|
# draft
|
|
87
87
|
DRAFT_ALREADY_EXISTS=A draft for this entity already exists
|
|
88
|
-
DRAFT_LOCKED_BY_ANOTHER_USER=The entity is locked by
|
|
88
|
+
DRAFT_LOCKED_BY_ANOTHER_USER=The entity is locked by user "{0}"
|
|
89
89
|
DRAFT_MODIFICATION_ONLY_VIA_ROOT=A draft can only be modified via its root entity
|
|
90
90
|
|
|
91
91
|
# singleton
|
|
@@ -8,6 +8,7 @@ const _toRef = (alias, column) => {
|
|
|
8
8
|
const _adaptRefs = (onCond, path, { select, join }) => {
|
|
9
9
|
const _adaptEl = el => {
|
|
10
10
|
const ref = el.ref
|
|
11
|
+
|
|
11
12
|
if (ref) {
|
|
12
13
|
if (ref[0] === path.join('_') && ref[1]) {
|
|
13
14
|
return _toRef(select, ref.slice(1))
|
|
@@ -19,41 +20,34 @@ const _adaptRefs = (onCond, path, { select, join }) => {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
return _toRef(join, ref.slice(0))
|
|
22
|
-
} else if (el.xpr) {
|
|
23
|
-
return { xpr: el.xpr.map(_adaptEl) }
|
|
24
23
|
}
|
|
25
24
|
|
|
25
|
+
if (el.xpr) return { xpr: el.xpr.map(_adaptEl) }
|
|
26
26
|
return el
|
|
27
27
|
}
|
|
28
|
+
|
|
28
29
|
return onCond.map(_adaptEl)
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const _args = (csnElement, path, aliases) => {
|
|
32
33
|
const onCond = csnElement.on
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
return []
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (onCond.length < 3) {
|
|
39
|
-
return onCond
|
|
40
|
-
}
|
|
41
|
-
|
|
34
|
+
if (!onCond || onCond.length === 0) return []
|
|
35
|
+
if (onCond.length < 3 && !onCond[0]?.xpr) return onCond
|
|
42
36
|
if (!csnElement._isSelfManaged) return _adaptRefs(onCond, path, aliases)
|
|
43
37
|
|
|
44
38
|
// revert join and select aliases because of backlink
|
|
45
|
-
const
|
|
39
|
+
const mutOnCond = _newOnConditions(csnElement._backlink, [csnElement._backlink.name], {
|
|
46
40
|
select: aliases.join,
|
|
47
41
|
join: aliases.select
|
|
48
42
|
})
|
|
49
43
|
|
|
50
44
|
if (onCond.some(e => e === 'and')) {
|
|
51
|
-
// managed with ON-conditions must contain `$self`, which we replace with `
|
|
52
|
-
const
|
|
53
|
-
|
|
45
|
+
// managed with ON-conditions must contain `$self`, which we replace with `mutOnCond`
|
|
46
|
+
const onCondWithoutSelf = _adaptRefs(_onCondWithout$self(onCond), path, aliases)
|
|
47
|
+
mutOnCond.push('and', ...onCondWithoutSelf)
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
return
|
|
50
|
+
return mutOnCond
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
const _isSelfRef = e => e && e.ref && e.ref[0] === '$self'
|
|
@@ -64,23 +58,27 @@ const _onCondWithout$self = onCond => {
|
|
|
64
58
|
if (e === 'and') return _isSelfRef(on[i + 1]) || _isSelfRef(on[i + 3])
|
|
65
59
|
return on[i + 1] === '=' && (_isSelfRef(e) || _isSelfRef(on[i + 2]))
|
|
66
60
|
})
|
|
61
|
+
|
|
67
62
|
onCondWithoutSelf.splice(selfIndex, 4)
|
|
68
63
|
return onCondWithoutSelf
|
|
69
64
|
}
|
|
70
65
|
|
|
66
|
+
// this is only for 2one managed w/o on-conditions, i.e. no static values are possible
|
|
71
67
|
const _foreignToOn = (csnElement, path, { select, join }) => {
|
|
72
|
-
// this is only for 2one managed w/o ON-conditions i.e. no static values are possible
|
|
73
68
|
const on = []
|
|
69
|
+
|
|
74
70
|
for (const key of csnElement._foreignKeys) {
|
|
75
71
|
if (on.length !== 0) {
|
|
76
72
|
on.push('and')
|
|
77
73
|
}
|
|
74
|
+
|
|
78
75
|
const prefixChild = prefixForStruct(key.childElement)
|
|
79
76
|
const ref1 = _toRef(select, prefixChild + key.childElement.name)
|
|
80
77
|
const structPrefix = path.length > 1 ? path.slice(0, -1) : []
|
|
81
78
|
const ref2 = _toRef(join, [...structPrefix, key.parentElement.name])
|
|
82
79
|
on.push(ref1, '=', ref2)
|
|
83
80
|
}
|
|
81
|
+
|
|
84
82
|
return on
|
|
85
83
|
}
|
|
86
84
|
|
|
@@ -93,10 +91,8 @@ const _newOnConditions = (csnElement, path, aliases) => {
|
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
const getOnCond = (csnElement, path = [], aliases = { select: '', join: '' }) => {
|
|
96
|
-
const
|
|
97
|
-
return [{ xpr:
|
|
94
|
+
const onCond = _newOnConditions(csnElement, path, aliases)
|
|
95
|
+
return [{ xpr: onCond }]
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
module.exports = {
|
|
101
|
-
getOnCond
|
|
102
|
-
}
|
|
98
|
+
module.exports = { getOnCond }
|