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.
- checksums.yaml +15 -0
- data/README.md +35 -0
- data/ansr.gemspec +2 -1
- data/ansr_blacklight/Gemfile +3 -0
- data/ansr_blacklight/README.md +37 -0
- data/ansr_blacklight/ansr_blacklight.gemspec +28 -0
- data/ansr_blacklight/lib/ansr_blacklight.rb +57 -0
- data/ansr_blacklight/lib/ansr_blacklight/arel.rb +6 -0
- data/ansr_blacklight/lib/ansr_blacklight/arel/big_table.rb +57 -0
- data/ansr_blacklight/lib/ansr_blacklight/arel/visitors.rb +6 -0
- data/ansr_blacklight/lib/ansr_blacklight/arel/visitors/query_builder.rb +217 -0
- data/ansr_blacklight/lib/ansr_blacklight/arel/visitors/to_no_sql.rb +14 -0
- data/ansr_blacklight/lib/ansr_blacklight/base.rb +21 -0
- data/ansr_blacklight/lib/ansr_blacklight/connection_adapters/no_sql_adapter.rb +38 -0
- data/ansr_blacklight/lib/ansr_blacklight/model/querying.rb +29 -0
- data/ansr_blacklight/lib/ansr_blacklight/relation.rb +50 -0
- data/ansr_blacklight/lib/ansr_blacklight/relation/solr_projection_methods.rb +55 -0
- data/ansr_blacklight/lib/ansr_blacklight/request_builders.rb +141 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr.rb +4 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/request.rb +46 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/response.rb +94 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/response/group.rb +32 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/response/group_response.rb +50 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/response/more_like_this.rb +14 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/response/pagination_methods.rb +35 -0
- data/ansr_blacklight/lib/ansr_blacklight/solr/response/spelling.rb +92 -0
- data/ansr_blacklight/spec/fixtures/config.yml +0 -0
- data/ansr_blacklight/spec/lib/loaded_relation_spec.rb +223 -0
- data/ansr_blacklight/spec/lib/queryable_relation_spec.rb +133 -0
- data/ansr_blacklight/spec/lib/relation/faceting_spec.rb +475 -0
- data/ansr_blacklight/spec/lib/relation/grouping_spec.rb +159 -0
- data/ansr_blacklight/spec/spec_helper.rb +72 -0
- data/ansr_dpla/Gemfile +3 -0
- data/ansr_dpla/Gemfile.lock +138 -0
- data/ansr_dpla/README.md +2 -2
- data/ansr_dpla/ansr_dpla.gemspec +2 -2
- data/ansr_dpla/lib/ansr_dpla.rb +3 -0
- data/ansr_dpla/lib/ansr_dpla/api.rb +3 -3
- data/ansr_dpla/lib/ansr_dpla/arel.rb +1 -2
- data/ansr_dpla/lib/ansr_dpla/arel/big_table.rb +4 -0
- data/ansr_dpla/lib/ansr_dpla/arel/visitors.rb +6 -0
- data/ansr_dpla/lib/ansr_dpla/arel/visitors/query_builder.rb +188 -0
- data/ansr_dpla/lib/ansr_dpla/arel/visitors/to_no_sql.rb +9 -0
- data/ansr_dpla/lib/ansr_dpla/connection_adapters/no_sql_adapter.rb +58 -0
- data/ansr_dpla/lib/ansr_dpla/model/base.rb +7 -0
- data/ansr_dpla/lib/ansr_dpla/model/querying.rb +6 -10
- data/ansr_dpla/lib/ansr_dpla/relation.rb +61 -0
- data/ansr_dpla/lib/ansr_dpla/request.rb +5 -0
- data/ansr_dpla/spec/lib/api_spec.rb +8 -5
- data/ansr_dpla/spec/lib/item_spec.rb +2 -2
- data/ansr_dpla/spec/lib/relation/facet_spec.rb +27 -19
- data/ansr_dpla/spec/lib/relation/select_spec.rb +10 -8
- data/ansr_dpla/spec/lib/relation/where_spec.rb +1 -1
- data/ansr_dpla/spec/lib/relation_spec.rb +31 -29
- data/ansr_dpla/test/system.rb +4 -2
- data/lib/ansr.rb +7 -0
- data/lib/ansr/arel.rb +3 -0
- data/lib/ansr/arel/big_table.rb +43 -3
- data/lib/ansr/arel/configured_field.rb +19 -0
- data/lib/ansr/arel/nodes.rb +41 -0
- data/lib/ansr/arel/visitors.rb +7 -0
- data/lib/ansr/arel/visitors/context.rb +13 -0
- data/lib/ansr/arel/visitors/query_builder.rb +47 -0
- data/lib/ansr/arel/visitors/to_no_sql.rb +41 -0
- data/lib/ansr/base.rb +29 -1
- data/lib/ansr/configurable.rb +6 -12
- data/lib/ansr/connection_adapters.rb +5 -0
- data/lib/ansr/connection_adapters/no_sql_adapter.rb +80 -0
- data/lib/ansr/dummy_associations.rb +105 -0
- data/lib/ansr/facets.rb +103 -0
- data/lib/ansr/model.rb +17 -107
- data/lib/ansr/model/connection_handler.rb +6 -0
- data/lib/ansr/relation.rb +40 -23
- data/lib/ansr/relation/group.rb +31 -0
- data/lib/ansr/relation/predicate_builder.rb +106 -0
- data/lib/ansr/relation/query_methods.rb +192 -45
- data/lib/ansr/sanitization.rb +5 -18
- data/lib/ansr/utils.rb +89 -0
- data/lib/ansr/version.rb +1 -1
- metadata +73 -25
- data/ansr_dpla/lib/ansr_dpla/arel/connection.rb +0 -81
- data/ansr_dpla/lib/ansr_dpla/arel/query_builder.rb +0 -131
- data/lib/ansr/model/connection.rb +0 -103
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Ansr::Arel::Visitors
|
|
2
|
+
class Context
|
|
3
|
+
attr_reader :attribute
|
|
4
|
+
def initialize(attribute)
|
|
5
|
+
@attribute = attribute
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# create some thin subclasses in this module
|
|
10
|
+
%W(Facet Filter From Order).each do |name|
|
|
11
|
+
const_set(name, Class.new(Context))
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Ansr::Arel::Visitors
|
|
2
|
+
class QueryBuilder < Arel::Visitors::Visitor
|
|
3
|
+
attr_reader :table
|
|
4
|
+
def initialize(table)
|
|
5
|
+
@table = table
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def visit(object, attribute=nil)
|
|
9
|
+
super(object, attribute)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def visit_Ansr_Arel_BigTable(object, attribute)
|
|
13
|
+
visit object.name, attribute if Ansr::Arel::Visitors::From === attribute
|
|
14
|
+
@table = object if Ansr::Arel::BigTable === object and Ansr::Arel::Visitors::From === attribute
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def visit_Arel_Nodes_SelectCore(object, attribute)
|
|
18
|
+
visit(object.froms, From.new(attribute)) if object.froms
|
|
19
|
+
object.projections.each { |x| visit(x, attribute) }
|
|
20
|
+
object.wheres.each { |x| visit(x, attribute) }
|
|
21
|
+
object.groups.each {|x| visit(x, attribute) if x}
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def visit_Symbol o, a
|
|
26
|
+
visit o.to_s, a
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def visit_Array o, a
|
|
30
|
+
o.map { |x| visit x, a }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def visit_Arel_Nodes_And(object, attribute)
|
|
34
|
+
visit(object.children, attribute)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def field_key_from_node(node)
|
|
38
|
+
table.model.field_name(node)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# determines whether multiple values should accumulate or overwrite in merges
|
|
42
|
+
def multiple?(field_key)
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Ansr::Arel::Visitors
|
|
2
|
+
class ToNoSql < Arel::Visitors::Visitor
|
|
3
|
+
attr_reader :table
|
|
4
|
+
|
|
5
|
+
def initialize(big_table)
|
|
6
|
+
super()
|
|
7
|
+
@table = big_table
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def query_builder(opts = nil)
|
|
11
|
+
Ansr::Arel::Visitors::QueryBuilder.new(table, opts)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# the object generated by this method will be passed to the NoSqlAdapter#execute
|
|
15
|
+
def visit_Arel_Nodes_SelectStatement(object, attribute)
|
|
16
|
+
builder = query_builder
|
|
17
|
+
|
|
18
|
+
if object.with
|
|
19
|
+
builder.visit(object.with, attribute)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
object.cores.each { |x| builder.visit_Arel_Nodes_SelectCore(x, attribute) }
|
|
23
|
+
|
|
24
|
+
unless object.orders.empty?
|
|
25
|
+
|
|
26
|
+
object.orders.each do |x|
|
|
27
|
+
oa = Ansr::Arel::Visitors::Order.new(attribute)
|
|
28
|
+
builder.visit x, oa
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
builder.visit(object.limit, attribute) if object.limit
|
|
33
|
+
builder.visit(object.offset, attribute) if object.offset
|
|
34
|
+
# not relevant
|
|
35
|
+
|
|
36
|
+
builder.query_opts
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
data/lib/ansr/base.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
require 'active_record'
|
|
1
2
|
module Ansr
|
|
2
3
|
class Base < ActiveRecord::Base
|
|
3
|
-
|
|
4
|
+
include Ansr::Model
|
|
4
5
|
extend Ansr::Configurable
|
|
5
6
|
extend Ansr::QueryMethods
|
|
6
7
|
extend Ansr::ArelMethods
|
|
7
8
|
include Ansr::Sanitization
|
|
9
|
+
#TODO remove the dummy associations
|
|
10
|
+
include Ansr::DummyAssociations
|
|
8
11
|
|
|
9
12
|
self.abstract_class = true
|
|
10
13
|
|
|
@@ -13,6 +16,27 @@ module Ansr
|
|
|
13
16
|
@source_doc = doc
|
|
14
17
|
end
|
|
15
18
|
|
|
19
|
+
def core_initialize(attributes = nil, options = {})
|
|
20
|
+
defaults = self.class.column_defaults.dup
|
|
21
|
+
defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
|
|
22
|
+
|
|
23
|
+
@attributes = self.class.initialize_attributes(defaults)
|
|
24
|
+
@column_types_override = nil
|
|
25
|
+
@column_types = self.class.column_types
|
|
26
|
+
|
|
27
|
+
init_internals
|
|
28
|
+
init_changed_attributes
|
|
29
|
+
ensure_proper_type
|
|
30
|
+
populate_with_current_scope_attributes
|
|
31
|
+
|
|
32
|
+
# +options+ argument is only needed to make protected_attributes gem easier to hook.
|
|
33
|
+
# Remove it when we drop support to this gem.
|
|
34
|
+
init_attributes(attributes, options) if attributes
|
|
35
|
+
|
|
36
|
+
yield self if block_given?
|
|
37
|
+
run_callbacks :initialize unless _initialize_callbacks.empty?
|
|
38
|
+
end
|
|
39
|
+
|
|
16
40
|
def filter_source_hash(doc)
|
|
17
41
|
fields = self.class.model().table().fields()
|
|
18
42
|
filtered = doc.select do |k,v|
|
|
@@ -21,6 +45,10 @@ module Ansr
|
|
|
21
45
|
filtered.with_indifferent_access
|
|
22
46
|
end
|
|
23
47
|
|
|
48
|
+
def columns(name=self.name)
|
|
49
|
+
super(name)
|
|
50
|
+
end
|
|
51
|
+
|
|
24
52
|
def [](key)
|
|
25
53
|
@source_doc[key]
|
|
26
54
|
end
|
data/lib/ansr/configurable.rb
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
module Ansr
|
|
2
2
|
module Configurable
|
|
3
|
-
def config
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
else
|
|
10
|
-
yaml
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
y
|
|
14
|
-
end : @config
|
|
3
|
+
def config
|
|
4
|
+
@config ||= {}
|
|
5
|
+
if block_given?
|
|
6
|
+
yield @config
|
|
7
|
+
end
|
|
8
|
+
@config
|
|
15
9
|
end
|
|
16
10
|
|
|
17
11
|
alias_method :configure, :config
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
require 'arel/visitors/bind_visitor'
|
|
3
|
+
module Ansr
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
class NoSqlAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
|
|
6
|
+
attr_reader :table
|
|
7
|
+
def initialize(klass, connection, logger = nil, pool = nil)
|
|
8
|
+
super(connection, logger, pool)
|
|
9
|
+
@table = klass.table
|
|
10
|
+
@visitor = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Converts an arel AST to NOSQL Query
|
|
14
|
+
def to_nosql(arel, binds = [])
|
|
15
|
+
arel = arel.ast if arel.respond_to?(:ast)
|
|
16
|
+
if arel.is_a? ::Arel::Nodes::Node
|
|
17
|
+
binds = binds.dup
|
|
18
|
+
visitor.accept(arel) do
|
|
19
|
+
quote(*binds.shift.reverse)
|
|
20
|
+
end
|
|
21
|
+
else # assume it is already serialized
|
|
22
|
+
arel
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# attr_accessor :visitor is a self.class::BindSubstitution in unprepared contexts
|
|
27
|
+
class BindSubstitution < ::Arel::Visitors::MySQL # :nodoc:
|
|
28
|
+
include ::Arel::Visitors::BindVisitor
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Executes +query+ statement in the context of this connection using
|
|
32
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
|
33
|
+
# the executed +query+ statement.
|
|
34
|
+
def execute(query, name = 'ANSR-NOSQL')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# called back from ::Arel::Table
|
|
38
|
+
def primary_key(table_name)
|
|
39
|
+
'id' # table.primary_key || 'id'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def table_exists?(name)
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def schema_cache
|
|
47
|
+
ActiveRecord::ConnectionAdapters::SchemaCache.new(self)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# this is called by the BigTable impl
|
|
51
|
+
# should it be retired in favor of the more domain-appropriate 'fields'? Not usually seen by clients anyway.
|
|
52
|
+
def columns(table_name, *rest)
|
|
53
|
+
@table.fields.map {|s| ::ActiveRecord::ConnectionAdapters::Column.new(s.to_s, nil, String)}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def sanitize_limit(limit_value)
|
|
57
|
+
if limit_value.to_s.to_i >= 0
|
|
58
|
+
limit_value
|
|
59
|
+
else
|
|
60
|
+
Ansr::Relation::DEFAULT_PAGE_SIZE
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def sanitize_filter_name(filter_value)
|
|
65
|
+
if filter_value.is_a? Array
|
|
66
|
+
return filter_value.collect {|x| sanitize_filter_name(x)}.compact
|
|
67
|
+
else
|
|
68
|
+
if @table.facets.include? filter_value.to_sym
|
|
69
|
+
return filter_value
|
|
70
|
+
else
|
|
71
|
+
raise "#{filter_value} is not a filterable field"
|
|
72
|
+
#Rails.logger.warn "Ignoring #{filter_value} (not a filterable field)" if Rails.logger
|
|
73
|
+
#return nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Ansr
|
|
2
|
+
module DummyAssociations
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
module ClassMethods
|
|
5
|
+
def create_reflection(macro, name, scope, options, active_record)
|
|
6
|
+
case macro
|
|
7
|
+
when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many
|
|
8
|
+
klass = options[:through] ? DummyThroughReflection : DummyAssociationReflection
|
|
9
|
+
reflection = klass.new(macro, name, scope, options, active_record)
|
|
10
|
+
when :composed_of
|
|
11
|
+
reflection = DummyAggregateReflection.new(macro, name, scope, options, active_record)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
self.reflections = self.reflections.merge(name => reflection)
|
|
15
|
+
reflection
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns an array of AggregateReflection objects for all the aggregations in the class.
|
|
19
|
+
def reflect_on_all_aggregations
|
|
20
|
+
reflections.values.grep(DummyAggregateReflection)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the AggregateReflection object for the named +aggregation+ (use the symbol).
|
|
24
|
+
#
|
|
25
|
+
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
|
|
26
|
+
#
|
|
27
|
+
def reflect_on_aggregation(aggregation)
|
|
28
|
+
reflection = reflections[aggregation]
|
|
29
|
+
reflection if reflection.is_a?(DummyAggregateReflection)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns an array of DummyAssociationReflection objects for all the
|
|
33
|
+
# associations in the class. If you only want to reflect on a certain
|
|
34
|
+
# association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>,
|
|
35
|
+
# <tt>:belongs_to</tt>) as the first parameter.
|
|
36
|
+
#
|
|
37
|
+
# Example:
|
|
38
|
+
#
|
|
39
|
+
# Account.reflect_on_all_associations # returns an array of all associations
|
|
40
|
+
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
|
41
|
+
#
|
|
42
|
+
def reflect_on_all_associations(macro = nil)
|
|
43
|
+
association_reflections = reflections.values.grep(DummyAssociationReflection)
|
|
44
|
+
macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns the DummyAssociationReflection object for the +association+ (use the symbol).
|
|
48
|
+
#
|
|
49
|
+
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
|
50
|
+
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
|
51
|
+
#
|
|
52
|
+
def reflect_on_association(association)
|
|
53
|
+
reflection = reflections[association]
|
|
54
|
+
reflection if reflection.is_a?(DummyAssociationReflection)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
|
58
|
+
def reflect_on_all_autosave_associations
|
|
59
|
+
reflections.values.select { |reflection| reflection.options[:autosave] }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
class DummyReflection < ActiveRecord::Reflection::AggregateReflection
|
|
63
|
+
def initialize(macro, name, scope, options, active_record)
|
|
64
|
+
super(macro, name, scope, options, active_record)
|
|
65
|
+
@symbol = name
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def polymorphic?
|
|
69
|
+
false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def foreign_key
|
|
73
|
+
@symbol # ??
|
|
74
|
+
end
|
|
75
|
+
def collection?
|
|
76
|
+
[:has_one, :has_many, :has_and_belongs_to_many].include? macro
|
|
77
|
+
end
|
|
78
|
+
def validate?
|
|
79
|
+
false
|
|
80
|
+
end
|
|
81
|
+
def association_class
|
|
82
|
+
DummyAssociation
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def check_validity!
|
|
86
|
+
true
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
class DummyAssociationReflection < DummyReflection; end
|
|
90
|
+
class DummyAggregateReflection < DummyReflection; end
|
|
91
|
+
class DummyThroughReflection < DummyReflection; end
|
|
92
|
+
class DummyAssociation < ActiveRecord::Associations::Association
|
|
93
|
+
def writer(*args); end
|
|
94
|
+
def reader(*args)
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
def loaded?
|
|
98
|
+
true
|
|
99
|
+
end
|
|
100
|
+
def identifier
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
data/lib/ansr/facets.rb
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'ostruct'
|
|
2
|
+
|
|
3
|
+
module Ansr::Facets
|
|
4
|
+
|
|
5
|
+
# represents a facet value; which is a field value and its hit count
|
|
6
|
+
class FacetItem < OpenStruct
|
|
7
|
+
def initialize *args
|
|
8
|
+
options = args.extract_options!
|
|
9
|
+
|
|
10
|
+
# Backwards-compat method signature
|
|
11
|
+
value = args.shift
|
|
12
|
+
hits = args.shift
|
|
13
|
+
|
|
14
|
+
options[:value] = value if value
|
|
15
|
+
options[:hits] = hits if hits
|
|
16
|
+
|
|
17
|
+
super(options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def label
|
|
21
|
+
super || value
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def as_json(props = nil)
|
|
25
|
+
table.as_json(props)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# represents a facet; which is a field and its values
|
|
30
|
+
class FacetField
|
|
31
|
+
attr_reader :name, :items
|
|
32
|
+
def initialize name, items, options = {}
|
|
33
|
+
@name, @items = name, items
|
|
34
|
+
@options = options
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def limit
|
|
38
|
+
@options[:limit]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def sort
|
|
42
|
+
@options[:sort] || 'index'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def offset
|
|
46
|
+
@options[:offset] || 0
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @response.facets.each do |facet|
|
|
51
|
+
# facet.name
|
|
52
|
+
# facet.items
|
|
53
|
+
# end
|
|
54
|
+
# "caches" the result in the @facets instance var
|
|
55
|
+
def facets
|
|
56
|
+
@facets ||= begin
|
|
57
|
+
facet_fields.map do |(facet_field_name,values_and_hits)|
|
|
58
|
+
items = []
|
|
59
|
+
options = {}
|
|
60
|
+
values_and_hits.each_slice(2) do |k,v|
|
|
61
|
+
items << FacetItem.new(:value => k, :hits => v)
|
|
62
|
+
end
|
|
63
|
+
options[:sort] = (params[:"f.#{facet_field_name}.facet.sort"] || params[:'facet.sort'])
|
|
64
|
+
if params[:"f.#{facet_field_name}.facet.limit"] || params[:"facet.limit"]
|
|
65
|
+
options[:limit] = (params[:"f.#{facet_field_name}.facet.limit"] || params[:"facet.limit"]).to_i
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if params[:"f.#{facet_field_name}.facet.offset"] || params[:'facet.offset']
|
|
69
|
+
options[:offset] = (params[:"f.#{facet_field_name}.facet.offset"] || params[:'facet.offset']).to_i
|
|
70
|
+
end
|
|
71
|
+
FacetField.new(facet_field_name, items, options)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# pass in a facet field name and get back a Facet instance
|
|
77
|
+
def facet_by_field_name(name)
|
|
78
|
+
@facets_by_field_name ||= {}
|
|
79
|
+
@facets_by_field_name[name] ||= (
|
|
80
|
+
facets.detect{|facet|facet.name.to_s == name.to_s}
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def facet_counts
|
|
85
|
+
@facet_counts ||= self['facet_counts'] || {}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns the hash of all the facet_fields (ie: {'instock_b' => ['true', 123, 'false', 20]}
|
|
89
|
+
def facet_fields
|
|
90
|
+
@facet_fields ||= facet_counts['facet_fields'] || {}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Returns all of the facet queries
|
|
94
|
+
def facet_queries
|
|
95
|
+
@facet_queries ||= facet_counts['facet_queries'] || {}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns all of the facet queries
|
|
99
|
+
def facet_pivot
|
|
100
|
+
@facet_pivot ||= facet_counts['facet_pivot'] || {}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end # end Facets
|