Skip to content

Commit 12c983c

Browse files
danjoankaputnik
andauthored
Adjusted to support multitenancy (#141)
Co-authored-by: Nick Josipovic <[email protected]>
1 parent f505e97 commit 12c983c

File tree

1 file changed

+72
-49
lines changed

1 file changed

+72
-49
lines changed

cds-plugin.js

Lines changed: 72 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
const cds = require('@sap/cds')
2+
const DEBUG = cds.debug('changelog')
23

34
const isRoot = 'change-tracking-isRootEntity'
45
const hasParent = 'change-tracking-parentEntity'
56

6-
const isChangeTracked = (entity) => (
7-
(entity['@changelog']
8-
|| entity.elements && Object.values(entity.elements).some(e => e['@changelog'])) && entity.query?.SET?.op !== 'union'
9-
)
7+
const isChangeTracked = (entity) => {
8+
if (entity.query?.SET?.op === 'union') return false // REVISIT: should that be an error or warning?
9+
if (entity['@changelog']) return true
10+
if (Object.values(entity.elements).some(e => e['@changelog'])) return true
11+
}
1012

1113
// Add the appropriate Side Effects attribute to the custom action
1214
const addSideEffects = (actions, flag, element) => {
@@ -139,57 +141,72 @@ function findParentAssociation (entity, csn, elements) {
139141
})
140142
}
141143

144+
145+
146+
/**
147+
* Returns an expression for the key of the given entity, which we can use as the right-hand-side of an ON condition.
148+
*/
149+
function entityKey4 (entity) {
150+
const xpr = []
151+
for (let k in entity.elements) {
152+
const e = entity.elements[k]; if (!e.key) continue
153+
if (xpr.length) xpr.push('||')
154+
if (e.type === 'cds.Association') xpr.push({ ref: [k, e.keys?.[0]?.ref?.[0]] })
155+
else xpr.push({ ref:[k] })
156+
}
157+
return xpr
158+
}
159+
160+
142161
// Unfold @changelog annotations in loaded model
143-
cds.on('loaded', m => {
162+
function enhanceModel (m) {
163+
164+
const _enhanced = 'sap.changelog.enhanced'
165+
if (m.meta?.[_enhanced]) return // already enhanced
144166

145167
// Get definitions from Dummy entity in our models
146168
const { 'sap.changelog.aspect': aspect } = m.definitions; if (!aspect) return // some other model
147169
const { '@UI.Facets': [facet], elements: { changes } } = aspect
148-
changes.on.pop() // remove ID -> filled in below
170+
if (changes.on.length > 2) changes.on.pop() // remove ID -> filled in below
149171

150-
// Process entities to define the relation
151-
processEntities(m)
172+
processEntities(m) // REVISIT: why is that required ?!?
152173

153174
for (let name in m.definitions) {
154-
const entity = m.definitions[name]
155-
if (isChangeTracked(entity)) {
156-
157-
// Determine entity keys
158-
const keys = [], { elements: elms } = entity
159-
for (let e in elms) {
160-
if (elms[e].key) {
161-
if (elms[e].type === 'cds.Association') {
162-
keys.push({
163-
e,
164-
val: elms[e]
165-
})
166-
} else {
167-
keys.push(e)
168-
}
169-
}
170-
}
171175

172-
// If no key attribute is defined for the entity, the logic to add association to ChangeView should be skipped.
173-
if (keys.length === 0) {
174-
continue
175-
}
176+
const entity = m.definitions[name]
177+
if (entity.kind === 'entity' && !entity['@cds.autoexposed'] && isChangeTracked(entity)) {
176178

177-
// Add association to ChangeView...
178-
const on = [...changes.on]
179-
keys.forEach((k, i) => {
180-
i && on.push("||")
181-
on.push({
182-
ref: k?.val?.type === "cds.Association" ? [k.e, k.val.keys?.[0]?.ref?.[0]] : [k]
183-
})
184-
})
185-
const assoc = { ...changes, on }
186-
const query = entity.projection || entity.query?.SELECT
187179
if (!entity['@changelog.disable_assoc']) {
188-
if (query) {
189-
(query.columns ??= ['*']).push({ as: 'changes', cast: assoc })
190-
} else {
191-
entity.elements.changes = assoc
192-
}
180+
181+
// Add association to ChangeView...
182+
const keys = entityKey4(entity); if (!keys.length) continue // If no key attribute is defined for the entity, the logic to add association to ChangeView should be skipped.
183+
const assoc = { ...changes, on: [ ...changes.on, ...keys ] }
184+
185+
// --------------------------------------------------------------------
186+
// PARKED: Add auto-exposed projection on ChangeView to service if applicable
187+
// const namespace = name.match(/^(.*)\.[^.]+$/)[1]
188+
// const service = m.definitions[namespace]
189+
// if (service) {
190+
// const projection = {from:{ref:[assoc.target]}}
191+
// m.definitions[assoc.target = namespace + '.' + Changes] = {
192+
// '@cds.autoexposed':true, kind:'entity', projection
193+
// }
194+
// DEBUG?.(`\n
195+
// extend service ${namespace} with {
196+
// entity ${Changes} as projection on ${projection.from.ref[0]};
197+
// }
198+
// `.replace(/ {10}/g,''))
199+
// }
200+
// --------------------------------------------------------------------
201+
202+
DEBUG?.(`\n
203+
extend ${name} with {
204+
changes : Association to many ${assoc.target} on ${ assoc.on.map(x => x.ref?.join('.') || x).join(' ') };
205+
}
206+
`.replace(/ {8}/g,''))
207+
const query = entity.projection || entity.query?.SELECT
208+
if (query) (query.columns ??= ['*']).push({ as: 'changes', cast: assoc })
209+
else if (entity.elements) entity.elements.changes = assoc
193210

194211
// Add UI.Facet for Change History List
195212
if (!entity['@changelog.disable_facet'])
@@ -200,9 +217,7 @@ cds.on('loaded', m => {
200217
const hasParentInfo = entity[hasParent]
201218
const entityName = hasParentInfo?.entityName
202219
const parentEntity = entityName ? m.definitions[entityName] : null
203-
204220
const isParentRootAndHasFacets = parentEntity?.[isRoot] && parentEntity?.['@UI.Facets']
205-
206221
if (entity[isRoot] && entity['@UI.Facets']) {
207222
// Add side effects for root entity
208223
addSideEffects(entity.actions, true)
@@ -213,10 +228,11 @@ cds.on('loaded', m => {
213228
}
214229
}
215230
}
216-
})
231+
(m.meta ??= {})[_enhanced] = true
232+
}
217233

218234
// Add generic change tracking handlers
219-
cds.on('served', () => {
235+
function addGenericHandlers() {
220236
const { track_changes, _afterReadChangeView } = require("./lib/change-log")
221237
for (const srv of cds.services) {
222238
if (srv instanceof cds.ApplicationService) {
@@ -234,4 +250,11 @@ cds.on('served', () => {
234250
}
235251
}
236252
}
237-
})
253+
}
254+
255+
256+
// Register plugin hooks
257+
cds.on('compile.for.runtime', csn => { DEBUG?.('on','compile.for.runtime'); enhanceModel(csn) })
258+
cds.on('compile.to.edmx', csn => { DEBUG?.('on','compile.to.edmx'); enhanceModel(csn) })
259+
cds.on('compile.to.dbx', csn => { DEBUG?.('on','compile.to.dbx'); enhanceModel(csn) })
260+
cds.on('served', addGenericHandlers)

0 commit comments

Comments
 (0)