Skip to content

Commit bac2160

Browse files
Advanced query search syntax for multi byte search (#7546)
* Advanced query search syntax for multi byte search * Advanced search for my queries * Add advanced query seearch tooltip * Revert "Add advanced query seearch tooltip" This reverts commit 43148ba.
1 parent c5aa5da commit bac2160

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

redash/models/__init__.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import datetime
33
import logging
44
import numbers
5+
import re
56
import time
67

78
import pytz
@@ -644,6 +645,43 @@ def outdated_queries(cls):
644645

645646
return list(outdated_queries.values())
646647

648+
@classmethod
649+
def _do_multi_byte_search(cls, all_queries, term, limit=None):
650+
# term examples:
651+
# - word
652+
# - name:word
653+
# - query:word
654+
# - "multiple words"
655+
# - name:"multiple words"
656+
# - word1 word2 word3
657+
# - word1 "multiple word" query:"select foo"
658+
tokens = re.findall(r'(?:([^:\s]+):)?(?:"([^"]+)"|(\S+))', term)
659+
conditions = []
660+
for token in tokens:
661+
key = None
662+
if token[0]:
663+
key = token[0]
664+
665+
if token[1]:
666+
value = token[1]
667+
else:
668+
value = token[2]
669+
670+
pattern = f"%{value}%"
671+
672+
if key == "id" and value.isdigit():
673+
conditions.append(cls.id.equal(int(value)))
674+
elif key == "name":
675+
conditions.append(cls.name.ilike(pattern))
676+
elif key == "query":
677+
conditions.append(cls.query_text.ilike(pattern))
678+
elif key == "description":
679+
conditions.append(cls.description.ilike(pattern))
680+
else:
681+
conditions.append(or_(cls.name.ilike(pattern), cls.description.ilike(pattern)))
682+
683+
return all_queries.filter(and_(*conditions)).order_by(Query.id).limit(limit)
684+
647685
@classmethod
648686
def search(
649687
cls,
@@ -664,12 +702,7 @@ def search(
664702

665703
if multi_byte_search:
666704
# Since tsvector doesn't work well with CJK languages, use `ilike` too
667-
pattern = "%{}%".format(term)
668-
return (
669-
all_queries.filter(or_(cls.name.ilike(pattern), cls.description.ilike(pattern)))
670-
.order_by(Query.id)
671-
.limit(limit)
672-
)
705+
return cls._do_multi_byte_search(all_queries, term, limit)
673706

674707
# sort the result using the weight as defined in the search vector column
675708
return all_queries.search(term, sort=True).limit(limit)
@@ -678,13 +711,7 @@ def search(
678711
def search_by_user(cls, term, user, limit=None, multi_byte_search=False):
679712
if multi_byte_search:
680713
# Since tsvector doesn't work well with CJK languages, use `ilike` too
681-
pattern = "%{}%".format(term)
682-
return (
683-
cls.by_user(user)
684-
.filter(or_(cls.name.ilike(pattern), cls.description.ilike(pattern)))
685-
.order_by(Query.id)
686-
.limit(limit)
687-
)
714+
return cls._do_multi_byte_search(cls.by_user(user), term, limit)
688715

689716
return cls.by_user(user).search(term, sort=True).limit(limit)
690717

0 commit comments

Comments
 (0)