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

feat: allow queries preview with same query but different filters or params #1392

Conversation

lauramargar
Copy link
Contributor

@lauramargar lauramargar commented Jan 15, 2024

Pull request template

In the current implementation, we are only saving queries. As a second step, we should also support filters and extraparams, but then we should save the hash of query+filters.

We have used js-md5 hash to make an id to differentiate the same queries but with different filters applied.

There was a problem when dealing with multiple instances of the QueryPreview component with the same query hash. In that case, the order of mounting and unmounting the components matter and it could lead to a scenario where a component is mounted but afterwards, the other one with the same query hash is unmounted and both of them will be gone from the DOM.

We have applied the following SOLUTION:

Refactor the events emitted from QueryPreview. Remove NonCacheableQueryPreviewUnmounted and add QueryPreviewMounted: string; QueryPreviewUnmounted: { query: string, cache: boolean };

Enhance the QueryPreviewItem from the state with a field

  /** The number of instances showing the query preview*/
  instances: number;

The fetchAndSaveQueryPreview action will set the instances field to 1 since it will be the first instance of a QueryPreview using this query hash.

Every QueryPreview instance when is created and picks the data from the cache will emit QueryPreviewMounted so the instances count is increased. Every instance of QueryPreview will emit QueryPreviewUnmounted so the instances count for that query hash will be decreased and if the cache is set to false, then the query will be removed safely from the state since there will be no component showing that data.

Motivation and context

  • Dependencies. If any, specify:
  • Open issue. If applicable, link: EMP-3079

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that causes existing functionality to not work as expected)
  • Change requires a documentation update

What is the destination branch of this PR?

  • Main
  • Other. Specify:

How has this been tested?

You can test 2 scenarios:

  1. Same query + different filters
  2. Same query in different instances

In scenario 1 --> you can add in Home.vue file this new query preview in queriesPreviewInfo :

{
  query: 'summer dress',
  filters: ['brand:marni']
}

You should see 2 carrousels with 'summer dress' as the title but with different results.

In scenario 2 --> add in the same place as the previous scenario the following query preview:

{
  query: 'charger'
}

Then search for battery in the search box. This query has the query charger as a semantic query.
As we had saved charger in the state from the brand recommendations, in semantic queries should be loaded from the state instead of being requested again.

Once we clear the query in the search box, we should see that charger keeps saved in the query preview state and is displayed as a brand recommendation.

Checklist:

  • My code follows the style guidelines of this project.
  • I have performed a self-review on my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation.
  • My changes generate no new warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.

@lauramargar lauramargar requested a review from a team as a code owner January 15, 2024 08:13
annacv
annacv previously approved these changes Jan 15, 2024
Copy link
Contributor

@annacv annacv left a comment

Choose a reason for hiding this comment

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

Also tested with:{ query: 'wallet', filters: ['brand:valentino']}, as a queryPreview + searching for charger to check that Semantic Queries will show results for the query wallet without being filtered.

*
* @internal
*/
public queryOfQueryPreviewHash = getHashFromQueryPreviewInfo(this.queryPreviewInfo);
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename to queryPreviewHash

*
* @internal
*/
public queryOfQueryPreviewHash = getHashFromQueryPreviewInfo(this.queryPreviewInfo);
Copy link
Contributor

Choose a reason for hiding this comment

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

This uses a dynamic value to generate a non-dynamic value. Make it a computed property.

