diff --git a/judo-tatami-jsl-jsl2ui/.editorconfig b/judo-tatami-jsl-jsl2ui/.editorconfig new file mode 100644 index 00000000..3c1c1ce0 --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/.editorconfig @@ -0,0 +1,5 @@ +[src/main/epsilon/**.{eol,etl}] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/equivalentDiscriminated.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/equivalentDiscriminated.eol index 651a60dd..f02b3008 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/equivalentDiscriminated.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/equivalentDiscriminated.eol @@ -1,62 +1,62 @@ operation Any equivalentDiscriminated(transformation : String, id : String, discriminator : String) : Any { - if (self.isUndefined()) { - throw "Transformation called in empty object: " + id + " / " + discriminator + " Transformation: " + transformation; - } - var targetId = id + "/(discriminator/" + discriminator + ")"; + if (self.isUndefined()) { + throw "Transformation called in empty object: " + id + " / " + discriminator + " Transformation: " + transformation; + } + var targetId = id + "/(discriminator/" + discriminator + ")"; var r = JSL.target.resource; // Find the discriminated id in cahe first - var f = __cacheMap.get(targetId); + var f = __cacheMap.get(targetId); // Whenit is not found in cache, search from the model and put to cache when found - if (f.isUndefined()) { - f = ecoreUtil.getAllContents(r, false).select(e | e.getId() == targetId).first; - if (f.isDefined()) { - __cacheMap.put(targetId, f); - return f; - } - } - - // When the element found, but ID is different, it is missused of discriminated API, error + if (f.isUndefined()) { + f = ecoreUtil.getAllContents(r, false).select(e | e.getId() == targetId).first; + if (f.isDefined()) { + __cacheMap.put(targetId, f); + return f; + } + } + + // When the element found, but ID is different, it is missused of discriminated API, error if (f.isDefined()) { if (f.getId() != targetId) { - throw "ID does not match defined in cache: " + f.getId() + " Cache ID: " + targetId; + throw "ID does not match defined in cache: " + f.getId() + " Cache ID: " + targetId; } - return f; + return f; } else { - // When no model element with discriminated ID found, call equivalent to create original element or get it - f = self.equivalent(transformation); + // When no model element with discriminated ID found, call equivalent to create original element or get it + f = self.equivalent(transformation); - if (f.isUndefined()) { - throw "No instance of transformation call: " + id + " / " + discriminator + " Transformation: " + transformation; - } - - // When discriminated ID not matches new clone have to be created - if (__originalMap.containsKey(f) and f.getId() != targetId) { - f = ecoreUtil.copy(f); - r.contents.add(f); + if (f.isUndefined()) { + throw "No instance of transformation call: " + id + " / " + discriminator + " Transformation: " + transformation; + } + + // When discriminated ID not matches new clone have to be created + if (__originalMap.containsKey(f) and f.getId() != targetId) { + f = ecoreUtil.copy(f); + r.contents.add(f); - __cacheMap.put(targetId, f); - // Store traceability links - /* - for (t in transTrace.transformations) { - if (t.source == self and t.rule.name == transformation) { - t.targets.add(f); - } - } */ + __cacheMap.put(targetId, f); + // Store traceability links + /* + for (t in transTrace.transformations) { + if (t.source == self and t.rule.name == transformation) { + t.targets.add(f); + } + } */ + } + f.eResource.setId(f, targetId); + if (not __originalMap.containsKey(f)) { + __originalMap.put(f, targetId); } - f.eResource.setId(f, targetId); - if (not __originalMap.containsKey(f)) { - __originalMap.put(f, targetId); - } - __cacheMap.put(targetId, f); - return f; + __cacheMap.put(targetId, f); + return f; } } operation Any equivalentDiscriminated(transformation : String, discriminator : String) : Any { - return self.equivalentDiscriminated(transformation, - "(jsl/" + self.getId() + ")/" + transformation, - discriminator - ); + return self.equivalentDiscriminated(transformation, + "(jsl/" + self.getId() + ")/" + transformation, + discriminator + ); } diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/id.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/id.eol index 469658ae..a54c0cb3 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/id.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/id.eol @@ -1,31 +1,31 @@ operation Any setId(id: String) { - if (id.isUndefined()) { - throw "ID is not defined" + self; - } - if (self.isUndefined()) { - throw "Could not determinate ID of " + self; - } - var r = self.eResource; + if (id.isUndefined()) { + throw "ID is not defined" + self; + } + if (self.isUndefined()) { + throw "Could not determinate ID of " + self; + } + var r = self.eResource; if (r.isUndefined()) { - throw "Object is not added to resource " + self; + throw "Object is not added to resource " + self; } if (__originalMap.containsKey(self)) { - __originalMap.put(self, id); + __originalMap.put(self, id); } if (__cacheMap.containsKey(self.getId())) { - __cacheMap.remove(self.getId()); - __cacheMap.put(id, self); + __cacheMap.remove(self.getId()); + __cacheMap.put(id, self); } r.setId(self, id); } operation Any getId() : String { - if (self.isUndefined()) { - throw "Could not determinate ID of " + self; - } - var r = self.eResource; + if (self.isUndefined()) { + throw "Could not determinate ID of " + self; + } + var r = self.eResource; if (r.isUndefined()) { - throw "Object is not added to resource " + self; + throw "Object is not added to resource " + self; } return r.getId(self); diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/_importAll.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/_importAll.eol index b98334a3..1e7c0fae 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/_importAll.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/_importAll.eol @@ -1,2 +1,4 @@ +import "actor/_importActor.eol"; import "data/_importData.eol"; import "namespace/_importNamespace.eol"; +import "ui/_importUI.eol"; diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/_importActor.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/_importActor.eol new file mode 100644 index 00000000..1cf39fee --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/_importActor.eol @@ -0,0 +1,4 @@ +import "actorAccessDeclaration.eol"; +import "actorDeclaration.eol"; +import "actorGroupDeclaration.eol"; +import "actorLinkDeclaration.eol"; diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorAccessDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorAccessDeclaration.eol similarity index 100% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorAccessDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorAccessDeclaration.eol diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorDeclaration.eol similarity index 94% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorDeclaration.eol index 4b93539b..9c9c457f 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorDeclaration.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorDeclaration.eol @@ -89,10 +89,3 @@ operation JSL!ActorDeclaration getExposedTransferObjects() : Set { return collected; } - -@cached -operation JSL!ActorDeclaration getTransferObjects() : Set { - var transfers = new Set(); - self.collectExposed(new Set(), transfers, new Set()); - return transfers; -} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorGroupDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorGroupDeclaration.eol similarity index 100% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorGroupDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorGroupDeclaration.eol diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorLinkDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorLinkDeclaration.eol similarity index 100% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/actorLinkDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/actor/actorLinkDeclaration.eol diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/_importData.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/_importData.eol index 47e4a01e..fa960007 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/_importData.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/_importData.eol @@ -1,16 +1,10 @@ -import "actorAccessDeclaration.eol"; -import "actorDeclaration.eol"; -import "actorGroupDeclaration.eol"; -import "actorLinkDeclaration.eol"; import "dataTypeDeclaration.eol"; -import "modelDeclaration.eol"; +import "entityMemberDeclaration.eol"; import "enumDeclaration.eol"; import "enumLiteral.eol"; -import "modifiable.eol"; import "primitiveDeclaration.eol"; import "simpleTransferDeclaration.eol"; import "transferDeclaration.eol"; import "transferFieldDeclaration.eol"; import "transferRelationDeclaration.eol"; -import "viewDeclaration.eol"; -import "visibleDeclaration.eol"; + diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/entityMemberDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/entityMemberDeclaration.eol new file mode 100644 index 00000000..bc38e822 --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/entityMemberDeclaration.eol @@ -0,0 +1,14 @@ +@cached +operation JSL!EntityMemberDeclaration isEager() : Boolean { + return jslUtils.isEager(self); +} + +@cached +operation JSL!EntityMemberDeclaration isCalculated(): Boolean { + return jslUtils.isCalculated(self); +} + +@cached +operation JSL!EntityMemberDeclaration isRequired(): Boolean { + return jslUtils.isRequired(self); +} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/modifiable.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/modifiable.eol deleted file mode 100644 index be12e745..00000000 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/modifiable.eol +++ /dev/null @@ -1,74 +0,0 @@ -@cached -operation JSL!Modifiable getId(): String { - return (self.eContainer.getId() + "/" + self.id); -} - -@cached -operation JSL!Modifiable getLabelModifier(): JSL!Modifier { - return self.modifiers.selectOne(m | m.isTypeOf(JSL!LabelModifier)); -} - -@cached -operation JSL!Modifiable getIconModifier(): JSL!Modifier { - return self.modifiers.selectOne(m | m.isTypeOf(JSL!IconModifier)); -} - -@cached -operation JSL!Modifiable getPrecision(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "precision")); -} - -@cached -operation JSL!Modifiable getScale(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "scale")); -} - -@cached -operation JSL!Modifiable getRegex(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "regex")); -} - -@cached -operation JSL!Modifiable getRequired(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "required")); -} - -@cached -operation JSL!Modifiable getMaxSize(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "max-size")); -} - -@cached -operation JSL!Modifiable getMaxFileSize(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "max-file-size")); -} - -@cached -operation JSL!Modifiable getMinSize(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "min-size")); -} - -@cached -operation JSL!Modifiable getMimeType(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "mime-type")); -} - -@cached -operation JSL!Modifiable getOpposite(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "opposite" or m.type == "opposite-add")); -} - -@cached -operation JSL!Modifiable getDefault(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "default")); -} - -@cached -operation JSL!Modifiable getChoices(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "choices")); -} - -@cached -operation JSL!Modifiable getBind(): JSL!Modifier { - return (self.modifiers.selectOne(m | m.type == "bind")); -} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferDeclaration.eol index d397e9dd..5f648ee2 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferDeclaration.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferDeclaration.eol @@ -9,39 +9,25 @@ operation JSL!TransferDeclaration getFqName(): String { } @cached -operation JSL!TransferDeclaration getActorDeclaration(): JSL!ActorDeclaration { - if (self.eContainer.isTypeOf(JSL!ActorDeclaration)) { - return self.eContainer; - } else if (self.eContainer.isTypeOf(JSL!ModelDeclaration)) { - return self.eContainer.declarations.selectOne(e | e.isTypeOf(JSL!ActorDeclaration)); - } - return null; -} - -@cached -operation JSL!TransferDeclaration getExposedTransferObjects() : Set { +operation JSL!TransferDeclaration getExposedTransferObjects(): Set { var transfers = new Set(); var relations = self.getExposedRelations(); - transfers.addAll(relations.collect(r | r.referenceType).asSet()); + transfers.addAll(relations.collect(r | r.referenceType)); for (relation in relations) { - var detail = relation.getDetail(); - - if (detail.isDefined() and detail.view.isDefined()) { - transfers.add(detail.view); - } + transfers.addAll(relation.referenceType.getExposedTransferObjects()); } return transfers; } @cached -operation JSL!TransferDeclaration getExposedRelations() : Set { +operation JSL!TransferDeclaration getExposedRelations(): Set { return self.collectExposedRelations(new Set()); } -operation JSL!TransferDeclaration collectExposedRelations(collected : Set) : Set { +operation JSL!TransferDeclaration collectExposedRelations(collected: Set): Set { var relations = self.getAllRelations(); // var operations = self.getAllOperations().select(op | not op.hasQueryParameters()); /*relations.addAll(operations @@ -63,6 +49,82 @@ operation JSL!TransferDeclaration collectExposedRelations(collected : Set) : Set return collected; } -operation JSL!TransferDeclaration getAllRelations() : Set { - return self.members.select(m | m.isKindOf(JSL!TransferRelationDeclaration)); +@cached +operation JSL!TransferDeclaration getAllRelations(): Set { + var relations = new Set(); + relations.addAll(self.members.select(m | m.isKindOf(JSL!TransferRelationDeclaration))); + + if (self.isKindOf(JSL!ActorDeclaration)) { + var linkRelations = self.getAllMenuDeclarations(); + relations.addAll(linkRelations); + + for (ref in linkRelations) { + if (ref.referenceType.isKindOf(JSL!TransferDeclaration)) { + relations.addAll(ref.referenceType.getAllRelations()); + } + } + } + + for (member in self.members.select(m | m.isKindOf(JSL!ViewPanelDeclaration))) { + relations.addAll(member.getAllRelations()); + } + + return relations; +} + +@cached +operation JSL!TransferDeclaration getAllPrimitiveFields(): Set { + var fields = new Set(); + fields.addAll(self.members.select(m | m.isKindOf(JSL!TransferFieldDeclaration) and m.referenceType.isDefined() and m.referenceType.`primitive`.isDefined())); + + for (member in self.members.select(m | m.isKindOf(JSL!ViewPanelDeclaration))) { + fields.addAll(member.getAllPrimitiveFields()); + } + + return fields; +} + +@cached +operation JSL!TransferDeclaration isDeleteSupported(): Boolean { + if (self.map.isDefined()) { + return self.members.exists(m | m.isKindOf(JSL!TransferDeleteDeclaration) and m.isEventInstead()); + } + return false; +} + +@cached +operation JSL!TransferDeclaration isCreateSupported(): Boolean { + if (self.map.isDefined()) { + return self.members.exists(m | m.isKindOf(JSL!TransferCreateDeclaration) and m.isEventInstead()); + } + return false; +} + +@cached +operation JSL!TransferDeclaration isUpdateSupported(): Boolean { + if (self.map.isDefined()) { + return self.members.exists(m | m.isKindOf(JSL!TransferUpdateDeclaration) and m.isEventInstead()); + } + return false; +} + +@cached +operation JSL!TransferDeclaration isDefinedAsInputParameter(): Boolean { + return JSL!TransferActionDeclaration.all().collect(a | a.getParameterType()).contains(self); +} + +@cached +operation JSL!TransferDeclaration isGetTemplateSupported(): Boolean { + if (self.isCreateSupported()) { + return true; + } + if (self.map.isUndefined()) { + return self.isDefinedAsInputParameter(); + } + return false; +} + +@cached +operation JSL!TransferDeclaration isRefreshSupported(): Boolean { + return self.map.isDefined(); } diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferFieldDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferFieldDeclaration.eol index 4afec996..f0ac18a5 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferFieldDeclaration.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferFieldDeclaration.eol @@ -1,11 +1,3 @@ -@cached -operation JSL!TransferFieldDeclaration getActorDeclaration(): JSL!ActorDeclaration { - if (self.eContainer.isKindOf(JSL!TransferDeclaration)) { - return self.eContainer.getActorDeclaration(); - } - return null; -} - @cached operation JSL!TransferFieldDeclaration getId(): String { return (self.eContainer.getId() + "/" + self.name); @@ -31,14 +23,19 @@ operation JSL!TransferFieldDeclaration reads(): Boolean { return jslUtils.isReads(self); } +@cached +operation JSL!TransferFieldDeclaration isTransient(): Boolean { + return not self.maps() and not self.reads(); +} + @cached operation JSL!TransferFieldDeclaration getFqName(): String { return self.eContainer.getFqName() + "#" + self.name; } @cached -operation JSL!TransferFieldDeclaration getTransferFieldDeclarationEquivalent() : UI!ui::data::AttributeType { - if (not self.maps() and not self.reads()) { +operation JSL!TransferFieldDeclaration getTransferFieldDeclarationEquivalent(): UI!ui::data::AttributeType { + if (self.isTransient()) { return self.equivalent("CreateTransientTransferAttribute"); } if (self.reads()) { @@ -51,7 +48,28 @@ operation JSL!TransferFieldDeclaration getTransferFieldDeclarationEquivalent() : } @cached -operation JSL!TransferFieldDeclaration isSortable() : Boolean { +operation JSL!TransferFieldDeclaration getTransferContainer(): JSL!TransferDeclaration { + if (self.eContainer.isKindOf(JSL!TransferDeclaration)) { + return self.eContainer; + } else if (self.eContainer.isKindOf(JSL!ViewPanelDeclaration)) { + return self.eContainer.getTransferContainer(); + } + return null; +} + +@cached +operation JSL!TransferFieldDeclaration getContainerEquivalentClassType(): UI!ui::data::ClassType { + var container = self.getTransferContainer(); + if (container.isDefined() and container.isTypeOf(JSL!ActorDeclaration)) { + return self.getTransferContainer().equivalent("Actor"); + } else if (container.isDefined() and container.isKindOf(JSL!TransferDeclaration)) { + return self.getTransferContainer().equivalent("ClassType"); + } + return null; +} + +@cached +operation JSL!TransferFieldDeclaration isSortable(): Boolean { if (self.referenceType.`primitive`.isUndefined()) { return false; } @@ -66,7 +84,7 @@ operation JSL!TransferFieldDeclaration isSortable() : Boolean { } @cached -operation JSL!TransferFieldDeclaration isFilterable() : Boolean { +operation JSL!TransferFieldDeclaration isFilterable(): Boolean { if (self.referenceType.`primitive`.isUndefined()) { return false; } diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferRelationDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferRelationDeclaration.eol index 7a0ac1a0..0982c5aa 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferRelationDeclaration.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/transferRelationDeclaration.eol @@ -8,7 +8,162 @@ operation JSL!TransferRelationDeclaration getFqName(): String { return self.eContainer.getFqName() + "::" + self.name; } +@cached +operation JSL!TransferRelationDeclaration isEager(): Boolean { + return jslUtils.isEager(self); +} + @cached operation JSL!TransferRelationDeclaration getDetail(): JSL!DetailModifier { return self.modifiers.selectOne(m | m.isTypeOf(JSL!DetailModifier)); } + +@cached +operation JSL!TransferRelationDeclaration isAggregation(): Boolean { + return jslUtils.isAggregation(self); +} + +@cached +operation JSL!TransferRelationDeclaration isRequired(): Boolean { + return jslUtils.isRequired(self); +} + +@cached +operation JSL!TransferRelationDeclaration maps(): Boolean { + return jslUtils.isMaps(self); +} + +@cached +operation JSL!TransferRelationDeclaration reads(): Boolean { + return jslUtils.isReads(self); +} + +@cached +operation JSL!TransferRelationDeclaration isTransient(): Boolean { + return not self.maps() and not self.reads(); +} + +@cached +operation JSL!TransferRelationDeclaration isListAllowed(): Boolean { + return self.maps() or self.reads(); +} + +@cached +operation JSL!TransferRelationDeclaration isTemplateAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!DefaultModifier)); +} + +@cached +operation JSL!TransferRelationDeclaration isCreateAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!CreateModifier) and m.`true`); +} + +@cached +operation JSL!TransferRelationDeclaration isValidateCreateAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!CreateModifier) and m.`true`); +} + +@cached +operation JSL!TransferRelationDeclaration isUpdateAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!UpdateModifier) and m.`true`); +} + +@cached +operation JSL!TransferRelationDeclaration isValidateUpdateAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!UpdateModifier) and m.`true`); +} + +@cached +operation JSL!TransferRelationDeclaration isDeleteAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!DeleteModifier) and m.`true`); +} + +@cached +operation JSL!TransferRelationDeclaration isChoiceDefined(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!ChoiceModifier)); +} + +@cached +operation JSL!TransferRelationDeclaration isAddReferenceAllowed(): Boolean { + var lower = self.isRequired() and not self.isMany ? 1 : 0; + var upper = self.isMany ? -1 : 1; + return self.maps() and self.eContainer.isUpdateSupported() + and upper != 1 and (lower < upper or upper == -1); +} + +@cached +operation JSL!TransferRelationDeclaration isRemoveReferenceAllowed(): Boolean { + var lower = self.isRequired() and not self.isMany ? 1 : 0; + var upper = self.isMany ? -1 : 1; + return self.maps() and self.eContainer.isUpdateSupported() + and upper != 1 and (lower < upper or upper == -1); +} + +@cached +operation JSL!TransferRelationDeclaration isSetReferenceAllowed(): Boolean { + return self.maps() and self.eContainer.isUpdateSupported() and not self.isRequired(); +} + +@cached +operation JSL!TransferRelationDeclaration isUnsetReferenceAllowed(): Boolean { + return self.maps() and self.eContainer.isUpdateSupported() and not self.isRequired(); +} + +@cached +operation JSL!TransferRelationDeclaration isGetRangeAllowed(): Boolean { + return self.modifiers.exists(m | m.isTypeOf(JSL!ChoiceModifier)); +} + +@cached +operation JSL!TransferRelationDeclaration isRefreshAllowed(): Boolean { + return self.maps(); +} + +@cached +operation JSL!TransferRelationDeclaration isOrderSupported(): Boolean { + return (self.maps() or self.reads()) and self.referenceType.getAllPrimitiveFields().exists(f | f.isSortable()); +} + +@cached +operation JSL!TransferRelationDeclaration isFilterSupported(): Boolean { + return (self.maps() or self.reads()) and self.referenceType.getAllPrimitiveFields().exists(f | f.isFilterable()); +} + +@cached +operation JSL!TransferRelationDeclaration getMappedTransferRelationEquivalent(): UI!ui::data::RelationType { + var ret = null; + if (self.reads()) { + ret = self.equivalent("CreateDerivedTransferObjectEmbeddedRelationForTransferRelationDeclaration"); + } else if (self.maps()) { + ret = self.equivalent("CreateMappedTransferObjectEmbeddedRelationForTransferRelationDeclaration"); + } else { + ret = self.equivalent("CreateTransientTransferObjectRelationForTransferRelationDeclaration"); + } + if (ret.isUndefined) { + throw "Could not get relation"; + } + return ret; +} + +@cached +operation JSL!TransferRelationDeclaration getTransferContainer(): JSL!TransferDeclaration { + if (self.eContainer.isKindOf(JSL!TransferDeclaration)) { + return self.eContainer; + } else if (self.eContainer.isTypeOf(JSL!ActorGroupDeclaration)) { + return self.eContainer.getActorDeclaration(); + } else if (self.eContainer.isKindOf(JSL!ViewPanelDeclaration)) { + return self.eContainer.getTransferContainer(); + } + return null; +} + +@cached +operation JSL!TransferRelationDeclaration getContainerEquivalentClassType(): UI!ui::data::ClassType { + var container = self.getTransferContainer(); + if (container.isDefined() and container.isTypeOf(JSL!ActorDeclaration)) { + return self.getTransferContainer().equivalent("Actor"); + } else if (container.isDefined() and container.isKindOf(JSL!TransferDeclaration)) { + return self.getTransferContainer().equivalent("ClassType"); + } + return null; +} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/_importNamespace.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/_importNamespace.eol index e69de29b..9d18379d 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/_importNamespace.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/_importNamespace.eol @@ -0,0 +1,2 @@ +import "modelDeclaration.eol"; +import "modifiable.eol"; diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/modelDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/modelDeclaration.eol similarity index 87% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/modelDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/modelDeclaration.eol index 040b8162..4ed0b01a 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/modelDeclaration.eol +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/modelDeclaration.eol @@ -9,7 +9,7 @@ operation JSL!ModelDeclaration getFqName(): String { } @cached -operation String getUniqueModelName() : String { +operation String getUniqueModelName(): String { if (not JSL!ModelDeclaration.all.exists(s | s == self)) { return self; } else { diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/modifiable.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/modifiable.eol new file mode 100644 index 00000000..40678932 --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/namespace/modifiable.eol @@ -0,0 +1,89 @@ +@cached +operation JSL!Modifiable getId(): String { + return (self.eContainer.getId() + "/" + self.id); +} + +@cached +operation JSL!Modifiable getLabelModifier(): JSL!Modifier { + return self.modifiers.selectOne(m | m.isTypeOf(JSL!LabelModifier)); +} + +@cached +operation JSL!Modifiable getIconModifier(): JSL!Modifier { + return self.modifiers.selectOne(m | m.isTypeOf(JSL!IconModifier)); +} + +@cached +operation JSL!Modifiable getPrecision(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "precision")); +} + +@cached +operation JSL!Modifiable getScale(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "scale")); +} + +@cached +operation JSL!Modifiable getRegex(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "regex")); +} + +@cached +operation JSL!Modifiable getRequired(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "required")); +} + +@cached +operation JSL!Modifiable getMaxSize(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "max-size")); +} + +@cached +operation JSL!Modifiable getMaxFileSize(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "max-file-size")); +} + +@cached +operation JSL!Modifiable getMinSize(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "min-size")); +} + +@cached +operation JSL!Modifiable getMimeType(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "mime-type")); +} + +@cached +operation JSL!Modifiable getOpposite(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "opposite" or m.type == "opposite-add")); +} + +@cached +operation JSL!Modifiable getDefault(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "default")); +} + +@cached +operation JSL!Modifiable getChoices(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "choices")); +} + +@cached +operation JSL!Modifiable getBind(): JSL!Modifier { + return (self.modifiers.selectOne(m | m.type == "bind")); +} + +@cached +operation JSL!Modifiable isEventInstead(): Boolean { + return (not self.modifiers.exists(m|m.type == "on")); +} + +@cached +operation JSL!Modifiable isEventBefore(): Boolean { + return (self.modifiers.exists(m|m.type == "on" and m.before)); +} + +@cached +operation JSL!Modifiable isEventAfter(): Boolean { + return (self.modifiers.exists(m|m.type == "on" and m.after)); +} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/_importUI.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/_importUI.eol new file mode 100644 index 00000000..f23b932e --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/_importUI.eol @@ -0,0 +1,3 @@ +import "viewDeclaration.eol"; +import "viewPanelDeclaration.eol"; +import "visibleDeclaration.eol"; diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/viewDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/viewDeclaration.eol similarity index 100% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/viewDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/viewDeclaration.eol diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/viewPanelDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/viewPanelDeclaration.eol new file mode 100644 index 00000000..29046906 --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/viewPanelDeclaration.eol @@ -0,0 +1,52 @@ +@cached +operation JSL!ViewPanelDeclaration getAllRelations(): Set { + var relations = new Set(); + + if (self.isTypeOf(JSL!ViewGroupDeclaration)) { + relations.addAll(self.members.select(m | m.isKindOf(JSL!TransferRelationDeclaration))); + for (group in self.members.select(m | m.isKindOf(JSL!ViewGroupDeclaration))) { + relations.addAll(group.getAllRelations()); + } + for (tabs in self.members.select(m | m.isKindOf(JSL!ViewTabsDeclaration))) { + relations.addAll(tabs.getAllRelations()); + } + } else if (self.isTypeOf(JSL!ViewTabsDeclaration)) { + for (group in self.groups) { + relations.addAll(group.getAllRelations()); + } + } + + return relations; +} + +@cached +operation JSL!ViewPanelDeclaration getAllPrimitiveFields(): Set { + var fields = new Set(); + + if (self.isTypeOf(JSL!ViewGroupDeclaration)) { + fields.addAll(self.members.select(m | m.isKindOf(JSL!TransferFieldDeclaration) and m.referenceType.isDefined() and m.referenceType.`primitive`.isDefined())); + for (group in self.members.select(m | m.isKindOf(JSL!ViewGroupDeclaration))) { + fields.addAll(group.getAllPrimitiveFields()); + } + for (tab in self.members.select(m | m.isKindOf(JSL!ViewTabsDeclaration))) { + fields.addAll(tab.getAllPrimitiveFields()); + } + } else if (self.isTypeOf(JSL!ViewTabsDeclaration)) { + for (group in self.groups) { + fields.addAll(group.getAllPrimitiveFields()); + } + } + + return fields; +} + +@cached +operation JSL!ViewPanelDeclaration getTransferContainer(): JSL!TransferDeclaration { + if (self.eContainer.isKindOf(JSL!TransferDeclaration)) { + return self.eContainer; + } else if (self.eContainer.isKindOf(JSL!ViewPanelDeclaration)) { + return self.eContainer.getTransferContainer(); + } + + return null; +} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/visibleDeclaration.eol b/judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/visibleDeclaration.eol similarity index 100% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/data/visibleDeclaration.eol rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/operations/jsl/ui/visibleDeclaration.eol diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/jslToUi.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/jslToUi.etl index 2f5afd63..bd74121d 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/jslToUi.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/jslToUi.etl @@ -4,13 +4,15 @@ import "modules/application/actorDeclaration.etl"; import "modules/application/actorGroupDeclaration.etl"; import "modules/application/actorLinkDeclaration.etl"; import "modules/application/modifiable.etl"; -import "modules/application/transferFieldDeclaration.etl"; -import "modules/application/viewDeclaration.etl"; -import "modules/structure/class.etl"; +import "modules/structure/transferDeclaration.etl"; +import "modules/structure/transferFieldDeclaration.etl"; +import "modules/structure/transferRelationDeclaration.etl"; import "modules/type/type.etl"; +import "modules/view/viewDeclaration.etl"; + pre { var ecoreUtil = new Native("org.eclipse.emf.ecore.util.EcoreUtil"); var __cacheMap = new ConcurrentMap(); diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorDeclaration.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorDeclaration.etl index c4288e2e..982ae687 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorDeclaration.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorDeclaration.etl @@ -1,9 +1,9 @@ rule Application transform s: JSL!ActorDeclaration to t: UI!ui::Application { - guard: s = actorDeclaration + guard: s = actorDeclaration - t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/Application"); + t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/Application"); log.debug("Application: " + s.name); @@ -23,11 +23,11 @@ rule Application } //if (s.defaultLanguage.isDefined()) { - t.defaultLanguage = "en-US"; + t.defaultLanguage = "en-US"; //} //if (s.applicationLogo.isDefined()) { - t.logo = "judo-color-logo.png"; + t.logo = "judo-color-logo.png"; //} t.navigationController = s.equivalent("NavigationController"); @@ -36,8 +36,8 @@ rule Application rule Theme transform s: JSL!ActorDeclaration to t: UI!ui::Theme { - t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/Theme"); - /* + t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/Theme"); + /* if (s.textPrimaryColor.isDefined()) { t.textPrimaryColor = s.textPrimaryColor; } diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorGroupDeclaration.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorGroupDeclaration.etl index 04b0853c..e7e55e30 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorGroupDeclaration.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/actorGroupDeclaration.etl @@ -3,8 +3,8 @@ rule MenuItemGroup to t : UI!ui::NavigationItem { guard: s.getActorDeclaration().isDefined() and s.getActorDeclaration() == actorDeclaration - t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/MenuItemGroup"); - t.name = s.getFqName(); + t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/MenuItemGroup"); + t.name = s.getFqName(); log.debug("Create Navigation Group: " + s.name ); diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/modifiable.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/modifiable.etl index 58bbbd21..1e3c509e 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/modifiable.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/modifiable.etl @@ -6,3 +6,15 @@ rule IconModifierIcon t.name = s.getId() + "/Icon"; t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/IconModifierIcon"); } + +rule ClaimModifier + transform s: JSL!ClaimModifier + to t: UI!ui::Claim { + guard: s.eContainer == actorDeclaration and s.eContainer.getIdentity().isDefined() + + t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/ClaimModifier"); + t.attributeType = s.eContainer.getIdentity().field.getTransferFieldDeclarationEquivalent(); + t.type = UI!ui::ClaimType#UNDEFINED; // UI is not relying on this info, at least we think it doesn't + + s.eContainer.equivalent("Authentication").claims.add(t); +} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/class.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferDeclaration.etl similarity index 81% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/class.etl rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferDeclaration.etl index 3c51d660..c1923138 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/class.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferDeclaration.etl @@ -7,14 +7,13 @@ rule ClassType t.setId(actorDeclaration.name + "/(jsl/" + s.getId() + ")/ClassType"); t.name = s.getFqName() + "::ClassType"; - //t.transferObjectTypeName = s.transferObjectTypeName(); + t.transferObjectTypeName = s.name; t.simpleName = s.name; //t.setPackageNameTokens(s); - // t.isMapped = s.isMapped(); + t.isMapped = s.map.isDefined(); // t.isOptional = s.isMapped(); - /* if (s.isRefreshSupported()) { t.behaviours.add(UI!ui::data::ClassBehaviourType#REFRESH); } @@ -22,10 +21,6 @@ rule ClassType t.behaviours.add(UI!ui::data::ClassBehaviourType#UPDATE); t.isForCreateOrUpdateType = true; } - if (s.isValidateUpdateSupported()) { - t.behaviours.add(UI!ui::data::ClassBehaviourType#VALIDATE_UPDATE); - t.isForCreateOrUpdateType = true; - } if (s.isDeleteSupported()) { t.behaviours.add(UI!ui::data::ClassBehaviourType#DELETE); @@ -35,7 +30,6 @@ rule ClassType t.behaviours.add(UI!ui::data::ClassBehaviourType#TEMPLATE); t.isOptional = true; } - */ actorDeclaration.equivalent("Application").dataElements.add(t); diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/transferFieldDeclaration.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferFieldDeclaration.etl similarity index 82% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/transferFieldDeclaration.etl rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferFieldDeclaration.etl index aa35eaee..51e2f897 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/transferFieldDeclaration.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferFieldDeclaration.etl @@ -2,10 +2,8 @@ rule AbstractCreateTransferAttribute transform s: JSL!TransferFieldDeclaration to t: UI!ui::data::AttributeType { - guard: s.getActorDeclaration().isDefined() - and s.getActorDeclaration() == actorDeclaration - and s.referenceType.isKindOf(JSL!PrimitiveDeclaration) - and actorDeclaration.getExposedTransferObjects().includes(s.eContainer) + guard: s.referenceType.isKindOf(JSL!PrimitiveDeclaration) + and actorDeclaration.getExposedTransferObjects().includes(s.getTransferContainer()) t.name = s.name; @@ -25,7 +23,7 @@ rule CreateTransientTransferAttribute t.memberType = UI!ui::data::MemberType#TRANSIENT; t.isReadOnly = false; - s.eContainer.equivalent("ClassType").attributes.add(t); + s.getContainerEquivalentClassType().attributes.add(t); log.debug("Created AttributeType (Transient) for TransferFieldDeclaration: [" + t.name + "] into [" + t.eContainer.name + "]"); } @@ -40,7 +38,7 @@ rule CreateDerivedTransferAttribute t.memberType = UI!ui::data::MemberType#DERIVED; t.isReadOnly = true; - s.eContainer.equivalent("ClassType").attributes.add(t); + s.getContainerEquivalentClassType().attributes.add(t); log.debug("Created AttributeType (Derived) for TransferFieldDeclaration: [" + t.name + "] into [" + t.eContainer.name + "]"); } @@ -55,6 +53,6 @@ rule CreateMappedTransferAttribute t.memberType = UI!ui::data::MemberType#MAPPED; t.isReadOnly = false; - s.eContainer.equivalent("ClassType").attributes.add(t); + s.getContainerEquivalentClassType().attributes.add(t); log.debug("Created AttributeType (Mapped) for TransferFieldDeclaration: [" + t.name + "] into [" + t.eContainer.name + "]"); } diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferRelationDeclaration.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferRelationDeclaration.etl new file mode 100644 index 00000000..ae928a2d --- /dev/null +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/structure/transferRelationDeclaration.etl @@ -0,0 +1,118 @@ +@abstract +rule AbstractRelationType + transform s: JSL!TransferRelationDeclaration + to t: UI!ui::data::RelationType { + guard: actorDeclaration.getExposedRelations().includes(s) + + t.name = s.name; + t.target = s.referenceType.equivalent("ClassType"); + t.isOptional = not s.isRequired() or s.isMany; + t.isCollection = s.isMany; + t.isReadOnly = s.reads(); + + t.memberType = UI!ui::data::MemberType#TRANSIENT; + + if (s.isAggregation()) { + t.relationKind = UI!ui::data::RelationKind#AGGREGATION; + } else { + t.relationKind = UI!ui::data::RelationKind#ASSOCIATION; + } + + if (s.reads()) { + t.memberType = UI!ui::data::MemberType#DERIVED; + } else if (s.maps()) { + var entityMember = s.getterExpr.features.first.member; + + if (not entityMember.isTypeOf(JSL!EntityRelationOppositeInjected)) { + if (entityMember.isCalculated()) { + t.memberType = UI!ui::data::MemberType#DERIVED; + } else { + t.memberType = UI!ui::data::MemberType#STORED; + } + } else { + // TODO handle opposite add......... + t.memberType = UI!ui::data::MemberType#STORED; + } + } else { + t.memberType = UI!ui::data::MemberType#TRANSIENT; + } + +/* + if (s.isInlineCreateSupported()) { + t.isInlineCreatable = true; + } +*/ + + if (s.isListAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#LIST); + } + if (s.isTemplateAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#TEMPLATE); + } + if (s.isCreateAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#CREATE); + t.target.isForCreateOrUpdateType = true; + } + if (s.isValidateCreateAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#VALIDATE_CREATE); + t.target.isForCreateOrUpdateType = true; + } + if (s.isSetReferenceAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#SET); + } + if (s.isUnsetReferenceAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#UNSET); + } + if (s.isAddReferenceAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#ADD); + } + if (s.isRemoveReferenceAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#REMOVE); + } + if (s.isGetRangeAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#RANGE); + t.isOptional = true; + } + if (s.isRefreshAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#REFRESH); + } + /* + if (s.isExportSupported()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#EXPORT); + } + */ + if (s.isUpdateAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#UPDATE); + t.target.isForCreateOrUpdateType = true; + } + if (s.isValidateUpdateAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#VALIDATE_UPDATE); + t.target.isForCreateOrUpdateType = true; + } + if (s.isDeleteAllowed()) { + t.behaviours.add(UI!ui::data::RelationBehaviourType#DELETE); + } + + t.isOrderable = s.isOrderSupported(); + t.isFilterable = s.isFilterSupported(); +} + +@greedy +rule RelationType + transform s: JSL!TransferRelationDeclaration + to t: UI!ui::data::RelationType + extends AbstractRelationType { + t.setId("(jsl/" + s.getId() + ")/RelationType"); + var containerClassType = s.getContainerEquivalentClassType(); + containerClassType.relations.add(t); + log.debug("Created RelationType [" + t.name + "] into [" + containerClassType.name + "]"); +} + +@lazy +@greedy +rule CloneRelationType + transform s: JSL!TransferRelationDeclaration + to t: UI!ui::data::RelationType + extends AbstractRelationType { + log.debug("Cloned RelationType [" + t.name + "]"); +} diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/type/type.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/type/type.etl index 026a26c7..ae2c4362 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/type/type.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/type/type.etl @@ -75,8 +75,8 @@ rule CreateEnumerationMember @greedy rule CreateBooleanType - transform s : JSL!DataTypeDeclaration - to t : UI!ui::data::BooleanType { + transform s : JSL!DataTypeDeclaration + to t : UI!ui::data::BooleanType { guard: s.`primitive` == "boolean" and ((s.getActorDeclaration().isDefined() and s.getActorDeclaration() == actorDeclaration) or s.eContainer.name == "judo::types") t.setId("(jsl/" + s.getId() + ")/CreateBooleanType"); @@ -87,8 +87,8 @@ rule CreateBooleanType @greedy rule CreateStringType - transform s : JSL!DataTypeDeclaration - to t : UI!ui::data::StringType { + transform s : JSL!DataTypeDeclaration + to t : UI!ui::data::StringType { guard: s.`primitive` == "string" and ((s.getActorDeclaration().isDefined() and s.getActorDeclaration() == actorDeclaration) or s.eContainer.name == "judo::types") t.setId("(jsl/" + s.getId() + ")/CreateStringType"); @@ -107,13 +107,13 @@ rule CreateStringType rule MimeType transform s: String to t: UI!ui::data::MimeType { - t.setId("(jsl/" + s + ")/MimeType"); - var split = s.split("/"); - t.type = split[0]; - t.subType = split[1]; + t.setId("(jsl/" + s + ")/MimeType"); + var split = s.split("/"); + t.type = split[0]; + t.subType = split[1]; - actorDeclaration.equivalent("Application").mimeTypes.add(t); - log.debug("Created MimeType: " + s); + actorDeclaration.equivalent("Application").mimeTypes.add(t); + log.debug("Created MimeType: " + s); } @greedy diff --git a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/viewDeclaration.etl b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/view/viewDeclaration.etl similarity index 96% rename from judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/viewDeclaration.etl rename to judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/view/viewDeclaration.etl index 33a87163..00141d5d 100644 --- a/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/application/viewDeclaration.etl +++ b/judo-tatami-jsl-jsl2ui/src/main/epsilon/transformations/ui/modules/view/viewDeclaration.etl @@ -10,6 +10,8 @@ rule AccessPageDefinition actorDeclaration.equivalent("Application").pages.add(t); + t.dataElement = s.equivalent("RelationType"); + log.debug("Create AccessPageDefinition: " + t.name); } diff --git a/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiApplicationTest.java b/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiApplicationTest.java index 0bedd4ad..e958f325 100644 --- a/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiApplicationTest.java +++ b/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiApplicationTest.java @@ -4,6 +4,7 @@ import hu.blackbelt.judo.meta.ui.*; import hu.blackbelt.judo.meta.ui.data.ClassType; import hu.blackbelt.judo.meta.ui.data.DataType; +import hu.blackbelt.judo.meta.ui.data.RelationType; import hu.blackbelt.judo.tatami.jsl.jsl2ui.AbstractTest; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeAll; @@ -182,68 +183,69 @@ row ProductRow(Product product) { void testMultipleActors() throws Exception { jslModel = JslParser.getModelFromStrings("MultipleActorsTestModel", List.of(""" model MultipleActorsTestModel; - + import judo::types; - + entity User { identifier String userName required; } - + entity User2 { - identifier String userName required; + identifier String userName2 required; } - + entity Product { identifier String name required; field Integer price required; } - + entity Product2 { identifier String name2 required; field Integer price2 required; } - + view ProductListView { - table ProductRow[] products <= Product.all(); + table ProductRow[] productsOnList <= Product.all(); } - + view ProductListView2 { - table ProductRow2[] products2 <= Product2.all(); + table ProductRow2[] products2OnList <= Product2.all(); } - + view ProductDetailView(Product product) { field String name <= product.name; field Integer priceNumber <= product.price; field String price <= product.price.asString() + " HUF"; } - + view ProductDetailView2(Product2 product2) { field String name2 <= product2.name2; + field Integer priceNumber2 <= product2.price2; field String price2 <= product2.price2.asString() + " HUF"; } - + row ProductRow(Product product) { link ProductDetailView detail <= product eager detail; field String name <= product.name; field String price <= product.price.asString() + " HUF"; } - + row ProductRow2(Product2 product2) { - link ProductDetailView2 detail <= product2 eager detail; - field String name <= product2.name2; - field String price <= product2.price2.asString() + " HUF"; + link ProductDetailView2 detail2 <= product2 eager detail; + field String name2 <= product2.name2; + field String price2 <= product2.price2.asString() + " HUF"; } - + actor Actor1 human { group first label:"Group1" { - link ProductListView products2 label:"Products11"; + link ProductListView products1 label:"Products1"; } link ProductListView allProducts label:"All Products" icon:"tools"; } - + actor Actor2 human { group first label:"Group2" { - link ProductListView2 products22 label:"Products21"; + link ProductListView2 products2 label:"Products2"; } link ProductListView2 allProducts2 label:"All Products 2" icon:"tools"; } @@ -322,41 +324,61 @@ row ProductRow2(Product2 product2) { // Data Elements List classTypes = app1.getClassTypes(); + List relationTypes = app1.getRelationTypes(); assertEquals(4, classTypes.size()); + assertEquals(4, relationTypes.size()); Set class1Names = classTypes.stream().map(c -> c.getName()).collect(Collectors.toSet()); + Set relations1Names = relationTypes.stream().map(c -> c.getFQName()).collect(Collectors.toSet()); - assertTrue(Set.of( + assertEquals(Set.of( "MultipleActorsTestModel::Actor1::ClassType", "MultipleActorsTestModel::ProductDetailView::ClassType", "MultipleActorsTestModel::ProductListView::ClassType", "MultipleActorsTestModel::ProductRow::ClassType" - ).containsAll(class1Names)); + ), class1Names); + + assertEquals(Set.of( + "Actor1::Application::MultipleActorsTestModel::Actor1::ClassType::products1", + "Actor1::Application::MultipleActorsTestModel::Actor1::ClassType::allProducts", + "Actor1::Application::MultipleActorsTestModel::ProductListView::ClassType::productsOnList", + "Actor1::Application::MultipleActorsTestModel::ProductRow::ClassType::detail" + ), relations1Names); List dataTypes1 = app1.getDataTypes(); Set dataTypes1Names = dataTypes1.stream().map(c -> c.getName()).collect(Collectors.toSet()); - assertTrue(Set.of( + assertEquals(Set.of( "Integer", "String" - ).containsAll(dataTypes1Names)); + ), dataTypes1Names); assertTrue(getXMIID(dataTypes1.get(0)).contains("judo::types")); assertTrue(getXMIID(dataTypes1.get(1)).contains("judo::types")); List classTypes2 = app2.getClassTypes(); + List relationsTypes2 = app2.getRelationTypes(); assertEquals(4, classTypes2.size()); + assertEquals(4, relationsTypes2.size()); Set class2Names = classTypes2.stream().map(c -> c.getName()).collect(Collectors.toSet()); + Set relations2Names = relationsTypes2.stream().map(c -> c.getFQName()).collect(Collectors.toSet()); - assertTrue(Set.of( + assertEquals(Set.of( "MultipleActorsTestModel::Actor2::ClassType", "MultipleActorsTestModel::ProductDetailView2::ClassType", "MultipleActorsTestModel::ProductListView2::ClassType", "MultipleActorsTestModel::ProductRow2::ClassType" - ).containsAll(class2Names)); + ), class2Names); + + assertEquals(Set.of( + "Actor2::Application::MultipleActorsTestModel::Actor2::ClassType::products2", + "Actor2::Application::MultipleActorsTestModel::Actor2::ClassType::allProducts2", + "Actor2::Application::MultipleActorsTestModel::ProductListView2::ClassType::products2OnList", + "Actor2::Application::MultipleActorsTestModel::ProductRow2::ClassType::detail2" + ), relations2Names); // Pages @@ -367,7 +389,7 @@ row ProductRow2(Product2 product2) { PageDefinition page = pages.get(0); PageDefinition page2 = pages.get(1); - assertEquals("MultipleActorsTestModel::Actor1::MenuItemGroup::first::products2::PageDefinition", page.getName()); + assertEquals("MultipleActorsTestModel::Actor1::MenuItemGroup::first::products1::PageDefinition", page.getName()); assertEquals("MultipleActorsTestModel::Actor1::allProducts::PageDefinition", page2.getName()); List pages2 = app2.getPages(); @@ -377,7 +399,7 @@ row ProductRow2(Product2 product2) { PageDefinition page21 = pages2.get(0); PageDefinition page22 = pages2.get(1); - assertEquals("MultipleActorsTestModel::Actor2::MenuItemGroup::first::products22::PageDefinition", page21.getName()); + assertEquals("MultipleActorsTestModel::Actor2::MenuItemGroup::first::products2::PageDefinition", page21.getName()); assertEquals("MultipleActorsTestModel::Actor2::allProducts2::PageDefinition", page22.getName()); } @@ -432,5 +454,11 @@ void testSecurity() throws Exception { assertEquals("UserTransfer", principal.getSimpleName()); assertTrue(principal.isIsPrincipal()); + // Claim + + assertEquals(1, authentication.getClaims().size()); + assertEquals("UNDEFINED", authentication.getClaims().get(0).getType().getName()); + assertEquals(principal.getAttributes().stream().filter(a -> a.getName().equals("email")).findFirst().orElse(null), authentication.getClaims().get(0).getAttributeType()); + } } diff --git a/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiDataTest.java b/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiDataTest.java index 3e5e7640..39074a06 100644 --- a/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiDataTest.java +++ b/judo-tatami-jsl-jsl2ui/src/test/java/hu/blackbelt/judo/tatami/jsl/jsl2ui/application/JslModel2UiDataTest.java @@ -12,7 +12,10 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.*; @@ -115,14 +118,14 @@ enum MyEnum { // DataTypes var dataTypes = app.getDataTypes(); - StringType stringType = (StringType) dataTypes.stream().filter(t -> t instanceof StringType).findFirst().get(); - BooleanType booleanType = (BooleanType) dataTypes.stream().filter(t -> t instanceof BooleanType).findFirst().get(); - BinaryType binaryType = (BinaryType) dataTypes.stream().filter(t -> t instanceof BinaryType).findFirst().get(); - NumericType numericType = (NumericType) dataTypes.stream().filter(t -> t instanceof NumericType).findFirst().get(); - EnumerationType enumType = (EnumerationType) dataTypes.stream().filter(t -> t instanceof EnumerationType).findFirst().get(); - DateType dateType = (DateType) dataTypes.stream().filter(t -> t instanceof DateType).findFirst().get(); - TimeType timeType = (TimeType) dataTypes.stream().filter(t -> t instanceof TimeType).findFirst().get(); - TimestampType timestampType = (TimestampType) dataTypes.stream().filter(t -> t instanceof TimestampType).findFirst().get(); + StringType stringType = (StringType) dataTypes.stream().filter(t -> t instanceof StringType).findFirst().orElseThrow(); + BooleanType booleanType = (BooleanType) dataTypes.stream().filter(t -> t instanceof BooleanType).findFirst().orElseThrow(); + BinaryType binaryType = (BinaryType) dataTypes.stream().filter(t -> t instanceof BinaryType).findFirst().orElseThrow(); + NumericType numericType = (NumericType) dataTypes.stream().filter(t -> t instanceof NumericType).findFirst().orElseThrow(); + EnumerationType enumType = (EnumerationType) dataTypes.stream().filter(t -> t instanceof EnumerationType).findFirst().orElseThrow(); + DateType dateType = (DateType) dataTypes.stream().filter(t -> t instanceof DateType).findFirst().orElseThrow(); + TimeType timeType = (TimeType) dataTypes.stream().filter(t -> t instanceof TimeType).findFirst().orElseThrow(); + TimestampType timestampType = (TimestampType) dataTypes.stream().filter(t -> t instanceof TimestampType).findFirst().orElseThrow(); assertEquals(8, dataTypes.size()); @@ -168,77 +171,77 @@ enum MyEnum { AttributeAssertion asserter = new AttributeAssertion("Actor::Application::BasicDataTestModel::UserTransfer::ClassType::"); - ClassType userTransfer = (ClassType) app.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("BasicDataTestModel::UserTransfer::ClassType")).findFirst().get(); + ClassType userTransfer = (ClassType) app.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("BasicDataTestModel::UserTransfer::ClassType")).findFirst().orElseThrow(); assertNotNull(userTransfer); assertEquals(23, userTransfer.getAttributes().size()); - AttributeType email = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("email")).findFirst().get(); + AttributeType email = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("email")).findFirst().orElseThrow(); asserter.assertAttributeType(email, "email", "String", MemberType.MAPPED, true, true, false); - AttributeType binaryDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("binaryDerived")).findFirst().get(); + AttributeType binaryDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("binaryDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(binaryDerived, "binaryDerived", "Binary", MemberType.DERIVED, false, false, true); - AttributeType stringDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("stringDerived")).findFirst().get(); + AttributeType stringDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("stringDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(stringDerived, "stringDerived", "String", MemberType.DERIVED, false, true, true); - AttributeType booleanDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("booleanDerived")).findFirst().get(); + AttributeType booleanDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("booleanDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(booleanDerived, "booleanDerived", "Boolean", MemberType.DERIVED, false, true, true); - AttributeType dateDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("dateDerived")).findFirst().get(); + AttributeType dateDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("dateDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(dateDerived, "dateDerived", "Date", MemberType.DERIVED, false, true, true); - AttributeType numericDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("numericDerived")).findFirst().get(); + AttributeType numericDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("numericDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(numericDerived, "numericDerived", "Numeric", MemberType.DERIVED, false, true, true); - AttributeType timeDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timeDerived")).findFirst().get(); + AttributeType timeDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timeDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(timeDerived, "timeDerived", "Time", MemberType.DERIVED, false, true, true); - AttributeType timestampDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timestampDerived")).findFirst().get(); + AttributeType timestampDerived = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timestampDerived")).findFirst().orElseThrow(); asserter.assertAttributeType(timestampDerived, "timestampDerived", "Timestamp", MemberType.DERIVED, false, true, true); - AttributeType mappedEnum = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("mappedEnum")).findFirst().get(); + AttributeType mappedEnum = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("mappedEnum")).findFirst().orElseThrow(); asserter.assertAttributeType(mappedEnum, "mappedEnum", "MyEnum", MemberType.MAPPED, false, false, false); - AttributeType binaryTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("binaryTransient")).findFirst().get(); + AttributeType binaryTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("binaryTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(binaryTransient, "binaryTransient", "Binary", MemberType.TRANSIENT, false, false, false); - AttributeType stringTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("stringTransient")).findFirst().get(); + AttributeType stringTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("stringTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(stringTransient, "stringTransient", "String", MemberType.TRANSIENT, false, false, false); - AttributeType booleanTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("booleanTransient")).findFirst().get(); + AttributeType booleanTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("booleanTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(booleanTransient, "booleanTransient", "Boolean", MemberType.TRANSIENT, false, false, false); - AttributeType dateTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("dateTransient")).findFirst().get(); + AttributeType dateTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("dateTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(dateTransient, "dateTransient", "Date", MemberType.TRANSIENT, false, false, false); - AttributeType numericTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("numericTransient")).findFirst().get(); + AttributeType numericTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("numericTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(numericTransient, "numericTransient", "Numeric", MemberType.TRANSIENT, false, false, false); - AttributeType timeTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timeTransient")).findFirst().get(); + AttributeType timeTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timeTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(timeTransient, "timeTransient", "Time", MemberType.TRANSIENT, false, false, false); - AttributeType timestampTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timestampTransient")).findFirst().get(); + AttributeType timestampTransient = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timestampTransient")).findFirst().orElseThrow(); asserter.assertAttributeType(timestampTransient, "timestampTransient", "Timestamp", MemberType.TRANSIENT, false, false, false); - AttributeType binaryMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("binaryMapped")).findFirst().get(); + AttributeType binaryMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("binaryMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(binaryMapped, "binaryMapped", "Binary", MemberType.MAPPED, false, false, false); - AttributeType stringMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("stringMapped")).findFirst().get(); + AttributeType stringMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("stringMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(stringMapped, "stringMapped", "String", MemberType.MAPPED, false, true, false); - AttributeType booleanMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("booleanMapped")).findFirst().get(); + AttributeType booleanMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("booleanMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(booleanMapped, "booleanMapped", "Boolean", MemberType.MAPPED, false, true, false); - AttributeType dateMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("dateMapped")).findFirst().get(); + AttributeType dateMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("dateMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(dateMapped, "dateMapped", "Date", MemberType.MAPPED, false, true, false); - AttributeType numericMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("numericMapped")).findFirst().get(); + AttributeType numericMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("numericMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(numericMapped, "numericMapped", "Numeric", MemberType.MAPPED, false, true, false); - AttributeType timeMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timeMapped")).findFirst().get(); + AttributeType timeMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timeMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(timeMapped, "timeMapped", "Time", MemberType.MAPPED, false, true, false); - AttributeType timestampMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timestampMapped")).findFirst().get(); + AttributeType timestampMapped = userTransfer.getAttributes().stream().filter(a -> a.getName().equals("timestampMapped")).findFirst().orElseThrow(); asserter.assertAttributeType(timestampMapped, "timestampMapped", "Timestamp", MemberType.MAPPED, false, true, false); } @@ -289,28 +292,126 @@ row Transfer2Row(Entity2 e2) { Application app = apps.get(0); - ClassType transfer1Row = (ClassType) app.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("BasicDataCrossTransfersTestModel::Transfer1Row::ClassType")).findFirst().get(); + ClassType transfer1Row = (ClassType) app.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("BasicDataCrossTransfersTestModel::Transfer1Row::ClassType")).findFirst().orElseThrow(); assertNotNull(transfer1Row); assertEquals(2, transfer1Row.getAttributes().size()); AttributeAssertion tr1Asserter = new AttributeAssertion("Actor1::Application::BasicDataCrossTransfersTestModel::Transfer1Row::ClassType::"); - AttributeType string = transfer1Row.getAttributes().stream().filter(a -> a.getName().equals("string")).findFirst().get(); + AttributeType string = transfer1Row.getAttributes().stream().filter(a -> a.getName().equals("string")).findFirst().orElseThrow(); tr1Asserter.assertAttributeType(string, "string", "String", MemberType.DERIVED, false, true, true); - AttributeType booleanAttr = transfer1Row.getAttributes().stream().filter(a -> a.getName().equals("boolean")).findFirst().get(); + AttributeType booleanAttr = transfer1Row.getAttributes().stream().filter(a -> a.getName().equals("boolean")).findFirst().orElseThrow(); tr1Asserter.assertAttributeType(booleanAttr, "boolean", "Boolean", MemberType.DERIVED, false, true, true); - ClassType transfer2Row = (ClassType) app.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("BasicDataCrossTransfersTestModel::Transfer2Row::ClassType")).findFirst().get(); + ClassType transfer2Row = (ClassType) app.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("BasicDataCrossTransfersTestModel::Transfer2Row::ClassType")).findFirst().orElseThrow(); assertNotNull(transfer2Row); assertEquals(1, transfer2Row.getAttributes().size()); AttributeAssertion tr2Asserter = new AttributeAssertion("Actor1::Application::BasicDataCrossTransfersTestModel::Transfer2Row::ClassType::"); - AttributeType integer = transfer2Row.getAttributes().stream().filter(a -> a.getName().equals("integer")).findFirst().get(); + AttributeType integer = transfer2Row.getAttributes().stream().filter(a -> a.getName().equals("integer")).findFirst().orElseThrow(); tr2Asserter.assertAttributeType(integer, "integer", "Integer", MemberType.DERIVED, false, true, true); } + @Test + void testNestedFieldsAndRelations() throws Exception { + jslModel = JslParser.getModelFromStrings("NestedFieldsAndRelationsTestModel", List.of(""" + model NestedFieldsAndRelationsTestModel; + + import judo::types; + + entity Entity1 { + field String string; + field Boolean boolean; + } + + row Transfer1Row(Entity1 e1) { + field String stringOnRow <= e1.string; + field Boolean booleanOnRow <= e1.boolean; + } + + view Transfer1View(Entity1 e1) { + field String stringOnView <= e1.string; + field Boolean booleanOnView <= e1.boolean; + } + + view TransferRootView { + group level1 frame { + group level2 { + table Transfer1Row[] tr1s <= Entity1.all(); + link Transfer1View tr1 <= Entity1.any(); + field String transientNested; + } + } + } + + actor ActorForNestedMembers human { + link TransferRootView root label:"Root"; + } + """)); + + transform(); + + List apps = uiModelWrapper.getStreamOfUiApplication().toList(); + + assertEquals(1, apps.size()); + + Application app = apps.get(0); + + List classTypes = app.getClassTypes(); + + assertEquals(4, classTypes.size()); + + ClassType actorClass = classTypes.stream().filter(c -> c.isIsActor()).findFirst().orElseThrow(); + ClassType transferRootViewClass = classTypes.stream().filter(c -> c.getName().equals("NestedFieldsAndRelationsTestModel::TransferRootView::ClassType")).findFirst().orElseThrow(); + ClassType transfer1ViewClass = classTypes.stream().filter(c -> c.getName().equals("NestedFieldsAndRelationsTestModel::Transfer1View::ClassType")).findFirst().orElseThrow(); + ClassType transfer1RowClass = classTypes.stream().filter(c -> c.getName().equals("NestedFieldsAndRelationsTestModel::Transfer1Row::ClassType")).findFirst().orElseThrow(); + + assertEquals("NestedFieldsAndRelationsTestModel::ActorForNestedMembers::ClassType", actorClass.getName()); + assertEquals(1, actorClass.getRelations().size()); + + RelationType relation = actorClass.getRelations().get(0); + assertEquals("root", relation.getName()); + assertEquals(transferRootViewClass, relation.getTarget()); + + assertEquals(1, transferRootViewClass.getAttributes().size()); + assertEquals("transientNested", transferRootViewClass.getAttributes().get(0).getName()); + + assertEquals(2, transferRootViewClass.getRelations().size()); + + RelationType tr1 = transferRootViewClass.getRelations().stream().filter(r -> r.getTarget().equals(transfer1ViewClass)).findFirst().orElseThrow(); + RelationType tr1s = transferRootViewClass.getRelations().stream().filter(r -> r.getTarget().equals(transfer1RowClass)).findFirst().orElseThrow(); + + assertEquals("tr1", tr1.getName()); + assertFalse(tr1.isIsCollection()); + + assertEquals("tr1s", tr1s.getName()); + assertTrue(tr1s.isIsCollection()); + + assertEquals(2, transfer1RowClass.getAttributes().size()); + + AttributeType stringOnRow = transfer1RowClass.getAttributes().stream().filter(a -> a.getName().equals("stringOnRow")).findFirst().orElseThrow(); + AttributeType booleanOnRow = transfer1RowClass.getAttributes().stream().filter(a -> a.getName().equals("booleanOnRow")).findFirst().orElseThrow(); + + assertEquals("String", stringOnRow.getDataType().getName()); + assertTrue(stringOnRow.getIsMemberTypeDerived()); + + assertEquals("Boolean", booleanOnRow.getDataType().getName()); + assertTrue(booleanOnRow.getIsMemberTypeDerived()); + + assertEquals(2, transfer1ViewClass.getAttributes().size()); + + AttributeType stringOnView = transfer1ViewClass.getAttributes().stream().filter(a -> a.getName().equals("stringOnView")).findFirst().orElseThrow(); + AttributeType booleanOnView = transfer1ViewClass.getAttributes().stream().filter(a -> a.getName().equals("booleanOnView")).findFirst().orElseThrow(); + + assertEquals("String", stringOnView.getDataType().getName()); + assertTrue(stringOnView.getIsMemberTypeDerived()); + + assertEquals("Boolean", booleanOnView.getDataType().getName()); + assertTrue(booleanOnView.getIsMemberTypeDerived()); + } + @Test void testRelations() throws Exception { jslModel = JslParser.getModelFromStrings("RelationsTestModel", List.of(""" @@ -323,43 +424,85 @@ void testRelations() throws Exception { field EntityRelated containment; field EntityRelated[] containmentCollection; - + relation EntityRelated association; - relation EntityRelated containmentDerived <= self.containment eager:true; - relation EntityRelated[] containmentCollectionDerived <= self.containmentCollection eager:true; + relation EntityRelated[] associationCollection; + relation EntityRelated derivedContainment <= self.containment eager:true; + relation EntityRelated[] derivedContainmentCollection <= self.containmentCollection eager:true; } entity EntityRelated { - relation User `user` opposite-add:userRelatedOpposite; field String hello; + + relation User user opposite-add:userRelatedOpposite; + relation User userCollection opposite-add:userRelatedOppositeCollection[]; } transfer UserTransfer maps User as u { field String email <= u.email bind; - relation UnmappedRelated unmappedContainment; - relation UnmappedRelated unmappedContainmentRequired required; - relation UnmappedRelated[] unmappedContainmentCollection; - - relation MappedRelated mappedAssociation <= u.association create:true; - relation MappedRelated mappedAssociationOpposite <= u.userRelatedOpposite create:true; - relation MappedRelated derivedAssociation <= u.association; - relation MappedRelated derivedAssociationOpposite <= u.userRelatedOpposite create:true; - relation MappedRelated derivedContainmentStatic <= EntityRelated.any(); - relation MappedRelated[] derivedContainmentCollectionStatic <= EntityRelated.all(); - relation MappedRelated mappedContainmentDerived <= u.containmentDerived; - relation MappedRelated[] mappedContainmentCollectionDerived <= u.containmentCollectionDerived; } - transfer UnmappedRelated { - field String someField; + view UserView(User u) { + link UnmappedRelated unmappedLazy; + link UnmappedRelated unmappedLazyRequired required; + table UnmappedRelatedRow[] unmappedLazyCollection; + + link MappedRelated lazyAssociation <= u.association create:true update:true delete:true; + link MappedRelated lazyAssociationOpposite <= u.userRelatedOpposite create:true update:true delete:true; + + link MappedRelated derivedLazyContainment <= u.containment; + table MappedRelatedRow[] derivedLazyContainmentCollection <= u.containmentCollection; + + link MappedRelated derivedEagerContainment <= u.containment eager:true; + table MappedRelatedRow[] derivedEagerContainmentCollection <= u.containmentCollection eager:true; + + link MappedRelated derivedLazyAssociation <= u.association; + table MappedRelatedRow[] derivedLazyAssociationCollection <= u.associationCollection; + + link MappedRelated derivedEagerAssociation <= u.association eager:true; + table MappedRelatedRow[] derivedEagerAssociationCollection <= u.associationCollection eager:true; + + link MappedRelated derivedLazyStatic <= EntityRelated.any(); + table MappedRelatedRow[] derivedLazyCollectionStatic <= EntityRelated.all(); + + link MappedRelated derivedEagerStatic <= EntityRelated.any() eager:true; + table MappedRelatedRow[] derivedEagerCollectionStatic <= EntityRelated.all() eager:true; + + link MappedRelated mappedLazyAssociationDerived <= u.derivedContainment; + table MappedRelatedRow[] mappedLazyAssociationCollectionDerived <= u.derivedContainmentCollection; + + link MappedRelated lazyAssociationWithChoicesAndDefault <= u.association choices:EntityRelated.all() default:EntityRelated.any() create:true; + table MappedRelatedRow[] lazyAssociationCollectionWithChoicesAndDefault <= u.associationCollection choices:EntityRelated.all() default:EntityRelated.all() create:true; + link MappedRelated lazyAssociationOppositeWithChoicesAndDefault <= u.userRelatedOpposite choices:EntityRelated.all(); + table MappedRelatedRow[] lazyAssociationOppositeCollectionWithChoicesAndDefault <= u.userRelatedOppositeCollection choices:EntityRelated.all(); + + link MappedRelated lazyTransientWithDefault default:EntityRelated.any(); + table MappedRelatedRow[] lazyTransientCollectionWithDefault default:EntityRelated.all(); + } + + view UnmappedRelated { + field String transient; + } + + row UnmappedRelatedRow { + field String transient; } - transfer MappedRelated maps EntityRelated as e { - field String mappedAttribute <= e.hello bind; + view MappedRelated(EntityRelated e) { + field String mappedAttribute <= e.hello; + event create onCreate; + event update onUpdate; + event delete onDelete; + } + + row MappedRelatedRow(EntityRelated e) { + field String mappedAttribute <= e.hello; event create onCreate; } - actor Actor human realm:"COMPANY" claim:"email" identity:UserTransfer::email; + actor Actor human realm:"COMPANY" claim:"email" identity:UserTransfer::email { + link UserView users label:"Users"; + } """)); transform(); @@ -369,6 +512,171 @@ void testRelations() throws Exception { assertEquals(1, apps.size()); Application app1 = apps.get(0); + + assertEquals(7, app1.getClassTypes().size()); + assertEquals(26, app1.getRelationTypes().size()); + + RelationType users = (RelationType) app1.getRelationTypes().stream().filter(r -> ((RelationType) r).getName().equals("users")).findFirst().orElseThrow(); + + ClassType userTransfer = (ClassType) app1.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("RelationsTestModel::UserTransfer::ClassType")).findFirst().orElseThrow(); + ClassType userView = (ClassType) app1.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("RelationsTestModel::UserView::ClassType")).findFirst().orElseThrow(); + ClassType mappedRelated = (ClassType) app1.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("RelationsTestModel::MappedRelated::ClassType")).findFirst().orElseThrow(); + ClassType mappedRelatedRow = (ClassType) app1.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("RelationsTestModel::MappedRelatedRow::ClassType")).findFirst().orElseThrow(); + ClassType unmappedRelated = (ClassType) app1.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("RelationsTestModel::UnmappedRelated::ClassType")).findFirst().orElseThrow(); + ClassType unmappedRelatedRow = (ClassType) app1.getClassTypes().stream().filter(c -> ((ClassType) c).getName().equals("RelationsTestModel::UnmappedRelatedRow::ClassType")).findFirst().orElseThrow(); + + assertEquals(userView, users.getTarget()); + + List userViewRelations = userView.getRelations(); + + assertEquals(25, userViewRelations.size()); + + // According to JSLUtils, transients are always aggregation regardless of what we model. + RelationType unmappedLazy = userViewRelations.stream().filter(r -> r.getName().equals("unmappedLazy")).findFirst().orElseThrow(); + assertRelationType(unmappedLazy, unmappedRelated, RelationKind.AGGREGATION, MemberType.TRANSIENT, false, true, false, false, Set.of()); + + RelationType unmappedLazyRequired = userViewRelations.stream().filter(r -> r.getName().equals("unmappedLazyRequired")).findFirst().orElseThrow(); + assertRelationType(unmappedLazyRequired, unmappedRelated, RelationKind.AGGREGATION, MemberType.TRANSIENT, false, false, false, false, Set.of()); + + RelationType unmappedLazyCollection = userViewRelations.stream().filter(r -> r.getName().equals("unmappedLazyCollection")).findFirst().orElseThrow(); + assertRelationType(unmappedLazyCollection, unmappedRelatedRow, RelationKind.AGGREGATION, MemberType.TRANSIENT, true, true, false, false, Set.of()); + + RelationType lazyAssociation = userViewRelations.stream().filter(r -> r.getName().equals("lazyAssociation")).findFirst().orElseThrow(); + assertRelationType(lazyAssociation, mappedRelated, RelationKind.ASSOCIATION, MemberType.STORED, false, true, true, true, Set.of( + RelationBehaviourType.VALIDATE_CREATE, + RelationBehaviourType.CREATE, + RelationBehaviourType.VALIDATE_UPDATE, + RelationBehaviourType.UPDATE, + RelationBehaviourType.DELETE, + RelationBehaviourType.REFRESH, + RelationBehaviourType.LIST + )); + + RelationType lazyAssociationOpposite = userViewRelations.stream().filter(r -> r.getName().equals("lazyAssociationOpposite")).findFirst().orElseThrow(); + assertRelationType(lazyAssociationOpposite, mappedRelated, RelationKind.ASSOCIATION, MemberType.STORED, false, true, true, true, Set.of( + RelationBehaviourType.VALIDATE_CREATE, + RelationBehaviourType.CREATE, + RelationBehaviourType.VALIDATE_UPDATE, + RelationBehaviourType.UPDATE, + RelationBehaviourType.DELETE, + RelationBehaviourType.REFRESH, + RelationBehaviourType.LIST + )); + + RelationType derivedLazyContainment = userViewRelations.stream().filter(r -> r.getName().equals("derivedLazyContainment")).findFirst().orElseThrow(); + assertRelationType(derivedLazyContainment, mappedRelated, RelationKind.ASSOCIATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedLazyContainmentCollection = userViewRelations.stream().filter(r -> r.getName().equals("derivedLazyContainmentCollection")).findFirst().orElseThrow(); + assertRelationType(derivedLazyContainmentCollection, mappedRelatedRow, RelationKind.ASSOCIATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedEagerContainment = userViewRelations.stream().filter(r -> r.getName().equals("derivedEagerContainment")).findFirst().orElseThrow(); + assertRelationType(derivedEagerContainment, mappedRelated, RelationKind.AGGREGATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedEagerContainmentCollection = userViewRelations.stream().filter(r -> r.getName().equals("derivedEagerContainmentCollection")).findFirst().orElseThrow(); + assertRelationType(derivedEagerContainmentCollection, mappedRelatedRow, RelationKind.AGGREGATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedLazyAssociation = userViewRelations.stream().filter(r -> r.getName().equals("derivedLazyAssociation")).findFirst().orElseThrow(); + assertRelationType(derivedLazyAssociation, mappedRelated, RelationKind.ASSOCIATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedLazyAssociationCollection = userViewRelations.stream().filter(r -> r.getName().equals("derivedLazyAssociationCollection")).findFirst().orElseThrow(); + assertRelationType(derivedLazyAssociationCollection, mappedRelatedRow, RelationKind.ASSOCIATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedEagerAssociation = userViewRelations.stream().filter(r -> r.getName().equals("derivedEagerAssociation")).findFirst().orElseThrow(); + assertRelationType(derivedEagerAssociation, mappedRelated, RelationKind.AGGREGATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedEagerAssociationCollection = userViewRelations.stream().filter(r -> r.getName().equals("derivedEagerAssociationCollection")).findFirst().orElseThrow(); + assertRelationType(derivedEagerAssociationCollection, mappedRelatedRow, RelationKind.AGGREGATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedLazyStatic = userViewRelations.stream().filter(r -> r.getName().equals("derivedLazyStatic")).findFirst().orElseThrow(); + assertRelationType(derivedLazyStatic, mappedRelated, RelationKind.ASSOCIATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedLazyCollectionStatic = userViewRelations.stream().filter(r -> r.getName().equals("derivedLazyCollectionStatic")).findFirst().orElseThrow(); + assertRelationType(derivedLazyCollectionStatic, mappedRelatedRow, RelationKind.ASSOCIATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedEagerStatic = userViewRelations.stream().filter(r -> r.getName().equals("derivedEagerStatic")).findFirst().orElseThrow(); + assertRelationType(derivedEagerStatic, mappedRelated, RelationKind.AGGREGATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType derivedEagerCollectionStatic = userViewRelations.stream().filter(r -> r.getName().equals("derivedEagerCollectionStatic")).findFirst().orElseThrow(); + assertRelationType(derivedEagerCollectionStatic, mappedRelatedRow, RelationKind.AGGREGATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType mappedLazyAssociationDerived = userViewRelations.stream().filter(r -> r.getName().equals("mappedLazyAssociationDerived")).findFirst().orElseThrow(); + assertRelationType(mappedLazyAssociationDerived, mappedRelated, RelationKind.ASSOCIATION, MemberType.DERIVED, false, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType mappedLazyAssociationCollectionDerived = userViewRelations.stream().filter(r -> r.getName().equals("mappedLazyAssociationCollectionDerived")).findFirst().orElseThrow(); + assertRelationType(mappedLazyAssociationCollectionDerived, mappedRelatedRow, RelationKind.ASSOCIATION, MemberType.DERIVED, true, true, true, true, Set.of( + RelationBehaviourType.LIST + )); + + RelationType lazyAssociationWithChoicesAndDefault = userViewRelations.stream().filter(r -> r.getName().equals("lazyAssociationWithChoicesAndDefault")).findFirst().orElseThrow(); + assertRelationType(lazyAssociationWithChoicesAndDefault, mappedRelated, RelationKind.ASSOCIATION, MemberType.STORED, false, true, true, true, Set.of( + RelationBehaviourType.LIST, + RelationBehaviourType.REFRESH, + RelationBehaviourType.RANGE, + RelationBehaviourType.TEMPLATE, + RelationBehaviourType.CREATE, + RelationBehaviourType.VALIDATE_CREATE + )); + + RelationType lazyAssociationCollectionWithChoicesAndDefault = userViewRelations.stream().filter(r -> r.getName().equals("lazyAssociationCollectionWithChoicesAndDefault")).findFirst().orElseThrow(); + assertRelationType(lazyAssociationCollectionWithChoicesAndDefault, mappedRelatedRow, RelationKind.ASSOCIATION, MemberType.STORED, true, true, true, true, Set.of( + RelationBehaviourType.LIST, + RelationBehaviourType.REFRESH, + RelationBehaviourType.RANGE, + RelationBehaviourType.TEMPLATE, + RelationBehaviourType.CREATE, + RelationBehaviourType.VALIDATE_CREATE + )); + + RelationType lazyAssociationOppositeWithChoicesAndDefault = userViewRelations.stream().filter(r -> r.getName().equals("lazyAssociationOppositeWithChoicesAndDefault")).findFirst().orElseThrow(); + assertRelationType(lazyAssociationOppositeWithChoicesAndDefault, mappedRelated, RelationKind.ASSOCIATION, MemberType.STORED, false, true, true, true, Set.of( + RelationBehaviourType.LIST, + RelationBehaviourType.REFRESH, + RelationBehaviourType.RANGE + )); + + RelationType lazyAssociationOppositeCollectionWithChoicesAndDefault = userViewRelations.stream().filter(r -> r.getName().equals("lazyAssociationOppositeCollectionWithChoicesAndDefault")).findFirst().orElseThrow(); + assertRelationType(lazyAssociationOppositeCollectionWithChoicesAndDefault, mappedRelatedRow, RelationKind.ASSOCIATION, MemberType.STORED, true, true, true, true, Set.of( + RelationBehaviourType.LIST, + RelationBehaviourType.REFRESH, + RelationBehaviourType.RANGE + )); + + // According to JSLUtils, transients are always aggregation regardless of what we model. + RelationType lazyTransientWithDefault = userViewRelations.stream().filter(r -> r.getName().equals("lazyTransientWithDefault")).findFirst().orElseThrow(); + assertRelationType(lazyTransientWithDefault, mappedRelated, RelationKind.AGGREGATION, MemberType.TRANSIENT, false, true, false, false, Set.of( + RelationBehaviourType.TEMPLATE + )); + + RelationType lazyTransientCollectionWithDefault = userViewRelations.stream().filter(r -> r.getName().equals("lazyTransientCollectionWithDefault")).findFirst().orElseThrow(); + assertRelationType(lazyTransientCollectionWithDefault, mappedRelatedRow, RelationKind.AGGREGATION, MemberType.TRANSIENT, true, true, false, false, Set.of( + RelationBehaviourType.TEMPLATE + )); } static class AttributeAssertion { @@ -388,4 +696,15 @@ public void assertAttributeType(AttributeType attributeType, String name, String assertEquals(isReadonly,attributeType.isIsReadOnly()); } } + + static void assertRelationType(RelationType relationType, ClassType target, RelationKind relationKind, MemberType memberType, boolean isCollection, boolean isOptional, boolean isOrderable, boolean isFilterable, Set behaviourTypes) { + assertEquals(isCollection, relationType.isIsCollection()); + assertEquals(isOptional, relationType.isIsOptional()); + assertEquals(target, relationType.getTarget()); + assertEquals(memberType, relationType.getMemberType()); + assertEquals(relationKind, relationType.getRelationKind()); + assertEquals(behaviourTypes, new HashSet<>(relationType.getBehaviours())); + assertEquals(isOrderable, relationType.isIsOrderable()); + assertEquals(isFilterable, relationType.isIsFilterable()); + } }