Skip to content

fix(salesforce): translate metric expressions and validate field references - #404

Draft
saurabhdeshp wants to merge 6 commits into
apache:mainfrom
saurabhdeshp:feature/mds-platforms/salesforce-metric-expressions
Draft

saurabhdeshp wants to merge 6 commits into
apache:mainfrom
saurabhdeshp:feature/mds-platforms/salesforce-metric-expressions

Conversation

@saurabhdeshp

@saurabhdeshp saurabhdeshp commented Sep 15, 2026

Copy link
Copy Markdown

Implements the initial metric-expression scope of #403 on top of #402. Supported OSI SNOWFLAKE and ANSI_SQL formulas compile to Tableau Next Tua; invalid types, aggregation or references fail with the metric name. Preferred TABLEAU formulas are validated too.

Supports aggregates, arithmetic, searched CASE, Boolean comparisons, null handling and ABS/ROUND/CEIL/FLOOR. For example, SUM(orders.profit) / NULLIF(SUM(orders.revenue), 0) becomes a bracketed Tua ratio with an IF null guard.

The PR is limited to metric conversion: 16 changed files, 1,220 production additions. Deployment bindings, derived-field compilation, metric dependencies, date/string functions, extension changes and whole-model validation are deferred. The existing field/relationship mapping pipeline stays in place.

Review the implementation in this order:

  1. MetricMappingHandler calls the compiler with one resolver per model.
  2. SqlMetricExpressionParser uses JSqlParser 5.3; TuaMetricExpressionParser handles the bounded native syntax. Both return the small MetricExpression AST.
  3. MetricExpressionTranslator checks types/aggregation before emitting Tua.
  4. MetricFieldResolver verifies declared and exported identities, physical bindings, and the enabled relationship paths needed by metrics. It rejects derived expressions misclassified as physical columns and changed join-key pairs; it does not rewrite the relationship mapper or prove join grain.

JSqlParser is used under its Apache-2.0 option, with its unused JMH dependency excluded. No Python runtime is required.

Validation: JDK 21 mvn -DrequireSalesforceSchema=true clean verify passed 280 tests with zero failures/errors/skips; Apache RAT and packaged-JAR export smoke checks passed. Tests include repeated unary operators, redundant grouping, malformed modifier/tuple rejection, ordered ELSEIF evaluation, signed-zero handling, composed formulas, nulls/empty inputs/duplicates/zero denominators, quoting, parser bounds, types, relationship correspondence, and CLI failures without partial output.

Draft: native Tableau Next validation remains pending. Local evaluation and schema tests do not prove authoring API acceptance or native results. #403 stays open for native validation and later milestones.

Refs #399 and #403. Merge #402 first; its commit and authorship are preserved. Extension-preservation work belongs there. The CLI error-output line overlaps #286.

Ashfaqbs and others added 3 commits September 15, 2026 22:15
MetricMappingHandler.mapOssieToSalesforce() was a stub that discarded
every metric mapping and returned without writing anything, so an
Ossie model's metrics never appeared in the exported Salesforce
semanticCalculatedMeasurements.

Wire up the existing generic name/description mapping (mappings.yaml
already declared metrics.name/metrics.description, unused until now),
and add unwrapExpressions() to flatten each metric's expression into a
Salesforce-compatible string. TABLEAU is preferred when present since
that is what Salesforce/Tableau CRM speaks; a model authored without
one falls back to its ANSI_SQL expression unresolved/untranslated,
since actually resolving/rewriting into TABLEAU syntax depends on
apache#222's still-open expression-language work, not this fix. A metric
with neither dialect fails the conversion with an actionable error
naming the metric, rather than being silently dropped.

Fixes apache#399
Use JSqlParser with a shared typed expression pipeline for derived fields
and dependent metrics. Preserve semantic identities through environment
bindings, validate relationships and final model references, and reject
unsupported expressions or ambiguous metadata before export.

Validation: 442 tests passed with no skips, Apache RAT passed, and packaged
CLI export, import, and physical-binding smoke checks passed.
Defer physical bindings, derived fields, metric dependencies, extension
changes and whole-model validation. Keep JSqlParser-backed metric parsing,
typed Tua generation and targeted field/relationship reference checks.

Consolidate the compiler around metric-specific components and retain
focused semantic and integration regressions.

Validation: 254 tests passed with no skips, Apache RAT passed, and the
packaged CLI export smoke check passed.
… tests

Normalize bounded unary chains and redundant grouping before JSqlParser,
while preserving operand validation, quotes, function arguments and limits.
Reject malformed null predicates and tuple arguments explicitly.

Fix ELSEIF evaluation and signed-zero equality, distinct counting and
zero-divisor checks in the independent semantic test helper. Add focused
compatibility, semantic and rejection regressions.

Validation: 280 tests passed with no skips; Apache RAT passed. Packaged CLI
checks cover successful conversion and failure without partial output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants