@healthcatalyst/mdx-rxjs
TypeScript icon, indicating that this package has built-in type declarations

0.0.8-beta • Public • Published

mdx-rxjs

API for posting multidimensional expression (MDX) queries using rxjs.

Initializing the API

Create an Instance

const cube = 'SomeCube';
const catalog = 'SomeCatalog';
const url = 'http://localhost/olap/';

const mdx = new Mdx(cube, new SoapMdxHandler(catalog, url));

As an Angular Service

@Injectable()
export class MdxService extends Mdx {
    constructor() {
        const cube = 'SomeCube';
        const catalog = 'SomeCatalog';
        const url = 'http://localhost/olap/';

        super(cube, new SoapMdxHandler(catalog, url));
    }
}

Tables

One basic use case for MDX queries could be measuring specific facts across one or more dimensions (a.k.a. tables), but still on two axes. Two variations exist for this, getTableRowData and getTableRowDtos. They can both be used to serve the same purpose, but the DTO variation allows you to type your rows using an interface.

See the below examples for some vanilla scenarios:

Get Table Row Data

const someStringAttributeExpression = '[SomeDimension].[SomeString]';
const someNumberAttributeExpression = '[SomeDimension].[SomeNumber]';
const rows = [
  someStringAttributeExpression,
  someNumberAttributeExpression
];

const someMeasureExpressionA = '[Measures].[SomeMeasureA]';
const someMeasureExpressionB = '[Measures].[SomeMeasureB]';
const measures = [
  someMeasureExpressionA,
  someMeasureExpressionB
];

mdx.getTableRowData(measures, rows)
  .subscribe(result => {
    const someStrings = result.rows.map(r => r[someStringAttributeExpression] as string);
    const someNumbers = result.rows.map(r => r[someNumberAttributeExpression] as number);

    const measuresA = result.rows.map(r => r[someMeasureExpressionA] as number);
    const measuresB = result.rows.map(r => r[someMeasureExpressionB] as number);
  });

Get Table Rows as DTOs

interface SomePivot {
  someString: string;
  someNumber: number;

  someMeasureA: number;
  someMeasureB: number;
}

mdx
  .getTableRowDtos<SomePivot>({
    someString: '[SomeDimension].[SomeString]',
    someNumber: '[SomeDimension].[SomeNumber]',

    someMeasureA: '[Measures].[SomeMeasureA]',
    someMeasureB: '[Measures].[SomeMeasureB]'
  })
  .subscribe(result => {
    const someStrings = result.rows.map(r => r.someString);
    const someNumbers = result.rows.map(r => r.someNumber);

    const measuresA = result.rows.map(r => r.someMeasureA);
    const measuresB = result.rows.map(r => r.someMeasureB);
  });

Advanced Querying

Both of the above table functions allow you to provide optional options parameters of type IMdxQueryOptions. These can be used for more advanced scenarios to further qualify the query and/or slicer axis.

Most of these options are also available to other functions as optional parameters.

Filter Options

  • levelExpression: The level expression of the attribute or measure.
  • comparisonOperator?: The operator to be used for comparison in the slicer axis. Must be used in conjunction with the comparisonValue. Possible values include:
    • '<'
    • '<='
    • '<>'
    • '='
    • '>'
    • '>='
  • comparisonValue?: The value to be used for comparison in the slicer axis. Must be used in conjunction with the comparisonOperator.
  • includeAllAggregation?: Whether or not to include all members (which includes the total aggregation), or just the children. Default: false.
  • includeInTotalCount?: Whether or not to include the attribute or measure in the total count. If none are included, the total count will not be calculated. Default false.
  • memberKeys?: Specific values to be selected from the slicer axis. Mutually exclusive with includeAllAggregation.

Sort Options

  • orderBy?: An array of level expressions and sort directions.
    • levelExpression: The level expression of the attribute or measure.
    • sortDirection?: The sort direction, including whether or not to break hierarchy. Possible values include:
      • 'ASC'
      • 'DESC'
      • 'BASC'
      • 'BDESC'
  • skip?: How many rows to skip from the result.
  • top?: How many rows to include in the result.

Virtual Tables (Measures Only)

Another use case of tables may be when you have facts to measure, but don't want to pivot them against any dimensions for that second axis. For this, call getVirtualTableBuilder to queue up some measures under some virtual arrangement, and then post it for their results.

