from peewee import NodeList, SQL, fn, TextField, Field def _escape_wildcard(search_query): """ Escapes the wildcards found in the given search query so that they are treated as *characters* rather than wildcards when passed to a LIKE or ILIKE clause with an ESCAPE '!'. """ search_query = ( search_query.replace("!", "!!").replace("%", "!%").replace("_", "!_").replace("[", "![") ) # Just to be absolutely sure. search_query = search_query.replace("'", "") search_query = search_query.replace('"', "") search_query = search_query.replace("`", "") return search_query def prefix_search(field, prefix_query): """ Returns the wildcard match for searching for the given prefix query. """ # Escape the known wildcard characters. prefix_query = _escape_wildcard(prefix_query) return Field.__pow__(field, NodeList((prefix_query + "%", SQL("ESCAPE '!'")))) def match_mysql(field, search_query): """ Generates a full-text match query using a Match operation, which is needed for MySQL. """ if field.name.find("`") >= 0: # Just to be safe. raise Exception("How did field name '%s' end up containing a backtick?" % field.name) # Note: There is a known bug in MySQL (https://bugs.mysql.com/bug.php?id=78485) that causes # queries of the form `*` to raise a parsing error. If found, simply filter out. search_query = search_query.replace("*", "") # Just to be absolutely sure. search_query = search_query.replace("'", "") search_query = search_query.replace('"', "") search_query = search_query.replace("`", "") return NodeList( (fn.MATCH(SQL("`%s`" % field.name)), fn.AGAINST(SQL("%s", [search_query]))), parens=True ) def match_like(field, search_query): """ Generates a full-text match query using an ILIKE operation, which is needed for SQLite and Postgres. """ escaped_query = _escape_wildcard(search_query) clause = NodeList(("%" + escaped_query + "%", SQL("ESCAPE '!'"))) return Field.__pow__(field, clause)