Skip to content

Commit

Permalink
Merge pull request #1025 from datacite/10-10-Other_related_ids
Browse files Browse the repository at this point in the history
Get other_related works/dois
  • Loading branch information
jrhoads authored Oct 20, 2023
2 parents 736428e + ecba0d5 commit e8f0d3c
Show file tree
Hide file tree
Showing 9 changed files with 576 additions and 17 deletions.
270 changes: 270 additions & 0 deletions app/graphql/schema.graphql

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions app/graphql/types/doi_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ class CitationFormat < GraphQL::Schema::Enum
Int,
null: true,
description: "Total number of DOIs the resource is a part of"
field :other_related_count,
Int,
null: true,
description: "Total number of DOIs related to the resource"
field :citations_over_time,
[YearTotalType],
null: true, description: "Citations by year"
Expand Down Expand Up @@ -280,6 +284,57 @@ class CitationFormat < GraphQL::Schema::Enum
argument :after, String, required: false
end

field :other_related,
WorkConnectionWithTotalType,
null: true,
max_page_size: 100,
description: "Other works related to this DOI." do
argument :query, String, required: false
argument :ids, [String], required: false
argument :published, String, required: false
argument :user_id, String, required: false
argument :funder_id, String, required: false
argument :repository_id, String, required: false
argument :member_id, String, required: false
argument :affiliation_id, String, required: false
argument :organization_id, String, required: false
argument :registration_agency, String, required: false
argument :resource_type_id, String, required: false
argument :license, String, required: false
argument :language, String, required: false
argument :has_person, Boolean, required: false
argument :has_funder, Boolean, required: false
argument :has_organization, Boolean, required: false
argument :has_affiliation, Boolean, required: false
argument :has_citations, Int, required: false
argument :has_parts, Int, required: false
argument :has_versions, Int, required: false
argument :has_views, Int, required: false
argument :has_downloads, Int, required: false
argument :field_of_science, String, required: false
argument :first, Int, required: false, default_value: 25
argument :after, String, required: false
end

def other_related(**args)
args[:ids] = get_other_related_ids(object.doi)
ElasticsearchModelResponseConnection.new(
response(args),
context: context, first: args[:first], after: args[:after],
)
end

def other_related_count
get_other_related_ids(object.doi).count
end

def get_other_related_ids(_doi)
Event.events_involving(_doi).map do |e|
e.doi
end.flatten.uniq - [_doi.downcase]
end


field :parts,
WorkConnectionWithTotalType,
null: true, max_page_size: 100, description: "Parts of this DOI." do
Expand Down
14 changes: 14 additions & 0 deletions app/models/doi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,20 @@ def indexed_version_of
Doi.query(nil, ids: version_of_ids, page: { number: 1, size: 25 }).results
end

def other_relation_events
Event.events_involving(doi, Event::OTHER_RELATION_TYPES)
end

def other_relation_ids
other_relation_events.map do |e|
e.doi
end.flatten.uniq - [doi.downcase]
end

def other_relation_count
other_relation_ids.length
end

def xml_encoded
Base64.strict_encode64(xml) if xml.present?
rescue ArgumentError
Expand Down
44 changes: 33 additions & 11 deletions app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,23 @@ class Event < ApplicationRecord
alias_attribute :created, :created_at
alias_attribute :updated, :updated_at

INCLUDED_RELATION_TYPES = %w[
cites
is-cited-by
is-supplement-to
is-supplemented-by
references
is-referenced-by
].freeze

# renamed to make it clearer that these relation types are grouped together as references
REFERENCE_RELATION_TYPES = %w[cites is-supplemented-by references].freeze
REFERENCE_RELATION_TYPES = %w[
cites is-supplemented-by references
].freeze

# renamed to make it clearer that these relation types are grouped together as citations
CITATION_RELATION_TYPES = %w[is-cited-by is-supplement-to is-referenced-by].freeze
CITATION_RELATION_TYPES = %w[
is-cited-by is-supplement-to is-referenced-by
].freeze

INCLUDED_RELATION_TYPES = REFERENCE_RELATION_TYPES | CITATION_RELATION_TYPES

PART_RELATION_TYPES = %w[
is-part-of has-part
]

NEW_RELATION_TYPES = %w[ is-reply-to is-translation-of is-published-in ]
RELATIONS_RELATION_TYPES = %w[
compiles
is-compiled-by
Expand Down Expand Up @@ -121,6 +123,16 @@ class Event < ApplicationRecord
is-described-by
].freeze

OTHER_RELATION_TYPES = (
RELATIONS_RELATION_TYPES | NEW_RELATION_TYPES
) - INCLUDED_RELATION_TYPES - PART_RELATION_TYPES

RELATED_SOURCE_IDS = %w[
datacite-related
datacite-crossref
crossref
].freeze

validates :subj_id, :source_id, :source_token, presence: true

attr_accessor :container_title, :url
Expand Down Expand Up @@ -1043,4 +1055,14 @@ def set_defaults
self.license = "https://creativecommons.org/publicdomain/zero/1.0/"
end
end # overridden, use uuid instead of id

def self.events_involving(_doi, relation_types = OTHER_RELATION_TYPES)
self.query(
nil,
doi: _doi,
source_id: RELATED_SOURCE_IDS.join(","),
relation_type_id: relation_types.join(","),
page: { size: 500 }
).results.results
end
end
10 changes: 5 additions & 5 deletions spec/factories/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
occurred_at { Time.zone.now }

factory :event_for_datacite_related do
source_id { "datacite_related" }
source_id { "datacite-related" }
source_token { "datacite_related_123" }
sequence(:subj_id) { |n| "http://doi.org/10.5061/DRYAD.47SD5e/#{n}" }
subj do
Expand All @@ -39,7 +39,7 @@
end

