-
Notifications
You must be signed in to change notification settings - Fork 14.4k
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
Autocomplete in the table browser in SQL lab is broken - Fix part 2 #7770
Conversation
@@ -191,12 +199,6 @@ export default class TableSelector extends React.PureComponent { | |||
this.onChange(); | |||
}); | |||
} | |||
addOptionIfMissing(options, value) { |
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.
@khtruong we don't need this anymore?
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.
Oh I'm sorry. I totally forgot to mention in my description. So this entire component is buggy and doesn't work as expected. What this function does is that if the option is missing, then we add it to the list with just the table name. I believe the original intent was to display something while we were fetching the tables. This led to a few bugs:
- We may be adding a table that no longer exists to the list, which doesn't make sense. So when the user selects this table, it just breaks silently because the table doesn't exist.
- Even if the table exists, we did not populate this option with the schema and so when we make a request to get the table, again it breaks silently because we get the table with just its name and no schema information.
I felt that if we really wanted to display something while we fetch the tables, we should do it properly with tests. So I just removed the buggy code for now and thought we can revisit it later if that is a feature we really want.
The component is still buggy but it's less buggy. I'll add this explanation to the description. Let me know your thoughts.
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.
Thanks, make sense!
superset/assets/spec/javascripts/components/TableSelector_spec.jsx
Outdated
Show resolved
Hide resolved
Codecov Report
@@ Coverage Diff @@
## master #7770 +/- ##
=========================================
Coverage ? 65.89%
=========================================
Files ? 459
Lines ? 22007
Branches ? 2417
=========================================
Hits ? 14502
Misses ? 7384
Partials ? 121
Continue to review full report at Codecov.
|
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.
Note that <TableSelector />
is also used in the <TableEditor />
, where it's used in somewhat different ways. If a chart points to a table and that physical table gets dropped, we still need to see it there.
Really in that case we should have some sort of red exclamation point with a tooltip highlighting that fact.
Another element of complexity that I was dealing with when I generalized that component (for Clearly searching/ across schemas is super useful, but adds another layer of complexity on top or an already heavy component. |
A bit more context. I think recently in #7297, there was an effort to move from using "fully-qualified" table names as in |
The breaking change @mistercrunch is referring to was introduced in #7453 , where fully qualified table names were replaced by objects. It seems the consequences were more far reaching than were understood at the time.. |
I didn't see TableEditor but I did see TableSelector in DataSourceEditor and verified this fix there. There was also another issue when a user explores a chart based off a query. The query name would then be added to the list of tables, which doesn't make sense. I could file a Github to track the ideal experience where there is some sort of red bang with a tooltip letting the user know what the physical table was. Otherwise putting addOptionIfMissing brings back all the issues highlighted earlier. Let me know what you think. |
@villebro @mistercrunch Thanks for the backstory! Wow, I can see that there was a lot of work done to fix the previous issues. One question: Will there be a regression if the option value is not specifically an object {table: ..., schema: ...}? I did not use fully-qualified table names. I just pulled out table and schema into separate properties in the parent object and it seems fine. Am I missing something? |
@khtruong I think any solution that makes it possible to unambiguously separate schema from table name should be fine. IIRC one option that was proposed was to keep using a fully qualified string, but apply escaping where necessary. I also remember that @john-bodley is/was working on introducing the concept of a cluster, i.e. one level of abstraction above schema ( |
@mistercrunch Let me know if you prefer a specific change. I think my changes will not bring back issues you saw when we used the fully qualified names in the past because the table name and schema name are still separate properties. And I can file a Github issue to track the ideal experience where there is some sort of red bang with a tooltip letting the user know if the physical table is missing. |
I just wanted to make sure you have all the context for the complexity in this area. I'm ok with the change if there are no regressions across the board. The caching feature (from cross schema table name autocomplete) I mentioned seems brittle, and someone at Airbnb (where they use the feature) might want to confirm that this works there. |
Gotcha! I don't think this should affect the caching feature since that is a backend operation and this change is mostly frontend changes and does not modify the schema/table name itself. I have filed issue #7798 as well. |
If it's of any help I'll be happy to run this PR through some testing, as the Presto + Pular and Drill issues that were the basis for my PRs that were mentioned here are still fresh in my memory. Will be able to do a thorough testing during the weekend. |
That'd be awesome @villebro ! Thanks! |
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.
Functionally this works 100 % with all difficult edge cases I used to validate the Presto+Pulsar and Drill PRs. Apart from aligning the object structures across the frontend and backend this LGTM. Incidentally, what is the role of title
, as it seems to always have the same value as label
?
value: o.value.table, | ||
schema: o.value.schema, | ||
label: o.label, | ||
title: o.label, |
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.
To avoid confusion down the line I think it might be a good idea to align what is returned by the backend with this new structure. Something along these lines (didn't test so might contain typos):
diff --git a/superset/assets/spec/javascripts/sqllab/fixtures.js b/superset/assets/spec/javascripts/sqllab/fixtures.js
index 99e740c3..2b737fef 100644
--- a/superset/assets/spec/javascripts/sqllab/fixtures.js
+++ b/superset/assets/spec/javascripts/sqllab/fixtures.js
@@ -343,16 +343,22 @@ export const databases = {
export const tables = {
options: [
{
- value: { schema: 'main', table: 'birth_names' },
+ value: 'birth_names',
+ schema: 'main',
label: 'birth_names',
+ title: 'birth_names',
},
{
- value: { schema: 'main', table: 'energy_usage' },
+ value: 'energy_usage',
+ schema: 'main',
label: 'energy_usage',
+ title: 'energy_usage',
},
{
- value: { schema: 'main', table: 'wb_health_population' },
+ value: 'wb_health_population',
+ schema: 'main',
label: 'wb_health_population',
+ title: 'wb_health_population',
},
],
};
diff --git a/superset/assets/src/components/TableSelector.jsx b/superset/assets/src/components/TableSelector.jsx
index 4c9ef7a9..dc5d075c 100644
--- a/superset/assets/src/components/TableSelector.jsx
+++ b/superset/assets/src/components/TableSelector.jsx
@@ -108,10 +108,10 @@ export default class TableSelector extends React.PureComponent {
`${encodeURIComponent(this.props.schema)}/${encodeURIComponent(input)}`),
}).then(({ json }) => {
const options = json.options.map(o => ({
- value: o.value.table,
- schema: o.value.schema,
+ value: o.value,
+ schema: o.schema,
label: o.label,
- title: o.label,
+ title: o.title,
}));
return ({ options });
});
@@ -138,10 +138,10 @@ export default class TableSelector extends React.PureComponent {
return SupersetClient.get({ endpoint })
.then(({ json }) => {
const options = json.options.map(o => ({
- value: o.value.table,
- schema: o.value.schema,
+ value: o.value,
+ schema: o.schema,
label: o.label,
- title: o.label,
+ title: o.title,
}));
this.setState(() => ({
filterOptions: createFilterOptions({ options }),
diff --git a/superset/views/core.py b/superset/views/core.py
index 06727f7a..8355ec39 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -1627,14 +1627,16 @@ class Superset(BaseSupersetView):
max_tables = max_items * len(tables) // total_items
max_views = max_items * len(views) // total_items
- def get_datasource_value(ds_name: utils.DatasourceName) -> Dict[str, str]:
- return {'schema': ds_name.schema, 'table': ds_name.table}
-
- table_options = [{'value': get_datasource_value(tn),
- 'label': get_datasource_label(tn)}
+ table_options = [{'value': tn.table,
+ 'schema': tn.schema,
+ 'label': get_datasource_label(tn),
+ 'title': get_datasource_label(tn)}
for tn in tables[:max_tables]]
- table_options.extend([{'value': get_datasource_value(vn),
- 'label': f'[view] {get_datasource_label(vn)}'}
+ table_options.extend([{'value': vn.table,
+ 'schema': vn.schema,
+ 'label': f'[view] {get_datasource_label(vn)}',
+ 'title': f'[view] {get_datasource_label(vn)}',
+ }
for vn in views[:max_views]])
payload = {
'tableLength': len(tables) + len(views),
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.
Sounds good! I'll update the code. As for the title, I am not sure what the history is on that attribute and why we need it.
value: o.value.table, | ||
schema: o.value.schema, | ||
label: o.label, | ||
title: o.label, |
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.
Same as above
One problem that @mistercrunch pointed out is that if I think these changes go slightly beyond the original intent of this PR, so I propose we merge this as is, and I can put together a new PR that tackles this stuff I've just proposed (should be fairly quick). |
Got it. That would be awesome if you have time. Otherwise, we can file an issue to track it for the future. |
CATEGORY
Choose one
SUMMARY
This is the complete fix for autocomplete in the table browser in SQL lab. We use the createFilterOptions API from the react-select-fast-filter-options library for autocomplete. The API expects a list of option objects where its properties value and label are strings. The bug is that we were passing objects to the property value, which caused the algorithm to not work properly. Now we explicitly pass strings to the API.
Two additional changes I added:
I feel that if we really wanted to display something while we fetch the tables, we should do it properly with tests. So I just removed the buggy code for now and thought we can revisit it later if that is a feature we really want.
TEST PLAN
Manually and extended unit tests
REVIEWERS
@mistercrunch @betodealmeida @DiggidyDave @xtinec