From 4c11ded84419ac8715f55f0ca2ae64634a4d50d9 Mon Sep 17 00:00:00 2001 From: Struan Donald Date: Mon, 27 Apr 2020 16:21:27 +0100 Subject: [PATCH] allow sort order to be specified for attribute values Add a values_sorted property to Attribute that is an array ref with the order the keys of values should be returned in. If that's present then use that to sort the values, otherwise remain alphabetical. --- perllib/Open311/Endpoint.pm | 12 +- perllib/Open311/Endpoint/Service/Attribute.pm | 11 ++ t/open311/endpoint.t | 104 ++++++++++++++++++ t/open311/endpoint/Endpoint1.pm | 30 +++++ 4 files changed, 156 insertions(+), 1 deletion(-) diff --git a/perllib/Open311/Endpoint.pm b/perllib/Open311/Endpoint.pm index c5e0d4633..84ede1e9b 100644 --- a/perllib/Open311/Endpoint.pm +++ b/perllib/Open311/Endpoint.pm @@ -407,7 +407,7 @@ sub GET_Service_Definition { key => $key, name => $name, } - } sort { $a->[0] cmp $b->[0] } $attribute->values_kv + } $self->service_attribute_values( $attribute ) ]) : (), map { $_ => $attribute->$_ } qw/ code datatype datatype_description description /, @@ -419,6 +419,16 @@ sub GET_Service_Definition { return $service_definition; } +sub service_attribute_values { + my ( $self, $attribute ) = @_; + + if ( $attribute->has_sorted_values ) { + return map { [ $_ => $attribute->values->{$_} ] } $attribute->get_sorted_values; + } else { + return sort { $a->[0] cmp $b->[0] } $attribute->values_kv; + } +} + sub POST_Service_Request_input_schema { my ($self, $args) = @_; diff --git a/perllib/Open311/Endpoint/Service/Attribute.pm b/perllib/Open311/Endpoint/Service/Attribute.pm index ea9b16b5e..9fef6ce55 100644 --- a/perllib/Open311/Endpoint/Service/Attribute.pm +++ b/perllib/Open311/Endpoint/Service/Attribute.pm @@ -70,6 +70,17 @@ has values => ( } ); +has values_sorted => ( + is => 'ro', + isa => ArrayRef, + default => sub { [] }, + handles_via => 'Array', + handles => { + get_sorted_values => 'elements', + has_sorted_values => 'count', + } +); + sub schema_definition { my $self = shift; diff --git a/t/open311/endpoint.t b/t/open311/endpoint.t index fc570d3bb..83171f35a 100644 --- a/t/open311/endpoint.t +++ b/t/open311/endpoint.t @@ -29,6 +29,15 @@ subtest "GET Service List" => sub { Pothole Repairs realtime + + Sorted Pothole Repairs Service + highways + deep,hole,wow + true + SPOT + Sorted Pothole Repairs + realtime + Bin Enforcement Service sanitation @@ -52,6 +61,14 @@ CONTENT "metadata" => "true", "description" => "Pothole Repairs Service", "service_code" => "POT" + }, { + "keywords" => "deep,hole,wow", + "group" => "highways", + "service_name" => "Sorted Pothole Repairs", + "type" => "realtime", + "metadata" => "true", + "description" => "Sorted Pothole Repairs Service", + "service_code" => "SPOT" }, { "keywords" => "bin", "group" => "sanitation", @@ -151,6 +168,93 @@ CONTENT }, 'json structure ok'; }; + +subtest "GET Service Definition with non standard values order" => sub { + my $res = $endpoint->run_test_request( GET => '/services/SPOT.xml' ); + ok $res->is_success, 'xml success', + or diag $res->content; + is_string $res->content, < + + + + depth + number + an integer + depth of pothole, in centimetres + 1 + true + true + + + shape + singlevaluelist + square | circle | triangle + shape of the pothole + 2 + false + + + Circle + circle + + + Triangle + triangle + + + Square + square + + + true + + + SPOT + +CONTENT + + $res = $endpoint->run_test_request( GET => '/services/SPOT.json' ); + ok $res->is_success, 'json success'; + is_deeply decode_json($res->content), + { + "service_code" => "SPOT", + "attributes" => [ + { + "order" => 1, + "code" => "depth", + "required" => "true", + "variable" => "true", + "datatype_description" => "an integer", + "description" => "depth of pothole, in centimetres", + "datatype" => "number", + }, + { + "order" => 2, + "code" => "shape", + "variable" => "true", + "datatype_description" => "square | circle | triangle", + "description" => "shape of the pothole", + "required" => "false", + "datatype" => "singlevaluelist", + "values" => [ + { + "name" => "Circle", + "key" => "circle" + }, + { + "name" => "Triangle", + "key" => "triangle" + }, + { + "name" => "Square", + "key" => "square" + }, + ], + } + ], + }, 'json structure ok'; +}; subtest "POST Service Request validation" => sub { my $res = $endpoint->run_test_request( POST => '/requests.json', diff --git a/t/open311/endpoint/Endpoint1.pm b/t/open311/endpoint/Endpoint1.pm index ae12172b8..81382c681 100644 --- a/t/open311/endpoint/Endpoint1.pm +++ b/t/open311/endpoint/Endpoint1.pm @@ -40,6 +40,36 @@ sub services { keywords => [qw/ deep hole wow/], group => 'highways', ), + t::open311::endpoint::ServiceType1->new( + service_code => 'SPOT', + service_name => 'Sorted Pothole Repairs', + description => 'Sorted Pothole Repairs Service', + attributes => [ + Open311::Endpoint::Service::Attribute->new( + code => 'depth', + required => 1, + datatype => 'number', + datatype_description => 'an integer', + description => 'depth of pothole, in centimetres', + ), + Open311::Endpoint::Service::Attribute->new( + code => 'shape', + required => 0, + datatype => 'singlevaluelist', + datatype_description => 'square | circle | triangle', + description => 'shape of the pothole', + values_sorted => [ 'circle', 'triangle', 'square' ], + values => { + square => 'Square', + circle => 'Circle', + triangle => 'Triangle', + }, + ), + ], + type => 'realtime', + keywords => [qw/ deep hole wow/], + group => 'highways', + ), t::open311::endpoint::ServiceType1->new( service_code => 'BIN', service_name => 'Bin Enforcement',