Skip to content

Commit 0bc9a7d

Browse files
committed
Improve reference detection for aliases
1 parent 5667fa0 commit 0bc9a7d

File tree

3 files changed

+84
-23
lines changed

3 files changed

+84
-23
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8-
## Version 0.2.2 - 2025-07-xx
8+
## Version 0.2.2 - 2025-06-26
99

1010
### Fixed
1111

12-
- tbd
12+
- Improve reference detection for aliases
1313

1414
## Version 0.2.1 - 2025-06-26
1515

db/schema.cds

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ entity Pages {
3333
on quotes.page = $self;
3434
}
3535

36-
entity PagesView as select from Pages mixin {
36+
entity PagesView as select from Pages as pages mixin {
3737
mixinBook : Association to Books on ID = ID;
3838
} into {
39+
pages.ID,
40+
pages.no,
3941
*,
4042
mixinBook
4143
} where mixinBook.ID = ID;

src/replication-cache/ReplicationCache.js

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -875,27 +875,68 @@ function selectFromRefs(model, query) {
875875
return refs;
876876
}
877877

878+
function selectFromAliases(model, query) {
879+
let aliases = {};
880+
if (query.SELECT.from.SELECT) {
881+
// Sub-select aliases are not (yet) supported
882+
} else if (query.SELECT.from.ref) {
883+
const ref = resolveRef(model, query.SELECT.from.ref);
884+
if (query.SELECT.from.as) {
885+
aliases[query.SELECT.from.as] = ref;
886+
} else {
887+
const as = ref.split(".").pop();
888+
aliases[as] = ref;
889+
}
890+
} else if ((query.SELECT.from.join || query.SELECT.from.SET) && query.SELECT.from.args) {
891+
for (const arg of query.SELECT.from.args) {
892+
const ref = resolveRef(model, arg.ref);
893+
if (arg.as) {
894+
aliases[arg.as] = ref;
895+
} else {
896+
const as = ref.split(".").pop();
897+
aliases[as] = ref;
898+
}
899+
}
900+
}
901+
return aliases;
902+
}
903+
878904
function selectRefs(model, query) {
879905
let refs = selectFromRefs(model, query);
906+
const aliases = selectFromAliases(model, query);
880907
if (query._target) {
881908
const target = model.definitions[query._target.name];
882909
if (query.SELECT.orderBy) {
883-
refs = refs.concat(expressionRefs(model, target, query.SELECT.orderBy, query.SELECT.mixin));
910+
refs = refs.concat(expressionRefs(model, target, query.SELECT.orderBy, query.SELECT.mixin, aliases));
884911
}
885912
if (query.SELECT.columns) {
886-
refs = refs.concat(expressionRefs(model, target, query.SELECT.columns, query.SELECT.mixin));
887-
refs = refs.concat(expandRefs(model, target, query.SELECT.columns, query.SELECT.mixin));
913+
refs = refs.concat(expressionRefs(model, target, query.SELECT.columns, query.SELECT.mixin, aliases));
914+
refs = refs.concat(expandRefs(model, target, query.SELECT.columns, query.SELECT.mixin, aliases));
888915
}
889916
if (query.SELECT.where) {
890-
refs = refs.concat(expressionRefs(model, target, query.SELECT.where, query.SELECT.mixin));
917+
refs = refs.concat(expressionRefs(model, target, query.SELECT.where, query.SELECT.mixin, aliases));
891918
}
892919
if (query.SELECT.having) {
893-
refs = refs.concat(expressionRefs(model, target, query.SELECT.having, query.SELECT.mixin));
920+
refs = refs.concat(expressionRefs(model, target, query.SELECT.having, query.SELECT.mixin, aliases));
894921
}
895922
}
896923
return refs;
897924
}
898925

926+
function resolveRef(model, refs) {
927+
let ref = refs[0];
928+
if (ref.id) {
929+
ref = ref.id;
930+
}
931+
let current = model.definitions[ref];
932+
for (const ref of refs.slice(1)) {
933+
if (current.elements[ref].type === "cds.Association" || current.elements[ref].type === "cds.Composition") {
934+
current = current.elements[ref]._target;
935+
}
936+
}
937+
return current.name;
938+
}
939+
899940
function resolveRefs(model, refs) {
900941
let resolvedRefs = [];
901942
let ref = refs[0];
@@ -917,17 +958,16 @@ function resolveRefs(model, refs) {
917958
return resolvedRefs;
918959
}
919960

920-
function identifierRefs(model, definition, expressions, mixin) {
961+
function identifierRefs(model, definition, expressions, mixins, aliases) {
921962
let refs = [];
922963
for (const expression of expressions) {
923964
if (Array.isArray(expression.ref)) {
924965
let current = definition;
925-
let currentMixin = mixin;
966+
let currentMixins = mixins;
926967
for (const ref of expression.ref) {
927-
const element = current.elements[ref] || currentMixin?.[ref];
928-
if (element.type === "cds.Association" || element.type === "cds.Composition") {
929-
current = model.definitions[element.target];
930-
currentMixin = {};
968+
current = target(model, current, currentMixins, aliases, ref);
969+
if (current !== null) {
970+
currentMixins = {};
931971
refs.push(current.name);
932972
}
933973
}
@@ -936,30 +976,29 @@ function identifierRefs(model, definition, expressions, mixin) {
936976
return refs;
937977
}
938978

939-
function expressionRefs(model, definition, expressions, mixin) {
940-
let refs = identifierRefs(model, definition, expressions, mixin);
979+
function expressionRefs(model, definition, expressions, mixins, aliases) {
980+
let refs = identifierRefs(model, definition, expressions, mixins, aliases);
941981
for (const expression of expressions) {
942982
if (expression.xpr) {
943-
refs = refs.concat(expressionRefs(model, definition, expression.xpr, mixin));
983+
refs = refs.concat(expressionRefs(model, definition, expression.xpr, mixins, aliases));
944984
} else if (expression.args) {
945-
refs = refs.concat(expressionRefs(model, definition, expression.args, mixin));
985+
refs = refs.concat(expressionRefs(model, definition, expression.args, mixins, aliases));
946986
} else if (expression.SELECT) {
947987
refs = refs.concat(selectRefs(model, expression));
948988
}
949989
}
950990
return refs;
951991
}
952992

953-
function expandRefs(model, definition, columns, mixin) {
993+
function expandRefs(model, definition, columns, mixins, aliases) {
954994
let refs = [];
955995
for (const column of columns) {
956996
if (Array.isArray(column.ref) && column.expand) {
957997
let current = definition;
958-
let currentMixin = mixin;
998+
let currentMixins = mixins;
959999
for (const ref of column.ref) {
960-
const element = current.elements[ref] || currentMixin?.[ref];
961-
current = model.definitions[element.target];
962-
currentMixin = {};
1000+
current = target(model, current, currentMixins, aliases, ref);
1001+
currentMixins = {};
9631002
refs.push(current.name);
9641003
}
9651004
refs = refs.concat(expandRefs(model, current, column.expand));
@@ -968,6 +1007,26 @@ function expandRefs(model, definition, columns, mixin) {
9681007
return refs;
9691008
}
9701009

1010+
function target(model, entity, mixins, aliases, ref) {
1011+
if (aliases?.[ref]) {
1012+
return typeof aliases[ref] === "string" ? model.definitions[aliases[ref]] : aliases[ref];
1013+
}
1014+
if (entity.name.endsWith(`.${ref}`)) {
1015+
return entity;
1016+
}
1017+
const element = entity.elements[ref] || mixins?.[ref];
1018+
if (!element) {
1019+
cds.log(Component).warn("Reference not found in entity", {
1020+
entity: entity.name,
1021+
ref,
1022+
});
1023+
}
1024+
if (element.type === "cds.Association" || element.type === "cds.Composition") {
1025+
return model.definitions[element.target];
1026+
}
1027+
return null;
1028+
}
1029+
9711030
function staticRefs(model, refs) {
9721031
for (const ref of refs) {
9731032
if (!model.definitions[ref][Annotations.ReplicateStatic]) {

0 commit comments

Comments
 (0)