Optimize with_all_roles and has_all_roles queries #604
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
How it works
For example:
Before: 3 separate queries (one for each role)
After: 1 query like:
Then it checks if
count == 3(the number of roles requested). Both methods now use single SQL queries when possible, eliminating the N+1 query problem! 🎉The
has_any_role?method was already using a single query via self.class.adapter.where(self.roles, *args) which leverages the build_conditions method that creates OR conditions.For the
with_any_roleandwith_all_rolesmethods, replace the loopingparse_argsapproach with a single query that leverages the existingbuild_conditionsmethod in the adapter. Here's the optimized implementation:build_conditionsmethod which already knows how to build OR conditionsUser.with_any_role: Uses a single query with OR conditions andDISTINCTto get unique usersUser.with_all_roles: UsesGROUP BYandHAVING COUNTto ensure users have ALL the specified rolesAfter (optimized):