Skip to content

Commit 6a088ac

Browse files
Adding support --order and --order_by for list operations (#506)
## 📝 Description Adds --order_by and --order to filtering operations. ## ✔️ How to Test Tested using command line. Ex. `linode-cli linodes list --order_by label --order desc` `linode-cli linodes list --order_by label`
1 parent ba57de8 commit 6a088ac

File tree

3 files changed

+108
-9
lines changed

3 files changed

+108
-9
lines changed

linodecli/api_request.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ def _build_filter_header(
150150
if p.name in parsed_args_dict:
151151
del parsed_args_dict[p.name]
152152

153+
# check for order_by and order
154+
order_by = parsed_args_dict.pop("order_by")
155+
order = parsed_args_dict.pop("order") or "asc"
156+
153157
# The "+and" list to be used in the filter header
154158
filter_list = []
155159

@@ -161,15 +165,16 @@ def _build_filter_header(
161165
new_filters = [{k: j} for j in v] if isinstance(v, list) else [{k: v}]
162166
filter_list.extend(new_filters)
163167

164-
if len(filter_list) < 1:
165-
return None
166-
167-
return json.dumps(
168-
# Only use +and if there are multiple attributes to filter on
169-
{"+and": filter_list}
170-
if len(filter_list) > 1
171-
else filter_list[0]
172-
)
168+
result = {}
169+
if len(filter_list) > 0:
170+
if len(filter_list) == 1:
171+
result = filter_list[0]
172+
else:
173+
result["+and"] = filter_list
174+
if order_by is not None:
175+
result["+order_by"] = order_by
176+
result["+order"] = order
177+
return json.dumps(result) if len(result) > 0 else None
173178

174179

175180
def _build_request_url(ctx, operation, parsed_args) -> str:

linodecli/baked/operation.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import json
77
import platform
88
import re
9+
import sys
910
from getpass import getpass
1011
from os import environ, path
1112
from typing import List, Tuple
@@ -322,11 +323,13 @@ def process_response_json(
322323

323324
def _add_args_filter(self, parser):
324325
# build args for filtering
326+
filterable_args = []
325327
for attr in self.response_model.attrs:
326328
if not attr.filterable:
327329
continue
328330

329331
expected_type = TYPES[attr.datatype]
332+
filterable_args.append(attr.name)
330333
if expected_type == list:
331334
parser.add_argument(
332335
"--" + attr.name,
@@ -341,6 +344,20 @@ def _add_args_filter(self, parser):
341344
type=expected_type,
342345
metavar=attr.name,
343346
)
347+
# Add --order_by and --order argument
348+
parser.add_argument(
349+
"--order_by",
350+
choices=filterable_args,
351+
help="Attribute to order the results by - must be filterable.",
352+
required="--order" in sys.argv,
353+
)
354+
355+
parser.add_argument(
356+
"--order",
357+
choices=["asc", "desc"],
358+
default="asc",
359+
help="Either “asc” or “desc”. Defaults to “asc”. Requires +order_by",
360+
)
344361

345362
def _add_args_post_put(self, parser) -> List[Tuple[str, str]]:
346363
list_items = []

tests/unit/test_api_request.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ def test_build_filter_header(self, list_operation):
167167
SimpleNamespace(
168168
filterable_result="bar",
169169
filterable_list_result=["foo", "bar"],
170+
order_by=None,
171+
order=None,
170172
),
171173
)
172174

@@ -188,6 +190,8 @@ def test_build_filter_header_single(self, list_operation):
188190
list_operation,
189191
SimpleNamespace(
190192
filterable_result="bar",
193+
order_by=None,
194+
order=None,
191195
),
192196
)
193197

@@ -203,6 +207,8 @@ def test_build_filter_header_single_list(self, list_operation):
203207
list_operation,
204208
SimpleNamespace(
205209
filterable_list_result=["foo", "bar"],
210+
order_by=None,
211+
order=None,
206212
),
207213
)
208214

@@ -218,6 +224,77 @@ def test_build_filter_header_single_list(self, list_operation):
218224
== result
219225
)
220226

227+
def test_build_filter_header_order_by(self, list_operation):
228+
result = api_request._build_filter_header(
229+
list_operation,
230+
SimpleNamespace(
231+
filterable_result="bar",
232+
filterable_list_result=["foo", "bar"],
233+
order_by="baz",
234+
order=None,
235+
),
236+
)
237+
238+
assert (
239+
json.dumps(
240+
{
241+
"+and": [
242+
{"filterable_result": "bar"},
243+
{"filterable_list_result": "foo"},
244+
{"filterable_list_result": "bar"},
245+
],
246+
"+order_by": "baz",
247+
"+order": "asc",
248+
}
249+
)
250+
== result
251+
)
252+
253+
def test_build_filter_header_order(self, list_operation):
254+
result = api_request._build_filter_header(
255+
list_operation,
256+
SimpleNamespace(
257+
filterable_result="bar",
258+
filterable_list_result=["foo", "bar"],
259+
order_by="baz",
260+
order="desc",
261+
),
262+
)
263+
264+
assert (
265+
json.dumps(
266+
{
267+
"+and": [
268+
{"filterable_result": "bar"},
269+
{"filterable_list_result": "foo"},
270+
{"filterable_list_result": "bar"},
271+
],
272+
"+order_by": "baz",
273+
"+order": "desc",
274+
}
275+
)
276+
== result
277+
)
278+
279+
def test_build_filter_header_only_order(self, list_operation):
280+
result = api_request._build_filter_header(
281+
list_operation,
282+
SimpleNamespace(
283+
order_by="baz",
284+
order="desc",
285+
),
286+
)
287+
288+
assert (
289+
json.dumps(
290+
{
291+
"+order_by": "baz",
292+
"+order": "desc",
293+
}
294+
)
295+
== result
296+
)
297+
221298
def test_do_request_get(self, mock_cli, list_operation):
222299
mock_response = Mock(status_code=200, reason="OK")
223300

0 commit comments

Comments
 (0)