You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ossie.apache.org by jb...@apache.org on 2026/10/04 15:02:09 UTC
(ossie) branch main updated: fix(salesforce): restore metric custom_extensions, default label, respect restored dataType (#512)
This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ossie.git
The following commit(s) were added to refs/heads/main by this push:
new 9e87fa34 fix(salesforce): restore metric custom_extensions, default label, respect restored dataType (#512)
9e87fa34 is described below
commit 9e87fa34847cdeb17e929818e7655ffb8ed2e45a
Author: Ashfaq <10...@users.noreply.github.com>
AuthorDate: Sun Oct 4 20:32:04 2026 +0530
fix(salesforce): restore metric custom_extensions, default label, respect restored dataType (#512)
* fix(salesforce): restore metric custom_extensions on export
MetricMappingHandler.mapOssieToSalesforce() is the only one of the four
array-level handlers (datasets, relationships, semantic model, metrics)
that never called CustomExtensionHandler.restoreCustomExtensionsAtLevel()
for its own level, even though the METRICS case in that switch has
existed since the custom-extensions mechanism was added. A metric's
custom_extensions (e.g. a Salesforce-specific label) were silently
dropped on Ossie -> Salesforce export.
Wire the same restore call used by DatasetMappingHandler and
RelationshipMappingHandler, placed before the expression is compiled so
it only fills in properties the generic mapping didn't already produce.
Signed-off-by: Ashfaq <10...@users.noreply.github.com>
* fix(salesforce): default metric label, prefer restored dataType
Ossie metrics have no label field, so every exported
semanticCalculatedMeasurement had none unless custom_extensions
restored one. Default it to apiName, matching
DatasetMappingHandler/SemanticModelMappingHandler's existing pattern.
Also switch the Tua compiler's dataType assignment to putIfAbsent, so
an exact Salesforce dataType restored from custom_extensions (e.g.
Currency) is not clobbered by the derived type.
Signed-off-by: Ashfaq <10...@users.noreply.github.com>
---------
Signed-off-by: Ashfaq <10...@users.noreply.github.com>
---
.../ossie/converter/MetricMappingHandler.java | 21 +++++++-
.../ossie/OssieToSalesforceConverterTest.java | 60 ++++++++++++++++++++++
2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/converters/salesforce/src/main/java/org/apache/ossie/converter/MetricMappingHandler.java b/converters/salesforce/src/main/java/org/apache/ossie/converter/MetricMappingHandler.java
index 5278abaf..682a482c 100644
--- a/converters/salesforce/src/main/java/org/apache/ossie/converter/MetricMappingHandler.java
+++ b/converters/salesforce/src/main/java/org/apache/ossie/converter/MetricMappingHandler.java
@@ -93,15 +93,32 @@ public class MetricMappingHandler implements PipelineStep {
outputData.putAll(mappedData);
+ customExtensionHandler.restoreCustomExtensionsAtLevel(outputData, sourceData, Level.METRICS);
+
List<Object> sfMetrics = getList(outputData, SEMANTIC_CALCULATED_MEASUREMENTS);
if (sfMetrics != null) {
unwrapExpressions(ossieMetrics, sfMetrics, sourceData, outputData);
+ applyDefaults(sfMetrics);
} else if (!ossieMetrics.isEmpty()) {
throw new ConversionException("Metric '" + getString(asMap(ossieMetrics.get(0)), NAME)
+ "': metric mappings produced no calculated measurements");
}
}
+ /**
+ * Ossie metrics have no label field; Salesforce requires one. Default it to apiName,
+ * matching DatasetMappingHandler/SemanticModelMappingHandler, unless custom_extensions
+ * already restored an exact Salesforce label.
+ */
+ private void applyDefaults(List<Object> sfMetrics) {
+ for (Object sfMetricObj : sfMetrics) {
+ Map<String, Object> sfMetric = asMap(sfMetricObj);
+ if (!sfMetric.containsKey(LABEL) && sfMetric.containsKey(API_NAME)) {
+ sfMetric.put(LABEL, getString(sfMetric, API_NAME));
+ }
+ }
+ }
+
/**
* Maps Salesforce semanticCalculatedMeasurements to Ossie metrics.
*/
@@ -154,7 +171,9 @@ public class MetricMappingHandler implements PipelineStep {
MetricExpressionTranslator.Result translated =
MetricExpressionTranslator.translate(ossieMetric, resolver);
sfMetric.put(EXPRESSION, translated.expression());
- sfMetric.put(DATA_TYPE, translated.dataType());
+ // Exact Salesforce dataType restored from custom_extensions (e.g. "Currency")
+ // wins over the Tua compiler's derived type.
+ sfMetric.putIfAbsent(DATA_TYPE, translated.dataType());
sfMetric.put("syntax", "Tua");
sfMetric.put("aggregationType", "UserAgg");
}
diff --git a/converters/salesforce/src/test/java/org/apache/ossie/OssieToSalesforceConverterTest.java b/converters/salesforce/src/test/java/org/apache/ossie/OssieToSalesforceConverterTest.java
index 15c1c7d9..71db6657 100644
--- a/converters/salesforce/src/test/java/org/apache/ossie/OssieToSalesforceConverterTest.java
+++ b/converters/salesforce/src/test/java/org/apache/ossie/OssieToSalesforceConverterTest.java
@@ -315,6 +315,66 @@ class OssieToSalesforceConverterTest {
assertEquals("AVG([Orders].[amount])", avgOrderValue.get("expression"));
}
+ @Test
+ void testMetricCustomExtensionsRestoredBeforeExpressionCompilation() throws Exception {
+ // Normalize line endings first: the fixture file may check out with CRLF depending on
+ // the platform's autocrlf setting, but the substitution below is written with LF.
+ String yamlWithMetricExtension = ossieYaml.replace("\r\n", "\n").replace(
+ "metrics:\n"
+ + "- description: Sum of all order amounts\n"
+ + " name: total_revenue\n"
+ + " datatype: Decimal\n"
+ + " expression:\n"
+ + " dialects:\n"
+ + " - dialect: ANSI_SQL\n"
+ + " expression: SUM([Orders].[amount])\n",
+ "metrics:\n"
+ + "- description: Sum of all order amounts\n"
+ + " name: total_revenue\n"
+ + " datatype: Decimal\n"
+ + " expression:\n"
+ + " dialects:\n"
+ + " - dialect: ANSI_SQL\n"
+ + " expression: SUM([Orders].[amount])\n"
+ + " custom_extensions:\n"
+ + " - vendor_name: SALESFORCE\n"
+ + " data: |-\n"
+ + " {\n"
+ + " \"label\": \"Total Revenue (Custom Label)\",\n"
+ + " \"dataType\": \"Currency\"\n"
+ + " }\n");
+ assertTrue(yamlWithMetricExtension.contains("Total Revenue (Custom Label)"),
+ "fixture text substitution did not match");
+
+ List<String> results = converter.convert(yamlWithMetricExtension);
+ Map<String, Object> sfModel = jsonMapper.readValue(results.get(0), new TypeReference<Map<String, Object>>() {});
+ List<Map<String, Object>> calcMeasurements = (List<Map<String, Object>>) sfModel.get("semanticCalculatedMeasurements");
+
+ Map<String, Object> totalRevenue = calcMeasurements.stream()
+ .filter(m -> "total_revenue".equals(m.get("apiName")))
+ .findFirst()
+ .orElse(null);
+ assertNotNull(totalRevenue);
+ assertEquals("Total Revenue (Custom Label)", totalRevenue.get("label"),
+ "custom_extensions on a metric should be restored onto its exported semanticCalculatedMeasurement");
+ assertEquals("Currency", totalRevenue.get("dataType"),
+ "exact Salesforce dataType restored from custom_extensions should win over the Tua compiler's derived type");
+ // The compiled Tua expression is still produced normally; restoring custom_extensions
+ // must not interfere with fields the expression compiler itself computes.
+ assertEquals("SUM([Orders].[amount])", totalRevenue.get("expression"));
+ assertEquals("Tua", totalRevenue.get("syntax"));
+
+ Map<String, Object> avgOrderValue = calcMeasurements.stream()
+ .filter(m -> "avg_order_value".equals(m.get("apiName")))
+ .findFirst()
+ .orElse(null);
+ assertNotNull(avgOrderValue);
+ assertEquals("avg_order_value", avgOrderValue.get("label"),
+ "a metric with no custom_extensions label should default its label to apiName");
+ assertEquals("Number", avgOrderValue.get("dataType"),
+ "a metric with no custom_extensions dataType should keep the Tua compiler's derived type");
+ }
+
@Test
void testMetricExpressionPrefersTableauDialectOverAnsiSql() throws Exception {
// Normalize line endings first: the fixture file may check out with CRLF depending on