ansr 0.0.1 → 0.0.3

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.
Files changed (83) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +35 -0
  3. data/ansr.gemspec +2 -1
  4. data/ansr_blacklight/Gemfile +3 -0
  5. data/ansr_blacklight/README.md +37 -0
  6. data/ansr_blacklight/ansr_blacklight.gemspec +28 -0
  7. data/ansr_blacklight/lib/ansr_blacklight.rb +57 -0
  8. data/ansr_blacklight/lib/ansr_blacklight/arel.rb +6 -0
  9. data/ansr_blacklight/lib/ansr_blacklight/arel/big_table.rb +57 -0
  10. data/ansr_blacklight/lib/ansr_blacklight/arel/visitors.rb +6 -0
  11. data/ansr_blacklight/lib/ansr_blacklight/arel/visitors/query_builder.rb +217 -0
  12. data/ansr_blacklight/lib/ansr_blacklight/arel/visitors/to_no_sql.rb +14 -0
  13. data/ansr_blacklight/lib/ansr_blacklight/base.rb +21 -0
  14. data/ansr_blacklight/lib/ansr_blacklight/connection_adapters/no_sql_adapter.rb +38 -0
  15. data/ansr_blacklight/lib/ansr_blacklight/model/querying.rb +29 -0
  16. data/ansr_blacklight/lib/ansr_blacklight/relation.rb +50 -0
  17. data/ansr_blacklight/lib/ansr_blacklight/relation/solr_projection_methods.rb +55 -0
  18. data/ansr_blacklight/lib/ansr_blacklight/request_builders.rb +141 -0
  19. data/ansr_blacklight/lib/ansr_blacklight/solr.rb +4 -0
  20. data/ansr_blacklight/lib/ansr_blacklight/solr/request.rb +46 -0
  21. data/ansr_blacklight/lib/ansr_blacklight/solr/response.rb +94 -0
  22. data/ansr_blacklight/lib/ansr_blacklight/solr/response/group.rb +32 -0
  23. data/ansr_blacklight/lib/ansr_blacklight/solr/response/group_response.rb +50 -0
  24. data/ansr_blacklight/lib/ansr_blacklight/solr/response/more_like_this.rb +14 -0
  25. data/ansr_blacklight/lib/ansr_blacklight/solr/response/pagination_methods.rb +35 -0
  26. data/ansr_blacklight/lib/ansr_blacklight/solr/response/spelling.rb +92 -0
  27. data/ansr_blacklight/spec/fixtures/config.yml +0 -0
  28. data/ansr_blacklight/spec/lib/loaded_relation_spec.rb +223 -0
  29. data/ansr_blacklight/spec/lib/queryable_relation_spec.rb +133 -0
  30. data/ansr_blacklight/spec/lib/relation/faceting_spec.rb +475 -0
  31. data/ansr_blacklight/spec/lib/relation/grouping_spec.rb +159 -0
  32. data/ansr_blacklight/spec/spec_helper.rb +72 -0
  33. data/ansr_dpla/Gemfile +3 -0
  34. data/ansr_dpla/Gemfile.lock +138 -0
  35. data/ansr_dpla/README.md +2 -2
  36. data/ansr_dpla/ansr_dpla.gemspec +2 -2
  37. data/ansr_dpla/lib/ansr_dpla.rb +3 -0
  38. data/ansr_dpla/lib/ansr_dpla/api.rb +3 -3
  39. data/ansr_dpla/lib/ansr_dpla/arel.rb +1 -2
  40. data/ansr_dpla/lib/ansr_dpla/arel/big_table.rb +4 -0
  41. data/ansr_dpla/lib/ansr_dpla/arel/visitors.rb +6 -0
  42. data/ansr_dpla/lib/ansr_dpla/arel/visitors/query_builder.rb +188 -0
  43. data/ansr_dpla/lib/ansr_dpla/arel/visitors/to_no_sql.rb +9 -0
  44. data/ansr_dpla/lib/ansr_dpla/connection_adapters/no_sql_adapter.rb +58 -0
  45. data/ansr_dpla/lib/ansr_dpla/model/base.rb +7 -0
  46. data/ansr_dpla/lib/ansr_dpla/model/querying.rb +6 -10
  47. data/ansr_dpla/lib/ansr_dpla/relation.rb +61 -0
  48. data/ansr_dpla/lib/ansr_dpla/request.rb +5 -0
  49. data/ansr_dpla/spec/lib/api_spec.rb +8 -5
  50. data/ansr_dpla/spec/lib/item_spec.rb +2 -2
  51. data/ansr_dpla/spec/lib/relation/facet_spec.rb +27 -19
  52. data/ansr_dpla/spec/lib/relation/select_spec.rb +10 -8
  53. data/ansr_dpla/spec/lib/relation/where_spec.rb +1 -1
  54. data/ansr_dpla/spec/lib/relation_spec.rb +31 -29
  55. data/ansr_dpla/test/system.rb +4 -2
  56. data/lib/ansr.rb +7 -0
  57. data/lib/ansr/arel.rb +3 -0
  58. data/lib/ansr/arel/big_table.rb +43 -3
  59. data/lib/ansr/arel/configured_field.rb +19 -0
  60. data/lib/ansr/arel/nodes.rb +41 -0
  61. data/lib/ansr/arel/visitors.rb +7 -0
  62. data/lib/ansr/arel/visitors/context.rb +13 -0
  63. data/lib/ansr/arel/visitors/query_builder.rb +47 -0
  64. data/lib/ansr/arel/visitors/to_no_sql.rb +41 -0
  65. data/lib/ansr/base.rb +29 -1
  66. data/lib/ansr/configurable.rb +6 -12
  67. data/lib/ansr/connection_adapters.rb +5 -0
  68. data/lib/ansr/connection_adapters/no_sql_adapter.rb +80 -0
  69. data/lib/ansr/dummy_associations.rb +105 -0
  70. data/lib/ansr/facets.rb +103 -0
  71. data/lib/ansr/model.rb +17 -107
  72. data/lib/ansr/model/connection_handler.rb +6 -0
  73. data/lib/ansr/relation.rb +40 -23
  74. data/lib/ansr/relation/group.rb +31 -0
  75. data/lib/ansr/relation/predicate_builder.rb +106 -0
  76. data/lib/ansr/relation/query_methods.rb +192 -45
  77. data/lib/ansr/sanitization.rb +5 -18
  78. data/lib/ansr/utils.rb +89 -0
  79. data/lib/ansr/version.rb +1 -1
  80. metadata +73 -25
  81. data/ansr_dpla/lib/ansr_dpla/arel/connection.rb +0 -81
  82. data/ansr_dpla/lib/ansr_dpla/arel/query_builder.rb +0 -131
  83. data/lib/ansr/model/connection.rb +0 -103
