ddr-models 2.4.0.rc5 → 2.4.0.rc6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a57bdb43e8f09d8bba57f543fa677e6f584d49e0
4
- data.tar.gz: aaf3160fc9732099da710cff89d874701f2c9432
3
+ metadata.gz: 41cc8abee7e422452e72bf103a639f2fd8c9b12f
4
+ data.tar.gz: 2500d3facc196eeeb47deb8a31f01bc89c4d9b97
5
5
  SHA512:
6
- metadata.gz: dbb52a96b1ea4168b8bc8a0d7cc813b425b3e407f9ce5a13d1a330a176c1684e039c3195182bf615f3199d13fc8465b3765dbc97c95bc6be47822feba9fbb7a1
7
- data.tar.gz: d8f17c7f174c712105de7c53a6107fafb216fb6121655b9e439adeb886cf359f8c524edd06a7a9e2123e252ee0a05a2408fba4da5e2ee66762c3fc4561ce2bbc
6
+ metadata.gz: 0d1a0070f6099ca82a7f134eef231dfa14226c0829d076f70baa6505ef380d1381da691fcedc6bba135eff0a8007071ae4870cfc5d084af700105d1b29617701
7
+ data.tar.gz: 95f8776c042c8612a2ab9bac5268daed97b80498c69cfbf4bfaffe90e36989b38b91d54e784b13667e24a21093b3fc1515984c9cd76a6837c953a362c295414a
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
33
33
  s.add_dependency "cancancan", "~> 1.12"
34
34
  s.add_dependency "ddr-antivirus", "~> 2.1.1"
35
35
  s.add_dependency "virtus", "~> 1.0.5"
36
+ s.add_dependency "hashie", "~> 3.4.3"
36
37
 
37
38
  s.add_development_dependency "bundler", "~> 1.11"
38
39
  s.add_development_dependency "rake"
@@ -4,6 +4,7 @@ module Ddr
4
4
 
5
5
  autoload :AbstractQueryResult
6
6
  autoload :Connection
7
+ autoload :CSVOptions
7
8
  autoload :CSVQueryResult
8
9
  autoload :DocumentBuilder
9
10
  autoload :Field
@@ -18,6 +19,7 @@ module Ddr
18
19
  autoload :QueryParams
19
20
  autoload :QueryResult
20
21
  autoload :Response
22
+ autoload :SolrCSVOptions
21
23
  autoload :SortOrder
22
24
  autoload :UniqueKeyField
23
25
 
@@ -6,7 +6,7 @@ module Ddr::Index
6
6
  delegate :params, to: :query
7
7
 
8
8
  def initialize(query)
9
- @query = query
9
+ @query = query.dup.freeze
10
10
  @conn = Connection.new
11
11
  end
12
12
 
@@ -0,0 +1,14 @@
1
+ require "csv"
2
+ require "hashie"
3
+
4
+ module Ddr::Index
5
+ class CSVOptions < Hashie::Dash
6
+
7
+ property :headers, default: CSV::DEFAULT_OPTIONS[:headers]
8
+ property :return_headers, default: true
9
+ property :write_headers, default: true
10
+ property :col_sep, default: CSV::DEFAULT_OPTIONS[:col_sep]
11
+ property :quote_char, default: CSV::DEFAULT_OPTIONS[:quote_char]
12
+
13
+ end
14
+ end
@@ -4,57 +4,64 @@ module Ddr::Index
4
4
  class CSVQueryResult < AbstractQueryResult
5
5
 
6
6
  MAX_ROWS = 10**8
7
+ MV_SEP = ";"
7
8
 
8
- COL_SEP = CSV::DEFAULT_OPTIONS[:col_sep].freeze
9
- QUOTE_CHAR = CSV::DEFAULT_OPTIONS[:quote_char].freeze
9
+ attr_reader :mv_sep
10
10
 
11
- SOLR_CSV_OPTS = {
12
- "csv.header" => "false",
13
- "csv.mv.separator" => ";",
14
- "wt" => "csv",
15
- }.freeze
11
+ delegate :read, :each, to: :csv
16
12
 
17
- CSV_OPTS = {
18
- return_headers: true,
19
- write_headers: true,
20
- }.freeze
21
-
22
- attr_reader :csv_opts, :solr_csv_opts
23
-
24
- def initialize(query, **opts)
13
+ def initialize(query, mv_sep: MV_SEP)
25
14
  super(query)
15
+ @mv_sep = mv_sep
16
+ end
17
+
18
+ def csv
19
+ CSV.new(data, csv_opts.to_h)
20
+ end
26
21
 
