From 713c0a0455a28a343d6bdbdb31b1ef636528c25d Mon Sep 17 00:00:00 2001 From: Martin Fenner Date: Sun, 16 Jun 2019 16:37:24 +0200 Subject: [PATCH] graphql for re3data. #292 --- app/controllers/dois_controller.rb | 1 + app/graphql/types/api_type.rb | 8 +++ app/graphql/types/name_type.rb | 7 +++ app/graphql/types/query_type.rb | 20 +++++++ .../repository_connection_with_meta_type.rb | 14 +++++ ...itory_dataset_connection_with_meta_type.rb | 14 +++++ app/graphql/types/repository_edge_type.rb | 5 ++ ...y_publication_connection_with_meta_type.rb | 14 +++++ ...tory_software_connection_with_meta_type.rb | 14 +++++ app/graphql/types/repository_type.rb | 52 +++++++++++++++++++ app/graphql/types/scheme_type.rb | 8 +++ app/graphql/types/text_language_type.rb | 8 +++ app/graphql/types/text_restriction_type.rb | 8 +++ app/graphql/types/text_type.rb | 7 +++ app/models/concerns/indexable.rb | 2 + app/models/repository.rb | 7 ++- app/serializers/client_serializer.rb | 2 +- 17 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 app/graphql/types/api_type.rb create mode 100644 app/graphql/types/name_type.rb create mode 100644 app/graphql/types/repository_connection_with_meta_type.rb create mode 100644 app/graphql/types/repository_dataset_connection_with_meta_type.rb create mode 100644 app/graphql/types/repository_edge_type.rb create mode 100644 app/graphql/types/repository_publication_connection_with_meta_type.rb create mode 100644 app/graphql/types/repository_software_connection_with_meta_type.rb create mode 100644 app/graphql/types/repository_type.rb create mode 100644 app/graphql/types/scheme_type.rb create mode 100644 app/graphql/types/text_language_type.rb create mode 100644 app/graphql/types/text_restriction_type.rb create mode 100644 app/graphql/types/text_type.rb diff --git a/app/controllers/dois_controller.rb b/app/controllers/dois_controller.rb index 84ff8d5c5..26004e13a 100644 --- a/app/controllers/dois_controller.rb +++ b/app/controllers/dois_controller.rb @@ -57,6 +57,7 @@ def index registered: params[:registered], provider_id: params[:provider_id], client_id: params[:client_id], + repository_id: params[:repository_id], prefix: params[:prefix], person_id: params[:person_id], resource_type_id: params[:resource_type_id], diff --git a/app/graphql/types/api_type.rb b/app/graphql/types/api_type.rb new file mode 100644 index 000000000..67e678766 --- /dev/null +++ b/app/graphql/types/api_type.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class ApiType < BaseObject + description "Information" + + field :url, String, null: false, description: "URL" + field :type, String, null: true, description: "Type" +end diff --git a/app/graphql/types/name_type.rb b/app/graphql/types/name_type.rb new file mode 100644 index 000000000..1dc222457 --- /dev/null +++ b/app/graphql/types/name_type.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class NameType < BaseObject + description "Information" + + field :name, String, null: false, description: "Information" +end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 3d825fff9..54650f6ff 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -112,6 +112,26 @@ def organization(id:) result end + field :repositories, RepositoryConnectionWithMetaType, null: false, connection: true, max_page_size: 100 do + argument :query, String, required: false + argument :first, Int, required: false, default_value: 25 + end + + def repositories(query: nil, first: nil) + Repository.query(query, limit: first).fetch(:data, []) + end + + field :repository, RepositoryType, null: false do + argument :id, ID, required: true + end + + def repository(id:) + result = Repository.find_by_id(id).fetch(:data, []).first + fail ActiveRecord::RecordNotFound if result.nil? + + result + end + field :datasets, DatasetConnectionWithMetaType, null: false, connection: true, max_page_size: 100 do argument :query, String, required: false argument :first, Int, required: false, default_value: 25 diff --git a/app/graphql/types/repository_connection_with_meta_type.rb b/app/graphql/types/repository_connection_with_meta_type.rb new file mode 100644 index 000000000..565f94f9a --- /dev/null +++ b/app/graphql/types/repository_connection_with_meta_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class RepositoryConnectionWithMetaType < BaseConnection + edge_type(RepositoryEdgeType) + field_class GraphQL::Cache::Field + + field :total_count, Integer, null: false, cache: true + + def total_count + args = object.arguments + + Repository.query(args[:query], limit: 0).dig(:meta, "total").to_i + end +end diff --git a/app/graphql/types/repository_dataset_connection_with_meta_type.rb b/app/graphql/types/repository_dataset_connection_with_meta_type.rb new file mode 100644 index 000000000..1ae1d8209 --- /dev/null +++ b/app/graphql/types/repository_dataset_connection_with_meta_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class RepositoryDatasetConnectionWithMetaType < BaseConnection + edge_type(DatasetEdgeType) + field_class GraphQL::Cache::Field + + field :total_count, Integer, null: false, cache: true + + def total_count + args = object.arguments + + Doi.query(args[:query], repository_id: doi_from_url(object.parent[:id]), resource_type_id: "Dataset", state: "findable", page: { number: 1, size: args[:first] }).results.total + end +end diff --git a/app/graphql/types/repository_edge_type.rb b/app/graphql/types/repository_edge_type.rb new file mode 100644 index 000000000..eb819226a --- /dev/null +++ b/app/graphql/types/repository_edge_type.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class RepositoryEdgeType < GraphQL::Types::Relay::BaseEdge + node_type(RepositoryType) +end diff --git a/app/graphql/types/repository_publication_connection_with_meta_type.rb b/app/graphql/types/repository_publication_connection_with_meta_type.rb new file mode 100644 index 000000000..9b4b8cf0f --- /dev/null +++ b/app/graphql/types/repository_publication_connection_with_meta_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class RepositoryPublicationConnectionWithMetaType < BaseConnection + edge_type(DatasetEdgeType) + field_class GraphQL::Cache::Field + + field :total_count, Integer, null: false, cache: true + + def total_count + args = object.arguments + + Doi.query(args[:query], repository_id: doi_from_url(object.parent[:id]), resource_type_id: "Text", state: "findable", page: { number: 1, size: args[:first] }).results.total + end +end diff --git a/app/graphql/types/repository_software_connection_with_meta_type.rb b/app/graphql/types/repository_software_connection_with_meta_type.rb new file mode 100644 index 000000000..0f3dfe9a7 --- /dev/null +++ b/app/graphql/types/repository_software_connection_with_meta_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class RepositorySoftwareConnectionWithMetaType < BaseConnection + edge_type(DatasetEdgeType) + field_class GraphQL::Cache::Field + + field :total_count, Integer, null: false, cache: true + + def total_count + args = object.arguments + + Doi.query(args[:query], repository_id: doi_from_url(object.parent[:id]), resource_type_id: "Software", state: "findable", page: { number: 1, size: args[:first] }).results.total + end +end diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb new file mode 100644 index 000000000..8ba0b9516 --- /dev/null +++ b/app/graphql/types/repository_type.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +class RepositoryType < BaseObject + description "Information about repository" + + field :id, ID, null: false, description: "Repository ID" + field :re3data_id, String, null: false, description: "re3data ID" + field :name, String, null: false, description: "Repository name" + field :additional_names, [TextLanguageType], null: false, description: "Additional repository names" + field :url, String, null: true, description: "Repository URL" + field :contacts, [TextType], null: true, description: "Repository contact information" + field :description, String, null: true, description: "Repository description" + field :certificates, [TextType], null: true, description: "Repository certificates" + field :subjects, [SchemeType], null: true, description: "Subjects" + field :content_types, [SchemeType], null: true, description: "Content types" + field :provider_types, [TextType], null: true, description: "Provider types" + field :keywords, [TextType], null: true, description: "Keywords" + field :data_accesses, [TextRestrictionType], null: true, description: "Data accesses" + field :data_uploads, [TextRestrictionType], null: true, description: "Data uploads" + field :pid_systems, [TextType], null: true, description: "PID Systems" + field :apis, [ApiType], null: true, description: "APIs" + field :software, [NameType], null: true, description: "Software" + + field :datasets, RepositoryDatasetConnectionWithMetaType, null: false, connection: true, max_page_size: 100, description: "Datasets hosted by the repository" do + argument :query, String, required: false + argument :first, Int, required: false, default_value: 25 + end + + field :publications, RepositoryPublicationConnectionWithMetaType, null: false, connection: true, max_page_size: 100, description: "Publications hosted by the repository" do + argument :query, String, required: false + argument :first, Int, required: false, default_value: 25 + end + + field :softwares, RepositorySoftwareConnectionWithMetaType, null: false, connection: true, max_page_size: 100, description: "Software hosted by the repository" do + argument :query, String, required: false + argument :first, Int, required: false, default_value: 25 + end + + def datasets(**args) + logger = Logger.new(STDOUT) + logger.info doi_from_url(object[:id]) + Doi.query(args[:query], repository_id: doi_from_url(object[:id]), resource_type_id: "Dataset", page: { number: 1, size: args[:first] }).results.to_a + end + + def publications(**args) + Doi.query(args[:query], repository_id: doi_from_url(object[:id]), resource_type_id: "Text", page: { number: 1, size: args[:first] }).results.to_a + end + + def softwares(**args) + Doi.query(args[:query], repository_id: doi_from_url(object[:id]), resource_type_id: "Software", page: { number: 1, size: args[:first] }).results.to_a + end +end diff --git a/app/graphql/types/scheme_type.rb b/app/graphql/types/scheme_type.rb new file mode 100644 index 000000000..bf474100b --- /dev/null +++ b/app/graphql/types/scheme_type.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class SchemeType < BaseObject + description "Information" + + field :scheme, String, null: false, description: "Schema" + field :text, String, null: false, description: "Information" +end diff --git a/app/graphql/types/text_language_type.rb b/app/graphql/types/text_language_type.rb new file mode 100644 index 000000000..d03e27047 --- /dev/null +++ b/app/graphql/types/text_language_type.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class TextLanguageType < BaseObject + description "Information" + + field :language, String, null: true, description: "Language" + field :text, String, null: false, description: "Information" +end diff --git a/app/graphql/types/text_restriction_type.rb b/app/graphql/types/text_restriction_type.rb new file mode 100644 index 000000000..434be60e6 --- /dev/null +++ b/app/graphql/types/text_restriction_type.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class TextRestrictionType < BaseObject + description "Information" + + field :text, String, null: false, description: "Information" + field :restriction, [TextType], null: true, description: "Restriction" +end diff --git a/app/graphql/types/text_type.rb b/app/graphql/types/text_type.rb new file mode 100644 index 000000000..98d220fda --- /dev/null +++ b/app/graphql/types/text_type.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class TextType < BaseObject + description "Information" + + field :text, String, null: false, description: "Information" +end diff --git a/app/models/concerns/indexable.rb b/app/models/concerns/indexable.rb index d607857ca..e47703bb9 100644 --- a/app/models/concerns/indexable.rb +++ b/app/models/concerns/indexable.rb @@ -178,6 +178,8 @@ def query(query, options={}) elsif self.name == "Doi" must << { terms: { aasm_state: options[:state].to_s.split(",") }} if options[:state].present? must << { range: { registered: { gte: "#{options[:registered].split(",").min}||/y", lte: "#{options[:registered].split(",").max}||/y", format: "yyyy" }}} if options[:registered].present? + must << { term: { "client.repository_id": options[:repository_id].upcase }} if options[:repository_id].present? + must_not << { terms: { provider_id: ["crossref"] }} if options[:exclude_registration_agencies] elsif self.name == "Event" must << { term: { subj_id: options[:subj_id] }} if options[:subj_id].present? must << { term: { obj_id: options[:obj_id] }} if options[:obj_id].present? diff --git a/app/models/repository.rb b/app/models/repository.rb index 1ba171ede..e4e4e9330 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -52,7 +52,12 @@ def self.parse_message(id: nil, message: nil) subjects: message["subjects"], content_types: message["contentTypes"], provider_types: message["providerTypes"], - keywords: message["keywords"] }.compact + keywords: message["keywords"], + data_accesses: message["dataAccesses"], + data_uploads: message["dataUploads"], + pid_systems: message["pidSystems"], + apis: message["apis"], + software: message["software"] }.compact end def self.doi_from_url(url) diff --git a/app/serializers/client_serializer.rb b/app/serializers/client_serializer.rb index 47e32759e..3f24beb32 100644 --- a/app/serializers/client_serializer.rb +++ b/app/serializers/client_serializer.rb @@ -5,7 +5,7 @@ class ClientSerializer set_id :uid cache_options enabled: true, cache_length: 24.hours - attributes :name, :symbol, :year, :contact_name, :contact_email, :description, :domains, :url, :created, :updated + attributes :name, :symbol, :re3data, :year, :contact_name, :contact_email, :description, :domains, :url, :created, :updated belongs_to :provider, record_type: :providers belongs_to :repository, record_type: :repositories, if: Proc.new { |client| client.repository_id }