@@ -0,0 +1,6 @@
1
+ module Ansr::Dpla::Arel
2
+ module Visitors
3
+ require 'ansr_dpla/arel/visitors/query_builder'
4
+ require 'ansr_dpla/arel/visitors/to_no_sql'
5
+ end
6
+ end
@@ -0,0 +1,188 @@
1
+ module Ansr::Dpla::Arel::Visitors
2
+ class QueryBuilder < Ansr::Arel::Visitors::QueryBuilder
3
+ attr_reader :query_opts
4
+
5
+ def initialize(table, query_opts=nil)
6
+ super(table)
7
+ @query_opts = query_opts ||= Ansr::Dpla::Request.new
8
+ @query_opts.path = table.name
9
+ end
10
+
11
+ # determines whether multiple values should accumulate or overwrite in merges
12
+ def multiple?(field_key)
13
+ true
14
+ end
15
+
16
+ def visit_String o, a
17
+ case a
18
+ when Ansr::Arel::Visitors::From
19
+ query_opts.path = o
20
+ when Ansr::Arel::Visitors::Facet
21
+ filter_field(o.to_sym)
22
+ when Ansr::Arel::Visitors::Order
23
+ order(o)
24
+ else
25
+ raise "visited String \"#{o}\" with #{a.to_s}"
26
+ end
27
+ end
28
+
29
+ def visit_Arel_SqlLiteral(n, attribute)
30
+ select_val = n.to_s.split(" AS ")
31
+ case attribute
32
+ when Ansr::Arel::Visitors::Order
33
+ order(n.to_s)
34
+ when Ansr::Arel::Visitors::Facet
35
+ filter_field(select_val[0].to_sym)
36
+ else
37
+ field(select_val[0].to_sym)
38
+ if select_val[1]
39
+ query_opts.aliases ||= {}
40
+ query_opts.aliases[select_val[0]] = select_val[1]
41
+ end
42
+ end
43
+ end
44
+
45
+ def visit_Ansr_Arel_Nodes_Filter(object, attribute)
46
+ expr = object.expr
47
+ case expr
48
+ when ::Arel::SqlLiteral
49
+ visit expr, Ansr::Arel::Visitors::Filter.new(attribute) if object.select
50
+ when ::Arel::Attributes::Attribute
51
+ name = object.expr.name
52
+ name = "#{expr.relation.name}.#{name}" if expr.relation.name.to_s != table.name.to_s
53
+ visit name, Ansr::Arel::Visitors::Filter.new(attribute) if object.select
54
+ else
55
+ raise "Unexpected filter expression type #{object.expr.class}"
56
+ end
57
+ end
58
+
59
+ def visit_Ansr_Arel_Nodes_Facet(object, attribute)
60
+ expr = object.expr
61
+ case expr
62
+ when ::Arel::SqlLiteral
63
+ visit expr, Ansr::Arel::Visitors::Facet.new(attribute)
64
+ when ::Arel::Attributes::Attribute
65
+ name = object.expr.name
66
+ name = "#{expr.relation.name}.#{name}" if expr.relation.name.to_s != table.name.to_s
67
+ visit name, Ansr::Arel::Visitors::Facet.new(attribute) if object.select
68
+ else
69
+ raise "Unexpected filter expression type #{object.expr.class}"
70
+ end
71
+ end
72
+
73
+ def projections
74
+ query_opts[:fields] || []
75
+ end
76
+
77
+ def filter_projections
78
+ query_opts[:facets] || []
79
+ end
80
+
81
+
82
+ def field(field_name)
83
+ return unless field_name
84
+ old = query_opts[:fields] ? Array(query_opts[:fields]) : []
85
+ field_names = (old + Array(field_name)).uniq
86
+ if field_names[0]
87
+ query_opts[:fields] = field_names[1] ? field_names : field_names[0]
88
+ end
89
+ end
90
+
91
+ def filter_field(field_name)
92
+ return unless field_name
93
+ field_name = Array(field_name)
94
+ field_name.each {|fn| raise "#{fn} is not a facetable field" unless table.facets.include? fn.to_sym}
95
+ old = query_opts[:facets] ? Array(query_opts[:facets]) : []
96
+ field_names = (old + Array(field_name)).uniq
97
+ if field_names[0]
98
+ query_opts[:facets] = field_names[1] ? field_names : field_names[0]
99
+ end
100
+ end
101
+
102
+ def add_where_clause(attr_node, val)
103
+ field_key = field_key_from_node(attr_node)
104
+ if query_opts[field_key]
105
+ query_opts[field_key] = Array(query_opts[field_key]) << val
106
+ else
107
+ query_opts[field_key] = val
108
+ end
109
+ end
110
+
111
+ # the DPLA API makes no distinction between filter and normal queries
112
+ def visit_Arel_Nodes_Equality(object, attribute)
113
+ add_where_clause(object.left, object.right)
114
+ end
115
+
116
+ def visit_Arel_Nodes_NotEqual(object, attribute)
117
+ add_where_clause(object.left, "NOT " + object.right)
118
+ end
119
+ def visit_Arel_Nodes_Or(object, attribute)
120
+ add_where_clause(object.left, "OR " + object.right)
121
+ end
122
+
123
+ def visit_Arel_Nodes_Grouping(object, attribute)
124
+ visit object.expr, attribute
125
+ end
126
+
127
+ def visit_Arel_Nodes_Ordering(object, attribute)
128
+ if query_opts[:sort_by]
129
+ query_opts[:sort_by] = Array[query_opts[:sort_by]] << object.expr.name
130
+ else
131
+ query_opts[:sort_by] = object.expr.name
132
+ end
133
+ direction = :asc if (::Arel::Nodes::Ascending === object and direction)
134
+ direction = :desc if (::Arel::Nodes::Descending === object)
135
+ query_opts[:sort_order] = direction if direction
136
+ end
137
+
138
+ def order(*arel_nodes)
139
+ direction = nil
140
+ nodes = []
141
+ arel_nodes.inject(nodes) do |c, n|
142
+ if ::Arel::Nodes::Ordering === n
143
+ c << n
144
+ elsif n.is_a? String
145
+ _ns = n.split(',')
146
+ _ns.each do |_n|
147
+ _p = _n.split(/\s+/)
148
+ if (_p[1])
149
+ _p[1] = _p[1].downcase.to_sym
150
+ else
151
+ _p[1] = :asc
152
+ end
153
+ c << table[_p[0].to_sym].send(_p[1])
154
+ end
155
+ end
156
+ c
157
+ end
158
+ nodes.each do |node|
159
+ if ::Arel::Nodes::Ordering === node
160
+ if query_opts[:sort_by]
161
+ query_opts[:sort_by] = Array[query_opts[:sort_by]] << node.expr.name
162
+ else
163
+ query_opts[:sort_by] = node.expr.name
164
+ end
165
+ direction = :asc if (::Arel::Nodes::Ascending === node and direction)
166
+ direction = :desc if (::Arel::Nodes::Descending === node)
167
+ end
168
+ end
169
+ query_opts[:sort_order] = direction if direction
170
+ end
171
+
172
+ def visit_Arel_Nodes_Limit(object, attribute)
173
+ value = object.expr
174
+ if value and (value = value.to_i)
175
+ raise "Page size cannot be > 500 (#{value}" if value > 500
176
+ query_opts[:page_size] = value
177
+ end
178
+ end
179
+
180
+ def visit_Arel_Nodes_Offset(object, attribute)
181
+ value = object.expr
182
+ if value
183
+ query_opts[:page] = (value.to_i / (query_opts[:page_size] || Ansr::Relation::DEFAULT_PAGE_SIZE)) + 1
184
+ end
185
+ end
186
+
187
+ end
188
+ end
@@ -0,0 +1,9 @@
1
+ module Ansr::Dpla::Arel::Visitors
2
+ class ToNoSql < Ansr::Arel::Visitors::ToNoSql
3
+
4
+ def query_builder(opts = nil)
5
+ Ansr::Dpla::Arel::Visitors::QueryBuilder.new(table, opts)
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,58 @@
1
+ module Ansr::Dpla
2
+ module ConnectionAdapters
3
+ class NoSqlAdapter < Ansr::ConnectionAdapters::NoSqlAdapter
4
+
5
+ def self.connection_for(klass)
6
+ klass.api
7
+ end
8
+
9
+ def initialize(klass, logger = nil, pool = nil) #:nodoc:
10
+ super(klass, klass.api, logger, pool)
11
+ @visitor = Ansr::Dpla::Arel::Visitors::ToNoSql.new(@table)
12
+ end
13
+
14
+ def to_sql(*args)
15
+ to_nosql(*args)
16
+ end
17
+
18
+ def execute(query, name='ANSR-DPLA')
19
+ method = query.path
20
+ query = query.to_h if Ansr::Dpla::Request === query
21
+ query = query.dup
22
+ aliases = query.delete(:aliases)
23
+ json = @connection.send(method, query)
24
+ json = json.length > 0 ? JSON.load(json) : {'docs' => [], 'facets' => []}
25
+ if json['docs'] and aliases
26
+ json['docs'].each do |doc|
27
+ aliases.each do |k,v|
28
+ if doc[k]
29
+ old = doc.delete(k)
30
+ if old and doc[v]
31
+ doc[v] = Array(doc[v]) if doc[v]
32
+ Array(old).each {|ov| doc[v] << ov}
33
+ else
34
+ doc[v] = old
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ json
41
+ end
42
+
43
+ def table_exists?(table_name)
44
+ ['Collection', 'Item'].include? table_name
45
+ end
46
+
47
+ def sanitize_limit(limit_value)
48
+ if (0..500) === limit_value.to_s.to_i
49
+ limit_value
50
+ else
51
+ Ansr::Relation::DEFAULT_PAGE_SIZE
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+
58
+ end
@@ -6,6 +6,13 @@ module Ansr::Dpla
6
6
 
