From ee650bff66207fb392bb50b02e1bfdeb8da68ffb Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 8 Nov 2024 13:28:45 +0100 Subject: [PATCH 01/35] Fix indenting --- app/models/doi.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 53a9f83ce..9f933d350 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2518,7 +2518,7 @@ def update_publisher_from_hash def update_publisher_from_string self.publisher_obj = { name: publisher_before_type_cast } - end + end def reset_publishers self.publisher_obj = nil From 86dc385810f43841b4e2d686568f32cfadee92b0 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 8 Nov 2024 13:30:50 +0100 Subject: [PATCH 02/35] Change default ordering for DOIs in REST API --- app/controllers/datacite_dois_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 46c3d51b9..ef5c488f2 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -50,7 +50,7 @@ def index when "relevance" { "_score": { "order": "desc" } } else - { updated: { order: "desc" } } + { "_score": { "order": "desc" } } end page = page_from_params(params) From 3ec1400772066af99c1ad81de8b0e64cae1d29f3 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 8 Nov 2024 13:31:17 +0100 Subject: [PATCH 03/35] Change default ordering for DOIs in GRAPHQL API --- app/models/doi/graphql_query.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/doi/graphql_query.rb b/app/models/doi/graphql_query.rb index 6c10d1599..5461676d5 100644 --- a/app/models/doi/graphql_query.rb +++ b/app/models/doi/graphql_query.rb @@ -4,7 +4,7 @@ module Doi::GraphqlQuery class Builder include Modelable - DEFAULT_CURSOR = [0, ""] + DEFAULT_CURSOR = ["Infinity", 0] DEFAULT_PAGE_SIZE = 0 DEFAULT_FACET_COUNT = 10 @@ -29,7 +29,7 @@ def size end def sort - [{ created: "asc", uid: "asc" }] + [{ _score: "desc", uid: "asc" }] end def query_fields @@ -47,16 +47,16 @@ def query_fields def cursor tmp_cursor = @options.dig(:page, :cursor) - if tmp_cursor.nil? + if tmp_cursor.blank? return DEFAULT_CURSOR end if tmp_cursor.is_a?(Array) - timestamp, uid = tmp_cursor + tmp_score, uid = tmp_cursor elsif tmp_cursor.is_a?(String) - timestamp, uid = tmp_cursor.split(",") + tmp_score, uid = tmp_cursor.split(",") end - [timestamp.to_i, uid.to_s] + [tmp_score.to_f, uid.to_s] end def search_after From 99e104ee5a9cdc0c7bab254d01ab878f765540ed Mon Sep 17 00:00:00 2001 From: Joseph Rhoads Date: Thu, 14 Nov 2024 11:41:49 -0500 Subject: [PATCH 04/35] Revert "Chang default DOI search order" --- app/controllers/datacite_dois_controller.rb | 2 +- app/models/doi.rb | 2 +- app/models/doi/graphql_query.rb | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index ef5c488f2..46c3d51b9 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -50,7 +50,7 @@ def index when "relevance" { "_score": { "order": "desc" } } else - { "_score": { "order": "desc" } } + { updated: { order: "desc" } } end page = page_from_params(params) diff --git a/app/models/doi.rb b/app/models/doi.rb index 9f933d350..53a9f83ce 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2518,7 +2518,7 @@ def update_publisher_from_hash def update_publisher_from_string self.publisher_obj = { name: publisher_before_type_cast } - end + end def reset_publishers self.publisher_obj = nil diff --git a/app/models/doi/graphql_query.rb b/app/models/doi/graphql_query.rb index 5461676d5..6c10d1599 100644 --- a/app/models/doi/graphql_query.rb +++ b/app/models/doi/graphql_query.rb @@ -4,7 +4,7 @@ module Doi::GraphqlQuery class Builder include Modelable - DEFAULT_CURSOR = ["Infinity", 0] + DEFAULT_CURSOR = [0, ""] DEFAULT_PAGE_SIZE = 0 DEFAULT_FACET_COUNT = 10 @@ -29,7 +29,7 @@ def size end def sort - [{ _score: "desc", uid: "asc" }] + [{ created: "asc", uid: "asc" }] end def query_fields @@ -47,16 +47,16 @@ def query_fields def cursor tmp_cursor = @options.dig(:page, :cursor) - if tmp_cursor.blank? + if tmp_cursor.nil? return DEFAULT_CURSOR end if tmp_cursor.is_a?(Array) - tmp_score, uid = tmp_cursor + timestamp, uid = tmp_cursor elsif tmp_cursor.is_a?(String) - tmp_score, uid = tmp_cursor.split(",") + timestamp, uid = tmp_cursor.split(",") end - [tmp_score.to_f, uid.to_s] + [timestamp.to_i, uid.to_s] end def search_after From a4ea81a51e3f1932f2afe74e08b6d8c15533178c Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Fri, 15 Nov 2024 17:42:09 +0200 Subject: [PATCH 05/35] add middleware error handling --- lib/middleware/compressed_requests.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index 02ffbf541..988ba62d8 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -28,8 +28,14 @@ def call(env) env["rack.input"] = StringIO.new(extracted) end - status, headers, response = @app.call(env) - [status, headers, response] + begin + status, headers, response = @app.call(env) + [status, headers, response] + rescue => err + Raven.capture_exception(err) + Rails.logger.error(err.inspect) + [500, {}, [{"status": 400, "title": err.message}.to_json]] + end end def decode(input, content_encoding) From 41cf4495f24ea88f175660230d1cafea676e9eff Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Fri, 15 Nov 2024 17:48:36 +0200 Subject: [PATCH 06/35] fix rubocop offence --- lib/middleware/compressed_requests.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index 988ba62d8..f1de08b2b 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -31,10 +31,10 @@ def call(env) begin status, headers, response = @app.call(env) [status, headers, response] - rescue => err + rescue => errß Raven.capture_exception(err) Rails.logger.error(err.inspect) - [500, {}, [{"status": 400, "title": err.message}.to_json]] + [500, {}, [{ "status": 400, "title": err.message }.to_json]] end end From e20f7e8460a41a460f232c9e3e2fe0cc5d04a8da Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Fri, 15 Nov 2024 17:49:45 +0200 Subject: [PATCH 07/35] fix rubocop offence --- lib/middleware/compressed_requests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index f1de08b2b..7b23a99c3 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -31,7 +31,7 @@ def call(env) begin status, headers, response = @app.call(env) [status, headers, response] - rescue => errß + rescue => err Raven.capture_exception(err) Rails.logger.error(err.inspect) [500, {}, [{ "status": 400, "title": err.message }.to_json]] From 3839f8b4f0966f4589eb05e835bb8444f7161470 Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Fri, 15 Nov 2024 18:01:05 +0200 Subject: [PATCH 08/35] change status code --- lib/middleware/compressed_requests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index 7b23a99c3..2352df629 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -34,7 +34,7 @@ def call(env) rescue => err Raven.capture_exception(err) Rails.logger.error(err.inspect) - [500, {}, [{ "status": 400, "title": err.message }.to_json]] + [500, {}, [{ "status": 500, "title": err.message }.to_json]] end end From 0a0e0ebb3c6c0d50f4852171d7e8f31b06276f5c Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Mon, 18 Nov 2024 08:34:23 +0200 Subject: [PATCH 09/35] change status code --- lib/middleware/compressed_requests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index 2352df629..7b23a99c3 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -34,7 +34,7 @@ def call(env) rescue => err Raven.capture_exception(err) Rails.logger.error(err.inspect) - [500, {}, [{ "status": 500, "title": err.message }.to_json]] + [500, {}, [{ "status": 400, "title": err.message }.to_json]] end end From 1deddbb0a023454b3243d90332a716dd3bc5e49d Mon Sep 17 00:00:00 2001 From: Bryceson Laing Date: Tue, 19 Nov 2024 06:46:32 -0600 Subject: [PATCH 10/35] Add agency to dois response (#1276) * add agency to dois response * update spec for agency --- app/serializers/datacite_doi_serializer.rb | 1 + spec/requests/datacite_dois/datacite_dois_spec.rb | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index fc27235c5..39682551c 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -18,6 +18,7 @@ class DataciteDoiSerializer :titles, :publisher, :container, + :agency, :publication_year, :subjects, :contributors, diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index 4aa5593e9..04278b010 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -438,6 +438,17 @@ def clear_doi_index end end + describe "GET /dois/:id with agency values", prefix_pool_size: 1 do + let!(:doi) { create(:doi, client: client, aasm_state: "findable") } + + it "returns agency values" do + get "/dois/#{doi.doi}", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "agency")).to eq("datacite") + end + end + describe "GET /dois with client-type filter", prefix_pool_size: 3 do let!(:dois) { create_list(:doi, 10, client: client, aasm_state: "findable", version_info: "testtag") } let(:client_igsn_id_catalog) { create(:client, provider: provider, client_type: "igsnCatalog") } From 6c34d51fbeff294e6084f409bd35052dca845ab1 Mon Sep 17 00:00:00 2001 From: Bryceson Laing Date: Tue, 19 Nov 2024 09:58:50 -0600 Subject: [PATCH 11/35] Revert "Add agency to dois response (#1276)" (#1277) This reverts commit 1deddbb0a023454b3243d90332a716dd3bc5e49d. --- app/serializers/datacite_doi_serializer.rb | 1 - spec/requests/datacite_dois/datacite_dois_spec.rb | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index 39682551c..fc27235c5 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -18,7 +18,6 @@ class DataciteDoiSerializer :titles, :publisher, :container, - :agency, :publication_year, :subjects, :contributors, diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index 04278b010..4aa5593e9 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -438,17 +438,6 @@ def clear_doi_index end end - describe "GET /dois/:id with agency values", prefix_pool_size: 1 do - let!(:doi) { create(:doi, client: client, aasm_state: "findable") } - - it "returns agency values" do - get "/dois/#{doi.doi}", nil, headers - - expect(last_response.status).to eq(200) - expect(json.dig("data", "attributes", "agency")).to eq("datacite") - end - end - describe "GET /dois with client-type filter", prefix_pool_size: 3 do let!(:dois) { create_list(:doi, 10, client: client, aasm_state: "findable", version_info: "testtag") } let(:client_igsn_id_catalog) { create(:client, provider: provider, client_type: "igsnCatalog") } From c135d2d5f92946f6ed4b504e5aa731675dc46ecf Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Tue, 19 Nov 2024 18:11:15 +0200 Subject: [PATCH 12/35] Revert "add middleware error handling" --- lib/middleware/compressed_requests.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index 7b23a99c3..02ffbf541 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -28,14 +28,8 @@ def call(env) env["rack.input"] = StringIO.new(extracted) end - begin - status, headers, response = @app.call(env) - [status, headers, response] - rescue => err - Raven.capture_exception(err) - Rails.logger.error(err.inspect) - [500, {}, [{ "status": 400, "title": err.message }.to_json]] - end + status, headers, response = @app.call(env) + [status, headers, response] end def decode(input, content_encoding) From fdf9ec8328413eaaf67bd18787374cfa92117ce9 Mon Sep 17 00:00:00 2001 From: Bryceson Laing Date: Wed, 20 Nov 2024 08:18:36 -0600 Subject: [PATCH 13/35] Add agency to dois response (#1281) * add agency to dois response * update spec for agency * only return agency when include_other_registration_agencies is set * pass include_other_registration_agencies to serializer --- app/controllers/datacite_dois_controller.rb | 8 +++++++- app/serializers/datacite_doi_serializer.rb | 3 +++ .../datacite_dois/datacite_dois_spec.rb | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 46c3d51b9..456e4822c 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -203,6 +203,7 @@ def index detail: params[:detail], affiliation: params[:affiliation], publisher: params[:publisher], + include_other_registration_agencies: params[:include_other_registration_agencies], is_collection: options[:is_collection], } @@ -349,6 +350,7 @@ def index composite: params[:composite], affiliation: params[:affiliation], publisher: params[:publisher], + include_other_registration_agencies: params[:include_other_registration_agencies], is_collection: options[:is_collection], } @@ -447,6 +449,7 @@ def show composite: nil, affiliation: params[:affiliation], publisher: params[:publisher], + include_other_registration_agencies: params[:include_other_registration_agencies], } render( @@ -504,7 +507,8 @@ def validate options[:params] = { current_ability: current_ability, affiliation: params[:affiliation], - publisher: params[:publisher] + publisher: params[:publisher], + include_other_registration_agencies: params[:include_other_registration_agencies], } render( @@ -535,6 +539,7 @@ def create detail: true, affiliation: params[:affiliation], publisher: params[:publisher], + include_other_registration_agencies: params[:include_other_registration_agencies], } render( @@ -595,6 +600,7 @@ def update detail: true, affiliation: params[:affiliation], publisher: params[:publisher], + include_other_registration_agencies: params[:include_other_registration_agencies], } render( diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index fc27235c5..41d70982a 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -65,6 +65,9 @@ class DataciteDoiSerializer :citations_over_time, if: Proc.new { |_object, params| params && params[:detail] } + attributes :agency, + if: Proc.new { |_object, params| params && params[:include_other_registration_agencies] } + belongs_to :client, record_type: :clients belongs_to :provider, diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index 4aa5593e9..14c3bcf02 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -438,6 +438,24 @@ def clear_doi_index end end + describe "GET /dois/:id with agency values", prefix_pool_size: 1 do + let!(:doi) { create(:doi, client: client, aasm_state: "findable") } + + it "returns agency values when flag is set" do + get "/dois/#{doi.doi}?include_other_registration_agencies=true", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "agency")).to eq("datacite") + end + + it "does not returns agency values when flag isn't set" do + get "/dois/#{doi.doi}", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes")).to_not have_key("agency") + end + end + describe "GET /dois with client-type filter", prefix_pool_size: 3 do let!(:dois) { create_list(:doi, 10, client: client, aasm_state: "findable", version_info: "testtag") } let(:client_igsn_id_catalog) { create(:client, provider: provider, client_type: "igsnCatalog") } From 4a2c641b28bb388bd1bb496b9c3243f34ecd7a11 Mon Sep 17 00:00:00 2001 From: Wendel Fabian Chinsamy Date: Wed, 20 Nov 2024 17:25:36 +0200 Subject: [PATCH 14/35] add middleware error logging --- lib/middleware/compressed_requests.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/middleware/compressed_requests.rb b/lib/middleware/compressed_requests.rb index 02ffbf541..7b23a99c3 100644 --- a/lib/middleware/compressed_requests.rb +++ b/lib/middleware/compressed_requests.rb @@ -28,8 +28,14 @@ def call(env) env["rack.input"] = StringIO.new(extracted) end - status, headers, response = @app.call(env) - [status, headers, response] + begin + status, headers, response = @app.call(env) + [status, headers, response] + rescue => err + Raven.capture_exception(err) + Rails.logger.error(err.inspect) + [500, {}, [{ "status": 400, "title": err.message }.to_json]] + end end def decode(input, content_encoding) From 53103ab05b18fc416364f114518c9a118b64aab2 Mon Sep 17 00:00:00 2001 From: kudakwashe siziva <9620622+kaysiz@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:17:22 +0200 Subject: [PATCH 15/35] Schema 4.6 (#1259) * Update resource types general * Update with schema 4.6 attributes * Add .ruby-version * Use bolognese for schema2.6 branch * Added test for schema 4.6 changes * Add test case for schema 4.6 * fixed lint errors * Specify current the ruby version * Updated new bolognese gem version --------- Co-authored-by: Ashwini Sukale --- .gitignore | 1 - .ruby-version | 1 + Gemfile | 2 +- Gemfile.lock | 5 ++- app/models/doi.rb | 2 +- app/models/resource_type.rb | 2 + config/initializers/constants.rb | 1 + openapi.yaml | 8 ++++ spec/models/doi_spec.rb | 71 +++++++++++++++++++++++++++++++ spec/models/resource_type_spec.rb | 2 + 10 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 .ruby-version diff --git a/.gitignore b/.gitignore index 6589b2ff3..cec82e61c 100644 --- a/.gitignore +++ b/.gitignore @@ -53,7 +53,6 @@ doc/dependencies* !.env.travis !.env.build docker-compose.override.yml -.ruby-version .vscode .solargraph.yml .devspace \ No newline at end of file diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000..9cec7165a --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.1.6 diff --git a/Gemfile b/Gemfile index 74b3d0344..0d5048af0 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem "aws-sdk-sqs", "~> 1.3" gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" -gem "bolognese", "~> 2.2" +gem "bolognese", "~> 2.3" gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "countries", "~> 2.1", ">= 2.1.2" diff --git a/Gemfile.lock b/Gemfile.lock index 6b22da46c..a0c79b37d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -132,7 +132,7 @@ GEM bigdecimal (3.1.6) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bolognese (2.2.0) + bolognese (2.3.0) activesupport (>= 4.2.5) benchmark_methods (~> 0.7) bibtex-ruby (>= 5.1.0) @@ -768,6 +768,7 @@ GEM PLATFORMS aarch64-linux + arm64-darwin-23 universal-darwin-21 x86_64-darwin-20 x86_64-linux @@ -785,7 +786,7 @@ DEPENDENCIES bcrypt (~> 3.1.7) better_errors binding_of_caller - bolognese (~> 2.2) + bolognese (~> 2.3) bootsnap (~> 1.4, >= 1.4.4) brakeman (~> 6.1, >= 6.1.2) bullet (~> 7.1, >= 7.1.6) diff --git a/app/models/doi.rb b/app/models/doi.rb index 53a9f83ce..b9a2c9bd6 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -1961,7 +1961,7 @@ def check_contributors Array.wrap(contributors).each do |c| errors.add(:contributors, "Contributor '#{c}' should be an object instead of a string.") unless c.is_a?(Hash) if schema_version == "http://datacite.org/schema/kernel-4" - errors.add(:contributors, "Contributor type #{c['contributorType']} is not supported in schema 4.") unless %w(ContactPerson DataCollector DataCurator DataManager Distributor Editor HostingInstitution Other Producer ProjectLeader ProjectManager ProjectMember RegistrationAgency RegistrationAuthority RelatedPerson ResearchGroup RightsHolder Researcher Sponsor Supervisor WorkPackageLeader).include?(c["contributorType"]) + errors.add(:contributors, "Contributor type #{c['contributorType']} is not supported in schema 4.") unless %w(ContactPerson DataCollector DataCurator DataManager Distributor Editor HostingInstitution Other Producer ProjectLeader ProjectManager ProjectMember RegistrationAgency RegistrationAuthority RelatedPerson ResearchGroup RightsHolder Researcher Sponsor Supervisor Translator WorkPackageLeader).include?(c["contributorType"]) end end end diff --git a/app/models/resource_type.rb b/app/models/resource_type.rb index 54ac6ba04..79ec9e653 100644 --- a/app/models/resource_type.rb +++ b/app/models/resource_type.rb @@ -33,6 +33,7 @@ def self.debug def self.get_data(_options = {}) [ { "id" => "audiovisual", "title" => "Audiovisual" }, + { "id" => "award", "title" => "Award" }, { "id" => "book", "title" => "Book" }, { "id" => "book-chapter", "title" => "BookChapter" }, { "id" => "collection", "title" => "Collection" }, @@ -53,6 +54,7 @@ def self.get_data(_options = {}) { "id" => "peer-review", "title" => "PeerReview" }, { "id" => "physical-object", "title" => "PhysicalObject" }, { "id" => "preprint", "title" => "Preprint" }, + { "id" => "project", "title" => "Project" }, { "id" => "report", "title" => "Report" }, { "id" => "service", "title" => "Service" }, { "id" => "software", "title" => "Software" }, diff --git a/config/initializers/constants.rb b/config/initializers/constants.rb index d0c52a5fd..7c4c7d8a8 100644 --- a/config/initializers/constants.rb +++ b/config/initializers/constants.rb @@ -55,6 +55,7 @@ class IdentifierError < RuntimeError; end RESOURCE_TYPES_GENERAL = { "Audiovisual" => "Audiovisual", + "Award" => "Award", "Book" => "Book", "BookChapter" => "Book Chapter", "Collection" => "Collection", diff --git a/openapi.yaml b/openapi.yaml index 68acc0736..0dc0c754e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2165,6 +2165,7 @@ components: - Available - Copyrighted - Collected + - Coverage - Created - Issued - Submitted @@ -3047,11 +3048,14 @@ components: - Obsoletes - IsCollectedBy - Collects + - IsTranslationOf + - HasTranslation resourceTypeGeneral: description: '[DataCite Metadata Schema: resourceTypeGeneral](https://datacite-metadata-schema.readthedocs.io/en/4/appendices/appendix-1/resourceTypeGeneral/)' type: string enum: - Audiovisual + - Award - Book - BookChapter - Collection @@ -3072,6 +3076,7 @@ components: - PeerReview - PhysicalObject - Preprint + - Project - Report - Service - Software @@ -3104,6 +3109,7 @@ components: - RightsHolder - Sponsor - Supervisor + - Translator - WorkPackageLeader - Other relatedIdentifierType: @@ -3113,6 +3119,7 @@ components: - ARK - arXiv - bibcode + - CSTR - DOI - EAN13 - EISSN @@ -3125,6 +3132,7 @@ components: - LSID - PMID - PURL + - RRID - UPC - URL - URN diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index 5e97b64a7..85bad8fc1 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -1215,6 +1215,27 @@ }, ], }, + { + "contributorType" => "Translator", + "familyName" => "Doe", + "givenName" => "Jane", + "name" => "Doe, Jane", + "nameIdentifiers" => [ + { + "nameIdentifier" => "https://orcid.org/0000-0003-0800-1234", + "nameIdentifierScheme" => "ORCID", + "schemeUri" => "https://orcid.org", + }, + ], + "nameType" => "Personal", + "affiliation" => [ + { + "name" => "Example Translation Services", + "affiliationIdentifier" => "https://ror.org/013meh9876", + "affiliationIdentifierScheme" => "ROR", + }, + ], + }, ] ) expect(subject).to be_valid @@ -1222,6 +1243,7 @@ [ "https://orcid.org/0000-0003-3484-6875", "https://orcid.org/0000-0003-3484-0000", + "https://orcid.org/0000-0003-0800-1234", # Contributor: Jane Doe (Translator) ] ) end @@ -1994,4 +2016,53 @@ ) end end + + describe "check schema 4.6 changes" do + let(:doi) { FactoryBot.create(:doi, + types: { + "resourceTypeGeneral": "Award", + "resourceType": "Grant" + }, + creators: [{ + "nameType": "Personal", + "name": "Doe, John", + "givenName": "John", + "familyName": "Doe", + "contributorType": "Translator" + }], + related_identifiers: [ + { + "relatedIdentifier": "RRID:SCR_123456", + "relatedIdentifierType": "RRID", + "relationType": "HasTranslation" + } + ], + dates: [ + { "date": "2011-10-23", "dateType": "Issued" }, + { "date": "2020-03-15", "dateType": "Coverage" } + ] + )} + + it "saves and returns new resourceTypeGeneral values" do + expect(doi.types["resourceTypeGeneral"]).to eq("Award") + expect(doi.types["resourceType"]).to eq("Grant") + end + + it "saves and returns new contributorType value" do + expect(doi.creators.first["contributorType"]).to eq("Translator") + end + + it "saves and returns new relatedIdentifierType value" do + expect(doi.related_identifiers.first["relatedIdentifierType"]).to eq("RRID") + end + + it "saves and returns new relationType value" do + expect(doi.related_identifiers.first["relationType"]).to eq("HasTranslation") + end + + it "saves and returns new dateType value" do + coverage_date = doi.dates.find { |d| d["dateType"] == "Coverage" } + expect(coverage_date["date"]).to eq("2020-03-15") + end + end end diff --git a/spec/models/resource_type_spec.rb b/spec/models/resource_type_spec.rb index 2afa5d939..872b707dd 100644 --- a/spec/models/resource_type_spec.rb +++ b/spec/models/resource_type_spec.rb @@ -47,6 +47,8 @@ { "id" => "standard", "title" => "Standard" }, { "id" => "text", "title" => "Text" }, { "id" => "workflow", "title" => "Workflow" }, + { "id" => "award", "title" => "Award" }, + { "id" => "project", "title" => "Project" }, { "id" => "other", "title" => "Other" }) end end From eaffb5c48aec63078c3ce709cfa6f81620e36c5e Mon Sep 17 00:00:00 2001 From: Bryceson Laing Date: Wed, 20 Nov 2024 12:04:23 -0600 Subject: [PATCH 16/35] add spec for agency in dois search response (#1283) --- .../datacite_dois/datacite_dois_spec.rb | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index 14c3bcf02..999c5031c 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -456,6 +456,29 @@ def clear_doi_index end end + describe "GET /dois search with agency values", prefix_pool_size: 1 do + let!(:dois) { create_list(:doi, 10, client: client, aasm_state: "findable") } + + before do + clear_doi_index + import_doi_index + end + + it "returns agency values when flag is set" do + get "/dois?include_other_registration_agencies=true", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", 0, "attributes", "agency")).to eq("datacite") + end + + it "does not returns agency values when flag isn't set" do + get "/dois", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", 0, "attributes")).to_not have_key("agency") + end + end + describe "GET /dois with client-type filter", prefix_pool_size: 3 do let!(:dois) { create_list(:doi, 10, client: client, aasm_state: "findable", version_info: "testtag") } let(:client_igsn_id_catalog) { create(:client, provider: provider, client_type: "igsnCatalog") } From 2c917fc40cdd649f7c80685628be89d62c902660 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:55:39 -0500 Subject: [PATCH 17/35] Update bolognese to 2.3.2 --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 0d5048af0..2739be83a 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem "aws-sdk-sqs", "~> 1.3" gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" -gem "bolognese", "~> 2.3" +gem "bolognese", "~> 2.3.2" gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "countries", "~> 2.1", ">= 2.1.2" diff --git a/Gemfile.lock b/Gemfile.lock index a0c79b37d..8547a5e07 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -132,7 +132,7 @@ GEM bigdecimal (3.1.6) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bolognese (2.3.0) + bolognese (2.3.2) activesupport (>= 4.2.5) benchmark_methods (~> 0.7) bibtex-ruby (>= 5.1.0) @@ -786,7 +786,7 @@ DEPENDENCIES bcrypt (~> 3.1.7) better_errors binding_of_caller - bolognese (~> 2.3) + bolognese (~> 2.3.2) bootsnap (~> 1.4, >= 1.4.4) brakeman (~> 6.1, >= 6.1.2) bullet (~> 7.1, >= 7.1.6) @@ -883,4 +883,4 @@ DEPENDENCIES webmock (~> 3.18, >= 3.18.1) BUNDLED WITH - 2.5.6 + 2.3.27 From 38cd9560f4f6f7d8a5ae2f10f9fd6bb34e39d9da Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:53:32 -0500 Subject: [PATCH 18/35] Initial implementation of clientTypes facets in GraphQL --- app/graphql/schema.graphql | 27 ++++- .../types/interfaces/work_facets_interface.rb | 9 ++ app/models/doi/graphql_query.rb | 9 ++ spec/graphql/types/work_type_spec.rb | 109 ++++++++++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index a917b04ad..cce3b8b23 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -409,6 +409,7 @@ The connection type for Audiovisual. type AudiovisualConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1048,6 +1049,7 @@ The connection type for BookChapter. type BookChapterConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1099,6 +1101,7 @@ The connection type for Book. type BookConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1492,6 +1495,7 @@ The connection type for Collection. type CollectionConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1837,6 +1841,7 @@ The connection type for ConferencePaper. type ConferencePaperConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -2474,6 +2479,7 @@ The connection type for DataManagementPlan. type DataManagementPlanConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -2819,6 +2825,7 @@ The connection type for DataPaper. type DataPaperConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -3185,6 +3192,7 @@ The connection type for Dataset. type DatasetConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] datasetConnectionCount: Int! @@ -3627,6 +3635,7 @@ The connection type for Dissertation. type DissertationConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -5261,6 +5270,7 @@ The connection type for Image. type ImageConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -5606,6 +5616,7 @@ The connection type for Instrument. type InstrumentConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -5951,6 +5962,7 @@ The connection type for InteractiveResource. type InteractiveResourceConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -6301,6 +6313,7 @@ The connection type for JournalArticle. type JournalArticleConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -6942,6 +6955,7 @@ The connection type for Model. type ModelConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -7484,6 +7498,7 @@ The connection type for Other. type OtherConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -7854,6 +7869,7 @@ The connection type for PeerReview. type PeerReviewConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -8336,6 +8352,7 @@ The connection type for PhysicalObject. type PhysicalObjectConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -8734,6 +8751,7 @@ The connection type for Preprint. type PreprintConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -9079,6 +9097,7 @@ The connection type for Publication. type PublicationConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] datasetConnectionCount: Int! @@ -9246,7 +9265,7 @@ type Query { work(id: ID!): Work! workflow(id: ID!): Workflow! workflows(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): WorkflowConnectionWithTotal! - works(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, resourceType: String, resourceTypeId: String, userId: String): WorkConnectionWithTotal! + works(after: String, clientType: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, resourceType: String, resourceTypeId: String, userId: String): WorkConnectionWithTotal! } """ @@ -10099,6 +10118,7 @@ The connection type for Service. type ServiceConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -10470,6 +10490,7 @@ The connection type for Software. type SoftwareConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] datasetConnectionCount: Int! @@ -10821,6 +10842,7 @@ The connection type for Sound. type SoundConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -11377,6 +11399,7 @@ The connection type for Work. type WorkConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -11429,6 +11452,7 @@ type WorkEdge { interface WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] fieldsOfScience: [Facet!] fieldsOfScienceCombined: [Facet!] @@ -11744,6 +11768,7 @@ The connection type for Workflow. type WorkflowConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] + clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ diff --git a/app/graphql/types/interfaces/work_facets_interface.rb b/app/graphql/types/interfaces/work_facets_interface.rb index baa78cfe7..182f22cc0 100644 --- a/app/graphql/types/interfaces/work_facets_interface.rb +++ b/app/graphql/types/interfaces/work_facets_interface.rb @@ -19,6 +19,7 @@ module Interfaces::WorkFacetsInterface field :fields_of_science_repository, [FacetType], null: true, cache: true field :licenses, [FacetType], null: true, cache: true field :languages, [FacetType], null: true, cache: true + field :client_types, [FacetType], null: true, cache: true field :person_to_work_types_multilevel, [MultiFacetType], null: true, cache: true def person_to_work_types_multilevel @@ -140,4 +141,12 @@ def languages [] end end + + def client_types + if object.aggregations.client_types + facet_by_client_type(object.aggregations.client_types.buckets) + else + [] + end + end end diff --git a/app/models/doi/graphql_query.rb b/app/models/doi/graphql_query.rb index 6c10d1599..660de86ab 100644 --- a/app/models/doi/graphql_query.rb +++ b/app/models/doi/graphql_query.rb @@ -175,6 +175,8 @@ def filters filter << { terms: { "client.certificate" => options[:certificate].split(",") } } if options[:certificate].present? filter << { terms: { "creators.nameIdentifiers.nameIdentifier" => options[:user_id].split(",").collect { |id| "https://orcid.org/#{orcid_from_url(id)}" } } } if options[:user_id].present? filter << { term: { "creators.nameIdentifiers.nameIdentifierScheme" => "ORCID" } } if options[:has_person].present? + filter << { term: { "client.client_type" => options[:client_type] } } if options[:client_type] + filter << { term: { "types.resourceTypeGeneral" => "PhysicalObject" } } if options[:client_type] == "igsnCatalog" filter end @@ -407,6 +409,13 @@ def aggregations download_count: { sum: { field: "download_count" } }, citation_count: { sum: { field: "citation_count" } }, content_url_count: { value_count: { field: "content_url" } }, + client_types: { + terms: { + field: "client.client_type", + size: facet_count, + min_doc_count: 1 + } + } } end end diff --git a/spec/graphql/types/work_type_spec.rb b/spec/graphql/types/work_type_spec.rb index bd73f974e..5caf7de78 100644 --- a/spec/graphql/types/work_type_spec.rb +++ b/spec/graphql/types/work_type_spec.rb @@ -2220,4 +2220,113 @@ expect(response.dig("data", "works", "nodes", 0, "doi")).to eq(study_registration_doi.doi.downcase) expect(response.dig("data", "works", "nodes", 0, "types", "resourceTypeGeneral")).to eq("StudyRegistration") end + + it "returns project resource types" do + response = LupoSchema.execute(query, variables: { first: 15, cursor: nil }).as_json + + expect(response.dig("data", "works", "resourceTypes")).to eq( + [{ "count" => 10, "id" => "project", "title" => "Project" }, { "count" => 5, "id" => "dataset", "title" => "Dataset" }] + ) + end + + it "returns projects when querying works based on resource_type_id" do + response = + LupoSchema.execute( + query, + variables: { first: 15, cursor: nil, resourceTypeId: "Project" } + ). + as_json + + expect(response.dig("data", "works", "totalCount")).to eq(10) + end +end + +describe "query with client_type facet", elasticsearch: true do + let(:provider) { create(:provider) } + let(:client_repository) { create(:client, provider: provider, client_type: "repository") } + let(:client_periodical) { create(:client, provider: provider, client_type: "periodical") } + let(:client_igsn_id_catalog) { create(:client, provider: provider, client_type: "igsnCatalog") } + let(:client_raid_registry) { create(:client, provider: provider, client_type: "raidRegistry") } + let!(:dois_repository) { create_list(:doi, 10, client: client_repository, aasm_state: "findable", version_info: "testtag") } + let!(:dois_periodical) { create_list(:doi, 10, client: client_periodical, aasm_state: "findable", version_info: "testtag") } + let!(:doi_igsn_id) { create(:doi, client: client_igsn_id_catalog, aasm_state: "findable", types: { "resourceTypeGeneral": "PhysicalObject" }) } + let!(:doi_igsn_id_dataset) { create(:doi, client: client_igsn_id_catalog, aasm_state: "findable", types: { "resourceTypeGeneral": "Dataset" }) } + let!(:doi_raid_registry) { create(:doi, client: client_raid_registry, aasm_state: "findable") } + + before do + Doi.import + sleep 2 + end + + let(:query) do + "query($first: Int, $cursor: String) { + works(first: $first, after: $cursor) { + totalCount + clientTypes { + id + title + count + } + nodes { + doi + types { + resourceTypeGeneral + } + } + } + }" + end + + let(:query_with_client_type_filter) do + "query($first: Int, $cursor: String, $clientType: String) { + works(first: $first, after: $cursor, clientType: $clientType) { + totalCount + clientTypes { + id + title + count + } + nodes { + doi + types { + resourceTypeGeneral + } + } + } + }" + end + + it "returns clientTypes facet" do + response = + LupoSchema.execute( + query, + ). + as_json + + expect(response.dig("data", "works", "totalCount")).to eq(23) + expect(response.dig("data", "works", "clientTypes")).to eq( + [ + { "count" => 10, "id" => "periodical", "title" => "Periodical" }, + { "count" => 10, "id" => "repository", "title" => "Repository" }, + { "count" => 2, "id" => "igsnCatalog", "title" => "IGSN ID Catalog" }, + { "count" => 1, "id" => "raidRegistry", "title" => "RAiD Registry" }, + ] + ) + end + + it "returns filtered DOIs by clientType and only returns PhysicalObjects for igsnCatalog filter" do + response = + LupoSchema.execute( + query_with_client_type_filter, + variables: { first: 15, cursor: nil, clientType: "igsnCatalog" } + ). + as_json + + expect(response.dig("data", "works", "totalCount")).to eq(1) + expect(response.dig("data", "works", "clientTypes")).to eq( + [ + { "count" => 1, "id" => "igsnCatalog", "title" => "IGSN ID Catalog" }, + ] + ) + end end From 5eaa099689eb28dff36bca8772aa10c7aace2e83 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 Nov 2024 11:49:51 +0100 Subject: [PATCH 19/35] Add client_type/repository_type as a parameter the user can pass to the gql query --- app/graphql/types/query_type.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 2f6ac604b..f56b2f432 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -256,6 +256,7 @@ def actor(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :resource_type_id, String, required: false @@ -303,6 +304,7 @@ def work(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -345,6 +347,7 @@ def dataset(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -387,6 +390,7 @@ def publication(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -429,6 +433,7 @@ def audiovisual(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -471,6 +476,7 @@ def collection(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -513,6 +519,7 @@ def data_paper(id:) argument :published, String, required: false argument :user_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -553,6 +560,7 @@ def event(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -595,6 +603,7 @@ def image(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -637,6 +646,7 @@ def interactive_resource(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -679,6 +689,7 @@ def model(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -721,6 +732,7 @@ def physical_object(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -764,6 +776,7 @@ def service(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -806,6 +819,7 @@ def software(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -848,6 +862,7 @@ def sound(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -890,6 +905,7 @@ def workflow(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -933,6 +949,7 @@ def dissertation(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -976,6 +993,7 @@ def data_management_plan(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1019,6 +1037,7 @@ def preprint(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1062,6 +1081,7 @@ def peer_review(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1105,6 +1125,7 @@ def conference_paper(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1148,6 +1169,7 @@ def book_chapter(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1191,6 +1213,7 @@ def book(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1234,6 +1257,7 @@ def journal_article(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1277,6 +1301,7 @@ def instrument(id:) argument :user_id, String, required: false argument :funder_id, String, required: false argument :repository_id, String, required: false + argument :repository_type, String, required: false argument :member_id, String, required: false argument :registration_agency, String, required: false argument :license, String, required: false @@ -1337,6 +1362,7 @@ def response(**args) ids: args[:ids], user_id: args[:user_id], client_id: args[:repository_id], + client_type: args[:repository_type], provider_id: args[:member_id], funder_id: args[:funder_id], resource_type_id: args[:resource_type_id], From 672a09d6d5db789c41f034ca1d10578161d03ce2 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 Nov 2024 11:51:52 +0100 Subject: [PATCH 20/35] Update schema.graphql --- app/graphql/schema.graphql | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index cce3b8b23..8131f30ad 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -9184,66 +9184,66 @@ type Query { actor(id: ID!): ActorItem! actors(after: String, first: Int = 25, query: String): ActorConnection! audiovisual(id: ID!): Audiovisual! - audiovisuals(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): AudiovisualConnectionWithTotal! + audiovisuals(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): AudiovisualConnectionWithTotal! book(id: ID!): Book! bookChapter(id: ID!): BookChapter! - bookChapters(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): BookChapterConnectionWithTotal! - books(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): BookConnectionWithTotal! + bookChapters(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): BookChapterConnectionWithTotal! + books(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): BookConnectionWithTotal! collection(id: ID!): Collection! - collections(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): CollectionConnectionWithTotal! + collections(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): CollectionConnectionWithTotal! conferencePaper(id: ID!): ConferencePaper! - conferencePapers(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): ConferencePaperConnectionWithTotal! + conferencePapers(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): ConferencePaperConnectionWithTotal! dataCatalog(id: ID!): DataCatalog! dataCatalogs(after: String, certified: String, disciplinary: String, first: Int = 25, open: String, pid: String, query: String, software: String, subject: String): DataCatalogConnectionWithTotal! dataManagementPlan(id: ID!): DataManagementPlan! - dataManagementPlans(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): DataManagementPlanConnectionWithTotal! + dataManagementPlans(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): DataManagementPlanConnectionWithTotal! dataPaper(id: ID!): DataPaper! - dataPapers(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): DataPaperConnectionWithTotal! + dataPapers(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): DataPaperConnectionWithTotal! dataset(id: ID!): Dataset! - datasets(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): DatasetConnectionWithTotal! + datasets(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): DatasetConnectionWithTotal! dissertation(id: ID!): Dissertation! - dissertations(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): DissertationConnectionWithTotal! + dissertations(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): DissertationConnectionWithTotal! event(id: ID!): Event! - events(after: String, facetCount: Int = 10, fieldOfScience: String, first: Int = 25, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): EventConnectionWithTotal! + events(after: String, facetCount: Int = 10, fieldOfScience: String, first: Int = 25, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): EventConnectionWithTotal! funder(id: ID!): Funder! funders(after: String, first: Int = 25, query: String): FunderConnectionWithTotal! image(id: ID!): Image! - images(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): ImageConnectionWithTotal! + images(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): ImageConnectionWithTotal! instrument(id: ID!): Instrument! - instruments(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): InstrumentConnectionWithTotal! + instruments(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): InstrumentConnectionWithTotal! interactiveResource(id: ID!): InteractiveResource! - interactiveResources(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): InteractiveResourceConnectionWithTotal! + interactiveResources(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): InteractiveResourceConnectionWithTotal! journalArticle(id: ID!): JournalArticle! - journalArticles(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): JournalArticleConnectionWithTotal! + journalArticles(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): JournalArticleConnectionWithTotal! me: Me member(id: ID!): Member! members(after: String, first: Int = 25, query: String, year: String): MemberConnectionWithTotal! model(id: ID!): Model! - models(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): ModelConnectionWithTotal! + models(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): ModelConnectionWithTotal! organization(crossrefFunderId: ID, gridId: ID, id: ID): Organization! organizations(after: String, country: String, query: String, types: String): OrganizationConnectionWithTotal! other(id: ID!): Other! - others(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): OtherConnectionWithTotal! + others(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): OtherConnectionWithTotal! peerReview(id: ID!): PeerReview! - peerReviews(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): PeerReviewConnectionWithTotal! + peerReviews(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): PeerReviewConnectionWithTotal! people(after: String, first: Int = 25, query: String): PersonConnectionWithTotal! person(id: ID!): Person! physicalObject(id: ID!): PhysicalObject! - physicalObjects(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): PhysicalObjectConnectionWithTotal! + physicalObjects(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): PhysicalObjectConnectionWithTotal! prefix(id: ID!): Prefix! prefixes(after: String, first: Int = 25, query: String): PrefixConnectionWithTotal! preprint(id: ID!): Preprint! - preprints(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): PreprintConnectionWithTotal! + preprints(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): PreprintConnectionWithTotal! publication(id: ID!): Publication! - publications(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): PublicationConnectionWithTotal! + publications(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): PublicationConnectionWithTotal! repositories(after: String, certificate: String, first: Int = 25, hasPid: String, isCertified: String, isDisciplinary: String, isOpen: String, query: String, repositoryType: String, software: String, subject: String, subjectId: String): RepositoryConnectionWithTotal! repository(id: ID!): Repository! service(id: ID!): Service! - services(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, pidEntity: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): ServiceConnectionWithTotal! + services(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, pidEntity: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): ServiceConnectionWithTotal! software(id: ID!): Software! - softwares(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): SoftwareConnectionWithTotal! + softwares(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): SoftwareConnectionWithTotal! sound(id: ID!): Sound! - sounds(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): SoundConnectionWithTotal! + sounds(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): SoundConnectionWithTotal! usageReport(id: ID!): UsageReport! usageReports( """ @@ -9264,8 +9264,8 @@ type Query { ): UsageReportConnectionWithTotal! work(id: ID!): Work! workflow(id: ID!): Workflow! - workflows(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, userId: String): WorkflowConnectionWithTotal! - works(after: String, clientType: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, resourceType: String, resourceTypeId: String, userId: String): WorkConnectionWithTotal! + workflows(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, userId: String): WorkflowConnectionWithTotal! + works(after: String, facetCount: Int = 10, fieldOfScience: String, fieldOfScienceCombined: String, fieldOfScienceRepository: String, first: Int = 25, funderId: String, hasAffiliation: Boolean, hasCitations: Int, hasDownloads: Int, hasFunder: Boolean, hasMember: Boolean, hasOrganization: Boolean, hasParts: Int, hasPerson: Boolean, hasVersions: Int, hasViews: Int, ids: [String!], language: String, license: String, memberId: String, published: String, query: String, registrationAgency: String, repositoryId: String, repositoryType: String, resourceType: String, resourceTypeId: String, userId: String): WorkConnectionWithTotal! } """ From f1e217c52492865982d2b7a2019a809161b9eae4 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 Nov 2024 13:37:12 +0100 Subject: [PATCH 21/35] Rename the facet 'client_types' to 'repository_types' --- app/graphql/schema.graphql | 50 +++++++++---------- .../types/interfaces/work_facets_interface.rb | 4 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 8131f30ad..fa22e5ea8 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -409,7 +409,6 @@ The connection type for Audiovisual. type AudiovisualConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -437,6 +436,7 @@ type AudiovisualConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -1049,7 +1049,6 @@ The connection type for BookChapter. type BookChapterConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1077,6 +1076,7 @@ type BookChapterConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -1101,7 +1101,6 @@ The connection type for Book. type BookConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1129,6 +1128,7 @@ type BookConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -1495,7 +1495,6 @@ The connection type for Collection. type CollectionConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1523,6 +1522,7 @@ type CollectionConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -1841,7 +1841,6 @@ The connection type for ConferencePaper. type ConferencePaperConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -1869,6 +1868,7 @@ type ConferencePaperConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -2479,7 +2479,6 @@ The connection type for DataManagementPlan. type DataManagementPlanConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -2507,6 +2506,7 @@ type DataManagementPlanConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -2825,7 +2825,6 @@ The connection type for DataPaper. type DataPaperConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -2853,6 +2852,7 @@ type DataPaperConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -3192,7 +3192,6 @@ The connection type for Dataset. type DatasetConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] datasetConnectionCount: Int! @@ -3225,6 +3224,7 @@ type DatasetConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] softwareConnectionCount: Int! totalCount: Int! } @@ -3635,7 +3635,6 @@ The connection type for Dissertation. type DissertationConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -3663,6 +3662,7 @@ type DissertationConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -5270,7 +5270,6 @@ The connection type for Image. type ImageConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -5298,6 +5297,7 @@ type ImageConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -5616,7 +5616,6 @@ The connection type for Instrument. type InstrumentConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -5644,6 +5643,7 @@ type InstrumentConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -5962,7 +5962,6 @@ The connection type for InteractiveResource. type InteractiveResourceConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -5990,6 +5989,7 @@ type InteractiveResourceConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -6313,7 +6313,6 @@ The connection type for JournalArticle. type JournalArticleConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -6341,6 +6340,7 @@ type JournalArticleConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -6955,7 +6955,6 @@ The connection type for Model. type ModelConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -6983,6 +6982,7 @@ type ModelConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -7498,7 +7498,6 @@ The connection type for Other. type OtherConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -7526,6 +7525,7 @@ type OtherConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -7869,7 +7869,6 @@ The connection type for PeerReview. type PeerReviewConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -7897,6 +7896,7 @@ type PeerReviewConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -8352,7 +8352,6 @@ The connection type for PhysicalObject. type PhysicalObjectConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -8380,6 +8379,7 @@ type PhysicalObjectConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -8751,7 +8751,6 @@ The connection type for Preprint. type PreprintConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -8779,6 +8778,7 @@ type PreprintConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -9097,7 +9097,6 @@ The connection type for Publication. type PublicationConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] datasetConnectionCount: Int! @@ -9130,6 +9129,7 @@ type PublicationConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] softwareConnectionCount: Int! totalCount: Int! } @@ -10118,7 +10118,6 @@ The connection type for Service. type ServiceConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -10147,6 +10146,7 @@ type ServiceConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -10490,7 +10490,6 @@ The connection type for Software. type SoftwareConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] datasetConnectionCount: Int! @@ -10523,6 +10522,7 @@ type SoftwareConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] softwareConnectionCount: Int! totalCount: Int! } @@ -10842,7 +10842,6 @@ The connection type for Sound. type SoundConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -10870,6 +10869,7 @@ type SoundConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -11399,7 +11399,6 @@ The connection type for Work. type WorkConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -11427,6 +11426,7 @@ type WorkConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] resourceTypes: [Facet!] totalContentUrl: Int totalCount: Int! @@ -11452,7 +11452,6 @@ type WorkEdge { interface WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] fieldsOfScience: [Facet!] fieldsOfScienceCombined: [Facet!] @@ -11465,6 +11464,7 @@ interface WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } @@ -11768,7 +11768,6 @@ The connection type for Workflow. type WorkflowConnectionWithTotal implements WorkFacetsInterface { affiliations: [Facet!] authors: [Facet!] - clientTypes: [Facet!] creatorsAndContributors: [Facet!] """ @@ -11796,6 +11795,7 @@ type WorkflowConnectionWithTotal implements WorkFacetsInterface { published: [Facet!] registrationAgencies: [Facet!] repositories: [Facet!] + repositoryTypes: [Facet!] totalCount: Int! } diff --git a/app/graphql/types/interfaces/work_facets_interface.rb b/app/graphql/types/interfaces/work_facets_interface.rb index 182f22cc0..044dc29c6 100644 --- a/app/graphql/types/interfaces/work_facets_interface.rb +++ b/app/graphql/types/interfaces/work_facets_interface.rb @@ -19,7 +19,7 @@ module Interfaces::WorkFacetsInterface field :fields_of_science_repository, [FacetType], null: true, cache: true field :licenses, [FacetType], null: true, cache: true field :languages, [FacetType], null: true, cache: true - field :client_types, [FacetType], null: true, cache: true + field :repository_types, [FacetType], null: true, cache: true field :person_to_work_types_multilevel, [MultiFacetType], null: true, cache: true def person_to_work_types_multilevel @@ -142,7 +142,7 @@ def languages end end - def client_types + def repository_types if object.aggregations.client_types facet_by_client_type(object.aggregations.client_types.buckets) else From 3dfa6957fa44740643bffc13a84ae9b32afc7caf Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 Nov 2024 14:45:00 +0100 Subject: [PATCH 22/35] Update specs for repository_types --- spec/graphql/types/work_type_spec.rb | 39 +++++++--------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/spec/graphql/types/work_type_spec.rb b/spec/graphql/types/work_type_spec.rb index 5caf7de78..92deeef52 100644 --- a/spec/graphql/types/work_type_spec.rb +++ b/spec/graphql/types/work_type_spec.rb @@ -2220,25 +2220,6 @@ expect(response.dig("data", "works", "nodes", 0, "doi")).to eq(study_registration_doi.doi.downcase) expect(response.dig("data", "works", "nodes", 0, "types", "resourceTypeGeneral")).to eq("StudyRegistration") end - - it "returns project resource types" do - response = LupoSchema.execute(query, variables: { first: 15, cursor: nil }).as_json - - expect(response.dig("data", "works", "resourceTypes")).to eq( - [{ "count" => 10, "id" => "project", "title" => "Project" }, { "count" => 5, "id" => "dataset", "title" => "Dataset" }] - ) - end - - it "returns projects when querying works based on resource_type_id" do - response = - LupoSchema.execute( - query, - variables: { first: 15, cursor: nil, resourceTypeId: "Project" } - ). - as_json - - expect(response.dig("data", "works", "totalCount")).to eq(10) - end end describe "query with client_type facet", elasticsearch: true do @@ -2262,7 +2243,7 @@ "query($first: Int, $cursor: String) { works(first: $first, after: $cursor) { totalCount - clientTypes { + repositoryTypes { id title count @@ -2278,10 +2259,10 @@ end let(:query_with_client_type_filter) do - "query($first: Int, $cursor: String, $clientType: String) { - works(first: $first, after: $cursor, clientType: $clientType) { + "query($first: Int, $cursor: String, $repositoryType: String) { + works(first: $first, after: $cursor, repositoryType: $repositoryType) { totalCount - clientTypes { + repositoryTypes { id title count @@ -2296,7 +2277,7 @@ }" end - it "returns clientTypes facet" do + it "returns repositoryTypes facet" do response = LupoSchema.execute( query, @@ -2304,7 +2285,7 @@ as_json expect(response.dig("data", "works", "totalCount")).to eq(23) - expect(response.dig("data", "works", "clientTypes")).to eq( + expect(response.dig("data", "works", "repositoryTypes")).to eq( [ { "count" => 10, "id" => "periodical", "title" => "Periodical" }, { "count" => 10, "id" => "repository", "title" => "Repository" }, @@ -2314,16 +2295,16 @@ ) end - it "returns filtered DOIs by clientType and only returns PhysicalObjects for igsnCatalog filter" do + it "returns filtered DOIs by repositoryType and only returns PhysicalObjects for igsnCatalog filter" do response = LupoSchema.execute( query_with_client_type_filter, - variables: { first: 15, cursor: nil, clientType: "igsnCatalog" } + variables: { first: 15, cursor: nil, repositoryType: "igsnCatalog" } ). as_json - + expect(response.dig("data", "works", "totalCount")).to eq(1) - expect(response.dig("data", "works", "clientTypes")).to eq( + expect(response.dig("data", "works", "repositoryTypes")).to eq( [ { "count" => 1, "id" => "igsnCatalog", "title" => "IGSN ID Catalog" }, ] From cb7ba117fd27ac097699c8825e5ab2a23bb04691 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Tue, 19 Nov 2024 13:49:27 +0100 Subject: [PATCH 23/35] Add more specs to the query builder for filters --- spec/models/doi/graphql_query_builder_spec.rb | 192 +++++++++++++++++- 1 file changed, 184 insertions(+), 8 deletions(-) diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index c506a9017..da466fb4a 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -58,18 +58,194 @@ end end - describe "filters" do - it "is an empty array if not set" do - expect(described_class.new("", {}).filters).to eq([]) - expect(described_class.new(nil, {}).filters).to eq([]) +describe "#filters" do + let(:query) { "" } + let(:options) { {} } + let(:builder) { described_class.new(query, options) } + + context "with basic filters" do + context "when filtering by DOI ids" do + let(:options) { { ids: "10.5438/0012,10.5438/0013" } } + + it "includes DOI terms filter" do + expect(builder.filters).to include( + { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } + ) + end + end + + context "when filtering by resource type" do + let(:options) { { resource_type: "dataset,text" } } + + it "includes resource type terms filter" do + expect(builder.filters).to include( + { terms: { "types.resourceType": ["dataset", "text"] } } + ) + end end - it "can filter for ids" do - expect(described_class.new("foo", { ids: ["bar"] }).filters).to eq([{ terms: { doi: ["BAR"] } }]) + context "when filtering by language" do + let(:options) { { language: "en,de" } } + + it "includes language terms filter" do + expect(builder.filters).to include( + { terms: { language: ["en", "de"].map(&:downcase) } } + ) + end end + end + + context "with date range filters" do + let(:options) { { published: "2020,2022" } } - it "can filter for ids as single string" do - expect(described_class.new("foo", { ids: "bar" }).filters).to eq([{ terms: { doi: ["BAR"] } }]) + it "handles publication year range" do + expect(builder.filters).to include( + { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } } + ) + end + + context "when filtering by created date" do + let(:options) { { created: "2021,2023" } } + + it "handles created date range" do + expect(builder.filters).to include( + { range: { created: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } + ) + end + end end + + context "with count-based filters" do + let(:options) { { has_views: "10" } } + + it "handles view count threshold" do + expect(builder.filters).to include( + { range: { view_count: { gte: 10 } } } + ) + end + + context "when filtering by citations" do + let(:options) { { has_citations: "5" } } + + it "handles citation count threshold" do + expect(builder.filters).to include( + { range: { citation_count: { gte: 5 } } } + ) + end + end + end + + context "with subject-based filters" do + let(:options) { { pid_entity: "dataset,software" } } + + it "handles pid entity filters" do + expect(builder.filters).to include( + { term: { "subjects.subjectScheme": "PidEntity" } }, + { terms: { "subjects.subject": ["Dataset", "Software"] } } + ) + end + + context "when filtering by field of science" do + let(:options) { { field_of_science: "computer_science,mathematics" } } + + it "handles field of science filters" do + expect(builder.filters).to include( + { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, + { terms: { "subjects.subject": ["FOS: Computer science", "FOS: Mathematics"] } } + ) + end + end + end + + context "with landing page filters" do + let(:options) { { link_check_status: "200" } } + + it "handles landing page status" do + expect(builder.filters).to include( + { term: { "landing_page.status": "200" } } + ) + end + + context "with schema.org check" do + let(:options) { { link_check_has_schema_org: true } } + + it "handles schema.org presence check" do + expect(builder.filters).to include( + { term: { "landing_page.hasSchemaOrg": true } } + ) + end + end + end + + context "with identifier filters" do + context "with ids" do + it "can filter for ids" do + expect(described_class.new("foo", { ids: ["bar"] }).filters).to eq([{ terms: { doi: ["BAR"] } }]) + end + + it "can filter for ids as single string" do + expect(described_class.new("foo", { ids: "bar" }).filters).to eq([{ terms: { doi: ["BAR"] } }]) + end + end + + context "with certificate" do + let(:options) { { certificate: "CoreTrustSeal,CLARIN" } } + + it "handles client certificate" do + expect(builder.filters).to include( + { terms: { "client.certificate" => ["CoreTrustSeal", "CLARIN"] } } + ) + end + end + + context "with ORCID" do + let(:options) { { user_id: "https://orcid.org/0000-0003-1419-2405" } } + + it "handles user ORCID" do + expect(builder.filters).to include( + { terms: { "creators.nameIdentifiers.nameIdentifier" => ["https://orcid.org/0000-0003-1419-2405"] } } + ) + end + end + end + + context "with multiple filters" do + it "combines different filter types" do + options = { + resource_type: "dataset", + published: "2020,2022", + has_citations: "5", + language: "en" + } + + builder = described_class.new(query, options) + filters = builder.filters + + expect(filters).to include( + { terms: { "types.resourceType": ["dataset"] } }, + { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } }, + { range: { citation_count: { gte: 5 } } }, + { terms: { language: ["en"] } } + ) + expect(filters.length).to eq(4) + end + end + + context "with empty or invalid filters" do + it "handles empty options" do + builder = described_class.new(query, {}) + expect(builder.filters).to be_empty + end + + it "handles nil values" do + options = { resource_type: nil, language: nil } + builder = described_class.new(query, options) + expect(builder.filters).to be_empty + end + end + end + + describe "filters" do + end end From c7a938c29dc36bb57e51db53b3b28eca8b4685e4 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Wed, 20 Nov 2024 12:25:50 +0100 Subject: [PATCH 24/35] Remove unnessesary context blocks. Refactor inline --- spec/models/doi/graphql_query_builder_spec.rb | 137 ++++++++---------- 1 file changed, 57 insertions(+), 80 deletions(-) diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index da466fb4a..cd25db1b4 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -4,9 +4,9 @@ require "rails_helper" RSpec.describe Doi::GraphqlQuery::Builder do + let(:query) { "" } + let(:options) { {} } describe "page size" do - let(:query) { "" } - let(:options) { {} } let(:builder) { described_class.new(query, options) } it "is DEFAULT_PAGE_SIZE with no options" do @@ -23,8 +23,6 @@ end describe "cursor" do - let(:query) { "" } - let(:options) { {} } let(:builder) { described_class.new(query, options) } it "is DEFAULT_CURSOR with no options" do @@ -58,129 +56,114 @@ end end -describe "#filters" do - let(:query) { "" } - let(:options) { {} } - let(:builder) { described_class.new(query, options) } +describe "filters" do context "with basic filters" do - context "when filtering by DOI ids" do - let(:options) { { ids: "10.5438/0012,10.5438/0013" } } - - it "includes DOI terms filter" do + it "handles DOI ids" do + options = { ids: "10.5438/0012,10.5438/0013" } + builder = described_class.new(query, options) expect(builder.filters).to include( { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } ) end - end - context "when filtering by resource type" do - let(:options) { { resource_type: "dataset,text" } } - - it "includes resource type terms filter" do + it "handles resource type" do + options = { resource_type: "dataset,text" } + builder = described_class.new(query, options) expect(builder.filters).to include( { terms: { "types.resourceType": ["dataset", "text"] } } ) end - end - - context "when filtering by language" do - let(:options) { { language: "en,de" } } - it "includes language terms filter" do + it "handles language" do + options = { language: "en,de" } + builder = described_class.new(query, options) expect(builder.filters).to include( { terms: { language: ["en", "de"].map(&:downcase) } } ) end - end end context "with date range filters" do - let(:options) { { published: "2020,2022" } } - it "handles publication year range" do + options = { published: "2020,2022" } + builder = described_class.new(query, options) expect(builder.filters).to include( { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } } ) end - context "when filtering by created date" do - let(:options) { { created: "2021,2023" } } - - it "handles created date range" do - expect(builder.filters).to include( - { range: { created: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } - ) - end + it "handles created date range" do + options = { created: "2021,2023" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { created: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } + ) end end context "with count-based filters" do - let(:options) { { has_views: "10" } } - it "handles view count threshold" do + options = { has_views: "10" } + builder = described_class.new(query, options) expect(builder.filters).to include( { range: { view_count: { gte: 10 } } } ) end - context "when filtering by citations" do - let(:options) { { has_citations: "5" } } - - it "handles citation count threshold" do - expect(builder.filters).to include( - { range: { citation_count: { gte: 5 } } } - ) - end + it "handles citation count threshold" do + options = { has_citations: "5" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { citation_count: { gte: 5 } } } + ) end end context "with subject-based filters" do - let(:options) { { pid_entity: "dataset,software" } } - it "handles pid entity filters" do + options = { pid_entity: "dataset,software" } + builder = described_class.new(query, options) expect(builder.filters).to include( { term: { "subjects.subjectScheme": "PidEntity" } }, { terms: { "subjects.subject": ["Dataset", "Software"] } } ) end - context "when filtering by field of science" do - let(:options) { { field_of_science: "computer_science,mathematics" } } - - it "handles field of science filters" do - expect(builder.filters).to include( - { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, - { terms: { "subjects.subject": ["FOS: Computer science", "FOS: Mathematics"] } } - ) - end + it "handles field of science filters" do + options = { field_of_science: "computer_science,mathematics" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, + { terms: { "subjects.subject": ["FOS: Computer science", "FOS: Mathematics"] } } + ) end end context "with landing page filters" do - let(:options) { { link_check_status: "200" } } - it "handles landing page status" do + options = { link_check_status: "200" } + builder = described_class.new(query, options) expect(builder.filters).to include( { term: { "landing_page.status": "200" } } ) end - context "with schema.org check" do - let(:options) { { link_check_has_schema_org: true } } - - it "handles schema.org presence check" do - expect(builder.filters).to include( - { term: { "landing_page.hasSchemaOrg": true } } - ) - end + it "handles schema.org presence check" do + options = { link_check_has_schema_org: true } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "landing_page.hasSchemaOrg": true } } + ) end end context "with identifier filters" do context "with ids" do it "can filter for ids" do - expect(described_class.new("foo", { ids: ["bar"] }).filters).to eq([{ terms: { doi: ["BAR"] } }]) + expect(described_class.new("foo", { ids: ["bar"] }).filters).to eq( + [{ terms: { doi: ["BAR"] } }] + ) end it "can filter for ids as single string" do @@ -188,25 +171,18 @@ end end - context "with certificate" do - let(:options) { { certificate: "CoreTrustSeal,CLARIN" } } - - it "handles client certificate" do - expect(builder.filters).to include( - { terms: { "client.certificate" => ["CoreTrustSeal", "CLARIN"] } } - ) - end + it "handles client certificate" do + builder = described_class.new(query, { certificate: "CoreTrustSeal,CLARIN" }) + expect(builder.filters).to include( + { terms: { "client.certificate" => ["CoreTrustSeal", "CLARIN"] } } + ) end - context "with ORCID" do - let(:options) { { user_id: "https://orcid.org/0000-0003-1419-2405" } } - it "handles user ORCID" do - expect(builder.filters).to include( + expect(described_class.new(query, { user_id: "https://orcid.org/0000-0003-1419-2405" }).filters).to include( { terms: { "creators.nameIdentifiers.nameIdentifier" => ["https://orcid.org/0000-0003-1419-2405"] } } ) end - end end context "with multiple filters" do @@ -245,7 +221,8 @@ end end - describe "filters" do + describe "sorting" do + + end - end end From 39699dc9cf00f3a9b7af415cbcaef0eda238df37 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Wed, 20 Nov 2024 12:47:09 +0100 Subject: [PATCH 25/35] Set and spec default sorting --- app/models/doi/graphql_query.rb | 3 +- spec/models/doi/graphql_query_builder_spec.rb | 64 +++++++++++-------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/app/models/doi/graphql_query.rb b/app/models/doi/graphql_query.rb index 660de86ab..e7e899e21 100644 --- a/app/models/doi/graphql_query.rb +++ b/app/models/doi/graphql_query.rb @@ -7,6 +7,7 @@ class Builder DEFAULT_CURSOR = [0, ""] DEFAULT_PAGE_SIZE = 0 DEFAULT_FACET_COUNT = 10 + DEFAULT_SORT = [{ created: "asc", uid: "asc" }] def initialize(query, options) @query = query @@ -29,7 +30,7 @@ def size end def sort - [{ created: "asc", uid: "asc" }] + DEFAULT_SORT end def query_fields diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index cd25db1b4..74ea60656 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -56,33 +56,32 @@ end end -describe "filters" do - - context "with basic filters" do - it "handles DOI ids" do - options = { ids: "10.5438/0012,10.5438/0013" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } - ) - end + describe "filters" do + context "with basic filters" do + it "handles DOI ids" do + options = { ids: "10.5438/0012,10.5438/0013" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } + ) + end - it "handles resource type" do - options = { resource_type: "dataset,text" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { "types.resourceType": ["dataset", "text"] } } - ) - end + it "handles resource type" do + options = { resource_type: "dataset,text" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { "types.resourceType": ["dataset", "text"] } } + ) + end - it "handles language" do - options = { language: "en,de" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { language: ["en", "de"].map(&:downcase) } } - ) - end - end + it "handles language" do + options = { language: "en,de" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { language: ["en", "de"].map(&:downcase) } } + ) + end + end context "with date range filters" do it "handles publication year range" do @@ -222,6 +221,21 @@ end describe "sorting" do + let(:builder) { described_class.new(query, options) } + + context "with no sort options" do + it "uses default sort" do + expect(builder.sort).to eq(described_class::DEFAULT_SORT) + end + end + + context "with sort options" do + let(:options) { { sort: "relevance" } } + it "ignores any sort options and returns the default" do + expect(builder.sort).to eq(described_class::DEFAULT_SORT) + + end + end end From b10d89d35f9b6af991820acb505b8ba2cfe0a1ac Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 Nov 2024 11:09:01 +0100 Subject: [PATCH 26/35] Add more specs for filters --- spec/models/doi/graphql_query_builder_spec.rb | 102 ++++++++++++++++-- 1 file changed, 93 insertions(+), 9 deletions(-) diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index 74ea60656..3134a6e3b 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -66,6 +66,15 @@ ) end + it "handles resource_type_id" do + options = { resource_type_id: "Journal_Article" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { resource_type_id: "journal-article" } } + ) + + end + it "handles resource type" do options = { resource_type: "dataset,text" } builder = described_class.new(query, options) @@ -74,6 +83,23 @@ ) end + + it "handles agency" do + options = {agency: "crossref"} + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { agency: ["crossref"].map(&:downcase) } } + ) + end + + it "handles prefix" do + options = {prefix: "10.5438"} + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { prefix: ["10.5438"].map(&:downcase) } } + ) + end + it "handles language" do options = { language: "en,de" } builder = described_class.new(query, options) @@ -81,6 +107,14 @@ { terms: { language: ["en", "de"].map(&:downcase) } } ) end + + it "handles uid" do + options = { uid: "10.5438/0012" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { uid: "10.5438/0012" } } + ) + end end context "with date range filters" do @@ -102,11 +136,11 @@ end context "with count-based filters" do - it "handles view count threshold" do - options = { has_views: "10" } + it "handles reference count threshold" do + options = { has_references: "5" } builder = described_class.new(query, options) expect(builder.filters).to include( - { range: { view_count: { gte: 10 } } } + { range: { reference_count: { gte: 5 } } } ) end @@ -117,6 +151,54 @@ { range: { citation_count: { gte: 5 } } } ) end + + it "handles part count threshold" do + options = { has_parts: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { part_count: { gte: 10 } } } + ) + end + + it "handles part of count threshold" do + options = { has_part_of: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { part_of_count: { gte: 10 } } } + ) + end + + it "handles version count threshold" do + options = { has_versions: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { version_count: { gte: 10 } } } + ) + end + + it "handles version of count threshold" do + options = { has_version_of: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { version_of_count: { gte: 10 } } } + ) + end + + it "handles view count threshold" do + options = { has_views: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { view_count: { gte: 10 } } } + ) + end + + it "handles download count threshold" do + options = { has_downloads: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { download_count: { gte: 10 } } } + ) + end end context "with subject-based filters" do @@ -177,11 +259,11 @@ ) end - it "handles user ORCID" do - expect(described_class.new(query, { user_id: "https://orcid.org/0000-0003-1419-2405" }).filters).to include( - { terms: { "creators.nameIdentifiers.nameIdentifier" => ["https://orcid.org/0000-0003-1419-2405"] } } - ) - end + it "handles user ORCID" do + expect(described_class.new(query, { user_id: "https://orcid.org/0000-0003-1419-2405" }).filters).to include( + { terms: { "creators.nameIdentifiers.nameIdentifier" => ["https://orcid.org/0000-0003-1419-2405"] } } + ) + end end context "with multiple filters" do @@ -218,6 +300,9 @@ expect(builder.filters).to be_empty end end + + + end describe "sorting" do @@ -236,7 +321,6 @@ end end - end end From 787b74f2318ac4fbcb620483bec55d4959166a27 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 29 Nov 2024 15:48:31 +0100 Subject: [PATCH 27/35] Add more specs for filters --- spec/models/doi/graphql_query_builder_spec.rb | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index 3134a6e3b..d08a8b63e 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -115,6 +115,58 @@ { term: { uid: "10.5438/0012" } } ) end + + it "handles state" do + options = { state: "findable,registered" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { aasm_state: ["findable", "registered"] } } + ) + end + + it "handles consortium_id" do + options = { consortium_id: "dc" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { consortium_id: { :case_insensitive => true, :value => "dc" } } } + ) + end + + it "handles registered" do + options = { registered: "2021,2023" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { registered: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } + ) + end + + end + + context "filters based on client metadata" do + it "handles re3data_id" do + options = { re3data_id: "10.17616/r31njmjx" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "client.re3data_id" => "10.17616/r31njmjx" } } + ) + end + + it "handles opendoar_id" do + options = { opendoar_id: "123456" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "client.opendoar_id" => "123456" } } + ) + end + + it "handles certificates" do + options = { certificate: "CoreTrustSeal,WDS" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { "client.certificate" => ["CoreTrustSeal", "WDS"] } } + ) + end + end context "with date range filters" do From 1ad7b27749d96fd44194cbcf3b8c895e7fc4c0c4 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 29 Nov 2024 16:26:39 +0100 Subject: [PATCH 28/35] Refactor filters specs into their own file --- .../doi/graphql_query_builder_filters_spec.rb | 311 +++++++++++++++++ spec/models/doi/graphql_query_builder_spec.rb | 319 +----------------- 2 files changed, 320 insertions(+), 310 deletions(-) create mode 100644 spec/models/doi/graphql_query_builder_filters_spec.rb diff --git a/spec/models/doi/graphql_query_builder_filters_spec.rb b/spec/models/doi/graphql_query_builder_filters_spec.rb new file mode 100644 index 000000000..84aa88316 --- /dev/null +++ b/spec/models/doi/graphql_query_builder_filters_spec.rb @@ -0,0 +1,311 @@ + + +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Doi::GraphqlQuery::Builder do + let(:query) { "" } + let(:options) { {} } + + describe "filters" do + context "with basic filters" do + it "handles DOI ids" do + options = { ids: "10.5438/0012,10.5438/0013" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } + ) + end + + it "handles resource_type_id" do + options = { resource_type_id: "Journal_Article" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { resource_type_id: "journal-article" } } + ) + + end + + it "handles resource type" do + options = { resource_type: "dataset,text" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { "types.resourceType": ["dataset", "text"] } } + ) + end + + + it "handles agency" do + options = {agency: "crossref"} + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { agency: ["crossref"].map(&:downcase) } } + ) + end + + it "handles prefix" do + options = {prefix: "10.5438"} + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { prefix: ["10.5438"].map(&:downcase) } } + ) + end + + it "handles language" do + options = { language: "en,de" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { language: ["en", "de"].map(&:downcase) } } + ) + end + + it "handles uid" do + options = { uid: "10.5438/0012" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { uid: "10.5438/0012" } } + ) + end + + it "handles state" do + options = { state: "findable,registered" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { aasm_state: ["findable", "registered"] } } + ) + end + + it "handles consortium_id" do + options = { consortium_id: "dc" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { consortium_id: { :case_insensitive => true, :value => "dc" } } } + ) + end + + it "handles registered" do + options = { registered: "2021,2023" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { registered: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } + ) + end + + end + + context "filters based on client metadata" do + it "handles re3data_id" do + options = { re3data_id: "10.17616/r31njmjx" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "client.re3data_id" => "10.17616/r31njmjx" } } + ) + end + + it "handles opendoar_id" do + options = { opendoar_id: "123456" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "client.opendoar_id" => "123456" } } + ) + end + + it "handles certificates" do + options = { certificate: "CoreTrustSeal,WDS" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { "client.certificate" => ["CoreTrustSeal", "WDS"] } } + ) + end + + end + + context "with date range filters" do + it "handles publication year range" do + options = { published: "2020,2022" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } } + ) + end + + it "handles created date range" do + options = { created: "2021,2023" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { created: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } + ) + end + end + + context "with count-based filters" do + it "handles reference count threshold" do + options = { has_references: "5" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { reference_count: { gte: 5 } } } + ) + end + + it "handles citation count threshold" do + options = { has_citations: "5" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { citation_count: { gte: 5 } } } + ) + end + + it "handles part count threshold" do + options = { has_parts: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { part_count: { gte: 10 } } } + ) + end + + it "handles part of count threshold" do + options = { has_part_of: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { part_of_count: { gte: 10 } } } + ) + end + + it "handles version count threshold" do + options = { has_versions: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { version_count: { gte: 10 } } } + ) + end + + it "handles version of count threshold" do + options = { has_version_of: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { version_of_count: { gte: 10 } } } + ) + end + + it "handles view count threshold" do + options = { has_views: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { view_count: { gte: 10 } } } + ) + end + + it "handles download count threshold" do + options = { has_downloads: "10" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { download_count: { gte: 10 } } } + ) + end + end + + context "with subject-based filters" do + it "handles pid entity filters" do + options = { pid_entity: "dataset,software" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "subjects.subjectScheme": "PidEntity" } }, + { terms: { "subjects.subject": ["Dataset", "Software"] } } + ) + end + + it "handles field of science filters" do + options = { field_of_science: "computer_science,mathematics" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, + { terms: { "subjects.subject": ["FOS: Computer science", "FOS: Mathematics"] } } + ) + end + end + + context "with landing page filters" do + it "handles landing page status" do + options = { link_check_status: "200" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "landing_page.status": "200" } } + ) + end + + it "handles schema.org presence check" do + options = { link_check_has_schema_org: true } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "landing_page.hasSchemaOrg": true } } + ) + end + end + + context "with identifier filters" do + context "with ids" do + it "can filter for ids" do + expect(described_class.new("foo", { ids: ["bar"] }).filters).to eq( + [{ terms: { doi: ["BAR"] } }] + ) + end + + it "can filter for ids as single string" do + expect(described_class.new("foo", { ids: "bar" }).filters).to eq([{ terms: { doi: ["BAR"] } }]) + end + end + + it "handles client certificate" do + builder = described_class.new(query, { certificate: "CoreTrustSeal,CLARIN" }) + expect(builder.filters).to include( + { terms: { "client.certificate" => ["CoreTrustSeal", "CLARIN"] } } + ) + end + + it "handles user ORCID" do + expect(described_class.new(query, { user_id: "https://orcid.org/0000-0003-1419-2405" }).filters).to include( + { terms: { "creators.nameIdentifiers.nameIdentifier" => ["https://orcid.org/0000-0003-1419-2405"] } } + ) + end + end + + context "with multiple filters" do + it "combines different filter types" do + options = { + resource_type: "dataset", + published: "2020,2022", + has_citations: "5", + language: "en" + } + + builder = described_class.new(query, options) + filters = builder.filters + + expect(filters).to include( + { terms: { "types.resourceType": ["dataset"] } }, + { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } }, + { range: { citation_count: { gte: 5 } } }, + { terms: { language: ["en"] } } + ) + expect(filters.length).to eq(4) + end + end + + context "with empty or invalid filters" do + it "handles empty options" do + builder = described_class.new(query, {}) + expect(builder.filters).to be_empty + end + + it "handles nil values" do + options = { resource_type: nil, language: nil } + builder = described_class.new(query, options) + expect(builder.filters).to be_empty + end + end + + + + end +end diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index d08a8b63e..683eb74a6 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -56,323 +56,22 @@ end end - describe "filters" do - context "with basic filters" do - it "handles DOI ids" do - options = { ids: "10.5438/0012,10.5438/0013" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } - ) - end - - it "handles resource_type_id" do - options = { resource_type_id: "Journal_Article" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { resource_type_id: "journal-article" } } - ) - - end - - it "handles resource type" do - options = { resource_type: "dataset,text" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { "types.resourceType": ["dataset", "text"] } } - ) - end - - - it "handles agency" do - options = {agency: "crossref"} - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { agency: ["crossref"].map(&:downcase) } } - ) - end - - it "handles prefix" do - options = {prefix: "10.5438"} - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { prefix: ["10.5438"].map(&:downcase) } } - ) - end - - it "handles language" do - options = { language: "en,de" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { language: ["en", "de"].map(&:downcase) } } - ) - end - - it "handles uid" do - options = { uid: "10.5438/0012" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { uid: "10.5438/0012" } } - ) - end - - it "handles state" do - options = { state: "findable,registered" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { aasm_state: ["findable", "registered"] } } - ) - end - - it "handles consortium_id" do - options = { consortium_id: "dc" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { consortium_id: { :case_insensitive => true, :value => "dc" } } } - ) - end - - it "handles registered" do - options = { registered: "2021,2023" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { registered: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } - ) - end - - end - - context "filters based on client metadata" do - it "handles re3data_id" do - options = { re3data_id: "10.17616/r31njmjx" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "client.re3data_id" => "10.17616/r31njmjx" } } - ) - end - - it "handles opendoar_id" do - options = { opendoar_id: "123456" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "client.opendoar_id" => "123456" } } - ) - end - - it "handles certificates" do - options = { certificate: "CoreTrustSeal,WDS" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { "client.certificate" => ["CoreTrustSeal", "WDS"] } } - ) - end - - end - - context "with date range filters" do - it "handles publication year range" do - options = { published: "2020,2022" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } } - ) - end - - it "handles created date range" do - options = { created: "2021,2023" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { created: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } - ) - end - end - - context "with count-based filters" do - it "handles reference count threshold" do - options = { has_references: "5" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { reference_count: { gte: 5 } } } - ) - end - - it "handles citation count threshold" do - options = { has_citations: "5" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { citation_count: { gte: 5 } } } - ) - end - - it "handles part count threshold" do - options = { has_parts: "10" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { part_count: { gte: 10 } } } - ) - end - - it "handles part of count threshold" do - options = { has_part_of: "10" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { part_of_count: { gte: 10 } } } - ) - end - - it "handles version count threshold" do - options = { has_versions: "10" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { version_count: { gte: 10 } } } - ) - end - - it "handles version of count threshold" do - options = { has_version_of: "10" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { version_of_count: { gte: 10 } } } - ) - end - - it "handles view count threshold" do - options = { has_views: "10" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { view_count: { gte: 10 } } } - ) - end - - it "handles download count threshold" do - options = { has_downloads: "10" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { download_count: { gte: 10 } } } - ) - end - end - - context "with subject-based filters" do - it "handles pid entity filters" do - options = { pid_entity: "dataset,software" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "subjects.subjectScheme": "PidEntity" } }, - { terms: { "subjects.subject": ["Dataset", "Software"] } } - ) - end - - it "handles field of science filters" do - options = { field_of_science: "computer_science,mathematics" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, - { terms: { "subjects.subject": ["FOS: Computer science", "FOS: Mathematics"] } } - ) - end - end - - context "with landing page filters" do - it "handles landing page status" do - options = { link_check_status: "200" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "landing_page.status": "200" } } - ) - end - - it "handles schema.org presence check" do - options = { link_check_has_schema_org: true } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "landing_page.hasSchemaOrg": true } } - ) - end - end - - context "with identifier filters" do - context "with ids" do - it "can filter for ids" do - expect(described_class.new("foo", { ids: ["bar"] }).filters).to eq( - [{ terms: { doi: ["BAR"] } }] - ) - end - - it "can filter for ids as single string" do - expect(described_class.new("foo", { ids: "bar" }).filters).to eq([{ terms: { doi: ["BAR"] } }]) - end - end - - it "handles client certificate" do - builder = described_class.new(query, { certificate: "CoreTrustSeal,CLARIN" }) - expect(builder.filters).to include( - { terms: { "client.certificate" => ["CoreTrustSeal", "CLARIN"] } } - ) - end + describe "sorting" do + let(:builder) { described_class.new(query, options) } - it "handles user ORCID" do - expect(described_class.new(query, { user_id: "https://orcid.org/0000-0003-1419-2405" }).filters).to include( - { terms: { "creators.nameIdentifiers.nameIdentifier" => ["https://orcid.org/0000-0003-1419-2405"] } } - ) + context "with no sort options" do + it "uses default sort" do + expect(builder.sort).to eq(described_class::DEFAULT_SORT) end end - context "with multiple filters" do - it "combines different filter types" do - options = { - resource_type: "dataset", - published: "2020,2022", - has_citations: "5", - language: "en" - } - - builder = described_class.new(query, options) - filters = builder.filters + context "with sort options" do + let(:options) { { sort: "relevance" } } + it "ignores any sort options and returns the default" do + expect(builder.sort).to eq(described_class::DEFAULT_SORT) - expect(filters).to include( - { terms: { "types.resourceType": ["dataset"] } }, - { range: { publication_year: { gte: "2020||/y", lte: "2022||/y", format: "yyyy" } } }, - { range: { citation_count: { gte: 5 } } }, - { terms: { language: ["en"] } } - ) - expect(filters.length).to eq(4) end end - - context "with empty or invalid filters" do - it "handles empty options" do - builder = described_class.new(query, {}) - expect(builder.filters).to be_empty - end - - it "handles nil values" do - options = { resource_type: nil, language: nil } - builder = described_class.new(query, options) - expect(builder.filters).to be_empty - end - end - - - end - describe "sorting" do - let(:builder) { described_class.new(query, options) } - - context "with no sort options" do - it "uses default sort" do - expect(builder.sort).to eq(described_class::DEFAULT_SORT) - end - end - - context "with sort options" do - let(:options) { { sort: "relevance" } } - it "ignores any sort options and returns the default" do - expect(builder.sort).to eq(described_class::DEFAULT_SORT) - - end - end - end - end From eafbeaea32656559258bc6675dd87a79e82e3b9a Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 29 Nov 2024 16:49:04 +0100 Subject: [PATCH 29/35] Add spec for aggregates --- .../graphql_query_builder_aggregates_spec.rb | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 spec/models/doi/graphql_query_builder_aggregates_spec.rb diff --git a/spec/models/doi/graphql_query_builder_aggregates_spec.rb b/spec/models/doi/graphql_query_builder_aggregates_spec.rb new file mode 100644 index 000000000..d3853eebe --- /dev/null +++ b/spec/models/doi/graphql_query_builder_aggregates_spec.rb @@ -0,0 +1,212 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Doi::GraphqlQuery::Builder do + let(:query) { "" } + let(:options) { {} } + + describe "aggregations" do + it "by default all aggregations are enabled" do + builder = described_class.new(query, options) + expect(builder.aggregations).to eq( + { + :affiliations=>{:terms=>{:field=>"affiliation_id_and_name", :min_doc_count=>1, :missing=>"__missing__", :size=>10}}, + :authors=>{ + :aggs=>{:authors=>{ + :top_hits=>{:_source=>{ + :includes=>["creators.name", "creators.nameIdentifiers.nameIdentifier"], + }, :size=>1}, + }}, + :terms=>{:field=>"creators.nameIdentifiers.nameIdentifier", :include=>"https?://orcid.org/.*", :min_doc_count=>1, :size=>10}, + }, + :citation_count=>{ + :sum=>{:field=>"citation_count"}, + }, + :client_types=>{ + :terms=>{:field=>"client.client_type", :min_doc_count=>1, :size=>10}, + }, + :clients=>{ + :terms=>{:field=>"client_id_and_name", :min_doc_count=>1, :size=>10}, + }, + :content_url_count=>{ + :value_count=>{:field=>"content_url"}, + }, + :creators_and_contributors=>{ + :aggs=>{ + :creators_and_contributors=>{ + :top_hits=>{:_source=>{ + :includes=>["creators_and_contributors.name", "creators_and_contributors.nameIdentifiers.nameIdentifier"], + }, :size=>1}, + }, + :work_types=>{:terms=>{:field=>"resource_type_id_and_name", :min_doc_count=>1}}, + }, + :terms=>{ + :field=>"creators_and_contributors.nameIdentifiers.nameIdentifier", + :include=>"https?://orcid.org/.*", + :min_doc_count=>1, + :size=>10, + }, + }, + :download_count=>{ + :sum=>{:field=>"download_count"}, + }, + :fields_of_science=>{ + :aggs=>{ + :subject=>{ + :terms=>{ + :field=>"subjects.subject", + :include=>"FOS:.*", + :min_doc_count=>1, + :size=>10, + }, + }, + }, + :filter=>{ + :term=>{:"subjects.subjectScheme"=>"Fields of Science and Technology (FOS)"}, + }, + }, + :fields_of_science_combined=>{ + :terms=>{ + :field=>"fields_of_science_combined", + :min_doc_count=>1, + :size=>10, + }, + }, + :fields_of_science_repository=>{ + :terms=>{ + :field=>"fields_of_science_repository", + :min_doc_count=>1, + :size=>10, + }, + }, + :funders=>{ + :aggs=>{:funders=>{:top_hits=>{:_source=>{:includes=>["funding_references.funderName", "funding_references.funderIdentifier"]}, :size=>1}}}, + :terms=>{ + :field=>"funding_references.funderIdentifier", + :min_doc_count=>1, + :size=>10, + }, + }, + :languages=>{ + :terms=>{ + :field=>"language", + :min_doc_count=>1, + :size=>10, + }, + }, + :licenses=>{ + :terms=>{ + :field=>"rights_list.rightsIdentifier", + :min_doc_count=>1, + :missing=>"__missing__", + :size=>10, + }, + }, + :open_licenses=>{ + :aggs=>{ + :resource_types=>{ + :terms=>{ + :field=>"resource_type_id_and_name", + :min_doc_count=>1, + :size=>10, + }, + }, + }, + :filter=>{ + :terms=>{:"rights_list.rightsIdentifier"=>[ + "cc-by-1.0", + "cc-by-2.0", + "cc-by-2.5", + "cc-by-3.0", + "cc-by-3.0-at", + "cc-by-3.0-us", + "cc-by-4.0", + "cc-pddc", + "cc0-1.0", + "cc-pdm-1.0", + ]}, + }, + }, + :pid_entities=>{ + :aggs=>{ + :subject=>{ + :terms=>{ + :field=>"subjects.subject", + :include=>[ + "Dataset", + "Publication", + "Software", + "Organization", + "Funder", + "Person", + "Grant", + "Sample", + "Instrument", + "Repository", + "Project", + ], + :min_doc_count=>1, + :size=>10, + }, + }, + }, + :filter=>{:term=>{:"subjects.subjectScheme"=>"PidEntity"}}, + }, + :published=>{ + :date_histogram=>{ + :field=>"publication_year", + :format=>"year", + :interval=>"year", + :min_doc_count=>1, + :order=>{:_key=>"desc"}, + }, + }, + :registration_agencies=>{ + :terms=>{:field=>"agency", :min_doc_count=>1, :size=>10}, + }, + :resource_types=>{:terms=>{ + :field=>"resource_type_id_and_name", + :min_doc_count=>1, + :missing=>"__missing__", + :size=>10, + }}, + :view_count=>{ + :sum=>{:field=>"view_count"}, + }, + } + ) + end + + it "has keys for all aggregates" do + expected_keys = %i[ + affiliations + authors + citation_count + client_types + clients + content_url_count + creators_and_contributors + download_count + fields_of_science + fields_of_science_combined + fields_of_science_repository + funders + languages + licenses + open_licenses + pid_entities + published + registration_agencies + resource_types + view_count + ] + + builder = described_class.new(query, options) + expect(builder.aggregations.keys).to match_array(expected_keys) + end + end + + + +end From 7283a4637c0d1efcbd51972d59a7fcffc785ee95 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:32:18 -0500 Subject: [PATCH 30/35] Refactors /dois faceting and adds support for on-demand facets --- app/controllers/datacite_dois_controller.rb | 101 ++++----- app/models/doi.rb | 198 +++++++++++------- .../datacite_dois/datacite_dois_spec.rb | 59 ++++++ 3 files changed, 227 insertions(+), 131 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 456e4822c..9162c4d5a 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -136,6 +136,7 @@ def index source: params[:source], scroll_id: params[:scroll_id], disable_facets: disable_facets, + facets: params[:facets], page: page, sort: sort, random: params[:random], @@ -221,47 +222,43 @@ def index ) end else - if total.positive? && !disable_facets - states = facet_by_key(response.aggregations.states.buckets) - resource_types = facet_by_combined_key(response.aggregations.resource_types.buckets) - published = facet_by_range(response.aggregations.published.buckets) - created = facet_by_key_as_string(response.aggregations.created.buckets) - created_by_month = response.aggregations.created_by_month ? facet_by_key_as_string(response.aggregations.created_by_month.buckets) : nil - registered = facet_by_key_as_string(response.aggregations.registered.buckets) - providers = facet_by_combined_key(response.aggregations.providers.buckets) - clients = facet_by_combined_key(response.aggregations.clients.buckets) - prefixes = facet_by_key(response.aggregations.prefixes.buckets) - schema_versions = facet_by_schema(response.aggregations.schema_versions.buckets) - affiliations = facet_by_combined_key(response.aggregations.affiliations.buckets) - subjects = facet_by_key(response.aggregations.subjects.buckets) - fields_of_science = facet_by_fos(response.aggregations.fields_of_science.subject.buckets) - certificates = facet_by_key(response.aggregations.certificates.buckets) - licenses = facet_by_license(response.aggregations.licenses.buckets) - link_checks_status = facet_by_cumulative_year(response.aggregations.link_checks_status.buckets) - citations = metric_facet_by_year(response.aggregations.citations.buckets) - views = metric_facet_by_year(response.aggregations.views.buckets) - downloads = metric_facet_by_year(response.aggregations.downloads.buckets) - else - states = nil - resource_types = nil - published = nil - created = nil - registered = nil - providers = nil - clients = nil - prefixes = nil - schema_versions = nil - affiliations = nil - subjects = nil - fields_of_science = nil - certificates = nil - licenses = nil - link_checks_status = nil - citations = nil - views = nil - downloads = nil - end + facets_to_facet_methods = { + states: :facet_by_key, + resource_types: :facet_by_combined_key, + created: :facet_by_key_as_string, + created_by_month: :facet_by_key_as_string, + published: :facet_by_range, + registered: :facet_by_key_as_string, + providers: :facet_by_combined_key, + clients: :facet_by_combined_key, + client_types: :facet_by_client_type, + affiliations: :facet_by_combined_key, + prefixes: :facet_by_key, + certificates: :facet_by_key, + licenses: :facet_by_license, + schema_versions: :facet_by_schema, + link_checks_status: :facet_by_cumulative_year, + creators_and_contributors: :facet_by_creators_and_contributors, + subjects: :facet_by_key, + fields_of_science: :facet_by_fos, + languages: :facet_by_language, + registration_agencies: :facet_by_registration_agency, + citations: :metric_facet_by_year, + views: :metric_facet_by_year, + downloads: :metric_facet_by_year + } + + facets_to_bucket_path = { + fields_of_science: [:subject, :buckets] + } + aggregations = response.aggregations + facets = facets_to_facet_methods.map do |facet, method| + if aggregations.dig(facet) + buckets = facets_to_bucket_path.dig(facet) ? aggregations.dig(facet, *facets_to_bucket_path[facet]) : aggregations.dig(facet).buckets + [facet.to_s.camelize(:lower), send(method, buckets)] + end + end.compact.to_h respond_to do |format| format.json do options = {} @@ -271,27 +268,8 @@ def index page: if page[:cursor].nil? && page[:number].present? page[:number] - end, - states: states, - "resourceTypes" => resource_types, - created: created, - createdByMonth: created_by_month, - published: published, - registered: registered, - providers: providers, - clients: clients, - affiliations: affiliations, - prefixes: prefixes, - certificates: certificates, - licenses: licenses, - "schemaVersions" => schema_versions, - "linkChecksStatus" => link_checks_status, - subjects: subjects, - "fieldsOfScience" => fields_of_science, - citations: citations, - views: views, - downloads: downloads, - }.compact + end + }.merge(facets).compact options[:links] = { self: request.original_url, @@ -325,6 +303,7 @@ def index "has-affiliation" => params[:has_affiliation], "has-funder" => params[:has_funder], "disable-facets" => params[:disable_facets], + "facets" => params[:facets], detail: params[:detail], composite: params[:composite], affiliation: params[:affiliation], diff --git a/app/models/doi.rb b/app/models/doi.rb index b9a2c9bd6..737ba3605 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -674,81 +674,139 @@ def as_indexed_json(_options = {}) } end - - def self.query_aggregations(disable_facets: false) - if !disable_facets - { - # number of resourceTypeGeneral increased from 16 to 28 in schema 4.4 - resource_types: { terms: { field: "resource_type_id_and_name", size: 30, min_doc_count: 1 } }, - states: { terms: { field: "aasm_state", size: 3, min_doc_count: 1 } }, - published: { - date_histogram: { - field: "publication_year", - interval: "year", - format: "year", - order: { - _key: "desc", - }, - min_doc_count: 1, + def self.all_doi_aggregations + { + # number of resourceTypeGeneral increased from 16 to 28 in schema 4.4 + resource_types: { terms: { field: "resource_type_id_and_name", size: 30, min_doc_count: 1 } }, + states: { terms: { field: "aasm_state", size: 3, min_doc_count: 1 } }, + published: { + date_histogram: { + field: "publication_year", + interval: "year", + format: "year", + order: { + _key: "desc", }, + min_doc_count: 1, }, - registration_agencies: { terms: { field: "agency", size: 10, min_doc_count: 1 } }, - created: { date_histogram: { field: "created", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, - aggs: { bucket_truncate: { bucket_sort: { size: 10 } } } }, - registered: { date_histogram: { field: "registered", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, - aggs: { bucket_truncate: { bucket_sort: { size: 10 } } } }, - providers: { terms: { field: "provider_id_and_name", size: 10, min_doc_count: 1 } }, - clients: { terms: { field: "client_id_and_name", size: 10, min_doc_count: 1 } }, - affiliations: { terms: { field: "affiliation_id_and_name", size: 10, min_doc_count: 1 } }, - prefixes: { terms: { field: "prefix", size: 10, min_doc_count: 1 } }, - schema_versions: { terms: { field: "schema_version", size: 10, min_doc_count: 1 } }, - link_checks_status: { terms: { field: "landing_page.status", size: 10, min_doc_count: 1 } }, - # link_checks_has_schema_org: { terms: { field: 'landing_page.hasSchemaOrg', size: 2, min_doc_count: 1 } }, - # link_checks_schema_org_id: { value_count: { field: "landing_page.schemaOrgId" } }, - # link_checks_dc_identifier: { value_count: { field: "landing_page.dcIdentifier" } }, - # link_checks_citation_doi: { value_count: { field: "landing_page.citationDoi" } }, - # links_checked: { value_count: { field: "landing_page.checked" } }, - # sources: { terms: { field: 'source', size: 15, min_doc_count: 1 } }, - subjects: { terms: { field: "subjects.subject", size: 10, min_doc_count: 1 } }, - pid_entities: { - filter: { term: { "subjects.subjectScheme": "PidEntity" } }, - aggs: { - subject: { terms: { field: "subjects.subject", size: 10, min_doc_count: 1, - include: %w(Dataset Publication Software Organization Funder Person Grant Sample Instrument Repository Project) } }, - }, + }, + registration_agencies: { terms: { field: "agency", size: 10, min_doc_count: 1 } }, + created: { date_histogram: { field: "created", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, + aggs: { bucket_truncate: { bucket_sort: { size: 10 } } } }, + registered: { date_histogram: { field: "registered", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, + aggs: { bucket_truncate: { bucket_sort: { size: 10 } } } }, + providers: { terms: { field: "provider_id_and_name", size: 10, min_doc_count: 1 } }, + clients: { terms: { field: "client_id_and_name", size: 10, min_doc_count: 1 } }, + client_types: { + terms: { + field: "client.client_type", + size: 4, + min_doc_count: 1 + } + }, + affiliations: { terms: { field: "affiliation_id_and_name", size: 10, min_doc_count: 1 } }, + prefixes: { terms: { field: "prefix", size: 10, min_doc_count: 1 } }, + schema_versions: { terms: { field: "schema_version", size: 10, min_doc_count: 1 } }, + link_checks_status: { terms: { field: "landing_page.status", size: 10, min_doc_count: 1 } }, + subjects: { terms: { field: "subjects.subject", size: 10, min_doc_count: 1 } }, + pid_entities: { + filter: { term: { "subjects.subjectScheme": "PidEntity" } }, + aggs: { + subject: { terms: { field: "subjects.subject", size: 10, min_doc_count: 1, + include: %w(Dataset Publication Software Organization Funder Person Grant Sample Instrument Repository Project) } }, }, - fields_of_science: { - filter: { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, - aggs: { - subject: { terms: { field: "subjects.subject", size: 10, min_doc_count: 1, - include: "FOS:.*" } }, - }, + }, + fields_of_science: { + filter: { term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" } }, + aggs: { + subject: { terms: { field: "subjects.subject", size: 10, min_doc_count: 1, + include: "FOS:.*" } }, }, - licenses: { terms: { field: "rights_list.rightsIdentifier", size: 10, min_doc_count: 1 } }, - languages: { terms: { field: "language", size: 10, min_doc_count: 1 } }, - certificates: { terms: { field: "client.certificate", size: 10, min_doc_count: 1 } }, - views: { - date_histogram: { field: "publication_year", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, - aggs: { - metric_count: { sum: { field: "view_count" } }, - bucket_truncate: { bucket_sort: { size: 10 } }, - }, + }, + licenses: { terms: { field: "rights_list.rightsIdentifier", size: 10, min_doc_count: 1 } }, + languages: { terms: { field: "language", size: 10, min_doc_count: 1 } }, + certificates: { terms: { field: "client.certificate", size: 10, min_doc_count: 1 } }, + creators_and_contributors: { + terms: { + field: "creators_and_contributors.nameIdentifiers.nameIdentifier", + size: 10, + min_doc_count: 1, + include: "https?://orcid.org/.*" }, - downloads: { - date_histogram: { field: "publication_year", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, - aggs: { - metric_count: { sum: { field: "download_count" } }, - bucket_truncate: { bucket_sort: { size: 10 } }, + aggs: { + creators_and_contributors: { + top_hits: { + _source: { + includes: [ + "creators_and_contributors.name", + "creators_and_contributors.nameIdentifiers.nameIdentifier" + ] + }, + size: 1 + } }, + "work_types": { + "terms": { + "field": "resource_type_id_and_name", + "min_doc_count": 1 + } + } + } + }, + views: { + date_histogram: { field: "publication_year", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, + aggs: { + metric_count: { sum: { field: "view_count" } }, + bucket_truncate: { bucket_sort: { size: 10 } }, }, - citations: { - date_histogram: { field: "publication_year", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, - aggs: { - metric_count: { sum: { field: "citation_count" } }, - bucket_truncate: { bucket_sort: { size: 10 } }, - }, + }, + downloads: { + date_histogram: { field: "publication_year", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, + aggs: { + metric_count: { sum: { field: "download_count" } }, + bucket_truncate: { bucket_sort: { size: 10 } }, }, - } + }, + citations: { + date_histogram: { field: "publication_year", interval: "year", format: "year", order: { _key: "desc" }, min_doc_count: 1 }, + aggs: { + metric_count: { sum: { field: "citation_count" } }, + bucket_truncate: { bucket_sort: { size: 10 } }, + }, + }, + } + end + + def self.default_doi_query_facets + [ + :resource_types, + :states, + :published, + :created, + :registered, + :providers, + :clients, + :affiliations, + :prefixes, + :schema_versions, + :link_checks_status, + :subjects, + :fields_of_science, + :licenses, + :certificates, + :views, + :downloads, + :citations + ] + end + + def self.query_aggregations(disable_facets: false, facets: nil) + requested_facets = facets.respond_to?(:split) ? facets.split(",").map(&:strip).map(&:underscore).map(&:to_sym).uniq : default_doi_query_facets + + if disable_facets + {} + else + requested_facets.map { |facet| [facet, all_doi_aggregations.dig(facet)] }.to_h.compact end end @@ -820,7 +878,7 @@ def self.find_by_ids(ids, options = {}) must: must, }, }, - aggregations: query_aggregations(disable_facets: options[:disable_facets]), + aggregations: query_aggregations(disable_facets: options[:disable_facets], facets: options[:facets]), ) end @@ -902,9 +960,9 @@ def self.query(query, options = {}) elsif options[:totals_agg] == "prefix" prefix_aggregations elsif options[:client_type] == "igsnCatalog" - query_aggregations(disable_facets: options[:disable_facets]).merge(self.igsn_id_catalog_aggregations) + query_aggregations(disable_facets: options[:disable_facets], facets: options[:facets]).merge(self.igsn_id_catalog_aggregations) else - query_aggregations(disable_facets: options[:disable_facets]) + query_aggregations(disable_facets: options[:disable_facets], facets: options[:facets]) end # Cursor nav uses search_after, this should always be an array of values that match the sort. diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index 999c5031c..7f29ab56a 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -236,6 +236,65 @@ def clear_doi_index next_link = next_link_absolute.path + "?" + next_link_absolute.query expect(next_link).to eq("/dois?fields%5Bdois%5D=id%2Csubjects&page%5Bnumber%5D=2&page%5Bsize%5D=2") end + + it "returns default facets" do + get "/dois", nil, headers + + expect(last_response.status).to eq(200) + expect(json["data"].size).to eq(10) + expect(json.dig("meta", "total")).to eq(10) + + expect(json.dig("meta").length).to eq(21) + expect(json.dig("meta", "states")).to be_truthy + expect(json.dig("meta", "resourceTypes")).to be_truthy + expect(json.dig("meta", "created")).to be_truthy + expect(json.dig("meta", "published")).to be_truthy + expect(json.dig("meta", "registered")).to be_truthy + expect(json.dig("meta", "providers")).to be_truthy + expect(json.dig("meta", "clients")).to be_truthy + expect(json.dig("meta", "affiliations")).to be_truthy + expect(json.dig("meta", "prefixes")).to be_truthy + expect(json.dig("meta", "certificates")).to be_truthy + expect(json.dig("meta", "licenses")).to be_truthy + expect(json.dig("meta", "schemaVersions")).to be_truthy + expect(json.dig("meta", "linkChecksStatus")).to be_truthy + expect(json.dig("meta", "subjects")).to be_truthy + expect(json.dig("meta", "fieldsOfScience")).to be_truthy + expect(json.dig("meta", "citations")).to be_truthy + expect(json.dig("meta", "views")).to be_truthy + expect(json.dig("meta", "downloads")).to be_truthy + + expect(json.dig("meta", "clientTypes")).to eq(nil) + expect(json.dig("meta", "languages")).to eq(nil) + expect(json.dig("meta", "creatorsAndContributors")).to eq(nil) + end + + it "returns no facets when disable-facets is set" do + get "/dois?disable-facets=true", nil, headers + + expect(last_response.status).to eq(200) + expect(json["data"].size).to eq(10) + expect(json.dig("meta", "total")).to eq(10) + expect(json.dig("meta").length).to eq(3) + expect(json.dig("meta", "states")).to eq(nil) + end + + it "returns specified facets when facets is set" do + get "/dois?facets=client_types,registrationAgencies, clients,languages,creators_and_contributors,made_up_facet", nil, headers + + expect(last_response.status).to eq(200) + expect(json["data"].size).to eq(10) + expect(json.dig("meta", "total")).to eq(10) + expect(json.dig("meta").length).to eq(8) + expect(json.dig("meta", "states")).to eq(nil) + expect(json.dig("meta", "clientTypes")).to be_truthy + expect(json.dig("meta", "registrationAgencies")).to be_truthy + expect(json.dig("meta", "clients")).to be_truthy + expect(json.dig("meta", "languages")).to be_truthy + expect(json.dig("meta", "creatorsAndContributors")).to be_truthy + expect(json.dig("meta", "madeUpFacet")).to eq(nil) + expect(json.dig("meta", "made_up_facet")).to eq(nil) + end end describe "GET /dois with nil publisher values", elsasticsearch: true, prefix_pool_size: 1 do From 5b3fc6540dd44bb29c1fe4467a57c65cd8aefce9 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:36:39 -0500 Subject: [PATCH 31/35] Support for facets and disable-facets URL params in find_by_ids --- app/controllers/datacite_dois_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 9162c4d5a..9162a02c6 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -84,7 +84,7 @@ def index if params[:id].present? response = DataciteDoi.find_by_id(params[:id]) elsif params[:ids].present? - response = DataciteDoi.find_by_ids(params[:ids], page: page, sort: sort) + response = DataciteDoi.find_by_ids(params[:ids], disable_facets: params[:disable_facets], facets: params[:facets], page: page, sort: sort) else response = DataciteDoi.query( From 642b2210a867b79923f0fa32bdac0e7d77de799b Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Mon, 9 Dec 2024 09:54:04 -0500 Subject: [PATCH 32/35] Change enumeration to hash method --- app/models/doi.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 737ba3605..53cb7b206 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -801,13 +801,10 @@ def self.default_doi_query_facets end def self.query_aggregations(disable_facets: false, facets: nil) - requested_facets = facets.respond_to?(:split) ? facets.split(",").map(&:strip).map(&:underscore).map(&:to_sym).uniq : default_doi_query_facets + return {} if disable_facets - if disable_facets - {} - else - requested_facets.map { |facet| [facet, all_doi_aggregations.dig(facet)] }.to_h.compact - end + requested_facets = facets.respond_to?(:split) ? facets.split(",").map(&:strip).map(&:underscore).map(&:to_sym).uniq : default_doi_query_facets + requested_facets.index_with { |facet| all_doi_aggregations.dig(facet) }.compact end def self.provider_aggregations From 39d6ece26efb0b4ba005731333b61c8c55854699 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Thu, 12 Dec 2024 12:05:15 +0100 Subject: [PATCH 33/35] Appease rubocop --- app/models/doi/graphql_query.rb | 2 +- .../graphql_query_builder_aggregates_spec.rb | 223 +++++++++--------- .../doi/graphql_query_builder_filters_spec.rb | 188 +++++++-------- spec/models/doi/graphql_query_builder_spec.rb | 2 - 4 files changed, 202 insertions(+), 213 deletions(-) diff --git a/app/models/doi/graphql_query.rb b/app/models/doi/graphql_query.rb index e7e899e21..46611b534 100644 --- a/app/models/doi/graphql_query.rb +++ b/app/models/doi/graphql_query.rb @@ -30,7 +30,7 @@ def size end def sort - DEFAULT_SORT + DEFAULT_SORT end def query_fields diff --git a/spec/models/doi/graphql_query_builder_aggregates_spec.rb b/spec/models/doi/graphql_query_builder_aggregates_spec.rb index d3853eebe..9c10e0911 100644 --- a/spec/models/doi/graphql_query_builder_aggregates_spec.rb +++ b/spec/models/doi/graphql_query_builder_aggregates_spec.rb @@ -11,110 +11,110 @@ builder = described_class.new(query, options) expect(builder.aggregations).to eq( { - :affiliations=>{:terms=>{:field=>"affiliation_id_and_name", :min_doc_count=>1, :missing=>"__missing__", :size=>10}}, - :authors=>{ - :aggs=>{:authors=>{ - :top_hits=>{:_source=>{ - :includes=>["creators.name", "creators.nameIdentifiers.nameIdentifier"], - }, :size=>1}, - }}, - :terms=>{:field=>"creators.nameIdentifiers.nameIdentifier", :include=>"https?://orcid.org/.*", :min_doc_count=>1, :size=>10}, - }, - :citation_count=>{ - :sum=>{:field=>"citation_count"}, - }, - :client_types=>{ - :terms=>{:field=>"client.client_type", :min_doc_count=>1, :size=>10}, - }, - :clients=>{ - :terms=>{:field=>"client_id_and_name", :min_doc_count=>1, :size=>10}, - }, - :content_url_count=>{ - :value_count=>{:field=>"content_url"}, - }, - :creators_and_contributors=>{ - :aggs=>{ - :creators_and_contributors=>{ - :top_hits=>{:_source=>{ - :includes=>["creators_and_contributors.name", "creators_and_contributors.nameIdentifiers.nameIdentifier"], - }, :size=>1}, + affiliations: { terms: { field: "affiliation_id_and_name", min_doc_count: 1, missing: "__missing__", size: 10 } }, + authors: { + aggs: { authors: { + top_hits: { _source: { + includes: ["creators.name", "creators.nameIdentifiers.nameIdentifier"], + }, size: 1 }, + } }, + terms: { field: "creators.nameIdentifiers.nameIdentifier", include: "https?://orcid.org/.*", min_doc_count: 1, size: 10 }, + }, + citation_count: { + sum: { field: "citation_count" }, + }, + client_types: { + terms: { field: "client.client_type", min_doc_count: 1, size: 10 }, + }, + clients: { + terms: { field: "client_id_and_name", min_doc_count: 1, size: 10 }, + }, + content_url_count: { + value_count: { field: "content_url" }, + }, + creators_and_contributors: { + aggs: { + creators_and_contributors: { + top_hits: { _source: { + includes: ["creators_and_contributors.name", "creators_and_contributors.nameIdentifiers.nameIdentifier"], + }, size: 1 }, }, - :work_types=>{:terms=>{:field=>"resource_type_id_and_name", :min_doc_count=>1}}, + work_types: { terms: { field: "resource_type_id_and_name", min_doc_count: 1 } }, }, - :terms=>{ - :field=>"creators_and_contributors.nameIdentifiers.nameIdentifier", - :include=>"https?://orcid.org/.*", - :min_doc_count=>1, - :size=>10, + terms: { + field: "creators_and_contributors.nameIdentifiers.nameIdentifier", + include: "https?://orcid.org/.*", + min_doc_count: 1, + size: 10, }, }, - :download_count=>{ - :sum=>{:field=>"download_count"}, - }, - :fields_of_science=>{ - :aggs=>{ - :subject=>{ - :terms=>{ - :field=>"subjects.subject", - :include=>"FOS:.*", - :min_doc_count=>1, - :size=>10, + download_count: { + sum: { field: "download_count" }, + }, + fields_of_science: { + aggs: { + subject: { + terms: { + field: "subjects.subject", + include: "FOS:.*", + min_doc_count: 1, + size: 10, }, }, }, - :filter=>{ - :term=>{:"subjects.subjectScheme"=>"Fields of Science and Technology (FOS)"}, + filter: { + term: { "subjects.subjectScheme": "Fields of Science and Technology (FOS)" }, }, }, - :fields_of_science_combined=>{ - :terms=>{ - :field=>"fields_of_science_combined", - :min_doc_count=>1, - :size=>10, + fields_of_science_combined: { + terms: { + field: "fields_of_science_combined", + min_doc_count: 1, + size: 10, }, }, - :fields_of_science_repository=>{ - :terms=>{ - :field=>"fields_of_science_repository", - :min_doc_count=>1, - :size=>10, + fields_of_science_repository: { + terms: { + field: "fields_of_science_repository", + min_doc_count: 1, + size: 10, }, }, - :funders=>{ - :aggs=>{:funders=>{:top_hits=>{:_source=>{:includes=>["funding_references.funderName", "funding_references.funderIdentifier"]}, :size=>1}}}, - :terms=>{ - :field=>"funding_references.funderIdentifier", - :min_doc_count=>1, - :size=>10, + funders: { + aggs: { funders: { top_hits: { _source: { includes: ["funding_references.funderName", "funding_references.funderIdentifier"] }, size: 1 } } }, + terms: { + field: "funding_references.funderIdentifier", + min_doc_count: 1, + size: 10, }, }, - :languages=>{ - :terms=>{ - :field=>"language", - :min_doc_count=>1, - :size=>10, + languages: { + terms: { + field: "language", + min_doc_count: 1, + size: 10, }, }, - :licenses=>{ - :terms=>{ - :field=>"rights_list.rightsIdentifier", - :min_doc_count=>1, - :missing=>"__missing__", - :size=>10, + licenses: { + terms: { + field: "rights_list.rightsIdentifier", + min_doc_count: 1, + missing: "__missing__", + size: 10, }, }, - :open_licenses=>{ - :aggs=>{ - :resource_types=>{ - :terms=>{ - :field=>"resource_type_id_and_name", - :min_doc_count=>1, - :size=>10, + open_licenses: { + aggs: { + resource_types: { + terms: { + field: "resource_type_id_and_name", + min_doc_count: 1, + size: 10, }, }, }, - :filter=>{ - :terms=>{:"rights_list.rightsIdentifier"=>[ + filter: { + terms: { "rights_list.rightsIdentifier": [ "cc-by-1.0", "cc-by-2.0", "cc-by-2.5", @@ -125,15 +125,15 @@ "cc-pddc", "cc0-1.0", "cc-pdm-1.0", - ]}, + ] }, }, }, - :pid_entities=>{ - :aggs=>{ - :subject=>{ - :terms=>{ - :field=>"subjects.subject", - :include=>[ + pid_entities: { + aggs: { + subject: { + terms: { + field: "subjects.subject", + include: [ "Dataset", "Publication", "Software", @@ -146,33 +146,33 @@ "Repository", "Project", ], - :min_doc_count=>1, - :size=>10, + min_doc_count: 1, + size: 10, }, }, }, - :filter=>{:term=>{:"subjects.subjectScheme"=>"PidEntity"}}, - }, - :published=>{ - :date_histogram=>{ - :field=>"publication_year", - :format=>"year", - :interval=>"year", - :min_doc_count=>1, - :order=>{:_key=>"desc"}, + filter: { term: { "subjects.subjectScheme": "PidEntity" } }, + }, + published: { + date_histogram: { + field: "publication_year", + format: "year", + interval: "year", + min_doc_count: 1, + order: { _key: "desc" }, }, }, - :registration_agencies=>{ - :terms=>{:field=>"agency", :min_doc_count=>1, :size=>10}, + registration_agencies: { + terms: { field: "agency", min_doc_count: 1, size: 10 }, }, - :resource_types=>{:terms=>{ - :field=>"resource_type_id_and_name", - :min_doc_count=>1, - :missing=>"__missing__", - :size=>10, - }}, - :view_count=>{ - :sum=>{:field=>"view_count"}, + resource_types: { terms: { + field: "resource_type_id_and_name", + min_doc_count: 1, + missing: "__missing__", + size: 10, + } }, + view_count: { + sum: { field: "view_count" }, }, } ) @@ -206,7 +206,4 @@ expect(builder.aggregations.keys).to match_array(expected_keys) end end - - - end diff --git a/spec/models/doi/graphql_query_builder_filters_spec.rb b/spec/models/doi/graphql_query_builder_filters_spec.rb index 84aa88316..261ef7af2 100644 --- a/spec/models/doi/graphql_query_builder_filters_spec.rb +++ b/spec/models/doi/graphql_query_builder_filters_spec.rb @@ -10,115 +10,112 @@ describe "filters" do context "with basic filters" do - it "handles DOI ids" do - options = { ids: "10.5438/0012,10.5438/0013" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } - ) - end - - it "handles resource_type_id" do - options = { resource_type_id: "Journal_Article" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { resource_type_id: "journal-article" } } - ) - - end + it "handles DOI ids" do + options = { ids: "10.5438/0012,10.5438/0013" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { doi: ["10.5438/0012", "10.5438/0013"].map(&:upcase) } } + ) + end - it "handles resource type" do - options = { resource_type: "dataset,text" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { "types.resourceType": ["dataset", "text"] } } - ) - end + it "handles resource_type_id" do + options = { resource_type_id: "Journal_Article" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { resource_type_id: "journal-article" } } + ) + end + it "handles resource type" do + options = { resource_type: "dataset,text" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { "types.resourceType": ["dataset", "text"] } } + ) + end - it "handles agency" do - options = {agency: "crossref"} - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { agency: ["crossref"].map(&:downcase) } } - ) - end - it "handles prefix" do - options = {prefix: "10.5438"} - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { prefix: ["10.5438"].map(&:downcase) } } - ) - end + it "handles agency" do + options = { agency: "crossref" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { agency: ["crossref"].map(&:downcase) } } + ) + end - it "handles language" do - options = { language: "en,de" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { language: ["en", "de"].map(&:downcase) } } - ) - end + it "handles prefix" do + options = { prefix: "10.5438" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { prefix: ["10.5438"].map(&:downcase) } } + ) + end - it "handles uid" do - options = { uid: "10.5438/0012" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { uid: "10.5438/0012" } } - ) - end + it "handles language" do + options = { language: "en,de" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { language: ["en", "de"].map(&:downcase) } } + ) + end - it "handles state" do - options = { state: "findable,registered" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { aasm_state: ["findable", "registered"] } } - ) - end + it "handles uid" do + options = { uid: "10.5438/0012" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { uid: "10.5438/0012" } } + ) + end - it "handles consortium_id" do - options = { consortium_id: "dc" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { consortium_id: { :case_insensitive => true, :value => "dc" } } } - ) - end + it "handles state" do + options = { state: "findable,registered" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { aasm_state: ["findable", "registered"] } } + ) + end - it "handles registered" do - options = { registered: "2021,2023" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { range: { registered: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } - ) - end + it "handles consortium_id" do + options = { consortium_id: "dc" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { consortium_id: { case_insensitive: true, value: "dc" } } } + ) + end + it "handles registered" do + options = { registered: "2021,2023" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { range: { registered: { gte: "2021||/y", lte: "2023||/y", format: "yyyy" } } } + ) + end end context "filters based on client metadata" do - it "handles re3data_id" do - options = { re3data_id: "10.17616/r31njmjx" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "client.re3data_id" => "10.17616/r31njmjx" } } - ) - end - - it "handles opendoar_id" do - options = { opendoar_id: "123456" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { term: { "client.opendoar_id" => "123456" } } - ) - end + it "handles re3data_id" do + options = { re3data_id: "10.17616/r31njmjx" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "client.re3data_id" => "10.17616/r31njmjx" } } + ) + end - it "handles certificates" do - options = { certificate: "CoreTrustSeal,WDS" } - builder = described_class.new(query, options) - expect(builder.filters).to include( - { terms: { "client.certificate" => ["CoreTrustSeal", "WDS"] } } - ) - end + it "handles opendoar_id" do + options = { opendoar_id: "123456" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { term: { "client.opendoar_id" => "123456" } } + ) + end + it "handles certificates" do + options = { certificate: "CoreTrustSeal,WDS" } + builder = described_class.new(query, options) + expect(builder.filters).to include( + { terms: { "client.certificate" => ["CoreTrustSeal", "WDS"] } } + ) + end end context "with date range filters" do @@ -304,8 +301,5 @@ expect(builder.filters).to be_empty end end - - - end end diff --git a/spec/models/doi/graphql_query_builder_spec.rb b/spec/models/doi/graphql_query_builder_spec.rb index 683eb74a6..034adcbcf 100644 --- a/spec/models/doi/graphql_query_builder_spec.rb +++ b/spec/models/doi/graphql_query_builder_spec.rb @@ -69,9 +69,7 @@ let(:options) { { sort: "relevance" } } it "ignores any sort options and returns the default" do expect(builder.sort).to eq(described_class::DEFAULT_SORT) - end end end - end From f4029e1252330437a449c8c871f31e76f1fd056f Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:38:52 -0500 Subject: [PATCH 34/35] Implements expected behavior for disable_facets=false and allow query_aggregations to be callable with an array of symbols --- app/models/doi.rb | 21 +++-- spec/models/doi_spec.rb | 85 +++++++++++++++++++ .../datacite_dois/datacite_dois_spec.rb | 78 +++++++++++------ 3 files changed, 149 insertions(+), 35 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 53cb7b206..0210d0475 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -674,10 +674,9 @@ def as_indexed_json(_options = {}) } end - def self.all_doi_aggregations - { - # number of resourceTypeGeneral increased from 16 to 28 in schema 4.4 - resource_types: { terms: { field: "resource_type_id_and_name", size: 30, min_doc_count: 1 } }, + DOI_AGGREGATION_DEFINITIONS = { + # number of resourceTypeGeneral increased from 30 to 32 in schema 4.6 + resource_types: { terms: { field: "resource_type_id_and_name", size: 32, min_doc_count: 1 } }, states: { terms: { field: "aasm_state", size: 3, min_doc_count: 1 } }, published: { date_histogram: { @@ -775,7 +774,6 @@ def self.all_doi_aggregations }, }, } - end def self.default_doi_query_facets [ @@ -801,10 +799,17 @@ def self.default_doi_query_facets end def self.query_aggregations(disable_facets: false, facets: nil) - return {} if disable_facets + return {} if disable_facets.to_s == "true" + + selected_facets = if facets.is_a?(String) + facets.split(",").map(&:strip).map(&:underscore).map(&:to_sym) + else + Array.wrap(facets).map(&:to_sym) + end.uniq + + selected_facets = default_doi_query_facets if facets.nil? - requested_facets = facets.respond_to?(:split) ? facets.split(",").map(&:strip).map(&:underscore).map(&:to_sym).uniq : default_doi_query_facets - requested_facets.index_with { |facet| all_doi_aggregations.dig(facet) }.compact + DOI_AGGREGATION_DEFINITIONS.slice(*selected_facets) end def self.provider_aggregations diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index 85bad8fc1..5d03eb7f5 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -1929,6 +1929,91 @@ end end + describe "query_aggregations" do + default_aggregations = Doi.default_doi_query_facets + + it "returns default aggregations when disable_facets and facets are not set" do + aggregations = Doi.query_aggregations + + expect(aggregations.keys).to match_array(default_aggregations) + end + + it "returns default aggregations when disable_facets is set to false" do + aggregations = Doi.query_aggregations(disable_facets: false) + + expect(aggregations.keys).to match_array(default_aggregations) + end + + it "returns blank aggregations when disable_facets is true" do + aggregations = Doi.query_aggregations(disable_facets: true) + + expect(aggregations).to eq({}) + end + + it "returns blank aggregations when disable_facets is true string" do + aggregations = Doi.query_aggregations(disable_facets: "true") + + expect(aggregations).to eq({}) + end + + it "returns default aggregations when disable_facets is false" do + aggregations = Doi.query_aggregations(disable_facets: false) + + expect(aggregations.keys).to match_array(default_aggregations) + end + + it "returns default aggregations when disable_facets is false string" do + aggregations = Doi.query_aggregations(disable_facets: "false") + + expect(aggregations.keys).to match_array(default_aggregations) + end + + it "returns selected aggregations when facets is a string" do + facets_string = "creators_and_contributors, registrationAgencies,made_up_facet,states,registration_agencies" + aggregations = Doi.query_aggregations(facets: facets_string) + expected_aggregations = [:creators_and_contributors, :registration_agencies, :states] + + expect(aggregations.keys).to match_array(expected_aggregations) + end + + it "returns blank aggregations when facets is a blank string" do + facets_string = "" + aggregations = Doi.query_aggregations(facets: facets_string) + + expect(aggregations).to eq({}) + end + + it "returns selected aggregations when facets is an array of symbols" do + facets_array = [:creators_and_contributors, :registration_agencies, :states, :made_up_facet, :registration_agencies] + aggregations = Doi.query_aggregations(facets: facets_array) + expected_aggregations = [:creators_and_contributors, :registration_agencies, :states] + + expect(aggregations.keys).to match_array(expected_aggregations) + end + + it "returns blank aggregations when facets is a blank array" do + facets_array = [] + aggregations = Doi.query_aggregations(facets: facets_array) + + expect(aggregations).to eq({}) + end + + it "returns selected aggregations when facets are an array of symbols and disable_facets is false" do + facets_array = [:creators_and_contributors, :registration_agencies, :states, :made_up_facet, :registration_agencies] + aggregations = Doi.query_aggregations(facets: facets_array, disable_facets: false) + expected_aggregations = [:creators_and_contributors, :registration_agencies, :states] + + expect(aggregations.keys).to match_array(expected_aggregations) + end + + it "returns blank aggregations when facets are an array of symbols and disable_facets is true" do + facets_array = [:creators_and_contributors, :registration_agencies, :states, :made_up_facet, :registration_agencies] + aggregations = Doi.query_aggregations(facets: facets_array, disable_facets: true) + + expect(aggregations).to eq({}) + end + end + describe "formats" do content_url = [ "https://redivis.com/datasets/rt7m-4ndqm48zf/tables/1dgp-0rkbx6ahe?v=1.2", diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index 7f29ab56a..ee79d372f 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -13,6 +13,26 @@ def clear_doi_index DataciteDoi.__elasticsearch__.client.indices.refresh(index: DataciteDoi.index_name) end +DEFAULT_DOIS_FACETS = [ + "states", + "resourceTypes", + "created", + "published", + "registered", + "providers", + "clients", + "affiliations", + "prefixes", + "certificates", + "licenses", + "schemaVersions", + "linkChecksStatus", + "subjects", + "fieldsOfScience", + "citations", + "views", + "downloads" +] describe DataciteDoisController, type: :request, vcr: true do let(:admin) { create(:provider, symbol: "ADMIN") } @@ -244,39 +264,43 @@ def clear_doi_index expect(json["data"].size).to eq(10) expect(json.dig("meta", "total")).to eq(10) - expect(json.dig("meta").length).to eq(21) - expect(json.dig("meta", "states")).to be_truthy - expect(json.dig("meta", "resourceTypes")).to be_truthy - expect(json.dig("meta", "created")).to be_truthy - expect(json.dig("meta", "published")).to be_truthy - expect(json.dig("meta", "registered")).to be_truthy - expect(json.dig("meta", "providers")).to be_truthy - expect(json.dig("meta", "clients")).to be_truthy - expect(json.dig("meta", "affiliations")).to be_truthy - expect(json.dig("meta", "prefixes")).to be_truthy - expect(json.dig("meta", "certificates")).to be_truthy - expect(json.dig("meta", "licenses")).to be_truthy - expect(json.dig("meta", "schemaVersions")).to be_truthy - expect(json.dig("meta", "linkChecksStatus")).to be_truthy - expect(json.dig("meta", "subjects")).to be_truthy - expect(json.dig("meta", "fieldsOfScience")).to be_truthy - expect(json.dig("meta", "citations")).to be_truthy - expect(json.dig("meta", "views")).to be_truthy - expect(json.dig("meta", "downloads")).to be_truthy - - expect(json.dig("meta", "clientTypes")).to eq(nil) - expect(json.dig("meta", "languages")).to eq(nil) - expect(json.dig("meta", "creatorsAndContributors")).to eq(nil) - end - - it "returns no facets when disable-facets is set" do + expect(json.dig("meta").length).to eq(DEFAULT_DOIS_FACETS.length + 3) + expect(json.dig("meta").keys).to match_array(DEFAULT_DOIS_FACETS + ["total", "totalPages", "page"]) + end + + it "returns default facets when disable-facets is set to false" do + get "/dois?disable-facets=false", nil, headers + + expect(last_response.status).to eq(200) + expect(json["data"].size).to eq(10) + expect(json.dig("meta", "total")).to eq(10) + + expect(json.dig("meta").length).to eq(DEFAULT_DOIS_FACETS.length + 3) + expect(json.dig("meta").keys).to match_array(DEFAULT_DOIS_FACETS + ["total", "totalPages", "page"]) + end + + it "returns no facets when disable-facets is set to true" do get "/dois?disable-facets=true", nil, headers expect(last_response.status).to eq(200) expect(json["data"].size).to eq(10) expect(json.dig("meta", "total")).to eq(10) expect(json.dig("meta").length).to eq(3) - expect(json.dig("meta", "states")).to eq(nil) + DEFAULT_DOIS_FACETS.each do |facet| + expect(json.dig("meta", facet)).to eq(nil) + end + end + + it "returns no facets when facets is empty" do + get "/dois?facets=", nil, headers + + expect(last_response.status).to eq(200) + expect(json["data"].size).to eq(10) + expect(json.dig("meta", "total")).to eq(10) + expect(json.dig("meta").length).to eq(3) + DEFAULT_DOIS_FACETS.each do |facet| + expect(json.dig("meta", facet)).to eq(nil) + end end it "returns specified facets when facets is set" do From a169b1a0bdba80ba706c773ef12bc33d69468161 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:45:57 -0500 Subject: [PATCH 35/35] Returns no facets when the result set is empty --- app/controllers/datacite_dois_controller.rb | 14 +++++++------ .../datacite_dois/datacite_dois_spec.rb | 20 +++++++++++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 9162a02c6..74639fbec 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -253,12 +253,14 @@ def index } aggregations = response.aggregations - facets = facets_to_facet_methods.map do |facet, method| - if aggregations.dig(facet) - buckets = facets_to_bucket_path.dig(facet) ? aggregations.dig(facet, *facets_to_bucket_path[facet]) : aggregations.dig(facet).buckets - [facet.to_s.camelize(:lower), send(method, buckets)] - end - end.compact.to_h + facets = total == 0 ? {} : + facets_to_facet_methods.map do |facet, method| + if aggregations.dig(facet) + buckets = facets_to_bucket_path.dig(facet) ? aggregations.dig(facet, *facets_to_bucket_path[facet]) : aggregations.dig(facet).buckets + [facet.to_s.camelize(:lower), send(method, buckets)] + end + end.compact.to_h + respond_to do |format| format.json do options = {} diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index ee79d372f..bec0cf9d0 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -34,6 +34,12 @@ def clear_doi_index "downloads" ] +DEFAULT_META_FIELDS = [ + "total", + "totalPages", + "page", +] + describe DataciteDoisController, type: :request, vcr: true do let(:admin) { create(:provider, symbol: "ADMIN") } let(:admin_bearer) { Client.generate_token(role_id: "staff_admin", uid: admin.symbol, password: admin.password) } @@ -265,7 +271,7 @@ def clear_doi_index expect(json.dig("meta", "total")).to eq(10) expect(json.dig("meta").length).to eq(DEFAULT_DOIS_FACETS.length + 3) - expect(json.dig("meta").keys).to match_array(DEFAULT_DOIS_FACETS + ["total", "totalPages", "page"]) + expect(json.dig("meta").keys).to match_array(DEFAULT_DOIS_FACETS + DEFAULT_META_FIELDS) end it "returns default facets when disable-facets is set to false" do @@ -276,7 +282,7 @@ def clear_doi_index expect(json.dig("meta", "total")).to eq(10) expect(json.dig("meta").length).to eq(DEFAULT_DOIS_FACETS.length + 3) - expect(json.dig("meta").keys).to match_array(DEFAULT_DOIS_FACETS + ["total", "totalPages", "page"]) + expect(json.dig("meta").keys).to match_array(DEFAULT_DOIS_FACETS + DEFAULT_META_FIELDS) end it "returns no facets when disable-facets is set to true" do @@ -319,6 +325,16 @@ def clear_doi_index expect(json.dig("meta", "madeUpFacet")).to eq(nil) expect(json.dig("meta", "made_up_facet")).to eq(nil) end + + it "returns no facets when the result set is empty" do + get "/dois?query=creators.name:foo", nil, headers + + expect(last_response.status).to eq(200) + expect(json["data"].size).to eq(0) + expect(json.dig("meta", "total")).to eq(0) + expect(json.dig("meta").length).to eq(3) + expect(json.dig("meta").keys).to match_array(DEFAULT_META_FIELDS) + end end describe "GET /dois with nil publisher values", elsasticsearch: true, prefix_pool_size: 1 do