@cap-js-community/common 0.2.2 → 0.2.4
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 +87 -0
- package/README.md +3 -0
- package/package.json +9 -8
- package/src/replication-cache/ReplicationCache.js +169 -64
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
6
|
+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## Version 0.2.4 - 2025-07-03
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Multi-tenancy fixes
|
|
13
|
+
- Improve reference detection
|
|
14
|
+
- Deactivate TTL for negative value and static entities
|
|
15
|
+
|
|
16
|
+
## Version 0.2.3 - 2025-07-01
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Improve reference detection
|
|
21
|
+
|
|
22
|
+
## Version 0.2.2 - 2025-06-26
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Improve reference detection for aliases
|
|
27
|
+
|
|
28
|
+
## Version 0.2.1 - 2025-06-26
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Improve reference detection
|
|
33
|
+
- Static non-tenant aware replication via `cds.replicate.static`
|
|
34
|
+
|
|
35
|
+
## Version 0.2.0 - 2025-06-03
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- CDS 9 compatibility
|
|
40
|
+
|
|
41
|
+
## Version 0.1.7 - 2025-05-08
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- Enabling journal mode and changing entity in same cycle is not allowed
|
|
46
|
+
|
|
47
|
+
## Version 0.1.6 - 2025-05-07
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- Redis 4
|
|
52
|
+
|
|
53
|
+
## Version 0.1.5 - 2025-05-05
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- Dependencies
|
|
58
|
+
|
|
59
|
+
## Version 0.1.4 - 2025-04-10
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- Improvements
|
|
64
|
+
|
|
65
|
+
## Version 0.1.3 - 2025-04-10
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- Redis client improvements
|
|
70
|
+
|
|
71
|
+
## Version 0.1.2 - 2025-04-09
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- Improvements
|
|
76
|
+
|
|
77
|
+
## Version 0.1.1 - 2025-04-09
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- Improvements
|
|
82
|
+
|
|
83
|
+
## Version 0.1.0 - 2025-04-09
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- Internal release
|
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ Options can be passed to migration check via CDS environment via `cds.migrationC
|
|
|
121
121
|
|
|
122
122
|
- Maintain the whitelist extension file `migration-extension-whitelist.json` for compatible changes:
|
|
123
123
|
- **Whitelist Entity**:
|
|
124
|
+
|
|
124
125
|
```json
|
|
125
126
|
{
|
|
126
127
|
"definitions": {
|
|
@@ -128,7 +129,9 @@ Options can be passed to migration check via CDS environment via `cds.migrationC
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
```
|
|
132
|
+
|
|
131
133
|
- **Whitelist Entity Element**:
|
|
134
|
+
|
|
132
135
|
```json
|
|
133
136
|
{
|
|
134
137
|
"definitions": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js-community/common",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "CAP Node.js Community Common",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"engines": {
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"bin",
|
|
21
21
|
"src",
|
|
22
22
|
"LICENSE",
|
|
23
|
-
"cds-plugin.js"
|
|
23
|
+
"cds-plugin.js",
|
|
24
|
+
"CHANGELOG.md"
|
|
24
25
|
],
|
|
25
26
|
"main": "index.js",
|
|
26
27
|
"types": "index.d.ts",
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
"audit": "npm audit --only=prod"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@cap-js/sqlite": "^2.0.
|
|
48
|
+
"@cap-js/sqlite": "^2.0.2",
|
|
48
49
|
"commander": "^14.0.0",
|
|
49
50
|
"redis": "^4.7.1",
|
|
50
51
|
"verror": "^1.10.1"
|
|
@@ -52,17 +53,17 @@
|
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@cap-js-community/common": "./",
|
|
54
55
|
"@cap-js/cds-test": "^0.4.0",
|
|
55
|
-
"@sap/cds": "^9.0
|
|
56
|
+
"@sap/cds": "^9.1.0",
|
|
56
57
|
"@sap/cds-common-content": "^3.0.1",
|
|
57
|
-
"@sap/cds-dk": "^9.0
|
|
58
|
-
"eslint": "9.
|
|
58
|
+
"@sap/cds-dk": "^9.1.0",
|
|
59
|
+
"eslint": "9.30.1",
|
|
59
60
|
"eslint-config-prettier": "10.1.5",
|
|
60
61
|
"eslint-plugin-jest": "29.0.1",
|
|
61
62
|
"eslint-plugin-n": "^17.20.0",
|
|
62
|
-
"jest": "30.0.
|
|
63
|
+
"jest": "30.0.4",
|
|
63
64
|
"jest-html-reporters": "3.1.7",
|
|
64
65
|
"jest-junit": "16.0.0",
|
|
65
|
-
"prettier": "3.6.
|
|
66
|
+
"prettier": "3.6.2",
|
|
66
67
|
"shelljs": "^0.10.0"
|
|
67
68
|
},
|
|
68
69
|
"cds": {
|
|
@@ -73,10 +73,14 @@ class ReplicationCache {
|
|
|
73
73
|
this.options?.credentials?.database &&
|
|
74
74
|
this.options?.credentials?.database !== Constants.InMemory
|
|
75
75
|
) {
|
|
76
|
-
this.log.
|
|
77
|
-
this.template = createDB(Tenant.Template, this.model, this.options)
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
this.log.info("Preparing replication cache template database");
|
|
77
|
+
this.template = createDB(Tenant.Template, this.model, this.options)
|
|
78
|
+
.then(() => {
|
|
79
|
+
this.log.info("Prepared replication cache template database");
|
|
80
|
+
})
|
|
81
|
+
.catch((err) => {
|
|
82
|
+
this.log.error("Preparing replication cache failed", err);
|
|
83
|
+
});
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
}
|
|
@@ -178,7 +182,7 @@ class ReplicationCache {
|
|
|
178
182
|
if (fromRefs.length === 0 || !this.relevant(fromRefs)) {
|
|
179
183
|
return await next();
|
|
180
184
|
}
|
|
181
|
-
let refs = queryRefs(model, req.query);
|
|
185
|
+
let refs = queryRefs(model, req.query, req.target);
|
|
182
186
|
if (!this.options.deploy) {
|
|
183
187
|
if (!this.localized(req.query, refs)) {
|
|
184
188
|
return await next();
|
|
@@ -220,9 +224,17 @@ class ReplicationCache {
|
|
|
220
224
|
if (this.options.measure) {
|
|
221
225
|
return this.measure(
|
|
222
226
|
async () => {
|
|
223
|
-
return db.tx(
|
|
224
|
-
|
|
225
|
-
|
|
227
|
+
return db.tx(
|
|
228
|
+
{
|
|
229
|
+
tenant: req.context.tenant,
|
|
230
|
+
locale: req.context.locale,
|
|
231
|
+
user: req.context.user,
|
|
232
|
+
http: req.context.http,
|
|
233
|
+
},
|
|
234
|
+
async (tx) => {
|
|
235
|
+
return tx.run(req.query);
|
|
236
|
+
},
|
|
237
|
+
);
|
|
226
238
|
},
|
|
227
239
|
async () => {
|
|
228
240
|
await next();
|
|
@@ -585,6 +597,7 @@ class ReplicationCacheEntry {
|
|
|
585
597
|
this.db = tenant.db;
|
|
586
598
|
this.ref = ref;
|
|
587
599
|
this.definition = this.csn[ref];
|
|
600
|
+
this.static = !!this.definition[Annotations.ReplicateStatic];
|
|
588
601
|
this.preload = this.cache.options.preload && this.definition[Annotations.ReplicatePreload];
|
|
589
602
|
this.name = this.definition.name.replace(/\./gi, "_");
|
|
590
603
|
this.status = Status.New;
|
|
@@ -614,13 +627,15 @@ class ReplicationCacheEntry {
|
|
|
614
627
|
await this.load(thread);
|
|
615
628
|
this.status = Status.Ready;
|
|
616
629
|
this.failures = 0;
|
|
617
|
-
this.
|
|
618
|
-
this.
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
630
|
+
if (this.ttl > 0 && !this.static) {
|
|
631
|
+
this.timeout = setTimeout(async () => {
|
|
632
|
+
this.cache.log.debug("Replication cache ref TTL reached", {
|
|
633
|
+
tenant: this.tenant.id,
|
|
634
|
+
ref: this.ref,
|
|
635
|
+
});
|
|
636
|
+
await this.clear(true);
|
|
637
|
+
}, this.ttl).unref();
|
|
638
|
+
}
|
|
624
639
|
}
|
|
625
640
|
this.cache.log.debug("Preparing replication cache ref finished", {
|
|
626
641
|
tenant: this.tenant.id,
|
|
@@ -779,7 +794,11 @@ async function createDB(tenant, model, options) {
|
|
|
779
794
|
const db = new SQLiteService(tenant ?? Tenant.Default, model, {
|
|
780
795
|
kind: "sqlite",
|
|
781
796
|
impl: "@cap-js/sqlite",
|
|
782
|
-
|
|
797
|
+
multiTenant: false,
|
|
798
|
+
credentials: {
|
|
799
|
+
...options.credentials,
|
|
800
|
+
database: filePath,
|
|
801
|
+
},
|
|
783
802
|
});
|
|
784
803
|
await db.init();
|
|
785
804
|
if (options.deploy && (filePath === Constants.InMemory || tenant === Tenant.Template)) {
|
|
@@ -818,13 +837,18 @@ function baseRefs(model, refs) {
|
|
|
818
837
|
const baseRefs = [];
|
|
819
838
|
let currentRefs = refs;
|
|
820
839
|
let nextRefs = [];
|
|
840
|
+
const visited = new Set();
|
|
821
841
|
while (currentRefs.length > 0) {
|
|
822
842
|
for (const ref of currentRefs) {
|
|
843
|
+
if (visited.has(ref)) {
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
visited.add(ref);
|
|
823
847
|
const definition = model.definitions[ref];
|
|
824
848
|
if (!definition.query) {
|
|
825
849
|
baseRefs.push(ref);
|
|
826
850
|
} else {
|
|
827
|
-
nextRefs = nextRefs.concat(queryRefs(model, definition.query));
|
|
851
|
+
nextRefs = nextRefs.concat(queryRefs(model, definition.query, definition));
|
|
828
852
|
}
|
|
829
853
|
}
|
|
830
854
|
currentRefs = nextRefs;
|
|
@@ -853,33 +877,61 @@ function queryFromRefs(model, query) {
|
|
|
853
877
|
return unique(selectFromRefs(model, query));
|
|
854
878
|
}
|
|
855
879
|
|
|
856
|
-
function queryRefs(model, query) {
|
|
880
|
+
function queryRefs(model, query, definition) {
|
|
857
881
|
if (!query.SELECT) {
|
|
858
882
|
return [];
|
|
859
883
|
}
|
|
860
|
-
return unique(selectRefs(model, query));
|
|
884
|
+
return unique(selectRefs(model, definition, query));
|
|
861
885
|
}
|
|
862
886
|
|
|
863
887
|
function selectFromRefs(model, query) {
|
|
864
888
|
let refs = [];
|
|
865
|
-
if (query.SELECT.from.
|
|
866
|
-
refs = selectFromRefs(model, query.SELECT.from);
|
|
867
|
-
} else if (query.SELECT.from.ref) {
|
|
889
|
+
if (query.SELECT.from.ref) {
|
|
868
890
|
refs = resolveRefs(model, query.SELECT.from.ref);
|
|
869
|
-
} else if (
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
891
|
+
} else if (query.SELECT.from.args) {
|
|
892
|
+
for (const arg of query.SELECT.from.args) {
|
|
893
|
+
if (arg.ref) {
|
|
894
|
+
refs = refs.concat(resolveRefs(model, arg.ref));
|
|
895
|
+
} else if (arg.args) {
|
|
896
|
+
refs = refs.concat(selectFromRefs(model, { SELECT: { from: { args: arg.args } } }));
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} else if (query.SELECT.from.SET?.args) {
|
|
900
|
+
for (const arg of query.SELECT.from.SET.args) {
|
|
901
|
+
refs = refs.concat(selectFromRefs(model, arg));
|
|
902
|
+
}
|
|
903
|
+
} else if (query.SELECT.from.SELECT) {
|
|
904
|
+
refs = selectFromRefs(model, query.SELECT.from);
|
|
874
905
|
}
|
|
875
906
|
return refs;
|
|
876
907
|
}
|
|
877
908
|
|
|
878
|
-
function
|
|
909
|
+
function selectFromPrimaryRef(model, query) {
|
|
910
|
+
if (query.SELECT.from.ref) {
|
|
911
|
+
return resolveRef(model, query.SELECT.from.ref);
|
|
912
|
+
} else if (query.SELECT.from.args) {
|
|
913
|
+
for (const arg of query.SELECT.from.args) {
|
|
914
|
+
if (arg.ref) {
|
|
915
|
+
return resolveRef(model, arg.ref);
|
|
916
|
+
} else if (arg.args) {
|
|
917
|
+
return selectFromPrimaryRef(model, { SELECT: { from: { args: arg.args } } });
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
} else if (query.SELECT.from.SET?.args) {
|
|
921
|
+
for (const arg of query.SELECT.from.SET.args) {
|
|
922
|
+
return selectFromPrimaryRef(model, arg);
|
|
923
|
+
}
|
|
924
|
+
} else if (query.SELECT.from.SELECT) {
|
|
925
|
+
return selectFromPrimaryRef(model, query.SELECT.from);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function selectFromAliases(model, definition, query) {
|
|
879
930
|
let aliases = {};
|
|
880
|
-
if (
|
|
881
|
-
|
|
882
|
-
}
|
|
931
|
+
if (definition?.name) {
|
|
932
|
+
aliases["$self"] = definition.name;
|
|
933
|
+
}
|
|
934
|
+
if (query.SELECT.from.ref) {
|
|
883
935
|
const ref = resolveRef(model, query.SELECT.from.ref);
|
|
884
936
|
if (query.SELECT.from.as) {
|
|
885
937
|
aliases[query.SELECT.from.as] = ref;
|
|
@@ -887,39 +939,84 @@ function selectFromAliases(model, query) {
|
|
|
887
939
|
const as = ref.split(".").pop();
|
|
888
940
|
aliases[as] = ref;
|
|
889
941
|
}
|
|
890
|
-
} else if (
|
|
942
|
+
} else if (query.SELECT.from.args) {
|
|
891
943
|
for (const arg of query.SELECT.from.args) {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
944
|
+
if (arg.ref) {
|
|
945
|
+
const ref = resolveRef(model, arg.ref);
|
|
946
|
+
if (arg.as) {
|
|
947
|
+
aliases[arg.as] = ref;
|
|
948
|
+
} else {
|
|
949
|
+
const as = ref.split(".").pop();
|
|
950
|
+
aliases[as] = ref;
|
|
951
|
+
}
|
|
952
|
+
} else if (arg.args) {
|
|
953
|
+
aliases = {
|
|
954
|
+
...aliases,
|
|
955
|
+
...selectFromAliases(model, definition, { SELECT: { from: { args: arg.args } } }),
|
|
956
|
+
};
|
|
898
957
|
}
|
|
899
958
|
}
|
|
959
|
+
} else if (query.SELECT.from.SET?.args) {
|
|
960
|
+
for (const arg of query.SELECT.from.SET.args) {
|
|
961
|
+
aliases = {
|
|
962
|
+
...aliases,
|
|
963
|
+
...selectFromAliases(model, definition, arg),
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
} else if (query.SELECT.from.SELECT) {
|
|
967
|
+
aliases = {
|
|
968
|
+
...aliases,
|
|
969
|
+
...selectFromAliases(model, definition, query.SELECT.from),
|
|
970
|
+
};
|
|
900
971
|
}
|
|
901
972
|
return aliases;
|
|
902
973
|
}
|
|
903
974
|
|
|
904
|
-
function
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
if (query.SELECT.having) {
|
|
920
|
-
refs = refs.concat(expressionRefs(model, target, query.SELECT.having, query.SELECT.mixin, aliases));
|
|
975
|
+
function selectOuterAliases(model, target, columns, mixins, aliases) {
|
|
976
|
+
const outerAliases = {};
|
|
977
|
+
if (columns) {
|
|
978
|
+
for (const column of columns) {
|
|
979
|
+
if (column.ref) {
|
|
980
|
+
const as = column.as || column.ref[column.ref.length - 1];
|
|
981
|
+
let current = target;
|
|
982
|
+
for (const ref of column.ref) {
|
|
983
|
+
const currentTarget = targetEntity(model, current, mixins, aliases, ref);
|
|
984
|
+
if (currentTarget != null) {
|
|
985
|
+
current = currentTarget;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
outerAliases[as] = (current || target).name;
|
|
989
|
+
}
|
|
921
990
|
}
|
|
922
991
|
}
|
|
992
|
+
return outerAliases;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function selectRefs(model, definition, query, aliases) {
|
|
996
|
+
let targetName = selectFromPrimaryRef(model, query);
|
|
997
|
+
const target = targetName ? model.definitions[targetName] : undefined;
|
|
998
|
+
let refs = selectFromRefs(model, query);
|
|
999
|
+
aliases = {
|
|
1000
|
+
...aliases,
|
|
1001
|
+
...selectFromAliases(model, definition, query),
|
|
1002
|
+
};
|
|
1003
|
+
if (query.SELECT.columns) {
|
|
1004
|
+
refs = refs.concat(expressionRefs(model, target, query.SELECT.columns, query.SELECT.mixin, aliases));
|
|
1005
|
+
refs = refs.concat(expandRefs(model, target, query.SELECT.columns, query.SELECT.mixin, aliases));
|
|
1006
|
+
}
|
|
1007
|
+
if (query.SELECT.where) {
|
|
1008
|
+
refs = refs.concat(expressionRefs(model, target, query.SELECT.where, query.SELECT.mixin, aliases));
|
|
1009
|
+
}
|
|
1010
|
+
const outerAliases = {
|
|
1011
|
+
...aliases,
|
|
1012
|
+
...selectOuterAliases(model, target, query.SELECT.columns, query.SELECT.mixin, aliases),
|
|
1013
|
+
};
|
|
1014
|
+
if (query.SELECT.having) {
|
|
1015
|
+
refs = refs.concat(expressionRefs(model, target, query.SELECT.having, query.SELECT.mixin, outerAliases));
|
|
1016
|
+
}
|
|
1017
|
+
if (query.SELECT.orderBy) {
|
|
1018
|
+
refs = refs.concat(expressionRefs(model, target, query.SELECT.orderBy, query.SELECT.mixin, outerAliases));
|
|
1019
|
+
}
|
|
923
1020
|
return refs;
|
|
924
1021
|
}
|
|
925
1022
|
|
|
@@ -965,11 +1062,14 @@ function identifierRefs(model, definition, expressions, mixins, aliases) {
|
|
|
965
1062
|
let current = definition;
|
|
966
1063
|
let currentMixins = mixins;
|
|
967
1064
|
for (const ref of expression.ref) {
|
|
968
|
-
|
|
969
|
-
if (current !== null) {
|
|
970
|
-
currentMixins = {};
|
|
1065
|
+
if (current?.name !== definition?.name) {
|
|
971
1066
|
refs.push(current.name);
|
|
972
1067
|
}
|
|
1068
|
+
if (ref.startsWith("$")) {
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
current = targetEntity(model, current, currentMixins, aliases, ref);
|
|
1072
|
+
currentMixins = {};
|
|
973
1073
|
}
|
|
974
1074
|
}
|
|
975
1075
|
}
|
|
@@ -984,7 +1084,12 @@ function expressionRefs(model, definition, expressions, mixins, aliases) {
|
|
|
984
1084
|
} else if (expression.args) {
|
|
985
1085
|
refs = refs.concat(expressionRefs(model, definition, expression.args, mixins, aliases));
|
|
986
1086
|
} else if (expression.SELECT) {
|
|
987
|
-
refs = refs.concat(
|
|
1087
|
+
refs = refs.concat(
|
|
1088
|
+
selectRefs(model, undefined, expression, {
|
|
1089
|
+
...aliases,
|
|
1090
|
+
["$self"]: undefined,
|
|
1091
|
+
}),
|
|
1092
|
+
);
|
|
988
1093
|
}
|
|
989
1094
|
}
|
|
990
1095
|
return refs;
|
|
@@ -997,7 +1102,7 @@ function expandRefs(model, definition, columns, mixins, aliases) {
|
|
|
997
1102
|
let current = definition;
|
|
998
1103
|
let currentMixins = mixins;
|
|
999
1104
|
for (const ref of column.ref) {
|
|
1000
|
-
current =
|
|
1105
|
+
current = targetEntity(model, current, currentMixins, aliases, ref);
|
|
1001
1106
|
currentMixins = {};
|
|
1002
1107
|
refs.push(current.name);
|
|
1003
1108
|
}
|
|
@@ -1007,17 +1112,17 @@ function expandRefs(model, definition, columns, mixins, aliases) {
|
|
|
1007
1112
|
return refs;
|
|
1008
1113
|
}
|
|
1009
1114
|
|
|
1010
|
-
function
|
|
1115
|
+
function targetEntity(model, entity, mixins, aliases, ref) {
|
|
1011
1116
|
if (aliases?.[ref]) {
|
|
1012
1117
|
return typeof aliases[ref] === "string" ? model.definitions[aliases[ref]] : aliases[ref];
|
|
1013
1118
|
}
|
|
1014
|
-
if (entity
|
|
1119
|
+
if (entity?.name.endsWith(`.${ref}`)) {
|
|
1015
1120
|
return entity;
|
|
1016
1121
|
}
|
|
1017
|
-
const element = entity
|
|
1122
|
+
const element = entity?.elements[ref] || mixins?.[ref];
|
|
1018
1123
|
if (!element) {
|
|
1019
1124
|
cds.log(Component).warn("Reference not found in entity", {
|
|
1020
|
-
entity: entity
|
|
1125
|
+
entity: entity?.name,
|
|
1021
1126
|
ref,
|
|
1022
1127
|
});
|
|
1023
1128
|
}
|