Skip to content

Commit

Permalink
[resotocore][feat] Allow history search with multiple change types (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
aquamatthias authored Feb 6, 2024
1 parent 6318aa1 commit cfd8e29
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 17 deletions.
23 changes: 17 additions & 6 deletions resotocore/resotocore/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ def args_info(self) -> ArgsInfo:
help_text="type of change",
expects_value=True,
possible_values=[e.value for e in list(HistoryChange)],
can_occur_multiple_times=True,
),
ArgInfo(expects_value=True, value_hint="search"),
]
Expand Down Expand Up @@ -1391,7 +1392,7 @@ def parse_known(arg: str) -> Tuple[Dict[str, Any], str]:
parser.add_argument("--history", dest="history", default=None, action="store_true")
parser.add_argument("--after", dest="after", default=None)
parser.add_argument("--before", dest="before", default=None)
parser.add_argument("--change", dest="change", default=None)
parser.add_argument("--change", dest="change", action="append", default=[])
parser.add_argument("--at", dest="at", default=None)
try:
# try to parse as many arguments as possible
Expand All @@ -1408,12 +1409,20 @@ def parse_known(arg: str) -> Tuple[Dict[str, Any], str]:
@staticmethod
def argument_string(args: Dict[str, Any]) -> str:
result = []

def render_flag(name: str, value: Any) -> None:
result.append(f"--{name}")
if value is not True:
result.append(f"'{value}'") # put the value into single quotes to maintain the spaces

for key, value in args.items():
if value is None or value is False:
continue
result.append(f"--{key}")
if value is not True:
result.append(f"'{value}'") # put the value into single quotes to maintain the spaces
if isinstance(value, list):
for v in value:
render_flag(key, v)
else:
render_flag(key, value)
return " ".join(result) + " " if result else ""

def parse(self, arg: Optional[str] = None, ctx: CLIContext = EmptyContext, **kwargs: Any) -> CLISource:
Expand Down Expand Up @@ -1473,8 +1482,10 @@ async def prepare() -> Tuple[CLISourceContext, AsyncIterator[Json]]:
if history:
before = if_set(parsed.get("before"), lambda x: parse_time_or_delta(strip_quotes(x)))
after = if_set(parsed.get("after"), lambda x: parse_time_or_delta(strip_quotes(x)))
change = if_set(parsed.get("change"), lambda x: HistoryChange[strip_quotes(x)])
context = await db.search_history(query_model, change, before, after, with_count=count, timeout=timeout)
changes = [HistoryChange[strip_quotes(x)] for x in parsed.get("change", [])]
context = await db.search_history(
query_model, changes, before, after, with_count=count, timeout=timeout
)
elif query.aggregate:
context = await db.search_aggregation(query_model)
elif with_edges:
Expand Down
12 changes: 6 additions & 6 deletions resotocore/resotocore/db/graphdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ async def search_list(
async def search_history(
self,
query: QueryModel,
change: Optional[HistoryChange] = None,
changes: Optional[List[HistoryChange]] = None,
before: Optional[datetime] = None,
after: Optional[datetime] = None,
with_count: bool = False,
Expand Down Expand Up @@ -691,7 +691,7 @@ async def search_list(
async def search_history(
self,
query: QueryModel,
change: Optional[HistoryChange] = None,
changes: Optional[List[HistoryChange]] = None,
before: Optional[datetime] = None,
after: Optional[datetime] = None,
with_count: bool = False,
Expand All @@ -705,8 +705,8 @@ async def search_history(
raise AttributeError("Fulltext, merge terms and navigation is not supported in history queries!")
# adjust query
term = query.query.current_part.term
if change:
term = term.and_term(P.single("change").eq(change.value))
if changes:
term = term.and_term(P.single("change").is_in([c.value for c in changes]))
if after:
term = term.and_term(P.single("changed_at").gt(utc_str(after)))
if before:
Expand Down Expand Up @@ -1767,7 +1767,7 @@ async def search_list(
async def search_history(
self,
query: QueryModel,
change: Optional[HistoryChange] = None,
changes: Optional[List[HistoryChange]] = None,
before: Optional[datetime] = None,
after: Optional[datetime] = None,
with_count: bool = False,
Expand All @@ -1776,7 +1776,7 @@ async def search_history(
) -> AsyncCursorContext:
counters, context = query.query.analytics()
await self.event_sender.core_event(CoreEvent.HistoryQuery, context, **counters)
return await self.real.search_history(query, change, before, after, with_count, timeout, **kwargs)
return await self.real.search_history(query, changes, before, after, with_count, timeout, **kwargs)

async def search_graph_gen(
self, query: QueryModel, with_count: bool = False, timeout: Optional[timedelta] = None
Expand Down
4 changes: 2 additions & 2 deletions resotocore/resotocore/web/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1213,10 +1213,10 @@ async def query_history(self, request: Request, deps: TenantDependencies) -> Str
graph_db, query_model = await self.graph_query_model_from_request(request, deps)
before = request.query.get("before")
after = request.query.get("after")
change = request.query.get("change")
changes = if_set(request.query.get("change"), lambda x: x.split(","))
async with await graph_db.search_history(
query=query_model,
change=HistoryChange[change] if change else None,
change=[HistoryChange[change] for change in changes] if changes else None,
before=parse_utc(before) if before else None,
after=parse_utc(after) if after else None,
) as cursor:
Expand Down
2 changes: 1 addition & 1 deletion resotocore/tests/resotocore/cli/command_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ async def history_count(cmd: str) -> int:
assert await history_count(f"history --change node_created") == 112
assert await history_count(f"history --change node_updated") == 1
assert await history_count(f"history --change node_deleted") == 0
assert await history_count(f"history --change node_deleted") == 0
assert await history_count(f"history --change node_created --change node_updated --change node_deleted") == 113
assert await history_count(f"history is(foo)") == 10
# combine all selectors
assert await history_count(f"history --after 5m --before {five_min_later} --change node_created is(foo)") == 10
Expand Down
4 changes: 2 additions & 2 deletions resotocore/tests/resotocore/db/graphdb_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ async def nodes(query: Query, **args: Any) -> List[Json]:
assert len(await nodes(Query.by("foo"))) == 10
assert len(await nodes(Query.by("foo"), after=five_min_ago)) == 10
assert len(await nodes(Query.by("foo"), before=five_min_ago)) == 0
assert len(await nodes(Query.by("foo"), after=five_min_ago, change=HistoryChange.node_created)) == 10
assert len(await nodes(Query.by("foo"), after=five_min_ago, change=HistoryChange.node_deleted)) == 0
assert len(await nodes(Query.by("foo"), after=five_min_ago, changes=[HistoryChange.node_created])) == 10
assert len(await nodes(Query.by("foo"), after=five_min_ago, changes=[HistoryChange.node_deleted])) == 0


@mark.asyncio
Expand Down

0 comments on commit cfd8e29

Please sign in to comment.