@sap/cds 5.4.6 → 5.5.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 +208 -2
- package/apis/ql.d.ts +17 -15
- package/app/index.js +1 -1
- package/bin/build/buildTaskEngine.js +26 -42
- package/bin/build/buildTaskFactory.js +6 -10
- package/bin/build/buildTaskHandler.js +2 -4
- package/bin/build/buildTaskProvider.js +3 -1
- package/bin/build/buildTaskProviderFactory.js +9 -15
- package/bin/build/constants.js +15 -3
- package/bin/build/index.js +5 -4
- package/bin/build/mtaUtil.js +8 -11
- package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
- package/bin/build/provider/buildTaskProviderInternal.js +16 -42
- package/bin/build/provider/fiori/index.js +13 -24
- package/bin/build/provider/hana/2migration.js +17 -15
- package/bin/build/provider/hana/2tabledata.js +52 -48
- package/bin/build/provider/hana/index.js +27 -25
- package/bin/build/provider/hana/migrationtable.js +91 -67
- package/bin/build/provider/java-cf/index.js +14 -24
- package/bin/build/provider/mtx/index.js +12 -14
- package/bin/build/provider/node-cf/index.js +18 -32
- package/bin/cds.js +5 -5
- package/bin/serve.js +29 -23
- package/bin/version.js +0 -1
- package/lib/compile/etc/_localized.js +4 -9
- package/lib/compile/for/sql.js +5 -2
- package/lib/compile/parse.js +25 -17
- package/lib/compile/to/srvinfo.js +2 -1
- package/lib/connect/bindings.js +2 -1
- package/lib/connect/index.js +48 -49
- package/lib/core/classes.js +1 -1
- package/lib/core/reflect.js +10 -2
- package/lib/deploy.js +26 -23
- package/lib/env/defaults.js +13 -6
- package/lib/env/index.js +73 -78
- package/lib/env/requires.js +38 -19
- package/lib/index.js +9 -10
- package/lib/lazy.js +2 -2
- package/lib/log/index.js +33 -45
- package/lib/log/service/index.js +2 -2
- package/lib/ql/CREATE.js +14 -9
- package/lib/ql/DELETE.js +6 -5
- package/lib/ql/DROP.js +12 -9
- package/lib/ql/INSERT.js +40 -16
- package/lib/ql/Query.js +67 -40
- package/lib/ql/SELECT.js +162 -127
- package/lib/ql/UPDATE.js +74 -42
- package/lib/ql/Whereable.js +77 -87
- package/lib/ql/index.js +36 -24
- package/lib/ql/parse.js +35 -0
- package/lib/req/context.js +44 -8
- package/lib/req/locale.js +7 -7
- package/lib/serve/Service-api.js +21 -14
- package/lib/serve/Service-dispatch.js +28 -12
- package/lib/serve/Transaction.js +22 -10
- package/lib/serve/index.js +16 -11
- package/lib/utils/axios.js +23 -16
- package/lib/utils/data.js +35 -0
- package/lib/utils/tests.js +27 -18
- package/libx/_runtime/audit/generic/personal/access.js +81 -0
- package/libx/_runtime/audit/generic/personal/constants.js +4 -0
- package/libx/_runtime/audit/generic/personal/index.js +50 -0
- package/libx/_runtime/audit/generic/personal/modification.js +138 -0
- package/libx/_runtime/audit/generic/personal/utils.js +186 -0
- package/libx/_runtime/audit/utils/v2.js +10 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
- package/libx/_runtime/cds-services/services/Service.js +40 -5
- package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
- package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
- package/libx/_runtime/common/composition/data.js +44 -55
- package/libx/_runtime/common/composition/delete.js +97 -71
- package/libx/_runtime/common/composition/index.js +2 -1
- package/libx/_runtime/common/composition/insert.js +34 -11
- package/libx/_runtime/common/composition/tree.js +119 -92
- package/libx/_runtime/common/composition/update.js +4 -1
- package/libx/_runtime/common/composition/utils.js +1 -3
- package/libx/_runtime/common/constants/draft.js +12 -1
- package/libx/_runtime/common/generic/auth.js +6 -22
- package/libx/_runtime/common/generic/crud.js +14 -13
- package/libx/_runtime/common/generic/input.js +23 -26
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/sorting.js +16 -16
- package/libx/_runtime/common/i18n/index.js +1 -1
- package/libx/_runtime/common/i18n/messages.properties +4 -0
- package/libx/_runtime/common/utils/backlinks.js +12 -5
- package/libx/_runtime/common/utils/cqn.js +6 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
- package/libx/_runtime/common/utils/csn.js +47 -4
- package/libx/_runtime/common/utils/data.js +0 -37
- package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
- package/libx/_runtime/common/utils/generateOnCond.js +11 -12
- package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
- package/libx/_runtime/common/utils/path.js +35 -0
- package/libx/_runtime/common/utils/postProcessing.js +86 -0
- package/libx/_runtime/common/utils/quotingStyles.js +37 -26
- package/libx/_runtime/common/utils/resolveView.js +223 -171
- package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
- package/libx/_runtime/common/utils/structured.js +6 -12
- package/libx/_runtime/common/utils/template.js +10 -5
- package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
- package/libx/_runtime/common/utils/templateProcessor.js +22 -30
- package/libx/_runtime/common/utils/union.js +31 -0
- package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
- package/libx/_runtime/db/Service.js +1 -1
- package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
- package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
- package/libx/_runtime/db/expand/index.js +3 -3
- package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
- package/libx/_runtime/db/generic/index.js +1 -1
- package/libx/_runtime/db/generic/input.js +5 -7
- package/libx/_runtime/db/generic/integrity.js +1 -1
- package/libx/_runtime/db/generic/rewrite.js +2 -10
- package/libx/_runtime/db/generic/update.js +13 -5
- package/libx/_runtime/db/generic/virtual.js +22 -58
- package/libx/_runtime/db/query/delete.js +7 -4
- package/libx/_runtime/db/query/insert.js +6 -4
- package/libx/_runtime/db/query/read.js +13 -20
- package/libx/_runtime/db/query/run.js +4 -1
- package/libx/_runtime/db/query/update.js +5 -4
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
- package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
- package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
- package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
- package/libx/_runtime/db/utils/deep.js +8 -0
- package/libx/_runtime/db/utils/generateAliases.js +2 -1
- package/libx/_runtime/fiori/generic/activate.js +19 -15
- package/libx/_runtime/fiori/generic/before.js +3 -11
- package/libx/_runtime/fiori/generic/cancel.js +1 -1
- package/libx/_runtime/fiori/generic/delete.js +3 -1
- package/libx/_runtime/fiori/generic/edit.js +12 -2
- package/libx/_runtime/fiori/generic/new.js +5 -5
- package/libx/_runtime/fiori/generic/patch.js +0 -18
- package/libx/_runtime/fiori/generic/read.js +241 -189
- package/libx/_runtime/fiori/utils/delete.js +36 -7
- package/libx/_runtime/fiori/utils/handler.js +43 -44
- package/libx/_runtime/fiori/utils/where.js +30 -15
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
- package/libx/_runtime/hana/execute.js +2 -2
- package/libx/_runtime/hana/localized.js +4 -4
- package/libx/_runtime/hana/pool.js +29 -14
- package/libx/_runtime/hana/search2cqn4sql.js +2 -1
- package/libx/_runtime/hana/searchToContains.js +18 -14
- package/libx/_runtime/index.js +0 -5
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
- package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
- package/libx/_runtime/messaging/service.js +7 -6
- package/libx/_runtime/odata/cqn2odata.js +110 -43
- package/libx/_runtime/odata/index.js +26 -48
- package/libx/_runtime/odata/odata2cqn.js +1 -6154
- package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
- package/libx/_runtime/odata/readToCqn.js +94 -64
- package/libx/_runtime/remote/Service.js +74 -21
- package/libx/_runtime/remote/cqn2odata/index.js +1 -5
- package/libx/_runtime/remote/utils/client.js +24 -101
- package/libx/_runtime/remote/utils/dataConversion.js +27 -12
- package/libx/_runtime/sqlite/Service.js +3 -5
- package/libx/_runtime/sqlite/execute.js +23 -24
- package/libx/_runtime/sqlite/localized.js +12 -7
- package/libx/_runtime/types/api.js +10 -0
- package/package.json +1 -1
- package/server.js +16 -2
- package/lib/ql/grammar.pegjs +0 -208
- package/lib/ql/parser.js +0 -1
- package/lib/ql/rt/DELETE.js +0 -29
- package/lib/ql/rt/INSERT.js +0 -23
- package/lib/ql/rt/Query.js +0 -84
- package/lib/ql/rt/SELECT.js +0 -174
- package/lib/ql/rt/UPDATE.js +0 -119
- package/lib/ql/rt/_helpers.js +0 -91
- package/lib/ql/rt/index.js +0 -32
- package/libx/_runtime/audit/generic/personal.js +0 -260
- package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
- package/libx/_runtime/cds-services/statements/Create.js +0 -57
- package/libx/_runtime/cds-services/statements/Delete.js +0 -33
- package/libx/_runtime/cds-services/statements/Drop.js +0 -42
- package/libx/_runtime/cds-services/statements/Insert.js +0 -201
- package/libx/_runtime/cds-services/statements/Select.js +0 -826
- package/libx/_runtime/cds-services/statements/Update.js +0 -181
- package/libx/_runtime/cds-services/statements/Where.js +0 -726
- package/libx/_runtime/cds-services/statements/index.js +0 -25
- package/libx/_runtime/common/generic/resolve-mock.js +0 -9
package/lib/ql/rt/SELECT.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
const { CQL, CXL, cds, is_array, is_projection, is_function, _projection4, libx } = require('./_helpers')
|
|
2
|
-
const $ = Object.assign
|
|
3
|
-
|
|
4
|
-
// We'll extend and replace these below...
|
|
5
|
-
const SELECT = libx.SELECT.from('X').constructor
|
|
6
|
-
const select_columns = SELECT.prototype.columns
|
|
7
|
-
const select_where = SELECT.prototype.where
|
|
8
|
-
const select_having = SELECT.prototype.having
|
|
9
|
-
const select_groupBy = SELECT.prototype.groupBy
|
|
10
|
-
const select_orderBy = SELECT.prototype.orderBy
|
|
11
|
-
const select_limit = SELECT.prototype.limit
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
module.exports = cds.extend (SELECT) .with (class {
|
|
15
|
-
|
|
16
|
-
static from(..._) { return (this.new).from(..._) }
|
|
17
|
-
static _api() {
|
|
18
|
-
return $((..._) => (this.new)._select_or_from(..._), {
|
|
19
|
-
columns: (..._) => (this.new).columns(..._),
|
|
20
|
-
from: (..._) => (this.new).from(..._),
|
|
21
|
-
one: $((...x) => (this.new).one._select_or_from(...x),{
|
|
22
|
-
columns: (..._) => (this.new).one.columns(..._),
|
|
23
|
-
from: (..._) => (this.new).one.from(..._),
|
|
24
|
-
}),
|
|
25
|
-
distinct: $((...x) => (this.new).distinct._select_or_from(...x),{
|
|
26
|
-
columns: (..._) => (this.new).distinct.columns(..._),
|
|
27
|
-
from: (..._) => (this.new).distinct.from(..._),
|
|
28
|
-
}),
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
_select_or_from (cols, ...more) {
|
|
33
|
-
if (!cols) return this
|
|
34
|
-
else if (cols.name) return this.from (...arguments)
|
|
35
|
-
else if (is_function(cols)) return select_columns.call (this, _projection4 (cols, this.entity))
|
|
36
|
-
else if (is_array(cols)) return !cols[0] ? this : select_columns.call (this, cols)
|
|
37
|
-
else if (!isNaN(cols)) return select_columns.apply (this,arguments) //> numbers can't be from
|
|
38
|
-
else if (cols === '*') return select_columns.apply (this,arguments)
|
|
39
|
-
else if (cols.raw) {
|
|
40
|
-
let tts = [ ...cols ]; tts.raw = true //> because tt strings are sealed
|
|
41
|
-
if (tts[0].startsWith('from ')) { //> it's a from, with an arbitrary long CQL tail...
|
|
42
|
-
tts[0] = 'SELECT '+ tts[0]
|
|
43
|
-
let {SELECT} = CQL(tts, ...more)
|
|
44
|
-
Object.assign (this._, SELECT)
|
|
45
|
-
return this
|
|
46
|
-
} else if (tts[0].includes(':')) { //> it's a from (and needs to be handled, as it would become a cast instead)
|
|
47
|
-
return this.from (String.raw(...arguments))
|
|
48
|
-
} else if (tts[0][0] === '{') { //> it's a select
|
|
49
|
-
tts[0] = 'SELECT from X '+ tts[0]
|
|
50
|
-
let {SELECT} = CQL(tts, ...more)
|
|
51
|
-
return select_columns.call (this, SELECT.columns)
|
|
52
|
-
} else { //> still ambiguous...
|
|
53
|
-
tts[0] = 'SELECT from X { '+ tts[0]; tts[tts.length-1] += ' }'
|
|
54
|
-
let {SELECT:{columns:c}} = CQL(tts, ...more)
|
|
55
|
-
if (c.length > 1 || !c[0].ref) return select_columns.call (this, c)
|
|
56
|
-
else cols = c[0] //> goes on below...
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
else if (typeof cols === 'string' && cols.includes(':')) {
|
|
60
|
-
return select_columns.apply (this,arguments)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// it's still unclear whether it's a select or a from case
|
|
65
|
-
// -> return a proxy assuming it's a from and switching to
|
|
66
|
-
// columns on a subsequent call of .from, if any.
|
|
67
|
-
const {one} = this._
|
|
68
|
-
return Object.defineProperties (this.from(cols, ...more), {
|
|
69
|
-
from: {configurable:true,value:(..._) => {
|
|
70
|
-
delete this.from; delete this._.columns; delete this._.where
|
|
71
|
-
if (!one) delete this._.one
|
|
72
|
-
return this.from(..._).columns(cols, ...more)
|
|
73
|
-
}},
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
columns (cols, ...more) {
|
|
78
|
-
if (!cols) return this
|
|
79
|
-
if (is_function(cols)) return select_columns.call (this, _projection4 (cols, this.entity))
|
|
80
|
-
if (is_array(cols)) return !cols[0] ? this : select_columns.call (this, cols)
|
|
81
|
-
if (cols.raw) {
|
|
82
|
-
let tts = [ ...cols ]; tts.raw = true //> because tt strings are sealed
|
|
83
|
-
if (tts[0][0] === '{') {
|
|
84
|
-
tts[0] = 'SELECT from X '+ tts[0]
|
|
85
|
-
} else {
|
|
86
|
-
tts[0] = 'SELECT from X { '+ tts[0]
|
|
87
|
-
tts[tts.length-1] += ' }'
|
|
88
|
-
}
|
|
89
|
-
let {SELECT} = CQL(tts, ...more)
|
|
90
|
-
cols = SELECT.columns
|
|
91
|
-
}
|
|
92
|
-
return select_columns.call (this, cols, ...more)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
from (target, second, third) {
|
|
96
|
-
this._.from = target === '*' || this._target_ref4 (...arguments)
|
|
97
|
-
if (!target.raw && second) {
|
|
98
|
-
if (is_projection(second)) this.columns(second)
|
|
99
|
-
else this.byKey(second)
|
|
100
|
-
if (third) this.columns(third)
|
|
101
|
-
}
|
|
102
|
-
// REVISIT: compatibility with overly eager impl in cds-runtime
|
|
103
|
-
if (!this._.columns) this._addSelectColumns (target)
|
|
104
|
-
return this
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
limit (rows,offset) {
|
|
108
|
-
if (rows === undefined) return this
|
|
109
|
-
if (typeof rows === 'object') this._.limit = rows
|
|
110
|
-
else select_limit.call(this,rows,offset)
|
|
111
|
-
return this
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
get distinct() {
|
|
115
|
-
this._.distinct = true
|
|
116
|
-
return this
|
|
117
|
-
}
|
|
118
|
-
get one() {
|
|
119
|
-
this._.one = true
|
|
120
|
-
return this
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
redirectTo (entity) {
|
|
124
|
-
return this.clone().from(entity)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
expand (ref, cols, exp = 'expand') {
|
|
128
|
-
const { SELECT } = this,
|
|
129
|
-
columns = SELECT.columns || (SELECT.columns = [])
|
|
130
|
-
const col = { ref: ref.split('.'), [exp]: cols ? _projection4(cols) : ['*'] }
|
|
131
|
-
columns.push(col)
|
|
132
|
-
return this
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
inline (ref, cols) {
|
|
136
|
-
return this.expand(ref, cols, 'inline')
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
where(...args) {
|
|
140
|
-
if (!args[0]) return this
|
|
141
|
-
if (args[0].raw) args = [CXL(...args).xpr]
|
|
142
|
-
return select_where.apply(this,args)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
having(...args) {
|
|
146
|
-
if (args[0].raw) { this._.having = CXL(...args).xpr; return this }
|
|
147
|
-
return select_having.apply(this,args)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
groupBy (...args) {
|
|
151
|
-
if (args[0].raw) {
|
|
152
|
-
let tts = [ ...args ]; tts.raw = true //> because tt strings are sealed
|
|
153
|
-
tts[0] = 'SELECT from X group by '+ tts[0]
|
|
154
|
-
this._.groupBy = CQL(...tts).SELECT.groupBy
|
|
155
|
-
return this
|
|
156
|
-
}
|
|
157
|
-
return select_groupBy.apply(this,args)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
orderBy (...args) {
|
|
161
|
-
if (args[0].raw) {
|
|
162
|
-
let tts = [ ...args ]; tts.raw = true //> because tt strings are sealed
|
|
163
|
-
tts[0] = 'SELECT from X order by '+ tts[0]
|
|
164
|
-
this._.orderBy = CQL(...tts).SELECT.orderBy
|
|
165
|
-
return this
|
|
166
|
-
}
|
|
167
|
-
return select_orderBy.apply(this,args)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
foreach(callback) {
|
|
171
|
-
return this.then((rows) => rows.map(callback))
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
})
|
package/lib/ql/rt/UPDATE.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
const { CXL, cds, libx } = require('./_helpers')
|
|
2
|
-
const $ = Object.assign
|
|
3
|
-
|
|
4
|
-
// We'll extend and replace these below...
|
|
5
|
-
const UPDATE = libx.UPDATE('x').constructor
|
|
6
|
-
const update_where = UPDATE.prototype.where
|
|
7
|
-
const update_set = UPDATE.prototype.set
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module.exports = cds.extend (UPDATE) .with (class {
|
|
11
|
-
|
|
12
|
-
static _api() {
|
|
13
|
-
return $((..._) => (this.new).entity(..._), {
|
|
14
|
-
entity: (..._) => (this.new).entity(..._),
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
entity (target, key) {
|
|
19
|
-
this._.entity = this._target_name4 (...arguments)
|
|
20
|
-
if (key) this.byKey(key)
|
|
21
|
-
return this
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
with (...args) {
|
|
25
|
-
return this.set(...args)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
set (...args) { // NOSONAR
|
|
29
|
-
const {_} = this
|
|
30
|
-
|
|
31
|
-
// A tagged template string
|
|
32
|
-
if (args[0].raw) {
|
|
33
|
-
_add (CXL(...args).xpr, args[0].raw)
|
|
34
|
-
// for (let each of _comma_separated_exprs(String.raw(...args))) {
|
|
35
|
-
// _add (cds.parse.expr(each).xpr, each)
|
|
36
|
-
// }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Alternating expr fragment / values args...
|
|
40
|
-
else if (args.length > 1) {
|
|
41
|
-
for (let i = 0; i < args.length; ++i) {
|
|
42
|
-
const [, col, op] = /\s*([\w.]+)\s*([%*+-]?=)/.exec(args[i])
|
|
43
|
-
_add ([ {ref:[col]}, op, { val: args[++i] } ])
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// A single expression string
|
|
48
|
-
else if (typeof args[0] === 'string') {
|
|
49
|
-
for (let each of _comma_separated_exprs(args[0])) {
|
|
50
|
-
_add (cds.parse.expr(each).xpr, each)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// A column - value / expr object
|
|
55
|
-
else if (typeof args[0] === 'object') {
|
|
56
|
-
update_set.call(this, ...args)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return this
|
|
60
|
-
|
|
61
|
-
function _add (xpr, src) {
|
|
62
|
-
if (!xpr) throw new Error (`Invalid UPDATE.set expression: ${src}`)
|
|
63
|
-
const [lhs, op, ...rhs] = xpr
|
|
64
|
-
if (!lhs.ref) throw new Error (`Invalid left-hand-side for UPDATE.set expression: ${lhs}`)
|
|
65
|
-
const col = lhs.ref.join('.')
|
|
66
|
-
const v = (
|
|
67
|
-
op === '=' ? (rhs.length === 1 ? rhs[0] : { xpr: rhs }) :
|
|
68
|
-
op.length === 2 && op[1] === '=' ? { xpr: [ lhs, op[0], ...rhs] } :
|
|
69
|
-
cds.errror('Invalid operator in UPDATE.set expression: ' + op)
|
|
70
|
-
)
|
|
71
|
-
if (v.val) (_.data || (_.data={}))[col] = v.val
|
|
72
|
-
else (_.with || (_.with={}))[col] = v
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
where (...args) {
|
|
77
|
-
if (!args[0]) return this
|
|
78
|
-
if (args[0].raw) args = [CXL(...args).xpr]
|
|
79
|
-
return update_where.apply(this,args)
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
function _comma_separated_exprs(s) { // NOSONAR
|
|
85
|
-
let all = [],
|
|
86
|
-
start = 0,
|
|
87
|
-
scope = 0,
|
|
88
|
-
close = 0,
|
|
89
|
-
stack = [close]
|
|
90
|
-
for (let i = 0; i < s.length; ++i) {
|
|
91
|
-
const c = s[i]
|
|
92
|
-
if (c === ',' && !scope) {
|
|
93
|
-
all.push(s.slice(start, i))
|
|
94
|
-
start = i + 1
|
|
95
|
-
} else if (c === "'") {
|
|
96
|
-
while (i < s.length) {
|
|
97
|
-
if (s[++i] === "'") {
|
|
98
|
-
if (s[i + 1] === "'") ++i // NOSONAR
|
|
99
|
-
else break
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
} else if (c === '(') {
|
|
103
|
-
scope++
|
|
104
|
-
stack.unshift((close = ')'))
|
|
105
|
-
} else if (c === '[') {
|
|
106
|
-
scope++
|
|
107
|
-
stack.unshift((close = ']'))
|
|
108
|
-
} else if (c === '{') {
|
|
109
|
-
scope++
|
|
110
|
-
stack.unshift((close = '}'))
|
|
111
|
-
} else if (c === close) {
|
|
112
|
-
scope--
|
|
113
|
-
stack.shift()
|
|
114
|
-
close = stack[0]
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
all.push(s.slice(start))
|
|
118
|
-
return all
|
|
119
|
-
}
|
package/lib/ql/rt/_helpers.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
const is_projection = (x) => is_function(x) || is_array(x)
|
|
2
|
-
const is_function = (x) => typeof x === 'function'
|
|
3
|
-
const is_array = (x) => Array.isArray(x) && !x.raw
|
|
4
|
-
|
|
5
|
-
const cds = require('../../index')
|
|
6
|
-
const { CQL, CXL } = cds.parse
|
|
7
|
-
|
|
8
|
-
module.exports = {
|
|
9
|
-
libx: require('../../../libx/_runtime').statements,
|
|
10
|
-
is_projection, is_array, is_function,
|
|
11
|
-
_projection4, _predicate4,
|
|
12
|
-
CQL, CXL, cds,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/* eslint no-unused-vars: off */
|
|
17
|
-
function _projection4(x, entity) { // NOSONAR
|
|
18
|
-
if (!x || x === '*') return ['*']
|
|
19
|
-
if (is_projection(x[0])) x = x[0]
|
|
20
|
-
if (is_array(x)) return x.map((c) => (c.ref ? c : { ref: c.split('.') }))
|
|
21
|
-
if (typeof x === 'function') {
|
|
22
|
-
const columns = []
|
|
23
|
-
x(
|
|
24
|
-
new Proxy(x, {
|
|
25
|
-
// handle top-level projections or subselects such as
|
|
26
|
-
// (foo)=>{ foo('*'), foo(SELECT...).as('bar') }
|
|
27
|
-
apply: (_, __, args, ...more) => {
|
|
28
|
-
if (!args.length) args = ['*']
|
|
29
|
-
let [x] = is_array(args[0]) || args[0].raw ? args[0] : args
|
|
30
|
-
if (x === '.*') x = '*'
|
|
31
|
-
columns.push(x)
|
|
32
|
-
return { as: (alias) => (x.as = alias) }
|
|
33
|
-
},
|
|
34
|
-
// handle top-level paths like (foo)=>{ foo.bar }
|
|
35
|
-
get: (_, p) => {
|
|
36
|
-
const col = { ref: [p] }
|
|
37
|
-
columns.push(col)
|
|
38
|
-
const nested = new Proxy(x, {
|
|
39
|
-
// handle n-fold paths like (foo)=>{ foo.bar.car }
|
|
40
|
-
get: (_, p) => {
|
|
41
|
-
if (p === 'where') return (x) => ((col.where = _predicate4(x)), nested)
|
|
42
|
-
if (p === 'as') return (alias) => ((col.as = alias), nested)
|
|
43
|
-
else col.ref.push(p)
|
|
44
|
-
return nested
|
|
45
|
-
},
|
|
46
|
-
// handle nested projections e.g. (foo)=>{ foo.bar (b=>{ ... }) }
|
|
47
|
-
apply: (_, __, args) => {
|
|
48
|
-
const [a, b] = args
|
|
49
|
-
if (!a) col.expand = ['*']
|
|
50
|
-
else if (a.raw) {
|
|
51
|
-
if (a[0] === '*') col.expand = ['*']
|
|
52
|
-
else if (a[0] === '.*') col.inline = ['*']
|
|
53
|
-
else {
|
|
54
|
-
let tts = [...a] //> tts are sealed
|
|
55
|
-
tts[0] = 'SELECT '+ col.ref[col.ref.length-1] +' '+ tts[0]
|
|
56
|
-
tts[tts.length-1] += ' from X'
|
|
57
|
-
let {SELECT} = CQL(...tts)
|
|
58
|
-
Object.assign (col, SELECT.columns[0])
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else if (a === '*') col.expand = ['*']
|
|
62
|
-
else if (a === '.*') col.inline = ['*']
|
|
63
|
-
else {
|
|
64
|
-
let x = (col[/^\(?_\b/.test(a) ? 'inline' : 'expand'] = _projection4(args))
|
|
65
|
-
if (b && b.levels)
|
|
66
|
-
while (--b.levels) x.push({ ...col, expand: (x = [...x]) })
|
|
67
|
-
}
|
|
68
|
-
return nested
|
|
69
|
-
},
|
|
70
|
-
})
|
|
71
|
-
return nested
|
|
72
|
-
},
|
|
73
|
-
})
|
|
74
|
-
)
|
|
75
|
-
return columns
|
|
76
|
-
}
|
|
77
|
-
else throw new Error('SELECT w/ invalid projection argument: ' + JSON.stringify(x))
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Helper to create a predicate from a feather object
|
|
83
|
-
*/
|
|
84
|
-
function _predicate4 (o,...more) {
|
|
85
|
-
if (o.raw) return CXL(o,...more).xpr
|
|
86
|
-
const predicates = []
|
|
87
|
-
for (let each in o) {
|
|
88
|
-
predicates.push('and', { ref: each.split('.') }, '=', { val: o[each] })
|
|
89
|
-
}
|
|
90
|
-
return predicates.slice(1)
|
|
91
|
-
}
|
package/lib/ql/rt/index.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Monkey-patched cds.ql implementations from cds-runtime
|
|
2
|
-
module.exports = Object.assign (_deprecated_srv_ql, require('../../../libx/_runtime').statements, {
|
|
3
|
-
Query: require('./Query'),
|
|
4
|
-
SELECT: require('./SELECT')._api(),
|
|
5
|
-
INSERT: require('./INSERT')._api(),
|
|
6
|
-
UPDATE: require('./UPDATE')._api(),
|
|
7
|
-
DELETE: require('./DELETE')._api(),
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function _deprecated_srv_ql() {
|
|
12
|
-
// eslint-disable-next-line no-console
|
|
13
|
-
console.trace(`
|
|
14
|
-
Method 'srv.ql(req)' is deprecated and superceded by 'cds.context'.
|
|
15
|
-
Please use global SELECT instead of 'const { SELECT } = srv.ql(req)'.
|
|
16
|
-
`)
|
|
17
|
-
return module.exports
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const {cds} = global
|
|
22
|
-
if (cds.env.features.cls && cds.env.features.debug_queries) {
|
|
23
|
-
const { AsyncResource } = require('async_hooks')
|
|
24
|
-
const { Query } = module.exports
|
|
25
|
-
const { then } = Query.prototype
|
|
26
|
-
Object.defineProperty (Query,'then',{
|
|
27
|
-
get(){
|
|
28
|
-
const q = new AsyncResource('cds.Query')
|
|
29
|
-
return (r,e) => q.runInAsyncScope (then,this,r,e)
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
}
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
|
|
3
|
-
const getTemplate = require('../../common/utils/template')
|
|
4
|
-
const templateProcessor = require('../../common/utils/templateProcessor')
|
|
5
|
-
|
|
6
|
-
const WRITE = { CREATE: 1, UPDATE: 1, DELETE: 1 }
|
|
7
|
-
const ASPECTS = { CREATE: '_auditCreate', READ: '_auditRead', UPDATE: '_auditUpdate', DELETE: '_auditDelete' }
|
|
8
|
-
|
|
9
|
-
/*
|
|
10
|
-
* common
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const _getRootEntity = element => {
|
|
14
|
-
let entity = element.parent
|
|
15
|
-
while (entity.kind !== 'entity') entity = entity.parent
|
|
16
|
-
return entity
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// REVISIT: does this hash calc work for structured keys?
|
|
20
|
-
const _getHash = (entity, row) => {
|
|
21
|
-
return `${entity.name}(${Object.keys(entity.keys)
|
|
22
|
-
.map(k => `${k}=${row[k]}`)
|
|
23
|
-
.join(',')})`
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const _addObjectID = (log, row, key) => {
|
|
27
|
-
if (!log.dataObject.id.find(ele => ele.keyName === key)) log.dataObject.id.push({ keyName: key, value: row[key] })
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// REVISIT: better solution for data subject calculation
|
|
31
|
-
const _addDataSubject = (log, row, key, entity, element, model) => {
|
|
32
|
-
let target = entity
|
|
33
|
-
let prefix = ''
|
|
34
|
-
if (element['@odata.foreignKey4']) {
|
|
35
|
-
const assoc = entity.elements[element['@odata.foreignKey4']]
|
|
36
|
-
target = model.definitions[assoc.target]
|
|
37
|
-
prefix = assoc.name + '_'
|
|
38
|
-
}
|
|
39
|
-
if (!log.dataSubject.type) log.dataSubject.type = target.name
|
|
40
|
-
const keyName = key.replace(prefix, '')
|
|
41
|
-
if (!log.dataSubject.id.find(ele => ele.keyName === keyName)) {
|
|
42
|
-
const value = row[key] || (row._old && row._old[key])
|
|
43
|
-
log.dataSubject.id.push({ keyName, value })
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const _getPick = event => {
|
|
48
|
-
return (element, target) => {
|
|
49
|
-
if (!target[ASPECTS[event]]) return
|
|
50
|
-
|
|
51
|
-
const categories = []
|
|
52
|
-
if (!element.isAssociation && element.key) categories.push('ObjectID')
|
|
53
|
-
if (!element.isAssociation && element['@PersonalData.FieldSemantics'] === 'DataSubjectID')
|
|
54
|
-
categories.push('DataSubjectID')
|
|
55
|
-
if (event in WRITE && element['@PersonalData.IsPotentiallyPersonal']) categories.push('IsPotentiallyPersonal')
|
|
56
|
-
if (element['@PersonalData.IsPotentiallySensitive']) categories.push('IsPotentiallySensitive')
|
|
57
|
-
if (categories.length) return { categories }
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/*
|
|
62
|
-
* modification
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
const _getOldAndNew = (action, row, key, sensitive) => {
|
|
66
|
-
let oldValue = action === 'Create' ? null : row._old && row._old[key]
|
|
67
|
-
if (oldValue === undefined) oldValue = null
|
|
68
|
-
let newValue = action === 'Delete' ? null : row[key]
|
|
69
|
-
if (newValue === undefined) newValue = null
|
|
70
|
-
return { oldValue, newValue }
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const _processorFnModification = (modificationLogs, model) => {
|
|
74
|
-
return (row, key, element, plain) => {
|
|
75
|
-
if (!row._op) return
|
|
76
|
-
|
|
77
|
-
const entity = _getRootEntity(element)
|
|
78
|
-
|
|
79
|
-
const action = row._op[0].toUpperCase() + row._op.slice(1)
|
|
80
|
-
|
|
81
|
-
// create or augment log entry
|
|
82
|
-
const hash = _getHash(entity, row)
|
|
83
|
-
let modificationLog = modificationLogs[hash]
|
|
84
|
-
if (!modificationLog) {
|
|
85
|
-
modificationLogs[hash] = {
|
|
86
|
-
dataObject: { type: entity.name, id: [] },
|
|
87
|
-
dataSubject: { id: [], role: entity['@PersonalData.DataSubjectRole'] },
|
|
88
|
-
action,
|
|
89
|
-
attributes: []
|
|
90
|
-
}
|
|
91
|
-
modificationLog = modificationLogs[hash]
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// process categories
|
|
95
|
-
for (const category of plain.categories) {
|
|
96
|
-
if (category === 'ObjectID') {
|
|
97
|
-
_addObjectID(modificationLog, row, key)
|
|
98
|
-
} else if (category === 'DataSubjectID') {
|
|
99
|
-
_addDataSubject(modificationLog, row, key, entity, element, model)
|
|
100
|
-
} else if (category === 'IsPotentiallyPersonal') {
|
|
101
|
-
if (!modificationLog.attributes.find(ele => ele.name === key)) {
|
|
102
|
-
const { oldValue, newValue } = _getOldAndNew(action, row, key)
|
|
103
|
-
if (oldValue !== newValue) modificationLog.attributes.push({ name: key, oldValue, newValue })
|
|
104
|
-
}
|
|
105
|
-
} else if (category === 'IsPotentiallySensitive') {
|
|
106
|
-
if (!modificationLog.attributes.find(ele => ele.name === key)) {
|
|
107
|
-
const { oldValue, newValue } = _getOldAndNew(action, row, key, true)
|
|
108
|
-
if (oldValue !== newValue) modificationLog.attributes.push({ name: key, oldValue, newValue })
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const _getDataModificationLogs = async (data, req, tx) => {
|
|
116
|
-
const template = getTemplate(
|
|
117
|
-
`personal_${req.event}`.toLowerCase(),
|
|
118
|
-
Object.assign({ name: req.target._service.name, model: req._model }),
|
|
119
|
-
req.target,
|
|
120
|
-
{ pick: _getPick(req.event) }
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
const modificationLogs = {}
|
|
124
|
-
const processFn = _processorFnModification(modificationLogs, tx.model)
|
|
125
|
-
templateProcessor({ processFn, row: req._diff, template })
|
|
126
|
-
|
|
127
|
-
return modificationLogs
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/*
|
|
131
|
-
* access
|
|
132
|
-
*/
|
|
133
|
-
|
|
134
|
-
const _processorFnAccess = (accessLogs, model) => {
|
|
135
|
-
return (row, key, element, plain) => {
|
|
136
|
-
const entity = _getRootEntity(element)
|
|
137
|
-
|
|
138
|
-
// create or augment log entry
|
|
139
|
-
const hash = _getHash(entity, row)
|
|
140
|
-
let accessLog = accessLogs[hash]
|
|
141
|
-
if (!accessLog) {
|
|
142
|
-
accessLogs[hash] = {
|
|
143
|
-
dataObject: { type: entity.name, id: [] },
|
|
144
|
-
dataSubject: { id: [], role: entity['@PersonalData.DataSubjectRole'] },
|
|
145
|
-
attributes: [],
|
|
146
|
-
attachments: []
|
|
147
|
-
}
|
|
148
|
-
accessLog = accessLogs[hash]
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// process categories
|
|
152
|
-
for (const category of plain.categories) {
|
|
153
|
-
if (category === 'ObjectID') {
|
|
154
|
-
_addObjectID(accessLog, row, key)
|
|
155
|
-
} else if (category === 'DataSubjectID') {
|
|
156
|
-
_addDataSubject(accessLog, row, key, entity, element, model)
|
|
157
|
-
} else if (category === 'IsPotentiallySensitive') {
|
|
158
|
-
// add attribute
|
|
159
|
-
if (!accessLog.attributes.find(ele => ele.name === key)) accessLog.attributes.push({ name: key })
|
|
160
|
-
// REVISIT: attribute vs. attachment?
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const _getDataAccessLogs = (data, req, tx) => {
|
|
167
|
-
const template = getTemplate(
|
|
168
|
-
'personal_read',
|
|
169
|
-
Object.assign({ name: req.target._service.name, model: req._model }),
|
|
170
|
-
req.target,
|
|
171
|
-
{ pick: _getPick('READ') }
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
const accessLogs = {}
|
|
175
|
-
const processFn = _processorFnAccess(accessLogs, tx.model)
|
|
176
|
-
const data_ = Array.isArray(data) ? data : [data]
|
|
177
|
-
data_.forEach(row => {
|
|
178
|
-
templateProcessor({ processFn, row, template })
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
return accessLogs
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/*
|
|
185
|
-
* handler registration
|
|
186
|
-
*/
|
|
187
|
-
|
|
188
|
-
let als
|
|
189
|
-
|
|
190
|
-
/*
|
|
191
|
-
* Generic handlers for audit logging access to writing personal data
|
|
192
|
-
*/
|
|
193
|
-
|
|
194
|
-
const _attachDiffToContextHandler = async function (req) {
|
|
195
|
-
// REVISIT: what does this do?
|
|
196
|
-
Object.defineProperty(req.query, '_selectAll', {
|
|
197
|
-
enumerable: false,
|
|
198
|
-
writable: false,
|
|
199
|
-
configurable: true,
|
|
200
|
-
value: true
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
// attach to root request
|
|
204
|
-
req.context._diff = await req.diff()
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const _auditModificationHandler = async function (data, req) {
|
|
208
|
-
als = als || (await cds.connect.to('audit-log'))
|
|
209
|
-
if (!als.ready) return
|
|
210
|
-
|
|
211
|
-
const modificationLogs = await _getDataModificationLogs(data, req, this)
|
|
212
|
-
const modifications = Object.keys(modificationLogs)
|
|
213
|
-
.map(k => modificationLogs[k])
|
|
214
|
-
.filter(ele => ele.attributes.length)
|
|
215
|
-
|
|
216
|
-
if (modifications.length) await als.emit('dataModificationLog', { modifications })
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/*
|
|
220
|
-
* Generic handler for audit logging access to reading personal data
|
|
221
|
-
*/
|
|
222
|
-
|
|
223
|
-
const _auditAccessHandler = async function (data, req) {
|
|
224
|
-
als = als || (await cds.connect.to('audit-log'))
|
|
225
|
-
if (!als.ready) return
|
|
226
|
-
|
|
227
|
-
const accessLogs = await _getDataAccessLogs(data, req, this)
|
|
228
|
-
const accesses = Object.keys(accessLogs).map(k => accessLogs[k])
|
|
229
|
-
|
|
230
|
-
if (accesses.length) await als.emit('dataAccessLog', { accesses })
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
module.exports = function () {
|
|
234
|
-
/*
|
|
235
|
-
* data modification
|
|
236
|
-
*/
|
|
237
|
-
// REVISIT: diff() doesn't work in srv after phase but foreign key propagation has not yet taken place in srv before phase
|
|
238
|
-
// -> calc diff in db layer and attach to root request
|
|
239
|
-
// -> REVISIT for GA: clear req._.partialPersistentState?
|
|
240
|
-
_attachDiffToContextHandler._initial = true
|
|
241
|
-
for (const entity of Object.values(this.entities).filter(e => e._auditCreate)) {
|
|
242
|
-
cds.db.before('CREATE', entity, _attachDiffToContextHandler)
|
|
243
|
-
this.after('CREATE', entity, _auditModificationHandler)
|
|
244
|
-
}
|
|
245
|
-
for (const entity of Object.values(this.entities).filter(e => e._auditUpdate)) {
|
|
246
|
-
cds.db.before('UPDATE', entity, _attachDiffToContextHandler)
|
|
247
|
-
this.after('UPDATE', entity, _auditModificationHandler)
|
|
248
|
-
}
|
|
249
|
-
for (const entity of Object.values(this.entities).filter(e => e._auditDelete)) {
|
|
250
|
-
cds.db.before('DELETE', entity, _attachDiffToContextHandler)
|
|
251
|
-
this.after('DELETE', entity, _auditModificationHandler)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/*
|
|
255
|
-
* data access
|
|
256
|
-
*/
|
|
257
|
-
for (const entity of Object.values(this.entities).filter(e => e._auditRead)) {
|
|
258
|
-
this.after('READ', entity, _auditAccessHandler)
|
|
259
|
-
}
|
|
260
|
-
}
|