All files / datamodel/src/operator difference.js

96.55% Statements 28/29
83.33% Branches 5/6
100% Functions 5/5
96.43% Lines 27/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                                                                                            2x 2x 2x 2x 2x 2x 2x 2x 2x     2x         2x 4x 4x 4x                     4x 16x 16x 16x 32x 32x 32x   16x 12x 12x           2x 2x   2x      
import DataModel from '../datamodel';
import { extend2 } from '../utils';
import { rowDiffsetIterator } from './row-diffset-iterator';
import { isArrEqual } from '../utils/helper';
 
/**
 * Difference operation only include rows which are present in the datamodel on which it was called but not on the
 * one passed as argument.
 *
 * @example
 *  //@preamble_start
 *  Promise.all([loadData('/static/cars.json'), loadData('/static/cars-schema.json')]).then(function (params) {
 *      const data = params[0];
 *      const schema = params[1];
 *      const DataModel = muze.DataModel;
 *      const dm = new DataModel(data, schema);
 *  //@preamble_end
 *  // DataModel instance is created from https://www.charts.com/static/cars.json data,
 *  // https://www.charts.com/static/cars-schema.json schema and assigned to variable dm. DataModel is extracted from
 *  // muze namespace and assigned to the variable DataModel.
 *
 *  // Creates a DataModel instance only including USA. Using chained version for conciseness.
 *  const usaMakerDM = dm.select(fields => fields.Origin.value === 'USA');
 *
 *  const difference = DataModel.Operators.difference;
 *  outputDM = difference(dm, usaMakerDM);
 *  //@preamble_start
 *  printDM(outputDM);
 *  });
 *  //@preamble_end
 *
 * @text
 * This is functional version of `difference` operator. `difference` can also be used as
 * {@link /muze/api/datamodel/functional-operator | chained operator}.
 *
 * @public
 * @namespace DataModel
 * @segment Operator
 *
 * @param {DataModel} leftDM Instance of DataModel from which the difference will be calculated. For the notation
 *      (A - B), A is the leftDM
 * @param {DataModel} rightDM Instance of DataModel which will be used to calculate the difference from the leftDM. For
 *      the notation (A - B), B is the rightDM.
 * @return {DataModel} New DataModel instance with the result of the operation
 */
export function difference (dm1, dm2) {
    const hashTable = {};
    const schema = [];
    const schemaNameArr = [];
    const data = [];
    const dm1FieldStore = dm1.getFieldspace();
    const dm2FieldStore = dm2.getFieldspace();
    const dm1FieldStoreFieldObj = dm1FieldStore.fieldsObj();
    const dm2FieldStoreFieldObj = dm2FieldStore.fieldsObj();
    const name = `${dm1FieldStore.name} union ${dm2FieldStore.name}`;
 
   // For union the columns should match otherwise return a clone of the dm1
    Iif (!isArrEqual(dm1._colIdentifier.split(',').sort(), dm2._colIdentifier.split(',').sort())) {
        return null;
    }
 
    // Prepare the schema
    (dm1._colIdentifier.split(',')).forEach((fieldName) => {
        const field = dm1FieldStoreFieldObj[fieldName];
        schema.push(extend2({}, field.schema));
        schemaNameArr.push(field.schema.name);
    });
 
    /**
     * The helper function to create the data.
     *
     * @param {dm} dm - The dm instance for which the data is inserted.
     * @param {Object} fieldsObj - The fieldStore object format.
     * @param {boolean} addData - If true only tuple will be added to the data.
     */
    function prepareDataHelper(dm, fieldsObj, addData) {
        rowDiffsetIterator(dm._rowDiffset, (i) => {
            const tuple = {};
            let hashData = '';
            schemaNameArr.forEach((schemaName) => {
                const value = fieldsObj[schemaName].data[i];
                hashData += `-${value}`;
                tuple[schemaName] = value;
            });
            if (!hashTable[hashData]) {
                if (addData) { data.push(tuple); }
                hashTable[hashData] = true;
            }
        });
    }
 
    // Prepare the data
    prepareDataHelper(dm2, dm2FieldStoreFieldObj, false);
    prepareDataHelper(dm1, dm1FieldStoreFieldObj, true);
 
    return new DataModel(data, schema, { name });
}