+ />
Refresh Schedule
-
+
|
diff --git a/client/app/services/query.js b/client/app/services/query.js
index 1999787cd9..ec89ffae56 100644
--- a/client/app/services/query.js
+++ b/client/app/services/query.js
@@ -375,12 +375,7 @@ function QueryResource(
return new Query({
query: '',
name: 'New Query',
- schedule: {
- time: null,
- until: null,
- interval: null,
- day_of_week: null,
- },
+ schedule: null,
user: currentUser,
options: {},
});
diff --git a/migrations/versions/73beceabb948_bring_back_null_schedule.py b/migrations/versions/73beceabb948_bring_back_null_schedule.py
new file mode 100644
index 0000000000..189282ef43
--- /dev/null
+++ b/migrations/versions/73beceabb948_bring_back_null_schedule.py
@@ -0,0 +1,56 @@
+"""bring_back_null_schedule
+
+Revision ID: 73beceabb948
+Revises: e7f8a917aa8e
+Create Date: 2019-01-17 13:22:21.729334
+
+"""
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import postgresql
+from sqlalchemy.sql import table
+
+from redash.models import MutableDict, PseudoJSON
+
+# revision identifiers, used by Alembic.
+revision = '73beceabb948'
+down_revision = 'e7f8a917aa8e'
+branch_labels = None
+depends_on = None
+
+
+def is_empty_schedule(schedule):
+ if schedule is None:
+ return False
+
+ if schedule == {}:
+ return True
+
+ if schedule.get('interval') is None and schedule.get('until') is None and schedule.get('day_of_week') is None and schedule.get('time') is None:
+ return True
+
+ return False
+
+
+def upgrade():
+ op.alter_column('queries', 'schedule',
+ nullable=True,
+ server_default=None)
+
+ queries = table(
+ 'queries',
+ sa.Column('id', sa.Integer, primary_key=True),
+ sa.Column('schedule', MutableDict.as_mutable(PseudoJSON)))
+
+ conn = op.get_bind()
+ for query in conn.execute(queries.select()):
+ if is_empty_schedule(query.schedule):
+ conn.execute(
+ queries
+ .update()
+ .where(queries.c.id == query.id)
+ .values(schedule=None))
+
+
+def downgrade():
+ pass
diff --git a/redash/models/__init__.py b/redash/models/__init__.py
index f072310fc3..a59bb25f28 100644
--- a/redash/models/__init__.py
+++ b/redash/models/__init__.py
@@ -443,7 +443,7 @@ def __str__(self):
def archive(self, user=None):
db.session.add(self)
self.is_archived = True
- self.schedule = {}
+ self.schedule = None
for vis in self.visualizations:
for w in vis.widgets:
@@ -550,11 +550,11 @@ def by_user(cls, user):
@classmethod
def outdated_queries(cls):
- queries = (db.session.query(Query)
- .options(joinedload(Query.latest_query_data).load_only('retrieved_at'))
- .filter(Query.schedule != {})
- .order_by(Query.id))
-
+ queries = (Query.query
+ .options(joinedload(Query.latest_query_data).load_only('retrieved_at'))
+ .filter(Query.schedule.isnot(None))
+ .order_by(Query.id))
+
now = utils.utcnow()
outdated_queries = {}
scheduled_queries_executions.refresh()
diff --git a/redash/models/types.py b/redash/models/types.py
index 105ce768e6..cda072c6fb 100644
--- a/redash/models/types.py
+++ b/redash/models/types.py
@@ -24,6 +24,9 @@ class PseudoJSON(TypeDecorator):
impl = db.Text
def process_bind_param(self, value, dialect):
+ if value is None:
+ return value
+
return json_dumps(value)
def process_result_value(self, value, dialect):
diff --git a/tests/factories.py b/tests/factories.py
index 73a1c21bd5..2c82e186da 100644
--- a/tests/factories.py
+++ b/tests/factories.py
@@ -75,7 +75,7 @@ def __call__(self):
user=user_factory.create,
is_archived=False,
is_draft=False,
- schedule={},
+ schedule=None,
data_source=data_source_factory.create,
org_id=1)
diff --git a/tests/models/test_dashboards.py b/tests/models/test_dashboards.py
index f168aaab3a..cf9595a17d 100644
--- a/tests/models/test_dashboards.py
+++ b/tests/models/test_dashboards.py
@@ -20,11 +20,11 @@ def create_tagged_dashboard(self, tags):
return dashboard
def test_all_tags(self):
- self.create_tagged_dashboard(tags=['tag1'])
- self.create_tagged_dashboard(tags=['tag1', 'tag2'])
- self.create_tagged_dashboard(tags=['tag1', 'tag2', 'tag3'])
+ self.create_tagged_dashboard(tags=[u'tag1'])
+ self.create_tagged_dashboard(tags=[u'tag1', u'tag2'])
+ self.create_tagged_dashboard(tags=[u'tag1', u'tag2', u'tag3'])
self.assertEqual(
list(Dashboard.all_tags(self.factory.org, self.factory.user)),
- [('tag1', 3), ('tag2', 2), ('tag3', 1)]
+ [(u'tag1', 3), (u'tag2', 2), (u'tag3', 1)]
)
diff --git a/tests/test_models.py b/tests/test_models.py
index 98a960e803..465d6bf65e 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -136,9 +136,12 @@ class QueryOutdatedQueriesTest(BaseTestCase):
# TODO: this test can be refactored to use mock version of should_schedule_next to simplify it.
def test_outdated_queries_skips_unscheduled_queries(self):
query = self.factory.create_query(schedule={'interval':None, 'time': None, 'until':None, 'day_of_week':None})
+ query_with_none = self.factory.create_query(schedule=None)
+
queries = models.Query.outdated_queries()
self.assertNotIn(query, queries)
+ self.assertNotIn(query_with_none, queries)
def test_outdated_queries_works_with_ttl_based_schedule(self):
two_hours_ago = utcnow() - datetime.timedelta(hours=2)
@@ -318,7 +321,7 @@ def test_removes_scheduling(self):
query.archive()
- self.assertEqual({}, query.schedule)
+ self.assertIsNone(query.schedule)
def test_deletes_alerts(self):
subscription = self.factory.create_alert_subscription()