ddr-models 2.4.0.rc2 → 2.4.0.rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,43 +6,73 @@ module Ddr::Index
6
6
  BEFORE_DAYS = "[* TO NOW-%sDAYS]"
7
7
 
8
8
  class << self
9
- # Standard Solr query, no escaping applied
9
+ # Builds a standard query clause, no escaping applied.
10
+ # @param field [Field, String] field
11
+ # @param value [String] query value
12
+ # @return [String] query clause
10
13
  def build(field, value)
11
14
  [field, value].join(":")
12
15
  end
13
16
 
17
+ # Builds a query clause to retrieve the index document by unique key.
14
18
  def unique_key(value)
15
19
  term(UniqueKeyField.instance, value)
16
20
  end
17
21
  alias_method :id, :unique_key
18
- alias_method :pid, :unique_key
19
22
 
23
+ # Builds a query clause to filter where field does not have the given value.
24
+ # @param field [Field, String] field
25
+ # @param value [String] query value
26
+ # @return [String] query clause
20
27
  def negative(field, value)
21
- build "-#{field}", value
28
+ build("-#{field}", value)
22
29
  end
23
30
 
31
+ # Builds a query clause to filter where field is present (i.e, has any value)
32
+ # @param field [Field, String] field
33
+ # @return [String] query clause
24
34
  def present(field)
25
- build field, PRESENT
35
+ build(field, PRESENT)
26
36
  end
27
37
 
38
+ # Builds a query clause to filter where field is NOT present (no values)
39
+ # @param field [Field, String] field
40
+ # @return [String] query clause
28
41
  def absent(field)
29
- negative field, PRESENT
42
+ negative(field, PRESENT)
30
43
  end
31
44
 
45
+ # Builds a query clause to filter where field contains at least one of a set of values.
46
+ # @param field [Field, String] field
47
+ # @param values [Array<String>] query values
48
+ # @return [String] query clause
32
49
  def or_values(field, values)
33
- build field, QueryValue.or_values(values)
50
+ build(field, QueryValue.or_values(values))
34
51
  end
35
52
 
53
+ # Builds a query clause to filter where date field value is earlier than a date/time value.
54
+ # @param field [Field, String] field
55
+ # @param value [Object] query value, must be coercible to a Solr date string.
56
+ # @return [String] query clause
36
57
  def before(field, date_time)
37
58
  value = "[* TO %s]" % Ddr::Utils.solr_date(date_time)
38
- build field, value
59
+ build(field, value)
39
60
  end
40
61
 
62
+ # Builds a query clause to filter where date field value is earlier than a number of days before now.
63
+ # @param field [Field, String] field
64
+ # @param value [String, Fixnum] query value, must be coercible to integer.
65
+ # @return [String] query clause
41
66
  def before_days(field, days)
42
67
  value = BEFORE_DAYS % days.to_i
43
- build field, value
68
+ build(field, value)
44
69
  end
45
70
 
71
+ # Builds a "term query" clause to filter where field contains value.
72
+ # Double quotes are escaped.
73
+ # @param field [Field, String] field
74
+ # @param value [String] query value
75
+ # @return [String] Solr term query
46
76
  def term(field, value)