7
7
  include Querying
8
8
 
9
+ def self.inherited(subclass)
10
+ super(subclass)
11
+ subclass.configure do |config|
12
+ config[:table_class] = Ansr::Dpla::Arel::BigTable
13
+ end
14
+ end
15
+
9
16
  def assign_nested_parameter_attributes(pairs)
10
17
  pairs.each do |k, v|
11
18
  v = PseudoAssociate.new(v) if Hash === v
@@ -5,10 +5,14 @@ module Ansr::Dpla
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
+ def build_default_scope
9
+ Ansr::Dpla::Relation.new(model(), table())
10
+ end
11
+
8
12
  def api
9
13
  @api ||= begin
10
14
  a = (config[:api] || Ansr::Dpla::Api).new
11
- a.config(self.config)
15
+ a.config{|x| x.merge!(self.config)}
12
16
  a
13
17
  end
14
18
  end
@@ -17,16 +21,8 @@ module Ansr::Dpla
17
21
  @api = api
18
22
  end
19
23
 
20
- def table
21
- @big_table ||= Ansr::Dpla::Arel::BigTable.new(model(), {:config => config()})
22
- end
23
-
24
- def table=(val)
25
- @big_table = val
26
- end
27
-
28
24
  def connection_handler
29
- @connection_handler ||= Ansr::Model::ConnectionHandler.new(Ansr::Dpla::Arel::Connection)
25
+ @connection_handler ||= Ansr::Model::ConnectionHandler.new(Ansr::Dpla::ConnectionAdapters::NoSqlAdapter)
30
26
  end
