Add Malloy semantic model adapter support#36
Conversation
Implements full Malloy file format support for Sidemantic with:
- **Import support**: Simple imports, named imports, aliased imports, multi-level
imports, and circular import cycle detection
- **Annotations**: Parse and preserve model/dimension/measure descriptions from
Malloy `# desc:` and `##` comments with full roundtrip export support
- **SQL sources**: Support for both table-based and SQL-based `duckdb.sql()` sources
with full query preservation
- **Comprehensive test coverage**: 44 tests (vs initial 5) covering:
- 7 import tests (simple, named, aliased, multi-level, circular, missing, directory)
- 5 basic parsing tests (flights, ecommerce, directory, export, roundtrip)
- 11 domain fixture tests (retail analytics, SaaS metrics)
- 9 edge case tests (minimal sources, complex expressions, all aggregations,
all join types, filtered sources, time granularities, booleans)
- 5 annotation tests (model/dimension/measure annotations, roundtrip)
- 7 SQL source tests (parsing, preservation, dimensions/measures, roundtrip)
Core implementation:
- MalloyAdapter class using ANTLR4 grammar for parsing
- MalloyModelVisitor traversing AST to extract semantic information
- Recursive file parsing with cycle detection for imports
- Type inference for dimensions (categorical, time, boolean, numeric)
- Mapping of Malloy concepts to Sidemantic: sources→models, dimensions→dimensions,
measures→metrics, joins→relationships
Extended Dimension class to support time granularities: second, minute, hour, day,
week, month, quarter, year.
All 44 tests passing, linting clean.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 495196d384
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if agg is None and sql: | ||
| # Check if it's a ratio or derived | ||
| if "/" in sql and not any(agg in sql.lower() for agg in ["sum(", "count(", "avg("]): | ||
| metric_type = "ratio" |
There was a problem hiding this comment.
Avoid ratio metrics without numerator/denominator
When a measure expression contains / and no sum/count/avg, this branch sets metric_type to ratio but never populates numerator/denominator. The Metric validator in sidemantic/core/metric.py rejects ratio metrics without those fields, so any Malloy measure like profit_margin is revenue / cost will raise during parsing and abort the import. Consider keeping these as derived or parsing and assigning numerator/denominator before constructing the Metric.
Useful? React with 👍 / 👎.
Summary
duckdb.sql()sources with full query preservation