@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 sqlalchemy@googlegroups.com To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---