Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Dimension(...).grain(...) in where filter #785

Merged
merged 11 commits into from
Oct 6, 2023

Conversation

DevonFulcher
Copy link
Contributor

@DevonFulcher DevonFulcher commented Sep 26, 2023

Resolves # SL-631 (internal to dbt labs)

Description

This PR adds support for the Dimension(...).grain(...) syntax for the where parameter and filter spec by using the factory pattern & implementing the Query Interface protocols.

I started on this branch before Tom & I talked about the git norms in this repo. Next PR, I will be sure to make every commit meaningful.

@cla-bot cla-bot bot added the cla:yes label Sep 26, 2023
@github-actions
Copy link

Thank you for your pull request! We could not find a changelog entry for this change. For details on how to document a change, see the contributing guide.

@DevonFulcher DevonFulcher marked this pull request as ready for review October 5, 2023 15:04
@tlento
Copy link
Contributor

tlento commented Oct 5, 2023

I started on this branch before Tom & I talked about the git norms in this repo. Next PR, I will be sure to make every commit meaningful.

Just as an aside, if you squash it's fine as long as the PR is reviewable in one chunk - I mainly care that every commit to the main source tree is focused and documented, so if squash achieves that it's totally fine.

Copy link
Contributor

@tlento tlento left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming I still understand this correctly I think this is good for now. Thanks for pushing these down to a more central location!

Once the current push is done we should go over all of this and see if there's an easy way to refine the interfaces further. I know Paul is doing some refactoring of the query parser itself, which I'm sure will have an effect on where we eventually land with these protocol specs.

Comment on lines +23 to +53
def resolve_dimension_spec(self, name: str, entity_path: Sequence[str]) -> DimensionSpec:
"""Resolve Dimension spec with the call_parameter_sets."""
structured_name = DunderedNameFormatter.parse_name(name)
call_parameter_set = DimensionCallParameterSet(
dimension_reference=DimensionReference(element_name=structured_name.element_name),
entity_path=(
tuple(EntityReference(element_name=arg) for arg in entity_path) + structured_name.entity_links
),
)
return DimensionSpec(
element_name=call_parameter_set.dimension_reference.element_name,
entity_links=call_parameter_set.entity_path,
)

def resolve_time_dimension_spec(
self, name: str, time_granularity_name: TimeGranularity, entity_path: Sequence[str]
) -> TimeDimensionSpec:
"""Resolve TimeDimension spec with the call_parameter_sets."""
structured_name = DunderedNameFormatter.parse_name(name)
call_parameter_set = TimeDimensionCallParameterSet(
time_dimension_reference=TimeDimensionReference(element_name=structured_name.element_name),
time_granularity=time_granularity_name,
entity_path=(
tuple(EntityReference(element_name=arg) for arg in entity_path) + structured_name.entity_links
),
)
assert call_parameter_set in self._call_parameter_sets.time_dimension_call_parameter_sets
return TimeDimensionSpec(
element_name=call_parameter_set.time_dimension_reference.element_name,
entity_links=call_parameter_set.entity_path,
time_granularity=call_parameter_set.time_granularity,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this logic already exist somewhere in MetricFlow? Or am I confusing that with this logic existing in some other repo?

I might be thinking of the deleted code below, too. 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure! This code was moved here from elsewhere in this PR, which was also moved there from somewhere that @plypaul put it. So, Paul is the original author, and I just moved it here. He may know if this is duplicative of somewhere else in MF.

Comment on lines +41 to +48
self.time_dimension_spec: Optional[TimeDimensionSpec] = None

def grain(self, _grain: str) -> QueryInterfaceDimension:
def grain(self, time_granularity_name: str) -> QueryInterfaceDimension:
"""The time granularity."""
raise NotImplementedError
self.time_dimension_spec = self._dimension_spec_resolver.resolve_time_dimension_spec(
self._name, TimeGranularity(time_granularity_name), self._entity_path
)
return self
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, this has to be here because it's the input protocol. The output QueryParameter or whatever it's called has these organized a bit better. Do I have that right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify what you mean by this and these 😃?

raise InvalidQuerySyntax(
"Can't set descending in the where clause. Try setting descending in the order_by clause instead"
)
raise InvalidQuerySyntax("descending is invalid in the where parameter")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. Seems like the protocol specs need more refinement, but this'll have to do for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the spec is fine. We don't have an LSP for the Jinja syntax, so I think providing a more specific error message will help our users more than a generic type error.

Comment on lines +40 to +41
self.dimension_spec = self._dimension_spec_resolver.resolve_dimension_spec(name, entity_path)
self.time_dimension_spec: Optional[TimeDimensionSpec] = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be using the type system to enforce that exactly one of these is set? Like we could make this a union type and keep the property itself internal, and then we get some protection against someone using a time dimension as a non-time dimension, which could get odd.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be using the type system to enforce that exactly one of these is set?

Do you mean something like:

self.spec: Union[DimensionSpec, TimeDimensionSpec] = self._dimension_spec_resolver.resolve_dimension_spec(name, entity_path)

I had started with that, but I think that would require the use of isinstance to disambiguate between the two types later when they are added to the lists. Paul steered me away from the use of isinstance.

protection against someone using a time dimension as a non-time dimension

Do you mean specifying grain on a non-time dimension? Or not specifying grain on a time dimension? I had thought that is validated after the specs are returned from create_from_where_filter. Is that not the case? I agree that should be checked somewhere

metricflow/specs/where_filter_dimension.py Outdated Show resolved Hide resolved
@DevonFulcher DevonFulcher merged commit dbbff3e into main Oct 6, 2023
8 checks passed
@DevonFulcher DevonFulcher deleted the dimension_dot_grain branch October 6, 2023 17:25
sarbmeetka pushed a commit to sarbmeetka/metricflow that referenced this pull request Nov 13, 2023
This PR adds support for the Dimension(...).grain(...) syntax for the where parameter and filter spec by using the factory pattern & implementing the Query Interface protocols.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants