private readData()

in src/dataViewBuilder/matrixBuilder.ts [447:571]


    private readData(
        rowHierarchyMetadata: HierarchyMetadata,
        columnHierarchyMetadata: HierarchyMetadata,
        measureMetadata: LevelMetadata | undefined,
        table: DataTable): powerbi.DataViewMatrix {

        const columnLevels = columnHierarchyMetadata.levels.map((level) => ({
            sources: level.sources,
        }));

        // if (measureMetadata)
        //     columnLevels.push({ sources: measureMetadata.sources });

        const matrix: powerbi.DataViewMatrix = {
            columns: {
                levels: columnLevels,
                root: {}
            },
            rows: {
                levels: rowHierarchyMetadata.levels.map((level) => ({
                    sources: level.sources,
                })),
                root: {},
            },
            valueSources: measureMetadata?.sources ?? [],
        };

        // Fill in empty children array for dimensions that don't have any grouping
        if (matrix.columns.levels.length === 0)
            matrix.columns.root.children = [];
        if (matrix.rows.levels.length === 0)
            matrix.rows.root.children = [];

        // We do two passes over the data table,
        // The first pass fills in the group instances of row & column hierarchies.
        // The second pass fills in the measure values. We need to do this as a second pass
        // because the index of the measure value will depend on the column hierarchy.
        // See the doc for findValueInHierarchy

        // Pass 1
        table.forEachRow((row) => {
            this.ensureValueInHierarchy(
                columnHierarchyMetadata,
                matrix.columns.root,
                row,
                true,  // explicitly sort the column data
            );
            this.ensureValueInHierarchy(
                rowHierarchyMetadata,
                matrix.rows.root,
                row,
                false,  // rows are sorted in the order they appear in the data
            );
        });

        if (measureMetadata) {
            // We ignore the last level of values, we only want to find a matching path up to, but not including, the measure nodes
            const hierarchyDepth = columnLevels.length - 2;

            // Pass 1.5, fill in intersections with null values
            const leafCount = this.findValueInHierarchy(
                (_node) => false,
                matrix.columns.root,
                hierarchyDepth,
            );
            this.forEachLeaf(
                matrix.rows.root,
                (leafNode) => {
                    leafNode.values =
                        range(0, leafCount)
                            .reduce((bag, i) => {
                                // @ts-ignore: No Implicit Any
                                bag[i] = <powerbi.DataViewMatrixNodeValue>{ value: null };
                                return bag;
                            },
                                {});
                }
            );

            // Pass 2
            table.forEachRow((row) => {
                // Find the leaf node in the column heirarchy and calculate the index
                const columnValues: any[][] = [];
                for (const level of columnHierarchyMetadata.levels) {
                    columnValues.push(level.tableIndices.map((index) => row[index]));
                }

                const isMatch = (node: powerbi.DataViewMatrixNode, level: number) => {
                    return this.sequenceEqual(columnValues[level], node.levelValues, (value, levelValue) => value === levelValue.value);
                };

                const indexOfColumnLeaf = this.findValueInHierarchy(isMatch, matrix.columns.root, hierarchyDepth);
                // debug.assert((leafCount === 0 && indexOfColumnLeaf === 0) || indexOfColumnLeaf < leafCount, 'could not find leaf ');

                // Find the leaf node in the row hierarchy matching this data row
                // TODO: find? we shouldn't be adding nodes here
                const rowNode = this.ensureValueInHierarchy(
                    rowHierarchyMetadata,
                    matrix.rows.root,
                    row,
                    false,
                );

                if (rowNode.values == null)
                    rowNode.values = {};

                for (let i = 0; i < measureMetadata.tableIndices.length; i++) {
                    const tableIdx = measureMetadata.tableIndices[i];
                    const measureValue = row[tableIdx];

                    let valueNode: powerbi.DataViewMatrixNodeValue = {
                        value: measureValue,
                    };

                    // We omit the valueSourceIndex when it is 0
                    if (i !== 0)
                        valueNode.valueSourceIndex = i;

                    rowNode.values[indexOfColumnLeaf + i] = valueNode;
                }
            });
        }

        return matrix;
    }