31
27
 
32
28
  def references
@@ -0,0 +1,61 @@
1
+ require 'yaml'
2
+ require 'blacklight'
3
+ module Ansr::Dpla
4
+ class Relation < ::Ansr::Relation
5
+
6
+ def initialize(klass, table, values = {})
7
+ raise "Cannot search nil model" if klass.nil?
8
+ super(klass, table, values)
9
+ end
10
+
11
+ def facet_values=(values)
12
+ values.each {|value| raise "#{value.expr.name.to_sym} is not facetable" unless table.facets.include? value.expr.name.to_sym}
13
+ super
14
+ end
15
+
16
+ def empty?
17
+ count == 0
18
+ end
19
+
20
+ def many?
21
+ count > 1
22
+ end
23
+
24
+ def offset!(value)
25
+ page_size = self.limit_value || default_limit_value
26
+ if (value.to_i % page_size.to_i) != 0
27
+ raise "Bad offset #{value} for page size #{page_size}"
28
+ end
29
+ self.offset_value=value
30
+ self
31
+ end
32
+
33
+ def count
34
+ self.load
35
+ @response['count']
36
+ end
37
+
38
+ def filters_from(response)
39
+ f = {}
40
+ (response['facets'] || {}).inject(f) do |h,(k,v)|
41
+
42
+ if v['total'] != 0
43
+ items = v['terms'].collect do |term|
44
+ Blacklight::SolrResponse::Facets::FacetItem.new(:value => term['term'], :hits => term['count'])
45
+ end
46
+ options = {:sort => 'asc', :offset => 0}
47
+ h[k] = Blacklight::SolrResponse::Facets::FacetField.new k, items, options
48
+ end
49
+ h
50
+ end
51
+ f
52
+ end
53
+
54
+ def docs_from(response)
55
+ response['docs']
56
+ end
57
+
58
+ end
59
+
60
+
61
+ end
@@ -0,0 +1,5 @@
1
+ module Ansr::Dpla
2
+ class Request < ::Ansr::OpenStructWithHashAccess
3
+ attr_accessor :path
4
+ end
5
+ end
@@ -9,18 +9,21 @@ describe Ansr::Dpla::Api do
9
9
 
