@Paul
I have been having a play with [py]parsing. What a nifty little
library!
I read those 2 free tutes and liked what I saw so bought a
subscription to safari just so I could read your short cut.
For my purposes (a few k objects at most, generally a few hundred) a
non indexed and inefficient like search will do fine until I work out
the match operator.
Here is what I have so far. Any tips welcome.
#################################### IMPORTS
###################################
# PyParsing
from pyparsing import ( CaselessLiteral, Literal, Word, alphas,
quotedString,
removeQuotes, operatorPrecedence,
ParseException,
stringEnd, opAssoc )
# SqlAlchemy
from sqlalchemy import and_, not_, or_
################################## LIKE ESCAPE
#################################
LIKE_ESCAPE = r'\\'
def like_escape(s):
return '%' + ( s.replace('\\', '\\\\')
.replace('%', '\\%')
.replace('_', '\\_') ) + '%'
############################### REUSABLE ACTIONS
###############################
class UnaryOperation(object):
def __init__(self, t):
self.op, self.a = t[0]
def __repr__(self):
return "%s:(%s)" % (self.name, str(self.a))
def express(self):
return self.operator[0](self.a.express())
class BinaryOperation(object):
def __init__(self, t):
self.op = t[0][1]
self.operands = t[0][0::2]
def __repr__(self):
return "%s:(%s)" % ( self.name,
",".join(str(oper) for oper in
self.operands) )
def express(self):
return self.operator[0](*( oper.express() for oper in
self.operands ))
class SearchAnd(BinaryOperation):
name = 'AND'
operator = [and_]
class SearchOr(BinaryOperation):
name = 'OR'
operator = [or_]
class SearchNot(UnaryOperation):
name = 'NOT'
operator = [not_]
############################### REUSABLE GRAMMARS
##############################
AND_ = CaselessLiteral("and") | Literal('+')
OR_ = CaselessLiteral("or") | Literal('|')
NOT_ = CaselessLiteral("not") | Literal('!')
searchTermMaster = (
Word(alphas) | quotedString.copy().setParseAction
( removeQuotes ) )
########################## THREAD SAFE PARSER FACTORY
##########################
def like_parser(model, fields=[]):
class SearchTerm(object):
def __init__(self, tokens):
self.term = tokens[0]
def express(self):
return or_ (
*( getattr(model, field).like( like_escape(self.term),
escape = LIKE_ESCAPE)
for field in fields )
)
def __repr__(self):
return self.term
searchTerm = searchTermMaster.copy().setParseAction(SearchTerm)
searchExpr = operatorPrecedence( searchTerm,
[ (NOT_, 1, opAssoc.RIGHT, SearchNot),
(AND_, 2, opAssoc.LEFT, SearchAnd),
(OR_, 2, opAssoc.LEFT, SearchOr) ] )
return searchExpr + stringEnd
########################### SEARCH FIELDS LIKE HELPER
##########################
def search_fields_like(s, model, fields):
if isinstance(fields, basestring): fields = [fields]
parser = like_parser(model, fields)
return parser.parseString(s)[0].express()
################################################################################
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---