/**
* The query preview has been mounted.
* Payload: The query preview query as a key converted into a unique id (query hash).
* When QueryPreviewMounted is emitted, the instances count is increased.
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to explain this here. What the module does when the event fires is not relevant here.

Comment on lines 38 to 40
* When QueryPreviewUnmounted is emitted, the instance count for that query hash
* will be decreased. If the cache is set to false, the query will be removed
* safely from the state since there will be no component showing that data.
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above

@@ -41,7 +42,21 @@ export const queriesPreviewXStoreModule: QueriesPreviewXStoreModule = {
state.selectedQueryPreview = selectedQueryPreview;
},
setConfig,
mergeConfig
mergeConfig,
addQueryPreviewInstance(state, query: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not the query, is the queryPreviewHash

Comment on lines 32 to 37
let queryPreviewFilters = '';
if (queryPreviewInfo.filters) {
queryPreviewInfo.filters.forEach(filter => {
queryPreviewFilters = queryPreviewFilters.concat('-' + filter);
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You can refactor to this:

Suggested change
let queryPreviewFilters = '';
if (queryPreviewInfo.filters) {
queryPreviewInfo.filters.forEach(filter => {
queryPreviewFilters = queryPreviewFilters.concat('-' + filter);
});
}
const queryPreviewFilters = queryPreviewInfo.filters ? queryPreviewInfo.filters.join('-') : '';

Comment on lines 12 to 20
let queryPreviewFilters = '';
if (queryPreview.request.filters) {
const queryPreviewFiltersKeys = Object.keys(queryPreview.request.filters);
queryPreviewFiltersKeys.forEach(key => {
queryPreview.request.filters![key].forEach(filter => {
queryPreviewFilters = queryPreviewFilters.concat('-' + filter.id.toString());
});
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You can refactor this to:

Suggested change
let queryPreviewFilters = '';
if (queryPreview.request.filters) {
const queryPreviewFiltersKeys = Object.keys(queryPreview.request.filters);
queryPreviewFiltersKeys.forEach(key => {
queryPreview.request.filters![key].forEach(filter => {
queryPreviewFilters = queryPreviewFilters.concat('-' + filter.id.toString());
});
});
}
const queryPreviewFilters = Object.values(queryPreview.request.filters)
.flat()
.map(filter => filter.id.toString())
.join('-');

Copy link
Contributor

Choose a reason for hiding this comment

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

Make the QP in the tests have filters. Half of the implementation is not being tested right now

this.queriesStatus[query] === 'success' || this.queriesStatus[query] === 'loading'
);
return this.queriesPreviewInfo.filter(item => {
const query = getHashFromQueryPreviewInfo(item);
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename to queryPreviewHash

@@ -86,7 +86,9 @@ describe('testing QueryPreviewList', () => {
expect(queryPreviews.at(1).text()).toEqual('jeans - Sick jeans');
});

it('hides queries with no results', async () => {
// TODO Uncomment when the 'error' event is fixed
Copy link
Contributor

Choose a reason for hiding this comment

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

If there's a task already, add the task ID here

Copy link
Contributor

Choose a reason for hiding this comment

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

Reference task EMP-3402

Copy link
Contributor

@CachedaCodes CachedaCodes left a comment

Choose a reason for hiding this comment

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

Fix the conflicts with main too

addQueryPreviewInstance(state, query: string) {
if (state.queriesPreview[query]) {
state.queriesPreview[query].instances += 1;
addQueryPreviewInstance(state, queryPreviewHash: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to specify the type in queryPreviewHash: string, it's already being done in the types file, remove the string.

state.queriesPreview[query].instances -= 1;
removeQueryPreviewInstance(
state,
{ queryPreviewHash, cache }: { queryPreviewHash: string; cache: boolean }
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, you don't need the type in { queryPreviewHash, cache }: { queryPreviewHash: string; cache: boolean }, leave it as { queryPreviewHash, cache }

@@ -111,8 +111,14 @@ export interface QueriesPreviewMutations extends ConfigMutations<QueriesPreviewS
* @param selectedQueryPreview - The selected query preview to save to the state.
*/
setSelectedQueryPreview(selectedQueryPreview: QueryPreviewInfo | null): void;
addQueryPreviewInstance(query: string): void;
removeQueryPreviewInstance({ query, cache }: { query: string; cache: boolean }): void;
addQueryPreviewInstance(queryPreviewHash: string): void;
Copy link
Contributor

Choose a reason for hiding this comment

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

Add docs

addQueryPreviewInstance(query: string): void;
removeQueryPreviewInstance({ query, cache }: { query: string; cache: boolean }): void;
addQueryPreviewInstance(queryPreviewHash: string): void;
removeQueryPreviewInstance({
Copy link
Contributor

Choose a reason for hiding this comment

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

Add docs

@@ -86,7 +86,9 @@ describe('testing QueryPreviewList', () => {
expect(queryPreviews.at(1).text()).toEqual('jeans - Sick jeans');
});

it('hides queries with no results', async () => {
// TODO Uncomment when the 'error' event is fixed
Copy link
Contributor

Choose a reason for hiding this comment

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

Reference task EMP-3402

@CachedaCodes CachedaCodes merged commit 4c1f63a into main Jan 25, 2024
4 checks passed
@CachedaCodes CachedaCodes deleted the feature/EMP-3079-allow-queries-preview-with-same-query-but-different-filters-or-params branch January 25, 2024 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants