ddr-models 2.4.0.rc2 → 2.4.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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