Code Reusability: Extending Cubes
Cube supports the extends
feature, which allows
you to reuse all declared members of a cube. This is a foundation for building
reusable data schemas.
Cubes are represented as JavaScript
objects with such properties as measures, dimensions, and
segments. Extending in Cube works similarly to JavaScript’s prototype
inheritance. Measures, dimensions, and segments are merged as separate objects.
So if the base cube defines measure A
and the extending cube defines measure
B
, the resulting cube will have both measures A
and B
.
The usual pattern is to extract common measures, dimensions, and joins into the base cube and then extend from the base cube. This helps to prevent code duplication and makes code easier to maintain and refactor.
In the example below, the BaseEvents
cube defines the common events measures,
dimensions, and a join to the Users
cube:
It’s important to use the CUBE
reference when referencing properties on the
cube. Not specifying the cube name or using ${BaseEvents}
does not work when
the cube is extended.
cube(`BaseEvents`, {
sql: `SELECT * FROM events`,
joins: {
Users: {
relationship: `belongsTo`,
sql: `${CUBE}.user_id = ${Users.id}`,
},
},
measures: {
count: {
type: `count`,
},
},
dimensions: {
timestamp: {
sql: `time`,
type: `time`,
},
},
});
The ProductPurchases
and PageViews
cubes are extended from BaseEvents
and
define only the specific dimensions – productName
for product purchases and
pagePath
for page views.
cube(`ProductPurchases`, {
sql: `SELECT * FROM product_purchases`,
extends: BaseEvents,
dimensions: {
productName: {
sql: `product_name`,
type: `string`,
},
},
});
cube(`PageViews`, {
sql: `SELECT * FROM page_views`,
extends: BaseEvents,
dimensions: {
pagePath: {
sql: `page_path`,
type: `string`,
},
},
});
If the base cube is using FILTER_PARAMS
in any sql
property, then extending cubes can do one of two things:
Override the
sql
property in each target cube.cube(`ProductPurchases`, { sql: `SELECT * FROM events WHERE {$FILTER_PARAMS.ProductPurchases.timestamp.filter('time')}`, ...
Put all filters inside the base cube and reference all specific cubes filters using
AND
. The unused filters will be rendered to1 = 1
in the SQL query.cube(`BaseEvents`, { sql: `SELECT * FROM events WHERE {$FILTER_PARAMS.BaseEvents.timestamp.filter('time')} AND {$FILTER_PARAMS.ProductPurchases.timestamp.filter('time')} AND {$FILTER_PARAMS.PageViews.timestamp.filter('time')}`, ...
Did you find this page useful?