Skip to content

Commit

Permalink
Story/3511 setting meta in nested objects (#914)
Browse files Browse the repository at this point in the history
* implement setting address and location

* add test for setting location on object

* implement nested meta setting

* neaten expression logic

* refactor neaten logic

* remove old todo comments

* update todo

* inline scoping logic

* make methods private

* rename method
  • Loading branch information
davidalk authored Jan 31, 2025
1 parent cf00332 commit 98d63bd
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 37 deletions.
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
)

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

0 comments on commit 98d63bd

Please sign in to comment.