10
10
  it "should be configurable with a Hash" do
11
11
  config_fixture = {:api_key => :foo, :url => :bar}
12
- @test.config(config_fixture)
12
+ @test.config{|x| x.merge!(config_fixture)}
13
13
  expect(@test.url).to eql(:bar)
14
14
  end
15
15
 
16
16
  it "should be configurable with a path to a yaml" do
17
- @test.config(fixture_path('dpla.yml'))
17
+ open(fixture_path('dpla.yml')) do |blob|
18
+ config = YAML.load(blob)
19
+ @test.config{|x| x.merge!(config)}
20
+ end
18
21
  expect(@test.url).to eql('http://fake.dp.la/v0/')
19
22
  end
20
23
 
21
24
  it "should raise an error of the config doesn't have required fields" do
22
- expect { Ansr::Dpla::Api.new.config({:url => :foo})}.to raise_error
23
- Ansr::Dpla::Api.new.config({:url => :foo, :api_key => :foo})
25
+ expect { Ansr::Dpla::Api.new.config{|x| x.merge!(:url => :foo)}}.to raise_error
26
+ Ansr::Dpla::Api.new.config {|x| x.merge!({:url => :foo, :api_key => :foo})}
24
27
  end
25
28
 
26
29
  end
@@ -28,7 +31,7 @@ describe Ansr::Dpla::Api do
28
31
  describe '#path_for' do
