Skip to content

Commit

Permalink
First attempt at putting geospatial behind feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
matt-bernhardt committed Feb 13, 2024
1 parent 5e2c10d commit ce1427a
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 80 deletions.
237 changes: 162 additions & 75 deletions app/graphql/types/query_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,65 +32,128 @@ def record_id(id:, index:)
raise GraphQL::ExecutionError, "Record '#{id}' not found"
end

field :search, SearchType, null: false,
description: 'Search for timdex records' do
argument :searchterm, String, required: false, default_value: nil, description: 'Query all searchable fields'
argument :citation, String, required: false, default_value: nil, description: 'Search by citation information'
argument :contributors, String, required: false, default_value: nil,
description: 'Search by contributor name; e.g., author, editor, etc.'
argument :funding_information, String, required: false, default_value: nil,
description: 'Search by funding information; e.g., funding source, ' \
'award name, etc.'
argument :geodistance, GeodistanceType, required: false, default_value: nil,
description: 'Search within a certain distance of a specific location'
argument :identifiers, String, required: false, default_value: nil,
description: 'Search by unique indentifier; e.g., ISBN, DOI, etc.'
argument :locations, String, required: false, default_value: nil, description: 'Search by locations'
argument :subjects, String, required: false, default_value: nil, description: 'Search by subject terms'
argument :title, String, required: false, default_value: nil, description: 'Search by title'
argument :from, String, required: false, default_value: '0',
description: 'Search result number to begin with (the first result is 0)'
argument :index, String, required: false, default_value: nil,
description: 'It is not recommended to provide an index value unless we have provided ' \
'you with one for your specific use case'

argument :source, String, required: false, default_value: 'All', deprecation_reason: 'Use `sourceFilter`'

# applied filters
argument :content_type_filter, [String], required: false, default_value: nil,
description: 'Filter results by content type. Use the `contentType` ' \
'aggregation for a list of possible values'
argument :contributors_filter, [String], required: false, default_value: nil,
description: 'Filter results by contributor. Use the `contributors` ' \
'aggregation for a list of possible values'
argument :format_filter, [String], required: false, default_value: nil,
description: 'Filter results by format. Use the `format` aggregation for a ' \
'list of possible values'
argument :languages_filter, [String], required: false, default_value: nil,
description: 'Filter results by language. Use the `languages` ' \
'aggregation for a list of possible values'
argument :literary_form_filter, String, required: false, default_value: nil,
description: 'Filter results by fiction or nonfiction'
argument :source_filter, [String], required: false, default_value: nil,
description: 'Filter by source record system. Use the `sources` aggregation ' \
'for a list of possible values'
argument :subjects_filter, [String], required: false, default_value: nil,
description: 'Filter by subject terms. Use the `contentType` aggregation ' \
if Flipflop.enabled? :geospatial_search
field :search, SearchType, null: false,
description: 'Search for timdex records' do
argument :searchterm, String, required: false, default_value: nil, description: 'Query all searchable fields'
argument :citation, String, required: false, default_value: nil, description: 'Search by citation information'
argument :contributors, String, required: false, default_value: nil,
description: 'Search by contributor name; e.g., author, editor, etc.'
argument :funding_information, String, required: false, default_value: nil,
description: 'Search by funding information; e.g., funding source, ' \
'award name, etc.'
argument :geodistance, GeodistanceType, required: false, default_value: nil,
description: 'Search within a certain distance of a specific location'
argument :identifiers, String, required: false, default_value: nil,
description: 'Search by unique indentifier; e.g., ISBN, DOI, etc.'
argument :locations, String, required: false, default_value: nil, description: 'Search by locations'
argument :subjects, String, required: false, default_value: nil, description: 'Search by subject terms'
argument :title, String, required: false, default_value: nil, description: 'Search by title'
argument :from, String, required: false, default_value: '0',
description: 'Search result number to begin with (the first result is 0)'
argument :index, String, required: false, default_value: nil,
description: 'It is not recommended to provide an index value unless we have provided ' \
'you with one for your specific use case'

argument :source, String, required: false, default_value: 'All', deprecation_reason: 'Use `sourceFilter`'

