Skip to content

Commit

Permalink
Extract Types::MarcRecordQuery
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeer committed Nov 24, 2020
1 parent a8789d5 commit abbbf4d
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 52 deletions.
3 changes: 1 addition & 2 deletions app/controllers/graphql_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ def execute
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
# current_user: current_user,
current_ability: current_ability
}
result = AggregatorSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
Expand Down
4 changes: 4 additions & 0 deletions app/graphql/types/base_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ module Types
# :nodoc:
class BaseObject < GraphQL::Schema::Object
field_class Types::BaseField

def current_ability
@current_ability ||= context[:current_ability] || Ability.new
end
end
end
67 changes: 67 additions & 0 deletions app/graphql/types/marc_records_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module Types
module MarcRecordsQuery
def with_limit(limit, what, **args, &block)
return send(what, **args, &block) unless limit

i = 0

send(what, **args).each do |record|
yield record
i += 1
break if i >= limit
end
end

def each_record(organization = nil, &block)
return to_enum(:each_record, organization) unless block

l = Array(organization) if organization
l ||= Organization.accessible_by(current_ability)

l.each do |org|
org.default_stream.uploads.find_each do |upload|
upload.each_marc_record_metadata(&block)
end
end
end

def filter_records(filter: nil, organization: nil, &block)
return to_enum(:filter_records, filter: filter, organization: organization) unless block

return each_record(organization, &block) unless filter

each_record(organization) do |record|
yield record if filter.all? { |f| evaluate_marcspec_filter(record.marc, f) }
end
end

def evaluate_marcspec_filter(record, filter)
if filter.include?('$')
field, subfield = filter.split('$', 2)

matching_fields(field).any? do |f|
f[subfield]
end
elsif filter.starts_with? 'LDR'
record.leader
elsif filter.match?(/^\d{3}[a-z]$/)
field = filter[0..2]
subfield = filter[3]
evaluate_marcspec_filter(record, "#{field}$#{subfield}")
else
matching_fields(filter).any?
end
end

def matching_fields(record, field)
return record.fields(filter) if field.match?(/[a-z0-9A-Z]{3}/)
return to_enum(:matching_fields, record, field) unless block_given?

field_as_regex = Regexp.new(field)

record.fields.each do |f|
yield f if f.tag.match?(field_as_regex)
end
end
end
end
53 changes: 4 additions & 49 deletions app/graphql/types/organization_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
module Types
# :nodoc:
class OrganizationType < Types::BaseObject
field :id, ID, null: false
include Types::MarcRecordsQuery

field :slug, ID, null: true
field :name, String, null: true
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
Expand All @@ -13,7 +15,6 @@ class OrganizationType < Types::BaseObject
# field :normalization_steps, Types::JsonType, null: true
field :public, Boolean, null: true
field :name, String, null: true
field :slug, String, null: true
field :records, [MarcRecordType], null: true do
description 'Return all MARC records'
argument :filter, [String], required: false
Expand All @@ -23,53 +24,7 @@ class OrganizationType < Types::BaseObject
def records(limit: 25, **args, &block)
return to_enum(:records, **args, limit: limit) unless block

with_limit(limit, **args, &block)
end

def with_limit(limit, **args, &block)
return filter_records(**args, &block) unless limit

i = 0

filter_records(**args).each do |record|
yield record
i += 1
break if i >= limit
end
end

def each_record(&block)
return to_enum(:each_record) unless block

object.default_stream.uploads.find_each do |upload|
upload.each_marc_record_metadata(&block)
end
end

def filter_records(filter: nil, &block)
return to_enum(:filter_records, filter: filter) unless block

return each_record(&block) unless filter

each_record do |record|
yield record if filter.all? { |f| evaluate_marcspec_filter(record.marc, f) }
end
end

def evaluate_marcspec_filter(record, filter)
if filter.include?('$')
field, subfield = filter.split('$', 2)

record.fields(field).any? do |f|
f[subfield]
end
elsif filter.match?(/^\d{3}[a-z]$/)
field = filter[0..2]
subfield = filter[3]
evaluate_marcspec_filter(record, "#{field}$#{subfield}")
else
record.marc[filter]
end
with_limit(limit, :filter_records, organization: object, **args, &block)
end
end
end
23 changes: 22 additions & 1 deletion app/graphql/types/query_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,37 @@
module Types
# :nodoc:
class QueryType < Types::BaseObject
include Types::MarcRecordsQuery
# Add root-level fields here.
# They will be entry points for queries on your schema.

field :organizations, [OrganizationType], null: false do
description 'List all organizations'
end

field :organization, OrganizationType, null: false do
description 'Find an organization by ID'
argument :id, ID, required: true
end

field :records, [MarcRecordType], null: false do
description 'List all marc records'
argument :filter, [String], required: false
argument :limit, Integer, required: false
end

def organization(id:)
Organization.friendly.find(id)
Organization.accessible_by(current_ability).friendly.find(id)
end

def organizations
Organization.accessible_by(current_ability)
end

def records(limit: 25, **args, &block)
return to_enum(:records, **args, limit: limit) unless block

with_limit(limit, :filter_records, **args, &block)
end
end
end

0 comments on commit abbbf4d

Please sign in to comment.