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,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