11import cloudinary
22from click import command , argument , option , launch
3+ from functools import wraps
34
45from cloudinary_cli .defaults import logger
56from cloudinary_cli .utils .json_utils import write_json_to_file , print_json
910DEFAULT_MAX_RESULTS = 500
1011
1112
13+ def shared_options (func ):
14+ @option ("-f" , "--with_field" , multiple = True , help = "Specify which non-default asset attributes to include "
15+ "in the result as a comma separated list." )
16+ @option ("-fi" , "--fields" , multiple = True , help = "Specify which asset attributes to include in the result "
17+ "(together with a subset of the default attributes) as a comma separated"
18+ " list. This overrides any value specified for with_field." )
19+ @option ("-s" , "--sort_by" , nargs = 2 , help = "Sort search results by (field, <asc|desc>)." )
20+ @option ("-a" , "--aggregate" , nargs = 1 ,
21+ help = "Specify the attribute for which an aggregation count should be calculated and returned." )
22+ @option ("-n" , "--max_results" , nargs = 1 , default = 10 ,
23+ help = "The maximum number of results to return. Default: 10, maximum: 500." )
24+ @option ("-c" , "--next_cursor" , nargs = 1 , help = "Continue a search using an existing cursor." )
25+ @option ("-A" , "--auto_paginate" , is_flag = True , help = "Return all results. Will call Admin API multiple times." )
26+ @option ("-F" , "--force" , is_flag = True , help = "Skip confirmation when running --auto-paginate." )
27+ @option ("-ff" , "--filter_fields" , multiple = True , help = "Specify which attributes to show in the response. "
28+ "None of the others will be shown." )
29+ @option ("-sq" , "--search-query" , is_flag = True , help = "Show the search request query." , hidden = True )
30+ @option ("--json" , nargs = 1 , help = "Save JSON output to a file. Usage: --json <filename>" )
31+ @option ("--csv" , nargs = 1 , help = "Save CSV output to a file. Usage: --csv <filename>" )
32+ @wraps (func )
33+ def wrapper (* args , ** kwargs ):
34+ return func (* args , ** kwargs )
35+
36+ return wrapper
37+
38+
1239@command ("search" ,
13- short_help = "Run the admin API search method." ,
40+ short_help = "Run the Admin API search method." ,
1441 help = """\b
15- Run the admin API search method.
42+ Run the Admin API search method.
1643Format: cld <cli options> search <command options> <Lucene query syntax string>
1744e.g. cld search cat AND tags:kitten -s public_id desc -f context -f tags -n 10
1845""" )
1946@argument ("query" , nargs = - 1 )
20- @option ("-f" , "--with_field" , multiple = True , help = "Specify which non-default asset attributes to include "
21- "in the result as a comma separated list. " )
22- @option ("-fi" , "--fields" , multiple = True , help = "Specify which asset attributes to include in the result "
23- "(together with a subset of the default attributes) as a comma separated"
24- " list. This overrides any value specified for with_field." )
25- @option ("-s" , "--sort_by" , nargs = 2 , help = "Sort search results by (field, <asc|desc>)." )
26- @option ("-a" , "--aggregate" , nargs = 1 ,
27- help = "Specify the attribute for which an aggregation count should be calculated and returned." )
28- @option ("-n" , "--max_results" , nargs = 1 , default = 10 ,
29- help = "The maximum number of results to return. Default: 10, maximum: 500." )
30- @option ("-c" , "--next_cursor" , nargs = 1 , help = "Continue a search using an existing cursor." )
31- @option ("-A" , "--auto_paginate" , is_flag = True , help = "Return all results. Will call Admin API multiple times." )
32- @option ("-F" , "--force" , is_flag = True , help = "Skip confirmation when running --auto-paginate." )
33- @option ("-ff" , "--filter_fields" , multiple = True , help = "Specify which attributes to show in the response. "
34- "None of the others will be shown." )
47+ @shared_options
3548@option ("-t" , "--ttl" , nargs = 1 , default = 300 , help = "Set the Search URL TTL in seconds. Default: 300." )
3649@option ("-u" , "--url" , is_flag = True , help = "Build a signed search URL." )
37- @option ("-sq" , "--search-query" , is_flag = True , help = "Show the search request query." , hidden = True )
38- @option ("--json" , nargs = 1 , help = "Save JSON output to a file. Usage: --json <filename>" )
39- @option ("--csv" , nargs = 1 , help = "Save CSV output to a file. Usage: --csv <filename>" )
4050@option ("-d" , "--doc" , is_flag = True , help = "Open Search API documentation page." )
4151def search (query , with_field , fields , sort_by , aggregate , max_results , next_cursor ,
4252 auto_paginate , force , filter_fields , ttl , url , search_query , json , csv , doc ):
53+ search_instance = cloudinary .search .Search ()
54+ doc_url = "https://cloudinary.com/documentation/search_api"
55+ result_field = 'resources'
56+ return _perform_search (query , with_field , fields , sort_by , aggregate , max_results , next_cursor ,
57+ auto_paginate , force , filter_fields , ttl , url , search_query , json , csv , doc ,
58+ search_instance , doc_url , result_field )
59+
60+
61+ @command ("search_folders" ,
62+ short_help = "Run the Admin API search folders method." ,
63+ help = """\b
64+ Run the Admin API search folders method.
65+ Format: cld <cli options> search_folders <command options> <Lucene query syntax string>
66+ e.g. cld search_folders name:folder AND path:my_parent AND created_at>4w
67+ """ )
68+ @argument ("query" , nargs = - 1 )
69+ @shared_options
70+ @option ("-d" , "--doc" , is_flag = True , help = "Open Search Folders API documentation page." )
71+ def search_folders (query , with_field , fields , sort_by , aggregate , max_results , next_cursor ,
72+ auto_paginate , force , filter_fields , search_query , json , csv , doc ):
73+ search_instance = cloudinary .search_folders .SearchFolders ()
74+ doc_url = "https://cloudinary.com/documentation/admin_api#search_folders"
75+ result_field = 'folders'
76+ return _perform_search (query , with_field , fields , sort_by , aggregate , max_results , next_cursor ,
77+ auto_paginate , force , filter_fields , 300 , False , search_query , json , csv , doc ,
78+ search_instance , doc_url , result_field )
79+
80+
81+ def _perform_search (query , with_field , fields , sort_by , aggregate , max_results , next_cursor ,
82+ auto_paginate , force , filter_fields , ttl , url , search_query , json , csv , doc ,
83+ search_instance , doc_url , result_field ):
84+ """Shared logic for running a search."""
4385 if doc :
44- return launch ("https://cloudinary.com/documentation/search_api" )
86+ return launch (doc_url )
4587
4688 fields_to_keep = []
4789 if filter_fields :
4890 fields_to_keep = tuple (normalize_list_params (filter_fields )) + tuple (normalize_list_params (with_field ))
4991
50- search = cloudinary . search . Search () .expression (" " .join (query ))
92+ search = search_instance .expression (" " .join (query ))
5193
5294 if auto_paginate :
5395 max_results = DEFAULT_MAX_RESULTS
@@ -74,32 +116,32 @@ def search(query, with_field, fields, sort_by, aggregate, max_results, next_curs
74116 print_json (search .as_dict ())
75117 return True
76118
77- res = execute_single_request (search , fields_to_keep )
119+ res = execute_single_request (search , fields_to_keep , result_field )
78120
79121 if auto_paginate :
80- res = handle_auto_pagination (res , search , force , fields_to_keep )
122+ res = handle_auto_pagination (res , search , force , fields_to_keep , result_field )
81123
82124 print_json (res )
83125
84126 if json :
85- write_json_to_file (res ['resources' ], json )
127+ write_json_to_file (res [result_field ], json )
86128 logger .info (f"Saved search JSON to '{ json } ' file" )
87129
88130 if csv :
89- write_json_list_to_csv (res ['resources' ], csv , fields_to_keep )
131+ write_json_list_to_csv (res [result_field ], csv , fields_to_keep )
90132 logger .info (f"Saved search to '{ csv } .csv' file" )
91133
92134
93- def execute_single_request (expression , fields_to_keep ):
135+ def execute_single_request (expression , fields_to_keep , result_field = 'resources' ):
94136 res = expression .execute ()
95137
96138 if fields_to_keep :
97- res ['resources' ] = whitelist_keys (res ['resources' ], fields_to_keep )
139+ res [result_field ] = whitelist_keys (res [result_field ], fields_to_keep )
98140
99141 return res
100142
101143
102- def handle_auto_pagination (res , expression , force , fields_to_keep ):
144+ def handle_auto_pagination (res , expression , force , fields_to_keep , result_field = 'resources' ):
103145 if 'next_cursor' not in res :
104146 return res
105147
@@ -119,9 +161,9 @@ def handle_auto_pagination(res, expression, force, fields_to_keep):
119161 while 'next_cursor' in res .keys ():
120162 expression .next_cursor (res ['next_cursor' ])
121163
122- res = execute_single_request (expression , fields_to_keep )
164+ res = execute_single_request (expression , fields_to_keep , result_field )
123165
124- all_results ['resources' ] += res ['resources' ]
166+ all_results [result_field ] += res [result_field ]
125167 all_results ['time' ] += res ['time' ]
126168
127169 all_results .pop ('next_cursor' , None ) # it is empty by now
0 commit comments