ddr-models 2.4.0.rc5 → 2.4.0.rc6

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