Skip to content

Commit

Permalink
Merge pull request #1417 from washort/sqlalchemy
Browse files Browse the repository at this point in the history
Change: Replace Peewee with SQLAlchemy/Alembic
  • Loading branch information
arikfr authored Dec 11, 2016
2 parents dde55e7 + b3bfc3b commit 19960ee
Show file tree
Hide file tree
Showing 109 changed files with 2,585 additions and 1,958 deletions.
11 changes: 6 additions & 5 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ machine:
2.7.3
dependencies:
pre:
- pip install --upgrade setuptools
- pip install -r requirements_dev.txt
- pip install -r requirements.txt
- pip install pymongo==3.2.1
Expand All @@ -26,11 +27,11 @@ deployment:
- make pack
# Skipping uploads for now, until master is stable.
# - make upload
- echo "client/app" >> .dockerignore
- docker pull redash/redash:latest
- docker build -t redash/redash:$(./manage.py version | sed -e "s/\+/./") .
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker push redash/redash:$(./manage.py version | sed -e "s/\+/./")
#- echo "client/app" >> .dockerignore
#- docker pull redash/redash:latest
#- docker build -t redash/redash:$(./manage.py version | sed -e "s/\+/./") .
#- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
#- docker push redash/redash:$(./manage.py version | sed -e "s/\+/./")
notify:
webhooks:
- url: https://webhooks.gitter.im/e/895d09c3165a0913ac2f
Expand Down
69 changes: 1 addition & 68 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,8 @@
"""
CLI to manage redash.
"""
import json


import click
from flask.cli import FlaskGroup, run_command

from redash import create_app, settings, __version__
from redash.cli import users, groups, database, data_sources, organization
from redash.monitor import get_status


def create(group):
app = create_app()
group.app = app
return app


@click.group(cls=FlaskGroup, create_app=create)
def manager():
"Management script for redash"


manager.add_command(database.manager, "database")
manager.add_command(users.manager, "users")
manager.add_command(groups.manager, "groups")
manager.add_command(data_sources.manager, "ds")
manager.add_command(organization.manager, "org")
manager.add_command(run_command, "runserver")


@manager.command()
def version():
"""Displays re:dash version."""
print __version__


@manager.command()
def status():
print json.dumps(get_status(), indent=2)


@manager.command()
def runworkers():
"""Start workers (deprecated)."""
print "** This command is deprecated. Please use Celery's CLI to control the workers. **"


@manager.command()
def check_settings():
"""Show the settings as re:dash sees them (useful for debugging)."""
for name, item in settings.all_settings().iteritems():
print "{} = {}".format(name, item)


@manager.command()
@click.argument('email', default=settings.MAIL_DEFAULT_SENDER, required=False)
def send_test_mail(email=None):
"""
Send test message to EMAIL (default: the address you defined in MAIL_DEFAULT_SENDER)
"""
from redash import mail
from flask_mail import Message

if email is None:
email = settings.MAIL_DEFAULT_SENDER

mail.send(Message(subject="Test Message from re:dash", recipients=[email],
body="Test message."))

from redash.cli import manager

if __name__ == '__main__':
manager()
9 changes: 9 additions & 0 deletions migrations/0001_warning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This is here just to print a warning for users who use the old Fabric upgrade script.

if __name__ == '__main__':
warning = "You're using an outdated upgrade script that is running migrations the wrong way. Please upgrade to " \
"newer version of the script before continuning the upgrade process."
print "*" * 20
print warning
print "*" * 20
exit(1)
1 change: 1 addition & 0 deletions migrations/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration.
44 changes: 44 additions & 0 deletions migrations/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# A generic, single database configuration.

[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = [%(asctime)s][PID:%(process)d][%(levelname)s][%(name)s] %(message)s
87 changes: 87 additions & 0 deletions migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
import logging

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""

# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.readthedocs.org/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')

engine = engine_from_config(config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)

connection = engine.connect()
context.configure(connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args)

try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()

if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
24 changes: 24 additions & 0 deletions migrations/script.py.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Add is_draft status to queries and dashboards
Revision ID: 65fc9ede4746
Revises:
Create Date: 2016-12-07 18:08:13.395586
"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
from sqlalchemy.exc import ProgrammingError

revision = '65fc9ede4746'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
try:
op.add_column('queries', sa.Column('is_draft', sa.Boolean, default=True, index=True))
op.add_column('dashboards', sa.Column('is_draft', sa.Boolean, default=True, index=True))
op.execute("UPDATE queries SET is_draft = (name = 'New Query')")
op.execute("UPDATE dashboards SET is_draft = false")
except ProgrammingError as e:
# The columns might exist if you ran the old migrations.
if 'column "is_draft" of relation "queries" already exists' in e.message:
print "Can't run this migration as you already have is_draft columns, please run:"
print "./manage.py db stamp {} # you might need to alter the command to match your environment.".format(revision)
exit()


def downgrade():
op.drop_column('queries', 'is_draft')
op.drop_column('dashboards', 'is_draft')
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 5 additions & 3 deletions redash/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from flask_mail import Mail
from flask_limiter import Limiter
from flask_limiter.util import get_ipaddr
from flask_migrate import Migrate

from redash import settings
from redash.query_runner import import_query_runners
Expand Down Expand Up @@ -52,6 +53,7 @@ def create_redis_connection():
setup_logging()
redis_connection = create_redis_connection()
mail = Mail()
migrate = Migrate()
mail.init_mail(settings.all_settings())
statsd_client = StatsClient(host=settings.STATSD_HOST, port=settings.STATSD_PORT, prefix=settings.STATSD_PREFIX)
limiter = Limiter(key_func=get_ipaddr, storage_uri=settings.REDIS_URL)
Expand Down Expand Up @@ -105,13 +107,13 @@ def create_app():
logging.getLogger().addHandler(sentry_handler)

# configure our database
settings.DATABASE_CONFIG.update({'threadlocals': True})
app.config['DATABASE'] = settings.DATABASE_CONFIG
app.config['SQLALCHEMY_DATABASE_URI'] = settings.SQLALCHEMY_DATABASE_URI
app.config.update(settings.all_settings())

provision_app(app)
init_admin(app)
db.init_app(app)
migrate.init_app(app, db)
init_admin(app)
mail.init_app(app)
setup_authentication(app)
handlers.init_app(app)
Expand Down
Loading

0 comments on commit 19960ee

Please sign in to comment.