diff --git a/panoramix/migrations/versions/2929af7925ed_tz_offsets_in_data_sources.py b/panoramix/migrations/versions/2929af7925ed_tz_offsets_in_data_sources.py new file mode 100644 index 000000000000..784657753f52 --- /dev/null +++ b/panoramix/migrations/versions/2929af7925ed_tz_offsets_in_data_sources.py @@ -0,0 +1,24 @@ +"""TZ offsets in data sources + +Revision ID: 2929af7925ed +Revises: 1e2841a4128 +Create Date: 2015-10-19 20:54:00.565633 + +""" + +# revision identifiers, used by Alembic. +revision = '2929af7925ed' +down_revision = '1e2841a4128' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +def upgrade(): + op.add_column('datasources', sa.Column('offset', sa.Integer(), nullable=True)) + op.add_column('tables', sa.Column('offset', sa.Integer(), nullable=True)) + + +def downgrade(): + op.drop_column('tables', 'offset') + op.drop_column('datasources', 'offset') diff --git a/panoramix/models.py b/panoramix/models.py index cf5f82b4499b..a55e56a3bcd5 100644 --- a/panoramix/models.py +++ b/panoramix/models.py @@ -11,9 +11,8 @@ from sqlalchemy import Table from sqlalchemy import create_engine, MetaData, desc, select, and_ from sqlalchemy.orm import relationship -from sqlalchemy.sql import table, literal_column, text, column +from sqlalchemy.sql import table, literal_column, text from sqlalchemy.sql.elements import ColumnClause -from flask import request from copy import deepcopy, copy from collections import namedtuple @@ -212,6 +211,7 @@ class SqlaTable(Model, Queryable, AuditMixinNullable): database_id = Column(Integer, ForeignKey('dbs.id'), nullable=False) database = relationship( 'Database', backref='tables', foreign_keys=[database_id]) + offset = Column(Integer, default=0) baselink = "tableview" @@ -637,7 +637,7 @@ def refresh_datasources(self): Datasource.sync_to_db(datasource, self) -class Datasource(Model, AuditMixin, Queryable): +class Datasource(Model, AuditMixinNullable, Queryable): type = "druid" baselink = "datasourcemodelview" @@ -655,6 +655,7 @@ class Datasource(Model, AuditMixin, Queryable): String(250), ForeignKey('clusters.cluster_name')) cluster = relationship( 'Cluster', backref='datasources', foreign_keys=[cluster_name]) + offset = Column(Integer, default=0) @property def metrics_combo(self): diff --git a/panoramix/views.py b/panoramix/views.py index 9a36c1cd1167..da5dbc330771 100644 --- a/panoramix/views.py +++ b/panoramix/views.py @@ -126,10 +126,14 @@ class DatabaseView(PanoramixModelView, DeleteMixin): class TableView(PanoramixModelView, DeleteMixin): datamodel = SQLAInterface(models.SqlaTable) list_columns = ['table_link', 'database'] - add_columns = ['table_name', 'database', 'default_endpoint'] + add_columns = ['table_name', 'database', 'default_endpoint', 'offset'] edit_columns = [ - 'table_name', 'database', 'main_dttm_col', 'default_endpoint'] + 'table_name', 'database', 'main_dttm_col', 'default_endpoint', + 'offset'] related_views = [TableColumnInlineView, SqlMetricInlineView] + description_columns = { + 'offset': "Timezone offset (in hours) for this datasource" + } def post_add(self, table): try: @@ -219,13 +223,17 @@ class DashboardModelView(PanoramixModelView, DeleteMixin): class DatasourceModelView(PanoramixModelView, DeleteMixin): datamodel = SQLAInterface(models.Datasource) list_columns = [ - 'datasource_link', 'cluster', 'owner', 'is_featured', 'is_hidden'] + 'datasource_link', 'cluster', 'owner', 'is_featured', 'is_hidden', + 'offset'] related_views = [ColumnInlineView, MetricInlineView] edit_columns = [ 'datasource_name', 'cluster', 'description', 'owner', - 'is_featured', 'is_hidden', 'default_endpoint'] + 'is_featured', 'is_hidden', 'default_endpoint', 'offset'] page_size = 100 base_order = ('datasource_name', 'asc') + description_columns = { + 'offset': "Timezone offset (in hours) for this datasource" + } def post_add(self, datasource): datasource.generate_metrics() diff --git a/panoramix/viz.py b/panoramix/viz.py index 4c766f65447e..d45a40097f32 100644 --- a/panoramix/viz.py +++ b/panoramix/viz.py @@ -1,6 +1,5 @@ from collections import OrderedDict, defaultdict -from copy import copy -from datetime import datetime +from datetime import datetime, timedelta import json import uuid @@ -110,6 +109,8 @@ def get_df(self, query_obj=None): else: if 'timestamp' in df.columns: df.timestamp = pd.to_datetime(df.timestamp) + if self.datasource.offset: + df.timestamp += timedelta(hours=self.datasource.offset) return df @property