Skip to content

Commit

Permalink
update feature having clause, support full cut type
Browse files Browse the repository at this point in the history
  • Loading branch information
Nam Nd committed Jan 9, 2016
1 parent b5e984c commit 96f0bbe
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 60 deletions.
10 changes: 5 additions & 5 deletions cubes/cells.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@

class Cell(object):
"""Part of a cube determined by slicing dimensions. Immutable object."""
def __init__(self, cube=None, cuts=None, having_clauses=None):
def __init__(self, cube=None, cuts=None, having_cuts=None):
if not isinstance(cube, Cube):
raise ArgumentError("Cell cube should be sublcass of Cube, "
"provided: %s" % type(cube).__name__)
self.cube = cube
self.cuts = cuts if cuts is not None else []
self.having_clauses = having_clauses if having_clauses is not None else []
self.having_cuts = having_cuts if having_cuts is not None else []

def __and__(self, other):
"""Returns a new cell that is a conjunction of the two provided
Expand All @@ -52,15 +52,15 @@ def __and__(self, other):
"cubes '%s' and '%s'."
% (self.name, other.name))
cuts = self.cuts + other.cuts
having_clauses = self.having_clauses + other.having_clauses
return Cell(self.cube, cuts=cuts, having_clause=having_clauses)
having_cuts = self.having_cuts + other.having_cuts
return Cell(self.cube, cuts=cuts, having_cuts=having_cuts)

def to_dict(self):
"""Returns a dictionary representation of the cell"""
result = {
"cube": str(self.cube.name),
"cuts": [cut.to_dict() for cut in self.cuts],
"having_clauses": [clause.to_dict() for clause in self.having_clauses]
"having_cuts": [clause.to_dict() for clause in self.having_cuts]
}

return result
Expand Down
25 changes: 13 additions & 12 deletions cubes/sql/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,25 +579,26 @@ def aggregation_statement(self, cell, aggregates, drilldown=None,
else:
selection += aggregate_cols

# namnd added:
# HAVING
# madman: HAVING
# ------
having_clauses = context.clause_for_having(cell)
havings = having_clauses["condition"]
group_clauses = having_clauses["groups"]
if group_by is None:
group_by = []
for group in group_clauses:
if group not in group_by:
group_by.append(group)
having_clauses = None
colums_and_havings = context.colums_and_having_cut_for_cell(cell)
if colums_and_havings is not None:
having_clauses = colums_and_havings[1]
group_clauses = colums_and_havings[0]
if group_by is None:
group_by = []
for group in group_clauses:
if group not in group_by:
group_by.append(group)

statement = sql.expression.select(selection,
from_obj=context.star,
use_labels=True,
whereclause=condition,
group_by=group_by,
having=havings)
# print("statement: {}".format(statement))
having=having_clauses)

return (statement, context.get_labels(statement.columns))

def _log_statement(self, statement, label=None):
Expand Down
65 changes: 22 additions & 43 deletions cubes/sql/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -1111,55 +1111,34 @@ def column_for_split(self, split_cell, label=None):

return split_column.label(label)

# namnd added
def clause_for_having(self, cell):
"""Returns a clause for having clause and attr for group. If cell is empty, not contain having or cell is
# madman: get having clause and attributes
def colums_and_having_cut_for_cell(self, cell):
"""Returns attributes and having clause. If cell is empty, not contain having or cell is
`None` then returns `None`."""

if not cell:
return None

clauses = self.clauses_for_having(cell.having_clauses)
condition = and_(*clauses["condition"])
clauses["condition"] = condition
return clauses
having_cuts = cell.having_cuts
hav_condition = and_(*self.conditions_for_cuts(having_cuts))

# namnd added
def clauses_for_having(self, having_clauses):
clauses = []
groups = []
for cut in having_clauses:
hierarchy = str(cut.hierarchy) if cut.hierarchy else None
if isinstance(cut, PointCut):
path = cut.path
hav_conds = self.having_condition(str(cut.dimension),
path,
hierarchy, cut.invert)
clauses.append(hav_conds["condition"])
groups += hav_conds["group"]
# return one dict
dict_clause = {"groups": groups, "condition": clauses}
return dict_clause

# namnd added
def having_condition(self, dim, path, hierarchy=None, invert=False):
"""Returns a dict of `Condition` tuple (`attributes`, `conditions`,
`group_by`) dimension `dim` point at `path` and list group attrs use having. It is a compound
condition - one equality condition for each path element in form:
``level[i].key = path[i]``"""
conditions = []
groups = []
levels = self.level_keys(dim, hierarchy, path)
for level_key, value in zip(levels, path):
# Prepare condition: dimension.level_key = path_value
column = self.column(level_key)
conditions.append(column == value)
groups.append(column)
if hav_condition is None:
return None

condition = sql.expression.and_(*conditions)
colums = self.colums_in_having_cuts(having_cuts)

if invert:
condition = sql.expression.not_(condition)
return (colums, hav_condition)

# madman: get attributes in having cuts
def colums_in_having_cuts(self, having_cus):

columns = []

for cut in having_cus:
hierarchy = str(cut.hierarchy) if cut.hierarchy else None
levels = self.hierarchies[(str(cut.dimension), hierarchy)]
for level_key in levels:
column = self.column(level_key)
columns.append(column)

dict_condition = {"group": groups, "condition": condition}
return dict_condition
return columns

0 comments on commit 96f0bbe

Please sign in to comment.