11"""Query data in InfluxDB 3."""
2-
2+ import asyncio
33# coding: utf-8
44import json
55
66from pyarrow .flight import FlightClient , Ticket , FlightCallOptions , FlightStreamReader
7+
78from influxdb_client_3 .version import USER_AGENT
89
910
@@ -121,19 +122,28 @@ def __init__(self,
121122 """
122123 self ._token = token
123124 self ._flight_client_options = flight_client_options or {}
125+ default_user_agent = ("grpc.secondary_user_agent" , USER_AGENT )
126+ if "generic_options" in self ._flight_client_options :
127+ if "grpc.secondary_user_agent" not in dict (self ._flight_client_options ["generic_options" ]).keys ():
128+ self ._flight_client_options ["generic_options" ].append (default_user_agent )
129+ else :
130+ self ._flight_client_options ["generic_options" ] = [default_user_agent ]
124131 self ._proxy = proxy
132+ from influxdb_client_3 import _merge_options as merge_options
125133 if options :
126134 if options .flight_client_options :
127- self ._flight_client_options = options .flight_client_options
135+ self ._flight_client_options = merge_options (self ._flight_client_options ,
136+ None ,
137+ options .flight_client_options )
138+ if ('generic_options' in options .flight_client_options and
139+ 'grpc.secondary_user_agent' in dict (options .flight_client_options ["generic_options" ]).keys ()):
140+ self ._flight_client_options ['generic_options' ].remove (default_user_agent )
128141 if options .tls_root_certs :
129142 self ._flight_client_options ["tls_root_certs" ] = options .tls_root_certs
130143 if options .proxy :
131144 self ._proxy = options .proxy
132145 if options .tls_verify is not None :
133146 self ._flight_client_options ["disable_server_verification" ] = not options .tls_verify
134- self ._flight_client_options ["generic_options" ] = [
135- ("grpc.secondary_user_agent" , USER_AGENT )
136- ]
137147 if self ._proxy :
138148 self ._flight_client_options ["generic_options" ].append (("grpc.http_proxy" , self ._proxy ))
139149 self ._flight_client = FlightClient (connection_string , ** self ._flight_client_options )
@@ -152,48 +162,88 @@ def query(self, query: str, language: str, mode: str, database: str, **kwargs):
152162 It should be a ``dictionary`` of key-value pairs.
153163 :return: The query result in the specified mode.
154164 """
155- from influxdb_client_3 import polars as has_polars , _merge_options as merge_options
156165 try :
157- # Create an authorization header
158- optargs = {
159- "headers" : [(b"authorization" , f"Bearer { self ._token } " .encode ('utf-8' ))],
160- "timeout" : 300
161- }
162- opts = merge_options (optargs , exclude_keys = ['query_parameters' ], custom = kwargs )
163- _options = FlightCallOptions (** opts )
164-
165- #
166- # Ticket data
167- #
168- ticket_data = {
169- "database" : database ,
170- "sql_query" : query ,
171- "query_type" : language
172- }
173- # add query parameters
174- query_parameters = kwargs .get ("query_parameters" , None )
175- if query_parameters :
176- ticket_data ["params" ] = query_parameters
166+ ticket , _options = self ._prepare_query (query , language , database , ** kwargs )
177167
178- ticket = Ticket (json .dumps (ticket_data ).encode ('utf-8' ))
179168 flight_reader = self ._do_get (ticket , _options )
180169
170+ return self ._translate_stream_reader (flight_reader , mode )
171+ except Exception as e :
172+ raise e
173+
174+ async def query_async (self , query : str , language : str , mode : str , database : str , ** kwargs ):
175+ """Query data from InfluxDB asynchronously.
176+
177+ Wraps internal FlightClient.doGet call in its own executor, so that the event_loop will not be blocked.
178+
179+ :param query: The query to execute on the database.
180+ :param language: The query language.
181+ :param mode: The mode to use for the query.
182+ It should be one of "all", "pandas", "polars", "chunk", "reader" or "schema".
183+ :param database: The database to query from.
184+ :param kwargs: Additional arguments to pass to the ``FlightCallOptions headers``.
185+ For example, it can be used to set up per request headers.
186+ :keyword query_parameters: The query parameters to use in the query.
187+ It should be a ``dictionary`` of key-value pairs.
188+ :return: The query result in the specified mode.
189+ """
190+ try :
191+ ticket , options = self ._prepare_query (query , language , database , ** kwargs )
192+ loop = asyncio .get_running_loop ()
193+ _flight_reader = await loop .run_in_executor (None ,
194+ self ._flight_client .do_get , ticket , options )
195+ return await loop .run_in_executor (None , self ._translate_stream_reader ,
196+ _flight_reader ,
197+ mode )
198+ except Exception as e :
199+ raise e
200+
201+ def _translate_stream_reader (self , reader : FlightStreamReader , mode : str ):
202+ from influxdb_client_3 import polars as has_polars
203+ try :
181204 mode_funcs = {
182- "all" : flight_reader .read_all ,
183- "pandas" : flight_reader .read_pandas ,
184- "chunk" : lambda : flight_reader ,
185- "reader" : flight_reader .to_reader ,
186- "schema" : lambda : flight_reader .schema
205+ "all" : reader .read_all ,
206+ "pandas" : reader .read_pandas ,
207+ "chunk" : lambda : reader ,
208+ "reader" : reader .to_reader ,
209+ "schema" : lambda : reader .schema
187210 }
188211 if has_polars :
189212 import polars as pl
190- mode_funcs ["polars" ] = lambda : pl .from_arrow (flight_reader .read_all ())
191- mode_func = mode_funcs .get (mode , flight_reader .read_all )
213+ mode_funcs ["polars" ] = lambda : pl .from_arrow (reader .read_all ())
214+ mode_func = mode_funcs .get (mode , reader .read_all )
192215
193216 return mode_func () if callable (mode_func ) else mode_func
194217 except Exception as e :
195218 raise e
196219
220+ def _prepare_query (self , query : str , language : str , database : str , ** kwargs ):
221+ from influxdb_client_3 import _merge_options as merge_options
222+ # Create an authorization header
223+ optargs = {
224+ "headers" : [(b"authorization" , f"Bearer { self ._token } " .encode ('utf-8' ))],
225+ "timeout" : 300
226+ }
227+ opts = merge_options (optargs , exclude_keys = ['query_parameters' ], custom = kwargs )
228+ _options = FlightCallOptions (** opts )
229+
230+ #
231+ # Ticket data
232+ #
233+ ticket_data = {
234+ "database" : database ,
235+ "sql_query" : query ,
236+ "query_type" : language
237+ }
238+ # add query parameters
239+ query_parameters = kwargs .get ("query_parameters" , None )
240+ if query_parameters :
241+ ticket_data ["params" ] = query_parameters
242+
243+ ticket = Ticket (json .dumps (ticket_data ).encode ('utf-8' ))
244+
245+ return ticket , _options
246+
197247 def _do_get (self , ticket : Ticket , options : FlightCallOptions = None ) -> FlightStreamReader :
198248 return self ._flight_client .do_get (ticket , options )
199249
0 commit comments