Skip to content

Commit e0c1720

Browse files
committed
Extract Types::MarcRecordQuery
1 parent a8789d5 commit e0c1720

File tree

5 files changed

+101
-52
lines changed

5 files changed

+101
-52
lines changed

app/controllers/graphql_controller.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ def execute
1616
query = params[:query]
1717
operation_name = params[:operationName]
1818
context = {
19-
# Query context goes here, for example:
20-
# current_user: current_user,
19+
current_ability: current_ability
2120
}
2221
result = AggregatorSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
2322
render json: result

app/graphql/types/base_object.rb

+4
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@ module Types
44
# :nodoc:
55
class BaseObject < GraphQL::Schema::Object
66
field_class Types::BaseField
7+
8+
def current_ability
9+
@current_ability ||= context[:current_ability] || Ability.new
10+
end
711
end
812
end
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
# Graphql query support for retrieving marc records, filtered by fields in the record
5+
module MarcRecordsQuery
6+
def with_limit(limit, what, **args, &block)
7+
return send(what, **args, &block) unless limit
8+
9+
i = 0
10+
11+
send(what, **args).each do |record|
12+
yield record
13+
i += 1
14+
break if i >= limit
15+
end
16+
end
17+
18+
def each_record(organization = nil, &block)
19+
return to_enum(:each_record, organization) unless block
20+
21+
l = Array(organization) if organization
22+
l ||= Organization.accessible_by(current_ability)
23+
24+
l.each do |org|
25+
org.default_stream.uploads.find_each do |upload|
26+
upload.each_marc_record_metadata(&block)
27+
end
28+
end
29+
end
30+
31+
def filter_records(filter: nil, organization: nil, &block)
32+
return to_enum(:filter_records, filter: filter, organization: organization) unless block
33+
34+
return each_record(organization, &block) unless filter
35+
36+
each_record(organization) do |record|
37+
yield record if filter.all? { |f| evaluate_marcspec_filter(record.marc, f) }
38+
end
39+
end
40+
41+
def evaluate_marcspec_filter(record, filter)
42+
if filter.include?('$')
43+
field, subfield = filter.split('$', 2)
44+
45+
matching_fields(field).any? do |f|
46+
f[subfield]
47+
end
48+
elsif filter.starts_with? 'LDR'
49+
record.leader
50+
elsif filter.match?(/^\d{3}[a-z]$/)
51+
field = filter[0..2]
52+
subfield = filter[3]
53+
evaluate_marcspec_filter(record, "#{field}$#{subfield}")
54+
else
55+
matching_fields(filter).any?
56+
end
57+
end
58+
59+
def matching_fields(record, field)
60+
return record.fields(filter) if field.match?(/[a-z0-9A-Z]{3}/)
61+
return to_enum(:matching_fields, record, field) unless block_given?
62+
63+
field_as_regex = Regexp.new(field)
64+
65+
record.fields.each do |f|
66+
yield f if f.tag.match?(field_as_regex)
67+
end
68+
end
69+
end
70+
end

app/graphql/types/organization_type.rb

+4-49
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
module Types
44
# :nodoc:
55
class OrganizationType < Types::BaseObject
6-
field :id, ID, null: false
6+
include Types::MarcRecordsQuery
7+
8+
field :slug, ID, null: true
79
field :name, String, null: true
810
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
911
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
@@ -13,7 +15,6 @@ class OrganizationType < Types::BaseObject
1315
# field :normalization_steps, Types::JsonType, null: true
1416
field :public, Boolean, null: true
1517
field :name, String, null: true
16-
field :slug, String, null: true
1718
field :records, [MarcRecordType], null: true do
1819
description 'Return all MARC records'
1920
argument :filter, [String], required: false
@@ -23,53 +24,7 @@ class OrganizationType < Types::BaseObject
2324
def records(limit: 25, **args, &block)
2425
return to_enum(:records, **args, limit: limit) unless block
2526

26-
with_limit(limit, **args, &block)
27-
end
28-
29-
def with_limit(limit, **args, &block)
30-
return filter_records(**args, &block) unless limit
31-
32-
i = 0
33-
34-
filter_records(**args).each do |record|
35-
yield record
36-
i += 1
37-
break if i >= limit
38-
end
39-
end
40-
41-
def each_record(&block)
42-
return to_enum(:each_record) unless block
43-
44-
object.default_stream.uploads.find_each do |upload|
45-
upload.each_marc_record_metadata(&block)
46-
end
47-
end
48-
49-
def filter_records(filter: nil, &block)
50-
return to_enum(:filter_records, filter: filter) unless block
51-
52-
return each_record(&block) unless filter
53-
54-
each_record do |record|
55-
yield record if filter.all? { |f| evaluate_marcspec_filter(record.marc, f) }
56-
end
57-
end
58-
59-
def evaluate_marcspec_filter(record, filter)
60-
if filter.include?('$')
61-
field, subfield = filter.split('$', 2)
62-
63-
record.fields(field).any? do |f|
64-
f[subfield]
65-
end
66-
elsif filter.match?(/^\d{3}[a-z]$/)
67-
field = filter[0..2]
68-
subfield = filter[3]
69-
evaluate_marcspec_filter(record, "#{field}$#{subfield}")
70-
else
71-
record.marc[filter]
72-
end
27+
with_limit(limit, :filter_records, organization: object, **args, &block)
7328
end
7429
end
7530
end

app/graphql/types/query_type.rb

+22-1
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,37 @@
33
module Types
44
# :nodoc:
55
class QueryType < Types::BaseObject
6+
include Types::MarcRecordsQuery
67
# Add root-level fields here.
78
# They will be entry points for queries on your schema.
89

10+
field :organizations, [OrganizationType], null: false do
11+
description 'List all organizations'
12+
end
13+
914
field :organization, OrganizationType, null: false do
1015
description 'Find an organization by ID'
1116
argument :id, ID, required: true
1217
end
1318

19+
field :records, [MarcRecordType], null: false do
20+
description 'List all marc records'
21+
argument :filter, [String], required: false
22+
argument :limit, Integer, required: false
23+
end
24+
1425
def organization(id:)
15-
Organization.friendly.find(id)
26+
Organization.accessible_by(current_ability).friendly.find(id)
27+
end
28+
29+
def organizations
30+
Organization.accessible_by(current_ability)
31+
end
32+
33+
def records(limit: 25, **args, &block)
34+
return to_enum(:records, **args, limit: limit) unless block
35+
36+
with_limit(limit, :filter_records, **args, &block)
1637
end
1738
end
1839
end

0 commit comments

Comments
 (0)