Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Story/3511 setting meta in nested objects #914

Merged
merged 13 commits into from
Jan 31, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ result Foo (1..1)

var code = generatorTestHelper.generateCode(model);

generatorTestHelper.writeClasses(code, "canSetMetaAddressOnFunctionObjectOutput");

var classes = generatorTestHelper.compileToClasses(code);

var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");
Expand Down Expand Up @@ -188,7 +186,7 @@ result string (1..1)
}


@Disabled //TODO: implement nested setting of meta and then complete this
@Disabled //TODO: is this syntax needed? if so we need to find a way to get key as a feature from a Data type
@Test
void canSetExternalKeyOnFunctionObjectOutput() {
var model = """
Expand All @@ -211,7 +209,7 @@ result Foo (1..1)

var code = generatorTestHelper.generateCode(model);
}

@Test
void canSetExternalReferenceOnFunctionObjectOutput() {
var model = """
Expand All @@ -231,7 +229,7 @@ result Foo (1..1)
[metadata reference]
set result -> reference: myKey
""";

var code = generatorTestHelper.generateCode(model);

var classes = generatorTestHelper.compileToClasses(code);
Expand All @@ -246,10 +244,9 @@ result Foo (1..1)
assertEquals(expected, result);
}

@Disabled //TODO: implement setting nested meta
@Test
void canSetMetaOnFunctionObjectOutputAndNestedBasicMetaField() {
var model = """
var model = """
type Foo:
a string (1..1)
b string (1..1)
Expand All @@ -266,6 +263,7 @@ result Foo (1..1)
""";

var code = generatorTestHelper.generateCode(model);

var classes = generatorTestHelper.compileToClasses(code);
var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,13 @@ class FunctionGenerator {
for (var pathIndex=0; pathIndex < intermediarySegmentSize; pathIndex++) {

val seg = op.pathTail.get(pathIndex)
val prop = findPojoProperty(seg, expr.expressionType.itemType)

if (expr.expressionType.itemType instanceof RJavaWithMetaValue) {
val metaExpr = expr
expr = JavaExpression.from('''«metaExpr».getOrCreateValue()''', (expr.expressionType.itemType as RJavaWithMetaValue).valueType)
}

val prop = getPojoProperty(seg, expr.expressionType.itemType)
val oldExpr = expr
val itemType = prop.type.itemType
expr = JavaExpression.from(
Expand All @@ -468,43 +473,50 @@ class FunctionGenerator {
.«prop.getOrCreateName»(«IF prop.type.isList»0«ENDIF»)''',
itemType
)
if (itemType instanceof RJavaWithMetaValue) {
val metaExpr = expr
expr = JavaExpression.from('''«metaExpr».getOrCreateValue()''', itemType.valueType)
}
}

//end of path
val seg = op.pathTail.get(op.pathTail.length - 1)

val oldExpr = expr
val oldExpr = expr
val outputExpressionType = expr.expressionType.itemType
val prop = findPojoProperty(seg, outputExpressionType)
val pojoPropertyType = prop.type.itemType
val prop = getPojoProperty(seg, outputExpressionType)

if (outputExpressionType instanceof RJavaWithMetaValue) {
expr = JavaExpression.from(
'''
«oldExpr»
«generateMetaWrapperCreator(seg, prop, outputExpressionType)».«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«seg.toPojoPropertyNames.toFirstUpper»(«it»)''',
JavaPrimitiveType.VOID
)
} else {
expr = JavaExpression.from(
'''
«oldExpr»
.«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«prop.name.toFirstUpper»«IF pojoPropertyType instanceof RJavaWithMetaValue && !op.assignAsKey»Value«ENDIF»(«it»)''',
JavaPrimitiveType.VOID
)
}
val propertySetterName = getPropertySetterName(outputExpressionType, prop, seg)
val requiresValueSetter = requiresValueSetter(outputExpressionType, prop, seg, op)
expr = JavaExpression.from(
'''
«oldExpr»
«generateMetaWrapperCreator(seg, prop, outputExpressionType)».«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«propertySetterName»«IF requiresValueSetter»Value«ENDIF»(«it»)''',
JavaPrimitiveType.VOID
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup


expr
].completeAsExpressionStatement
}
}

private def StringConcatenationClient generateMetaWrapperCreator(RFeature seg, JavaPojoProperty prop, RJavaWithMetaValue outputExpressionType) {
switch (outputExpressionType) {
private def String getPropertySetterName(JavaType outputExpressionType, JavaPojoProperty prop, RFeature segment) {
if (outputExpressionType instanceof RJavaWithMetaValue) {
segment.toPojoPropertyNames.toFirstUpper
} else {
prop.name.toFirstUpper
}
}

private def boolean requiresValueSetter(JavaType outputExpressionType, JavaPojoProperty outerPojoProperty, RFeature segment, ROperation op) {
val outerPropertyType = outerPojoProperty.type.itemType
val innerProp = if (outputExpressionType instanceof RJavaWithMetaValue && outerPropertyType instanceof JavaPojoInterface) {
getPojoProperty(segment, outerPropertyType)
} else {
outerPojoProperty
}

val innerPropType = innerProp.type.itemType
innerPropType instanceof RJavaWithMetaValue && !op.assignAsKey
}

private def StringConcatenationClient generateMetaWrapperCreator(RFeature seg, JavaPojoProperty prop, JavaType expressionType) {
switch (expressionType) {
RJavaFieldWithMeta: '''«IF seg instanceof RMetaAttribute».getOrCreateMeta()«ELSE».«prop.getOrCreateName»()«ENDIF»'''
RJavaReferenceWithMeta case seg instanceof RMetaAttribute && seg.name == "address": '''.«prop.getOrCreateName»()'''
RJavaReferenceWithMeta case !(seg instanceof RMetaAttribute): '''.getOrCreateValue()'''
Expand All @@ -513,7 +525,7 @@ class FunctionGenerator {
}

//The type of the output expression to be set and the pojo property type are not the same when working with meta
private def JavaPojoProperty findPojoProperty(RFeature seg, JavaType outputExpressionType) {
private def JavaPojoProperty getPojoProperty(RFeature seg, JavaType outputExpressionType) {
if (seg instanceof RMetaAttribute && outputExpressionType.itemType instanceof RJavaFieldWithMeta) {
(outputExpressionType as JavaPojoInterface).findProperty("meta")
} else if (seg instanceof RMetaAttribute && outputExpressionType.itemType instanceof RJavaReferenceWithMeta) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,15 @@ class RosettaScopeProvider extends ImportedNamespaceAwareLocalScopeProvider {
// Case handles the head of the segment
Operation: {
val receiverType = typeProvider.getRTypeOfSymbol(context.assignRoot)
val features = receiverType.allFeatures(context, [t| !(t instanceof REnumType)])
return Scopes.scopeFor(features) //TODO: don't get all features (i.e enum atrs)
return Scopes.scopeFor(receiverType.allFeatures(context, [t| !(t instanceof REnumType)]))
}
// Case handles the tail of the segment
Segment: {
val prev = context.prev
if (prev !== null) {
if (prev.feature.isResolved) {
val receiverType = typeProvider.getRTypeOfFeature(prev.feature, context)
return Scopes.scopeFor(receiverType.allFeatures(context, [t| !(t instanceof REnumType)])) //TODO: don't get all features (i.e enum atrs)
return Scopes.scopeFor(receiverType.allFeatures(context, [t| !(t instanceof REnumType)]))
}
}
if (context.eContainer instanceof Operation) {
Expand Down