IReadOnlyCollection <Panel> ValidatePanels(PanelValidationContext ctx) { var validated = new List <Panel>(); foreach (var panel in ctx.Allowed) { var itemCount = panel.SubPanels.SelectMany(x => x.PanelItems).Count(); if (itemCount == 0) { continue; } CheckDateFilter(panel); var validatedSubs = new List <SubPanel>(); foreach (var subpanel in panel.SubPanels) { if (subpanel.PanelItems.Any()) { subpanel.PanelIndex = panel.Index; foreach (var panelItem in subpanel.PanelItems) { panelItem.SubPanelIndex = subpanel.Index; panelItem.PanelIndex = panel.Index; } validatedSubs.Add(subpanel); } } panel.SubPanels = validatedSubs; validated.Add(panel); } return(validated); }
void ValidateItems(PanelValidationContext ctx) { var zipped = ZipContextItems(ctx); foreach (var mapping in zipped) { EnsureSpecializationAlignment(mapping); EnsureValidRecencyFilter(mapping); EnsureValidNumericFilter(mapping); } }
// NOTE(cspital) at this point, we are certain the counts are the same. IEnumerable <PanelItemMapping> ZipContextItems(PanelValidationContext ctx) { var dtos = ctx.Requested .SelectMany(p => p.SubPanels) .SelectMany(s => s.PanelItems) .ToArray(); var mods = ctx.Allowed .SelectMany(p => p.SubPanels) .SelectMany(s => s.PanelItems) .ToArray(); return(dtos.Zip(mods, (dto, mod) => new PanelItemMapping(dto, mod))); }
public PatientCountQuery Validate(PanelValidationContext ctx) { if (!ctx.PreflightPassed) { throw new InvalidOperationException("PreflightCheck failed, nothing to validate."); } ValidateItems(ctx); var panels = ValidatePanels(ctx); return(new PatientCountQuery { QueryId = ctx.QueryId, Panels = panels }); }
public void Obfuscate(ref PatientCount count, PanelValidationContext ctx, DeidentificationOptions opts) { if (!opts.Cohort.Enabled) { return; } // If low cell sizes should be masked and count less than or equal to threshold, set to threshold. if (opts.Cohort.LowCellSizeMasking.Enabled && count.Value <= opts.Cohort.LowCellSizeMasking.Threshold) { count.Value = opts.Cohort.LowCellSizeMasking.Threshold; count.PlusMinus = opts.Cohort.LowCellSizeMasking.Threshold; count.WithinLowCellThreshold = true; return; } // Bail if noise obfuscation not enabled if (!opts.Cohort.Noise.Enabled) { return; } // Ensure that variations of the same query (with concepts and panels moved around but the query logic identical) // always returns the same string of Guid Ids for concepts. var orderedIds = GetDeterministicConceptIdsAsString(ctx.Allowed); // Hash into a byte array. var hashed = md5.ComputeHash(Encoding.UTF8.GetBytes(orderedIds)); // Seed a random number generator from the hash. var generator = new Random(BitConverter.ToInt32(hashed, 0)); // Compute a random shifted value between the lower and upper bounds var shift = 0; while (shift == 0) { shift = generator.Next(opts.Cohort.Noise.LowerBound, opts.Cohort.Noise.UpperBound); } count.Value += shift; count.PlusMinus = Math.Max(Math.Abs(opts.Cohort.Noise.LowerBound), Math.Abs(opts.Cohort.Noise.UpperBound)); }