Skip to content

Commit

Permalink
[resotocore][fix] Make list column unique (#1826)
Browse files Browse the repository at this point in the history
* [resotocore][fix] Make list column unique

* use name if no path is available
  • Loading branch information
aquamatthias committed Nov 16, 2023
1 parent c6d86fa commit b29356b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
42 changes: 41 additions & 1 deletion resotocore/resotocore/cli/command.py
Expand Up @@ -2535,6 +2535,12 @@ class ListCommand(CLICommand, OutputTransformer):
(["change"], "change"),
(["changed_at"], "changed_at"),
]
default_properties_to_ignore = {
"ancestors.cloud.reported.id",
"ancestors.account.reported.id",
"ancestors.region.reported.id",
"ancestors.zone.reported.id",
}
all_default_props = {
".".join(path)
for path, _ in default_properties_to_show
Expand Down Expand Up @@ -2585,7 +2591,9 @@ def default_props_to_show() -> List[Tuple[List[str], str]]:
# add all predicates the user has queried
if ctx.query:
# add all predicates the user has queried
predicate_names = (p.name for p in ctx.query.visible_predicates)
predicate_names = (
p.name for p in ctx.query.visible_predicates if p.name not in self.default_properties_to_ignore
)
# add sort keys of the last part the user has defined
sort_names = (s.name for s in ctx.query.current_part.sort)
for name in chain(predicate_names, sort_names):
Expand Down Expand Up @@ -2623,7 +2631,39 @@ def parse_props_to_show(props_arg: str) -> List[Tuple[List[str], str]]:
props.append((path, as_name))
return props

def create_unique_names(all_props: List[Tuple[List[str], str]]) -> List[Tuple[List[str], str]]:
result = []
names: Set[str] = set()

def unique_name(path: List[str], current: str) -> str:
# compute the name by parameter path
current = "_".join(path) if path else current
if current not in names:
return current
# compute the name by parameter path and current name
count = 0
attempt = current
while attempt in names:
count += 1
attempt = f"{current}_{count}"
return attempt

for path, name in all_props:
if name in names:
if len(path) <= 1:
name = unique_name(path, name)
elif path[0] in ("ancestors", "descendants"):
name = unique_name([path[1]] + path[3:], name)
elif path[0] in Section.all:
name = unique_name(path[1:], name)
else:
name = unique_name(path, name)
names.add(name)
result.append((path, name))
return result

props_to_show = parse_props_to_show(properties) if properties is not None else default_props_to_show()
props_to_show = create_unique_names(props_to_show)

def fmt_json(elem: Json) -> JsonElement:
if is_node(elem):
Expand Down
13 changes: 10 additions & 3 deletions resotocore/tests/resotocore/cli/command_test.py
Expand Up @@ -583,14 +583,12 @@ async def test_list_command(cli: CLI) -> None:
assert result[0] == ["some_string=hello, some_int=0, node_id=sub_root"]

# List supports csv output
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
result = await cli.execute_cli_command(
f"json {json.dumps(props)} | list --csv a,b,c,d,e,f,non_existent", stream.list
)
assert result[0] == ['"a","b","c","d","e","f","non_existent"', '"a",True,False,"",12,1.234,""']

# List supports markdown output
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
result = await cli.execute_cli_command(
f"json {json.dumps(props)} | list --markdown a,b,c,d,e,f,non_existent", stream.list
)
Expand All @@ -615,10 +613,19 @@ async def test_list_command(cli: CLI) -> None:
]

# List supports only markdown or csv, but not both at the same time
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
with pytest.raises(CLIParseError):
await cli.execute_cli_command(f"json {json.dumps(props)}" " | list --csv --markdown", stream.list)

# List command will make sure to make the column name unique
props = dict(id="123", reported=props, ancestors={"account": {"reported": props}})
result = await cli.execute_cli_command(
f"json {json.dumps(props)} | list reported.a, reported.b as a, reported.c as a, reported.c, "
f"ancestors.account.reported.a, ancestors.account.reported.a, ancestors.account.reported.a as foo",
stream.list,
)
# b as a ==> b, c as a ==> c, c ==> c_1, ancestors.account.reported.a ==> account_a, again ==> _1
assert result[0][0] == "a=a, b=true, c=false, c_1=false, account_a=a, account_a_1=a, foo=a"


@pytest.mark.asyncio
async def test_jq_command(cli: CLI) -> None:
Expand Down

0 comments on commit b29356b

Please sign in to comment.