Skip to content

Commit edf78f2

Browse files
committed
experimental natural language search in grid
1 parent b7b2f53 commit edf78f2

1 file changed

Lines changed: 42 additions & 30 deletions

File tree

py4web/utils/grid.py

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from urllib.parse import urlparse
1010

1111
from pydal.objects import Expression, Field, FieldVirtual
12+
from pydal.querybuilder import QueryBuilder
1213
from yatl.helpers import (
1314
CAT,
1415
DIV,
@@ -54,6 +55,11 @@ def query_join(a, b):
5455
return a + ("&" if "?" in a else "?") + b
5556

5657

58+
def make_default_search_query(table):
59+
builder = QueryBuilder()
60+
return ["Query", (lambda text, table=table: builder.parse(table, text)), None]
61+
62+
5763
class GridClassStyle:
5864
"""
5965
Default grid style
@@ -105,6 +111,7 @@ class GridClassStyle:
105111
"grid-search-form-td": "grid-search-form-td",
106112
"grid-search-form-input": "grid-search-form-input",
107113
"grid-search-form-select": "grid-search-form-select",
114+
"grid-search-form-error": "py4web-validation-error",
108115
"grid-search-boolean": "grid-search-boolean",
109116
"grid-header-element": "grid-header-element info",
110117
"grid-footer-element": "grid-footer-element info",
@@ -163,6 +170,7 @@ class GridClassStyleBulma(GridClassStyle):
163170
"grid-search-form-td": "grid-search-form-td pr-1",
164171
"grid-search-form-input": "grid-search-form-input input",
165172
"grid-search-form-select": "grid-search-form-input control select",
173+
"grid-search-form-error": "py4web-validation-error",
166174
"grid-search-boolean": "grid-search-boolean",
167175
"grid-header-element": "grid-header-element button",
168176
"grid-footer-element": "grid-footer-element button",
@@ -216,6 +224,7 @@ class GridClassStyleBootstrap5(GridClassStyle):
216224
"grid-search-form-td": "grid-search-form-td pr-1",
217225
"grid-search-form-input": "grid-search-form-input form-control",
218226
"grid-search-form-select": "grid-search-form-input control select",
227+
"grid-search-form-error": "py4web-validation-error",
219228
"grid-search-boolean": "grid-search-boolean",
220229
"grid-header-element": "grid-header-element btn btn-sm",
221230
"grid-footer-element": "grid-footer-element btn btn-sm",
@@ -311,6 +320,7 @@ class GridClassStyleTailwind(GridClassStyle):
311320
"grid-search-form-td": "p-2",
312321
"grid-search-form-input": "px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 w-full",
313322
"grid-search-form-select": "px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 w-full",
323+
"grid-search-form-error": "p-2",
314324
"grid-search-boolean": "form-checkbox h-5 w-5 text-blue-600",
315325
"grid-header-element": "px-3 py-1 bg-gray-500 text-white rounded hover:bg-gray-600",
316326
"grid-footer-element": "px-3 py-1 bg-gray-500 text-white rounded hover:bg-gray-600",
@@ -493,6 +503,7 @@ def __init__(
493503
self.query = query # the filter query
494504
self.query2 = None # the query with additional filters
495505
self.query_parms = safely(lambda: request.params, default={})
506+
self.search_query_error = None # error to be displayed in case failed search
496507
self.T = T # the translator
497508
self.form_maker = form_maker # the object that makes forms
498509
self.referrer = None # page referring this one
@@ -556,23 +567,7 @@ def get_style(self, element, default=None):
556567
def process(self):
557568
query = None
558569
db = self.db
559-
if not self.param.search_form and self.param.search_queries:
560-
search_type = safe_int(request.query.get("search_type", 0), default=0)
561-
search_string = request.query.get("search_string")
562-
if search_type < len(self.param.search_queries) and search_string:
563-
query_lambda = self.param.search_queries[search_type][1]
564-
try:
565-
query = query_lambda(search_string)
566-
print(query)
567-
except Exception as e:
568-
import traceback
569-
print(traceback.format_exc())
570-
pass # TODO: display the error
571-
572-
if not query:
573-
self.query2 = self.query
574-
else:
575-
self.query2 = self.query & query
570+
self.search_query_error = None
576571

577572
self.mode = request.query.get("mode", "select")
578573
self.record_id = request.query.get("id")
@@ -596,6 +591,30 @@ def process(self):
596591

597592
# SECURITY: if the record does not exist or does not match query, than we are not allowed
598593
self.table = db[self.tablename]
594+
595+
# use the default search for the table
596+
if self.param.search_queries is None:
597+
self.param.search_queries = [make_default_search_query(self.table)]
598+
599+
# apply the search query
600+
if not self.param.search_form and self.param.search_queries:
601+
search_type = safe_int(request.query.get("search_type", 0), default=0)
602+
search_string = request.query.get("search_string")
603+
if search_type < len(self.param.search_queries) and search_string:
604+
_, query_lambda, requires = self.param.search_queries[search_type]
605+
if requires:
606+
search_string, self.search_query_error = requires(search_string)
607+
if not self.search_query_error:
608+
try:
609+
query = query_lambda(search_string)
610+
except Exception as e:
611+
self.search_query_error = str(e)
612+
613+
if not query:
614+
self.query2 = self.query
615+
else:
616+
self.query2 = self.query & query
617+
599618
if self.record_id:
600619
self.record = self.table(self.record_id)
601620
if not self.record:
@@ -969,7 +988,12 @@ def _make_default_form(self):
969988
tr.append(TD(select, _class=td_classes))
970989
tr.append(TD(input, _class=td_classes))
971990
tr.append(TD(submit, clear, _class=td_classes))
972-
form.append(TABLE(tr, _class=self.get_style("grid-search-form-table")))
991+
table = TABLE(tr, _class=self.get_style("grid-search-form-table"))
992+
if self.search_query_error:
993+
table.append(TR(TD(self.search_query_error,
994+
_colspan=3 if len(options)>1 else 2,
995+
_class=self.get_style("grid-search-form-error"))))
996+
form.append(table)
973997
div.append(form)
974998
return div
975999

@@ -1387,18 +1411,6 @@ def data(self):
13871411
else None
13881412
)
13891413

1390-
def add_search_query(self, name, query, requires):
1391-
if self.param.search_form:
1392-
raise ValueError(
1393-
"Cannot add search queries if a you provide a search_form to the grid call "
1394-
"or if auto_process is set to True. Ensure no search_form is set, set "
1395-
"auto_process to False, add your search query and then call grid.process()."
1396-
)
1397-
1398-
if self.param.search_queries is None:
1399-
self.param.search_queries = []
1400-
self.param.search_queries.append([name, query, requires])
1401-
14021414
def _get_tablenames(self, *args):
14031415
"""Returns the tablenames used by this grid"""
14041416
return list(self.db._adapter.tables(*args).keys())

0 commit comments

Comments
 (0)