0

I'm building a Flask service that uses SqlAlchemy Core for database operations, but I'm not using the ORM- just dispatching raw SQL to the PostgreSQL db. In order to track database migrations I'm using Alembic.

My migration looks roughly like this:

def upgrade():                                                                                                                                                                                                                           
      # Add the ossp extenson to enable use of UUIDs                                                                                                                                                                                       
      add_extension_command = 'create EXTENSION if not EXISTS "uuid-ossp";'                                                                                                                                                                
      bind = op.get_bind()                                                                                                                                                                                                                 
      session = Session(bind=bind)                                                                                                                                                                                                         
      session.execute(add_extension_command)                                                                                                                                                                                               

      # Create tables                                                                                                                                                                                                                      
      op.create_table(                                                                                                                                                                                                                     
          "account",                                                                                                                                                                                                                  
          Column(                                                                                                                                                                                                                          
              "id", UUID(as_uuid=True), primary_key=True, server_default=text("uuid_generate_v4()"),                                                                                                                                       
          ),                                                                                                                                                                                                                                                                                                                                                                                                    
          Column("created_at", DateTime, server_default=sql.func.now()),                                                                                                                                                                   
          Column("deleted_at", DateTime, default=None),                                                                                                                                                                                    
          Column("modified_at", DateTime, server_default=sql.func.now()),                                                                                                                                                                  
      )  

This works great in general- the main issue I'm having is with testing. After each test, I want to be able to drop and rebuild the DB to clean out the data. To do this, I'm using PyTest, and created the following App fixture:

@pytest.fixture                                                                
def app():                                                                   
      app = create_app("testing")                                                    
      with app.app_context():                                                  
          db.init_app(app)                                                               
          Migrate(app, db)                                                               
          upgrade()                                                             
          yield app                                                            
          db.drop_all()   

The general idea here was that each time we need the app context, we apply the database migrations, yield the app, then when the test is done we drop all the tables.

The issue is, db.drop_all() does nothing. I believe this is because the db object is not bound to any MetaData. The research I did lead here, which mentions that the create_table command does not create MetaData, which I assume is why the app is not aware of which tables are available to drop.

I'm a bit stuck here as to what the right path forward is. Should I change how I'm building these migrations? Is this not the right pattern to make sure I remove test data from the DB between tests?

Code_Pig
  • 31
  • 5
  • DO you mind showing what the downgrade() contains? With that I might be able to help you – iChux May 26 '20 at 15:52
  • Downgrade just has a series of `op.drop_table('table_name')` calls – Code_Pig May 26 '20 at 15:54
  • Well, the downgrade should hold the key to solving your problem, if I understand what you have written properly. Start by ensuring that within this upgrade that you remove the things you added e.g. 'create EXTENSION if not EXISTS "uuid-ossp";' before dropping the tables. Try that and see what happens – iChux May 26 '20 at 20:17

0 Answers0