Skip to content

Commit

Permalink
enable sorting on custom fields. Closes #220
Browse files Browse the repository at this point in the history
  • Loading branch information
cofiem committed Jun 29, 2015
1 parent 458abcc commit 5f9584b
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 28 deletions.
12 changes: 3 additions & 9 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
celluloid (0.16.0)
timers (~> 4.0.0)
climate_control (0.0.3)
activesupport (>= 3.0)
cocaine (0.5.7)
Expand Down Expand Up @@ -195,9 +193,9 @@ GEM
globalid (0.3.5)
activesupport (>= 4.1.0)
gmaps4rails (1.5.6)
guard (2.12.6)
guard (2.12.7)
formatador (>= 0.2.4)
listen (~> 2.7)
listen (>= 2.7, <= 4.0)
lumberjack (~> 1.0)
nenv (~> 0.1)
notiffany (~> 0.0)
Expand All @@ -220,7 +218,6 @@ GEM
haml (>= 4.0.6, < 5.0)
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hitimes (1.2.2)
html2haml (2.0.0)
erubis (~> 2.7.0)
haml (~> 4.0.0)
Expand All @@ -245,8 +242,7 @@ GEM
launchy (2.4.3)
addressable (~> 2.3)
libv8 (3.16.14.9)
listen (2.10.1)
celluloid (~> 0.16.0)
listen (3.0.0)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
loofah (2.0.2)
Expand Down Expand Up @@ -434,8 +430,6 @@ GEM
thread_safe (0.3.5)
tilt (1.4.1)
timeliness (0.3.7)
timers (4.0.1)
hitimes
tins (1.5.4)
tzinfo (1.2.2)
thread_safe (~> 0.1)
Expand Down
30 changes: 15 additions & 15 deletions lib/modules/filter/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,21 @@ def parse(filter_hash)
parse_filter(filter_hash)
end

def build_custom_field(column_name)

mappings = {}
unless @field_mappings.blank?
@field_mappings.each { |m| mappings[m[:name]] = m[:value] }
end

value = mappings[column_name]
if mappings.keys.include?(column_name) && !value.blank?
value
else
nil
end
end

private

# Parse a filter hash.
Expand Down Expand Up @@ -521,20 +536,5 @@ def build_joins(model, associations, joins = [])
[[], false]
end

def build_custom_field(column_name)

mappings = {}
unless @field_mappings.blank?
@field_mappings.each { |m| mappings[m[:name]] = m[:value] }
end

value = mappings[column_name]
if mappings.keys.include?(column_name) && !value.blank?
value
else
nil
end
end

end
end
8 changes: 6 additions & 2 deletions lib/modules/filter/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,14 @@ def apply_sort(query, table, column_name, allowed, direction)
validate_query_table_column(query, table, column_name, allowed)
validate_sorting(column_name, allowed, direction)

# allow sorting by field mappings
sort_field = @build.build_custom_field(column_name)
sort_field = table[column_name] if sort_field.blank?

if direction == :asc
query.order(table[column_name].asc)
query.order(Arel::Nodes::Ascending.new sort_field)
elsif direction == :desc
query.order(table[column_name].desc)
query.order(Arel::Nodes::Descending.new sort_field)
end
end

Expand Down
17 changes: 17 additions & 0 deletions spec/acceptance/audio_events_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,21 @@ def library_request(settings = {})
})
end

