Backends

Two objects play major role in Cubes backends:

  • aggregation browser – responsible for aggregations, fact listing, dimension member listing
  • store – represents a database connection, shared by multiple browsers

See also

Plugin Reference

Store

Data for cubes are provided by a data store – every cube has one. Stores have to be subclasses of Store for cubes to be able to find them.

../_images/cubes-backend_store.png

Backend data store.

Required methods:

  • __init__(**options) – initialize the store with options. Even if you use named arguments, you have to include the **options.
  • close() – release all resources associated with the store, close database connections
  • default_browser_name – a class variable with browser name that will be created for a cube, if not specified otherwise

A Store class:

from cubes import Store

class MyStore(Store):
    default_browser_name = "my"

    def __init__(self, **options):
        super(MyStore, self).__init__(**options)
        # configure the store here ...

Note

The custom store has to be a subclass of Store so Cubes can find it. The name will be derived from the class name: MyStore will become my, AnotherSQLStore will become another_sql. To explicitly specify a store name, set the __extension_name__ class variable.

Configuration

The store is configured from a slicer.ini file. The store instance receives all options from it’s configuration file section as arguments to the __init__() method.

It is highly recommended that the store provides a class variable named __options__ which is a list of parameter description dictionaries. The list is used for properly configuring the store from end-user tools, such as Slicer. It also provides information about how to convert options into appropriate data types. Example:

class MyStore(Store):
    default_browser_name = "my"

    __options__ = [
        {
            "name": "collection",
            "type": "string",
            "description": "Name of data collection"
        },
        {
            "name": "unfold",
            "type": "bool",
            "description": "Unfold nested structures"
        }
    }

    def __init__(self, collection=None, unfold=Flase, **options):
        super(MyStore, self).__init__(**options)

        self.collection = collection
        self.unfold = unfold

An example configuration for this store would look like:

[store]
type: my
collection: data
unfold: true

Aggregation Browser

Browser retrieves data from a store and works in a context of a cube and locale.

../_images/cubes-backend_browser.png

Backend data store.

Methods to be implemented:

  • __init__(cube, store, locale) – initialize the browser for cube stored in a store and use model and data locale.
  • features() – return a dictionary with browser’s features
  • aggregate(), facts(), fact(), members() – all basic browser actions that take a cell as first argument. See AggregationBrowser for more information.

For example:

class SnowflakeBrowser(AggregationBrowser):

    def __init__(self, cube, store, locale=None, **options):
        super(SnowflakeBrowser, self).__init__(cube, store, locale)
        # browser initialization...

Name of the example store will be snowflake. To explicitly set the browser name set the __extension_name__ class property:

class SnowflakeBrowser(AggregationBrowser):
    __extension_name__ = "sql"

In this case, the browser will be known by the name sql.

Note

The current AggregationBrowser API towards the extension development is provisional and will verylikely change. The change will mostly involve removal of requirements for preparation of arguments and return value.

Aggregate

Implement the provide_aggregate() method with the following arguments:

  • cell – cube cell to be aggregated, alwas a cubes.Cell instance
  • aggregates – list of aggregates to be considered
  • drilldowncubes.Drilldown instance (already prepared)
  • split (optional browser feature) – virtual cell-based dimension to split the aggregation cell into two: within the split cell or outside of the split cell. Can be either None or a cubes.Cell instance
  • page, page_size – page number and size of the page for paginated results
  • order – order specification: list of two-item tuples (attribute, order)
def provide_aggregate(self, cell, aggregates, drilldown, split, order,
                      page, page_size, **options):

    #
    # ... do the aggregation here ...
    #

    result = AggregationResult(cell=cell, aggregates=aggregates)

    # Set the result cells iterator (required)
    result.cells = ...
    result.labels = ...

    # Optional:
    result.total_cell_count = ...
    result.summary = ...

    return result

Note

Don’t override the aggregate() method – it takes care of proper argument conversions and set-up.

Facts

def facts(self, cell=None, fields=None, order=None, page=None,
          page_size=None):

    cell = cell or Cell(self.cube)
    attributes = self.cube.get_attributes(fields)
    order = self.prepare_order(order, is_aggregate=False)

    #
    # ... fetch the facts here ...
    #
    # facts = ... an iterable ...
    #

    result = Facts(facts, attributes)

    return result

Browser and Cube Features

The browser features for all or a particuliar cube (if there are differences) are returned by the cubes.AggregationBrowser.features() method. The method is expected to return at least one key in the dictionary: actions with list of browser actions that the browser supports.

Browser actions are: aggregate, fact, facts, members and cell.

Optional but recommended is setting the list of aggregate_functions – functions for measures computed in the browser’s engine. The other is post_aggregate_functions – list of fucntions used as post-aggregation outside of the browser.

Configuration

The browser is configured by merging:

  • model’s options property
  • cube’s options property
  • store’s configuration options (from slicer.ini)

The browser instance receives the options as parameters to the __init__() method.