29
32
  before do
30
33
  @test = Ansr::Dpla::Api.new
31
- @test.config({:api_key => :testing})
34
+ @test.config{|x| x.merge!(:api_key => :testing)}
32
35
  end
33
36
 
34
37
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Item do
4
4
  describe '.configure' do
5
5
  it "should store the configured Api class" do
6
- Item.configure({:api=>Ansr::Dpla::TestApi, :api_key => :dummy})
6
+ Item.configure {|x| x.merge!(:api=>Ansr::Dpla::TestApi, :api_key => :dummy)}
7
7
  expect(Item.api).to be_a Ansr::Dpla::TestApi
8
8
  end
9
9
  end
@@ -25,7 +25,7 @@ describe Item do
25
25
 
26
26
  describe '.where' do
27
27
  before do
28
- Item.configure({:api=>Ansr::Dpla::TestApi, :api_key => :dummy})
28
+ Item.configure{|x| x.merge!({:api=>Ansr::Dpla::TestApi, :api_key => :dummy})}
29
29
  end
30
30
  it 'should return a Relation when there is query information' do
31
31
  expect(Item.where({:q=>'kittens'})).to be_a Ansr::Relation
@@ -1,47 +1,55 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Ansr::Relation do
3
+ describe Ansr::Dpla::Relation do
4
4
  before do
5
5
  @kittens = read_fixture('kittens.jsonld')
6
6
  @faceted = read_fixture('kittens_faceted.jsonld')
7
7
  @empty = read_fixture('empty.jsonld')
8
8
  @mock_api = double('api')
9
- Item.config({:api_key => :foo})
9
+ Item.config{ |x| x[:api_key] = :foo}
10
10
  Item.engine.api= @mock_api
11
11
  end
12
+
13
+ subject { Ansr::Dpla::Relation.new(Item, Item.table) }
12
14
  describe '#filter' do
13
- it "do a single field, single value filter" do
14
- test = Ansr::Relation.new(Item, Item.table).filter(:object=>'kittens')
15
- @mock_api.should_receive(:items).with(:object => 'kittens', :facets => :object).and_return('')
16
- test.load
15
+ describe "do a single field, single value filter" do
16
+ it "with facet" do
17
+ test = subject.filter(:object=>'kittens').facet(:object)
18
+ @mock_api.should_receive(:items).with(:object => 'kittens', :facets => :object).and_return('')
19
+ test.load
20
+ end
21
+ it "without facet" do
22
+ test = subject.filter(:object=>'kittens')
23
+ @mock_api.should_receive(:items).with(:object => 'kittens').and_return('')
24
+ test.load
25
+ end
17
26
  end
