Thanks all for the prompt and thorough responses!

use Column subclass (class DontUseCol(Column)) then use @compiles to raise 
> any time this column is accessed in a SQL context 

We chose to follow this approach. It is a lightweight solution that works 
well for all of the outlined use cases, without an additional performance 
burden.

A few reasons why we don't want to remove the Column code from Python 
altogether:
- We'd like to run our whole test suite with the same database schema we'll 
have in production (including the "unused" column), in order to help catch 
errors such as removing a non-nullable column from Python
- This helps us better assert that our local database schemas and 
production schemas are in sync
- This makes it a little bit easier to test that migrations match the 
python schema

Thanks again!

Best,
Neena

On Thursday, August 17, 2017 at 5:59:53 AM UTC-7, Mike Bayer wrote:
>
> On Wed, Aug 16, 2017 at 7:35 PM, Neena Parikh <ne...@benchling.com 
> <javascript:>> wrote: 
> > Hi there! 
> > 
> > I'm looking to create a helper or decorator function that will enable us 
> to 
> > "mark" a column or table as “unused”, and raise an error if that column 
> or 
> > table is queried for in SQL. 
>
> There's a lot of ways to do this but they point towards what I would 
> think is the most obvious, remove the "Column('my_column')" code from 
> your Python application altogether.  This column can be present in the 
> database for real but not referred to in the Python application 
> itself. 
>
> The reason that comes up is because the next most direct way is just 
> to use an object that's not a Column here, just a descriptor that 
> raises an error: 
>
>
> class RaiseMe(object): 
>     def __get__(self, obj, type): 
>          raise TypeError("nope") 
>
>
> class MyClass(Base): 
>     # ... 
>
>     unused_col = RaiseMe() 
>
> This is not too dissimilar from what you're doing but you just create 
> a descriptor class to save on the typing. 
>
>
> Other ways include: 
>
> - use Column subclass (class DontUseCol(Column)) then use @compiles to 
> raise any time this column is accessed in a SQL context 
>
> - use @compiles on Column overall, check for an .info entry that the 
> col should not be used, raise is column is accessed in a SQL context 
> (this means the event is consulted for every column everywhere, tiny 
> ding in performance) 
>
> - use before_execute event, look in statement.columns for your column 
> (misses things like the WHERE clause), or use traversal to find the 
> column anywhere (a little more of a performance ding) 
>
> - many others, the mapping can exclude the column from being mapped 
> even though its present in the __table__, etc. 
>
>
>
>
>
> > 
> > 
> > Context 
> > The motivation behind this is to help us catch accidental references to 
> > deleted columns in our code. We currently follow this process for 
> database 
> > migrations that involve dropping columns or tables: 
> > 
> > Remove all usages of the column in the code, except the column 
> definition. 
> > (We keep the column definition around since we have tests to ensure our 
> > column definitions match up with our migrated database schemas.) 
> > Make the column deferred 
> > Wait a few days, then remove the column definition and run the database 
> > migration that actually drops the column 
> > 
> > The main issue with this process is that if there’s any code left in 
> that 
> > loads in the deleted column, we run into a number of issues upon running 
> the 
> > migration. We’d like to introduce a helper or decorator for dropped 
> > columns/tables that will trigger an error when the column/table is 
> > referenced / loaded in any of the following ways: 
> > 
> > session.query(MyTable.my_column).all() 
> > session.query(MyTable).options(undefer('*')).all() 
> > my_table_instance.my_column 
> > session.query(MyDroppedTable).all() 
> > 
> > Ideally, this would be a lightweight wrapper or decorator that could be 
> > applied to any column or table — something like my_column = 
> > unused(Column(…)) or an @unused decorator on a class. 
> > 
> > 
> > Prior Work 
> > We’ve looked at using hybrid_property to achieve this: 
> > 
> > 
> > class MyTable(): 
> >     ... 
> >     _my_column = deferred(Column('my_column', String(255), 
> nullable=True)) 
> > 
> >     @hybrid_property 
> >     def my_column(self): 
> >         raise Exception('Unused column') 
> > 
> >     @my_column.setter 
> >     def my_column(self, value): 
> >         raise Exception('Unused column') 
> > 
> > 
> > What this gets us: 
> > 
> > Exception on my_table_instance.my_column 
> > Exception on session.query(MyTable.my_column).all() 
> > Exception on session.query(MyTable).options(undefer('my_column')).all() 
> > 
> > Issues with this approach: 
> > 
> > No exception on session.query(MyTable).options(undefer('*')).all() 
> > Requires a fair amount of implementation overhead for each column 
> > Not applicable to unused tables 
> > 
> > 
> > 
> > Any tips on how we can best use SQLAlchemy to accomplish all of the 
> above? 
> > 
> > 
> > Thank you! 
> > Neena 
> > 
> > -- 
> > SQLAlchemy - 
> > The Python SQL Toolkit and Object Relational Mapper 
> > 
> > http://www.sqlalchemy.org/ 
> > 
> > To post example code, please provide an MCVE: Minimal, Complete, and 
> > Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> > description. 
> > --- 
> > You received this message because you are subscribed to the Google 
> Groups 
> > "sqlalchemy" group. 
> > To unsubscribe from this group and stop receiving emails from it, send 
> an 
> > email to sqlalchemy+...@googlegroups.com <javascript:>. 
> > To post to this group, send email to sqlal...@googlegroups.com 
> <javascript:>. 
> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> > For more options, visit https://groups.google.com/d/optout. 
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to