1
1
"""Query data in InfluxDB 3."""
2
-
2
+ import asyncio
3
3
# coding: utf-8
4
4
import json
5
5
6
6
from pyarrow .flight import FlightClient , Ticket , FlightCallOptions , FlightStreamReader
7
+
7
8
from influxdb_client_3 .version import USER_AGENT
8
9
9
10
@@ -121,19 +122,28 @@ def __init__(self,
121
122
"""
122
123
self ._token = token
123
124
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 ]
124
131
self ._proxy = proxy
132
+ from influxdb_client_3 import _merge_options as merge_options
125
133
if options :
126
134
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 )
128
141
if options .tls_root_certs :
129
142
self ._flight_client_options ["tls_root_certs" ] = options .tls_root_certs
130
143
if options .proxy :
131
144
self ._proxy = options .proxy
132
145
if options .tls_verify is not None :
133
146
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
- ]
137
147
if self ._proxy :
138
148
self ._flight_client_options ["generic_options" ].append (("grpc.http_proxy" , self ._proxy ))
139
149
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):
152
162
It should be a ``dictionary`` of key-value pairs.
153
163
:return: The query result in the specified mode.
154
164
"""
155
- from influxdb_client_3 import polars as has_polars , _merge_options as merge_options
156
165
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 )
177
167
178
- ticket = Ticket (json .dumps (ticket_data ).encode ('utf-8' ))
179
168
flight_reader = self ._do_get (ticket , _options )
180
169
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 :
181
204
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
187
210
}
188
211
if has_polars :
189
212
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 )
192
215
193
216
return mode_func () if callable (mode_func ) else mode_func
194
217
except Exception as e :
195
218
raise e
196
219
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
+
197
247
def _do_get (self , ticket : Ticket , options : FlightCallOptions = None ) -> FlightStreamReader :
198
248
return self ._flight_client .do_get (ticket , options )
199
249
0 commit comments