Пример #1
0
    def setUp(self):
        super(MapperTestCase, self).setUp()

        self.modelmd = self.model_metadata("mapper_test.json")
        self.workspace = self.create_workspace(model=self.modelmd)

        self.cube = self.workspace.cube("sales")
        self.mapper = SnowflakeMapper(self.cube,
                                      dimension_prefix='dim_',
                                      dimension_suffix="_dim")

        self.mapper.mappings = {
            "product.name": "product.product_name",
            "product.category": "product.category_id",
            "subcategory.name.en": "subcategory.subcategory_name_en",
            "subcategory.name.sk": "subcategory.subcategory_name_sk"
        }
Пример #2
0
    def setUp(self):
        super(MapperTestCase, self).setUp()

        self.modelmd = self.model_metadata("mapper_test.json")
        self.workspace = self.create_workspace(model=self.modelmd)

        self.cube = self.workspace.cube("sales")
        self.mapper = SnowflakeMapper(self.cube, dimension_prefix="dim_", dimension_suffix="_dim")

        self.mapper.mappings = {
            "product.name": "product.product_name",
            "product.category": "product.category_id",
            "subcategory.name.en": "subcategory.subcategory_name_en",
            "subcategory.name.sk": "subcategory.subcategory_name_sk",
        }
Пример #3
0
class MapperTestCase(CubesTestCaseBase):
    def setUp(self):
        super(MapperTestCase, self).setUp()

        self.modelmd = self.model_metadata("mapper_test.json")
        self.workspace = self.create_workspace(model=self.modelmd)

        self.cube = self.workspace.cube("sales")
        self.mapper = SnowflakeMapper(self.cube, dimension_prefix="dim_", dimension_suffix="_dim")

        self.mapper.mappings = {
            "product.name": "product.product_name",
            "product.category": "product.category_id",
            "subcategory.name.en": "subcategory.subcategory_name_en",
            "subcategory.name.sk": "subcategory.subcategory_name_sk",
        }

    def test_logical_reference(self):

        dim = self.workspace.dimension("date")
        attr = Attribute("month", dimension=dim)
        self.assertEqual("date.month", self.mapper.logical(attr))

        attr = Attribute("month", dimension=dim)
        dim = self.workspace.dimension("product")
        attr = Attribute("category", dimension=dim)
        self.assertEqual("product.category", self.mapper.logical(attr))

        self.assertEqual(True, self.mapper.simplify_dimension_references)
        dim = self.workspace.dimension("flag")
        attr = Attribute("flag", dimension=dim)
        self.assertEqual("flag", self.mapper.logical(attr))

        attr = Attribute("measure", dimension=None)
        self.assertEqual("measure", self.mapper.logical(attr))

    def test_logical_reference_as_string(self):
        self.assertRaises(AttributeError, self.mapper.logical, "amount")

    def test_dont_simplify_dimension_references(self):
        self.mapper.simplify_dimension_references = False

        dim = self.workspace.dimension("flag")
        attr = Attribute("flag", dimension=dim)
        self.assertEqual("flag.flag", self.mapper.logical(attr))

        attr = Attribute("measure", dimension=None)
        self.assertEqual("measure", self.mapper.logical(attr))

    def test_logical_split(self):
        split = self.mapper.split_logical

        self.assertEqual(("foo", "bar"), split("foo.bar"))
        self.assertEqual(("foo", "bar.baz"), split("foo.bar.baz"))
        self.assertEqual((None, "foo"), split("foo"))

    def assertMapping(self, expected, logical_ref, locale=None):
        """Create string reference by concatentanig table and column name.
        No schema is expected (is ignored)."""

        attr = self.mapper.attributes[logical_ref]
        ref = self.mapper.physical(attr, locale)
        sref = ref[1] + "." + ref[2]
        self.assertEqual(expected, sref)

    def test_physical_refs_dimensions(self):
        """Testing correct default mappings of dimensions (with and without
        explicit default prefix) in physical references."""

        # No dimension prefix
        self.mapper.dimension_prefix = ""
        self.mapper.dimension_suffix = ""
        self.assertMapping("date.year", "date.year")
        self.assertMapping("sales.flag", "flag")
        self.assertMapping("sales.amount", "amount")
        # self.assertEqual("fact.flag", sref("flag.flag"))

        # With prefix
        self.mapper.dimension_prefix = "dm_"
        self.assertMapping("dm_date.year", "date.year")
        self.assertMapping("dm_date.month_name", "date.month_name")
        self.assertMapping("sales.flag", "flag")
        self.assertMapping("sales.amount", "amount")
        self.mapper.dimension_prefix = ""
        self.mapper.dimension_suffix = ""

    def test_physical_refs_flat_dims(self):
        self.cube.fact = None
        self.assertMapping("sales.flag", "flag")

    def test_physical_refs_facts(self):
        """Testing correct mappings of fact attributes in physical references"""

        fact = self.cube.fact
        self.cube.fact = None
        self.assertMapping("sales.amount", "amount")
        # self.assertEqual("sales.flag", sref("flag.flag"))
        self.cube.fact = fact

    def test_physical_refs_with_mappings_and_locales(self):
        """Testing correct mappings of mapped attributes and localized
        attributes in physical references"""

        # Test defaults
        self.assertMapping("dim_date_dim.month_name", "date.month_name")
        self.assertMapping("dim_category_dim.category_name_en", "product.category_name")
        self.assertMapping("dim_category_dim.category_name_sk", "product.category_name", "sk")
        self.assertMapping("dim_category_dim.category_name_en", "product.category_name", "de")

        # Test with mapping
        self.assertMapping("dim_product_dim.product_name", "product.name")
        self.assertMapping("dim_product_dim.category_id", "product.category")
        self.assertMapping("dim_product_dim.product_name", "product.name", "sk")
        self.assertMapping("dim_category_dim.subcategory_name_en", "product.subcategory_name")
        self.assertMapping("dim_category_dim.subcategory_name_sk", "product.subcategory_name", "sk")
        self.assertMapping("dim_category_dim.subcategory_name_en", "product.subcategory_name", "de")