post '/audio_events/filter' do
let(:authentication_token) { reader_token }
let(:raw_post) { {
"filter":{"start_time_seconds":{"in":['5.2', '7', '100', '4']}},
"paging":{"items":10,"page":1},
"sorting":{"orderBy":"durationSeconds","direction":"desc"}
}.to_json }
standard_request_options(:post, 'FILTER (sort by custom field, as reader)', :ok,
{
expected_json_path: 'meta/sorting/order_by',
data_item_count: 1,
regex_match: /"in"\:\[\"5.2\",\"7\",\"100\",\"[0-9]+\"\]/,
response_body_content: ["\"low_frequency_hertz\":400.0", "\"order_by\":\"duration_seconds\""],
invalid_content: "\"project_ids\":[{\"id\":"
})
end

end
66 changes: 64 additions & 2 deletions spec/lib/filter/query_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ def create_filter(params)
end

it 'occurs for an invalid range filter' do
filter_params = {"filter"=>{"durationSeconds"=>{"inRange"=>"(5,6)"}}}
filter_params = {"filter" => {"durationSeconds" => {"inRange" => "(5,6)"}}}
expect {
create_filter(filter_params).query_full
}.to raise_error(CustomErrors::FilterArgumentError, "Range filter must be {'from': 'value', 'to': 'value'} or {'interval': 'value'} got (5,6)")
Expand Down Expand Up @@ -741,7 +741,7 @@ def create_filter(params)
end

context 'calculated field' do
it 'works for audio_event.duration_seconds' do
it 'audio_event.duration_seconds in filter' do
request_body_obj = {
filter: {
duration_seconds: {
Expand Down Expand Up @@ -793,6 +793,68 @@ def create_filter(params)
AND\"audio_events\".\"is_reference\"='t')) \
AND((\"audio_events\".\"end_time_seconds\"-\"audio_events\".\"start_time_seconds\")>3) \
ORDERBY\"audio_events\".\"created_at\"DESC \
LIMIT25OFFSET0"

expect(filter_query.query_full.to_sql.gsub(/\s+/, '')).to eq(expected_sql.gsub(/\s+/, ''))

end

it 'audio_event.duration_seconds for sorting' do
request_body_obj = {
filter: {
duration_seconds: {
gt: 3
}
},
sorting: {
orderBy: :duration_seconds,
direction: :asc
}
}

@permission = FactoryGirl.create(:write_permission)
user = @permission.user
user_id = user.id

filter_query = Filter::Query.new(
request_body_obj,
Access::Query.audio_events(user, Access::Core.levels_allow),
AudioEvent,
AudioEvent.filter_settings
)

expected_sql =
"SELECT\"audio_events\".\"id\",\"audio_events\".\"audio_recording_id\", \
\"audio_events\".\"start_time_seconds\",\"audio_events\".\"end_time_seconds\", \
\"audio_events\".\"low_frequency_hertz\",\"audio_events\".\"high_frequency_hertz\", \
\"audio_events\".\"is_reference\",\"audio_events\".\"creator_id\", \
\"audio_events\".\"updated_at\",\"audio_events\".\"created_at\" \
FROM\"audio_events\" \
INNERJOIN\"audio_recordings\"ON\"audio_recordings\".\"id\"=\"audio_events\".\"audio_recording_id\" \
AND(\"audio_recordings\".\"deleted_at\"ISNULL) \
INNERJOIN\"sites\"ON\"sites\".\"id\"=\"audio_recordings\".\"site_id\" \
AND(\"sites\".\"deleted_at\"ISNULL) \
INNERJOIN\"projects_sites\"ON\"projects_sites\".\"site_id\"=\"sites\".\"id\" \
INNERJOIN\"projects\"ON\"projects\".\"id\"=\"projects_sites\".\"project_id\" \
AND(\"projects\".\"deleted_at\"ISNULL) \
WHERE(\"audio_events\".\"deleted_at\"ISNULL) \
AND((\"projects\".\"id\"IN( \
SELECT\"projects\".\"id\" \
FROM\"projects\" \
WHERE\"projects\".\"deleted_at\"ISNULL \
AND\"projects\".\"creator_id\"=#{user_id}) \
OR\"projects\".\"id\"IN( \
SELECT\"permissions\".\"project_id\" \
FROM\"permissions\" \
WHERE\"permissions\".\"user_id\"=#{user_id} \
AND\"permissions\".\"level\"IN('reader','writer','owner'))) \
OR\"audio_events\".\"id\"IN( \
SELECT\"audio_events\".\"id\" \
FROM\"audio_events\" \
WHERE\"audio_events\".\"deleted_at\"ISNULL \
AND\"audio_events\".\"is_reference\"='t')) \
AND((\"audio_events\".\"end_time_seconds\"-\"audio_events\".\"start_time_seconds\")>3) \
ORDERBY(\"audio_events\".\"end_time_seconds\"-\"audio_events\".\"start_time_seconds\")ASC \
LIMIT25OFFSET0"

expect(filter_query.query_full.to_sql.gsub(/\s+/, '')).to eq(expected_sql.gsub(/\s+/, ''))
Expand Down

0 comments on commit 5f9584b

Please sign in to comment.