Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sqlalchemy 2.0 #6671

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/app/components/items-list/classes/ItemsFetcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class PaginatedListFetcher extends ItemsFetcher {
return this._originalGetRequest(
{
page: paginator.page,
page_size: paginator.itemsPerPage,
per_page: paginator.itemsPerPage,
order: sorter.compiled,
q: isString(searchTerm) && searchTerm !== "" ? searchTerm : undefined,
tags: selectedTags,
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/items-list/classes/ItemsSource.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type GetResourceRequest = any; // TODO: Add stricter type
export interface ItemsPage<INPUT = any> {
count: number;
page: number;
page_size: number;
per_page: number;
results: INPUT[];
}

Expand Down
4 changes: 2 additions & 2 deletions client/app/components/items-list/classes/StateStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class UrlStateStorage extends StateStorage {

return {
page: parseInt(params.page, 10) || defaultState.page,
itemsPerPage: parseInt(params.page_size, 10) || defaultState.itemsPerPage,
itemsPerPage: parseInt(params.per_page, 10) || defaultState.itemsPerPage,
orderByField,
orderByReverse,
searchTerm,
Expand All @@ -50,7 +50,7 @@ export class UrlStateStorage extends StateStorage {
location.setSearch(
{
page,
page_size: itemsPerPage,
per_page: itemsPerPage,
order: compileOrderBy(orderByField, orderByReverse),
q: searchTerm !== "" ? searchTerm : null,
},
Expand Down
343 changes: 149 additions & 194 deletions poetry.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ flask-login = "0.6.0"
flask-mail = "0.9.1"
flask-migrate = "2.5.2"
flask-restful = "0.3.10"
flask-sqlalchemy = "2.5.1"
flask-sqlalchemy = "3.1.1"
flask-talisman = "0.7.0"
flask-wtf = "1.1.1"
funcy = "1.13"
Expand Down Expand Up @@ -70,9 +70,9 @@ rq = "1.16.1"
rq-scheduler = "0.13.1"
semver = "2.8.1"
sentry-sdk = "1.28.1"
sqlalchemy = "1.3.24"
sqlalchemy-searchable = "1.2.0"
sqlalchemy-utils = "0.34.2"
sqlalchemy = "2.0.29"
sqlalchemy-searchable = "2.1.0"
sqlalchemy-utils = "0.41.2"
sqlparse = "0.5.0"
sshtunnel = "0.1.5"
statsd = "3.3.0"
Expand All @@ -97,8 +97,8 @@ botocore = "1.31.8"
cassandra-driver = "3.21.0"
certifi = ">=2019.9.11"
cmem-cmempy = "21.2.3"
databend-py = "0.4.6"
databend-sqlalchemy = "0.2.4"
databend-driver = "0.17.1"
databend-sqlalchemy = "0.4.6"
google-api-python-client = "1.7.11"
gspread = "5.11.2"
impyla = "0.16.0"
Expand Down
7 changes: 7 additions & 0 deletions redash/alerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from enum import Enum


class Alerts(str, Enum):
UNKNOWN_STATE = "unknown"
OK_STATE = "ok"
TRIGGERED_STATE = "triggered"
14 changes: 6 additions & 8 deletions redash/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,17 @@ def __init__(self, *args, **kwargs):


def create_app():
from redash import authentication, handlers, security, tasks
from redash.handlers.webpack import configure_webpack
from redash.metrics import request as request_metrics
from redash.models import db, users
from redash.utils import sentry

from . import (
authentication,
handlers,
limiter,
mail,
migrate,
security,
tasks,
)
from .handlers.webpack import configure_webpack
from .metrics import request as request_metrics
from .models import db, users
from .utils import sentry

sentry.init()
app = Redash()
Expand Down
5 changes: 3 additions & 2 deletions redash/authentication/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from flask import jsonify, redirect, request, session, url_for
from flask_login import LoginManager, login_user, logout_user, user_logged_in
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql import select
from werkzeug.exceptions import Unauthorized

from redash import models, settings
Expand Down Expand Up @@ -84,14 +85,14 @@ def hmac_load_user_from_request(request):
# TODO: 3600 should be a setting
if signature and time.time() < expires <= time.time() + 3600:
if user_id:
user = models.User.query.get(user_id)
user = models.db.session.get(models.User, user_id)
calculated_signature = sign(user.api_key, request.path, expires)

if user.api_key and signature == calculated_signature:
return user

if query_id:
query = models.Query.query.filter(models.Query.id == query_id).one()
query = models.db.session.scalars(select(models.Query).where(models.Query.id == query_id)).one()
calculated_signature = sign(query.api_key, request.path, expires)

if query.api_key and signature == calculated_signature:
Expand Down
21 changes: 11 additions & 10 deletions redash/cli/data_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from click.types import convert_type
from flask.cli import AppGroup
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql.expression import select

from redash import models
from redash.query_runner import (
Expand All @@ -27,13 +28,13 @@
"""List currently configured data sources."""
if organization:
org = models.Organization.get_by_slug(organization)
data_sources = models.DataSource.query.filter(models.DataSource.org == org)
data_sources = select(models.DataSource).where(models.DataSource.org == org)

Check warning on line 31 in redash/cli/data_sources.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/data_sources.py#L31

Added line #L31 was not covered by tests
else:
data_sources = models.DataSource.query
for i, ds in enumerate(data_sources.order_by(models.DataSource.name)):
data_sources = select(models.DataSource)
sources = models.db.session.scalars(data_sources.order_by(models.DataSource.name))
for i, ds in enumerate(sources):
if i > 0:
print("-" * 20)

print("Id: {}\nName: {}\nType: {}\nOptions: {}".format(ds.id, ds.name, ds.type, ds.options.to_json()))


Expand Down Expand Up @@ -69,8 +70,8 @@
"""Test connection to data source by issuing a trivial query."""
try:
org = models.Organization.get_by_slug(organization)
data_source = models.DataSource.query.filter(
models.DataSource.name == name, models.DataSource.org == org
data_source = models.db.session.scalars(
select(models.DataSource).where(models.DataSource.name == name, models.DataSource.org == org)
).one()
print("Testing connection to data source: {} (id={})".format(name, data_source.id))
try:
Expand Down Expand Up @@ -183,8 +184,8 @@
"""Delete data source by name."""
try:
org = models.Organization.get_by_slug(organization)
data_source = models.DataSource.query.filter(
models.DataSource.name == name, models.DataSource.org == org
data_source = models.db.session.scalars(
select(models.DataSource).where(models.DataSource.name == name, models.DataSource.org == org)
).one()
print("Deleting data source: {} (id={})".format(name, data_source.id))
models.db.session.delete(data_source)
Expand Down Expand Up @@ -218,8 +219,8 @@
if type is not None:
validate_data_source_type(type)
org = models.Organization.get_by_slug(organization)
data_source = models.DataSource.query.filter(
models.DataSource.name == name, models.DataSource.org == org
data_source = models.db.session.scalars(
select(models.DataSource).where(models.DataSource.name == name, models.DataSource.org == org)
).one()
update_attr(data_source, "name", new_name)
update_attr(data_source, "type", type)
Expand Down
6 changes: 3 additions & 3 deletions redash/cli/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from flask.cli import AppGroup
from flask_migrate import stamp
from sqlalchemy.exc import DatabaseError
from sqlalchemy.sql import select
from sqlalchemy.sql import select, text
from sqlalchemy_utils.types.encrypted.encrypted_type import FernetEngine

from redash import settings
Expand All @@ -22,7 +22,7 @@
retried = False
while not retried:
try:
db.engine.execute("SELECT 1;")
db.session.execute(text("SELECT 1;"))

Check warning on line 25 in redash/cli/database.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/database.py#L25

Added line #L25 was not covered by tests
return
except DatabaseError:
time.sleep(30)
Expand All @@ -33,7 +33,7 @@
def is_db_empty():
from redash.models import db

table_names = sqlalchemy.inspect(db.get_engine()).get_table_names()
table_names = sqlalchemy.inspect(db.engine).get_table_names()

Check warning on line 36 in redash/cli/database.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/database.py#L36

Added line #L36 was not covered by tests
return len(table_names) == 0


Expand Down
13 changes: 7 additions & 6 deletions redash/cli/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from click import argument, option
from flask.cli import AppGroup
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql.expression import select

from redash import models

Expand Down Expand Up @@ -58,7 +59,7 @@
print("Change permissions of group %s ..." % group_id)

try:
group = models.Group.query.get(group_id)
group = models.db.session.get(models.Group, group_id)
except NoResultFound:
print("Group [%s] not found." % group_id)
exit(1)
Expand Down Expand Up @@ -94,13 +95,13 @@
)
def list_command(organization=None):
"""List all groups"""
query_groups = select(models.Group)
if organization:
org = models.Organization.get_by_slug(organization)
groups = models.Group.query.filter(models.Group.org == org)
else:
groups = models.Group.query
query_groups = query_groups.where(models.Group.org == org)

Check warning on line 101 in redash/cli/groups.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/groups.py#L101

Added line #L101 was not covered by tests

for i, group in enumerate(groups.order_by(models.Group.name)):
groups = models.db.session.scalars(query_groups.order_by(models.Group.name)).all()
for i, group in enumerate(groups):
if i > 0:
print("-" * 20)

Expand All @@ -114,7 +115,7 @@
)
)

members = models.Group.members(group.id)
members = models.db.session.scalars(models.Group.members(group.id)).all()
user_names = [m.name for m in members]
if user_names:
print("Users: {}".format(", ".join(user_names)))
Expand Down
5 changes: 3 additions & 2 deletions redash/cli/organization.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from click import argument, option
from flask.cli import AppGroup
from sqlalchemy.sql.expression import select

from redash import models

Expand All @@ -12,7 +13,7 @@ def set_google_apps_domains(domains):
"""
Sets the allowable domains to the comma separated list DOMAINS.
"""
organization = models.Organization.query.first()
organization = models.db.session.scalar(select(models.Organization))
masayuki038 marked this conversation as resolved.
Show resolved Hide resolved
k = models.Organization.SETTING_GOOGLE_APPS_DOMAINS
organization.settings[k] = domains.split(",")
models.db.session.add(organization)
Expand All @@ -22,7 +23,7 @@ def set_google_apps_domains(domains):

@manager.command(name="show_google_apps_domains")
def show_google_apps_domains():
organization = models.Organization.query.first()
organization = models.db.session.scalar(select(models.Organization))
print("Current list of Google Apps domains: {}".format(", ".join(organization.google_apps_domains)))


Expand Down
29 changes: 16 additions & 13 deletions redash/cli/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from flask.cli import AppGroup
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql.expression import delete as sql_delete
from sqlalchemy.sql.expression import select

from redash import models
from redash.handlers.users import invite_user
Expand Down Expand Up @@ -145,13 +147,13 @@
print("Creating root user (%s, %s) in organization %s..." % (email, name, organization))
print("Login with Google Auth: %r\n" % google_auth)

user = models.User.query.filter(models.User.email == email).first()
user = models.db.session.scalar(select(models.User).where(models.User.email == email))

Check warning on line 150 in redash/cli/users.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/users.py#L150

Added line #L150 was not covered by tests
if user is not None:
print("User [%s] is already exists." % email)
exit(1)

org_slug = organization
org = models.Organization.query.filter(models.Organization.slug == org_slug).first()
org = models.db.session.scalar(select(models.Organization).where(models.Organization.slug == org_slug))

Check warning on line 156 in redash/cli/users.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/users.py#L156

Added line #L156 was not covered by tests
if org is None:
org = models.Organization(name=org_slug, slug=org_slug, settings={})

Expand Down Expand Up @@ -200,13 +202,13 @@
"""
Delete user EMAIL.
"""
deleted_users_query = sql_delete(models.User).where(models.User.email == email)
if organization:
org = models.Organization.get_by_slug(organization)
deleted_count = models.User.query.filter(models.User.email == email, models.User.org == org.id).delete()
else:
deleted_count = models.User.query.filter(models.User.email == email).delete(synchronize_session=False)
deleted_users_query = deleted_users_query.where(models.User.org == org)

Check warning on line 208 in redash/cli/users.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/users.py#L208

Added line #L208 was not covered by tests
result = models.db.session.execute(deleted_users_query.execution_options(synchronize_session=False))
models.db.session.commit()
print("Deleted %d users." % deleted_count)
print("Deleted %d users." % result.rowcount)


@manager.command()
Expand All @@ -224,9 +226,9 @@
"""
if organization:
org = models.Organization.get_by_slug(organization)
user = models.User.query.filter(models.User.email == email, models.User.org == org).first()
user = models.db.session.scalar(select(models.User).where(models.User.email == email, models.User.org == org))
else:
user = models.User.query.filter(models.User.email == email).first()
user = models.db.session.scalar(select(models.User).where(models.User.email == email))

if user is not None:
user.hash_password(password)
Expand Down Expand Up @@ -287,12 +289,13 @@
)
def list_command(organization=None):
"""List all users"""
query_users = select(models.User)
if organization:
org = models.Organization.get_by_slug(organization)
users = models.User.query.filter(models.User.org == org)
else:
users = models.User.query
for i, user in enumerate(users.order_by(models.User.name)):
query_users = query_users.where(models.User.org == org)

Check warning on line 295 in redash/cli/users.py

View check run for this annotation

Codecov / codecov/patch

redash/cli/users.py#L295

Added line #L295 was not covered by tests
users = models.db.session.scalars(query_users.order_by(models.User.name)).all()

for i, user in enumerate(users):
if i > 0:
print("-" * 20)

Expand All @@ -302,6 +305,6 @@
)
)

groups = models.Group.query.filter(models.Group.id.in_(user.group_ids)).all()
groups = models.db.session.scalars(select(models.Group).where(models.Group.id.in_(user.group_ids))).all()
group_names = [group.name for group in groups]
print("Groups: {}".format(", ".join(group_names)))
4 changes: 2 additions & 2 deletions redash/destinations/asana.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import requests

from redash.alerts import Alerts
from redash.destinations import BaseDestination, register
from redash.models import Alert


class Asana(BaseDestination):
Expand All @@ -30,7 +30,7 @@ def api_base_url(self):

def notify(self, alert, query, user, new_state, app, host, metadata, options):
# Documentation: https://developers.asana.com/docs/tasks
state = "TRIGGERED" if new_state == Alert.TRIGGERED_STATE else "RECOVERED"
state = "TRIGGERED" if new_state == Alerts.TRIGGERED_STATE else "RECOVERED"

notes = textwrap.dedent(
f"""
Expand Down