Пример #4
0
class MapperTestCase(CubesTestCaseBase):
    def setUp(self):
        super(MapperTestCase, self).setUp()

        self.modelmd = self.model_metadata("mapper_test.json")
        self.workspace = self.create_workspace(model=self.modelmd)

        self.cube = self.workspace.cube("sales")
        self.mapper = SnowflakeMapper(self.cube,
                                      dimension_prefix='dim_',
                                      dimension_suffix="_dim")

        self.mapper.mappings = {
            "product.name": "product.product_name",
            "product.category": "product.category_id",
            "subcategory.name.en": "subcategory.subcategory_name_en",
            "subcategory.name.sk": "subcategory.subcategory_name_sk"
        }

    def test_logical_reference(self):

        dim = self.workspace.dimension("date")
        attr = Attribute("month", dimension=dim)
        self.assertEqual("date.month", self.mapper.logical(attr))

        attr = Attribute("month", dimension=dim)
        dim = self.workspace.dimension("product")
        attr = Attribute("category", dimension=dim)
        self.assertEqual("product.category", self.mapper.logical(attr))

        self.assertEqual(True, self.mapper.simplify_dimension_references)
        dim = self.workspace.dimension("flag")
        attr = Attribute("flag", dimension=dim)
        self.assertEqual("flag", self.mapper.logical(attr))

        attr = Attribute("measure", dimension=None)
        self.assertEqual("measure", self.mapper.logical(attr))

    def test_logical_reference_as_string(self):
        self.assertRaises(AttributeError, self.mapper.logical, "amount")

    def test_dont_simplify_dimension_references(self):
        self.mapper.simplify_dimension_references = False

        dim = self.workspace.dimension("flag")
        attr = Attribute("flag", dimension=dim)
        self.assertEqual("flag.flag", self.mapper.logical(attr))

        attr = Attribute("measure", dimension=None)
        self.assertEqual("measure", self.mapper.logical(attr))

    def test_logical_split(self):
        split = self.mapper.split_logical

        self.assertEqual(('foo', 'bar'), split('foo.bar'))
        self.assertEqual(('foo', 'bar.baz'), split('foo.bar.baz'))
        self.assertEqual((None, 'foo'), split('foo'))

    def assertMapping(self, expected, logical_ref, locale=None):
        """Create string reference by concatentanig table and column name.
        No schema is expected (is ignored)."""

        attr = self.mapper.attributes[logical_ref]
        ref = self.mapper.physical(attr, locale)
        sref = ref[1] + "." + ref[2]
        self.assertEqual(expected, sref)

    def test_physical_refs_dimensions(self):
        """Testing correct default mappings of dimensions (with and without
        explicit default prefix) in physical references."""

        # No dimension prefix
        self.mapper.dimension_prefix = ""
        self.mapper.dimension_suffix = ""
        self.assertMapping("date.year", "date.year")
        self.assertMapping("sales.flag", "flag")
        self.assertMapping("sales.amount", "amount")
        # self.assertEqual("fact.flag", sref("flag.flag"))

        # With prefix
        self.mapper.dimension_prefix = "dm_"
        self.assertMapping("dm_date.year", "date.year")
        self.assertMapping("dm_date.month_name", "date.month_name")
        self.assertMapping("sales.flag", "flag")
        self.assertMapping("sales.amount", "amount")
        self.mapper.dimension_prefix = ""
        self.mapper.dimension_suffix = ""

    def test_physical_refs_flat_dims(self):
        self.cube.fact = None
        self.assertMapping("sales.flag", "flag")

    def test_physical_refs_facts(self):
        """Testing correct mappings of fact attributes in physical references"""

        fact = self.cube.fact
        self.cube.fact = None
        self.assertMapping("sales.amount", "amount")
        # self.assertEqual("sales.flag", sref("flag.flag"))
        self.cube.fact = fact

    def test_physical_refs_with_mappings_and_locales(self):
        """Testing correct mappings of mapped attributes and localized
        attributes in physical references"""

        # Test defaults
        self.assertMapping("dim_date_dim.month_name", "date.month_name")
        self.assertMapping("dim_category_dim.category_name_en",
                           "product.category_name")
        self.assertMapping("dim_category_dim.category_name_sk",
                           "product.category_name", "sk")
        self.assertMapping("dim_category_dim.category_name_en",
                           "product.category_name", "de")

        # Test with mapping
        self.assertMapping("dim_product_dim.product_name", "product.name")
        self.assertMapping("dim_product_dim.category_id", "product.category")
        self.assertMapping("dim_product_dim.product_name", "product.name",
                           "sk")
        self.assertMapping("dim_category_dim.subcategory_name_en",
                           "product.subcategory_name")
        self.assertMapping("dim_category_dim.subcategory_name_sk",
                           "product.subcategory_name", "sk")
        self.assertMapping("dim_category_dim.subcategory_name_en",
                           "product.subcategory_name", "de")
