def _test_migrations( self, table_snapshots: t.List[t.List[t.Type[Table]]], test_function: t.Optional[t.Callable[[RowMeta], None]] = None, ): """ Writes a migration file to disk and runs it. :param table_snapshots: A list of lists. Each sub list represents a snapshot of the table state. Migrations will be created and run based each snapshot. :param test_function: After the migrations are run, this function is called. It is passed a ``RowMeta`` instance which can be used to check the column was created correctly in the database. It should return ``True`` if the test passes, otherwise ``False``. """ temp_directory_path = tempfile.gettempdir() migrations_folder_path = os.path.join(temp_directory_path, "piccolo_migrations") if os.path.exists(migrations_folder_path): shutil.rmtree(migrations_folder_path) _create_migrations_folder(migrations_folder_path) app_config = AppConfig( app_name="test_app", migrations_folder_path=migrations_folder_path, table_classes=[], ) for table_snapshot in table_snapshots: app_config.table_classes = table_snapshot meta = run_sync( _create_new_migration(app_config=app_config, auto=True, auto_input="y")) self.assertTrue(os.path.exists(meta.migration_path)) self.run_migrations(app_config=app_config) # It's kind of absurd sleeping for 1 microsecond, but it guarantees # the migration IDs will be unique, and just in case computers # and / or Python get insanely fast in the future :) time.sleep(1e-6) if test_function: column_name = (table_snapshots[-1][-1]._meta. non_default_columns[0]._meta.db_column_name) row_meta = self.get_postgres_column_definition( tablename="my_table", column_name=column_name, ) self.assertTrue( test_function(row_meta), msg=f"Meta is incorrect: {row_meta}", )
def test_drop_table( self, get_app_config: MagicMock, get_migration_managers: MagicMock ): self.run_sync("DROP TABLE IF EXISTS musician;") name_column = Varchar() name_column._meta.name = "name" manager_1 = MigrationManager(migration_id="1", app_name="music") manager_1.add_table( class_name="Musician", tablename="musician", columns=[name_column] ) asyncio.run(manager_1.run()) manager_2 = MigrationManager(migration_id="2", app_name="music") manager_2.drop_table(class_name="Musician", tablename="musician") asyncio.run(manager_2.run()) self.assertTrue(not self.table_exists("musician")) # Reverse set_mock_return_value(get_migration_managers, [manager_1]) app_config = AppConfig(app_name="music", migrations_folder_path="") get_app_config.return_value = app_config asyncio.run(manager_2.run_backwards()) get_migration_managers.assert_called_with( app_config=app_config, max_migration_id="2", offset=-1 ) self.assertTrue(self.table_exists("musician")) self.run_sync("DROP TABLE IF EXISTS musician;")
def test_add_table(self, get_app_config: MagicMock): """ Test adding a table to a MigrationManager. """ self.run_sync("DROP TABLE IF EXISTS musician;") manager = MigrationManager() manager.add_table(class_name="Musician", tablename="musician") manager.add_column( table_class_name="Musician", tablename="musician", column_name="name", column_class_name="Varchar", ) asyncio.run(manager.run()) self.run_sync("INSERT INTO musician VALUES (default, 'Bob Jones');") response = self.run_sync("SELECT * FROM musician;") self.assertEqual(response, [{"id": 1, "name": "Bob Jones"}]) # Reverse get_app_config.return_value = AppConfig( app_name="music", migrations_folder_path="" ) asyncio.run(manager.run_backwards()) self.assertEqual(self.table_exists("musician"), False) self.run_sync("DROP TABLE IF EXISTS musician;")
def test_get_table_with_name(self): """ Register a table, then test retrieving it. """ config = AppConfig(app_name="Music", migrations_folder_path="") config.register_table(table_class=Manager) self.assertEqual(config.get_table_with_name("Manager"), Manager) with self.assertRaises(ValueError): config.get_table_with_name("Foo")
def test_get_migration_modules(self, get_app_config): get_app_config.return_value = AppConfig( app_name="music", migrations_folder_path=os.path.join(os.path.dirname(__file__), "test_migrations"), ) migration_managers = run_sync( BaseMigrationManager().get_migration_managers(app_name="music")) self.assertTrue(len(migration_managers) == 1) self.assertTrue( migration_managers[0].migration_id == "2020-03-31T20:38:22")
def test_get_table_from_snaphot(self, get_app_config): """ Test the get_table_from_snaphot method. """ get_app_config.return_value = AppConfig( app_name="music", migrations_folder_path=os.path.join(os.path.dirname(__file__), "test_migrations"), ) table = run_sync(BaseMigrationManager().get_table_from_snaphot( app_name="music", table_class_name="Band")) self.assertTrue(table.class_name == "Band")
def test_drop_column( self, get_app_config: MagicMock, get_migration_managers: MagicMock ): """ Test dropping a column with MigrationManager. """ manager_1 = MigrationManager() manager_1.add_table(class_name="Musician", tablename="musician") manager_1.add_column( table_class_name="Musician", tablename="musician", column_name="name", column_class_name="Varchar", ) asyncio.run(manager_1.run()) self.run_sync("INSERT INTO musician VALUES (default, 'Dave');") response = self.run_sync("SELECT * FROM musician;") self.assertEqual(response, [{"id": 1, "name": "Dave"}]) manager_2 = MigrationManager() manager_2.drop_column( table_class_name="Musician", tablename="musician", column_name="name", ) asyncio.run(manager_2.run()) response = self.run_sync("SELECT * FROM musician;") self.assertEqual(response, [{"id": 1}]) # Reverse set_mock_return_value(get_migration_managers, [manager_1]) app_config = AppConfig(app_name="music", migrations_folder_path="") get_app_config.return_value = app_config asyncio.run(manager_2.run_backwards()) response = self.run_sync("SELECT * FROM musician;") self.assertEqual(response, [{"id": 1, "name": ""}])
def test_create_new_migration(self): """ Create a manual migration (i.e. non-auto). """ migration_folder = "/tmp/piccolo_migrations/" if os.path.exists(migration_folder): shutil.rmtree(migration_folder) os.mkdir(migration_folder) app_config = AppConfig( app_name="music", migrations_folder_path=migration_folder, table_classes=[Manager], ) run_sync(_create_new_migration(app_config, auto=False)) migration_modules = BaseMigrationManager().get_migration_modules( migration_folder) self.assertTrue(len(migration_modules.keys()) == 1)
from piccolo.conf.apps import AppConfig from .commands.run import run APP_CONFIG = AppConfig(app_name="sql_shell", migrations_folder_path="", commands=[run])
from piccolo.conf.apps import AppConfig from .commands.dump import dump from .commands.load import load APP_CONFIG = AppConfig( app_name="fixtures", migrations_folder_path="", table_classes=[], migration_dependencies=[], commands=[dump, load], )
""" Import all of the Tables subclasses in your app here, and register them with the APP_CONFIG. """ import os from piccolo.conf.apps import AppConfig from .tables import User CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="accounts", migrations_folder_path=os.path.join( CURRENT_DIRECTORY, "piccolo_migrations" ), table_classes=[User], migration_dependencies=[], commands=[], )
import os from piccolo.conf.apps import AppConfig from .commands import clean from .tables import SessionsBase CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="session_auth", migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), table_classes=[SessionsBase], migration_dependencies=[], commands=[clean], )
import os from piccolo.conf.apps import AppConfig from .tables import Manager, Band, Venue, Concert, Ticket, Poster CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="example_app", table_classes=[Manager, Band, Venue, Concert, Ticket, Poster], migrations_folder_path=os.path.join( CURRENT_DIRECTORY, "piccolo_migrations" ), commands=[], )
from piccolo.conf.apps import AppConfig from .commands.new import new APP_CONFIG = AppConfig(app_name="asgi", migrations_folder_path="", commands=[new])
from piccolo.conf.apps import AppConfig, Command from .commands.new import new APP_CONFIG = AppConfig( app_name="asgi", migrations_folder_path="", commands=[Command(callable=new, aliases=["create"])], )
""" Import all of the Tables subclasses in your app here, and register them with the APP_CONFIG. """ import os from piccolo.conf.apps import AppConfig from forum.tables import Category, Reply, Topic CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="forum", migrations_folder_path=os.path.join( CURRENT_DIRECTORY, "piccolo_migrations" ), table_classes=[Category, Topic, Reply], migration_dependencies=[], commands=[], )
""" Import all of the Tables subclasses in your app here, and register them with the APP_CONFIG. """ import os from piccolo.conf.apps import AppConfig CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="piccolo_admin", migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), table_classes=[], migration_dependencies=[ "piccolo_api.session_auth.piccolo_app", "piccolo.apps.user.piccolo_app", ], commands=[], )
from piccolo.conf.apps import AppConfig from .commands.version import version APP_CONFIG = AppConfig( app_name="meta", migrations_folder_path="", commands=[version] )
""" Import all of the Tables subclasses in your app here, and register them with the APP_CONFIG. """ import os from piccolo.conf.apps import AppConfig from ads.tables import Ad, Image, Notification, Rent, Review CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="ads", migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), table_classes=[Ad, Review, Image, Rent, Notification], migration_dependencies=[], commands=[], )
from .tables import ( Band, Concert, Manager, Poster, RecordingStudio, Shirt, Ticket, Venue, ) CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="music", table_classes=[ Manager, Band, Venue, Concert, Ticket, Poster, Shirt, RecordingStudio, ], migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), commands=[], )
from piccolo.conf.apps import AppConfig, Command from .commands.run import run APP_CONFIG = AppConfig( app_name="shell", migrations_folder_path="", commands=[Command(callable=run, aliases=["start"])], )
import os from piccolo.conf.apps import AppConfig, Command from .commands.change_password import change_password from .commands.change_permissions import change_permissions from .commands.create import create from .tables import BaseUser CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="user", migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), table_classes=[BaseUser], migration_dependencies=[], commands=[ Command(callable=create, aliases=["new"]), Command(callable=change_password, aliases=["password", "pass"]), Command(callable=change_permissions, aliases=["perm", "perms"]), ], )
from piccolo.conf.apps import AppConfig from .commands.backwards import backwards from .commands.check import check from .commands.clean import clean from .commands.forwards import forwards from .commands.new import new APP_CONFIG = AppConfig( app_name="migrations", migrations_folder_path="", commands=[backwards, check, clean, forwards, new], )
from piccolo.conf.apps import AppConfig from .commands.new import new from .commands.show_all import show_all APP_CONFIG = AppConfig( app_name="app", migrations_folder_path="", commands=[new, show_all] )
from piccolo.conf.apps import AppConfig, Command from .commands.new import new from .commands.show_all import show_all APP_CONFIG = AppConfig( app_name="app", migrations_folder_path="", commands=[ Command(callable=new, aliases=["create"]), Command(callable=show_all, aliases=["show", "all", "list"]), ], )
from piccolo.conf.apps import AppConfig, Command from .commands.backwards import backwards from .commands.check import check from .commands.clean import clean from .commands.forwards import forwards from .commands.new import new APP_CONFIG = AppConfig( app_name="migrations", migrations_folder_path="", commands=[ Command(callable=backwards, aliases=["b", "back", "backward"]), Command(callable=check), Command(callable=clean), Command(callable=forwards, aliases=["f", "forward"]), Command(callable=new, aliases=["n", "create"]), ], )
import os from piccolo.conf.apps import AppConfig from .tables import TokenAuth CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="token_auth", migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), table_classes=[TokenAuth], migration_dependencies=["piccolo.apps.user.piccolo_app"], )
import os from piccolo.conf.apps import AppConfig from .tables import MegaTable, SmallTable CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="mega", table_classes=[MegaTable, SmallTable], migrations_folder_path=os.path.join( CURRENT_DIRECTORY, "piccolo_migrations" ), commands=[], )
from piccolo.conf.apps import AppConfig from .commands.run import run APP_CONFIG = AppConfig(app_name="playground", migrations_folder_path="", commands=[run])
""" Import all of the Tables subclasses in your app here, and register them with the APP_CONFIG. """ import os from piccolo.conf.apps import AppConfig from .tables import Answer, Category, Question CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) APP_CONFIG = AppConfig( app_name="questions", migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), table_classes=[Category, Question, Answer], migration_dependencies=[], commands=[], )