@@ -112,6 +112,8 @@ async def search(self, q, item_type=None):
112112
113113 return res
114114
115+
116+
115117 async def get_card_data (self , card_name = None , card_id = None , collection_name = None , collection_id = None ,
116118 data_format = 'json' , parameters = None , format_rows = False ):
117119 '''
@@ -156,3 +158,172 @@ async def get_card_data(self, card_name=None, card_id=None, collection_name=None
156158 if data_format == 'csv' :
157159 text = res .text if hasattr (res , 'text' ) else await res .text ()
158160 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