-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Dttm format #506
Dttm format #506
Changes from 12 commits
439b7a1
cec723a
404a2fd
4336f83
34b6278
eba364d
2ff5cc1
5816d01
7360fd2
6897c38
adcafad
7218303
e91507a
c610dc0
55bf3e0
53d7b24
09d0b9e
669cc77
d8552b0
7a6310e
9c5419a
646542a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"""add d timestamp format for tables | ||
|
||
Revision ID: 422116f431b7 | ||
Revises: 956a063c52b3 | ||
Create Date: 2016-05-20 19:11:57.218062 | ||
|
||
""" | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = '422116f431b7' | ||
down_revision = '956a063c52b3' | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
def upgrade(): | ||
try: | ||
op.add_column('datasources', sa.Column('timestamp_format', sa.String(length=256), nullable=True)) | ||
op.add_column('tables', sa.Column('timestamp_format', sa.String(length=256), nullable=True)) | ||
except Exception: | ||
pass | ||
|
||
|
||
def downgrade(): | ||
try: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, no try |
||
op.drop_column('tables', 'timestamp_format') | ||
op.drop_column('datasources', 'timestamp_format') | ||
except Exception: | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -428,9 +428,11 @@ def grains(self): | |
if self.sqlalchemy_uri.startswith(db_type): | ||
return grains | ||
|
||
def dttm_converter(self, dttm): | ||
def dttm_converter(self, dttm, tf=None): | ||
"""Returns a string that the database flavor understands as a date""" | ||
default = "'{}'".format(dttm.strftime('%Y-%m-%d %H:%M:%S.%f')) | ||
if tf is None or tf == '': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pythonesquier: |
||
tf = '%Y-%m-%d %H:%M:%S.%f' | ||
default = "'{}'".format(dttm.strftime(tf)) | ||
iso = dttm.isoformat() | ||
d = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think this previous approach had shortcomings to start with. It assumed that the casting required could be defined on a per-database basis where it cannot since even within a single table you could represent dates in different fashion (epoch, string, native DATETIME, DATE or TIMESTAMP types...). |
||
'mssql': "CONVERT(DATETIME, '{}', 126)".format(iso), #untested | ||
|
@@ -508,6 +510,7 @@ class SqlaTable(Model, Queryable, AuditMixinNullable): | |
offset = Column(Integer, default=0) | ||
cache_timeout = Column(Integer) | ||
schema = Column(String(255)) | ||
timestamp_format = Column(String(256)) | ||
|
||
baselink = "tablemodelview" | ||
|
||
|
@@ -657,18 +660,18 @@ def query( # sqla | |
select_exprs += [timestamp_grain] | ||
groupby_exprs += [timestamp_grain] | ||
|
||
tf = '%Y-%m-%d %H:%M:%S.%f' | ||
tf = self.timestamp_format | ||
time_filter = [ | ||
timestamp >= text(self.database.dttm_converter(from_dttm)), | ||
timestamp <= text(self.database.dttm_converter(to_dttm)), | ||
timestamp >= text(self.database.dttm_converter(from_dttm, tf)), | ||
timestamp <= text(self.database.dttm_converter(to_dttm, tf)), | ||
] | ||
inner_time_filter = copy(time_filter) | ||
if inner_from_dttm: | ||
inner_time_filter[0] = timestamp >= text( | ||
self.database.dttm_converter(inner_from_dttm)) | ||
self.database.dttm_converter(inner_from_dttm, tf)) | ||
if inner_to_dttm: | ||
inner_time_filter[1] = timestamp <= text( | ||
self.database.dttm_converter(inner_to_dttm)) | ||
self.database.dttm_converter(inner_to_dttm, tf)) | ||
else: | ||
inner_time_filter = [] | ||
|
||
|
@@ -961,6 +964,7 @@ class DruidDatasource(Model, AuditMixinNullable, Queryable): | |
'DruidCluster', backref='datasources', foreign_keys=[cluster_name]) | ||
offset = Column(Integer, default=0) | ||
cache_timeout = Column(Integer) | ||
timestamp_format = Column(String(256)) | ||
|
||
@property | ||
def metrics_combo(self): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,14 +143,16 @@ def get_df(self, query_obj=None): | |
self.results = None | ||
|
||
# The datasource here can be different backend but the interface is common | ||
timestamp_format = self.datasource.timestamp_format | ||
self.results = self.datasource.query(**query_obj) | ||
self.query = self.results.query | ||
df = self.results.df | ||
if df is None or df.empty: | ||
raise Exception("No data, review your incantations!") | ||
else: | ||
if 'timestamp' in df.columns: | ||
df.timestamp = pd.to_datetime(df.timestamp, utc=False) | ||
df.timestamp = pd.to_datetime( | ||
df.timestamp, utc=False, format=timestamp_format) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this here as opposed to relying on pandas's |
||
if self.datasource.offset: | ||
df.timestamp += timedelta(hours=self.datasource.offset) | ||
df = df.fillna(0) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
failing would result in a broken app, let's fail early in the migration script if anywhere