27
- @solr_csv_opts = SOLR_CSV_OPTS.dup
28
- @solr_csv_opts[:rows] ||= MAX_ROWS
22
+ def to_s
23
+ read.to_csv
24
+ end
29
25
 
30
- @csv_opts = CSV_OPTS.dup
31
- @csv_opts[:headers] = query.fields.map(&:label)
26
+ def rows
27
+ query.rows || MAX_ROWS
28
+ end
32
29
 
33
- # Set column separator and quote character consistently
34
- @csv_opts[:col_sep] = @solr_csv_opts["csv.separator"] = opts.fetch(:col_sep, COL_SEP)
35
- @csv_opts[:quote_char] = @solr_csv_opts["csv.encapsulator"] = opts.fetch(:quote_char, QUOTE_CHAR)
30
+ def csv_opts
31
+ @csv_opts ||= CSVOptions.new(headers: csv_headers)
36
32
  end
37
33
 
38
- def csv
39
- CSV.new(data, csv_opts)
34
+ def solr_csv_opts
35
+ @solr_csv_opts ||= SolrCSVOptions.new(col_sep: csv_opts.col_sep,
36
+ quote_char: csv_opts.quote_char,
37
+ header: solr_csv_header,
38
+ mv_sep: mv_sep,
39
+ rows: rows)
40
40
  end
41
41
 
42
- def each
43
- csv.each
42
+ def headers
43
+ @headers ||= query.fields.map(&:heading)
44
44
  end
45
45
 
46
- def to_s
47
- csv.string
46
+ def csv_headers
47
+ if headers.empty?
48
+ :first_row
49
+ else
50
+ headers
51
+ end
48
52
  end
49
53
 
50
- private
54
+ def solr_csv_header
55
+ csv_headers == :first_row
56
+ end
51
57
 
52
- def csv_params
53
- params.merge(solr_csv_opts)
58
+ def solr_csv_params
59
+ params.merge solr_csv_opts.params
54
60
  end
55
61
 
56
62
  def data
