Skip to content

Commit

Permalink
JNG-4080 support type conformance (#79)
Browse files Browse the repository at this point in the history
* JNG-4030 semicolons added to end of lines

* JNG-4082 Connect JSL (#73)

* JNG-4082 Version update

* JNG-4082 Fix literal function transpilation and add timestamp plus transpile

* JNG-4082 Version update

* JNG-4082 Trigger PR build for feature merge

* JNG-4082 Check parameter number on timestamp plus

* JNG-4082 Sout removed

* JNG=4082 Sout removed again

* JNG-4082 Version update

* JNG-4082 Revert build.yml

* JNG-4080 Support type conformance

* Fixing import

* Fixing errors

* Test cases added

* Fixing handling size

* Add missing files

* Update JSL version

* Update version

Co-authored-by: gprivi <[email protected]>
Co-authored-by: Bence Gelei <[email protected]>
Co-authored-by: bencegelei <[email protected]>
Co-authored-by: Robert Csakany <[email protected]>
  • Loading branch information
5 people authored Oct 10, 2022
1 parent a60e35b commit 265100b
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,36 @@
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
* #L%
*/

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import hu.blackbelt.judo.meta.jsl.jsldsl.EntityQueryTargetType;
import hu.blackbelt.judo.meta.jsl.jsldsl.Expression;
import hu.blackbelt.judo.meta.jsl.jsldsl.Feature;
import hu.blackbelt.judo.meta.jsl.jsldsl.FunctionCall;
import hu.blackbelt.judo.meta.jsl.jsldsl.FunctionedExpression;
import hu.blackbelt.judo.meta.jsl.jsldsl.LambdaFunction;
import hu.blackbelt.judo.meta.jsl.jsldsl.LiteralFunction;
import hu.blackbelt.judo.meta.jsl.jsldsl.LiteralFunctionParameter;
import hu.blackbelt.judo.meta.jsl.jsldsl.NavigationExpression;
import hu.blackbelt.judo.meta.jsl.jsldsl.SelfExpression;
import hu.blackbelt.judo.meta.jsl.jsldsl.SingleType;

import hu.blackbelt.judo.meta.jsl.runtime.TypeInfo;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.epsilon.ecl.parse.Ecl_EolParserRules.returnStatement_return;

import java.util.*;
import java.util.function.Function;
Expand All @@ -33,9 +47,9 @@
public class Jsl2JqlFunction {

private static class ParameterValue {
private String name;
private String defaultValue;
private Boolean mandatory = true;
private String name;
private String defaultValue;
private Boolean mandatory = true;

ParameterValue(String name, String defaultValue, Boolean mandatory) {
this.name = name;
Expand Down Expand Up @@ -105,78 +119,91 @@ public String toString() {
/**
* Keys are function names. Each "function" can have multiple possible parameter lists.
*/
private static Map<String, Collection<Collection<ParameterValue>>> literalFunctionParameters =
ImmutableMap.<String, Collection<Collection<ParameterValue>>>builder()
.put("getVariable", ImmutableList.of( ImmutableList.of(
ParameterValue.builder().name("category").build(),
ParameterValue.builder().name("key").build())))
.put("first", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("count").build())))
.put("last", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("count").build())))
.put("substring", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("count").build(),
ParameterValue.builder().name("offset").build())))
.put("matches", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("pattern").build())))
.put("position", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("substring").build())))
.put("like", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("pattern").build())))
.put("replace", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("oldstring").build(),
ParameterValue.builder().name("newstring").build())))
.put("fromMilliseconds", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("milliseconds").build())))
.put("of", ImmutableList.of(
ImmutableList.of(
ParameterValue.builder().name("year").build(),
ParameterValue.builder().name("month").build(),
ParameterValue.builder().name("day").build()),
ImmutableList.of(
ParameterValue.builder().name("hour").build(),
ParameterValue.builder().name("minute").build(),
ParameterValue.builder().name("second").build()),
ImmutableList.of(
ParameterValue.builder().name("date").build(),
ParameterValue.builder().name("time").mandatory(false).build())))
.put("plus", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("years").mandatory(false).build(),
ParameterValue.builder().name("months").mandatory(false).build(),
ParameterValue.builder().name("days").mandatory(false).build(),
ParameterValue.builder().name("hours").mandatory(false).build(),
ParameterValue.builder().name("minutes").mandatory(false).build(),
ParameterValue.builder().name("seconds").mandatory(false).build(),
ParameterValue.builder().name("milliseconds").mandatory(false).build())))
.put("typeOf", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("kindOf", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("asCollection", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("container", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("asType", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("memberOf", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("instances").build())))
.put("contains", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("instance").build())))
.build();
private static Map<String, Collection<Collection<ParameterValue>>> literalFunctionParameters =
ImmutableMap.<String, Collection<Collection<ParameterValue>>>builder()
.put("getVariable", ImmutableList.of( ImmutableList.of(
ParameterValue.builder().name("category").build(),
ParameterValue.builder().name("key").build())))
.put("first", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("count").build())))
.put("last", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("count").build())))
.put("substring", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("count").build(),
ParameterValue.builder().name("offset").build())))
.put("matches", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("pattern").build())))
.put("position", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("substring").build())))
.put("like", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("pattern").build())))
.put("replace", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("oldstring").build(),
ParameterValue.builder().name("newstring").build())))
.put("fromMilliseconds", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("milliseconds").build())))
.put("of", ImmutableList.of(
ImmutableList.of(
ParameterValue.builder().name("year").build(),
ParameterValue.builder().name("month").build(),
ParameterValue.builder().name("day").build()),
ImmutableList.of(
ParameterValue.builder().name("hour").build(),
ParameterValue.builder().name("minute").build(),
ParameterValue.builder().name("second").build()),
ImmutableList.of(
ParameterValue.builder().name("date").build(),
ParameterValue.builder().name("time").mandatory(false).build())))
.put("plus", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("years").mandatory(false).build(),
ParameterValue.builder().name("months").mandatory(false).build(),
ParameterValue.builder().name("days").mandatory(false).build(),
ParameterValue.builder().name("hours").mandatory(false).build(),
ParameterValue.builder().name("minutes").mandatory(false).build(),
ParameterValue.builder().name("seconds").mandatory(false).build(),
ParameterValue.builder().name("milliseconds").mandatory(false).build())))
.put("typeOf", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("kindOf", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("asCollection", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("container", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("asType", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("entityType").build())))
.put("memberOf", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("instances").build())))
.put("contains", ImmutableList.of(ImmutableList.of(
ParameterValue.builder().name("instance").build())))
.build();

