ansr 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjdhOTQ4ZmY2ZTY3OTFkM2YwZjQwNDI3MWI4NmEzYTYwMTc3YzkwZg==
5
+ data.tar.gz: !binary |-
6
+ ZDI1ODllMmMxOGMxMjg5MDI3MWEyYjIwZjQ5ODdkYWNhOGZjZTZhOA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MzhhMjYwMTA5YjljZjFhZmU3M2RmOWViNjZkMzg3YzA2ODIxOTRlYzc2M2Yy
10
+ NWUyNDI2NzY1ZTY5YzQ1ZTJhMTNmNzlmOWJjYWM1MzJlYjUyY2RiZjNkNzIx
11
+ ZjVlNzMyZjBlNzBjM2ZjOTNkMmI5NmRkOTZhZGQxNjJiYmI5YzE=
12
+ data.tar.gz: !binary |-
13
+ ZTlhMjE0NjczMjk0NDk1ZThmMzlkMGY0NWYwYzQ1OTU5NWVhMDA2NDY0N2Ux
14
+ YjE1ZGI5NTdiYTRmNGRjZmMyMmNjMzQ2ZWVlYjU4OTllN2FhNTlhYzNhMjk4
15
+ NDc1NjJmYTZhMGM0YTEzOTNkMjRmYmJmZDQzZTcxODQxMmI2Mjg=
@@ -0,0 +1,35 @@
1
+ ansr
2
+ ====
3
+
4
+ ActiveRecord(No-SQL)::Relation + Blacklight
5
+
6
+ Ansr is a library for building ActiveRecord-style models and Relation implementations that query no-SQL data sources.
7
+ Ansr is motivated by a proposed refactoring of Blacklight at Code4Lib 2014.
8
+
9
+ [Blacklight](https://github.com/projectblacklight/blacklight) (BL) defines itself as “an open source Solr user interface discovery platform.” The coupling to Solr is evident in the structure: Solr querying facilities are sprinkled throughout several mixins that are included in BL controllers. This results in a codebase that cannot, as is regularly asked on the mailing lists, be used in front of another document store (eg ElasticSeach). But this is not necessarily the case.
10
+
11
+ BL might be refactored to locate the actual Solr querying machinery behind the core model of BL apps (currently called SolrDocument). Refactoring the codebase this way would realize several benefits:
12
+
13
+ 1. Adherence to the Principle of Least Surprise: The BL document model would behave more like a Rails model backed by RDBMS. When bringing new developers into a BL project, familiarity with the standard patterns of Rails would translate more immediately to the BL context.
14
+
15
+ 2. Flexible abstraction of the document store: Moving the specifics of querying the document store would make the introduction of models interacting with other stores possible. For example, the DPLA REST API exposes some Solr-like concepts, and a proof-of-concept model for an ActiveRecord-like approach to searching them can be seen at (https://github.com/barmintor/ansr/tree/master/ansr_dpla)
16
+
17
+ 3. Clearer testing strategies and ease of console debugging
18
+
19
+ 4. Clarification of BL’s relationship to RSolr as the provider to an analog for ActiveRecord::Relation
20
+
21
+ What would such a refactor require?
22
+
23
+ 1. A definition of the backend requirements of BL beyond a reference to Solr per se: indexed documents with fields, a concept of facets corresponding to the Solr/Lucene definitions, the ability to expose Hash-like representations of results.
24
+
25
+ 2. A relocation of the searching methods from Blacklight::Catalog and Blacklight::SolrHelper into a model generated to include Solr code
26
+
27
+ 3. An accommodation of controller-specific Solr configuration, possibly resolved by having the BL config register Solr parms with the model a la SolrDocument extensions in BL 4
28
+
29
+ 4. An abstraction of the fielded/faceted search parameters to mimic ActiveRecord limits
30
+
31
+ 5. A partner institution capable of producing integration and system testing support for, at minimum, another Lucene-backed document store (ElasticSearch)
32
+
33
+ Since these changes are incompatible with current BL, they are proposed as a principal feature of BL 6.0.
34
+
35
+ An example of the kinds of models to be implemented can be seen in a [DPLA proof of concept](https://github.com/barmintor/ansr/tree/master/ansr_dpla).
@@ -14,7 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.require_paths = ["lib"]
15
15
 
16
16
  spec.add_dependency 'loggable'
17
- spec.add_dependency 'blacklight', '>=5.1.0'
17
+ spec.add_dependency 'arel'
18
+ spec.add_dependency 'activerecord'
18
19
 
19
20
  spec.add_development_dependency("rake")
20
21
  spec.add_development_dependency("bundler", ">= 1.0.14")
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,37 @@
1
+ Ansr::Blacklight
2
+ =================
3
+
4
+ A re-implementation of Blacklight's Solr model with find/search functionality moved behind ActiveRecord::Relation subclasses.
5
+
6
+ QUESTIONS
7
+
8
+ Is a closer conformation to the expectations from ActiveRecord valuable enough to forego use of Sunspot (https://github.com/sunspot/sunspot)?
9
+
10
+ REQUEST REQUIREMENTS
11
+
12
+ Considering the following block from the BL Solr request code:
13
+ SINGULAR_KEYS = %W{ facet fl q qt rows start spellcheck spellcheck.q sort
14
+ per_page wt hl group defType}
15
+ ARRAY_KEYS = %W{facet.field facet.query facet.pivot fq hl.fl }
16
+
17
+ facet : a boolean field indicating the requested presence of facet info in response
18
+ fl : the selected fields
19
+ q : the query (fielding?)
20
+ qt : query type; indicates queryHandler in Solr
21
+ rows : corresponds to limit
22
+ start : corresponds to offset
23
+ spellcheck : boolean?
24
+ spellcheck.q : ?
25
+ sort : ?
26
+ facet.field : the fields for which facet info is requested
27
+ facet.query : ?
28
+ facet.pivot : ?
29
+ fq : ?
30
+ hl.fl : field to highlight
31
+ How is facet query different from filter query (fq)?
32
+
33
+ Relations must be configurable with default parameters; this is fairly easy to do with a template Relation to spawn the default scope from.
34
+
35
+ RESPONSE REQUIREMENTS
36
+
37
+ tbd
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/ansr/version')
2
+ version = Ansr.version
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'ansr_blacklight'
5
+ spec.version = version
6
+ spec.platform = Gem::Platform::RUBY
7
+ spec.authors = ["Benjamin Armintor"]
8
+ spec.email = ["armintor@gmail.com"]
9
+ spec.summary = 'ActiveRecord-style models and relations for Blacklight'
10
+ spec.description = 'Wrapping the Blacklight/RSolr in Rails-like models and relations'
11
+ spec.homepage = 'https://github.com/barmintor/ansr/tree/master/ansr_blacklight'
12
+ spec.files = `git ls-files`.split("\n")
13
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_dependency 'ansr', version
18
+ spec.add_dependency 'json-ld'
19
+ spec.add_dependency 'rest-client'
20
+ spec.add_dependency 'loggable'
21
+ spec.add_dependency "rails", ">= 3.2.6", "< 5"
22
+ # spec.add_dependency 'blacklight', '>=5.1.0'
23
+ spec.add_dependency 'sass-rails'
24
+ spec.add_development_dependency("rake")
25
+ spec.add_development_dependency("bundler", ">= 1.0.14")
26
+ spec.add_development_dependency "rspec-rails"
27
+ spec.add_development_dependency("yard")
28
+ end
@@ -0,0 +1,57 @@
1
+ require 'ansr'
2
+ require 'rsolr'
3
+ module Ansr::Blacklight
4
+ extend ActiveSupport::Autoload
5
+ autoload :SolrProjectionMethods, 'ansr_blacklight/relation/solr_projection_methods'
6
+ require 'ansr_blacklight/solr'
7
+ require 'ansr_blacklight/request_builders'
8
+ require 'ansr_blacklight/arel'
9
+ require 'ansr_blacklight/connection_adapters/no_sql_adapter'
10
+ require 'ansr_blacklight/relation'
11
+ require 'ansr_blacklight/model/querying'
12
+ require 'ansr_blacklight/base'
13
+
14
+ def self.solr_file
15
+ "#{::Rails.root.to_s}/config/solr.yml"
16
+ end
17
+
18
+ def self.solr
19
+ @solr ||= RSolr.connect(Ansr::Blacklight.solr_config)
20
+ end
21
+
22
+ def self.solr_config
23
+ @solr_config ||= begin
24
+ raise "The #{::Rails.env} environment settings were not found in the solr.yml config" unless solr_yml[::Rails.env]
25
+ solr_yml[::Rails.env].symbolize_keys
26
+ end
27
+ end
28
+
29
+ def self.solr_yml
30
+ require 'erb'
31
+ require 'yaml'
32
+
33
+ return @solr_yml if @solr_yml
34
+ unless File.exists?(solr_file)
35
+ raise "You are missing a solr configuration file: #{solr_file}. Have you run \"rails generate blacklight:install\"?"
36
+ end
37
+
38
+ begin
39
+ @solr_erb = ERB.new(IO.read(solr_file)).result(binding)
40
+ rescue Exception => e
41
+ raise("solr.yml was found, but could not be parsed with ERB. \n#{$!.inspect}")
42
+ end
43
+
44
+ begin
45
+ @solr_yml = YAML::load(@solr_erb)
46
+ rescue StandardError => e
47
+ raise("solr.yml was found, but could not be parsed.\n")
48
+ end
49
+
50
+ if @solr_yml.nil? || !@solr_yml.is_a?(Hash)
51
+ raise("solr.yml was found, but was blank or malformed.\n")
52
+ end
53
+
54
+ return @solr_yml
55
+ end
56
+
57
+ end
@@ -0,0 +1,6 @@
1
+ module Ansr::Blacklight
2
+ module Arel
3
+ require 'ansr_blacklight/arel/visitors'
4
+ require 'ansr_blacklight/arel/big_table'
5
+ end
6
+ end
@@ -0,0 +1,57 @@
1
+ module Ansr::Blacklight::Arel
2
+ class BigTable < Ansr::Arel::BigTable
3
+ attr_accessor :name
4
+
5
+ def initialize(klass, engine=nil, config=nil)
6
+ super(klass, engine)
7
+ @name = 'select'
8
+ self.config(config)
9
+ end
10
+
11
+ delegate :index_fields, to: :config
12
+ delegate :show_fields, to: :config
13
+ delegate :sort_fields, to: :config
14
+
15
+ def filterable
16
+ config.facet_fields.keys
17
+ end
18
+
19
+ alias_method :facets, :filterable
20
+
21
+ def filterable?(field)
22
+ filterable.include? field
23
+ end
24
+
25
+ def constrainable
26
+ index_fields.keys
27
+ end
28
+
29
+ def constrainable?(field)
30
+ index_fields.include?(field)
31
+ end
32
+
33
+ def selectable
34
+ show_fields.keys + index_fields.keys
35
+ end
36
+
37
+ def selectable?(field)
38
+ show_fields.include? field
39
+ end
40
+
41
+ def fields
42
+ (constrainable + selectable + filterable).uniq
43
+ end
44
+
45
+ def sortable
46
+ sort_fields.keys
47
+ end
48
+
49
+ def sortable?(field)
50
+ sort_fields.include? field
51
+ end
52
+
53
+ def primary_key
54
+ @primary_key ||= ::Arel::Attribute.new(self, config.document_unique_id_param.to_s)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,6 @@
1
+ module Ansr::Blacklight::Arel
2
+ module Visitors
3
+ require 'ansr_blacklight/arel/visitors/query_builder'
4
+ require 'ansr_blacklight/arel/visitors/to_no_sql'
5
+ end
6
+ end
@@ -0,0 +1,217 @@
1
+ module Ansr::Blacklight::Arel::Visitors
2
+ class QueryBuilder < Ansr::Arel::Visitors::QueryBuilder
3
+ include Ansr::Blacklight::RequestBuilders
4
+ attr_reader :solr_request
5
+
6
+ def initialize(table)
7
+ super(table)
8
+ @solr_request = Ansr::Blacklight::Solr::Request.new
9
+ table.configure_fields.each do |k,v|
10
+ unless v[:select].blank?
11
+ v[:select].each do |sk, sv|
12
+ key = "f.#{k}.#{sk}".to_sym
13
+ @solr_request[key] = sv
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ public
20
+ def query_opts
21
+ solr_request
22
+ end
23
+
24
+ # determines whether multiple values should accumulate or overwrite in merges
25
+ def multiple?(field_key)
26
+ true
27
+ end
28
+
29
+ def visit_String o, a
30
+ case a
31
+ when Ansr::Arel::Visitors::From
32
+ query_opts.path = o
33
+ when Ansr::Arel::Visitors::Filter
34
+ filter_field(o.to_sym)
35
+ when Ansr::Arel::Visitors::Order
36
+ order(o)
37
+ else
38
+ raise "visited String \"#{o}\" with #{a.to_s}"
39
+ end
40
+ end
41
+
42
+
43
+ def visit_Arel_Nodes_TableAlias(object, attribute)
44
+ solr_request[:qt] = object.name.to_s
45
+ opts = {qt: object.name.to_s}
46
+ if (cf = table[object.name]).is_a? Ansr::Arel::ConfiguredField
47
+ opts.merge!(cf.config.fetch(:query,{}))
48
+ end
49
+ solr_request.merge!(opts)
50
+ visit object.relation, attribute
51
+ end
52
+
53
+ def visit_Ansr_Arel_Nodes_ProjectionTraits(object, attribute)
54
+ solr_request[:wt] = object.wt if object.wt
55
+ solr_request[:defType] = object.defType if object.defType
56
+ visit(object.expr, attribute)
57
+ end
58
+
59
+ def visit_Arel_SqlLiteral(n, attribute)
60
+ select_val = n.to_s.split(" AS ")
61
+ if Ansr::Arel::Visitors::Filter === attribute
62
+ solr_request.append_facet_fields(select_val[0].to_sym)
63
+ else
64
+ field(select_val[0].to_sym)
65
+ if select_val[1]
66
+ query_opts.aliases ||= {}
67
+ query_opts.aliases[select_val[0]] = select_val[1]
68
+ end
69
+ end
70
+ end
71
+
72
+ def from(value)
73
+ if value.respond_to? :name
74
+ solr_request.path = value.name
75
+ else
76
+ solr_request.path = value.to_s
77
+ end
78
+ self.table=value if (value.is_a? Ansr::Arel::BigTable)
79
+ end
80
+
81
+ def field(field_name)
82
+ return unless field_name
83
+ old = query_opts[:fields] ? Array(query_opts[:fields]) : []
84
+ field_names = (old + Array(field_name)).uniq
85
+ if field_names[0]
86
+ query_opts[:fields] = field_names[1] ? field_names : field_names[0]
87
+ end
88
+ end
89
+
90
+ def filter_field(field_name)
91
+ return unless field_name
92
+ old = solr_request[:"facet.field"] ? Array(solr_request[:"facet.field"]) : []
93
+ fields = Array(field_name).delete_if {|x| old.include? x}
94
+ solr_request.append_facet_fields(fields)
95
+ end
96
+
97
+ def visit_Arel_Nodes_Equality(object, attribute)
98
+ field_key = (object.left.respond_to? :expr) ? field_key_from_node(object.left.expr) : field_key_from_node(object.left)
99
+ opts = {}
100
+ opts.merge!(local_field_params(field_key))
101
+ opts.merge!(object.left.config.fetch(:local,{})) if object.left.respond_to? :config
102
+ if Ansr::Arel::Visitors::Filter === attribute or Ansr::Arel::Nodes::Filter === object.left
103
+ add_filter_fq_to_solr(solr_request, f: {field_key => object.right}, opts: opts)
104
+ else
105
+ # check the table for configured fields
106
+ add_query_to_solr(field_key, object.right, opts)
107
+ end
108
+ end
109
+
110
+ def visit_Arel_Nodes_NotEqual(object, attribute)
111
+ end
112
+
113
+ def visit_Arel_Nodes_Or(object, attribute)
114
+ end
115
+
116
+ def visit_Arel_Nodes_Grouping(object, attribute)
117
+ visit object.expr, attribute
118
+ end
119
+
120
+ def visit_Arel_Nodes_Group(object, attribute)
121
+ solr_request[:group] = object.expr.to_s
122
+ end
123
+
124
+ def visit_Ansr_Arel_Nodes_Facet(object, attribute)
125
+ name = object.expr
126
+ name = name.name if name.respond_to? :name
127
+ default = false
128
+ if name == ::Arel.star
129
+ prefix = "facet."
130
+ default = true
131
+ else
132
+ filter_field(name.to_sym) unless default
133
+ solr_request.append_facet_fields(name.to_sym) unless default
134
+ prefix = "f.#{name}.facet."
135
+ end
136
+ # there's got to be a helper for this
137
+ if object.pivot
138
+ solr_request.append_facet_pivot with_ex_local_param(object.ex, object.pivot.join(","))
139
+ elsif object.query
140
+ solr_request.append_facet_query object.query.map { |k, x| with_ex_local_param(object.ex, x[:fq]) }
141
+ else
142
+ object.opts.each do |att, value|
143
+ solr_request["#{prefix}#{att.to_s}".to_sym] = value.to_s unless att == :ex
144
+ end
145
+ solr_request.append_facet_fields with_ex_local_param(object.ex, name.to_sym) unless default
146
+ end
147
+ end
148
+
149
+ def visit_Ansr_Arel_Nodes_Spellcheck(object, attribute)
150
+ unless object.expr == false
151
+ solr_request[:spellcheck] = object.expr.to_s
152
+ end
153
+ object.opts.each do |att, val|
154
+ solr_request["spellcheck.#{att.to_s}".to_sym] = val if att != :select
155
+ end
156
+ end
157
+
158
+ def visit_Ansr_Arel_Nodes_Highlight(object, attribute)
159
+ unless object.expr == false or object.expr == true
160
+ solr_request[:hl] = object.expr.to_s
161
+ end
162
+ object.opts.each do |att, val|
163
+ solr_request["hl.#{att.to_s}".to_sym] = val if att != :select
164
+ end
165
+ end
166
+
167
+ def order(*arel_nodes)
168
+ direction = nil
169
+ nodes = []
170
+ arel_nodes.inject(nodes) do |c, n|
171
+ if ::Arel::Nodes::Ordering === n
172
+ c << n
173
+ elsif n.is_a? String
174
+ _ns = n.split(',')
175
+ _ns.each do |_n|
176
+ _p = _n.split(/\s+/)
177
+ if (_p[1])
178
+ _p[1] = _p[1].downcase.to_sym
179
+ else
180
+ _p[1] = :asc
181
+ end
182
+ c << table[_p[0].to_sym].send(_p[1])
183
+ end
184
+ end
185
+ c
186
+ end
187
+ nodes.each do |node|
188
+ if ::Arel::Nodes::Ordering === node
189
+ if solr_request[:sort_by]
190
+ solr_request[:sort_by] = Array[solr_request[:sort_by]] << node.expr.name
191
+ else
192
+ solr_request[:sort_by] = node.expr.name
193
+ end
194
+ direction = :asc if (::Arel::Nodes::Ascending === node and direction)
195
+ direction = :desc if (::Arel::Nodes::Descending === node)
196
+ end
197
+ end
198
+ solr_request[:sort_order] = direction if direction
199
+ end
200
+
201
+ def visit_Arel_Nodes_Limit(object, attribute)
202
+ value = object.expr
203
+ if value and (value = value.to_i)
204
+ raise "Page size cannot be > 500 (#{value}" if value > 500
205
+ solr_request[:rows] = value.to_s
206
+ end
207
+ end
208
+
209
+ def visit_Arel_Nodes_Offset(object, attribute)
210
+ value = object.expr
211
+ if value
212
+ solr_request[:start] = value.to_s
213
+ end
214
+ end
215
+
216
+ end
217
+ end