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

Use case expression type inference logic similar to annotate middleware in MLv2 #47902

Merged
merged 7 commits into from
Oct 18, 2024

Conversation

lbrdnk
Copy link
Contributor

@lbrdnk lbrdnk commented Sep 12, 2024

Closes #47887
Closes #48010
Closes #47888

Initial description (not actual anymore)

The issue is that we infer return type for case expression as most specific common ancestor. If the arguments are :type/Date and :type/DateTime the ancestor is :type/Temporal. That results in limited filter picker options.

This PR adds special case for arguments of aforemementioned types. The :type/Date is picked as the expression type.

The question is however, whether the current behavior is really erroneous. To the best of my knowledge there's no way to decide correct argument type in this case, and picking the :type/Date is best effort, that could enable some cases, but may result in error in others.

Following stack (in reverse) is significant for the context (ie. if you are interested in how I got to this specific change):

metabase.lib.util/top-level-expression-clause
metabase.lib.schema.expression/type-of :case
metabase.lib.schema.expression.conditional/best-return-type

Description

This PR solves multiple problems.

Generic filter picker

We stopped checking for the type Temporal when selecting a appropriate filter picker, and switched to Date or DateTime. The case expression in #47887 is a bit tricky. It returns DateTime value when condition is met and Date value in default case. The MLv2 expression inference code was returning most specific common ancestor in this case - Temporal.

This PR changes the MLv2 case expression inference code to follow the logic in metabase.query-processor.middleware.annotate/infer-expression-type.

Bigquery error

Bigquery bugs have a different cause. Something changed in a way we compute expressions. In older version that was done in subquery. But in the current version, the expression from reproduction is computed on the same level. The Bigquery logic for appropriate database type inference is now presented with the case expression instead of reference to field from subquery.

This PR adds metabase.driver.bigquery-cloud-sdk.query-processor/temporal-type implementation for :case expression, that follows same logic laid out in the annotate/infer-expression-type.

Long story short, that results in appropriate type reconciliation by means of metabase.driver.bigquery-cloud-sdk.query-processor/reconcile-temporal-types.

Is that a right decision to model inference by annotate/infer-expression-type?

Depends on context. Yes in short term. Those 2 bugs are recent regressions and this PR addresses them in relatively non-invasive manner, expanding approach that is taken already in neighboring part of the code base.

In long term, when looking for general right solution to Type system issues mentioned by Ranquild, we should keep in mind this case.

Maybe that would entail creating new type hierarchies for different contexts as noted by Metamben.

@lbrdnk lbrdnk changed the title Use type date for case expression when there are Date and DateTime args [WIP] Use type date for case expression when there are Date and DateTime args Sep 12, 2024
Copy link
Contributor

@ranquild ranquild left a comment

Choose a reason for hiding this comment

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

Looks correct. Let's add tests and merge.

Copy link
Contributor

@metamben metamben left a comment

Choose a reason for hiding this comment

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

To me, this means that we are saying that all operations that are valid for :type/Date are valid for a case expression containing a :type/DateTime value. If that's true, then :type/Date should be an ancestor of :type/DateTime, and this hack is not needed. If that's not true, then this invites trouble.

I have the feeling we are expecting too much from a single type hierarchy.

});

