slugbucket / crossword-hints

Python Flask web application to aid decipherment of cryptic crossword clues for known setters
GNU General Public License v3.0
1 stars 0 forks source link

Add search box to solutions list - feat0014 #20

Closed slugbucket closed 4 years ago

slugbucket commented 5 years ago

Add a search form to the solutions list to bring up entries matching clue, solution or setter

slugbucket commented 5 years ago

Track as feature/feat0014

slugbucket commented 5 years ago

After completing feat0017 and merging in to develop, the latter branch has been merged into feat0014 to avoid likely conflicts with the main application file.

slugbucket commented 4 years ago

The initial implementation for simple search capabilties of solutions is very messy due to the need to paginate the results: we need to run queries to get all the matching rows and the range that will actually be dispalyed.

https://peewee.readthedocs.io/en/2.0.2/peewee/querying.html#SelectQuery.paginate, however, describes a SELECT pagination function that migth be possible to apply to the full result set to leave just thos for displaying.

slugbucket commented 4 years ago

The initial implementation for simple search capabilties of solutions is very messy due to the need to paginate the results: we need to run queries to get all the matching rows and the range that will actually be dispalyed.

https://peewee.readthedocs.io/en/2.0.2/peewee/querying.html#SelectQuery.paginate, however, describes a SELECT pagination function that migth be possible to apply to the full result set to leave just those for displaying.

slugbucket commented 4 years ago

Using the raw SQL doesn't allow the use of the pagination method (although that might just be down to how I have been using it) so we need to rework the query to use native PeeWee ORM methods. After plenty of experimentation we come up with the following approach which allows a single query to be used to retrieve a count of all the affected rows with pagination to pull out for display only thois that we need.

        term = "%"+fdata["search_box"]+"%"
        rs = crossword_setters.select(crossword_solutions.rowid.alias("csid"),
                                crossword_solutions.solution,
                                solution_types.name.alias("soltype"),
                                crossword_setters.name.alias("setter")) \
                               .join(crossword_solutions, JOIN.INNER, on=(crossword_setters.rowid == crossword_solutions.crossword_setter_id)) \
                               .join(solution_types, JOIN.INNER, on=(crossword_solutions.solution_type_id == solution_types.rowid)) \
                          .where(crossword_solutions.solution.contains(term) | \
                                 crossword_setters.name.contains(term) | \
                                 solution_types.name.contains(term)) \
                          .order_by(fn.Lower(crossword_solutions.solution)).dicts()
        count = len(rs)
...
    solutions = rs.paginate(page, PER_PAGE)

This performs a search for solutions, setters and types that contain the search term. The term is preserved across the links in the paginated list but not if an item is edited or if the user navigates to another page.

The whole approach here is a big improvementover what was already in place. There are still some overall code improvements possible but it's better than it was.

slugbucket commented 4 years ago

Updated forms, templates and stylesheets updated, merged into develop and pushed. A follow-on issue will look into improving the solutions query and how to remove theduplication of the same query in the code paths.