18
27
  it "do a single field, multiple value filter" do
19
- test = Ansr::Relation.new(Item, Item.table).filter(:object=>['kittens', 'cats'])
28
+ test = subject.filter(:object=>['kittens', 'cats']).facet(:object)
20
29
  @mock_api.should_receive(:items).with(:object => ['kittens','cats'], :facets => :object).and_return('')
21
30
  test.load
22
31
  end
23
32
  it "do merge single field, multiple value filters" do
24
- test = Ansr::Relation.new(Item, Item.table).filter(:"provider.name"=>'kittens').filter(:"provider.name"=>'cats')
25
- @mock_api.should_receive(:items).with(:"provider.name" => ['kittens','cats'], :facets => :"provider.name").and_return('')
33
+ test = subject.filter(:"provider.name"=>'kittens').filter(:"provider.name"=>'cats').facet(:"provider.name")
34
+ @mock_api.should_receive(:items).with(hash_including(:"provider.name" => ['kittens','cats'], :facets => :"provider.name")).and_return('')
26
35
  test.load
27
36
  end
28
37
  it "do a multiple field, single value filter" do
29
- test = Ansr::Relation.new(Item, Item.table).filter(:object=>'kittens',:isShownAt=>'bears')
30
- @mock_api.should_receive(:items).with(:object => 'kittens', :isShownAt=>'bears', :facets => [:object, :isShownAt]).and_return('')
38
+ test = subject.filter(:object=>'kittens',:isShownAt=>'bears').facet([:object, :isShownAt])
39
+ @mock_api.should_receive(:items).with(hash_including(:object => 'kittens', :isShownAt=>'bears', :facets => [:object, :isShownAt])).and_return('')
31
40
  test.load
32
41
  end
33
42
  it "should keep scope distinct from spawned Relations" do
34
- test = Ansr::Relation.new(Item, Item.table).filter(:"provider.name"=>'kittens')
43
+ test = subject.filter(:"provider.name"=>'kittens').facet(:"provider.name")
35
44
  test.where(:q=>'cats')
36
45
  @mock_api.should_receive(:items).with(:"provider.name" => 'kittens', :facets => :"provider.name").and_return('')
37
46
  test.load
38
47
  end
39
- it "should raise an error if the requested field is not a filtered field" do
40
- test = Ansr::Relation.new(Item, Item.table)
41
- expect {test.filter(:foo=>'kittens')}.to raise_error
48
+ it "should raise an error if the requested field is not a facetable field" do
49
+ expect {subject.facet(:foo)}.to raise_error
42
50
  end
43
- it "should not require a search value for the filter" do
44
- test = Ansr::Relation.new(Item, Item.table).filter(:object)
51
+ it "should facet without a filter" do
52
+ test = subject.facet(:object)
45
53
  @mock_api.should_receive(:items).with(:facets => :object).and_return('')
46
54
  test.load
47
55
  end
@@ -52,7 +60,7 @@ describe Ansr::Relation do
52
60
  # Blacklight::SolrResponse::Facets::FacetItem.new(:value => s, :hits => v)
53
61
  # options = {:sort => 'asc', :offset => 0}
54
62
  # Blacklight::SolrResponse::Facets::FacetField.new name, items, options
55
- test = Ansr::Relation.new(Item, Item.table).where(:q=>'kittens')
63
+ test = subject.where(:q=>'kittens')
56
64
  @mock_api.should_receive(:items).with(:q => 'kittens').and_return(@faceted)
57
65
  test.load
58
66
  fkey = test.filters.keys.first
@@ -61,7 +69,7 @@ describe Ansr::Relation do
61
69
  facet.items
62
70
  end
63
71
  it 'should dispatch a query with no docs requested if not loaded' do
64
- test = Ansr::Relation.new(Item, Item.table).where(:q=>'kittens')
72
+ test = subject.where(:q=>'kittens')
65
73
  @mock_api.should_receive(:items).with(:q => 'kittens', :page_size=>0).once.and_return(@faceted)
66
74
  fkey = test.filters.keys.first
67
75
  facet = test.filters[fkey]