Skip to content

Commit

Permalink
Refactor detector GraphQL and implement journal detection type
Browse files Browse the repository at this point in the history
Why these changes are being introduced:

We've implemented a journal detection model but not the corresponding GraphQL. As this will be the second of many
detectors, it also makes sense to reconsider how the detector GraphQL is modeled.

Relevant ticket(s):

* [TCO-50](https://mitlibraries.atlassian.net/browse/TCO-50)

How this addresses that need:

This makes `journals` and `standard_identifiers` fields within a new `DetectorsType`. Much like the `Detector` module,
this new type is not to any ActiveRecord models and acts more as a namespace to contain the various detectors.

Side effects of this change:

* The graphql-ruby docs [advise against overusing JSON](https://graphql-ruby.org/api-doc/2.3.14/GraphQL/Types/JSON.html)
as a GraphQL type, but this feels like a good use case for it.
* I'm not certain whether my solution to the `detectors` field is idiomatic. It feels particularly odd given that,
in the SearchEventType, there is a method for the `phrase` field that returns the same thing.
* The gitignore file has been updated to ignore Lando config. This ended up being unrelated to this changeset, but it
might be useful during cassette regeneration.
  • Loading branch information
jazairi committed Aug 23, 2024
1 parent 09b51c5 commit 7083502
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 39 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@
.DS_Store
.vscode/
.yardoc
.lando.yml
22 changes: 22 additions & 0 deletions app/graphql/types/detectors_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module Types
class DetectorsType < Types::BaseObject
description 'Provides all available search term detectors'

field :journals, [Types::JournalsType], description: 'Information about journals detected in the search term'
field :standard_identifiers, [Types::StandardIdentifiersType], description: 'Currently supported: ISBN, ISSN, PMID, DOI'

def standard_identifiers
Detector::StandardIdentifiers.new(@object).identifiers.map do |identifier|
{ kind: identifier.first, value: identifier.last }
end
end

def journals
Detector::Journal.full_term_match(@object).map do |journal|
{ title: journal.name, additional_info: journal.additional_info }
end
end
end
end
10 changes: 10 additions & 0 deletions app/graphql/types/journals_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module Types
class JournalsType < Types::BaseObject
description 'A detector for journal titles in search terms'

field :additional_info, GraphQL::Types::JSON, description: 'Additional information about the detected journal'
field :title, String, null: false, description: 'Title of the detected journal'
end
end
8 changes: 3 additions & 5 deletions app/graphql/types/search_event_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
module Types
class SearchEventType < Types::BaseObject
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :detectors, Types::DetectorsType
field :id, ID, null: false
field :phrase, String
field :source, String
field :standard_identifiers, [StandardIdentifiersType]
field :term_id, Integer
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false

def phrase
@object.term.phrase
end

def standard_identifiers
Detector::StandardIdentifiers.new(@object.term.phrase).identifiers.map do |identifier|
{ kind: identifier.first, value: identifier.last }
end
def detectors
@object.term.phrase
end
end
end
8 changes: 5 additions & 3 deletions app/graphql/types/standard_identifiers_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

module Types
class StandardIdentifiersType < Types::BaseObject
field :details, DetailsType
field :kind, String, null: false
field :value, String, null: false
description 'A detector for standard identifiers in search terms. Currently supported: ISBN, ISSN, PMID, DOI'

field :details, DetailsType, description: 'Additional information about the detected identifier(s)'
field :kind, String, null: false, description: 'The type of identifier detected (one of ISBN, ISSN, PMID, DOI)'
field :value, String, null: false, description: 'The identifier detected in the search term'

# details does external lookups and should only be run if the fields
# have been explicitly requested
Expand Down
8 changes: 3 additions & 5 deletions app/graphql/types/term_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
module Types
class TermType < Types::BaseObject
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :detectors, Types::DetectorsType
field :id, ID, null: false
field :occurence_count, Integer
field :phrase, String, null: false
field :search_events, [SearchEventType], null: false
field :standard_identifiers, [StandardIdentifiersType]
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false

def occurence_count
@object.search_events.count
end

def standard_identifiers
StandardIdentifiers.new(@object.phrase).identifiers.map do |identifier|
{ kind: identifier.first, value: identifier.last }
end
def detectors
@object.phrase
end
end
end
5 changes: 2 additions & 3 deletions app/models/detector/standard_identifiers.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# frozen_string_literal: true

# StandardIdentifiers is a PatternDectector implementation that detects the identifiers DOI, ISBN, ISSN, PMID.
# See /docs/reference/pattern_detection_and_enhancement.md for details.

module Detector
# Detector::StandardIdentifiers detects the identifiers DOI, ISBN, ISSN, PMID.
# See /docs/reference/pattern_detection_and_enhancement.md for details.
class StandardIdentifiers
attr_reader :identifiers

Expand Down
69 changes: 46 additions & 23 deletions test/controllers/graphql_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,38 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
test 'search event query can return detected standard identifiers' do
post '/graphql', params: { query: '{
logSearchEvent(sourceSystem: "timdex", searchTerm: "10.1038/nphys1170") {
standardIdentifiers {
kind
value
}
detectors {
standardIdentifiers {
kind
value
}
}
}
}' }

json = response.parsed_body

assert_equal('doi', json['data']['logSearchEvent']['standardIdentifiers'].first['kind'])
assert_equal('10.1038/nphys1170', json['data']['logSearchEvent']['standardIdentifiers'].first['value'])
assert_equal('doi', json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['kind'])
assert_equal('10.1038/nphys1170', json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['value'])
end

test 'search event query can return detected journals' do
post '/graphql', params: { query: '{
logSearchEvent(sourceSystem: "timdex", searchTerm: "nature") {
detectors {
journals {
title
additionalInfo
}
}
}
}' }

json = response.parsed_body

assert_equal('nature', json['data']['logSearchEvent']['detectors']['journals'].first['title'])
assert_equal({"issns"=>["0028-0836", "1476-4687"]},
json['data']['logSearchEvent']['detectors']['journals'].first['additionalInfo'])
end

test 'search event query can return phrase from logged term' do
Expand All @@ -85,29 +106,31 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
test 'search event query can return details for detected standard identifiers' do
VCR.use_cassette('searchevent 10.1038/nphys1170') do
post '/graphql', params: { query: '{
logSearchEvent(sourceSystem: "timdex", searchTerm: "10.1038/nphys1170") {
standardIdentifiers {
kind
value
details {
title
linkResolverUrl
issns
authors
}
}
}
}' }
logSearchEvent(sourceSystem: "timdex", searchTerm: "10.1038/nphys1170") {
detectors {
standardIdentifiers {
kind
value
details {
title
linkResolverUrl
issns
authors
}
}
}
}
}' }

json = response.parsed_body

assert_equal('Measured measurement',
json['data']['logSearchEvent']['standardIdentifiers'].first['details']['title'])
json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['details']['title'])
assert_equal('https://mit.primo.exlibrisgroup.com/discovery/openurl?institution=01MIT_INST&rfr_id=info:sid/mit.tacos.api&vid=01MIT_INST:MIT&rft.atitle=Measured measurement&rft.date=&rft.genre=journal-article&rft.jtitle=Nature Physics&rft_id=info:doi/10.1038/nphys1170',
json['data']['logSearchEvent']['standardIdentifiers'].first['details']['linkResolverUrl'])
json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['details']['linkResolverUrl'])
assert_equal(%w[1745-2473 1745-2481],
json['data']['logSearchEvent']['standardIdentifiers'].first['details']['issns'])
assert_nil(json['data']['logSearchEvent']['standardIdentifiers'].first['details']['authors'])
json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['details']['issns'])
assert_nil(json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['details']['authors'])
end
end
end

0 comments on commit 7083502

Please sign in to comment.