6
6
7
7
import codecs
8
8
import csv
9
+ from datetime import datetime , timedelta
9
10
from typing import List , Generator , Any
11
+ from pytz import UTC
10
12
11
- from influxdb_client import Dialect
13
+ from influxdb_client import Dialect , IntegerLiteral , BooleanLiteral , FloatLiteral , DateTimeLiteral , StringLiteral , \
14
+ VariableAssignment , Identifier , OptionStatement , File , DurationLiteral , Duration , UnaryExpression
12
15
from influxdb_client import Query , QueryService
13
16
from influxdb_client .client .flux_csv_parser import FluxCsvParser , FluxSerializationMode
14
17
from influxdb_client .client .flux_table import FluxTable , FluxRecord
@@ -29,51 +32,54 @@ def __init__(self, influxdb_client):
29
32
self ._influxdb_client = influxdb_client
30
33
self ._query_api = QueryService (influxdb_client .api_client )
31
34
32
- def query_csv (self , query : str , org = None , dialect : Dialect = default_dialect ):
35
+ def query_csv (self , query : str , org = None , dialect : Dialect = default_dialect , params : dict = None ):
33
36
"""
34
37
Execute the Flux query and return results as a CSV iterator. Each iteration returns a row of the CSV file.
35
38
36
39
:param query: a Flux query
37
40
:param org: organization name (optional if already specified in InfluxDBClient)
38
41
:param dialect: csv dialect format
42
+ :param params: bind parameters
39
43
:return: The returned object is an iterator. Each iteration returns a row of the CSV file
40
44
(which can span multiple input lines).
41
45
"""
42
46
if org is None :
43
47
org = self ._influxdb_client .org
44
- response = self ._query_api .post_query (org = org , query = self ._create_query (query , dialect ), async_req = False ,
48
+ response = self ._query_api .post_query (org = org , query = self ._create_query (query , dialect , params ), async_req = False ,
45
49
_preload_content = False )
46
50
47
51
return csv .reader (codecs .iterdecode (response , 'utf-8' ))
48
52
49
- def query_raw (self , query : str , org = None , dialect = default_dialect ):
53
+ def query_raw (self , query : str , org = None , dialect = default_dialect , params : dict = None ):
50
54
"""
51
55
Execute synchronous Flux query and return result as raw unprocessed result as a str.
52
56
53
57
:param query: a Flux query
54
58
:param org: organization name (optional if already specified in InfluxDBClient)
55
59
:param dialect: csv dialect format
60
+ :param params: bind parameters
56
61
:return: str
57
62
"""
58
63
if org is None :
59
64
org = self ._influxdb_client .org
60
- result = self ._query_api .post_query (org = org , query = self ._create_query (query , dialect ), async_req = False ,
65
+ result = self ._query_api .post_query (org = org , query = self ._create_query (query , dialect , params ), async_req = False ,
61
66
_preload_content = False )
62
67
63
68
return result
64
69
65
- def query (self , query : str , org = None ) -> List ['FluxTable' ]:
70
+ def query (self , query : str , org = None , params : dict = None ) -> List ['FluxTable' ]:
66
71
"""
67
72
Execute synchronous Flux query and return result as a List['FluxTable'].
68
73
69
74
:param query: the Flux query
70
75
:param org: organization name (optional if already specified in InfluxDBClient)
76
+ :param params: bind parameters
71
77
:return:
72
78
"""
73
79
if org is None :
74
80
org = self ._influxdb_client .org
75
81
76
- response = self ._query_api .post_query (org = org , query = self ._create_query (query , self .default_dialect ),
82
+ response = self ._query_api .post_query (org = org , query = self ._create_query (query , self .default_dialect , params ),
77
83
async_req = False , _preload_content = False , _return_http_data_only = False )
78
84
79
85
_parser = FluxCsvParser (response = response , serialization_mode = FluxSerializationMode .tables )
@@ -82,12 +88,14 @@ def query(self, query: str, org=None) -> List['FluxTable']:
82
88
83
89
return _parser .tables
84
90
85
- def query_stream (self , query : str , org = None ) -> Generator ['FluxRecord' , Any , None ]:
91
+ def query_stream (self , query : str , org = None , params : dict = None ) -> Generator ['FluxRecord' , Any , None ]:
86
92
"""
87
93
Execute synchronous Flux query and return stream of FluxRecord as a Generator['FluxRecord'].
88
94
89
95
:param query: the Flux query
96
+ :param params: the Flux query parameters
90
97
:param org: organization name (optional if already specified in InfluxDBClient)
98
+ :param params: bind parameters
91
99
:return:
92
100
"""
93
101
if org is None :
@@ -100,7 +108,7 @@ def query_stream(self, query: str, org=None) -> Generator['FluxRecord', Any, Non
100
108
101
109
return _parser .generator ()
102
110
103
- def query_data_frame (self , query : str , org = None , data_frame_index : List [str ] = None ):
111
+ def query_data_frame (self , query : str , org = None , data_frame_index : List [str ] = None , params : dict = None ):
104
112
"""
105
113
Execute synchronous Flux query and return Pandas DataFrame.
106
114
@@ -109,11 +117,12 @@ def query_data_frame(self, query: str, org=None, data_frame_index: List[str] = N
109
117
:param query: the Flux query
110
118
:param org: organization name (optional if already specified in InfluxDBClient)
111
119
:param data_frame_index: the list of columns that are used as DataFrame index
120
+ :param params: bind parameters
112
121
:return:
113
122
"""
114
123
from ..extras import pd
115
124
116
- _generator = self .query_data_frame_stream (query , org = org , data_frame_index = data_frame_index )
125
+ _generator = self .query_data_frame_stream (query , org = org , data_frame_index = data_frame_index , params = params )
117
126
_dataFrames = list (_generator )
118
127
119
128
if len (_dataFrames ) == 0 :
@@ -123,7 +132,7 @@ def query_data_frame(self, query: str, org=None, data_frame_index: List[str] = N
123
132
else :
124
133
return _dataFrames
125
134
126
- def query_data_frame_stream (self , query : str , org = None , data_frame_index : List [str ] = None ):
135
+ def query_data_frame_stream (self , query : str , org = None , data_frame_index : List [str ] = None , params : dict = None ):
127
136
"""
128
137
Execute synchronous Flux query and return stream of Pandas DataFrame as a Generator['pd.DataFrame'].
129
138
@@ -132,12 +141,13 @@ def query_data_frame_stream(self, query: str, org=None, data_frame_index: List[s
132
141
:param query: the Flux query
133
142
:param org: organization name (optional if already specified in InfluxDBClient)
134
143
:param data_frame_index: the list of columns that are used as DataFrame index
144
+ :param params: bind parameters
135
145
:return:
136
146
"""
137
147
if org is None :
138
148
org = self ._influxdb_client .org
139
149
140
- response = self ._query_api .post_query (org = org , query = self ._create_query (query , self .default_dialect ),
150
+ response = self ._query_api .post_query (org = org , query = self ._create_query (query , self .default_dialect , params ),
141
151
async_req = False , _preload_content = False , _return_http_data_only = False )
142
152
143
153
_parser = FluxCsvParser (response = response , serialization_mode = FluxSerializationMode .dataFrame ,
@@ -146,10 +156,53 @@ def query_data_frame_stream(self, query: str, org=None, data_frame_index: List[s
146
156
147
157
# private helper for c
148
158
@staticmethod
149
- def _create_query (query , dialect = default_dialect ):
150
- created = Query (query = query , dialect = dialect )
159
+ def _create_query (query , dialect = default_dialect , params : dict = None ):
160
+ created = Query (query = query , dialect = dialect , extern = QueryApi . _build_flux_ast ( params ) )
151
161
return created
152
162
163
+ @staticmethod
164
+ def _params_to_extern_ast (params : dict ) -> List ['OptionStatement' ]:
165
+
166
+ statements = []
167
+ for key , value in params .items ():
168
+
169
+ if isinstance (value , bool ):
170
+ literal = BooleanLiteral ("BooleanLiteral" , value )
171
+ elif isinstance (value , int ):
172
+ literal = IntegerLiteral ("IntegerLiteral" , str (value ))
173
+ elif isinstance (value , float ):
174
+ literal = FloatLiteral ("FloatLiteral" , value )
175
+ elif isinstance (value , datetime ):
176
+ if not value .tzinfo :
177
+ value = UTC .localize (value )
178
+ else :
179
+ value = value .astimezone (UTC )
180
+ literal = DateTimeLiteral ("DateTimeLiteral" , value .strftime ('%Y-%m-%dT%H:%M:%S.%fZ' ))
181
+ elif isinstance (value , timedelta ):
182
+ # convert to microsecodns
183
+ _micro_delta = int (value / timedelta (microseconds = 1 ))
184
+ if _micro_delta < 0 :
185
+ literal = UnaryExpression ("UnaryExpression" , argument = DurationLiteral ("DurationLiteral" , [
186
+ Duration (magnitude = - _micro_delta , unit = "us" )]), operator = "-" )
187
+ else :
188
+ literal = DurationLiteral ("DurationLiteral" , [Duration (magnitude = _micro_delta , unit = "us" )])
189
+ elif isinstance (value , str ):
190
+ literal = StringLiteral ("StringLiteral" , str (value ))
191
+ else :
192
+ literal = value
193
+
194
+ statements .append (OptionStatement ("OptionStatement" ,
195
+ VariableAssignment ("VariableAssignment" , Identifier ("Identifier" , key ),
196
+ literal )))
197
+ return statements
198
+
199
+ @staticmethod
200
+ def _build_flux_ast (params : dict = None ):
201
+ if params is None :
202
+ return None
203
+
204
+ return File (package = None , name = None , type = None , imports = [], body = QueryApi ._params_to_extern_ast (params ))
205
+
153
206
def __del__ (self ):
154
207
"""Close QueryAPI."""
155
208
pass
0 commit comments