NebulaGraph Python Client 5.3.0
Loading...
Searching...
No Matches
base_executor.py
1# Copyright 2025 vesoft-inc
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import json
16import logging
17from abc import abstractmethod
18from datetime import date
19from typing import Any, Callable, Dict, Mapping, Optional, Type, Union
20
21from minijinja import render_str
22
23from nebulagraph_python.client.logger import debug_flag
24from nebulagraph_python.error import InternalError
25from nebulagraph_python.py_data_types import NVector, TargetPrimitiveType, TargetType
26from nebulagraph_python.result_set import ResultSet
27
28logger = logging.getLogger(__name__)
29
30
31def unwrap_value(v: Union[TargetType, TargetPrimitiveType]) -> str:
32 """Convert python value to GQL string"""
33
34 def from_vector(x: NVector):
35 return f"vector<{x.dimension}, float>([{', '.join(str(v) for v in x.values)}])"
36
37 mapping: Dict[
38 Type[Union[TargetType, TargetPrimitiveType]], Callable[[Any], str]
39 ] = {
40 str: lambda x: json.dumps(x, ensure_ascii=False).replace("'", "\\'"),
41 int: str,
42 float: str,
43 bool: lambda x: str(x).upper(),
44 list: lambda x: "[%s]" % ", ".join(unwrap_value(i) for i in x),
45 dict: lambda x: "{ %s }"
46 % ", ".join(f"`{k}`: {unwrap_value(v)}" for k, v in x.items()),
47 type(None): lambda x: "NULL",
48 NVector: from_vector,
49 date: lambda x: f'date("{x.strftime("%Y-%m-%d")}")',
50 }
51 try:
52 return mapping[type(v)](v)
53 except KeyError as e:
54 raise InternalError(f"Unsupported value type: {type(v)}") from e
55
56
57def unwrap_props(props: Mapping[str, Any]):
58 return ", ".join(f"`{k}`: {unwrap_value(v)}" for k, v in props.items())
59
60
62 @abstractmethod
63 async def execute(
64 self,
65 statement: str,
66 *,
67 timeout: Optional[float] = None,
68 do_ping: bool = False,
69 ) -> ResultSet:
70 pass
71
72 async def execute_py(
73 self,
74 stmt: str,
75 stmt_args: Optional[Dict[str, Any]] = None,
76 *,
77 timeout: Optional[float] = None,
78 do_ping: bool = False,
79 ) -> ResultSet:
80 """This is an util method to execute a statement and raise an error if the statement fails,
81
82 it will render the stmt_template with the stmt_args using Jinja2,
83
84 and then execute the statement, raise an error if the statement fails.
85 """
86
87 if stmt_args is not None:
88 unwrap_args = {k: unwrap_value(v) for k, v in stmt_args.items()}
89 stmt = render_str(stmt, **unwrap_args)
90 logger.debug("Executing NebulaGraph statement:\n%s", stmt)
91 return await self.execute(stmt, timeout=timeout, do_ping=do_ping)
92
94 self,
95 query: str,
96 style: str = "table",
97 width: Optional[int] = None,
98 min_width: int = 8,
99 max_width: Optional[int] = None,
100 padding: int = 1,
101 collapse_padding: bool = False,
102 ) -> None:
103 """Execute a query and print the results in a formatted way using rich
104
105 Args:
106 ----
107 query: The nGQL query to execute
108 style: Output style - either "table" (default) or "rows"
109 width: Fixed width for all columns. If None, width will be auto-calculated
110 min_width: Minimum width of columns when using table style
111 max_width: Maximum width of columns. If None, no maximum is enforced
112 padding: Number of spaces around cell contents in table style
113 collapse_padding: Reduce padding when cell contents are too wide
114
115 Raises:
116 ------
117 Exception if execution fails
118
119 """
120 try:
121 result = await self.execute(query)
122 result.print(
123 style=style,
124 width=width,
125 min_width=min_width,
126 max_width=max_width,
127 padding=padding,
128 collapse_padding=collapse_padding,
129 )
130 except Exception as e:
131 from rich.console import Console
132 from rich.traceback import Traceback
133
134 console = Console()
135 console.print(f"[bold red]Error executing query:[/bold red] {e!s}")
136 if debug_flag:
137 console.print(Traceback.from_exception(type(e), e, e.__traceback__))
138
139 async def pq(self, query: str, **kwargs):
140 """Print query result using rich"""
141 await self.print_query_result(query, **kwargs)
142
143
145 @abstractmethod
146 def execute(
147 self,
148 statement: str,
149 *,
150 timeout: Optional[float] = None,
151 do_ping: bool = False,
152 ) -> ResultSet:
153 pass
154
156 self,
157 stmt: str,
158 stmt_args: Optional[Dict[str, Any]] = None,
159 *,
160 timeout: Optional[float] = None,
161 do_ping: bool = False,
162 ) -> ResultSet:
163 """This is an util method to execute a statement and raise an error if the statement fails,
164
165 it will render the stmt_template with the stmt_args using Jinja2,
166
167 and then execute the statement, raise an error if the statement fails.
168 """
169
170 if stmt_args is not None:
171 unwrap_args = {k: unwrap_value(v) for k, v in stmt_args.items()}
172 stmt = render_str(stmt, **unwrap_args)
173 logger.debug("Executing NebulaGraph statement:\n%s", stmt)
174 return self.execute(stmt, timeout=timeout, do_ping=do_ping)
175
177 self,
178 query: str,
179 style: str = "table",
180 width: Optional[int] = None,
181 min_width: int = 8,
182 max_width: Optional[int] = None,
183 padding: int = 1,
184 collapse_padding: bool = False,
185 ) -> None:
186 """Execute a query and print the results in a formatted way using rich
187
188 Args:
189 ----
190 query: The nGQL query to execute
191 style: Output style - either "table" (default) or "rows"
192 width: Fixed width for all columns. If None, width will be auto-calculated
193 min_width: Minimum width of columns when using table style
194 max_width: Maximum width of columns. If None, no maximum is enforced
195 padding: Number of spaces around cell contents in table style
196 collapse_padding: Reduce padding when cell contents are too wide
197
198 Raises:
199 ------
200 Exception if execution fails
201
202 """
203 try:
204 result = self.execute(query)
205 result.print(
206 style=style,
207 width=width,
208 min_width=min_width,
209 max_width=max_width,
210 padding=padding,
211 collapse_padding=collapse_padding,
212 )
213 except Exception as e:
214 from rich.console import Console
215 from rich.traceback import Traceback
216
217 console = Console()
218 console.print(f"[bold red]Error executing query:[/bold red] {e!s}")
219 if debug_flag:
220 console.print(Traceback.from_exception(type(e), e, e.__traceback__))
221
222 def pq(self, query: str, **kwargs):
223 """Print query result using rich"""
224 self.print_query_result(query, **kwargs)
ResultSet execute_py(self, str stmt, Optional[Dict[str, Any]] stmt_args=None, *Optional[float] timeout=None, bool do_ping=False)
None print_query_result(self, str query, str style="table", Optional[int] width=None, int min_width=8, Optional[int] max_width=None, int padding=1, bool collapse_padding=False)
ResultSet execute(self, str statement, *Optional[float] timeout=None, bool do_ping=False)
ResultSet execute_py(self, str stmt, Optional[Dict[str, Any]] stmt_args=None, *Optional[float] timeout=None, bool do_ping=False)
None print_query_result(self, str query, str style="table", Optional[int] width=None, int min_width=8, Optional[int] max_width=None, int padding=1, bool collapse_padding=False)
ResultSet execute(self, str statement, *Optional[float] timeout=None, bool do_ping=False)