Get Virtual Table Rows

const tableBuilder = mdx.getVirtualTableBuilder<MdxValue>();
tableBuilder.addVirtualRow(row =>
  row
    .addStaticCell('Row 1')
    .addMeasureCell('[Measures].[SomeMeasureA]', data => data.value)
    .addMeasureCell('[Measures].[SomeMeasureB]', data => data.value)
    .addMeasureCell('[Measures].[SomeMeasureC]', data => data.value)
);

tableBuilder.addVirtualRow(row =>
  row
    .addStaticCell('Row 2')
    .addMeasureCell('[Measures].[SomeMeasureD]', data => data.value)
    .addMeasureCell('[Measures].[SomeMeasureE]', data => data.value)
    .addMeasureCell('[Measures].[SomeMeasureF]', data => data.value)
);

tableBuilder.post().subscribe(rows => {
  const staticCell1 = rows[0].cells[0];
  const measureA = rows[0].cells[1];
  const measureB = rows[0].cells[2];
  const measureC = rows[0].cells[3];

  const staticCell2 = rows[1].cells[0];
  const measureD = rows[1].cells[1];
  const measureE = rows[1].cells[2];
  const measureF = rows[1].cells[3];
});

Dimensions

To query just your dimensions, consider the counterparts getDimensionData and getDimensionDtos. Just as for tables, the DTO variation allows you to type your dimension using an interface.

See the vanilla examples below:

Get Dimension Data

const someStringAttributeExpression = '[SomeDimension].[SomeString]';
const someNumberAttributeExpression = '[SomeDimension].[SomeNumber]';

mdx.getDimensionData([
    someStringAttributeExpression,
    someNumberAttributeExpression
  ])
  .subscribe(result => {
    const someStrings = result.rows.map(r => r.data[someStringAttributeExpression] as string);
    const someNumbers = result.rows.map(r => r.data[someNumberAttributeExpression] as number);
  });

Get Dimensions as DTOs

interface SomeDimension {
  someString: string;
  someNumber: number;
}

mdx
  .getDimensionDtos<SomeDimension>({
    someString: '[SomeDimension].[SomeString]',
    someNumber: '[SomeDimension].[SomeNumber]'
  })
  .subscribe(result => {
    const someStrings = result.rows.map(r => r.data.someString);
    const someNumbers = result.rows.map(r => r.data.someNumber);
  });

Dimension Options

In addition to the filter and sorting options used for tables, dimension queries can also be qualified with the below:

  • measures?: An array of level expressions by which to measure the isNonEmpty property that's returned with each row.
  • type?: An indicator that determines the behavior followed when defining measures. Possible values include:
    • 'all'
    • 'empty'
    • 'nonEmpty'

Charts

In order to make it easy to adapt data to charts, the getChartData function was also provided, including a few new config options. This can be used when you want to keep your measures apart in distinct series of data. Conversely, if you need to represent them as series and tables, take a look at the zip function on the returned chart.

Here's the vanilla example:

Get Chart Data

interface Series {
  type: string;
  data: number[];
  name: string;
  measure: string;
}

const someMeasureExpressionA = '[Measures].[SomeMeasureA]';
const someMeasureExpressionB = '[Measures].[SomeMeasureB]';

mdx
  .getChartData({
    measures: [someMeasureExpressionA, someMeasureExpressionB],
    xAxisLevelExpression: '[SomeDimension].[SomeString]'
  })
  .subscribe(chart => {
    const lines = chart.map<Series>((data, name, measure) => ({
      type: 'line',
      data: data,
      name: name,
      measure: measure
    }));
  });

Chart Config

  • measures: The measures that will expand across the y-axis.
  • xAxisLevelExpression: The attribute that will expand across the x-axis. This will also determine the name of each series.
  • groupByLevelExpression?: The dimension by which to group individual series within a series group.

Readme

Keywords

none

Package Sidebar

Install

npm i @healthcatalyst/mdx-rxjs

Weekly Downloads

6

Version

0.0.8-beta

License

Apache-2.0

Unpacked Size

887 kB

Total Files

83

Last publish

Collaborators

  • hcvsadmin
  • health-catalyst
  • corykon
  • afrueh
  • bthuganator
  • jacerm
  • isaaclyman
  • phess123
  • aknowles