Пример #5
0
    def create_denormalized_view(self,
                                 cube,
                                 view_name=None,
                                 materialize=False,
                                 replace=False,
                                 create_index=False,
                                 keys_only=False,
                                 schema=None):
        """Creates a denormalized view named `view_name` of a `cube`. If
        `view_name` is ``None`` then view name is constructed by pre-pending
        value of `denormalized_view_prefix` from workspace options to the cube
        name. If no prefix is specified in the options, then view name will be
        equal to the cube name.

        Options:

        * `materialize` - whether the view is materialized (a table) or
          regular view
        * `replace` - if `True` then existing table/view will be replaced,
          otherwise an exception is raised when trying to create view/table
          with already existing name
        * `create_index` - if `True` then index is created for each key
          attribute. Can be used only on materialized view, otherwise raises
          an exception
        * `keys_only` - if ``True`` then only key attributes are used in the
          view, all other detail attributes are ignored
        * `schema` - target schema of the denormalized view, if not specified,
          then `denormalized_view_schema` from options is used if specified,
          otherwise default workspace schema is used (same schema as fact
          table schema).
        """

        cube = self.model.cube(cube)

        mapper = SnowflakeMapper(cube, cube.mappings, **self.options)
        context = QueryContext(cube, mapper, metadata=self.metadata)

        key_attributes = []
        for dim in cube.dimensions:
            key_attributes += dim.key_attributes()

        if keys_only:
            statement = context.denormalized_statement(
                attributes=key_attributes, expand_locales=True)
        else:
            statement = context.denormalized_statement(expand_locales=True)

        schema = schema or self.options.get(
            "denormalized_view_schema") or self.schema

        dview_prefix = self.options.get("denormalized_view_prefix", "")
        view_name = view_name or dview_prefix + cube.name

        table = sqlalchemy.Table(view_name,
                                 self.metadata,
                                 autoload=False,
                                 schema=schema)

        preparer = self.engine.dialect.preparer(self.engine.dialect)
        full_name = preparer.format_table(table)

        if mapper.fact_name == view_name and schema == mapper.schema:
            raise WorkspaceError(
                "target denormalized view is the same as source fact table")

        if table.exists():
            if not replace:
                raise WorkspaceError("View or table %s (schema: %s) already exists." % \
                                   (view_name, schema))

            inspector = sqlalchemy.engine.reflection.Inspector.from_engine(
                self.engine)
            view_names = inspector.get_view_names(schema=schema)

            if view_name in view_names:
                # Table reflects a view
                drop_statement = "DROP VIEW %s" % full_name
                self.engine.execute(drop_statement)
            else:
                # Table reflects a table
                table.drop(checkfirst=False)

        if materialize:
            create_stat = "CREATE TABLE"
        else:
            create_stat = "CREATE OR REPLACE VIEW"

        statement = "%s %s AS %s" % (create_stat, full_name, str(statement))
        self.logger.info("creating denormalized view %s (materialized: %s)" \
                                            % (full_name, materialize))
        # print("SQL statement:\n%s" % statement)
        self.engine.execute(statement)

        if create_index:
            if not materialize:
                raise WorkspaceError(
                    "Index can be created only on a materialized view")

            # self.metadata.reflect(schema = schema, only = [view_name] )
            table = sqlalchemy.Table(view_name,
                                     self.metadata,
                                     autoload=True,
                                     schema=schema)
            self.engine.reflecttable(table)

            for attribute in key_attributes:
                label = attribute.ref()
                self.logger.info("creating index for %s" % label)
                column = table.c[label]
                name = "idx_%s_%s" % (view_name, label)
                index = sqlalchemy.schema.Index(name, column)
                index.create(self.engine)

        return statement