diff --git a/mdxpy/mdx.py b/mdxpy/mdx.py index b0b8d36..6b42238 100644 --- a/mdxpy/mdx.py +++ b/mdxpy/mdx.py @@ -901,7 +901,7 @@ class HierarchizeSet(MdxHierarchySet): def __init__(self, underlying_hierarchy_set: MdxHierarchySet): super(HierarchizeSet, self).__init__(underlying_hierarchy_set.dimension, - underlying_hierarchy_set.hierarchy) + underlying_hierarchy_set.hierarchy) self.underlying_hierarchy_set = underlying_hierarchy_set def to_mdx(self) -> str: @@ -1075,17 +1075,29 @@ def is_empty(self) -> bool: def set_non_empty(self, non_empty: bool = True): self.non_empty = non_empty - def to_mdx(self, tm1_ignore_bad_tuples=False) -> str: + def to_mdx(self, tm1_ignore_bad_tuples: bool = False, head: int = None, tail: int = None) -> str: if self.is_empty(): return "{}" - return f"""{"NON EMPTY " if self.non_empty else ""}{"TM1IGNORE_BADTUPLES " if tm1_ignore_bad_tuples else ""}{self.dim_sets_to_mdx() if self.dim_sets else self.tuples_to_mdx()}""" + return f"""{"NON EMPTY " if self.non_empty else ""}{"TM1IGNORE_BADTUPLES " if tm1_ignore_bad_tuples else ""}{self.dim_sets_to_mdx(head, tail) if self.dim_sets else self.tuples_to_mdx(head, tail)}""" - def dim_sets_to_mdx(self) -> str: - return " * ".join(dim_set.to_mdx() for dim_set in self.dim_sets) + def dim_sets_to_mdx(self, head: int = None, tail: int = None) -> str: + mdx = " * ".join(dim_set.to_mdx() for dim_set in self.dim_sets) + if head is not None: + mdx = f"{{HEAD({mdx}, {head})}}" + if tail is not None: + mdx = f"{{TAIL({mdx}, {tail})}}" - def tuples_to_mdx(self) -> str: - return f"{{{','.join(tupl.to_mdx() for tupl in self.tuples)}}}" + return mdx + + def tuples_to_mdx(self, head: int = None, tail: int = None) -> str: + mdx = f"{{{','.join(tupl.to_mdx() for tupl in self.tuples)}}}" + if head is not None: + mdx = f"{{HEAD({mdx}, {head})}}" + if tail is not None: + mdx = f"{{TAIL({mdx}, {tail})}}" + + return mdx class MdxBuilder: @@ -1209,27 +1221,42 @@ def add_properties(self, axis: int, *args: Union[str, DimensionProperty]) -> 'Md return self - def _axis_mdx(self, position): + def _axis_mdx(self, position: int, head: int = None, tail: int = None, skip_dimension_properties=False): axis = self.axes[position] axis_properties = self.axes_properties.get(position, MdxPropertiesTuple.empty()) if axis.is_empty(): return "" + if skip_dimension_properties: + return " ".join([ + axis.to_mdx(self._tm1_ignore_bad_tuples, head, tail), + f"ON {position}" + ]) + return " ".join([ - axis.to_mdx(self._tm1_ignore_bad_tuples), + axis.to_mdx(self._tm1_ignore_bad_tuples, head, tail), "DIMENSION PROPERTIES", "MEMBER_NAME" if axis_properties.is_empty() else axis_properties.to_mdx(), f"ON {position}" ]) - def to_mdx(self) -> str: + def to_mdx(self, head_columns: int = None, head_rows: int = None, tail_columns: int = None, tail_rows: int = None, + skip_dimension_properties: bool = False) -> str: mdx_with = "WITH\r\n" + "\r\n".join( calculated_member.to_mdx() for calculated_member in self.calculated_members) + "\r\n" + head_by_axis_position = {0: head_columns, 1: head_rows} + tail_by_axis_position = {0: tail_columns, 1: tail_rows} + mdx_axes = ",\r\n".join( - self._axis_mdx(position) + self._axis_mdx( + position, + # default for head, tail is False for axes beyond rows and columns + head=head_by_axis_position.get(position, False), + tail=tail_by_axis_position.get(position, False), + skip_dimension_properties=skip_dimension_properties) for position in self.axes) diff --git a/setup.py b/setup.py index c092ce9..653b0e8 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name="mdxpy", - version='1.2', + version='1.3', maintainer='Marius Wirtz', maintainer_email='MWirtz@cubewise.com', license="MIT-LICENSE", diff --git a/test.py b/test.py index 7bd20f2..e5abfcf 100644 --- a/test.py +++ b/test.py @@ -216,6 +216,7 @@ def test_mdx_set_cross_joins(self): " * {[dimension].[dimension].[element3]}}", mdx_set.to_mdx()) + def test_mdx_set_tuples(self): mdx_set = MdxSet.tuples([ MdxTuple([Member.of("dimension1", "element1"), Member.of("dimension2", "element3")]), @@ -843,6 +844,58 @@ def test_mdx_build_with_multi_calculated_member(self): "WHERE ([dim2].[dim2].[totaldim2])", mdx) + def test_mdx_builder_to_mdx_skip_dimension_properties(self): + mdx = MdxBuilder.from_cube("cube") \ + .rows_non_empty() \ + .add_hierarchy_set_to_row_axis(MdxHierarchySet.all_leaves("Dim1")) \ + .columns_non_empty() \ + .add_hierarchy_set_to_column_axis(MdxHierarchySet.member(Member.of("Dim2", "Elem2"))) \ + .where(Member.of("Dim3", "Elem3"), Member.of("Dim4", "Elem4")) \ + .to_mdx(skip_dimension_properties=True) + + self.assertEqual( + "SELECT\r\n" + "NON EMPTY {[dim2].[dim2].[elem2]} ON 0,\r\n" + "NON EMPTY {TM1FILTERBYLEVEL({TM1SUBSETALL([dim1].[dim1])},0)} ON 1\r\n" + "FROM [cube]\r\n" + "WHERE ([dim3].[dim3].[elem3],[dim4].[dim4].[elem4])", + mdx) + + def test_mdx_builder_to_mdx_head_tail_columns(self): + mdx = MdxBuilder.from_cube("cube") \ + .add_hierarchy_set_to_column_axis(MdxHierarchySet.all_leaves("Dim1")) \ + .columns_non_empty() \ + .add_hierarchy_set_to_column_axis(MdxHierarchySet.member(Member.of("Dim2", "Elem2"))) \ + .where(Member.of("Dim3", "Elem3"), Member.of("Dim4", "Elem4")) \ + .to_mdx(head_columns=2, tail_columns=1) + + self.assertEqual( + "SELECT\r\n" + "NON EMPTY {TAIL({HEAD({TM1FILTERBYLEVEL({TM1SUBSETALL([dim1].[dim1])},0)} * {[dim2].[dim2].[elem2]}, 2)}, 1)} " + "DIMENSION PROPERTIES MEMBER_NAME ON 0\r\n" + "FROM [cube]\r\n" + "WHERE ([dim3].[dim3].[elem3],[dim4].[dim4].[elem4])", + mdx) + + def test_mdx_builder_to_mdx_head_tail_rows_and_columns(self): + mdx = MdxBuilder.from_cube("cube") \ + .add_hierarchy_set_to_column_axis(MdxHierarchySet.all_leaves("Dim1")) \ + .columns_non_empty() \ + .add_hierarchy_set_to_row_axis(MdxHierarchySet.all_leaves("Dim2")) \ + .rows_non_empty() \ + .where(Member.of("Dim3", "Elem3"), Member.of("Dim4", "Elem4")) \ + .to_mdx(head_columns=4, tail_columns=2, head_rows=2, tail_rows=1) + + self.assertEqual( + "SELECT\r\n" + "NON EMPTY {TAIL({HEAD({TM1FILTERBYLEVEL({TM1SUBSETALL([dim1].[dim1])},0)}, 4)}, 2)} " + "DIMENSION PROPERTIES MEMBER_NAME ON 0,\r\n" + "NON EMPTY {TAIL({HEAD({TM1FILTERBYLEVEL({TM1SUBSETALL([dim2].[dim2])},0)}, 2)}, 1)} " + "DIMENSION PROPERTIES MEMBER_NAME ON 1\r\n" + "FROM [cube]\r\n" + "WHERE ([dim3].[dim3].[elem3],[dim4].[dim4].[elem4])", + mdx) + def test_OrderType_ASC(self): order = Order("asc") self.assertEqual(order, Order.ASC) @@ -953,4 +1006,4 @@ def test_level_expression_name(self): def test_level_expression_member_level(self): level = MdxLevelExpression.member_level(Member.of("Dimension1", "Hierarchy1", "Element1")) - self.assertEqual("[dimension1].[hierarchy1].[element1].LEVEL", level.to_mdx()) \ No newline at end of file + self.assertEqual("[dimension1].[hierarchy1].[element1].LEVEL", level.to_mdx())