# applied filters
argument :content_type_filter, [String], required: false, default_value: nil,
description: 'Filter results by content type. Use the `contentType` ' \
'aggregation for a list of possible values'
argument :contributors_filter, [String], required: false, default_value: nil,
description: 'Filter results by contributor. Use the `contributors` ' \
'aggregation for a list of possible values'
argument :format_filter, [String], required: false, default_value: nil,
description: 'Filter results by format. Use the `format` aggregation for a ' \
'list of possible values'
argument :languages_filter, [String], required: false, default_value: nil,
description: 'Filter results by language. Use the `languages` ' \
'aggregation for a list of possible values'
argument :literary_form_filter, String, required: false, default_value: nil,
description: 'Filter results by fiction or nonfiction'
argument :source_filter, [String], required: false, default_value: nil,
description: 'Filter by source record system. Use the `sources` aggregation ' \
'for a list of possible values'
argument :subjects_filter, [String], required: false, default_value: nil,
description: 'Filter by subject terms. Use the `contentType` aggregation ' \
'for a list of possible values'
end
else
field :search, SearchType, null: false,
description: 'Search for timdex records' do
argument :searchterm, String, required: false, default_value: nil, description: 'Query all searchable fields'
argument :citation, String, required: false, default_value: nil, description: 'Search by citation information'
argument :contributors, String, required: false, default_value: nil,
description: 'Search by contributor name; e.g., author, editor, etc.'
argument :funding_information, String, required: false, default_value: nil,
description: 'Search by funding information; e.g., funding source, ' \
'award name, etc.'
argument :identifiers, String, required: false, default_value: nil,
description: 'Search by unique indentifier; e.g., ISBN, DOI, etc.'
argument :locations, String, required: false, default_value: nil, description: 'Search by locations'
argument :subjects, String, required: false, default_value: nil, description: 'Search by subject terms'
argument :title, String, required: false, default_value: nil, description: 'Search by title'
argument :from, String, required: false, default_value: '0',
description: 'Search result number to begin with (the first result is 0)'
argument :index, String, required: false, default_value: nil,
description: 'It is not recommended to provide an index value unless we have provided ' \
'you with one for your specific use case'

argument :source, String, required: false, default_value: 'All', deprecation_reason: 'Use `sourceFilter`'

# applied filters
argument :content_type_filter, [String], required: false, default_value: nil,
description: 'Filter results by content type. Use the `contentType` ' \
'aggregation for a list of possible values'
argument :contributors_filter, [String], required: false, default_value: nil,
description: 'Filter results by contributor. Use the `contributors` ' \
'aggregation for a list of possible values'
argument :format_filter, [String], required: false, default_value: nil,
description: 'Filter results by format. Use the `format` aggregation for a ' \
'list of possible values'
argument :languages_filter, [String], required: false, default_value: nil,
description: 'Filter results by language. Use the `languages` ' \
'aggregation for a list of possible values'
argument :literary_form_filter, String, required: false, default_value: nil,
description: 'Filter results by fiction or nonfiction'
argument :source_filter, [String], required: false, default_value: nil,
description: 'Filter by source record system. Use the `sources` aggregation ' \
'for a list of possible values'
argument :subjects_filter, [String], required: false, default_value: nil,
description: 'Filter by subject terms. Use the `contentType` aggregation ' \
'for a list of possible values'
end
end

def search(searchterm:, citation:, contributors:, funding_information:, geodistance:, identifiers:, locations:,
subjects:, title:, index:, source:, from:, **filters)
query = construct_query(searchterm, citation, contributors, funding_information, geodistance, identifiers,
locations, subjects, title, source, filters)
if Flipflop.enabled? :geospatial_search
def search(searchterm:, citation:, contributors:, funding_information:, geodistance:, identifiers:, locations:,
subjects:, title:, index:, source:, from:, **filters)
query = construct_query(searchterm, citation, contributors, funding_information, geodistance, identifiers,
locations, subjects, title, source, filters)

results = Opensearch.new.search(from, query, Timdex::OSClient, highlight_requested?, index)
results = Opensearch.new.search(from, query, Timdex::OSClient, highlight_requested?, index)

response = {}
response[:hits] = results['hits']['total']['value']
response[:records] = inject_hits_fields_into_source(results['hits']['hits'])
response[:aggregations] = collapse_buckets(results['aggregations'])
response
response = {}
response[:hits] = results['hits']['total']['value']
response[:records] = inject_hits_fields_into_source(results['hits']['hits'])
response[:aggregations] = collapse_buckets(results['aggregations'])
response
end
else
def search(searchterm:, citation:, contributors:, funding_information:, identifiers:, locations:,
subjects:, title:, index:, source:, from:, **filters)
query = construct_query(searchterm, citation, contributors, funding_information, identifiers,
locations, subjects, title, source, filters)

