Verified Commit 82d18110 authored by Micaël Bergeron's avatar Micaël Bergeron

Merge commit '517659ad' into monorepo

parents 843fd51b 517659ad
from enum import Enum
from .substitution import Substitution
from pypika import Field, functions as fn
class AggregateType(Enum):
unknown = 'UNKNOWN'
count = 'count'
sum = 'sum'
class Aggregate():
def __init__(self, measure, table):
sql = measure.settings['sql']
self.substitution = Substitution(sql, table)
self.measure = measure
self.table = table
self.sql = self.substitution.sql
self.aggregateType = AggregateType.unknown
self.getAggregateType()
def getAggregateType(self):
type_ = self.measure.settings['type']
if type_ == AggregateType.sum.value:
self.aggregateType = AggregateType.sum
self.setAggregateSQLSum()
elif type_ == AggregateType.count.value:
self.aggregateType = AggregateType.count
self.setAggregateSQLCount()
else:
self.aggregateType = AggregateType.unknown
raise Exception('Aggregate Type {} not implemented yet'.format(type_))
def setAggregateSQLSum(self):
self.sql = fn.Coalesce(fn.Sum(self.sql), 0, alias=self.substitution.alias)
def setAggregateSQLCount(self):
self.sql = fn.Coalesce(fn.Count(self.sql), 0, alias=self.substitution.alias)
\ No newline at end of file
from pypika import Field, functions as fn
from pypika.terms import Function
class DateTrunc(Function):
def __init__(self, part, term, alias=None):
super(DateTrunc, self).__init__('DATE_TRUNC', part, term, alias=alias)
class Date():
def __init__(self, timeframe, table, name):
self.sql = None
field = Field(name, table=table)
if timeframe == 'date*':
alias = '{}_date'.format((field.get_sql().replace('_', '')))
self.sql = fn.Date(field, alias=alias)
elif timeframe == 'month*':
alias = '{}_month'.format((field.get_sql().replace('_', '')))
self.sql = fn.ToChar(DateTrunc('month', field), 'YYYY-MM', alias=alias)
elif timeframe == 'week*':
alias = '{}_week'.format((field.get_sql().replace('_', '')))
self.sql = fn.ToChar(DateTrunc('week', field), 'YYYY-MM-DD', alias=alias)
elif timeframe == 'year*':
alias = '{}_year'.format((field.get_sql().replace('_', '')))
self.sql = fn.Extract('YEAR', field, alias=alias)
......@@ -55,69 +55,13 @@ def get_sql(model_name, explore_name):
model = Model.query.filter(Model.name == model_name).first()
explore = Explore.query.filter(Explore.name == explore_name).first()
incoming_json = request.get_json()
view_name = incoming_json['view']
limit = incoming_json['limit']
view = View.query.filter(View.name == view_name).first()
incoming_dimensions = incoming_json['dimensions']
incoming_joins = incoming_json['joins']
incoming_dimension_groups = incoming_json['dimension_groups']
incoming_measures = incoming_json['measures']
incoming_filters = incoming_json['filters']
# get all timeframes
timeframes = [t['timeframes'] for t in incoming_dimension_groups]
# flatten list of timeframes
timeframes = [y for x in timeframes for y in x]
group_by = sqlHelper.group_by(incoming_joins, incoming_dimensions, timeframes)
filter_by = sqlHelper.filter_by(incoming_filters, explore_name)
to_run = incoming_json['run']
base_table = view.settings['sql_table_name']
dimensions = filter(lambda x: x.name in incoming_dimensions, view.dimensions)
set_dimensions = dimensions
dimensions = map(lambda x: x.settings['sql'].replace("${TABLE}", explore_name), dimensions)
dimensions = ',\n\t '.join(map(lambda x: '{}'.format(x), dimensions))
dimension_groups = sqlHelper.dimension_groups(view.name, explore_name, incoming_dimension_groups)
measures = filter(lambda x: x.name in incoming_measures, view.measures)
set_measures = list(measures)
measures = filter(lambda x: x.name in incoming_measures, view.measures)
measures = ',\n\t '.join([sqlHelper.get_func(x.name, x.settings['type'], explore_name, x.settings['sql']) for x in measures])
join_dimensions = sqlHelper.join_dimensions(incoming_joins)
join_measures = sqlHelper.join_measures(incoming_joins)
if join_dimensions:
dimensions = join_dimensions
if join_measures:
measures = join_measures
join_sql = sqlHelper.joins_by(incoming_joins, view)
to_join = []
if dimensions:
to_join.append(dimensions)
if dimension_groups:
to_join.append(dimension_groups)
if measures:
to_join.append(measures)
set_dimensions = ([d.settings for d in set_dimensions])
set_measures = ([m.settings for m in set_measures])
measures_as_dict = {}
for settings in set_measures:
new_key = re.sub(r'\$\{[A-Za-z]+\}', explore_name, settings['sql']).rstrip()
measures_as_dict[new_key] = settings
outgoing_sql = sqlHelper.get_sql(explore, incoming_json)
incoming_order = incoming_json['order']
incoming_order_desc = incoming_json['desc']
order_by = 'ORDER BY {}'.format(incoming_order) if incoming_order else ''
if incoming_order_desc:
order_by = '{} DESC'.format(order_by)
base_sql = 'SELECT\n\t{}\nFROM {} AS {} \n{} {} \n{} \n{} \nLIMIT {};'.format(',\n '.join(to_join), base_table, explore_name, filter_by, join_sql, group_by, order_by, limit);
if to_run:
db_to_connect = model.settings['connection']
if not db_to_connect in connections:
......@@ -140,7 +84,7 @@ def get_sql(model_name, explore_name):
base_dict['measures'] = measures_as_dict
return json.dumps(base_dict, default=default)
else:
return json.dumps({'sql': base_sql}, default=default)
return json.dumps({'sql': outgoing_sql}, default=default)
@bp.route('/distinct/<model_name>/<explore_name>', methods=['POST'])
def get_distinct_field_name(model_name, explore_name):
......
import re
from collections import namedtuple
from enum import Enum
from pypika import Field, Case
class SubstitutionType(Enum):
unknown = 'UNKNOWN'
table = 'TABLE'
dimension = 'DIMENSION'
view_dimension = 'VIEW_DIMENSION'
view_sql_table_name = 'VIEW_SQL_TABLE_NAME'
class Substitution():
def __init__(self, _input, table, dimension=None):
self.input = _input
self.alias = None
self.sql = None
self.table = table
if not dimension:
self.type = 'string'
else:
self.type = dimension.settings['type']
self.outer_pattern = r'(\$\{[\w\.]*\})'
self.inner_pattern = r'\$\{([\w\.]*)\}'
self.substitutionType = SubstitutionType.unknown
self.getSubstitutionType()
self.placeholders = self.placeholder_match()
self.setSql()
def getSubstitutionType(self):
# trying guess the substitutionType in a cheap way
if '.' in self.input and '${TABLE}' not in self.input:
if 'SQL_TABLE_NAME' in self.input:
self.substitutionType = SubstitutionType.view_sql_table_name
else:
self.substitutionType = SubstitutionType.view_dimension
elif '${TABLE}' in self.input:
self.substitutionType = SubstitutionType.table
elif ' ' not in self.input:
self.substitutionType = SubstitutionType.dimension
else:
self.substitutionType = SubstitutionType.unknown
def placeholder_match(self):
outer_results = re.findall(self.outer_pattern, self.input);
inner_results = re.findall(self.inner_pattern, self.input);
Results = namedtuple('Results', 'inner outer')
return Results(inner=inner_results, outer=outer_results)
def setSql(self):
if self.substitutionType is SubstitutionType.table:
self.setSqlTableType()
else:
raise Exception('Substitution Type {} not implemented yet'.format(self.substitutionType.value))
def setSqlTableType(self):
self.sql = self.input.replace(self.placeholders.outer[0], self.table._table_name)
(table, field) = self.sql.split('.')
self.alias = self.sql
if self.type == 'yesno':
field = Field(field, table=self.table)
self.sql = Case(alias=self.sql)\
.when(field, 'yes')\
.else_('no')
else:
self.sql = Field(field, table=self.table, alias=self.sql)
This diff is collapsed.
......@@ -17,6 +17,9 @@
<a class="navbar-item" href="/">
Home
</a>
<a class="navbar-item" href="/extract">
Extract
</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">
Explore
......
......@@ -447,6 +447,10 @@ export default {
};
</script>
<style lang="scss" scoped>
code {
white-space: pre;
word-wrap: break-word;
}
.panel-block {
position: relative;
&.indented {
......@@ -522,9 +526,6 @@ export default {
padding: 1.5rem;
padding-left: 0;
}
code {
white-space: pre;
}
.chart-buttons {
margin-top: -34px;
margin-left: 70px;
......
......@@ -7,11 +7,36 @@
</p>
<ul class="menu-list">
<li><a>Connections</a></li>
<li><a>Deploy Keys</a></li>
</ul>
</aside>
<div class="column section">
<section class="section">
<h2 class="title">Connections</h2>
<h2 class="title">Deploy Keys</h2>
<!-- <h2 class="title">Connections</h2> -->
<div class="columns is-multiline is-mobile">
<div class="column is-half">
<div class="card">
<header class="card-header">
<p class="card-header-title">
GitLab Deploy Key
</p>
</header>
<div class="card-content">
<div class="content">
<p>
<strong>Title</strong>
<span class="is-pulled-right">GL Deploy</span>
</p>
<p>
<strong>Key</strong>
<span class="is-pulled-right">**************</span>
</p>
</div>
</div>
</div>
</div>
</div>
<p v-if="!hasConnections">No Database Connections</p>
<div class="columns is-multiline is-mobile">
<div class="column is-half"
......
......@@ -217,7 +217,6 @@ const actions = {
.filter(j => !!(j.dimensions || j.measures));
let order = null;
const dimensionGroups = baseView
.dimension_groups
.map(dg => ({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment