@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
-~----------~----~----~----~------~----~------~--~---

Reply via email to