fix: removeIED - prevent duplicate LNode's#147
Conversation
ec48b77 to
4ef2497
Compare
danyill
left a comment
There was a problem hiding this comment.
Thank you for looking at this and my apologies for the delay in reviewing.
I've flagged just a few small "tidyness", feel free to fix or not as you wish.
| * - Find all LNode references with matching iedName and either set them to None, or delete them if setting them to None would result in duplicate LNode keys within the same scope. | ||
| * The scope is defined as the nearest Bay, VL or Substation parent. | ||
| */ | ||
| describe("without 'preservveNodes' set (default)", () => { |
There was a problem hiding this comment.
| describe("without 'preservveNodes' set (default)", () => { | |
| describe("without 'preserveNodes' set (default)", () => { |
| * The scope is defined as the nearest Bay, VL or Substation parent. | ||
| */ | ||
| describe("without 'preservveNodes' set (default)", () => { | ||
| //TODO consider changing this into a forEach (Substation, VL and Bay) array test. |
There was a problem hiding this comment.
| //TODO consider changing this into a forEach (Substation, VL and Bay) array test. |
It looks like an array already...
|
|
||
| // |
There was a problem hiding this comment.
| // |
Just removing a little crud.
| // Do keep in mind however, the subject SCL has 2 of everything. E.g. S1 & S2 | ||
| ["Bay", "VoltageLevel", "Substation"].forEach((scope) => { | ||
| it(`Within a ${scope}, it sets all bound LNodes to None`, () => { | ||
| //we're using the "duplicates" test file, but by only deleting 1 IED, no duplicates occur (yet). |
There was a problem hiding this comment.
| //we're using the "duplicates" test file, but by only deleting 1 IED, no duplicates occur (yet). | |
| // We're using the "duplicates" test file, but by only deleting 1 IED, no duplicates occur (yet). |
| describe("referenced LNode's", () => { | ||
| /* | ||
| * Here we need to test: | ||
| * - Delete all LNode references found with matching iedName, BUT only inside the substation section (but not inside Private sections). |
There was a problem hiding this comment.
I thought after reading this you would have put an LNode inside a Private section to test this...
|
|
||
| ["Bay", "VoltageLevel", "Substation"].forEach((scope) => { | ||
| it(`Within a ${scope}, it removes 'would-be' duplicates`, () => { | ||
| //we're using the "duplicates" test file, but by only deleting 1 IED, no duplicates occur. |
There was a problem hiding this comment.
| //we're using the "duplicates" test file, but by only deleting 1 IED, no duplicates occur. | |
| // We're using the "duplicates" test file, but by only deleting 1 IED, no duplicates occur. |
| function removeBoundLNodes(ied: Element, name: string): Remove[] { | ||
| return (getLNodesByIedName(ied.ownerDocument, name) ?? []).map(removeLNode); | ||
| } |
There was a problem hiding this comment.
Is it me or is this very verbose? Or is that the AI secret sauce 😉
Why not just?
| function removeBoundLNodes(ied: Element, name: string): Remove[] { | |
| return (getLNodesByIedName(ied.ownerDocument, name) ?? []).map(removeLNode); | |
| } | |
| function removeBoundLNodes(ied: Element, name: string): Remove[] { | |
| return (getLNodesByIedName(ied.ownerDocument, name) ?? []).map( { node: ln };); | |
| } |
| return []; | ||
| } | ||
|
|
||
| const UnboundLNodesByScope = new Map<Element, Set<string>>(); |
There was a problem hiding this comment.
| const UnboundLNodesByScope = new Map<Element, Set<string>>(); | |
| const unboundLNodesByScope = new Map<Element, Set<string>>(); |
Why would this start with a capital letter?
resolves #121
Summary
When multiple IEDs reference the same LNode, removing those IEDs sequentially can result in duplicate LNode
entries with iedName="None". This PR modifies the default behaviour for
removeIED()to delete all LNodes bound to that IED by default, but exposes a new optional flagpreserveLNodeswhich will instead, set the LNodes ideName="None". In cases where setting the iedName="None" would lead to a duplicate LNode, then it is removed instead.E.g.
Changes
tIED/removeIED.ts:removeBoundLNodes()- Default handling for LNodes - find any (public) matching LNodes and create a Remove edit for them.detachLNodeBindings()- if "preserveLNodes flag set, this function is called instead, to instead set the LNodes iedName to "None", taking care to avoid duplicates. Any LNodes encountered which would cause a duplicate, are removed instead.Helper functions
lNodeKey- creates a key for the LNode based on all the other attributes (except iedName) which combined, must be unique.removeLNode()&setLNodeToNone()- oneliner functions, there only to make the code more readable.getLNodeByIedName()used to find the bound LNodes (and the specification LNodes (set ot None))Other Changed files
index.ts: ExportedRemoveIedOptionstypetIED/removeIED.spec.ts: Added tests for LNode removal and opt-in LNode updating behaviourtIED/removeIED.testfile.ts: Added test fixture with duplicate LNode scenario.gitignore: Added IDE and build artifact patternsCode coverage 99.52%