On Jan 15, 2011, at 10:53 PM, Hector Blanco wrote: > Hello list... > > I would like to allow the users to perform certain queries without me > (or well... my server) knowing in advance what those queries are going > to be (without hard-coding the query). > > For instance: I have a “Product” class. One of it's fields is > "manufacturer" and another is "model" > > class Product(declarativeBase): > def __init__(self): > self.model = "" > self.manufacturer = "" > > I would like the user be able to input an string with a query, such as > “Product.model != 'foo' or Product.model != 'bar'” > or: > "Product.model == 'foo' && Product.manufacturer == 'bar'" > > I have created a little Python module (queryTree) that tokenizes the > string and generates a tree for that kind of queries. For the last one > mentioned above, it would be something like: > > > sqlalchemy.and_ > / \ > == == > / \ / \ > Product.model "foo" Product.manufacturer "bar" > > 1) The “&&” string can be converted to (stored as) the sqlalchemy.and_ method > 2) The fields of Product are sqlalchemy.orm.synonym(s). If I pass my > tree module the class I'm going to perform the query for, it can call > getattr(cls, "model") and get the synonym (I mean: get the > Product.model synonym itself instead of the “model” string) > 3) Equally, the comparators are get with getattr(Product, "__eq__") or > getattr(Product, "__ne__") so I can store in the tree node the > comparator function instead of the string “==” or “!=” > > But when I try to run the query: > from mylibs.product import Product > queryString = "Product.model == 'foo' && Product.manufacturer == 'bar'" > session.query(Product.Product).filter(queryTree.getQuery(queryString, > Product.Product)) > > I get an exception: > File "/home/hbr/Documents/my-cms/backlib/product/ProductManager.py", > line 62, in getByCustomFilter > retval = > Database.session.query(Product.Product).filter(queryTokenizer.getQuery()).all() > File "<string>", line 1, in <lambda> > File > "/home/hbr/.buildout/eggs/SQLAlchemy-0.6.5-py2.6.egg/sqlalchemy/orm/query.py", > line 52, in generate > fn(self, *args[1:], **kw) > File > "/home/hbr/.buildout/eggs/SQLAlchemy-0.6.5-py2.6.egg/sqlalchemy/orm/query.py", > line 942, in filter > "filter() argument must be of type " > ArgumentError: filter() argument must be of type > sqlalchemy.sql.ClauseElement or string
Well everything I can see is correct here, so you just have to ensure getQuery() is returning the root of your tree (which, if it's an "and_()", or a "x == y", is in fact an instance of ClauseElement). Don't do anything with eval() or strings, keep it as a tokenized structure on your end. SQLA's job is to make it into a string. > > With some other tests, I've got some other exceptions that made me > realize that I could possibly modify somehow the nodes of my tree > until getting "something" that is accepted by MySQL as a valid query, > but that's kind of cheating... I'd like to use pure SqlAlchemy if > possible (I trust SqlAlchemy more than my programming skills) :-D the system you've built to interpret user input into a SQL expression tree should have adequate constraints such that only valid expressions are built in the first place. -- 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.