@click.command()
@click.argument('filepath')
@click.option('--limit', default=1000, help='Maximum number of entities.')
@click.option('--force', is_flag=True, help='Do not prompt for confirmation.')
@click.option('--no-auto-cleanup', is_flag=True, help='Do not remove created models.')
def main(filepath: str, limit: int=1000, force: bool=False, no_auto_cleanup: bool=False) -> None:
    auto_cleanup = (not no_auto_cleanup)
    session = db.session()
    print(f'Importing migration script: {filepath}')
    module = import_migration_script(Path(filepath))
    revision: str = getattr(module, 'revision', '')
    down_revision: str = getattr(module, 'down_revision', '')
    if ((not revision) or (not down_revision)):
        raise Exception("Not a valid migration script, couldn't find down_revision/revision")
    print(f'Migration goes from {down_revision} to {revision}')
    current_revision = db.engine.execute('SELECT version_num FROM alembic_version').scalar()
    print(f'Current version of the DB is {current_revision}')
    print('\nIdentifying models used in the migration:')
    models = find_models(module)
    model_rows: Dict[(Type[Model], int)] = {}
    for model in models:
        rows = session.query(model).count()
        print(f'- {model.__name__} ({rows} rows in table {model.__tablename__})')
        model_rows[model] = rows
    session.close()
    if (current_revision != down_revision):
        if (not force):
            click.confirm(f'''
Running benchmark will downgrade the Rabbitai DB to {down_revision} and upgrade to {revision} again. There may be data loss in downgrades. Continue?''', abort=True)
        downgrade(revision=down_revision)
    print('Benchmarking migration')
    results: Dict[(str, float)] = {}
    start = time.time()
    upgrade(revision=revision)
    duration = (time.time() - start)
    results['Current'] = duration
    print(f'Migration on current DB took: {duration:.2f} seconds')
    min_entities = 10
    new_models: Dict[(Type[Model], List[Model])] = defaultdict(list)
    while (min_entities <= limit):
        downgrade(revision=down_revision)
        print(f'Running with at least {min_entities} entities of each model')
        for model in models:
            missing = (min_entities - model_rows[model])
            if (missing > 0):
                print(f'- Adding {missing} entities to the {model.__name__} model')
                try:
                    added_models = add_sample_rows(session, model, missing)
                except Exception:
                    session.rollback()
                    raise
                model_rows[model] = min_entities
                session.commit()
                if auto_cleanup:
                    new_models[model].extend(added_models)
        start = time.time()
        upgrade(revision=revision)
        duration = (time.time() - start)
        print(f'Migration for {min_entities}+ entities took: {duration:.2f} seconds')
        results[f'{min_entities}+'] = duration
        min_entities *= 10
    if auto_cleanup:
        print('Cleaning up DB')
        for (model, entities) in list(new_models.items())[::(- 1)]:
            session.query(model).filter(model.id.in_((entity.id for entity in entities))).delete(synchronize_session=False)
        session.commit()
    if ((current_revision != revision) and (not force)):
        click.confirm(f'''
Revert DB to {revision}?''', abort=True)
        upgrade(revision=revision)
        print('Reverted')
    print('\nResults:\n')
    for (label, duration) in results.items():
        print(f'{label}: {duration:.2f} s')
@click.command()
@click.argument('filepath')
@click.option('--limit', default=1000, help='Maximum number of entities.')
@click.option('--force', is_flag=True, help='Do not prompt for confirmation.')
@click.option('--no-auto-cleanup', is_flag=True, help='Do not remove created models.')
def main(filepath: str, limit: int=1000, force: bool=False, no_auto_cleanup: bool=False) -> None:
    auto_cleanup = (not no_auto_cleanup)
    session = db.session()
    print(f'Importing migration script: {filepath}')
    module = import_migration_script(Path(filepath))
    revision: str = getattr(module, 'revision', )
    down_revision: str = getattr(module, 'down_revision', )
    if ((not revision) or (not down_revision)):
        raise Exception("Not a valid migration script, couldn't find down_revision/revision")
    print(f'Migration goes from {down_revision} to {revision}')
    current_revision = db.engine.execute('SELECT version_num FROM alembic_version').scalar()
    print(f'Current version of the DB is {current_revision}')
    print('\nIdentifying models used in the migration:')
    models = find_models(module)
    model_rows: Dict[(Type[Model], int)] = {}
    for model in models:
        rows = session.query(model).count()
        print(f'- {model.__name__} ({rows} rows in table {model.__tablename__})')
        model_rows[model] = rows
    session.close()
    if (current_revision != down_revision):
        if (not force):
            click.confirm(f'
Running benchmark will downgrade the Rabbitai DB to {down_revision} and upgrade to {revision} again. There may be data loss in downgrades. Continue?', abort=True)
        downgrade(revision=down_revision)
    print('Benchmarking migration')
    results: Dict[(str, float)] = {}
    start = time.time()
    upgrade(revision=revision)
    duration = (time.time() - start)
    results['Current'] = duration
    print(f'Migration on current DB took: {duration:.2f} seconds')
    min_entities = 10
    new_models: Dict[(Type[Model], List[Model])] = defaultdict(list)
    while (min_entities <= limit):
        downgrade(revision=down_revision)
        print(f'Running with at least {min_entities} entities of each model')
        for model in models:
            missing = (min_entities - model_rows[model])
            if (missing > 0):
                print(f'- Adding {missing} entities to the {model.__name__} model')
                try:
                    added_models = add_sample_rows(session, model, missing)
                except Exception:
                    session.rollback()
                    raise
                model_rows[model] = min_entities
                session.commit()
                if auto_cleanup:
                    new_models[model].extend(added_models)
        start = time.time()
        upgrade(revision=revision)
        duration = (time.time() - start)
        print(f'Migration for {min_entities}+ entities took: {duration:.2f} seconds')
        results[f'{min_entities}+'] = duration
        min_entities *= 10
    if auto_cleanup:
        print('Cleaning up DB')
        for (model, entities) in list(new_models.items())[::(- 1)]:
            session.query(model).filter(model.id.in_((entity.id for entity in entities))).delete(synchronize_session=False)
        session.commit()
    if ((current_revision != revision) and (not force)):
        click.confirm(f'
Revert DB to {revision}?', abort=True)
        upgrade(revision=revision)
        print('Reverted')
    print('\nResults:\n')
    for (label, duration) in results.items():
        print(f'{label}: {duration:.2f} s')