postgresqlsqlalchemyturbogears

SQLAlchemy declarative: defining triggers and indexes (Postgres 9)


Is there a way in the SQLAlchemy class of a table to define/create triggers and indexes for that table?

For instance if i had a basic table like ...

class Customer(DeclarativeBase):
    __tablename__ = 'customers'
    customer_id = Column(Integer, primary_key=True,autoincrement=True)
    customer_code = Column(Unicode(15),unique=True)
    customer_name = Column(Unicode(100))
    search_vector = Column(tsvector) ## *Not sure how do this yet either in sqlalchemy*.

I now want to create a trigger to update "search_vector"

CREATE TRIGGER customers_search_vector_update BEFORE INSERT OR UPDATE
ON customers
FOR EACH ROW EXECUTE PROCEDURE
tsvector_update_trigger(search_vector,'pg_catalog.english',customer_code,customer_name);

Then I wanted to add that field also as an index ...

create index customers_search_vector_indx ON customers USING gin(search_vector);

Right now after i do any kind of database regeneration from my app i have to do the add column for the tsvector column, the trigger definition, and then the index statement from psql. Not the end of the world but its easy to forget a step. I am all about automation so if I can get this all to happen during the apps setup then bonus!


Solution

  • Indicies are straight-forward to create. For single-column with index=True parameter like below:

    customer_code = Column(Unicode(15),unique=True,index=True)
    

    But if you want more control over the name and options, use the explicit Index() construct:

    Index('customers_search_vector_indx', Customer.__table__.c.search_vector, postgresql_using='gin')
    

    Triggers can be created as well, but those need to still be SQL-based and hooked to the DDL events. See Customizing DDL for more info, but the code might look similar to this:

    from sqlalchemy import event, DDL
    trig_ddl = DDL("""
        CREATE TRIGGER customers_search_vector_update BEFORE INSERT OR UPDATE
        ON customers
        FOR EACH ROW EXECUTE PROCEDURE
        tsvector_update_trigger(search_vector,'pg_catalog.english',customer_code,customer_name);
    """)
    tbl = Customer.__table__
    event.listen(tbl, 'after_create', trig_ddl.execute_if(dialect='postgresql'))
    

    Sidenote: I do not know how to configure tsvector datatype: deserves a separate question.