@@ -112,6 +112,8 @@ async def search(self, q, item_type=None):
112
112
113
113
return res
114
114
115
+
116
+
115
117
async def get_card_data (self , card_name = None , card_id = None , collection_name = None , collection_id = None ,
116
118
data_format = 'json' , parameters = None , format_rows = False ):
117
119
'''
@@ -156,3 +158,172 @@ async def get_card_data(self, card_name=None, card_id=None, collection_name=None
156
158
if data_format == 'csv' :
157
159
text = res .text if hasattr (res , 'text' ) else await res .text ()
158
160
return text .replace ('null' , '' )
161
+
162
+
163
+
164
+ async def clone_card (self , card_id ,
165
+ source_table_id = None , target_table_id = None ,
166
+ source_table_name = None , target_table_name = None ,
167
+ new_card_name = None , new_card_collection_id = None ,
168
+ ignore_these_filters = None , return_card = False ):
169
+ """
170
+ Async version of clone_card.
171
+ """
172
+ if not source_table_id :
173
+ if not source_table_name :
174
+ raise ValueError ('Either the name or id of the source table needs to be provided.' )
175
+ else :
176
+ source_table_id = await self .get_item_id ('table' , source_table_name )
177
+
178
+ if not target_table_id :
179
+ if not target_table_name :
180
+ raise ValueError ('Either the name or id of the target table needs to be provided.' )
181
+ else :
182
+ target_table_id = await self .get_item_id ('table' , target_table_name )
183
+
184
+ if ignore_these_filters :
185
+ assert type (ignore_these_filters ) == list
186
+
187
+ card_info = await self .get_item_info ('card' , card_id )
188
+ target_table_col_name_id_mapping = await self .get_columns_name_id (table_id = target_table_id )
189
+ source_table_col_id_name_mapping = await self .get_columns_name_id (table_id = source_table_id , column_id_name = True )
190
+
191
+ if card_info ['dataset_query' ]['type' ] == 'native' :
192
+ filters_data = card_info ['dataset_query' ]['native' ]['template-tags' ]
193
+ if not source_table_name :
194
+ source_table_name = await self .get_item_name ('table' , source_table_id )
195
+ if not target_table_name :
196
+ target_table_name = await self .get_item_name ('table' , target_table_id )
197
+ card_info ['dataset_query' ]['native' ]['query' ] = card_info ['dataset_query' ]['native' ]['query' ].replace (source_table_name , target_table_name )
198
+ for filter_variable_name , data in filters_data .items ():
199
+ if ignore_these_filters is not None and filter_variable_name in ignore_these_filters :
200
+ continue
201
+ column_id = data ['dimension' ][1 ]
202
+ column_name = source_table_col_id_name_mapping [column_id ]
203
+ target_col_id = target_table_col_name_id_mapping [column_name ]
204
+ card_info ['dataset_query' ]['native' ]['template-tags' ][filter_variable_name ]['dimension' ][1 ] = target_col_id
205
+
206
+ elif card_info ['dataset_query' ]['type' ] == 'query' :
207
+ query_data = card_info ['dataset_query' ]['query' ]
208
+ query_data ['source-table' ] = target_table_id
209
+ query_data_str = str (query_data )
210
+ import re
211
+ res = re .findall (r"\['field', .*?\]" , query_data_str )
212
+ source_column_IDs = [ eval (i )[1 ] for i in res ]
213
+ for source_col_id in source_column_IDs :
214
+ source_col_name = source_table_col_id_name_mapping [source_col_id ]
215
+ target_col_id = target_table_col_name_id_mapping [source_col_name ]
216
+ query_data_str = query_data_str .replace ("['field', {}, " .format (source_col_id ), "['field', {}, " .format (target_col_id ))
217
+ card_info ['dataset_query' ]['query' ] = eval (query_data_str )
218
+
219
+ new_card_json = {}
220
+ for key in ['dataset_query' , 'display' , 'visualization_settings' ]:
221
+ new_card_json [key ] = card_info [key ]
222
+
223
+ if new_card_name :
224
+ new_card_json ['name' ] = new_card_name
225
+ else :
226
+ new_card_json ['name' ] = card_info ['name' ]
227
+
228
+ if new_card_collection_id :
229
+ new_card_json ['collection_id' ] = new_card_collection_id
230
+ else :
231
+ new_card_json ['collection_id' ] = card_info ['collection_id' ]
232
+
233
+ if return_card :
234
+ return await self .create_card (custom_json = new_card_json , verbose = True , return_card = return_card )
235
+ else :
236
+ await self .create_card (custom_json = new_card_json , verbose = True )
237
+
238
+
239
+
240
+ async def move_to_archive (self , item_type , item_name = None , item_id = None ,
241
+ collection_name = None , collection_id = None , table_id = None , verbose = False ):
242
+ '''
243
+ Async version of move_to_archive.
244
+ '''
245
+ assert item_type in ['card' , 'dashboard' , 'collection' , 'pulse' , 'segment' ]
246
+
247
+ if not item_id :
248
+ if not item_name :
249
+ raise ValueError ('Either the name or id of the {} must be provided.' .format (item_type ))
250
+ if item_type == 'collection' :
251
+ item_id = await self .get_item_id ('collection' , item_name )
252
+ elif item_type == 'segment' :
253
+ item_id = await self .get_item_id ('segment' , item_name , table_id = table_id )
254
+ else :
255
+ item_id = await self .get_item_id (item_type , item_name , collection_id , collection_name )
256
+
257
+ if item_type == 'segment' :
258
+ res = await self .put ('/api/{}/{}' .format (item_type , item_id ), json = {'archived' :True , 'revision_message' :'archived!' })
259
+ else :
260
+ res = await self .put ('/api/{}/{}' .format (item_type , item_id ), json = {'archived' :True })
261
+
262
+ if res in [200 , 202 ]:
263
+ await self .verbose_print (verbose , 'Successfully Archived.' )
264
+ else :
265
+ print ('Archiving Failed.' )
266
+
267
+ return res
268
+
269
+
270
+
271
+ async def delete_item (self , item_type , item_name = None , item_id = None ,
272
+ collection_name = None , collection_id = None , verbose = False ):
273
+ '''
274
+ Async version of delete_item.
275
+ '''
276
+ assert item_type in ['card' , 'dashboard' , 'pulse' ]
277
+ if not item_id :
278
+ if not item_name :
279
+ raise ValueError ('Either the name or id of the {} must be provided.' .format (item_type ))
280
+ item_id = await self .get_item_id (item_type , item_name , collection_id , collection_name )
281
+
282
+ return await self .delete ('/api/{}/{}' .format (item_type , item_id ))
283
+
284
+
285
+
286
+ async def update_column (self , params , column_id = None , column_name = None ,
287
+ table_id = None , table_name = None , db_id = None , db_name = None ):
288
+ '''
289
+ Async version of update_column.
290
+ '''
291
+ assert type (params ) == dict
292
+
293
+ if not column_id :
294
+ if not column_name :
295
+ raise ValueError ('Either the name or id of the column needs to be provided.' )
296
+
297
+ if not table_id :
298
+ if not table_name :
299
+ raise ValueError ('When column_id is not given, either the name or id of the table needs to be provided.' )
300
+ table_id = await self .get_item_id ('table' , table_name , db_id = db_id , db_name = db_name )
301
+
302
+ columns_name_id_mapping = await self .get_columns_name_id (table_name = table_name , table_id = table_id , db_name = db_name , db_id = db_id )
303
+ column_id = columns_name_id_mapping .get (column_name )
304
+ if column_id is None :
305
+ raise ValueError ('There is no column named {} in the provided table' .format (column_name ))
306
+
307
+ res_status_code = await self .put ('/api/field/{}' .format (column_id ), json = params )
308
+ if res_status_code != 200 :
309
+ print ('Column Update Failed.' )
310
+
311
+ return res_status_code
312
+
313
+
314
+
315
+ async def add_card_to_dashboard (self , card_id , dashboard_id ):
316
+ params = {
317
+ 'cardId' : card_id
318
+ }
319
+ await self .post (f'/api/dashboard/{ dashboard_id } /cards' , json = params )
320
+
321
+ @staticmethod
322
+ async def make_json (raw_json , prettyprint = False ):
323
+ """Async version of make_json."""
324
+ import json
325
+ ret_dict = json .loads (raw_json )
326
+ if prettyprint :
327
+ import pprint
328
+ pprint .pprint (ret_dict )
329
+ return ret_dict
0 commit comments