improve diff filters
fix tests expander/compressor filter mangler
This commit is contained in:
@ -1,12 +1,40 @@
|
||||
import { RawReqFilter } from "System";
|
||||
import { ReqFilter } from "System";
|
||||
import { FlatReqFilter } from "./RequestExpander";
|
||||
import { distance } from "./Util";
|
||||
|
||||
export function mergeSimilar(filters: Array<RawReqFilter>): Array<RawReqFilter> {
|
||||
const hasCriticalKeySet = (a: RawReqFilter) => {
|
||||
return a.limit !== undefined || a.since !== undefined || a.until !== undefined;
|
||||
};
|
||||
const canEasilyMerge = filters.filter(a => !hasCriticalKeySet(a));
|
||||
const cannotMerge = filters.filter(a => hasCriticalKeySet(a));
|
||||
return [...(canEasilyMerge.length > 0 ? [simpleMerge(canEasilyMerge)] : []), ...cannotMerge];
|
||||
/**
|
||||
* Keys which can change the entire meaning of the filter outside the array types
|
||||
*/
|
||||
const DiscriminatorKeys = ["since", "until", "limit", "search"];
|
||||
|
||||
export function canMergeFilters(a: any, b: any): boolean {
|
||||
for (const key of DiscriminatorKeys) {
|
||||
if (key in a || key in b) {
|
||||
if (a[key] !== b[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function mergeSimilar(filters: Array<ReqFilter>): Array<ReqFilter> {
|
||||
const ret = [];
|
||||
|
||||
while (filters.length > 0) {
|
||||
const current = filters.shift()!;
|
||||
const mergeSet = [current];
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
const f = filters[i];
|
||||
if (mergeSet.every(v => canMergeFilters(v, f) && distance(v, f) === 1)) {
|
||||
mergeSet.push(filters.splice(i, 1)[0]);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
ret.push(simpleMerge(mergeSet));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -14,7 +42,7 @@ export function mergeSimilar(filters: Array<RawReqFilter>): Array<RawReqFilter>
|
||||
* @param filters
|
||||
* @returns
|
||||
*/
|
||||
export function simpleMerge(filters: Array<RawReqFilter>) {
|
||||
export function simpleMerge(filters: Array<ReqFilter>) {
|
||||
const result: any = {};
|
||||
|
||||
filters.forEach(filter => {
|
||||
@ -31,7 +59,7 @@ export function simpleMerge(filters: Array<RawReqFilter>) {
|
||||
});
|
||||
});
|
||||
|
||||
return result as RawReqFilter;
|
||||
return result as ReqFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,7 +68,7 @@ export function simpleMerge(filters: Array<RawReqFilter>) {
|
||||
* @param smaller
|
||||
* @returns
|
||||
*/
|
||||
export function filterIncludes(bigger: RawReqFilter, smaller: RawReqFilter) {
|
||||
export function filterIncludes(bigger: ReqFilter, smaller: ReqFilter) {
|
||||
const outside = bigger as Record<string, Array<string | number> | number>;
|
||||
for (const [k, v] of Object.entries(smaller)) {
|
||||
if (outside[k] === undefined) {
|
||||
@ -61,3 +89,61 @@ export function filterIncludes(bigger: RawReqFilter, smaller: RawReqFilter) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge expanded flat filters into combined concise filters
|
||||
* @param all
|
||||
* @returns
|
||||
*/
|
||||
export function flatMerge(all: Array<FlatReqFilter>): Array<ReqFilter> {
|
||||
let ret: Array<ReqFilter> = [];
|
||||
|
||||
// to compute filters which can be merged we need to calucate the distance change between each filter
|
||||
// then we can merge filters which are exactly 1 change diff from each other
|
||||
|
||||
function mergeFiltersInSet(filters: Array<FlatReqFilter>) {
|
||||
const result: any = {};
|
||||
|
||||
filters.forEach(f => {
|
||||
const filter = f as Record<string, string | number>;
|
||||
Object.entries(filter).forEach(([key, value]) => {
|
||||
if (!DiscriminatorKeys.includes(key)) {
|
||||
if (result[key] === undefined) {
|
||||
result[key] = [value];
|
||||
} else {
|
||||
result[key] = [...new Set([...result[key], value])];
|
||||
}
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return result as ReqFilter;
|
||||
}
|
||||
|
||||
// reducer, kinda verbose
|
||||
while (all.length > 0) {
|
||||
const currentFilter = all.shift()!;
|
||||
const mergeSet = [currentFilter];
|
||||
|
||||
for (let i = 0; i < all.length; i++) {
|
||||
const f = all[i];
|
||||
|
||||
if (mergeSet.every(a => canMergeFilters(a, f) && distance(a, f) === 1)) {
|
||||
mergeSet.push(all.splice(i, 1)[0]);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
ret.push(mergeFiltersInSet(mergeSet));
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const n = mergeSimilar([...ret]);
|
||||
if (n.length === ret.length) {
|
||||
break;
|
||||
}
|
||||
ret = n;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user