forked from cap-js/change-tracking
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcds-plugin.js
105 lines (92 loc) · 3.76 KB
/
cds-plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
const cds = require('@sap/cds')
const isChangeTracked = (entity) => (
(entity['@changelog']
|| entity.elements && Object.values(entity.elements).some(e => e['@changelog'])) && entity.query?.SET?.op !== 'union'
)
// Add the appropriate Side Effects attribute to the custom action
const addSideEffects = (actions, flag, element) => {
for (const se of Object.values(actions)) {
const target = flag ? 'TargetProperties' : 'TargetEntities'
const sideEffectAttr = se[`@Common.SideEffects.${target}`]
const property = flag ? 'changes' : { '=': `${element}.changes` }
if (sideEffectAttr?.length >= 0) {
sideEffectAttr.findIndex(
(item) =>
(item['='] ? item['='] : item) ===
(property['='] ? property['='] : property)
) === -1 && sideEffectAttr.push(property)
} else {
se[`@Common.SideEffects.${target}`] = [property]
}
}
}
// Unfold @changelog annotations in loaded model
cds.on('loaded', m => {
// Get definitions from Dummy entity in our models
const { 'sap.changelog.aspect': aspect } = m.definitions; if (!aspect) return // some other model
const { '@UI.Facets': [facet], elements: { changes } } = aspect
changes.on.pop() // remove ID -> filled in below
for (let name in m.definitions) {
const entity = m.definitions[name]
if (isChangeTracked(entity)) {
// Determine entity keys
const keys = [], { elements: elms } = entity
for (let e in elms) if (elms[e].key) keys.push(e)
// Add association to ChangeView...
const on = [...changes.on]; keys.forEach((k, i) => { i && on.push('||'); on.push({
ref: k === 'up_' ? [k,'ID'] : [k] // REVISIT: up_ handling is a dirty hack for now
})})
const assoc = { ...changes, on }
const query = entity.projection || entity.query?.SELECT
if (query) {
(query.columns ??= ['*']).push({ as: 'changes', cast: assoc })
} else {
entity.elements.changes = assoc
}
// Add UI.Facet for Change History List
entity['@UI.Facets']?.push(facet)
// The changehistory list should be refreshed after the custom action is triggered
if (entity.actions) {
// Update the changehistory list on the current entity when the custom action of the entity is triggered
if (entity['@UI.Facets']) {
addSideEffects(entity.actions, true)
}
// When the custom action of the child entity is performed, the change history list of the parent entity is updated
if (entity.elements) {
//ToDo: Revisit Breaklook with node.js Expert
breakLoop: for (const [ele, eleValue] of Object.entries(entity.elements)) {
const parentEntity = m.definitions[eleValue.target]
if (parentEntity && parentEntity['@UI.Facets'] && eleValue.type === 'cds.Association') {
for (const value of Object.values(parentEntity.elements)) {
if (value.target === name) {
addSideEffects(entity.actions, false, ele)
break breakLoop
}
}
}
}
}
}
}
}
})
// Add generic change tracking handlers
cds.on('served', () => {
const { track_changes, _afterReadChangeView } = require("./lib/change-log")
for (const srv of cds.services) {
if (srv instanceof cds.ApplicationService) {
let any = false
for (const entity of Object.values(srv.entities)) {
if (isChangeTracked(entity)) {
cds.db.before("CREATE", entity, track_changes)
cds.db.before("UPDATE", entity, track_changes)
cds.db.before("DELETE", entity, track_changes)
any = true
}
}
if (any && srv.entities.ChangeView) {
srv.after("READ", srv.entities.ChangeView, _afterReadChangeView)
}
}
}
})