import calendar
import datetime
from unittest import TestCase

import pytz
from dateutil.parser import parse as date_parse
from tests import BaseTestCase

from redash import models, redis_connection
from redash.models import db, types
from redash.utils import gen_query_hash, utcnow


class DashboardTest(BaseTestCase):
    def test_appends_suffix_to_slug_when_duplicate(self):
        d1 = self.factory.create_dashboard()
        db.session.flush()
        self.assertEqual(d1.slug, 'test')

        d2 = self.factory.create_dashboard(user=d1.user)
        db.session.flush()
        self.assertNotEqual(d1.slug, d2.slug)

        d3 = self.factory.create_dashboard(user=d1.user)
        db.session.flush()
        self.assertNotEqual(d1.slug, d3.slug)
        self.assertNotEqual(d2.slug, d3.slug)


class ShouldScheduleNextTest(TestCase):
    def test_interval_schedule_that_needs_reschedule(self):
        now = utcnow()
        two_hours_ago = now - datetime.timedelta(hours=2)
        self.assertTrue(models.should_schedule_next(two_hours_ago, now, "3600"))

    def test_interval_schedule_that_doesnt_need_reschedule(self):
        now = utcnow()
        half_an_hour_ago = now - datetime.timedelta(minutes=30)
        self.assertFalse(models.should_schedule_next(half_an_hour_ago, now, "3600"))

    def test_exact_time_that_needs_reschedule(self):
        now = utcnow()
        yesterday = now - datetime.timedelta(days=1)
        scheduled_datetime = now - datetime.timedelta(hours=3)
        scheduled_time = "{:02d}:00".format(scheduled_datetime.hour)
        self.assertTrue(models.should_schedule_next(yesterday, now, "86400",
                                                    scheduled_time))

    def test_exact_time_that_doesnt_need_reschedule(self):
        now = date_parse("2015-10-16 20:10")
        yesterday = date_parse("2015-10-15 23:07")
        schedule = "23:00"
        self.assertFalse(models.should_schedule_next(yesterday, now, "86400", schedule))

    def test_exact_time_with_day_change(self):
        now = utcnow().replace(hour=0, minute=1)
        previous = (now - datetime.timedelta(days=2)).replace(hour=23,
                                                              minute=59)
        schedule = "23:59".format(now.hour + 3)
        self.assertTrue(models.should_schedule_next(previous, now, "86400", schedule))

    def test_exact_time_every_x_days_that_needs_reschedule(self):
        now = utcnow()
        four_days_ago = now - datetime.timedelta(days=4)
        three_day_interval = "259200"
        scheduled_datetime = now - datetime.timedelta(hours=3)
        scheduled_time = "{:02d}:00".format(scheduled_datetime.hour)
        self.assertTrue(models.should_schedule_next(four_days_ago, now, three_day_interval,
                                                    scheduled_time))

    def test_exact_time_every_x_days_that_doesnt_need_reschedule(self):
        now = utcnow()
        four_days_ago = now - datetime.timedelta(days=2)
        three_day_interval = "259200"
        scheduled_datetime = now - datetime.timedelta(hours=3)
        scheduled_time = "{:02d}:00".format(scheduled_datetime.hour)
        self.assertFalse(models.should_schedule_next(four_days_ago, now, three_day_interval,
                                                    scheduled_time))

    def test_exact_time_every_x_days_with_day_change(self):
        now = utcnow().replace(hour=23, minute=59)
        previous = (now - datetime.timedelta(days=2)).replace(hour=0, minute=1)
        schedule = "23:58"
        three_day_interval = "259200"
        self.assertTrue(models.should_schedule_next(previous, now, three_day_interval, schedule))

    def test_exact_time_every_x_weeks_that_needs_reschedule(self):
        # Setup:
        #
        # 1) The query should run every 3 weeks on Tuesday
        # 2) The last time it ran was 3 weeks ago from this week's Thursday
        # 3) It is now Wednesday of this week
        #
        # Expectation: Even though less than 3 weeks have passed since the
        #              last run 3 weeks ago on Thursday, it's overdue since
        #              it should be running on Tuesdays.
        this_thursday = utcnow() + datetime.timedelta(days=list(calendar.day_name).index("Thursday") - utcnow().weekday())
        three_weeks_ago = this_thursday - datetime.timedelta(weeks=3)
        now = this_thursday - datetime.timedelta(days=1)
        three_week_interval = "1814400"
        scheduled_datetime = now - datetime.timedelta(hours=3)
        scheduled_time = "{:02d}:00".format(scheduled_datetime.hour)
        self.assertTrue(models.should_schedule_next(three_weeks_ago, now, three_week_interval,
                                                    scheduled_time, "Tuesday"))

    def test_exact_time_every_x_weeks_that_doesnt_need_reschedule(self):
        # Setup:
        #
        # 1) The query should run every 3 weeks on Thurday
        # 2) The last time it ran was 3 weeks ago from this week's Tuesday
        # 3) It is now Wednesday of this week
        #
        # Expectation: Even though more than 3 weeks have passed since the
        #              last run 3 weeks ago on Tuesday, it's not overdue since
        #              it should be running on Thursdays.
        this_tuesday = utcnow() + datetime.timedelta(days=list(calendar.day_name).index("Tuesday") - utcnow().weekday())
        three_weeks_ago = this_tuesday - datetime.timedelta(weeks=3)
        now = this_tuesday + datetime.timedelta(days=1)
        three_week_interval = "1814400"
        scheduled_datetime = now - datetime.timedelta(hours=3)
        scheduled_time = "{:02d}:00".format(scheduled_datetime.hour)
        self.assertFalse(models.should_schedule_next(three_weeks_ago, now, three_week_interval,
                                                    scheduled_time, "Thursday"))

    def test_backoff(self):
        now = utcnow()
        two_hours_ago = now - datetime.timedelta(hours=2)
        self.assertTrue(models.should_schedule_next(two_hours_ago, now, "3600",
                                                    failures=5))
        self.assertFalse(models.should_schedule_next(two_hours_ago, now,
                                                     "3600", failures=10))

    def test_next_iteration_overflow(self):
        now = utcnow()
        two_hours_ago = now - datetime.timedelta(hours=2)
        self.assertFalse(models.should_schedule_next(two_hours_ago, now, "3600", failures=32))


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)
        query = self.factory.create_query(schedule={'interval':'3600', 'time': None, 'until':None, 'day_of_week':None})
        query_result = self.factory.create_query_result(query=query.query_text, retrieved_at=two_hours_ago)
        query.latest_query_data = query_result

        queries = models.Query.outdated_queries()
        self.assertIn(query, queries)

    def test_outdated_queries_works_scheduled_queries_tracker(self):
        two_hours_ago = utcnow() - datetime.timedelta(hours=2)
        query = self.factory.create_query(schedule={'interval':'3600', 'time': None, 'until':None, 'day_of_week':None})
        query_result = self.factory.create_query_result(query=query, retrieved_at=two_hours_ago)
        query.latest_query_data = query_result

        models.scheduled_queries_executions.update(query.id)

        queries = models.Query.outdated_queries()
        self.assertNotIn(query, queries)

    def test_skips_fresh_queries(self):
        half_an_hour_ago = utcnow() - datetime.timedelta(minutes=30)
        query = self.factory.create_query(schedule={'interval':'3600', 'time': None, 'until':None, 'day_of_week':None})
        query_result = self.factory.create_query_result(query=query.query_text, retrieved_at=half_an_hour_ago)
        query.latest_query_data = query_result

        queries = models.Query.outdated_queries()
        self.assertNotIn(query, queries)

    def test_outdated_queries_works_with_specific_time_schedule(self):
        half_an_hour_ago = utcnow() - datetime.timedelta(minutes=30)
        query = self.factory.create_query(schedule={'interval':'86400', 'time':half_an_hour_ago.strftime('%H:%M'), 'until':None, 'day_of_week':None})
        query_result = self.factory.create_query_result(query=query.query_text, retrieved_at=half_an_hour_ago - datetime.timedelta(days=1))
        query.latest_query_data = query_result

        queries = models.Query.outdated_queries()
        self.assertIn(query, queries)

    def test_enqueues_query_only_once(self):
        """
        Only one query per data source with the same text will be reported by
        Query.outdated_queries().
        """
        query = self.factory.create_query(schedule={'interval':'60', 'until':None, 'time': None, 'day_of_week':None})
        query2 = self.factory.create_query(
            schedule={'interval':'60', 'until':None, 'time': None, 'day_of_week':None}, query_text=query.query_text,
            query_hash=query.query_hash)
        retrieved_at = utcnow() - datetime.timedelta(minutes=10)
        query_result = self.factory.create_query_result(
            retrieved_at=retrieved_at, query_text=query.query_text,
            query_hash=query.query_hash)
        query.latest_query_data = query_result
        query2.latest_query_data = query_result

        self.assertEqual(list(models.Query.outdated_queries()), [query2])

    def test_enqueues_query_with_correct_data_source(self):
        """
        Queries from different data sources will be reported by
        Query.outdated_queries() even if they have the same query text.
        """
        query = self.factory.create_query(
            schedule={'interval':'60', 'until':None, 'time': None, 'day_of_week':None}, data_source=self.factory.create_data_source())
        query2 = self.factory.create_query(
            schedule={'interval':'60', 'until':None, 'time': None, 'day_of_week':None}, query_text=query.query_text,
            query_hash=query.query_hash)
        retrieved_at = utcnow() - datetime.timedelta(minutes=10)
        query_result = self.factory.create_query_result(
            retrieved_at=retrieved_at, query_text=query.query_text,
            query_hash=query.query_hash)
        query.latest_query_data = query_result
        query2.latest_query_data = query_result

        outdated_queries = models.Query.outdated_queries()
        self.assertEqual(len(outdated_queries), 2)
        self.assertIn(query, outdated_queries)
        self.assertIn(query2, outdated_queries)

    def test_enqueues_only_for_relevant_data_source(self):
        """
        If multiple queries with the same text exist, only ones that are
        scheduled to be refreshed are reported by Query.outdated_queries().
        """
        query = self.factory.create_query(schedule={'interval':'60', 'until':None, 'time': None, 'day_of_week':None})
        query2 = self.factory.create_query(
            schedule={'interval':'3600', 'until':None, 'time': None, 'day_of_week':None}, query_text=query.query_text,
            query_hash=query.query_hash)
        retrieved_at = utcnow() - datetime.timedelta(minutes=10)
        query_result = self.factory.create_query_result(
            retrieved_at=retrieved_at, query_text=query.query_text,
            query_hash=query.query_hash)
        query.latest_query_data = query_result
        query2.latest_query_data = query_result

        self.assertEqual(list(models.Query.outdated_queries()), [query])

    def test_failure_extends_schedule(self):
        """
        Execution failures recorded for a query result in exponential backoff
        for scheduling future execution.
        """
        query = self.factory.create_query(schedule={'interval':'60', 'until':None, 'time': None, 'day_of_week':None}, schedule_failures=4)
        retrieved_at = utcnow() - datetime.timedelta(minutes=16)
        query_result = self.factory.create_query_result(
            retrieved_at=retrieved_at, query_text=query.query_text,
            query_hash=query.query_hash)
        query.latest_query_data = query_result

        self.assertEqual(list(models.Query.outdated_queries()), [])

        query_result.retrieved_at = utcnow() - datetime.timedelta(minutes=17)
        self.assertEqual(list(models.Query.outdated_queries()), [query])

    def test_schedule_until_after(self):
        """
        Queries with non-null ``schedule['until']`` are not reported by
        Query.outdated_queries() after the given time is past.
        """
        one_day_ago = (utcnow() - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
        two_hours_ago = utcnow() - datetime.timedelta(hours=2)
        query = self.factory.create_query(schedule={'interval':'3600', 'until':one_day_ago, 'time':None, 'day_of_week':None})
        query_result = self.factory.create_query_result(query=query.query_text, retrieved_at=two_hours_ago)
        query.latest_query_data = query_result

        queries = models.Query.outdated_queries()
        self.assertNotIn(query, queries)

    def test_schedule_until_before(self):
        """
        Queries with non-null ``schedule['until']`` are reported by
        Query.outdated_queries() before the given time is past.
        """
        one_day_from_now = (utcnow() + datetime.timedelta(days=1)).strftime("%Y-%m-%d")
        two_hours_ago = utcnow() - datetime.timedelta(hours=2)
        query = self.factory.create_query(schedule={'interval':'3600', 'until':one_day_from_now, 'time': None, 'day_of_week':None})
        query_result = self.factory.create_query_result(query=query.query_text, retrieved_at=two_hours_ago)
        query.latest_query_data = query_result

        queries = models.Query.outdated_queries()
        self.assertIn(query, queries)


class QueryArchiveTest(BaseTestCase):
    def test_archive_query_sets_flag(self):
        query = self.factory.create_query()
        db.session.flush()
        query.archive()

        self.assertEqual(query.is_archived, True)

    def test_archived_query_doesnt_return_in_all(self):
        query = self.factory.create_query(schedule={'interval':'1', 'until':None, 'time': None, 'day_of_week':None})
        yesterday = utcnow() - datetime.timedelta(days=1)
        query_result = models.QueryResult.store_result(
            query.org_id, query.data_source, query.query_hash, query.query_text,
            "1", 123, yesterday)

        query.latest_query_data = query_result
        groups = list(models.Group.query.filter(models.Group.id.in_(query.groups)))
        self.assertIn(query, list(models.Query.all_queries([g.id for g in groups])))
        self.assertIn(query, models.Query.outdated_queries())
        db.session.flush()
        query.archive()

        self.assertNotIn(query, list(models.Query.all_queries([g.id for g in groups])))
        self.assertNotIn(query, models.Query.outdated_queries())

    def test_removes_associated_widgets_from_dashboards(self):
        widget = self.factory.create_widget()
        query = widget.visualization.query_rel
        db.session.commit()
        query.archive()
        db.session.flush()
        self.assertEqual(models.Widget.query.get(widget.id), None)

    def test_removes_scheduling(self):
        query = self.factory.create_query(schedule={'interval':'1', 'until':None, 'time': None, 'day_of_week':None})

        query.archive()

        self.assertIsNone(query.schedule)

    def test_deletes_alerts(self):
        subscription = self.factory.create_alert_subscription()
        query = subscription.alert.query_rel
        db.session.commit()
        query.archive()
        db.session.flush()
        self.assertEqual(models.Alert.query.get(subscription.alert.id), None)
        self.assertEqual(models.AlertSubscription.query.get(subscription.id), None)


class TestUnusedQueryResults(BaseTestCase):
    def test_returns_only_unused_query_results(self):
        two_weeks_ago = utcnow() - datetime.timedelta(days=14)
        qr = self.factory.create_query_result()
        self.factory.create_query(latest_query_data=qr)
        db.session.flush()
        unused_qr = self.factory.create_query_result(retrieved_at=two_weeks_ago)
        self.assertIn(unused_qr, list(models.QueryResult.unused()))
        self.assertNotIn(qr, list(models.QueryResult.unused()))

    def test_returns_only_over_a_week_old_results(self):
        two_weeks_ago = utcnow() - datetime.timedelta(days=14)
        unused_qr = self.factory.create_query_result(retrieved_at=two_weeks_ago)
        db.session.flush()
        new_unused_qr = self.factory.create_query_result()

        self.assertIn(unused_qr, list(models.QueryResult.unused()))
        self.assertNotIn(new_unused_qr, list(models.QueryResult.unused()))


class TestQueryAll(BaseTestCase):
    def test_returns_only_queries_in_given_groups(self):
        ds1 = self.factory.create_data_source()
        ds2 = self.factory.create_data_source()

        group1 = models.Group(name="g1", org=ds1.org, permissions=['create', 'view'])
        group2 = models.Group(name="g2", org=ds1.org, permissions=['create', 'view'])

        q1 = self.factory.create_query(data_source=ds1)
        q2 = self.factory.create_query(data_source=ds2)

        db.session.add_all([
            ds1, ds2,
            group1, group2,
            q1, q2,
            models.DataSourceGroup(
                group=group1, data_source=ds1),
            models.DataSourceGroup(group=group2, data_source=ds2)
            ])
        db.session.flush()
        self.assertIn(q1, list(models.Query.all_queries([group1.id])))
        self.assertNotIn(q2, list(models.Query.all_queries([group1.id])))
        self.assertIn(q1, list(models.Query.all_queries([group1.id, group2.id])))
        self.assertIn(q2, list(models.Query.all_queries([group1.id, group2.id])))

    def test_skips_drafts(self):
        q = self.factory.create_query(is_draft=True)
        self.assertNotIn(q, models.Query.all_queries([self.factory.default_group.id]))

    def test_includes_drafts_of_given_user(self):
        q = self.factory.create_query(is_draft=True)
        self.assertIn(q, models.Query.all_queries([self.factory.default_group.id], user_id=q.user_id))

    def test_order_by_relationship(self):
        u1 = self.factory.create_user(name='alice')
        u2 = self.factory.create_user(name='bob')
        self.factory.create_query(user=u1)
        self.factory.create_query(user=u2)
        db.session.commit()
        # have to reset the order here with None since all_queries orders by
        # created_at by default
        base = models.Query.all_queries([self.factory.default_group.id]).order_by(None)
        qs1 = base.order_by(models.User.name)
        self.assertEqual(['alice', 'bob'], [q.user.name for q in qs1])
        qs2 = base.order_by(models.User.name.desc())
        self.assertEqual(['bob', 'alice'], [q.user.name for q in qs2])


class TestGroup(BaseTestCase):
    def test_returns_groups_with_specified_names(self):
        org1 = self.factory.create_org()
        org2 = self.factory.create_org()

        matching_group1 = models.Group(id=999, name="g1", org=org1)
        matching_group2 = models.Group(id=888, name="g2", org=org1)
        non_matching_group = models.Group(id=777, name="g1", org=org2)

        groups = models.Group.find_by_name(org1, ["g1", "g2"])
        self.assertIn(matching_group1, groups)
        self.assertIn(matching_group2, groups)
        self.assertNotIn(non_matching_group, groups)

    def test_returns_no_groups(self):
        org1 = self.factory.create_org()

        models.Group(id=999, name="g1", org=org1)
        self.assertEqual([], models.Group.find_by_name(org1, ["non-existing"]))


class TestQueryResultStoreResult(BaseTestCase):
    def setUp(self):
        super(TestQueryResultStoreResult, self).setUp()
        self.data_source = self.factory.data_source
        self.query = "SELECT 1"
        self.query_hash = gen_query_hash(self.query)
        self.runtime = 123
        self.utcnow = utcnow()
        self.data = '{"a": 1}'

    def test_stores_the_result(self):
        query_result = models.QueryResult.store_result(
            self.data_source.org_id, self.data_source, self.query_hash,
            self.query, self.data, self.runtime, self.utcnow)

        self.assertEqual(query_result._data, self.data)
        self.assertEqual(query_result.runtime, self.runtime)
        self.assertEqual(query_result.retrieved_at, self.utcnow)
        self.assertEqual(query_result.query_text, self.query)
        self.assertEqual(query_result.query_hash, self.query_hash)
        self.assertEqual(query_result.data_source, self.data_source)


class TestEvents(BaseTestCase):
    def raw_event(self):
        timestamp = 1411778709.791
        user = self.factory.user
        created_at = datetime.datetime.utcfromtimestamp(timestamp)
        db.session.flush()
        raw_event = {"action": "view",
                      "timestamp": timestamp,
                      "object_type": "dashboard",
                      "user_id": user.id,
                      "object_id": 1,
                      "org_id": 1}

        return raw_event, user, created_at

    def test_records_event(self):
        raw_event, user, created_at = self.raw_event()

        event = models.Event.record(raw_event)
        db.session.flush()
        self.assertEqual(event.user, user)
        self.assertEqual(event.action, "view")
        self.assertEqual(event.object_type, "dashboard")
        self.assertEqual(event.object_id, 1)
        self.assertEqual(event.created_at, created_at)

    def test_records_additional_properties(self):
        raw_event, _, _ = self.raw_event()
        additional_properties = {'test': 1, 'test2': 2, 'whatever': "abc"}
        raw_event.update(additional_properties)

        event = models.Event.record(raw_event)

        self.assertDictEqual(event.additional_properties, additional_properties)


def _set_up_dashboard_test(d):
    d.g1 = d.factory.create_group(name='First', permissions=['create', 'view'])
    d.g2 = d.factory.create_group(name='Second',  permissions=['create', 'view'])
    d.ds1 = d.factory.create_data_source()
    d.ds2 = d.factory.create_data_source()
    db.session.flush()
    d.u1 = d.factory.create_user(group_ids=[d.g1.id])
    d.u2 = d.factory.create_user(group_ids=[d.g2.id])
    db.session.add_all([
        models.DataSourceGroup(group=d.g1, data_source=d.ds1),
        models.DataSourceGroup(group=d.g2, data_source=d.ds2)
    ])
    d.q1 = d.factory.create_query(data_source=d.ds1)
    d.q2 = d.factory.create_query(data_source=d.ds2)
    d.v1 = d.factory.create_visualization(query_rel=d.q1)
    d.v2 = d.factory.create_visualization(query_rel=d.q2)
    d.w1 = d.factory.create_widget(visualization=d.v1)
    d.w2 = d.factory.create_widget(visualization=d.v2)
    d.w3 = d.factory.create_widget(visualization=d.v2, dashboard=d.w2.dashboard)
    d.w4 = d.factory.create_widget(visualization=d.v2)
    d.w5 = d.factory.create_widget(visualization=d.v1, dashboard=d.w4.dashboard)
    d.w1.dashboard.is_draft = False
    d.w2.dashboard.is_draft = False
    d.w4.dashboard.is_draft = False


class TestDashboardAll(BaseTestCase):
    def setUp(self):
        super(TestDashboardAll, self).setUp()
        _set_up_dashboard_test(self)

    def test_requires_group_or_user_id(self):
        d1 = self.factory.create_dashboard()
        self.assertNotIn(d1, list(models.Dashboard.all(
           d1.user.org, d1.user.group_ids, None)))
        l2 = list(models.Dashboard.all(
            d1.user.org, [0], d1.user.id))
        self.assertIn(d1, l2)

    def test_returns_dashboards_based_on_groups(self):
        self.assertIn(self.w1.dashboard, list(models.Dashboard.all(
            self.u1.org, self.u1.group_ids, None)))
        self.assertIn(self.w2.dashboard, list(models.Dashboard.all(
            self.u2.org, self.u2.group_ids, None)))
        self.assertNotIn(self.w1.dashboard, list(models.Dashboard.all(
            self.u2.org, self.u2.group_ids, None)))
        self.assertNotIn(self.w2.dashboard, list(models.Dashboard.all(
            self.u1.org, self.u1.group_ids, None)))

    def test_returns_each_dashboard_once(self):
        dashboards = list(models.Dashboard.all(self.u2.org, self.u2.group_ids, None))
        self.assertEqual(len(dashboards), 2)

    def test_returns_dashboard_you_have_partial_access_to(self):
        self.assertIn(self.w5.dashboard, models.Dashboard.all(self.u1.org, self.u1.group_ids, None))

    def test_returns_dashboards_created_by_user(self):
        d1 = self.factory.create_dashboard(user=self.u1)
        db.session.flush()
        self.assertIn(d1, list(models.Dashboard.all(self.u1.org, self.u1.group_ids, self.u1.id)))
        self.assertIn(d1, list(models.Dashboard.all(self.u1.org, [0], self.u1.id)))
        self.assertNotIn(d1, list(models.Dashboard.all(self.u2.org, self.u2.group_ids, self.u2.id)))

    def test_returns_dashboards_with_text_widgets(self):
        w1 = self.factory.create_widget(visualization=None)

        self.assertIn(w1.dashboard, models.Dashboard.all(self.u1.org, self.u1.group_ids, None))
        self.assertIn(w1.dashboard, models.Dashboard.all(self.u2.org, self.u2.group_ids, None))

    def test_returns_dashboards_from_current_org_only(self):
        w1 = self.factory.create_widget(visualization=None)

        user = self.factory.create_user(org=self.factory.create_org())

        self.assertIn(w1.dashboard, models.Dashboard.all(self.u1.org, self.u1.group_ids, None))
        self.assertNotIn(w1.dashboard, models.Dashboard.all(user.org, user.group_ids, None))

[((495, 4, 495, 22), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((17, 8, 17, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((21, 8, 21, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((25, 8, 25, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((32, 14, 32, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((37, 14, 37, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((42, 14, 42, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((50, 14, 50, 44), 'dateutil.parser.parse', 'date_parse', ({(50, 25, 50, 43): '"""2015-10-16 20:10"""'}, {}), "('2015-10-16 20:10')", True, 'from dateutil.parser import parse as date_parse\n'), ((51, 20, 51, 50), 'dateutil.parser.parse', 'date_parse', ({(51, 31, 51, 49): '"""2015-10-15 23:07"""'}, {}), "('2015-10-15 23:07')", True, 'from dateutil.parser import parse as date_parse\n'), ((63, 14, 63, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((72, 14, 72, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((126, 14, 126, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((134, 14, 134, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((145, 18, 145, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((156, 18, 156, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((165, 8, 165, 60), 'redash.models.scheduled_queries_executions.update', 'models.scheduled_queries_executions.update', ({(165, 51, 165, 59): 'query.id'}, {}), '(query.id)', False, 'from redash import models, redis_connection\n'), ((167, 18, 167, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((176, 18, 176, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((185, 18, 185, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((223, 27, 223, 58), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((274, 18, 274, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((288, 18, 288, 49), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((295, 8, 295, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((303, 23, 305, 32), 'redash.models.QueryResult.store_result', 'models.QueryResult.store_result', ({(304, 12, 304, 24): 'query.org_id', (304, 26, 304, 43): 'query.data_source', (304, 45, 304, 61): 'query.query_hash', (304, 63, 304, 79): 'query.query_text', (305, 12, 305, 15): '"""1"""', (305, 17, 305, 20): '123', (305, 22, 305, 31): 'yesterday'}, {}), "(query.org_id, query.data_source, query.\n    query_hash, query.query_text, '1', 123, yesterday)", False, 'from redash import models, redis_connection\n'), ((311, 8, 311, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((320, 8, 320, 27), 'redash.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((322, 8, 322, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((335, 8, 335, 27), 'redash.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((337, 8, 337, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((347, 8, 347, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((355, 8, 355, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((367, 17, 367, 85), 'redash.models.Group', 'models.Group', (), '', False, 'from redash import models, redis_connection\n'), ((368, 17, 368, 85), 'redash.models.Group', 'models.Group', (), '', False, 'from redash import models, redis_connection\n'), ((381, 8, 381, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((400, 8, 400, 27), 'redash.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((415, 26, 415, 67), 'redash.models.Group', 'models.Group', (), '', False, 'from redash import models, redis_connection\n'), ((416, 26, 416, 67), 'redash.models.Group', 'models.Group', (), '', False, 'from redash import models, redis_connection\n'), ((417, 29, 417, 70), 'redash.models.Group', 'models.Group', (), '', False, 'from redash import models, redis_connection\n'), ((419, 17, 419, 62), 'redash.models.Group.find_by_name', 'models.Group.find_by_name', ({(419, 43, 419, 47): 'org1', (419, 49, 419, 61): "['g1', 'g2']"}, {}), "(org1, ['g1', 'g2'])", False, 'from redash import models, redis_connection\n'), ((427, 8, 427, 49), 'redash.models.Group', 'models.Group', (), '', False, 'from redash import models, redis_connection\n'), ((436, 26, 436, 52), 'redash.utils.gen_query_hash', 'gen_query_hash', ({(436, 41, 436, 51): 'self.query'}, {}), '(self.query)', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((438, 22, 438, 30), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((442, 23, 444, 61), 'redash.models.QueryResult.store_result', 'models.QueryResult.store_result', ({(443, 12, 443, 35): 'self.data_source.org_id', (443, 37, 443, 53): 'self.data_source', (443, 55, 443, 70): 'self.query_hash', (444, 12, 444, 22): 'self.query', (444, 24, 444, 33): 'self.data', (444, 35, 444, 47): 'self.runtime', (444, 49, 444, 60): 'self.utcnow'}, {}), '(self.data_source.org_id, self.data_source,\n    self.query_hash, self.query, self.data, self.runtime, self.utcnow)', False, 'from redash import models, redis_connection\n'), ((458, 21, 458, 66), 'datetime.datetime.utcfromtimestamp', 'datetime.datetime.utcfromtimestamp', ({(458, 56, 458, 65): 'timestamp'}, {}), '(timestamp)', False, 'import datetime\n'), ((459, 8, 459, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((472, 16, 472, 46), 'redash.models.Event.record', 'models.Event.record', ({(472, 36, 472, 45): 'raw_event'}, {}), '(raw_event)', False, 'from redash import models, redis_connection\n'), ((473, 8, 473, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((485, 16, 485, 46), 'redash.models.Event.record', 'models.Event.record', ({(485, 36, 485, 45): 'raw_event'}, {}), '(raw_event)', False, 'from redash import models, redis_connection\n'), ((548, 8, 548, 26), 'redash.models.db.session.flush', 'db.session.flush', ({}, {}), '()', False, 'from redash.models import db, types\n'), ((33, 30, 33, 57), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((34, 24, 34, 79), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(34, 52, 34, 65): 'two_hours_ago', (34, 67, 34, 70): 'now', (34, 72, 34, 78): '"""3600"""'}, {}), "(two_hours_ago, now, '3600')", False, 'from redash import models, redis_connection\n'), ((38, 33, 38, 63), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((39, 25, 39, 83), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(39, 53, 39, 69): 'half_an_hour_ago', (39, 71, 39, 74): 'now', (39, 76, 39, 82): '"""3600"""'}, {}), "(half_an_hour_ago, now, '3600')", False, 'from redash import models, redis_connection\n'), ((43, 26, 43, 52), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((44, 35, 44, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((46, 24, 47, 67), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(46, 52, 46, 61): 'yesterday', (46, 63, 46, 66): 'now', (46, 68, 46, 75): '"""86400"""', (47, 52, 47, 66): 'scheduled_time'}, {}), "(yesterday, now, '86400', scheduled_time)", False, 'from redash import models, redis_connection\n'), ((53, 25, 53, 87), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(53, 53, 53, 62): 'yesterday', (53, 64, 53, 67): 'now', (53, 69, 53, 76): '"""86400"""', (53, 78, 53, 86): 'schedule'}, {}), "(yesterday, now, '86400', schedule)", False, 'from redash import models, redis_connection\n'), ((60, 24, 60, 85), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(60, 52, 60, 60): 'previous', (60, 62, 60, 65): 'now', (60, 67, 60, 74): '"""86400"""', (60, 76, 60, 84): 'schedule'}, {}), "(previous, now, '86400', schedule)", False, 'from redash import models, redis_connection\n'), ((64, 30, 64, 56), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((66, 35, 66, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((68, 24, 69, 67), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(68, 52, 68, 65): 'four_days_ago', (68, 67, 68, 70): 'now', (68, 72, 68, 90): 'three_day_interval', (69, 52, 69, 66): 'scheduled_time'}, {}), '(four_days_ago, now, three_day_interval,\n    scheduled_time)', False, 'from redash import models, redis_connection\n'), ((73, 30, 73, 56), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((75, 35, 75, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((77, 25, 78, 67), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(77, 53, 77, 66): 'four_days_ago', (77, 68, 77, 71): 'now', (77, 73, 77, 91): 'three_day_interval', (78, 52, 78, 66): 'scheduled_time'}, {}), '(four_days_ago, now, three_day_interval,\n    scheduled_time)', False, 'from redash import models, redis_connection\n'), ((85, 24, 85, 96), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(85, 52, 85, 60): 'previous', (85, 62, 85, 65): 'now', (85, 67, 85, 85): 'three_day_interval', (85, 87, 85, 95): 'schedule'}, {}), '(previous, now, three_day_interval, schedule)', False, 'from redash import models, redis_connection\n'), ((97, 24, 97, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((98, 42, 98, 69), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((99, 30, 99, 56), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((101, 35, 101, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((103, 24, 104, 78), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(103, 52, 103, 67): 'three_weeks_ago', (103, 69, 103, 72): 'now', (103, 74, 103, 93): 'three_week_interval', (104, 52, 104, 66): 'scheduled_time', (104, 68, 104, 77): '"""Tuesday"""'}, {}), "(three_weeks_ago, now, three_week_interval,\n    scheduled_time, 'Tuesday')", False, 'from redash import models, redis_connection\n'), ((116, 23, 116, 31), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((117, 41, 117, 68), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((118, 29, 118, 55), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((120, 35, 120, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((122, 25, 123, 79), 'redash.models.should_schedule_next', 'models.should_schedule_next', ({(122, 53, 122, 68): 'three_weeks_ago', (122, 70, 122, 73): 'now', (122, 75, 122, 94): 'three_week_interval', (123, 52, 123, 66): 'scheduled_time', (123, 68, 123, 78): '"""Thursday"""'}, {}), "(three_weeks_ago, now, three_week_interval,\n    scheduled_time, 'Thursday')", False, 'from redash import models, redis_connection\n'), ((127, 30, 127, 57), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((128, 24, 129, 63), 'redash.models.should_schedule_next', 'models.should_schedule_next', (), '', False, 'from redash import models, redis_connection\n'), ((130, 25, 131, 73), 'redash.models.should_schedule_next', 'models.should_schedule_next', (), '', False, 'from redash import models, redis_connection\n'), ((135, 30, 135, 57), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((136, 25, 136, 93), 'redash.models.should_schedule_next', 'models.should_schedule_next', (), '', False, 'from redash import models, redis_connection\n'), ((151, 24, 151, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((151, 35, 151, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((160, 24, 160, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((160, 35, 160, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((171, 27, 171, 35), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((171, 38, 171, 68), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((180, 27, 180, 35), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((180, 38, 180, 68), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((197, 23, 197, 31), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((197, 34, 197, 64), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((216, 23, 216, 31), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((216, 34, 216, 64), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((237, 23, 237, 31), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((237, 34, 237, 64), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((252, 23, 252, 31), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((252, 34, 252, 64), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((260, 36, 260, 44), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((260, 47, 260, 77), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((269, 24, 269, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((269, 35, 269, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((283, 24, 283, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((283, 35, 283, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((302, 20, 302, 28), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((302, 31, 302, 57), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((310, 29, 310, 60), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((315, 32, 315, 63), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((323, 25, 323, 59), 'redash.models.Widget.query.get', 'models.Widget.query.get', ({(323, 49, 323, 58): 'widget.id'}, {}), '(widget.id)', False, 'from redash import models, redis_connection\n'), ((338, 25, 338, 70), 'redash.models.Alert.query.get', 'models.Alert.query.get', ({(338, 48, 338, 69): 'subscription.alert.id'}, {}), '(subscription.alert.id)', False, 'from redash import models, redis_connection\n'), ((339, 25, 339, 76), 'redash.models.AlertSubscription.query.get', 'models.AlertSubscription.query.get', ({(339, 60, 339, 75): 'subscription.id'}, {}), '(subscription.id)', False, 'from redash import models, redis_connection\n'), ((344, 24, 344, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((344, 35, 344, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((353, 24, 353, 32), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((353, 35, 353, 62), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((389, 28, 389, 85), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(389, 53, 389, 84): '[self.factory.default_group.id]'}, {}), '([self.factory.default_group.id])', False, 'from redash import models, redis_connection\n'), ((393, 25, 393, 101), 'redash.models.Query.all_queries', 'models.Query.all_queries', (), '', False, 'from redash import models, redis_connection\n'), ((406, 28, 406, 51), 'redash.models.User.name.desc', 'models.User.name.desc', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((428, 29, 428, 78), 'redash.models.Group.find_by_name', 'models.Group.find_by_name', ({(428, 55, 428, 59): 'org1', (428, 61, 428, 77): "['non-existing']"}, {}), "(org1, ['non-existing'])", False, 'from redash import models, redis_connection\n'), ((499, 8, 499, 61), 'redash.models.DataSourceGroup', 'models.DataSourceGroup', (), '', False, 'from redash import models, redis_connection\n'), ((500, 8, 500, 61), 'redash.models.DataSourceGroup', 'models.DataSourceGroup', (), '', False, 'from redash import models, redis_connection\n'), ((525, 18, 526, 41), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(526, 12, 526, 23): 'd1.user.org', (526, 25, 526, 28): '[0]', (526, 30, 526, 40): 'd1.user.id'}, {}), '(d1.user.org, [0], d1.user.id)', False, 'from redash import models, redis_connection\n'), ((540, 26, 540, 84), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(540, 47, 540, 58): 'self.u2.org', (540, 60, 540, 77): 'self.u2.group_ids', (540, 79, 540, 83): 'None'}, {}), '(self.u2.org, self.u2.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((544, 41, 544, 99), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(544, 62, 544, 73): 'self.u1.org', (544, 75, 544, 92): 'self.u1.group_ids', (544, 94, 544, 98): 'None'}, {}), '(self.u1.org, self.u1.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((556, 36, 556, 94), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(556, 57, 556, 68): 'self.u1.org', (556, 70, 556, 87): 'self.u1.group_ids', (556, 89, 556, 93): 'None'}, {}), '(self.u1.org, self.u1.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((557, 36, 557, 94), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(557, 57, 557, 68): 'self.u2.org', (557, 70, 557, 87): 'self.u2.group_ids', (557, 89, 557, 93): 'None'}, {}), '(self.u2.org, self.u2.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((564, 36, 564, 94), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(564, 57, 564, 68): 'self.u1.org', (564, 70, 564, 87): 'self.u1.group_ids', (564, 89, 564, 93): 'None'}, {}), '(self.u1.org, self.u1.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((565, 39, 565, 91), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(565, 60, 565, 68): 'user.org', (565, 70, 565, 84): 'user.group_ids', (565, 86, 565, 90): 'None'}, {}), '(user.org, user.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((56, 14, 56, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((81, 14, 81, 22), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((204, 30, 204, 61), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((244, 30, 244, 61), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((258, 30, 258, 61), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((261, 30, 261, 61), 'redash.models.Query.outdated_queries', 'models.Query.outdated_queries', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((308, 48, 308, 81), 'redash.models.Group.id.in_', 'models.Group.id.in_', ({(308, 68, 308, 80): 'query.groups'}, {}), '(query.groups)', False, 'from redash import models, redis_connection\n'), ((309, 34, 309, 82), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(309, 59, 309, 81): '[g.id for g in groups]'}, {}), '([g.id for g in groups])', False, 'from redash import models, redis_connection\n'), ((314, 37, 314, 85), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(314, 62, 314, 84): '[g.id for g in groups]'}, {}), '([g.id for g in groups])', False, 'from redash import models, redis_connection\n'), ((349, 38, 349, 65), 'redash.models.QueryResult.unused', 'models.QueryResult.unused', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((350, 34, 350, 61), 'redash.models.QueryResult.unused', 'models.QueryResult.unused', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((358, 38, 358, 65), 'redash.models.QueryResult.unused', 'models.QueryResult.unused', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((359, 45, 359, 72), 'redash.models.QueryResult.unused', 'models.QueryResult.unused', ({}, {}), '()', False, 'from redash import models, redis_connection\n'), ((377, 12, 378, 46), 'redash.models.DataSourceGroup', 'models.DataSourceGroup', (), '', False, 'from redash import models, redis_connection\n'), ((379, 12, 379, 65), 'redash.models.DataSourceGroup', 'models.DataSourceGroup', (), '', False, 'from redash import models, redis_connection\n'), ((382, 31, 382, 68), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(382, 56, 382, 67): '[group1.id]'}, {}), '([group1.id])', False, 'from redash import models, redis_connection\n'), ((383, 34, 383, 71), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(383, 59, 383, 70): '[group1.id]'}, {}), '([group1.id])', False, 'from redash import models, redis_connection\n'), ((384, 31, 384, 79), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(384, 56, 384, 78): '[group1.id, group2.id]'}, {}), '([group1.id, group2.id])', False, 'from redash import models, redis_connection\n'), ((385, 31, 385, 79), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(385, 56, 385, 78): '[group1.id, group2.id]'}, {}), '([group1.id, group2.id])', False, 'from redash import models, redis_connection\n'), ((403, 15, 403, 72), 'redash.models.Query.all_queries', 'models.Query.all_queries', ({(403, 40, 403, 71): '[self.factory.default_group.id]'}, {}), '([self.factory.default_group.id])', False, 'from redash import models, redis_connection\n'), ((523, 34, 524, 48), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(524, 11, 524, 22): 'd1.user.org', (524, 24, 524, 41): 'd1.user.group_ids', (524, 43, 524, 47): 'None'}, {}), '(d1.user.org, d1.user.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((530, 46, 531, 49), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(531, 12, 531, 23): 'self.u1.org', (531, 25, 531, 42): 'self.u1.group_ids', (531, 44, 531, 48): 'None'}, {}), '(self.u1.org, self.u1.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((532, 46, 533, 49), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(533, 12, 533, 23): 'self.u2.org', (533, 25, 533, 42): 'self.u2.group_ids', (533, 44, 533, 48): 'None'}, {}), '(self.u2.org, self.u2.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((534, 49, 535, 49), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(535, 12, 535, 23): 'self.u2.org', (535, 25, 535, 42): 'self.u2.group_ids', (535, 44, 535, 48): 'None'}, {}), '(self.u2.org, self.u2.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((536, 49, 537, 49), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(537, 12, 537, 23): 'self.u1.org', (537, 25, 537, 42): 'self.u1.group_ids', (537, 44, 537, 48): 'None'}, {}), '(self.u1.org, self.u1.group_ids, None)', False, 'from redash import models, redis_connection\n'), ((549, 31, 549, 95), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(549, 52, 549, 63): 'self.u1.org', (549, 65, 549, 82): 'self.u1.group_ids', (549, 84, 549, 94): 'self.u1.id'}, {}), '(self.u1.org, self.u1.group_ids, self.u1.id)', False, 'from redash import models, redis_connection\n'), ((550, 31, 550, 81), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(550, 52, 550, 63): 'self.u1.org', (550, 65, 550, 68): '[0]', (550, 70, 550, 80): 'self.u1.id'}, {}), '(self.u1.org, [0], self.u1.id)', False, 'from redash import models, redis_connection\n'), ((551, 34, 551, 98), 'redash.models.Dashboard.all', 'models.Dashboard.all', ({(551, 55, 551, 66): 'self.u2.org', (551, 68, 551, 85): 'self.u2.group_ids', (551, 87, 551, 97): 'self.u2.id'}, {}), '(self.u2.org, self.u2.group_ids, self.u2.id)', False, 'from redash import models, redis_connection\n'), ((57, 26, 57, 52), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((82, 26, 82, 52), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((182, 112, 182, 138), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((268, 23, 268, 31), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((268, 34, 268, 60), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((282, 28, 282, 36), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((282, 39, 282, 65), 'datetime.timedelta', 'datetime.timedelta', (), '', False, 'import datetime\n'), ((97, 103, 97, 111), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n'), ((116, 101, 116, 109), 'redash.utils.utcnow', 'utcnow', ({}, {}), '()', False, 'from redash.utils import gen_query_hash, utcnow\n')]