factory :event_for_datacite_parts do
source_id { "datacite_related" }
source_id { "datacite-related" }
source_token { "datacite_related_123" }
subj_id { "http://doi.org/10.5061/DRYAD.47SD5" }
subj { { "datePublished" => "2006-06-13T16:14:19Z" } }
Expand All @@ -48,7 +48,7 @@
end

factory :event_for_datacite_part_of do
source_id { "datacite_related" }
source_id { "datacite-related" }
source_token { "datacite_related_123" }
subj_id { "http://doi.org/10.5061/DRYAD.47SD5/1" }
subj { { "datePublished" => "2006-06-13T16:14:19Z" } }
Expand All @@ -57,7 +57,7 @@
end

factory :event_for_datacite_versions do
source_id { "datacite_related" }
source_id { "datacite-related" }
source_token { "datacite_related_123" }
subj_id { "http://doi.org/10.5061/DRYAD.47SD5" }
subj { { "datePublished" => "2006-06-13T16:14:19Z" } }
Expand All @@ -66,7 +66,7 @@
end

factory :event_for_datacite_version_of do
source_id { "datacite_related" }
source_id { "datacite-related" }
source_token { "datacite_related_123" }
subj_id { "http://doi.org/10.5061/DRYAD.47SD5/1" }
subj { { "datePublished" => "2006-06-13T16:14:19Z" } }
Expand Down
4 changes: 4 additions & 0 deletions spec/graphql/types/doi_item_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
it { is_expected.to have_field(:downloadCount).of_type("Int") }
it { is_expected.to have_field(:versionCount).of_type("Int") }
it { is_expected.to have_field(:versionOfCount).of_type("Int") }
it { is_expected.to have_field(:otherRelatedCount).of_type("Int") }
it { is_expected.to have_field(:partCount).of_type("Int") }
it { is_expected.to have_field(:partOfCount).of_type("Int") }
it { is_expected.to have_field(:citationsOverTime).of_type("[YearTotal!]") }
Expand All @@ -72,5 +73,8 @@
it do
is_expected.to have_field(:version_of).of_type("WorkConnectionWithTotal")
end
it do
is_expected.to have_field(:other_related).of_type("WorkConnectionWithTotal")
end
end
end
120 changes: 120 additions & 0 deletions spec/graphql/types/work_type_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1910,4 +1910,124 @@
expect(response.dig("data", "works", "funders").length()).to eq(1)
end
end

describe "query with relationships", elasticsearch: true, vcr: true do
let(:client) { create(:client) }
let(:doi) { create(:doi, client: client, aasm_state: "findable") }

let!(:ref_target_dois) { create_list(:doi, 5, client: client, aasm_state: "findable") }
let!(:reference_events) do
ref_target_dois.each do |ref_target_doi|
create(:event_for_crossref, {
subj_id: "https://doi.org/#{doi.doi}",
obj_id: "https://doi.org/#{ref_target_doi.doi}",
relation_type_id: "references"
})
end
end
let!(:citation_target_dois) { create_list(:doi, 7, client: client, aasm_state: "findable") }
let!(:citation_events) do
citation_target_dois.each do |citation_target_doi|
create(:event_for_datacite_crossref, {
subj_id: "https://doi.org/#{doi.doi}",
obj_id: "https://doi.org/#{citation_target_doi.doi}",
relation_type_id: "is-referenced-by"
})
end
end

let!(:version_target_dois) { create_list(:doi, 3, client: client, aasm_state: "findable") }
let!(:version_events) do
version_target_dois.each do |version_target_doi|
create(:event_for_datacite_versions, {
subj_id: "https://doi.org/#{doi.doi}",
obj_id: "https://doi.org/#{version_target_doi.doi}"
})
end
end

let!(:part_target_dois) { create_list(:doi, 9, client: client, aasm_state: "findable") }
let!(:part_events) do
part_target_dois.each do |part_target_doi|
create(:event_for_datacite_parts, {
subj_id: "https://doi.org/#{doi.doi}",
obj_id: "https://doi.org/#{part_target_doi.doi}",
relation_type_id: "has-part"
})
end
end

before do
Doi.import
Event.import
sleep 2
@response = LupoSchema.execute(query).as_json
end


let(:query) do
"query {
work(id: \"https://doi.org/#{
doi.doi
}\") {
id
partCount
parts{
nodes{
id
}
}
referenceCount
references{
nodes{
id
}
}
citationCount
citations{
nodes{
id
}
}
versionCount
versions{
nodes{
id
}
}
otherRelatedCount
otherRelated{
nodes{
id
}
}
}
}"
end

it "references exist" do
expect(@response.dig("data", "work", "referenceCount")).to eq(5)
expect(@response.dig("data", "work", "references", "nodes").length).to eq(5)
end

it "citations exist" do
expect(@response.dig("data", "work", "citationCount")).to eq(7)
expect(@response.dig("data", "work", "citations", "nodes").length).to eq(7)
end

it "versions exist" do
expect(@response.dig("data", "work", "versionCount")).to eq(3)
expect(@response.dig("data", "work", "versions", "nodes").length).to eq(3)
end

it "parts exist" do
expect(@response.dig("data", "work", "partCount")).to eq(9)
expect(@response.dig("data", "work", "parts", "nodes").length).to eq(9)
end

it "other_relations should not include citations,parts,references" do
expect(@response.dig("data", "work", "otherRelatedCount")).to eq(3)
expect(@response.dig("data", "work", "otherRelated", "nodes").length).to eq(3)
end
end
end
Loading

0 comments on commit e8f0d3c

Please sign in to comment.