results = Opensearch.new.search(from, query, Timdex::OSClient, highlight_requested?, index)

response = {}
response[:hits] = results['hits']['total']['value']
response[:records] = inject_hits_fields_into_source(results['hits']['hits'])
response[:aggregations] = collapse_buckets(results['aggregations'])
response
end
end

def highlight_requested?
Expand All @@ -111,27 +174,51 @@ def inject_hits_fields_into_source(hits)
modded_sources
end

def construct_query(searchterm, citation, contributors, funding_information, geodistance, identifiers, locations,
subjects, title, source, filters)
query = {}
query[:q] = searchterm
query[:citation] = citation
query[:contributors] = contributors
query[:funding_information] = funding_information
query[:geodistance] = geodistance
query[:identifiers] = identifiers
query[:locations] = locations
query[:subjects] = subjects
query[:title] = title
query[:collection_filter] = filters[:collection_filter]
query[:content_format_filter] = filters[:format_filter]
query[:content_type_filter] = filters[:content_type_filter]
query[:contributors_filter] = filters[:contributors_filter]
query[:languages_filter] = filters[:languages_filter]
query[:literary_form_filter] = filters[:literary_form_filter]
query = source_deprecation_handler(query, filters[:source_filter], source)
query[:subjects_filter] = filters[:subjects_filter]
query
if Flipflop.enabled? :geospatial_search
def construct_query(searchterm, citation, contributors, funding_information, geodistance, identifiers, locations,
subjects, title, source, filters)
query = {}
query[:q] = searchterm
query[:citation] = citation
query[:contributors] = contributors
query[:funding_information] = funding_information
query[:geodistance] = geodistance
query[:identifiers] = identifiers
query[:locations] = locations
query[:subjects] = subjects
query[:title] = title
query[:collection_filter] = filters[:collection_filter]
query[:content_format_filter] = filters[:format_filter]
query[:content_type_filter] = filters[:content_type_filter]
query[:contributors_filter] = filters[:contributors_filter]
query[:languages_filter] = filters[:languages_filter]
query[:literary_form_filter] = filters[:literary_form_filter]
query = source_deprecation_handler(query, filters[:source_filter], source)
query[:subjects_filter] = filters[:subjects_filter]
query
end
else
def construct_query(searchterm, citation, contributors, funding_information, identifiers, locations,
subjects, title, source, filters)
query = {}
query[:q] = searchterm
query[:citation] = citation
query[:contributors] = contributors
query[:funding_information] = funding_information
query[:identifiers] = identifiers
query[:locations] = locations
query[:subjects] = subjects
query[:title] = title
query[:collection_filter] = filters[:collection_filter]
query[:content_format_filter] = filters[:format_filter]
query[:content_type_filter] = filters[:content_type_filter]
query[:contributors_filter] = filters[:contributors_filter]
query[:languages_filter] = filters[:languages_filter]
query[:literary_form_filter] = filters[:literary_form_filter]
query = source_deprecation_handler(query, filters[:source_filter], source)
query[:subjects_filter] = filters[:subjects_filter]
query
end
end

# source_deprecation_handler prefers our new `sourceFilter` array but will fall back on the
Expand Down
8 changes: 8 additions & 0 deletions test/controllers/graphql_controller_v2_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
require 'test_helper'

class GraphqlControllerV2Test < ActionDispatch::IntegrationTest
def enable_geospatial
test_strategy = Flipflop::FeatureSet.current.test!
test_strategy.switch!(:geospatial_search, true)
end

def setup
test_strategy = Flipflop::FeatureSet.current.test!
test_strategy.switch!(:v2, true)
Expand Down Expand Up @@ -184,6 +189,7 @@ def setup
end

test 'graphqlv2 geodistance search returns results' do
enable_geospatial
VCR.use_cassette('graphqlv2 geodistance') do
post '/graphql', params: { query: '{
search(geodistance: {
Expand All @@ -206,6 +212,7 @@ def setup
end

test 'graphqlv2 geodistance search fails without three required arguments' do
enable_geospatial
post '/graphql', params: { query: '{
search(geodistance: {
latitude: 42.3596653,
Expand All @@ -228,6 +235,7 @@ def setup
end

test 'graphqlv2 geodistance search with another argument' do
enable_geospatial
VCR.use_cassette('graphqlv2 geodistance with searchterm') do
post '/graphql', params: { query: '{
search(
Expand Down
Loading

0 comments on commit ce1427a

Please sign in to comment.