-
-
Notifications
You must be signed in to change notification settings - Fork 178
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: Filter pacticipant name on index page #446
Conversation
div.top-of-group { | ||
margin-top: 20px; | ||
margin-bottom: 20px; | ||
} |
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.
When I test it locally, looks like the change in the index.css
file does not
get reflected
Copy those changes and put into Firefox css style editor result in the image in
the PR description
Im not sure what I did wrong which made the index.css
changes not get copied
to the server asset. Any hint?
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.
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 can't think of anything to be honest.
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.
It is fixed now. Im not sure why it did not work before 🤷
end | ||
end | ||
|
||
context "when it is NOT blank and exist" do |
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.
I would prefer not having to many level of indentation, hence the and
in the
description. Please let me know if you think otherwise
a14a146
to
d103459
Compare
This is to fix #318 |
Can we re-think the search form? How about a single field where you can type in anything, and it does a partial match with either consumer or provider names? I feel like having to type in the exact consumer/provider name might be a bit fiddley. eg. Search: This is how the Pactflow search bar works. What do you think? |
I did not expect that gif to be so big 😆 |
Yes agree 👍
This can be archieved by having some sort of regex matching. However
This may need some kind of fuzzy search matching. This gem comes to my mind https://github.com/kiyoka/fuzzy-string-match. Im leaning toward using some kind of regex matching instead of adding extra dependency. What do you think? |
I think let's just start with a substring, ignore case match and get feedback on that. |
You can do a substring, case ignore match using the Sequel gem like so:
Then find any pact that has either the consumer or provider in that list of pacticipants. |
lib/pact_broker/index/service.rb
Outdated
error_messages = [] | ||
|
||
pacticipant = pacticipant_service.find_pacticipant_by_name(pacticipant_name) | ||
def self.filter_item_by_pacticipant_name(index_items, pacticipant_name) |
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.
The query to generate the index results is quite intensive, and can be slow. It's better to filter at the SQL level, not do the entire query and then filter in memory.
Find the matching pacticipants as per the example that I posted earlier, get their IDs, then update the base query to do something like:
query = query.where( Sequel.|( { consumer_id: pacticipant_ids}, { provider_id: pacticipant_ids} ) )
94ca4e2
to
84dff5e
Compare
lib/pact_broker/index/service.rb
Outdated
query | ||
end | ||
|
||
def self.pacticipant_name_query(pacticipant_name) |
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.
This is getting closer! But it's still filtering a really big slow dataset (the entire index query) on a string match, rather than finding the pacticipants (a really small query) on a string match, and then being able to set the exact IDs of the consumer and provider in the big query (which will make it super quick). What's your thinking behind that?
lib/pact_broker/index/service.rb
Outdated
query | ||
end | ||
|
||
def self.pacticipant_name_query(pacticipant_name) |
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.
This is getting closer! But it's still filtering a really big slow dataset (the entire index query) on a string match, rather than finding the pacticipants (a really small query) on a string match, and then being able to set the exact IDs of the consumer and provider in the big query (which will make it super quick). What's your thinking behind that?
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.
What's your thinking behind that?
I was thinking doing 2 round trips to the database is a bit inefficient.
However, I think I'm wrong as you said filtering string match with ilike
is also an expensive query
I'll do it the way you suggested and probably find the way to optimise the current index query on a different issue/PR :)
Thanks for being patient with me :)
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.
Attemp in 8fd82a5
The new SQL query looks like below
SELECT pact_publications.*
FROM pact_publications
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id)
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id)
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
WHERE ((pact_publications.id IN
(SELECT p.*
FROM
(SELECT pact_publications.id
FROM pact_publications
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
LEFT JOIN
(SELECT consumer_id,
provider_id,
"order"
FROM pact_publications
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)) AS pp2 ON ((pact_publications.consumer_id = pp2.consumer_id)
AND (pact_publications.provider_id = pp2.provider_id)
AND (pp2.order > cv.order))
WHERE (pp2.order IS NULL)) AS p
INNER JOIN latest_pact_publication_ids_for_consumer_versions AS lp ON (lp.pact_publication_id = p.id)))
AND (pact_publications.id IN
(SELECT pact_publications.id
FROM pact_publications
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id)
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id)
WHERE ((providers.name ILIKE '%test%' ESCAPE '\')
OR (providers.name ILIKE '%ap\_tesp%' ESCAPE '\')
OR (consumers.name ILIKE '%test\_d%' ESCAPE '\')
OR (consumers.name ILIKE '%appdf%' ESCAPE '\')))))
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.
Please let me know how you think.
There is a failed test in app_spec.rb
which Im a bit baffled to understand. Will look at it later after you are happy with the filtering :)
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.
This is the part that gets added to a big index query
AND (pact_publications.id IN
(SELECT pact_publications.id
FROM pact_publications
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id)
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id)
WHERE ((providers.name ILIKE '%test%' ESCAPE '\')
OR (providers.name ILIKE '%ap\_tesp%' ESCAPE '\')
OR (consumers.name ILIKE '%test\_d%' ESCAPE '\')
OR (consumers.name ILIKE '%appdf%' ESCAPE '\')))))
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.
The problem with this approach is that it has to do all the joins, creating a big dataset, then remove lines by filtering on the pacticipant names afterwards.
By doing the query to get the pacticipant ids first, and only joining those consumers, then the dataset never gets big in the first place. Ideally, we want a query that looks like:
SELECT pact_publications.id
FROM pact_publications
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id and pact_publications.consumer_id in [<the ids from the first query>])
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id and providers.id in [<the ids from the first query>])
I've learned that making an extra round trip to the database is worth the trade off when you can significantly cut down on the amount of data being processed in a subsequent query.
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.
Sorry, I put those IN statements in the wrong part of the query.
SELECT pact_publications.*
FROM pact_publications
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id)
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id)
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
WHERE ((pact_publications.id IN
(SELECT p.*
FROM
(SELECT pact_publications.id
FROM pact_publications
--- filter here
WHERE ( pact_publications.consumer_id IN [...] OR pact_publications.provider_id IN [...])
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
LEFT JOIN
(SELECT consumer_id,
provider_id,
"order"
FROM pact_publications
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)) AS pp2 ON ((pact_publications.consumer_id = pp2.consumer_id)
AND (pact_publications.provider_id = pp2.provider_id)
AND (pp2.order > cv.order))
WHERE (pp2.order IS NULL)) AS p
INNER JOIN latest_pact_publication_ids_for_consumer_versions AS lp ON (lp.pact_publication_id = p.id)))
AND (pact_publications.id IN
(SELECT pact_publications.id
FROM pact_publications
--- filter here
WHERE ( pact_publications.consumer_id IN [...] OR pact_publications.provider_id IN [...])
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id)
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id)
)
See how that's filtering the base table before it gets joined, rather than on a joined table after it gets joined?
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.
Fixed in 80388e9
This is the final SQL. As we already got the pacticipant ids, we can use them in a subquery too. I think it will also boost up the index query.
SELECT pact_publications.*
FROM pact_publications
INNER JOIN pacticipants AS consumers ON (pact_publications.consumer_id = consumers.id)
INNER JOIN pacticipants AS providers ON (pact_publications.provider_id = providers.id)
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
WHERE (pact_publications.id IN
(SELECT p.*
FROM
(SELECT pact_publications.id
FROM pact_publications
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
LEFT JOIN
(SELECT consumer_id,
provider_id,
ORDER
FROM pact_publications
INNER JOIN versions AS cv ON (pact_publications.consumer_version_id = cv.id)
--- use pacticticpant ids in subquery here
WHERE (pact_publications.id IN (1,
2,
3,
4))) AS pp2 ON ((pact_publications.consumer_id = pp2.consumer_id)
AND (pact_publications.provider_id = pp2.provider_id)
AND (pp2.order > cv.order))
--- filter by pacticipant ids here
WHERE ((pact_publications.id IN (1,
2,
3,
4))
AND (pp2.order IS NULL))) AS p
INNER JOIN latest_pact_publication_ids_for_consumer_versions AS lp ON (lp.pact_publication_id = p.id)));
07bf41c
to
6a7345d
Compare
313d324
to
80388e9
Compare
It's failing because the pull request build doesn't have access to the env var it needs. However, I thought I toggled that to only run when it had the env var. I'll have a look at it. |
lib/pact_broker/index/service.rb
Outdated
Sequel.|( *terms.map { |term| Sequel.ilike(Sequel[:consumers][:name], "%#{term}%") }) | ||
) | ||
|
||
PactBroker::Pacts::PactPublication |
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.
I'm still confused as to why you're querying the pact publication table, instead of just querying the pacticipant table directly. To do this query requires that you join the pacticipant table twice to the pact publication table, and then filter on the entire dataset based on two columns (there could be 1000s of pact publications).
If you query the pacticipant table directly, you only do the filtering once, there are no joins, and it's there are likely to be 10s of pacticipants maximum.
I feel like we're not on the same page here. Is there something I'm missing? Shall we have a lunch time catch up?
I've updated the code that runs the pact verify to check for empty string as well as nil. Merge master in, and see if that fixes the Sqlite build. |
2538ec1
to
d48df4f
Compare
Oh I have not tokenise by spliting |
There was no dash in the search string. I just put in "bar". "bar" should match "bar-provider". |
The unit test for search indicates that it should work, so I'm guessing the issue is somewhere outside that. |
Somehow this query base.where(Sequel.|(
Sequel[:pact_publications][:consumer_id] => pacticipant_ids,
Sequel[:pact_publications][:provider_id] => pacticipant_ids
)) return an SELECT `pact_publications`.`id` FROM `pact_publications`
WHERE ((`pact_publications`.`consumer_id` IN (1, 3)) AND (`pact_publications`.`provider_id` IN (1, 3))) I was expecting
|
Found the issue base.where(Sequel.|(
{ Sequel[:pact_publications][:consumer_id] => pacticipant_ids },
{ Sequel[:pact_publications][:provider_id] => pacticipant_ids }
)) |
Fixed in c45f3e4 |
🎉 Awesome! The search results are showing the expected results now. Next steps:
|
Done I'll work on other items and will keep you posted :) |
Done Used jQuery to redirect to the correct page in this case. I feel a bit hacky tho. Please let me know if you have a better idea |
Hi @bethesque do you have any feedbacks on this? :D |
Almost there!
|
Latest view of the form and functionality :D test-with-show-and-show-with-tags.mp4 |
Fantastic! Love it. Thank you so much. |
This is the look and feel