Repository navigation
test(validation): pin the precedence the NOT rank describes - #630
Merged
Merged
Conversation
Three expressions parsed through the validator's own OSSIE_SQL_2026 dialect entry: `NOT a = b` builds Not(EQ(a, b)), `- a = b` builds EQ(Neg(a), b), and `NOT a AND b` builds And(Not(a), b). Together they fix NOT between comparison and AND, and show that the unary operators it had been listed beside bind ahead of comparison instead.
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
1 open issue
What changed in this PR
Adds validator tests to pin the operator precedence behavior of the OSSIE_SQL_2026 dialect, specifically for NOT, unary -, comparisons, and AND, as a follow-up to #614.
Changes:
- Add a small parsing helper for OSSIE_SQL_2026 expressions used in tests.
- Add three new precedence tests covering
NOT a = b,- a = b, andNOT a AND b.
| File | Description |
|---|---|
| validation/tests/test_validate.py | Adds new sqlglot-based tests to lock in operator precedence expectations for OSSIE_SQL_2026 parsing. |
Review effort: Lite
Comment on lines
+378
to
+382
| def _parse_ossie_sql(expression: str): | ||
| """Parse *expression* the way the validator parses an OSSIE_SQL_2026 body.""" | ||
| return _VALIDATE.sqlglot.parse_one( | ||
| expression, dialect=_VALIDATE.DIALECT_MAP["OSSIE_SQL_2026"] | ||
| ) |
Copilot stopped reviewing on behalf of
ayushtkn due to an error
October 22, 2026 20:13
christianeu-db
approved these changes
Oct 23, 2026
christianeu-db
added a commit
to christianeu-db/ossie
that referenced
this pull request
Oct 23, 2026
Bring in apache#630 (precedence tests pinning the NOT rank), which landed on main after the previous merge. apache#630 adds three OSSIE_SQL_2026 precedence tests whose helper parses through `DIALECT_MAP["OSSIE_SQL_2026"]`. This branch split that map into `SQLGLOT_DIALECTS` (parseable) and `NON_SQL_DIALECTS`, so the merged-in helper is pointed at `SQLGLOT_DIALECTS[PORTABLE_DIALECT]`, which is the same None (sqlglot default) entry; the three tests pass unchanged otherwise. Verified against validation-ci.yml: duplicate-key tests (59), validation pytest (271, incl. the three apache#630 tests), python model tests (266), generator --check in sync, and all five example validations pass. Co-authored-by: Isaac <no-reply@databricks.com>
christianeu-db
added a commit
to christianeu-db/ossie
that referenced
this pull request
Oct 23, 2026
apache#630 added OSSIE_SQL_2026 precedence tests whose helper parses through `DIALECT_MAP["OSSIE_SQL_2026"]`. This branch split that map into `SQLGLOT_DIALECTS` (parseable) and `NON_SQL_DIALECTS`, so the merged-in helper hit `AttributeError: module 'ossie_validate' has no attribute 'DIALECT_MAP'`. Point it at `SQLGLOT_DIALECTS[PORTABLE_DIALECT]`, the same None (sqlglot default) entry, so the three tests pass unchanged. Co-authored-by: Isaac <no-reply@databricks.com>
christianeu-db
added a commit
that referenced
this pull request
Oct 26, 2026
* feat(core-spec): decouple core spec from specific vendor dialects
Make the core specification vendor-neutral:
- `Dialect` becomes a free-form string (was a closed enum), mirroring the
already-free-form `Vendor`; generic schema `examples` replace concrete
product names.
- Move the known-dialect and known-vendor catalogs out of the normative spec
into a new top-level `extensions/` folder (README, dialects.md, vendors.md),
framed as a community registry whose listings do not imply endorsement.
- Add an optional top-level portable `expression` field (OSSIE_SQL_2026) to the
expression object; when both it and an OSSIE_SQL_2026 `dialects` entry are
present, the top-level field is authoritative. Demonstrated on
`customer_full_name` in examples/tpcds_semantic_model.yaml.
- Keep the normative text that non-OSSIE dialects are opaque and
declaration-only.
Kept in sync: the enum-sync generator no longer emits `dialects` (free-form,
like vendors); the Python SDK types `dialect` as a free-form string and gains
the optional portable `expression`; the reference validator treats unregistered
dialects as opaque (skipped) and validates the portable expression. Converters
are otherwise unchanged except where the now-string dialect required a fix (the
dbt dialect comparison uses `==`, and the sigma and hex converters no longer
call `.value` on a dialect) and where the new portable `expression` is handled:
the ontology converter carries it through its model and both conversion
directions, and omni's round-trip test documents the portable marker as a
normalization (its text survives as the dialect entry).
Co-authored-by: Isaac <no-reply@databricks.com>
* fix(core-spec): allow portable-only expressions without dialects
An Expression required `dialects` on both the JSON Schema and the SDK, so a
document carrying only the portable top-level `expression` (OSSIE_SQL_2026) was
rejected, contradicting the spec's stated semantics.
- Schema: replace `required: [dialects]` with an anyOf requiring at least one of
`expression` or `dialects`; `dialects` keeps `minItems: 1` when present.
- SDK: make `OssieExpression.dialects` optional and add a model_validator that
rejects an expression carrying neither form.
- Tests: cover portable-only, dialects-only, both-present, and the empty cases
on both the schema and the SDK.
- Docs: note the "at least one" rule in spec.md and spec.yaml.
Co-authored-by: Isaac <no-reply@databricks.com>
* feat(validation): warn on unknown dialects instead of skipping silently
An unrecognized dialect is opaque and legitimate under the free-form `Dialect`
model, so its SQL cannot be parse-checked. The validator skipped it silently,
which also hid typos such as `SNOWFLKE`.
`validate_sql` now tallies expressions whose dialect is not in `DIALECT_MAP` and
emits one nonfatal `ValidationWarning` per distinct unknown dialect, with the
count of affected expressions. Validation still passes. Known-but-unparseable
dialects (MDX, DAX, HOLISTICS_AQL, ...) stay silent, and the per-call
`validate_sql_expression` is unchanged.
Co-authored-by: Isaac <no-reply@databricks.com>
* refactor(core-spec): rename portable expression key to 'sql'
The portable top-level key of the Expression object was `expression`,
nested under a field/metric's own `expression:` block -- the doubled
`expression.expression` Jochen flagged on the thread. Rename it to
`sql` so the key reads cleanly and names what it holds: the portable
OSSIE_SQL (OSSIE_SQL_2026) form.
Scope is the portable key only. The field/metric `expression:` key
(which holds the Expression object) and the per-dialect
`dialects[].expression` key (already qualified by its `dialect:`) are
unchanged.
This key was introduced by this same unreleased PR, so the rename
carries no migration burden; no released spec ever had
`expression.expression`. No back-compat alias -- the old key is
rejected (schema additionalProperties:false, SDK extra=forbid).
Touches the schema anyOf + property, the SDK model and validator, the
validator's portable reads, spec.md/spec.yaml/docs prose and examples,
the tpcds portable example, and the mirrored tests.
Co-authored-by: Isaac <no-reply@databricks.com>
* fix(validation): check a dataset-scoped metric's portable sql
A dataset-scoped metric may be written with only the portable `sql`
form (no dialects). Such a metric escaped both checks: `validate_sql`
only walked its `dialects`, so the portable form was never parsed; and
`validate_metric_scoping` likewise only walked `dialects`, so the
single-namespace scoping rules (no qualified references, declared
fields only) were never applied to it.
Both now handle the portable `sql` exactly like a dialect expression:
it is parsed as OSSIE_SQL_2026 and scope-checked. A portable-only
dataset-scoped metric with a cross-dataset reference or an undeclared
field is now reported, as a dialect form already was.
Adds four tests covering the portable form: a declared single-part
field passes, a cross-dataset reference and an undeclared field are
rejected, and an invalid portable expression is reported.
Co-authored-by: Isaac <no-reply@databricks.com>
* refactor(validation): walk expressions through one iterator
`validate_sql` and `validate_metric_scoping` each walked the document
to find every expression. Introduce `iter_expressions`, the single
traversal both consume, yielding an `Expression` record per portable
`sql` form and per dialect expression, keyed by `kind`
(field / dataset_metric / model_metric).
Also folded in while here:
- Split the overloaded DIALECT_MAP into SQLGLOT_DIALECTS (parseable,
mapped to the sqlglot dialect) and NON_SQL_DIALECTS (carried but not
parsed); one guard in _parse_sql_expression indexes SQLGLOT_DIALECTS.
- Name the PORTABLE_DIALECT constant; drop the `.get("dialect",
"ANSI_SQL")` fallback, since the schema requires `dialect`.
- A dialect this validator cannot parse is reported as a nonfatal
warning that its expressions were not syntax-checked; it may be a
legitimate entry from extensions/dialects.md, not a mistake.
- Honor the spec's precedence rule: a top-level `sql` outranks an
OSSIE_SQL_2026 dialect entry, so that entry is non-authoritative. It
is not scope-checked, and an invalid one warns instead of failing the
document, since a client may still read it.
- Spec/docs wording: write OSSIE_SQL_2026 directly (no parenthetical),
"Any string is accepted", drop "Optional:" from the portable-form
comments, describe `data` as an opaque string (not JSON), and give
the glossary Dialect entry only ANSI_SQL as an example.
- models.py: optional `dialects` comment and the "convenience set, not
a closed one" phrasing removed; docstrings state any string is
accepted.
- Tests track the split, assert exact scope messages, cover the
precedence behavior, and compare dialects by value.
Co-authored-by: Isaac <no-reply@databricks.com>
* fix(validation): tighten sql/dialect handling per PR #617 review
Addresses review feedback on the decouple-core-spec PR
(#617):
- Require non-empty expression and identity strings: add minLength 1 to
`sql`, `dialect`, the per-dialect `expression`, and `vendor_name` in
both the schema and the SDK, so an empty value is rejected there
rather than slipping through -- an empty `sql`/`expression` reached
the SQL validator, an empty `dialect` produced an "is not supported"
warning, and an empty `vendor_name` was unchecked. Suggested by
@abolfazlmadanii.
- Warn when a non-authoritative OSSIE_SQL_2026 dialect entry drifts from
the authoritative top-level `sql`: a differing or invalid entry is
dead text a client might still read, so report it as a nonfatal
warning; an identical one stays silent.
- Suggest the closest known dialect on an unsupported one (difflib,
cutoff 0.8), so `SNOWFLKE` says "Did you mean 'SNOWFLAKE'?" without
flagging a genuinely new dialect.
- extensions/README.md: note that dialect and vendor tokens are matched
exactly and are case-sensitive, so `snowflake` is distinct from
`SNOWFLAKE`.
- Describe custom-extension `data` as an opaque string, not a JSON
string, in the schema and SDK, matching the spec/docs wording.
Co-authored-by: Isaac <no-reply@databricks.com>
* docs(extensions): register ATACCAMA in the vendor catalog
Add the ATACCAMA token to the known-vendor table, per #629.
Co-authored-by: Isaac <no-reply@databricks.com>
* fix(ci): point #630's precedence tests at SQLGLOT_DIALECTS
#630 added OSSIE_SQL_2026 precedence tests whose helper parses through
`DIALECT_MAP["OSSIE_SQL_2026"]`. This branch split that map into
`SQLGLOT_DIALECTS` (parseable) and `NON_SQL_DIALECTS`, so the merged-in
helper hit `AttributeError: module 'ossie_validate' has no attribute
'DIALECT_MAP'`. Point it at `SQLGLOT_DIALECTS[PORTABLE_DIALECT]`, the
same None (sqlglot default) entry, so the three tests pass unchanged.
Co-authored-by: Isaac <no-reply@databricks.com>
---------
Co-authored-by: Isaac <no-reply@databricks.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Followup from: #614
Three expressions parsed through the validator's own OSSIE_SQL_2026 dialect entry:
NOT a = bbuilds Not(EQ(a, b)),- a = bbuilds EQ(Neg(a), b), andNOT a AND bbuilds And(Not(a), b). Together they fix NOT between comparison and AND, and show that the unary operators it had been listed beside bind ahead of comparison instead.Related Issues
Checklist
Specification
core-spec/and follow the existing structureOntology
ontology/are consistent with spec changesConverters
Validation
validation/are updated if the spec changedDocumentation
docs/is updated to reflect any user-facing changesCONTRIBUTING.mdis updated if the contribution process changedExamples
examples/are added or updated for any new spec constructsTests
pytest/ CI green)Compliance
NOTICEand/orLICENSEhave been updated per ASF policy