private static String getEffectiveFunctionName(String functionName) {
if (functionName.equalsIgnoreCase("lower")) {
return "lowerCase";
} else if (functionName.equalsIgnoreCase("upper")) {
return "upperCase";
} else if (functionName.equalsIgnoreCase("size")) {
return "count";
} else {
return functionName;
}
}
private static String getEffectiveFunctionName(String functionName, LiteralFunction literalFunction) {
if (functionName.equalsIgnoreCase("lower")) {
return "lowerCase";
} else if (functionName.equalsIgnoreCase("upper")) {
return "upperCase";
} else if (functionName.equalsIgnoreCase("size")) {
FunctionCall functionCall = (FunctionCall) literalFunction.eContainer();
TypeInfo baseType = TypeInfo.getParentFunctionCallReturnType(functionCall);
if (baseType.isPrimitive()) {
if (baseType.getPrimitive() == TypeInfo.PrimitiveType.STRING) {
return "length";
}
} else if (baseType.isCollection()) {
return "count";
}
return "count";
} else {
return functionName;
}
}

public static String getFunctionAsJql(LiteralFunction it, Function<Expression, String> expressionExtractor) {

/**
* Keys are function names. Each "function" can have multiple possible parameter lists.
*/
public static String getFunctionAsJql(LiteralFunction it, Function<Expression, String> expressionExtractor) {
String functionName = it.getFunctionDeclarationReference().getName();

if ("plus".equals(functionName)) {
Expand All @@ -188,19 +215,22 @@ public static String getFunctionAsJql(LiteralFunction it, Function<Expression, S
}

private static String getFunctionAsJql(LiteralFunction it, Function<Expression, String> expressionExtractor, String functionName) {
// System.out.println(getStack(it));
// System.out.println(TypeInfo.getFunctionCallReferences());

if (literalFunctionParameters.containsKey(functionName)) {
List<String> givenParameterNames = it.getParameters().stream().map(p -> p.getDeclaration().getName()).collect(Collectors.toList());
if (givenParameterNames.size() < 1 || givenParameterNames.size() > 7) {
throw new IllegalArgumentException(String.format("Invalid number of parameters for '%s'. Got: %s, Expected: min 1, max 7",
functionName, givenParameterNames.size()));
functionName, givenParameterNames.size()));
}
List<Collection<ParameterValue>> alignedParameterLists =
literalFunctionParameters.get(functionName).stream()
.filter(parameterValues -> parameterValues.stream().map(ParameterValue::getName).collect(Collectors.toList()).containsAll(givenParameterNames))
.collect(Collectors.toList());
.filter(parameterValues -> parameterValues.stream().map(ParameterValue::getName).collect(Collectors.toList()).containsAll(givenParameterNames))
.collect(Collectors.toList());
if (alignedParameterLists.size() > 1) {
throw new IllegalStateException(String.format("Cannot determine which definition of function '%s' to use with [%s] given parameters",
it.getFunctionDeclarationReference().getName(), String.join(", ", givenParameterNames)));
it.getFunctionDeclarationReference().getName(), String.join(", ", givenParameterNames)));
} else if (alignedParameterLists.size() == 1) {
Map<String, LiteralFunctionParameter> givenParameters = it.getParameters().stream().collect(Collectors.toMap(p -> p.getDeclaration().getName(), p -> p));
Collection<ParameterValue> definedParameters = alignedParameterLists.get(0);
Expand All @@ -217,11 +247,11 @@ private static String getFunctionAsJql(LiteralFunction it, Function<Expression,
jqlParameters.add(expressionExtractor.apply(givenParameters.get(definedParameter.getName()).getExpression()));
}
}
return getEffectiveFunctionName(functionName) + "(" + String.join(", ", jqlParameters) + ")";
return getEffectiveFunctionName(functionName, it) + "(" + String.join(", ", jqlParameters) + ")";
}
}

return getEffectiveFunctionName(functionName) + "()";
return getEffectiveFunctionName(functionName, it) + "()";
}

private static String getTimestampPlusFunctionAsJql(LiteralFunction literalFunction, Function<Expression, String> expressionExtractor, String functionName) {
Expand Down Expand Up @@ -253,5 +283,4 @@ private static String getJqlTimestampArithmeticFunctionNameOf(String parameterNa
default: throw new IllegalArgumentException("Unsupported timestamp arithmetic function (from parameter name): " + parameterName);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ void testDerivedExpressionModel() throws Exception {

jslModelWrapper = JslDslModelResourceSupport.jslDslModelResourceSupportBuilder().resourceSet(jslModel.getResourceSet()).build();

// TODO: JNG-4080 string size should be transformed to string length
// assertEquals("\"apple\"!length()", jqlDerived("SalesPerson", "strLength", "", ""));
assertEquals("\"apple\"!length()", jqlDerived("SalesPerson", "strLength", "", ""));

assertEquals("self.lead.salesPerson!filter(d | d.lead.closed == false)!filter(d | d.lead.closed == false)!substring(1, 1)!length()", jqlDerived("SalesPerson", "strLengthDerived3", "", ""));


assertEquals("self.leads!count()", jqlDerived("SalesPerson", "value", "", ""));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ entity SalesPerson {
derived Decimal decimalLiteral => 100.12;
derived Integer powerOfTen => 10 ^ 3;
derived Integer strLength => "apple"!size();
derived Integer strLengthChained => "apple"!substring(offset=1, count=1)!size();
derived Integer strLengthDerived => self.stringLiteral!substring(offset=1, count=1)!size();
derived Integer strLengthDerived2 => self.lead.salesPerson.stringLiteral!substring(offset=1, count=1)!size();
derived Integer strLengthDerived3 => self.lead.salesPerson!filter(d | d.lead.closed == false)!filter(d | d.lead.closed == false).stringLiteral!substring(offset=1, count=1)!size();
}

entity Customer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ model TestDerivesWithParameters;
type numeric Integer(precision = 9, scale = 0);
type string String(min-size = 0, max-size = 128);


query Lead[] staticLeadsBetween(Integer minLeadsBetween = 1, Integer maxLeadsBetween = 50) => Lead!filter(lead | lead.value > minLeadsBetween and lead.value < maxLeadsBetween);
// Lead!filter(lead | lead.value > input.minLeadsBetween!isDefined() ? input.minLeadsBetween : 1 and lead.value < input.maxLeadsBetween!isDefined() ? input.maxLeadsBetween : 50)

Expand All @@ -20,7 +19,6 @@ query Lead[] staticLeadsBetweenAndSalesPersonLeads(Integer minLeadsBetween = 1,
Lead!filter(lead | lead.value > minLeadsBetween and lead.value < maxLeadsBetween).salesPerson.leadsBetween(minLeadsBetween = minLeadsBetween, maxLeadsBetween = maxLeadsBetween);
// Lead!filter(lead | lead.value > input.minLeadsBetween!isDefined() ? input.minLeadsBetween : 1 and lead.value < input.maxLeadsBetween!isDefined() ? input.maxLeadsBetween : 50)


entity SalesPerson {
relation Lead[] leads opposite salesPerson;

Expand Down Expand Up @@ -52,7 +50,6 @@ entity SalesPerson {
query Integer leadsOverWithMinCount(Integer minLeadsOverMin = 5) => self.leadsBetweenCount(minLeadsBetween = minLeadsOverMin, maxLeadsBetween = 100);
// self.leads!filter(lead | lead.value > input.minLeadsOverMin!isDefined() ? input.minLeadsOverMin : 5 and lead.value < 100)!size()


derived Integer leadsOver10Count => self.leadsOverWithMinCount(minLeadsOverMin = 10);
// self.leads!filter(lead | lead.value > 10 and lead.value < 100)!size()

Expand Down
16 changes: 8 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@
<epsilon-runtime-version>1.5.1.20221005_230707_b5e4278d_develop</epsilon-runtime-version>

<!-- Model versions -->
<judo-meta-jsl-version>1.0.1.20221007_091934_42b13532_develop</judo-meta-jsl-version>

<judo-meta-rdbms-version>1.0.1.20221006_004515_f1d4e624_develop</judo-meta-rdbms-version>
<judo-meta-jql-version>1.0.2.20221006_004537_4e35baab_develop</judo-meta-jql-version>
<judo-meta-psm-version>1.2.2.20221006_004445_31fba004_develop</judo-meta-psm-version>
<judo-meta-asm-version>1.1.2.20221006_004501_e2ea11fc_develop</judo-meta-asm-version>
<judo-meta-expression-version>1.0.2.20221006_004907_eade56d0_develop</judo-meta-expression-version>
<judo-meta-liquibase-version>1.0.1.20221006_004546_a7e3fe1c_develop</judo-meta-liquibase-version>
<judo-meta-jsl-version>1.0.1.20221010_160921_0f697d26_feature_JNG_4080_SupportTypeConformance</judo-meta-jsl-version>

<judo-meta-rdbms-version>1.0.1.20221006_173508_36b41f9d_develop</judo-meta-rdbms-version>
<judo-meta-jql-version>1.0.2.20221006_173421_98f7c2f3_develop</judo-meta-jql-version>
<judo-meta-psm-version>1.2.2.20221006_173533_751cb8b0_develop</judo-meta-psm-version>
<judo-meta-asm-version>1.1.2.20221006_173554_3d80808b_develop</judo-meta-asm-version>
<judo-meta-expression-version>1.0.2.20221006_173741_d75341cf_develop</judo-meta-expression-version>
<judo-meta-liquibase-version>1.0.1.20221006_170739_642ebbda_develop</judo-meta-liquibase-version>
<judo-dao-api-version>1.0.3.20220930_100653_2b31acaa_develop</judo-dao-api-version>
<judo-sdk-common-version>1.0.2.20221006_004728_7cb86e0b_develop</judo-sdk-common-version>
<judo-dispatcher-api-version>1.0.3.20220926_012329_fb44a05f_develop</judo-dispatcher-api-version>
Expand Down

0 comments on commit 265100b

Please sign in to comment.