-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Refactor building the Query struct #5893
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
Conversation
|
zoldar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! 🙌 Looks like a really good starting point for further changes, like moving date range parsing out of building to parsing stage.
Just for the record - one potentially necessary thing the we have touched on when going over this PR though it's outside of scope - we'll also need a way to turn a Query back into query string.
|
|
||
| defp validate_revenue_metrics_access(site, query) do | ||
| if Revenue.requested?(query.metrics) and not Revenue.available?(site) do | ||
| {:error, "The owner of this site does not have access to the revenue metrics feature."} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For future consideration: make the validation errors more friendly for internal consumption (well formed tuples with atoms/values) and build the human-formatted versions on top of it in the relevant contexts?
| |> Query.put_imported_opts(site) | ||
|
|
||
| on_ee do | ||
| # NOTE: The Query API schema does not allow the sample_threshold param |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems to be only used in a couple tests against Query.from, but yeah, not here.
| end | ||
|
|
||
| def parse_filters(_invalid_metrics), do: {:error, "Invalid filters passed."} | ||
| def parse_filters(nil), do: {:ok, nil} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I know we went over it but, do we want to let it pass silently? While APIv2 schema might ensure this is a list, passing invalid value internally getting silently ignored might cause confusion. Maybe we should even let it crash then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, actually, that's another thing I wanted to touch base with you on...
passing invalid value internally getting silently ignored might cause confusion.
The change we're currently looking at is in QueryParser, which will not be used for internal query building. Now, while QueryParser "parses" the filters, it's also validating the format. Kind of tricky to separate parsing and validating filters but yeah, I agree that even the internal QueryBuilder.build should return {:error, :invalid_filters} when you try to construct a query with filters: [%{"event:page" => "/"}, %{"visit:source" => "Google"}] (which is obviously not the correct representation of filters).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, indeed, filter parsing is still part of builder. Okay, I guess let's leave it be for now and try to address it in the future follow-ups?
Hmm I think there are different "query objects" we need to consider. The one that gets serialized into a URL query string will be what's currently defined in React: export const queryDefaultValue: DashboardQuery = {
period: '28d' as QueryPeriod,
comparison: null,
match_day_of_week: true,
date: null,
from: null,
to: null,
compare_from: null,
compare_to: null,
filters: [],
resolvedFilters: [],
labels: {},
with_imported: true
}I think the However, we'll still need to be able to construct a
|
Changes
This PR is a refactor and doesn't introduce any new behaviour.
In the upcoming dashboard migration from React to LiveView, we want to be able to create
Querystructs from native data structures. E.g.:Query.buildfunction, not thesite_idDateTimestructs instead of iso8601 stringsThe biggest refactor in this PR is changing the current
Query.buildfunction intoQuery.parse_and_buildwhich calls two separate modules (QueryParserandQueryBuilder(new) for the respective actions).It also introduces an intermediate data structure that represents the parsed state between those two phases -
ParsedQueryParams.There was a lot of query "building" logic and validations incorporated into
QueryParser. The test file (with more than 3k lines of code) got turned intoQueryParseAndBuildTest, now asserting on a Query struct outcome rather than an arbitrary map.This PR doesn't tackle the
date_rangeinput aspect yet. For now,QueryBuilderwill expect a cleanutc_time_rangeinput (via theParsedQueryParamsstruct). It shouldn't block this PR though. I can tackle it later. E.g.: we'll likely want to build queries like:With that, we can also migrate any existing ad-hoc
Queryconstruction (e.g. in email reports orquery_24h_stats) to use this new version ofQuery.build.Tests
Changelog
Documentation
Dark mode