57
- conn.get "select", params: csv_params
63
+ raw = conn.get("select", params: solr_csv_params)
64
+ raw.gsub(/\\#{mv_sep}/, mv_sep)
58
65
  end
59
66
 
60
67
  end
@@ -3,7 +3,7 @@ require "virtus"
3
3
  module Ddr::Index
4
4
  class FieldAttribute < Virtus::Attribute
5
5
 
6
- def coerce(value)
6
+ def self.coerce(value)
7
7
  case value
8
8
  when Field
9
9
  value
@@ -14,5 +14,9 @@ module Ddr::Index
14
14
  end
15
15
  end
16
16
 
17
+ def coerce(value)
18
+ self.class.coerce(value)
19
+ end
20
+
17
21
  end
18
22
  end
@@ -27,6 +27,12 @@ module Ddr::Index
27
27
  self
28
28
  end
29
29
 
30
+ def where_not(conditions)
31
+ self.clauses += conditions.map do |field, v|
32
+ Array(v).map { |value| QueryClause.negative(field, value) }
33
+ end.flatten
34
+ end
35
+
30
36
  def absent(field)
31
37
  self.clauses << QueryClause.absent(field)
32
38
  self
@@ -59,7 +65,7 @@ module Ddr::Index
59
65
  delegate Api.public_instance_methods => :new_filter
60
66
 
61
67
  def has_content
62
- where active_fedora_model: [ "Component", "Attachment", "Target" ]
68
+ model "Component", "Attachment", "Target"
63
69
  end
64
70
 
65
71
  def is_governed_by(object_or_id)
@@ -70,6 +76,10 @@ module Ddr::Index
70
76
  term is_member_of_collection: internal_uri(object_or_id)
71
77
  end
72
78
 
79
+ def model(*models)
80
+ where active_fedora_model: models
81
+ end
82
+
73
83
  private
74
84
 
75
85
  def internal_uri(object_or_id)
@@ -15,6 +15,13 @@ module Ddr::Index
15
15
  delegate [:count, :docs, :pids, :each_pid, :all] => :result
16
16
  delegate :params => :query_params
17
17
 
18
+ def initialize(**args, &block)
19
+ super(**args)
20
+ if block_given?
21
+ build(&block)
22
+ end
23
+ end
24
+
18
25
  def inspect
19
26
  "#<#{self.class.name} q=#{q.inspect}, filters=#{filters.inspect}," \
20
27
  " sort=#{sort.inspect}, rows=#{rows.inspect}, fields=#{fields.inspect}>"
@@ -40,5 +47,10 @@ module Ddr::Index
40
47
  QueryParams.new(self)
41
48
  end
42
49
 
50
+ def build(&block)
51
+ QueryBuilder.new(self, &block)
52
+ self
53
+ end
54
+
43
55
  end
44
56
  end
@@ -12,6 +12,7 @@ module Ddr::Index
12
12
  #
13
13
  # asc [field], ...
14
14
  # Adds ascending orderings by the fields specified.
15
+ #
15
16
  # See also: desc, order_by
16
17
  #
17
18
  # before [field], [date_time]
@@ -20,10 +21,11 @@ module Ddr::Index
20
21
  #
21
22
  # before_days [field], [int]
22
23
  # Adds a filter selecting documents where the field has a date/time the
23
- # specified number of days before today (now) or earlier.
24
+ # specified number of days before today (now) or earlier.
24
25
  #
25
26
  # desc [field], ...
26
27
  # Adds descending orderings by the fields specified.
28
+ #
27
29
  # See also: asc, order_by
28
30
  #
29
31
  # id [doc_id]
@@ -31,6 +33,7 @@ module Ddr::Index
31
33
  #
32
34
  # filter [filter1], ...
33
35
  # Adds filters to the query.
36
+ #
34
37
  # Aliased as: filters
35
38
  #
36
39
  # filters [filter], ...
@@ -38,7 +41,8 @@ module Ddr::Index
38
41
  #
39
42
  # field [field1], ...
40
43
  # Adds fields to result documents.
41
- # Note that all fields are returned when none is specified.
44
+ # Note that all fields are returned when none is specified.
45
+ #
42
46
  # Aliased as: fields
43
47
  #
44
48
  # fields [field], ...
@@ -46,13 +50,19 @@ module Ddr::Index
46
50
  #
47
51
  # limit [int]
48
52
  # Limits the number of documents returned by the query.
53
+ #
49
54
  # Aliased as: rows
50
55
  #
56
+ # model [model_name], ...
57
+ # Adds a filter selecting document where ActiveFedora model equals value
58
+ # or one of the values.
59
+ #
51
60
  # negative [field], [value]
52
61
  # Adds a filter selecting document where field does not have the value.
53
62
  #
54
63
  # order_by [{field => order, ...}], ...
55
64
  # Adds ordering(s) to the query.
65
+ #
56
66
  # Aliased as: sort
57
67
  #
58
68
  # present [field]
@@ -75,8 +85,8 @@ module Ddr::Index
75
85
  #
76
86
  # where [{field => value, ...}]
77
87
  # Adds a filter of "standard" query clauses.
78
- # Values will be escaped when the filter is serialized.
79
- # If a hash value is an array, that query clause will select documents
88
+ # Values will be escaped when the filter is serialized.
89
+ # If a hash value is an array, that query clause will select documents
80
90
  # where the field matches any array entry.
81
91
  #
82
92
  class QueryBuilder
@@ -95,8 +105,8 @@ module Ddr::Index
95
105
 
96
106
  attr_reader :query
97
107
 
98
- def initialize(&block)
99
- @query = Query.new
108
+ def initialize(query = nil, &block)
109
+ @query = query || Query.new
100
110
  if block_given?
101
111
  instance_eval &block
102
112
  end
@@ -120,7 +130,7 @@ module Ddr::Index
120
130
  # @param fields [Array<Field>]
121
131
  # @return [QueryBuilder] self
122
132
  def field(*fields)
123
- query.fields += fields
133
+ query.fields += fields.flatten.map { |f| FieldAttribute.coerce(f) }
124
134
  self
125
135
  end
126
136
  alias_method :fields, :field
@@ -46,10 +46,11 @@ module Ddr::Index
46
46
  alias_method :id, :unique_key
47
47
 
48
48
  def where(field, value)
49
- if value.respond_to?(:each)
50
- disjunction(field, value)
49
+ values = Array(value)
50
+ if values.size > 1
51
+ disjunction(field, values)
51
52
  else
52
- new(field: field, value: value, quote_value: true)
53
+ new(field: field, value: values.first, quote_value: true)
53
54
  end
54
55
  end
55
56
 
@@ -65,7 +66,7 @@ module Ddr::Index
65
66
 
66
67
  # Builds a query clause to filter where field is NOT present (no values)
67
68
  def absent(field)
68
- new(field: "-#{field}", value: ANY_VALUE)
69
+ new(field: field, value: ANY_VALUE, template: NEGATIVE_QUERY)
69
70
  end
70
71
 
71
72
  # Builds a query clause to filter where field contains at least one of a set of values.
@@ -0,0 +1,18 @@
1
+ require "hashie"
2
+
3
+ module Ddr::Index
4
+ class SolrCSVOptions < Hashie::Trash
5
+
6
+ property "csv.header", from: :header, default: false
7
+ property "csv.separator", from: :col_sep, default: ","
8
+ property "csv.encapsulator", from: :quote_char, default: '"'
9
+ property "csv.mv.separator", from: :mv_sep, default: ","
10
+ property :wt, default: "csv"
11
+ property :rows
12
+
13
+ def params
14
+ to_h.reject { |k, v| v.nil? }
15
+ end
16
+
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  module Ddr
2
2
  module Models
3
- VERSION = "2.4.0.rc5"
3
+ VERSION = "2.4.0.rc6"
4
4
  end
5
5
  end
@@ -54,7 +54,23 @@ module Ddr::Index
54
54
  end
55
55
  describe ".has_content" do
56
56
  subject { described_class.has_content }
57
- its(:clauses) { are_expected.to eq([QueryClause.where(:active_fedora_model, ["Component", "Attachment", "Target"])]) }
57
+ its(:clauses) {
58
+ are_expected.to eq([QueryClause.where(:active_fedora_model, ["Component", "Attachment", "Target"])])
59
+ }
60
+ end
61
+ describe ".model" do
62
+ describe "with a single model" do
63
+ subject { described_class.model("Component") }
64
+ its(:clauses) {
65
+ are_expected.to eq([QueryClause.where(:active_fedora_model, "Component")])
66
+ }
67
+ end
68
+ describe "with a list of models" do
69
+ subject { described_class.model("Component", "Attachment", "Target") }
70
+ its(:clauses) {
71
+ are_expected.to eq([QueryClause.where(:active_fedora_model, ["Component", "Attachment", "Target"])])
72
+ }
73
+ end
58
74
  end
59
75
  describe ".where" do
60
76
  subject { described_class.where("foo"=>"bar", "spam"=>"eggs", "stuff"=>["dog", "cat", "bird"]) }
@@ -95,7 +111,7 @@ module Ddr::Index
95
111
 
96
112
  describe "API methods" do
97
113
  describe "#where" do
98
- it "adds raw query filters for the hash of conditions" do
114
+ it "adds query clauses for the hash of conditions" do
99
115
  subject.where("foo"=>"bar", "spam"=>"eggs", "stuff"=>["dog", "cat", "bird"])
100
116
  expect(subject.clauses).to eq([QueryClause.where("foo", "bar"),
101
117
  QueryClause.where("spam", "eggs"),
@@ -103,6 +119,17 @@ module Ddr::Index
103
119
  ])
104
120
  end
105
121
  end
122
+ describe "#where_not" do
123
+ it "adds negative query clauses for the hash of conditions" do
124
+ subject.where_not("foo"=>"bar", "spam"=>"eggs", "stuff"=>["dog", "cat", "bird"])
125
+ expect(subject.clauses).to eq([QueryClause.negative("foo", "bar"),
126
+ QueryClause.negative("spam", "eggs"),
127
+ QueryClause.negative("stuff", "dog"),
128
+ QueryClause.negative("stuff", "cat"),
129
+ QueryClause.negative("stuff", "bird")
130
+ ])
131
+ end
132
+ end
106
133
  describe "#raw" do
107
134
  it "adds the query clauses w/o escaping" do
108
135
  subject.raw("foo:bar", "spam:eggs")
@@ -43,7 +43,11 @@ module Ddr::Index
43
43
  subject { described_class.where("foo", "Jungle Fever") }
44
44
  its(:to_s) { is_expected.to eq "foo:\"Jungle Fever\"" }
45
45
  end
46
- describe "when the value is an array" do
46
+ describe "when the value is an Array with one entry" do
47
+ subject { described_class.where("foo", ["Jungle Fever"]) }
48
+ its(:to_s) { is_expected.to eq "foo:\"Jungle Fever\"" }
49
+ end
50
+ describe "when the value is an array with multiple entries" do
47
51
  subject { described_class.where("foo", ["Jungle Fever", "bar"]) }
48
52
  its(:to_s) { is_expected.to eq "{!lucene q.op=OR df=foo}\"Jungle Fever\" bar" }
49
53
  end
@@ -1,26 +1,48 @@
1
1
  module Ddr::Index
2
2
  RSpec.describe Query do
3
3
 
4
- let(:id) { UniqueKeyField.instance }
5
- let(:foo) { Field.new("foo") }
6
- let(:spam) { Field.new("spam") }
7
- let(:filter) { Filter.where(spam=>"eggs") }
8
- let(:sort_order) { SortOrder.new(field: foo, order: "asc") }
9
- let(:fields) { [id, foo, spam] }
4
+ describe "initialized with attributes" do
5
+ let(:id) { UniqueKeyField.instance }
6
+ let(:foo) { Field.new("foo") }
7
+ let(:spam) { Field.new("spam") }
8
+ let(:filter) { Filter.where(spam=>"eggs") }
9
+ let(:sort_order) { SortOrder.new(field: foo, order: "asc") }
10
+ let(:fields) { [id, foo, spam] }
10
11
 
11
- subject {
12
- described_class.new(q: "foo:bar",
13
- filters: [filter],
14
- fields: fields,
15
- sort: sort_order,
16
- rows: 50)
17
- }
12
+ subject {
13
+ described_class.new(q: "foo:bar",
14
+ filters: [filter],
15
+ fields: fields,
16
+ sort: sort_order,
17
+ rows: 50)
18
+ }
19
+
20
+ its(:to_s) {
21
+ is_expected.to eq "q=foo%3Abar&fq=spam%3Aeggs&fl=id%2Cfoo%2Cspam&sort=foo+asc&rows=50"
22
+ }
23
+ its(:params) {
24
+ is_expected.to eq({q: "foo:bar", fl: "id,foo,spam", fq: ["spam:eggs"], sort: "foo asc", rows: 50})
25
+ }
26
+ end
27
+
28
+ describe "initialized with a block" do
29
+ subject {
30
+ described_class.new do
31
+ q "foo:bar"
32
+ where "spam"=>"eggs"
33
+ fields :id, "foo", "spam"
34
+ asc "foo"
35
+ limit 50
36
+ end
37
+ }
38
+
39
+ its(:to_s) {
40
+ is_expected.to eq "q=foo%3Abar&fq=spam%3Aeggs&fl=id%2Cfoo%2Cspam&sort=foo+asc&rows=50"
41
+ }
42
+ its(:params) {
43
+ is_expected.to eq({q: "foo:bar", fl: "id,foo,spam", fq: ["spam:eggs"], sort: "foo asc", rows: 50})
44
+ }
45
+ end
18
46
 
19
- its(:to_s) {
20
- is_expected.to eq "q=foo%3Abar&fq=spam%3Aeggs&fl=id%2Cfoo%2Cspam&sort=foo+asc&rows=50"
21
- }
22
- its(:params) {
23
- is_expected.to eq({q: "foo:bar", fl: "id,foo,spam", fq: ["spam:eggs"], sort: "foo asc", rows: 50})
24
- }
25
47
  end
26
48
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddr-models
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0.rc5
4
+ version: 2.4.0.rc6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Coble
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-18 00:00:00.000000000 Z
12
+ date: 2016-01-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -227,6 +227,20 @@ dependencies:
227
227
  - - "~>"
228
228
  - !ruby/object:Gem::Version
229
229
  version: 1.0.5
230
+ - !ruby/object:Gem::Dependency
231
+ name: hashie
232
+ requirement: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: 3.4.3
237
+ type: :runtime
238
+ prerelease: false
239
+ version_requirements: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: 3.4.3
230
244
  - !ruby/object:Gem::Dependency
231
245
  name: bundler
232
246
  requirement: !ruby/object:Gem::Requirement
@@ -463,6 +477,7 @@ files:
463
477
  - lib/ddr/index.rb
464
478
  - lib/ddr/index/abstract_query_result.rb
465
479
  - lib/ddr/index/connection.rb
480
+ - lib/ddr/index/csv_options.rb
466
481
  - lib/ddr/index/csv_query_result.rb
467
482
  - lib/ddr/index/document_builder.rb
468
483
  - lib/ddr/index/field.rb
@@ -477,6 +492,7 @@ files:
477
492
  - lib/ddr/index/query_params.rb
478
493
  - lib/ddr/index/query_result.rb
479
494
  - lib/ddr/index/response.rb
495
+ - lib/ddr/index/solr_csv_options.rb
480
496
  - lib/ddr/index/sort_order.rb
481
497
  - lib/ddr/index/unique_key_field.rb
482
498
  - lib/ddr/jobs.rb