it("Case expression with type/Date default value and type/DateTime case value has Date filter popover enabled (metabase#47887)", () => {
visitQuestionAdhoc({
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 whether this is the right approach here. Would welcome FE eyes on this.

@lbrdnk lbrdnk changed the title [WIP] Use type date for case expression when there are Date and DateTime args Use type date for case expression when there are Date and DateTime args Oct 3, 2024
@lbrdnk lbrdnk added the backport Automatically create PR on current release branch on merge label Oct 4, 2024
@lbrdnk lbrdnk changed the title Use type date for case expression when there are Date and DateTime args Use case expression type inference logic similar to annotate middleware in MLv2 Oct 11, 2024
@appleby
Copy link
Contributor

appleby commented Oct 11, 2024

To me, this means that we are saying that all operations that are valid for :type/Date are valid for a case expression containing a :type/DateTime value. If that's true, then :type/Date should be an ancestor of :type/DateTime, and this hack is not needed. If that's not true, then this invites trouble.

I have the feeling we are expecting too much from a single type hierarchy.

I guess this comment was about a previous iteration of this PR, but overall agree. Maybe now it's even more lax since IIUC the temporal type of the case expression now depends on the order of the clauses, so we're saying any temporal type should be equivalent?

Copy link
Contributor

@appleby appleby left a comment

Choose a reason for hiding this comment

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

Approved since it fixes customer issues and it's reasonable to have the QP and schema agree on how to type the expressions, but also agree with @metamben's comment.

I would suggest to update that linked Notion doc under the temporal types heading with a link pointing to this issue.

;; Following logic for picking a type is taken from
;; the [[metabase.query-processor.middleware.annotate/infer-expression-type]].
(loop [[cond-or-else expr & rezt*] rezt]
(when (and expr (not= :else cond-or-else))
Copy link
Contributor

Choose a reason for hiding this comment

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

why does this exclude the :else clause?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the way annotate/infer-expression-type operates currently.

(mt/test-driver
:bigquery-cloud-sdk
(testing "Query with case expression with default Date and case DateTime is executable (#47888)"
(is (=? {:status :completed}
Copy link
Contributor

Choose a reason for hiding this comment

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

does it make sense to check the result rows here?

Copy link
Contributor Author

@lbrdnk lbrdnk Oct 17, 2024

Choose a reason for hiding this comment

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

Rows are empty in this case. Point of that test is to show whether query executes without underlying jdbc driver throwing an exception. I'll add the comment about that.

@lbrdnk lbrdnk merged commit 63a3b4b into master Oct 18, 2024
132 checks passed
@lbrdnk lbrdnk deleted the 47887-date-filter branch October 18, 2024 15:41
github-automation-metabase pushed a commit that referenced this pull request Oct 18, 2024
…re in MLv2 (#47902)

* Use type date for case expression when there are Date and DateTime args

* Use logic for getting case expr type from annotate middleware

* Add e2e test

* Add bigquery test

* Update test

* cljfmt and comment

* Adjust e2e test
@lbrdnk
Copy link
Contributor Author

lbrdnk commented Oct 18, 2024

@metabase-bot backport release-x.50.x

Copy link
Contributor

@lbrdnk something went wrong while creating a backport [Logs]

lbrdnk added a commit that referenced this pull request Oct 21, 2024
…re in MLv2 (#47902)

* Use type date for case expression when there are Date and DateTime args

* Use logic for getting case expr type from annotate middleware

* Add e2e test

* Add bigquery test

* Update test

* cljfmt and comment

* Adjust e2e test
github-automation-metabase added a commit that referenced this pull request Oct 21, 2024
…re in MLv2 (#47902) (#48893)

* Use type date for case expression when there are Date and DateTime args

* Use logic for getting case expr type from annotate middleware

* Add e2e test

* Add bigquery test

* Update test

* cljfmt and comment

* Adjust e2e test

Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
lbrdnk added a commit that referenced this pull request Oct 30, 2024
…re in MLv2 (#47902)

* Use type date for case expression when there are Date and DateTime args

* Use logic for getting case expr type from annotate middleware

* Add e2e test

* Add bigquery test

* Update test

* cljfmt and comment

* Adjust e2e test
lbrdnk added a commit that referenced this pull request Oct 31, 2024
…otate middleware in MLv2 (#47902) (#48923)

* Use case expression type inference logic similar to annotate middleware in MLv2 (#47902)

* Use type date for case expression when there are Date and DateTime args

* Use logic for getting case expr type from annotate middleware

* Add e2e test

* Add bigquery test

* Update test

* cljfmt and comment

* Adjust e2e test

* Adjust e2e test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport Automatically create PR on current release branch on merge .Team/Querying
Projects
None yet
4 participants