UNPKG

groupster-engine

Version:

Randomly group objects using do-group and don't-group rules.

84 lines (73 loc) 2.61 kB
import Joi from 'joi-browser'; import { uniq, difference } from 'lodash'; import { IDsSchema, GroupSizesSchema, RulesSchema } from './schema'; // Verify parameters conform to schema export function validateSchemas(IDs, groupSizes, rules) { [[IDs, IDsSchema], [groupSizes, GroupSizesSchema], [rules, RulesSchema]] .forEach(pair => Joi.assert(...pair)); } // Verify group sizes add up to IDs count export function validateGroupSizes(IDs, groupSizes) { const totalOfGroupSizes = groupSizes.reduce((sum, size) => sum + size, 0); if (IDs.length !== totalOfGroupSizes) { throw new Error(`Total of group sizes (${totalOfGroupSizes}) did not equal member count (${IDs.length}).`); } } // Verify Ids are unique export function validateIds(IDs) { const uniqueIds = uniq(IDs); if (IDs.length !== uniqueIds.length) { const duplicateIds = difference(IDs, uniqueIds); throw new Error(`One or more IDs had the same ID: [${duplicateIds.join(', ')}]`); } } // Build rules map export default function buildRuleMap(IDs, groupSizes, rules) { validateSchemas(IDs, groupSizes, rules); validateIds(IDs); validateGroupSizes(IDs, groupSizes); const ruleMap = IDs.reduce((acc, id) => ({ ...acc, [id]: {} }), {}); if (rules) { // For each rule... rules.forEach(rule => { const { shouldGroup, IDs: ruleIDs } = rule; // Ensure ruleIDs correspond to actual IDs ruleIDs.forEach(ruleID => { if (!ruleMap[ruleID]) { throw new Error(`Rule ${JSON.stringify(rule)} contained id not present in base IDs array ${JSON.stringify(Object.keys(ruleMap))}`); } }); // For each pairing within the rule's IDs... for (let i = 0; i < ruleIDs.length - 1; i += 1) { for (let j = i + 1; j < ruleIDs.length; j += 1) { const m1 = ruleIDs[i]; const m2 = ruleIDs[j]; // Check that rule doesn't conflict with previous rules const ruleExisted = ruleMap[m1][m2] !== undefined; if (ruleExisted && ((!shouldGroup && ruleMap[m1][m2]) || (shouldGroup && ruleMap[m1][m2] === false))) { throw new Error(`Rules conflicted, the following IDs were instructed to both group and not group with eachother: [${m1}, ${m2}]`); } // And add rule into map (both ways) ruleMap[m1][m2] = shouldGroup; ruleMap[m2][m1] = shouldGroup; } } }); } return ruleMap; } // { // a: { // b: true, // c: true, // }, // b: { // a: true, // c: false, // }, // c: { // a: true, // b: false, // }, // d: {}, // }