From 186fffc12b525157dd8e7f2859b30747d54a7919 Mon Sep 17 00:00:00 2001 From: Caden Buckhalt Date: Mon, 2 Dec 2024 16:14:51 -0600 Subject: [PATCH 1/3] fix: node filtering edge rules also filtering out edges --- lib/network-query/rules.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/network-query/rules.js b/lib/network-query/rules.js index af637ae4f..22b25487e 100644 --- a/lib/network-query/rules.js +++ b/lib/network-query/rules.js @@ -62,6 +62,7 @@ const singleNodeRule = // Reduce edges to any that match the rule // Filter nodes by the resulting edges +// Return the filtered nodes and the original edges (as they are only used to filter nodes) const edgeRule = ({ attribute, operator, type, value: other }) => (nodes, edges) => { @@ -95,7 +96,7 @@ const edgeRule = return { nodes: filteredNodes, - edges: filteredEdges, + edges, }; }; From a49928542f6aed63d7d936ebabdc2c80a230d778 Mon Sep 17 00:00:00 2001 From: Caden Buckhalt Date: Mon, 2 Dec 2024 16:33:41 -0600 Subject: [PATCH 2/3] update tests to expect all edges should not expect filtered edges for node filtering --- lib/network-query/__tests__/filter.test.js | 4 ++-- lib/network-query/__tests__/rules.test.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/network-query/__tests__/filter.test.js b/lib/network-query/__tests__/filter.test.js index b26ac6b79..bfa40d2a4 100644 --- a/lib/network-query/__tests__/filter.test.js +++ b/lib/network-query/__tests__/filter.test.js @@ -262,7 +262,7 @@ describe('filter', () => { (node) => node[entityAttributesProperty].name, ); expect(names).toEqual(['William', 'Theodore', 'Rufus']); - expect(result.edges.length).toEqual(3); + expect(result.edges.length).toEqual(4); }); it.todo('can filter edges by type (not)'); @@ -282,7 +282,7 @@ describe('filter', () => { const filter = getFilter(filterConfig); const result = filter(network); - expect(result.edges.length).toEqual(2); + expect(result.edges.length).toEqual(4); }); }); }); diff --git a/lib/network-query/__tests__/rules.test.js b/lib/network-query/__tests__/rules.test.js index f3b62d0ef..0a1bdea4f 100644 --- a/lib/network-query/__tests__/rules.test.js +++ b/lib/network-query/__tests__/rules.test.js @@ -232,7 +232,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore', 'Rufus']); - expect(edges.length).toEqual(2); + expect(edges.length).toEqual(4); }); it('NOT_EXISTS', () => { @@ -248,7 +248,7 @@ describe('rules', () => { 'Phone Box', 'Pillar Box', ]); - expect(edges.length).toEqual(2); + expect(edges.length).toEqual(4); }); describe('attribute rules', () => { @@ -268,7 +268,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore']); - expect(edges.length).toEqual(1); + expect(edges.length).toEqual(4); }); it('NOT', () => { @@ -281,7 +281,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['Theodore', 'Rufus']); - expect(edges.length).toEqual(1); + expect(edges.length).toEqual(4); }); it('GREATER_THAN', () => { @@ -294,7 +294,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore']); - expect(edges.length).toEqual(1); + expect(edges.length).toEqual(4); }); it('LESS_THAN', () => { @@ -307,7 +307,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['Theodore', 'Rufus']); - expect(edges.length).toEqual(1); + expect(edges.length).toEqual(4); }); it('GREATER_THAN_OR_EQUAL', () => { @@ -320,7 +320,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore']); - expect(edges.length).toEqual(1); + expect(edges.length).toEqual(4); }); it('LESS_THAN_OR_EQUAL', () => { @@ -333,7 +333,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['Theodore', 'Rufus']); - expect(edges.length).toEqual(1); + expect(edges.length).toEqual(4); }); }); }); From aba00e70cd1e2465c01ca309929182ac9ec7333f Mon Sep 17 00:00:00 2001 From: Caden Buckhalt Date: Tue, 3 Dec 2024 14:50:07 -0600 Subject: [PATCH 3/3] filter orphaned edges, add test case, fix existing tests --- lib/network-query/__tests__/filter.test.js | 21 ++++++++++++++++++++- lib/network-query/__tests__/rules.test.js | 16 ++++++++-------- lib/network-query/filter.js | 2 +- lib/network-query/rules.js | 16 ++++++++++++---- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/lib/network-query/__tests__/filter.test.js b/lib/network-query/__tests__/filter.test.js index bfa40d2a4..d0d84f139 100644 --- a/lib/network-query/__tests__/filter.test.js +++ b/lib/network-query/__tests__/filter.test.js @@ -245,7 +245,26 @@ describe('filter', () => { }); describe('Edges', () => { - it('can filter edges by type', () => { + + it('can filter nodes by edge and trim orphaned edges', () => { + const filterConfig = { + rules: [ + generateRuleConfig('edge', { + type: 'band', + operator: operators.EXISTS, + }), + ] + }; + + const filter = getFilter(filterConfig); + const result = filter(network); + const names = result.nodes.map( + (node) => node[entityAttributesProperty].name, + ) + expect(names).toEqual(['William', 'Theodore']); + expect(result.edges.length).toEqual(2); // should be band edge AND friend edge between valid nodes + }) + it('can filter nodes by edge type', () => { const filterConfig = { rules: [ generateRuleConfig('edge', { diff --git a/lib/network-query/__tests__/rules.test.js b/lib/network-query/__tests__/rules.test.js index 0a1bdea4f..85448a702 100644 --- a/lib/network-query/__tests__/rules.test.js +++ b/lib/network-query/__tests__/rules.test.js @@ -232,7 +232,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore', 'Rufus']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(3); }); it('NOT_EXISTS', () => { @@ -248,7 +248,7 @@ describe('rules', () => { 'Phone Box', 'Pillar Box', ]); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(3); }); describe('attribute rules', () => { @@ -268,7 +268,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(1); }); it('NOT', () => { @@ -281,7 +281,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['Theodore', 'Rufus']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(2); }); it('GREATER_THAN', () => { @@ -294,7 +294,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(1); }); it('LESS_THAN', () => { @@ -307,7 +307,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['Theodore', 'Rufus']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(2); }); it('GREATER_THAN_OR_EQUAL', () => { @@ -320,7 +320,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['William', 'Theodore']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(1); }); it('LESS_THAN_OR_EQUAL', () => { @@ -333,7 +333,7 @@ describe('rules', () => { const { nodeNames, edges } = runRuleHelper(ruleConfig); expect(nodeNames).toEqual(['Theodore', 'Rufus']); - expect(edges.length).toEqual(4); + expect(edges.length).toEqual(2); }); }); }); diff --git a/lib/network-query/filter.js b/lib/network-query/filter.js index de3a31e24..8ae79b114 100644 --- a/lib/network-query/filter.js +++ b/lib/network-query/filter.js @@ -2,7 +2,7 @@ import { entityPrimaryKeyProperty } from '@codaco/shared-consts'; import { getRule } from './rules'; // remove orphaned edges -const trimEdges = (network) => { +export const trimEdges = (network) => { const uids = new Set( network.nodes.map((node) => node[entityPrimaryKeyProperty]), ); diff --git a/lib/network-query/rules.js b/lib/network-query/rules.js index 22b25487e..35b030ee3 100644 --- a/lib/network-query/rules.js +++ b/lib/network-query/rules.js @@ -2,8 +2,8 @@ import { entityAttributesProperty, entityPrimaryKeyProperty, } from '@codaco/shared-consts'; -import { operators } from './predicate'; -import predicate from './predicate'; +import { trimEdges } from './filter'; +import predicate, { operators } from './predicate'; const singleEdgeRule = ({ type, attribute, operator, value: other }) => @@ -62,7 +62,8 @@ const singleNodeRule = // Reduce edges to any that match the rule // Filter nodes by the resulting edges -// Return the filtered nodes and the original edges (as they are only used to filter nodes) +// Remove orphaned edges from original edges +// Return filtered nodes and valid, non-orphaned edges const edgeRule = ({ attribute, operator, type, value: other }) => (nodes, edges) => { @@ -94,9 +95,16 @@ const edgeRule = edgeMap.includes(node[entityPrimaryKeyProperty]), ); + // remove orphaned edges + + const validEdges = trimEdges({ + nodes: filteredNodes, + edges: edges, + }).edges; + return { nodes: filteredNodes, - edges, + edges: validEdges, }; };