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.

  • Put all filters inside the base cube and reference all specific cubes filters using AND. The unused filters will be rendered to 1 = 1 in the SQL query.

Did you find this page useful?