Hi,

I'm using SQLAlchemy 0.6.6 for a web application.  At this point, the
app uses SQLite3 as the underlying database; I'm currently working on
abstracting this out to work with others (PostgreSQL, MySQL).

At a high level, the application receives CGI queries which are parsed
and sent to SQLAlchemy to query and filter.  Much of the filtering is
done against XML data (say dataset.xml) stored in a column (type text)
in SQLite.

We use SQLite's create_function approach to pass the XML filter
queries (basically lxml.etree xpath function wrapper) via (snippet):

        self.session = create_session(engine)
        self.connection = engine.raw_connection()
        self.connection.create_function('query_xpath', 2,
util.query_xpath)

Sample use case: a user provides a given XPath in their query which is
passed to query_xpath(dataset.xml, '/some/xpath') and returns either
None or the value of the XPath as a string, which would end up being
the following in SQL:

"select * from records where query_xpath(xml, '/some/xpath') = 'foo'";

This has served us very well so far.

Quite simply, we're looking for a similar way to 'register' Python
functions so that they can be used in the same manner as above, with
any database.

http://www.sqlalchemy.org/docs/core/expression_api.html?highlight=func#sqlalchemy.sql.expression.func
seems to suggest that custom Python functions can be called in the way
that we are looking for (i.e. dot separated packages).  Testing this
out like:

def foo()
    return 'bar'

...

query = session.query(dataset.xml).filter(func.foo()=='bar')

sqlalchemy.exc.ProgrammingError: (ProgrammingError) function foo()
does not exist
LINE 3: WHERE foo() = E'bar'
              ^
HINT:  No function matches the given name and argument types. You
might need to add explicit type casts.
 'SELECT records.xml AS records_xml \nFROM records \nWHERE foo() = %
(foo_1)s' {'foo_1': 'bar'}

Does this approach only apply to db queries which are set in the
backend db?

Alternatively, I'm wondering whether 
http://www.sqlalchemy.org/docs/core/compiler.html#greatest-function
serves as a better example to what I want to do.  Testing this out
like:

class query_xpath(expression.FunctionElement):
    type = String()
    name = 'query_xpath'

@compiles(query_xpath)
def default_query_xpath(element, compiler, **kw):
    return compiler.visit_function(element)

@compiles(query_xpath, 'sqlite')
@compiles(query_xpath, 'mysql')
@compiles(query_xpath, 'postgresql')
def case_query_xpath(element, compiler, **kw):
    arg1, arg2 = list(element.clauses)

    from server import util
    return util.query_xpath(compiler.process(arg1),
compiler.process(arg2))

...

query = session.query(query_xpath(dataset.xml, xpath_string))

print query


...which gives me an lxml.etree error saying the XML is not well-
formed.  Tracing through this, it looks like the column name is passed
to the function verbatim, instead of being evaluated to the column
value (I though compiler.process() would do this?)

I hope I have explained this well enough for some suggestions and / or
workarounds.

Thanks

..Tom

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