diff --git a/resotocore/resotocore/cli/cli.py b/resotocore/resotocore/cli/cli.py index c1b4c4616b..6654fe1ac2 100644 --- a/resotocore/resotocore/cli/cli.py +++ b/resotocore/resotocore/cli/cli.py @@ -394,7 +394,7 @@ async def parse_query(query_arg: str) -> Query: query_part = "all" if query_part.strip() == "" else query_part # section expansion is disabled here: it will happen on the final query after all parts have been combined return await self.dependencies.template_expander.parse_query( - "".join(query_part), None, omit_section_expansion=True, **ctx.env + "".join(query_part), None, omit_section_expansion=True, env=ctx.env ) query: Query = Query.by(AllTerm()) diff --git a/resotocore/resotocore/cli/command.py b/resotocore/resotocore/cli/command.py index 87790ed0a1..13f1bcd91c 100644 --- a/resotocore/resotocore/cli/command.py +++ b/resotocore/resotocore/cli/command.py @@ -51,7 +51,7 @@ from attr import evolve from attrs import define, field from dateutil import parser as date_parser -from parsy import Parser, string +from parsy import Parser, string, ParseError from resotoclient.models import Model as RCModel, Kind as RCKind from resotodatalink import EngineConfig from resotodatalink.batch_stream import BatchStream @@ -140,7 +140,7 @@ NavigateUntilLeaf, IsTerm, ) -from resotocore.query.query_parser import parse_query, aggregate_parameter_parser +from resotocore.query.query_parser import parse_query, aggregate_parameter_parser, predicate_term from resotocore.query.template_expander import tpl_props_p from resotocore.report import BenchmarkConfigPrefix, ReportSeverity from resotocore.report.benchmark_renderer import respond_benchmark_result @@ -170,6 +170,7 @@ ) from resotocore.worker_task_queue import WorkerTask, WorkerTaskName from resotolib.core import CLIEnvelope +from resotolib.durations import parse_duration from resotolib.parse_util import ( double_quoted_or_simple_string_dp, space_dp, @@ -1431,7 +1432,7 @@ def parse_at(x: Optional[str]) -> Optional[datetime]: at: Optional[datetime] = parse_at(parsed.get("at", None)) # all templates are expanded at this point, so we can call the parser directly. - query = parse_query(rest, **ctx.env) + query = parse_query(rest, ctx.env) async def get_db(at: Optional[datetime], graph_name: GraphName) -> Tuple[GraphDB, GraphName]: db_access = self.dependencies.db_access @@ -3904,7 +3905,7 @@ async def put_template(name: str, template_query: str) -> AsyncIterator[str]: # try to render_console the template with dummy values and see if the search can be parsed try: rendered_query = self.dependencies.template_expander.render(template_query, defaultdict(lambda: True)) - parse_query(rendered_query, **ctx.env) + parse_query(rendered_query, ctx.env) except Exception as ex: raise CLIParseError(f"Given template does not define a valid search: {template_query}") from ex await self.dependencies.template_expander.put_template(Template(name, template_query)) @@ -6036,6 +6037,115 @@ def key_fn(node: Json) -> Union[str, Tuple[str, str]]: raise AttributeError("Wrong or insufficient arguments. Execute `help db` to get more information.") +class TimeSeriesCommand(CLICommand): + """ + ``` + timeseries snapshot --name