def get_database_definition( self: T, sess: Session, dependencies: Optional[List["ReplaceableEntity"]] = None ) -> T: # $Optional[T]: """Creates the entity in the database, retrieves its 'rendered' then rolls it back""" with simulate_entity(sess, self, dependencies) as sess: # Drop self sess.execute(self.to_sql_statement_drop()) # collect all remaining entities db_entities: List[T] = sorted( self.from_database(sess, schema=self.schema), key=lambda x: x.identity ) with simulate_entity(sess, self, dependencies) as sess: # collect all remaining entities all_w_self: List[T] = sorted( self.from_database(sess, schema=self.schema), key=lambda x: x.identity ) # Find "self" by diffing the before and after for without_self, with_self in zip_longest(db_entities, all_w_self): if without_self is None or without_self.identity != with_self.identity: return with_self raise UnreachableException()
def solve_resolution_order(sess: Session, entities): """Solve for an entity resolution order that increases the probability that a migration will suceed if, for example, two new views are created and one refers to the other This strategy will only solve for simple cases """ resolved = [] # Resolve the entities with 0 dependencies first (faster) logger.info("Resolving entities with no dependencies") for entity in entities: try: with simulate_entity(sess, entity): resolved.append(entity) except (sqla_exc.ProgrammingError, sqla_exc.InternalError) as exc: continue # Resolve entities with possible dependencies for _ in range(len(entities)): logger.info( "Resolving entities with dependencies. This may take a minute") n_resolved = len(resolved) for entity in entities: if entity in resolved: continue try: with simulate_entity(sess, entity, dependencies=resolved): resolved.append(entity) except (sqla_exc.ProgrammingError, sqla_exc.InternalError): continue if len(resolved) == n_resolved: # No new entities resolved in the last iteration. Exit break for entity in entities: if entity not in resolved: resolved.append(entity) return resolved
def test_simulate_entity_shows_user_code_error(sess: Session) -> None: sess.execute(TEST_VIEW.to_sql_statement_create()) with pytest.raises(DataError): with simulate_entity(sess, TEST_VIEW): # Raises a sql error sess.execute("select 1/0").fetchone() # Confirm context manager exited gracefully assert True