Requested feature overview description.
Add order:artgroup and order:artgroup_asc as options for sorting art, so as to group art in search results by artist.
Why would it be useful?
If someone wants to search for art and wishes to order the results by artist tags, so that all art by each artist will be grouped together, this will be very helpful (admittedly, while writing this out, I'm realizing this is quite a bit more complicated a suggestion than I initially assumed it to be).
The idea is that search will determine how many artworks each artist that appears in search have that meet the initial search criterion, and sort the search results in a manner to keep each artist's works in a group.
If a post has multiple artist tags, it will be sorted into the artist group of whichever artist has a greater quantity of posts matching the search query.
In theory, it could be compatible with other sorting options in the Sorting Cheat Sheet, but will be the final sort, meaning that it will use the other sorts first, followed by the artist group sort
- Examples:
- If one searched "female order:artgroup" then all art for whichever artist has the greatest quantity of art tagged with female will appear first, followed by whichever artist has the second greatest quantity, and so on.
- If, instead, one searched for "female order:artgroup_asc" then it will sort by artists who have the least number of artworks (no less than 1 artwork) tagged with female first, followed by whichever artist has the second least quantity, and so on.
- If two or more artists have matching quantities of results for the search query, I can think of two resolutions as sorting tiebreakers
- artist groups with matching quantities would be sorted by name (simpler)
- artist group's ID numbers, are averaged, with newer being pushed to the front of the results (more complex, but sorts newer art closer to the front of results, more inline with the default method of search result order)
- If one searched for "female order:score order:artgroup" then it would sort each artist grouping by their score, rather than the default post ID numbers).
- Regarding posts with multiple artist tags, if one searched "female order:artgroup", then the post:
- post #2990060
- would be sorted into the tom fischbach group because that artist the greatest quantity of art with the female tag compared to all other artists on that post (tom fischbach: 4147, zakurujay: 19, rimarabernadette:11, kynum:8, tomtc:2, chaoskettle: 1).
When it comes to programming languages, if it isn't HTML or CSS, I am the epitome of the term n00b. I prompted a few AIs with this problem, asking for a potential solution that could, in theory, be appended to the source code without breaking the pre-existing source code.
Another thing I don't know is if this proposed feature would, if/when used, slow search for the user, or, worst case scenario, everyone, to a comparative crawl.
Regardless, here is a collapsed [section] containing the code that made the most sense to me out of what the different AIs I prompted suggested to me.
AI suggested code
class PostQueryBuilder # Existing instance variables and methods assumed: @tags, @order, etc. # Add this method to handle the new order:artgroup functionality def build_artist_group_query # Check if the order parameter includes 'artgroup' or 'artgroup_asc' return nil unless order&.include?('artgroup') # Determine sort direction: DESC for artgroup, ASC for artgroup_asc direction = order.include?('artgroup_asc') ? 'ASC' : 'DESC' # Extract additional sorting criteria (e.g., "score" from "order:score order:artgroup") additional_order = order.split(' ').reject { |o| o =~ /artgroup/ }.join(' ') additional_order_clause = build_standard_order_clause(additional_order) || 'posts.id DESC' # Step 1: Define base query for posts matching search criteria base_query = Post.joins(:tags).where(search_conditions) .where(tags: { category: Tag.categories.artist }) .select('posts.id, tags.name AS artist_name') # Step 2: Calculate post counts per artist artist_counts_subquery = Arel.sql( <<-SQL.squish SELECT artist_name, COUNT(*) AS post_count, AVG(posts.id) AS avg_post_id FROM (#{base_query.to_sql}) AS matching_posts GROUP BY artist_name SQL ) # Step 3: Determine primary artist for each post (artist with highest post count) # Uses a subquery to pick the top artist per post primary_artist_subquery = Arel.sql( <<-SQL.squish WITH artist_counts AS (#{artist_counts_subquery}) SELECT mp.id, (SELECT ac.artist_name FROM artist_counts ac WHERE ac.artist_name IN ( SELECT artist_name FROM (#{base_query.to_sql}) sub WHERE sub.id = mp.id ) ORDER BY ac.post_count DESC, ac.artist_name ASC LIMIT 1) AS primary_artist FROM (#{base_query.to_sql}) mp GROUP BY mp.id SQL ) # Step 4: Construct the final query # - Join posts with their primary artist and artist counts # - Order by artist post count, then additional criteria Post.joins( <<-SQL.squish INNER JOIN (#{primary_artist_subquery}) ppa ON posts.id = ppa.id INNER JOIN (#{artist_counts_subquery}) ac ON ppa.primary_artist = ac.artist_name SQL ) .select('posts.*', 'ac.post_count', 'ac.avg_post_id') .order(Arel.sql("ac.post_count #{direction}, #{additional_order_clause}")) end # Helper method to adapt existing order parsing for additional sorts def build_standard_order_clause(order_str) return nil if order_str.blank? # Map common order options to SQL (simplified; expand based on existing logic) case order_str when 'score' 'posts.score DESC' when 'date' 'posts.created_at DESC' else 'posts.id DESC' # Default fallback end end # Override or extend the existing build method to include artist grouping def build # If order:artgroup is specified, use the new query if order&.include?('artgroup') query = build_artist_group_query else # Existing build logic for standard queries query = Post.where(search_conditions) .order(build_standard_order_clause(order)) # ... (rest of existing build logic) end query end private # Placeholder for existing search conditions method # Assumes this constructs the WHERE clause based on @tags and other params def search_conditions # Simplified example; adapt to actual implementation TagQueryScanner.new(@tags).to_conditions end end
What part(s) of the site page(s) are affected?
Posts, search, e621:cheatsheet#Sorting
Updated