47
77
  TERM % [field, value.gsub(/"/, '\"')]
48
78
  end
@@ -0,0 +1,24 @@
1
+ require "delegate"
2
+
3
+ module Ddr::Index
4
+ class QueryParams < SimpleDelegator
5
+
6
+ attr_reader :params
7
+
8
+ def initialize(query)
9
+ super
10
+ @params = {
11
+ q: q,
12
+ fq: fq,
13
+ fl: fields.join(","),
14
+ sort: sort.join(","),
15
+ rows: rows,
16
+ }.select { |k, v| v.present? }
17
+ end
18
+
19
+ def fq
20
+ filters.map(&:clauses).flatten
21
+ end
22
+
23
+ end
24
+ end
@@ -2,11 +2,16 @@ module Ddr::Index
2
2
  class QueryValue
3
3
 
4
4
  class << self
5
+ # Returns an escaped query value
6
+ # @param value [String] the unescaped value
7
+ # @return [String] the escaped value
5
8
  def build(value)
6
9
  RSolr.solr_escape(value)
7
10
  end
8
11
 
12
+ # Builds an escaped query value for use in filtering on a field for any value in the list of values
9
13
  # @param values [Enumerable<String>]
14
+ # @return [String] query value
10
15
  def or_values(values)
11
16
  unless values.is_a?(::Enumerable) && values.present?
12
17
  raise ArgumentError, "`#{self.name}.or_values` requires a non-empty enumerable of strings."
@@ -0,0 +1,20 @@
1
+ require "virtus"
2
+
3
+ module Ddr::Index
4
+ class SortOrder
5
+ include Virtus.value_object(strict: true)
6
+
7
+ ASC = "asc"
8
+ DESC = "desc"
9
+
10
+ values do
11
+ attribute :field, String
12
+ attribute :order, String
13
+ end
14
+
15
+ def to_s
16
+ [field, order].join(" ")
17
+ end
18
+
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Models
3
- VERSION = "2.4.0.rc2"
3
+ VERSION = "2.4.0.rc3"
4
4
  end
5
5
  end
@@ -0,0 +1,175 @@
1
+ module Ddr::Index
2
+ RSpec.describe Fields do
3
+
4
+ describe "constants" do
5
+ describe "ID" do
6
+ subject { Fields::ID }
7
+ its(:label) { is_expected.to eq "Fedora PID" }
8
+ its(:heading) { is_expected.to eq "pid" }
9
+ end
10
+
11
+ describe "PID" do
12
+ subject { Fields::PID }
13
+ its(:label) { is_expected.to eq "Fedora PID" }
14
+ its(:heading) { is_expected.to eq "pid" }
15
+ end
16
+
17
+ describe "ACCESS_ROLE" do
18
+ subject { Fields::ACCESS_ROLE }
19
+ its(:label) { is_expected.to eq "Access Role" }
20
+ its(:heading) { is_expected.to eq "access_role" }
21
+ end
22
+
23
+ describe "ACTIVE_FEDORA_MODEL" do
24
+ subject { Fields::ACTIVE_FEDORA_MODEL }
25
+ its(:label) { is_expected.to eq "Model" }
26
+ its(:heading) { is_expected.to eq "model" }
27
+ end
28
+
29
+ describe "ADMIN_SET" do
30
+ subject { Fields::ADMIN_SET }
31
+ its(:label) { is_expected.to eq "Admin Set" }
32
+ its(:heading) { is_expected.to eq "admin_set" }
33
+ end
34
+
35
+ describe "ASPACE_ID" do
36
+ subject { Fields::ASPACE_ID }
37
+ its(:label) { is_expected.to eq "ArchivesSpace ID" }
38
+ its(:heading) { is_expected.to eq "aspace_id" }
39
+ end
40
+
41
+ describe "DOI" do
42
+ subject { Fields::DOI }
43
+ its(:label) { is_expected.to eq "DOI" }
44
+ its(:heading) { is_expected.to eq "doi" }
45
+ end
46
+
47
+ describe "EAD_ID" do
48
+ subject { Fields::EAD_ID }
49
+ its(:label) { is_expected.to eq "EAD ID" }
50
+ its(:heading) { is_expected.to eq "ead_id" }
51
+ end
52
+
53
+ describe "LOCAL_ID" do
54
+ subject { Fields::LOCAL_ID }
55
+ its(:label) { is_expected.to eq "Local ID" }
56
+ its(:heading) { is_expected.to eq "local_id" }
57
+ end
58
+
59
+ describe "OBJECT_CREATE_DATE" do
60
+ subject { Fields::OBJECT_CREATE_DATE }
61
+ its(:label) { is_expected.to eq "Creation Date" }
62
+ its(:heading) { is_expected.to eq "creation_date" }
63
+ end
64
+
65
+ describe "OBJECT_MODIFIED_DATE" do
66
+ subject { Fields::OBJECT_MODIFIED_DATE }
67
+ its(:label) { is_expected.to eq "Modification Date" }
68
+ its(:heading) { is_expected.to eq "modification_date" }
69
+ end
70
+
71
+ describe "PERMANENT_ID" do
72
+ subject { Fields::PERMANENT_ID }
73
+ its(:label) { is_expected.to eq "Permanent ID" }
74
+ its(:heading) { is_expected.to eq "permanent_id" }
75
+ end
76
+
77
+ describe "PERMANENT_URL" do
78
+ subject { Fields::PERMANENT_URL }
79
+ its(:label) { is_expected.to eq "Permanent URL" }
80
+ its(:heading) { is_expected.to eq "permanent_url" }
81
+ end
82
+
83
+ describe "TECHMD_COLOR_SPACE" do
84
+ subject { Fields::TECHMD_COLOR_SPACE }
85
+ its(:label) { is_expected.to eq "Color Space" }
86
+ its(:heading) { is_expected.to eq "color_space" }
87
+ end
88
+
89
+ describe "TECHMD_CREATING_APPLICATION" do
90
+ subject { Fields::TECHMD_CREATING_APPLICATION }
91
+ its(:label) { is_expected.to eq "Creating Application" }
92
+ its(:heading) { is_expected.to eq "creating_application" }
93
+ end
94
+
95
+ describe "TECHMD_CREATION_TIME" do
96
+ subject { Fields::TECHMD_CREATION_TIME }
97
+ its(:label) { is_expected.to eq "Creation Time" }
98
+ its(:heading) { is_expected.to eq "creation_time" }
99
+ end
100
+
101
+ describe "TECHMD_FILE_SIZE" do
102
+ subject { Fields::TECHMD_FILE_SIZE }
103
+ its(:label) { is_expected.to eq "File Size" }
104
+ its(:heading) { is_expected.to eq "file_size" }
105
+ end
106
+
107
+ describe "TECHMD_FITS_VERSION" do
108
+ subject { Fields::TECHMD_FITS_VERSION }
109
+ its(:label) { is_expected.to eq "FITS Version" }
110
+ its(:heading) { is_expected.to eq "fits_version" }
111
+ end
112
+
113
+ describe "TECHMD_FITS_DATETIME" do
114
+ subject { Fields::TECHMD_FITS_DATETIME }
115
+ its(:label) { is_expected.to eq "FITS Run At" }
116
+ its(:heading) { is_expected.to eq "fits_datetime" }
117
+ end
118
+
119
+ describe "TECHMD_FORMAT_LABEL" do
120
+ subject { Fields::TECHMD_FORMAT_LABEL }
121
+ its(:label) { is_expected.to eq "Format Label" }
122
+ its(:heading) { is_expected.to eq "format_label" }
123
+ end
124
+
125
+ describe "TECHMD_FORMAT_VERSION" do
126
+ subject { Fields::TECHMD_FORMAT_VERSION }
127
+ its(:label) { is_expected.to eq "Format Version" }
128
+ its(:heading) { is_expected.to eq "format_version" }
129
+ end
130
+
131
+ describe "TECHMD_IMAGE_HEIGHT" do
132
+ subject { Fields::TECHMD_IMAGE_HEIGHT }
133
+ its(:label) { is_expected.to eq "Image Height" }
134
+ its(:heading) { is_expected.to eq "image_height" }
135
+ end
136
+
137
+ describe "TECHMD_IMAGE_WIDTH" do
138
+ subject { Fields::TECHMD_IMAGE_WIDTH }
139
+ its(:label) { is_expected.to eq "Image Width" }
140
+ its(:heading) { is_expected.to eq "image_width" }
141
+ end
142
+
143
+ describe "TECHMD_MEDIA_TYPE" do
144
+ subject { Fields::TECHMD_MEDIA_TYPE }
145
+ its(:label) { is_expected.to eq "Media Type" }
146
+ its(:heading) { is_expected.to eq "media_type" }
147
+ end
148
+
149
+ describe "TECHMD_MODIFICATION_TIME" do
150
+ subject { Fields::TECHMD_MODIFICATION_TIME }
151
+ its(:label) { is_expected.to eq "Modification Time" }
152
+ its(:heading) { is_expected.to eq "modification_time" }
153
+ end
154
+
155
+ describe "TECHMD_PRONOM_IDENTIFIER" do
156
+ subject { Fields::TECHMD_PRONOM_IDENTIFIER }
157
+ its(:label) { is_expected.to eq "PRONOM Unique ID" }
158
+ its(:heading) { is_expected.to eq "pronom_uid" }
159
+ end
160
+
161
+ describe "TECHMD_VALID" do
162
+ subject { Fields::TECHMD_VALID }
163
+ its(:label) { is_expected.to eq "Valid" }
164
+ its(:heading) { is_expected.to eq "valid" }
165
+ end
166
+
167
+ describe "TECHMD_WELL_FORMED" do
168
+ subject { Fields::TECHMD_WELL_FORMED }
169
+ its(:label) { is_expected.to eq "Well-formed" }
170
+ its(:heading) { is_expected.to eq "well_formed" }
171
+ end
172
+ end
173
+
174
+ end
175
+ end
@@ -1,45 +1,101 @@
1
1
  module Ddr::Index
2
2
  RSpec.describe Filter do
3
3
 
4
- describe "#where(conditions)" do
5
- it "should add raw query filters for the field, value hash of conditions" do
6
- subject.where("foo"=>"bar", "spam"=>"eggs", "stuff"=>["dog", "cat", "bird"])
7
- expect(subject.clauses).to eq(["{!term f=foo}bar", "{!term f=spam}eggs", "stuff:(dog OR cat OR bird)"])
8
- end
9
- end
4
+ its(:clauses) { are_expected.to eq [] }
10
5
 
11
- describe "#raw(*clauses)" do
12
- it "should add the clauses w/o escaping" do
13
- subject.raw("foo:bar", "spam:eggs")
14
- expect(subject.clauses).to eq(["foo:bar", "spam:eggs"])
6
+ describe "equality" do
7
+ describe "when the other is a Filter instance" do
8
+ describe "and the clauses are equal" do
9
+ subject { described_class.new(["foo:bar", "spam:eggs"]) }
10
+ let(:other) { described_class.new(["foo:bar", "spam:eggs"]) }
11
+ specify { expect(subject).to eq other }
12
+ end
13
+ describe "and the clauses are not equal" do
14
+ subject { described_class.new(["foo:bar", "bam:baz"]) }
15
+ let(:other) { described_class.new(["foo:bar", "spam:eggs"]) }
16
+ specify { expect(subject).not_to eq other }
17
+ end
15
18
  end
16
- end
17
-
18
- describe "#present(field)" do
19
- it "should add a \"field present\" clause" do
20
- subject.present("foo")
21
- expect(subject.clauses).to eq(["foo:[* TO *]"])
19
+ describe "when the other is not a Filter instance" do
20
+ subject { described_class.new(["foo:bar", "spam:eggs"]) }
21
+ let(:other) { double(clauses: ["foo:bar", "spam:eggs"]) }
22
+ specify { expect(subject).not_to eq other }
22
23
  end
23
24
  end
24
25
 
25
- describe "#absent(field)" do
26
- it "should add a \"field not present\" clause" do
27
- subject.absent("foo")
28
- expect(subject.clauses).to eq(["-foo:[* TO *]"])
26
+ describe "class methods" do
27
+ describe ".where" do
28
+ subject { Filter.where("foo"=>"bar", "spam"=>"eggs", "stuff"=>["dog", "cat", "bird"]) }
29
+ its(:clauses) { are_expected.to eq (["{!term f=foo}bar", "{!term f=spam}eggs", "stuff:(dog OR cat OR bird)"]) }
29
30
  end
30
- end
31
-
32
- describe "#before_days(field, days)" do
33
- it "should add a date range query clause" do
34
- subject.before_days("foo", 60)
35
- expect(subject.clauses).to eq(["foo:[* TO NOW-60DAYS]"])
31
+ describe "#raw" do
32
+ subject { Filter.raw("foo:bar", "spam:eggs") }
33
+ its(:clauses) { are_expected.to eq(["foo:bar", "spam:eggs"]) }
34
+ end
35
+ describe "#negative" do
36
+ subject { Filter.negative("foo", "bar") }
37
+ its(:clauses) { are_expected.to eq(["-foo:bar"]) }
38
+ end
39
+ describe "#present" do
40
+ subject { Filter.present("foo") }
41
+ its(:clauses) { are_expected.to eq(["foo:[* TO *]"]) }
42
+ end
43
+ describe "#absent" do
44
+ subject { Filter.absent("foo") }
45
+ its(:clauses) { are_expected.to eq(["-foo:[* TO *]"]) }
46
+ end
47
+ describe "#before_days" do
48
+ subject { Filter.before_days("foo", 60) }
49
+ its(:clauses) { are_expected.to eq(["foo:[* TO NOW-60DAYS]"]) }
50
+ end
51
+ describe "#before" do
52
+ subject { Filter.before("foo", DateTime.parse("Thu, 27 Aug 2015 17:42:34 -0400")) }
53
+ its(:clauses) { are_expected.to eq(["foo:[* TO 2015-08-27T21:42:34Z]"]) }
36
54
  end
37
55
  end
38
56
 
39
- describe "#before(field, date_time)" do
40
- it "should add a date range query clause" do
41
- subject.before("foo", DateTime.parse("Thu, 27 Aug 2015 17:42:34 -0400"))
42
- expect(subject.clauses).to eq(["foo:[* TO 2015-08-27T21:42:34Z]"])
57
+ describe "instance methods" do
58
+ describe "#where" do
59
+ it "adds raw query filters for the hash of conditions" do
60
+ subject.where("foo"=>"bar", "spam"=>"eggs", "stuff"=>["dog", "cat", "bird"])
61
+ expect(subject.clauses).to eq(["{!term f=foo}bar", "{!term f=spam}eggs", "stuff:(dog OR cat OR bird)"])
62
+ end
63
+ end
64
+ describe "#raw" do
65
+ it "adds the query clauses w/o escaping" do
66
+ subject.raw("foo:bar", "spam:eggs")
67
+ expect(subject.clauses).to eq(["foo:bar", "spam:eggs"])
68
+ end
69
+ end
70
+ describe "#negative" do
71
+ it "adds a negation query clause" do
72
+ subject.negative("foo", "bar")
73
+ expect(subject.clauses).to eq(["-foo:bar"])
74
+ end
75
+ end
76
+ describe "#present" do
77
+ it "adds a \"field present\" query clause" do
78
+ subject.present("foo")
79
+ expect(subject.clauses).to eq(["foo:[* TO *]"])
80
+ end
81
+ end
82
+ describe "#absent" do
83
+ it "adds a \"field not present\" query clause" do
84
+ subject.absent("foo")
85
+ expect(subject.clauses).to eq(["-foo:[* TO *]"])
86
+ end
87
+ end
88
+ describe "#before_days" do
89
+ it "adds a date range query clause" do
90
+ subject.before_days("foo", 60)
91
+ expect(subject.clauses).to eq(["foo:[* TO NOW-60DAYS]"])
92
+ end
93
+ end
94
+ describe "#before" do
95
+ it "adds a date range query clause" do
96
+ subject.before("foo", DateTime.parse("Thu, 27 Aug 2015 17:42:34 -0400"))
97
+ expect(subject.clauses).to eq(["foo:[* TO 2015-08-27T21:42:34Z]"])
98
+ end
43
99
  end
44
100
  end
45
101