elastic_record 0.0.1

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.
data/README.rdoc ADDED
@@ -0,0 +1,23 @@
1
+ Expects that your model implements find(*ids)
2
+
3
+ class Widgets
4
+ include ElasticRecord::Model
5
+ end
6
+
7
+ scope = Widgets.filter(color: 'red').order(:price)
8
+
9
+ scope.count
10
+ scope.first
11
+ scope.last
12
+ scope.all
13
+ scope.each
14
+
15
+ Class methods are executed within scopes:
16
+
17
+ class Widgets
18
+ def self.ouput_to_screen
19
+ all.each do { |widget| puts widget }
20
+ end
21
+ end
22
+
23
+ scope.output_to_screen
@@ -0,0 +1,15 @@
1
+ module ElasticRecord
2
+ autoload :Config, 'elastic_record/config'
3
+ autoload :Connection, 'elastic_record/connection'
4
+
5
+ autoload :Relation, 'elastic_record/relation'
6
+ autoload :Batches, 'elastic_record/relation/batches'
7
+ autoload :Delegation, 'elastic_record/relation/delegation'
8
+ autoload :FinderMethods, 'elastic_record/relation/finder_methods'
9
+ autoload :Merging, 'elastic_record/relation/merging'
10
+ autoload :SearchMethods, 'elastic_record/relation/search_methods'
11
+
12
+ autoload :Searching, 'elastic_record/searching'
13
+
14
+ autoload :Model, 'elastic_record/model'
15
+ end
@@ -0,0 +1,21 @@
1
+ module ElasticRecord
2
+ class Config
3
+ class << self
4
+ def servers=(value)
5
+ @servers = value
6
+ end
7
+
8
+ def servers
9
+ @servers
10
+ end
11
+
12
+ def connection_options
13
+ @connection_options ||= {}
14
+ end
15
+
16
+ def connection_options=(options)
17
+ @connection_options = options
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module ElasticRecord
2
+ module Connection
3
+ def elastic_connection
4
+ ElasticRecord::Config.connection_options
5
+ @elastic_connection ||= ElasticSearch.new(
6
+ ElasticRecord::Config.servers,
7
+ ElasticRecord::Config.connection_options.merge(index: model_name.collection, type: model_name.element)
8
+ )
9
+ end
10
+
11
+ def elastic_connection=(connection)
12
+ @elastic_connection = connection
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module ElasticRecord
2
+ module Model
3
+ def self.included(base)
4
+ base.class_eval do
5
+ extend Connection
6
+ extend Searching
7
+ extend ClassMethods
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def relation
13
+ ElasticRecord::Relation.new(self, arelastic)
14
+ end
15
+
16
+ def arelastic
17
+ @arelastic ||= Arelastic::Builders::Search.new
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module ElasticRecord
2
+ module ActiveRecord
3
+ end
4
+ end
@@ -0,0 +1,61 @@
1
+ # require 'elastic_record/relation/delegation'
2
+ # require 'elastic_record/relation/finder_methods'
3
+ # require 'elastic_record/relation/merging'
4
+ # require 'elastic_record/relation/search_methods'
5
+
6
+ module ElasticRecord
7
+ class Relation
8
+ MULTI_VALUE_METHODS = [:extending, :filter, :facet, :order]
9
+ SINGLE_VALUE_METHODS = [:query, :limit, :offset]
10
+
11
+ include Batches, Delegation, FinderMethods, Merging, SearchMethods
12
+
13
+ attr_reader :klass, :arelastic, :values
14
+
15
+ def initialize(klass, arelastic)
16
+ @klass = klass
17
+ @arelastic = arelastic
18
+ @values = {}
19
+ end
20
+
21
+ def count
22
+ to_hits.total_entries
23
+ end
24
+
25
+ def facets
26
+ to_hits.facets
27
+ end
28
+
29
+ def to_a
30
+ @records ||= klass.find(to_ids)
31
+ end
32
+
33
+ def to_ids
34
+ to_hits.to_a.map(&:id)
35
+ end
36
+
37
+ def to_hits
38
+ @hits ||= klass.elastic_connection.search(as_elastic)#, ids_only: true)
39
+ end
40
+
41
+ def ==(other)
42
+ case other
43
+ when Relation
44
+ other.as_elastic == as_elastic
45
+ when Array
46
+ to_a == other
47
+ end
48
+ end
49
+
50
+ def inspect
51
+ to_a.inspect
52
+ end
53
+
54
+ def scoping
55
+ previous, klass.current_elastic_search = klass.current_elastic_search, self
56
+ yield
57
+ ensure
58
+ klass.current_elastic_search = previous
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,14 @@
1
+ module ElasticRecord
2
+ module Batches
3
+ def find_each
4
+ options = {scroll: '20m', size: 100, search_type: 'scan'}
5
+
6
+ hits = klass.elastic_connection.search(as_elastic, options)
7
+
8
+ klass.elastic_connection.scroll(hits.scroll_id, scroll: options[:scroll], ids_only: true) do |hits|
9
+ records = klass.find(hits.to_a)
10
+ records.each { |record| yield record }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module ElasticRecord
2
+ module Delegation
3
+ def to_ary
4
+ to_a.to_ary
5
+ end
6
+
7
+ private
8
+ def method_missing(method, *args, &block)
9
+ if klass.respond_to?(method)
10
+ scoping { klass.send(method, *args, &block) }
11
+ elsif Array.method_defined?(method)
12
+ to_a.send(method, *args, &block)
13
+ else
14
+ super
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module ElasticRecord
2
+ module FinderMethods
3
+ def find(id)
4
+ filter(arelastic.filter.ids(id)).to_a.first
5
+ end
6
+
7
+ def first
8
+ find_one order('_uid')
9
+ end
10
+
11
+ def last
12
+ find_one order('color' => 'reverse')
13
+ end
14
+
15
+ def all
16
+ to_a
17
+ end
18
+
19
+ private
20
+
21
+ def find_one(relation)
22
+ relation.limit(1).to_a.first
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ module ElasticRecord
2
+ module Merging
3
+ def merge!(other)
4
+ Merger.new(self, other).merge
5
+ end
6
+
7
+ def merge(other)
8
+ clone.merge!(other)
9
+ end
10
+
11
+ private
12
+ class Merger
13
+ attr_accessor :relation, :values
14
+
15
+ def initialize(relation, other)
16
+ @relation = relation
17
+ @values = other.values
18
+ end
19
+
20
+ def normal_values
21
+ Relation::MULTI_VALUE_METHODS + Relation::SINGLE_VALUE_METHODS
22
+ end
23
+
24
+ def merge
25
+ normal_values.each do |name|
26
+ value = values[name]
27
+ relation.send("#{name}!", value) unless value.blank?
28
+ end
29
+
30
+ relation
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,185 @@
1
+ module ElasticRecord
2
+ module SearchMethods
3
+ Relation::MULTI_VALUE_METHODS.each do |name|
4
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
5
+ def #{name}_values # def filter_values
6
+ @values[:#{name}] || [] # @values[:filter] || []
7
+ end # end
8
+ #
9
+ def #{name}_values=(values) # def filter_values=(values)
10
+ @values[:#{name}] = values # @values[:filter] = values
11
+ end # end
12
+ CODE
13
+ end
14
+
15
+ Relation::SINGLE_VALUE_METHODS.each do |name|
16
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
17
+ def #{name}_value # def offset_value
18
+ @values[:#{name}] # @values[:offset]
19
+ end # end
20
+
21
+ def #{name}_value=(value) # def offset_value=(value)
22
+ @values[:#{name}] = value # @values[:offset] = value
23
+ end # end
24
+ CODE
25
+ end
26
+
27
+ def query!(value)
28
+ self.query_value = value
29
+ self
30
+ end
31
+
32
+ def query(value)
33
+ clone.query! value
34
+ end
35
+
36
+ def filter!(*args)
37
+ self.filter_values += args.flatten
38
+ self
39
+ end
40
+
41
+ def filter(*args)
42
+ clone.filter!(*args)
43
+ end
44
+
45
+ def limit!(value)
46
+ self.limit_value = value
47
+ self
48
+ end
49
+
50
+ def limit(value)
51
+ clone.limit!(value)
52
+ end
53
+
54
+ def offset!(value)
55
+ self.offset_value = value
56
+ self
57
+ end
58
+
59
+ def offset(value)
60
+ clone.offset! value
61
+ end
62
+
63
+ def facet!(name_or_facet, options = {})
64
+ if name_or_facet.is_a?(String)
65
+ self.facet_values += [arelastic.facet[name_or_facet].terms(name_or_facet, options)]
66
+ else
67
+ self.facet_values += [name_or_facet]
68
+ end
69
+
70
+ self
71
+ end
72
+
73
+ def facet(facet_or_name, options = {})
74
+ clone.facet! facet_or_name, options = {}
75
+ end
76
+
77
+ def order!(*args)
78
+ self.order_values += args.flatten
79
+ self
80
+ end
81
+
82
+ def order(*args)
83
+ clone.order! *args
84
+ end
85
+
86
+ def extending!(*modules, &block)
87
+ modules << Module.new(&block) if block_given?
88
+
89
+ self.extending_values += modules.flatten
90
+ extend(*extending_values)
91
+
92
+ self
93
+ end
94
+
95
+ def extending(*modules, &block)
96
+ clone.extending!(*modules, &block)
97
+ end
98
+
99
+ def as_elastic
100
+ build_search.as_elastic
101
+ end
102
+
103
+ private
104
+ def build_search
105
+ searches = [
106
+ build_query_and_filter(query_value, filter_values),
107
+ build_limit(limit_value),
108
+ build_offset(offset_value),
109
+ build_facets(facet_values),
110
+ build_orders(order_values)
111
+ ].compact
112
+
113
+ Arelastic::Nodes::HashGroup.new searches
114
+ end
115
+
116
+ def build_query_and_filter(query, filters)
117
+ query = build_query(query)
118
+ filter = build_filter(filters)
119
+ if query && filter
120
+ arelastic.query.filtered(query, filter)
121
+ elsif query
122
+ query
123
+ elsif filter
124
+ arelastic.query.constant_score(filter)
125
+ else
126
+ arelastic.query.match_all
127
+ end
128
+ end
129
+
130
+ def build_query(query)
131
+ if query.is_a?(String)
132
+ query = Arelastic::Queries::QueryString.new query
133
+ end
134
+
135
+ if query
136
+ Arelastic::Searches::Query.new query
137
+ end
138
+ end
139
+
140
+ def build_filter(filters)
141
+ nodes = []
142
+
143
+ filters.map do |filter|
144
+ if filter.is_a?(Arelastic::Filters::Filter)
145
+ nodes << filter
146
+ else
147
+ filter.each do |field, terms|
148
+ case terms
149
+ when Array, Range
150
+ nodes << arelastic[field].in(terms)
151
+ else
152
+ nodes << arelastic[field].eq(terms)
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ if nodes.size == 1
159
+ Arelastic::Searches::Filter.new nodes.first
160
+ elsif nodes.size > 1
161
+ Arelastic::Searches::Filter.new Arelastic::Filters::And.new(nodes)
162
+ end
163
+ end
164
+
165
+ def build_limit(limit)
166
+ if limit
167
+ Arelastic::Searches::Size.new(limit)
168
+ end
169
+ end
170
+
171
+ def build_offset(offset)
172
+ if offset
173
+ Arelastic::Searches::From.new(offset)
174
+ end
175
+ end
176
+
177
+ def build_facets(facets)
178
+ Arelastic::Searches::Facets.new(facets) unless facets.empty?
179
+ end
180
+
181
+ def build_orders(orders)
182
+ Arelastic::Searches::Sort.new(orders) unless orders.empty?
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,30 @@
1
+ module ElasticRecord
2
+ module Searching
3
+ def elastic_search
4
+ if current_elastic_search
5
+ current_elastic_search.clone
6
+ else
7
+ relation
8
+ end
9
+ end
10
+
11
+ def elastic_scope(name, body, &block)
12
+ extension = Module.new(&block) if block
13
+
14
+ singleton_class.send(:define_method, name) do |*args|
15
+ relation = body.call(*args)
16
+ relation = elastic_search.merge(relation)
17
+
18
+ extension ? relation.extending(extension) : relation
19
+ end
20
+ end
21
+
22
+ def current_elastic_search #:nodoc:
23
+ Thread.current["#{self}_current_elastic_search"]
24
+ end
25
+
26
+ def current_elastic_search=(relation) #:nodoc:
27
+ Thread.current["#{self}_current_elastic_search"] = relation
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::ConfigTest < MiniTest::Spec
4
+ end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::ConnectionTest < MiniTest::Spec
4
+ def test_elastic_connection
5
+ connection = Widget.elastic_connection
6
+
7
+ assert_equal 'widget', connection.default_type
8
+ assert_equal 'widgets', connection.default_index
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::ModelTest < MiniTest::Spec
4
+ def test_relation
5
+ relation = Widget.relation
6
+
7
+ assert_equal Widget, relation.klass
8
+ assert_equal Widget.arelastic, relation.arelastic
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::Relation::BatchesTest < MiniTest::Spec
4
+ def setup
5
+ Widget.reset_index!
6
+ create_widgets
7
+ end
8
+
9
+ def test_find_each
10
+ results = []
11
+ Widget.relation.find_each do |widget|
12
+ results << widget.id
13
+ end
14
+ assert_equal ['5', '10', '15'].to_set, results.to_set
15
+ end
16
+
17
+ def test_find_each_with_scope
18
+ results = []
19
+ Widget.relation.filter(color: %w(red blue)).find_each do |widget|
20
+ results << widget.id
21
+ end
22
+ assert_equal ['5', '10'].to_set, results.to_set
23
+ end
24
+
25
+ private
26
+ def create_widgets
27
+ Widget.elastic_connection.index({'widget' => {'color' => 'red'}}, {index: 'widgets', type: 'widget', id: 5})
28
+ Widget.elastic_connection.index({'widget' => {'color' => 'blue'}}, {index: 'widgets', type: 'widget', id: 10})
29
+ Widget.elastic_connection.index({'widget' => {'color' => 'green'}}, {index: 'widgets', type: 'widget', id: 15})
30
+
31
+ Widget.elastic_connection.refresh
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::Relation::DelegationTest < MiniTest::Spec
4
+ def setup
5
+ Widget.reset_index!
6
+ end
7
+
8
+ def test_delegate_to_array
9
+ Widget.elastic_connection.index({'widget' => {'color' => 'red'}}, {index: 'widgets', type: 'widget', id: 5})
10
+ Widget.elastic_connection.refresh
11
+
12
+ records = []
13
+ Widget.relation.each do |record|
14
+ records << record
15
+ end
16
+
17
+ assert_equal 1, records.size
18
+ end
19
+
20
+ def test_delegate_to_klass
21
+ model = Class.new(Widget) do
22
+ def self.do_it
23
+ elastic_search.as_elastic
24
+ end
25
+ end
26
+
27
+ result = model.relation.filter('foo' => 'bar').do_it
28
+
29
+ expected = {"query"=>{"constant_score"=>{"filter"=>{"term"=>{"foo"=>"bar"}}}}}
30
+ assert_equal expected, result
31
+ end
32
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::Relation::FinderMethodsTest < MiniTest::Spec
4
+ def setup
5
+ Widget.reset_index!
6
+ create_widgets
7
+ end
8
+
9
+ def test_find
10
+ refute_nil Widget.relation.find('05')
11
+ refute_nil Widget.relation.filter('color' => 'red').find('05')
12
+ assert_nil Widget.relation.filter('color' => 'blue').find('05')
13
+ end
14
+
15
+ def test_first
16
+ assert_equal '05', Widget.relation.first.id
17
+ assert_equal '05', Widget.relation.filter('color' => 'red').first.id
18
+ assert_equal '10', Widget.relation.filter('color' => 'blue').first.id
19
+ assert_nil Widget.relation.filter('color' => 'green').first
20
+ end
21
+
22
+ def test_last
23
+ assert_equal '10', Widget.relation.last.id
24
+ assert_equal '05', Widget.relation.filter('color' => 'red').last.id
25
+ assert_equal '10', Widget.relation.filter('color' => 'blue').last.id
26
+ assert_nil Widget.relation.filter('color' => 'green').last
27
+ end
28
+
29
+ def test_all
30
+ assert_equal 2, Widget.relation.all.size
31
+ assert_equal 1, Widget.relation.filter('color' => 'red').all.size
32
+ end
33
+
34
+ private
35
+
36
+ def create_widgets
37
+ Widget.elastic_connection.index({'widget' => {'color' => 'red'}}, {index: 'widgets', type: 'widget', id: '05'})
38
+ Widget.elastic_connection.index({'widget' => {'color' => 'blue'}}, {index: 'widgets', type: 'widget', id: '10'})
39
+
40
+ Widget.elastic_connection.refresh
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::Relation::MergingTest < MiniTest::Spec
4
+ def test_merge_single_values
5
+ relation = Widget.relation.limit(5)
6
+ other = Widget.relation.limit(10)
7
+
8
+ relation.merge! other
9
+
10
+ assert_equal 10, relation.limit_value
11
+ end
12
+
13
+ def test_merge_multi_values
14
+ relation = Widget.relation.filter(color: 'green')
15
+ other = Widget.relation.filter(weight: 1.0)
16
+
17
+ relation.merge! other
18
+
19
+ assert_equal [{color: 'green'}, {weight: 1.0}], relation.filter_values
20
+ end
21
+ end
@@ -0,0 +1,157 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::Relation::SearchMethodsTest < MiniTest::Spec
4
+ def test_query_with_no_queries
5
+ expected = {"match_all" => {}}
6
+
7
+ assert_equal expected, relation.as_elastic['query']
8
+ end
9
+
10
+ def test_query_with_multiple_filters
11
+ relation.filter!('foo' => 'bar')
12
+ relation.filter!(Widget.arelastic['faz'].in ['baz', 'fum'])
13
+
14
+ expected = {
15
+ "constant_score" => {
16
+ "filter" => {
17
+ "and" => [
18
+ {"term" => {"foo" => "bar"}},
19
+ {"terms" => {"faz" => ["baz", "fum"]}}
20
+ ]
21
+ }
22
+ }
23
+ }
24
+
25
+ assert_equal expected, relation.as_elastic['query']
26
+ end
27
+
28
+ def test_query_with_range_filter
29
+ relation.filter!(Widget.arelastic['faz'].in 3..5)
30
+
31
+ expected = {
32
+ "constant_score" => {
33
+ "filter" => {
34
+ "range" => {
35
+ "faz" => {"gte"=>3, "lte"=>5}
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ assert_equal expected, relation.as_elastic['query']
42
+ end
43
+
44
+ def test_query_with_only_query
45
+ relation.query!('foo')
46
+
47
+ expected = {"query_string" => {"query" => "foo"}}
48
+
49
+ assert_equal expected, relation.as_elastic['query']
50
+ end
51
+
52
+ def test_query_with_both_filter_and_query
53
+ relation.query!('field' => {'name' => 'joe'})
54
+ relation.filter!(Widget.arelastic['name'].prefix "mat")
55
+
56
+ expected = {
57
+ "filtered" => {
58
+ "query" => {
59
+ "field" => {
60
+ "name"=>"joe"
61
+ },
62
+ },
63
+ "filter" => {
64
+ "prefix" => {
65
+ "name" => "mat"
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ assert_equal expected, relation.as_elastic['query']
72
+ end
73
+
74
+ def test_facet_with_arelastic
75
+ relation.facet!(Widget.arelastic.facet['popular_tags'].histogram('field' => 'field_name', 'interval' => 100))
76
+
77
+ expected = {
78
+ "popular_tags" => {
79
+ "histogram" =>
80
+ {
81
+ "field" => "field_name",
82
+ "interval" => 100
83
+ }
84
+ }
85
+ }
86
+
87
+ assert_equal expected, relation.as_elastic['facets']
88
+ end
89
+
90
+ def test_facet_with_string
91
+ relation.facet!('tags', 'size' => 10)
92
+
93
+ expected = {
94
+ "tags" => {
95
+ "terms" => {
96
+ "field" => "tags",
97
+ "size" => 10
98
+ }
99
+ }
100
+ }
101
+
102
+ assert_equal expected, relation.as_elastic['facets']
103
+ end
104
+
105
+ def test_limit
106
+ relation.limit!(5)
107
+
108
+ expected = 5
109
+ assert_equal expected, relation.as_elastic['size']
110
+ end
111
+
112
+ def test_offset
113
+ relation.offset!(42)
114
+
115
+ expected = 42
116
+ assert_equal expected, relation.as_elastic['from']
117
+ end
118
+
119
+ def test_order
120
+ relation.order! 'foo'
121
+ relation.order! 'bar' => 'desc'
122
+
123
+ expected = [
124
+ 'foo',
125
+ 'bar' => 'desc'
126
+ ]
127
+
128
+ assert_equal expected, relation.as_elastic['sort']
129
+ end
130
+
131
+ def test_extending_with_block
132
+ relation.extending! do
133
+ def foo
134
+ 'foo'
135
+ end
136
+ end
137
+
138
+ assert_equal 'foo', relation.foo
139
+ end
140
+
141
+ def test_extending_with_module
142
+ mod = Module.new do
143
+ def bar
144
+ 'bar'
145
+ end
146
+ end
147
+
148
+ relation.extending! mod
149
+
150
+ assert_equal 'bar', relation.bar
151
+ end
152
+
153
+ private
154
+ def relation
155
+ @relation ||= Widget.relation
156
+ end
157
+ end
@@ -0,0 +1,52 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::RelationTest < MiniTest::Spec
4
+ def setup
5
+ Widget.reset_index!
6
+ create_widgets
7
+ end
8
+
9
+ def test_to_hits
10
+ assert Widget.relation.to_hits.is_a?(ElasticSearch::Api::Hits)
11
+ end
12
+
13
+ def test_to_ids
14
+ assert_equal ['5', '10'], Widget.relation.to_ids
15
+ end
16
+
17
+ def test_to_a
18
+ array = Widget.relation.to_a
19
+
20
+ assert_equal 2, array.size
21
+ assert array.first.is_a?(Widget)
22
+ end
23
+
24
+ def test_count
25
+ assert_equal 2, Widget.relation.count
26
+ end
27
+
28
+ def test_facets
29
+ facets = Widget.relation.facet(Widget.arelastic.facet['popular_colors'].terms('color')).facets
30
+
31
+ assert_equal 2, facets['popular_colors']['total']
32
+ end
33
+
34
+ def test_equal
35
+ assert(Widget.relation.filter(color: 'green') == Widget.relation.filter(color: 'green'))
36
+ assert(Widget.relation.filter(color: 'green') != Widget.relation.filter(color: 'blue'))
37
+
38
+ assert(Widget.relation.filter(color: 'magenta') == [])
39
+ end
40
+
41
+ def test_inspect
42
+ assert_equal [].inspect, Widget.relation.filter(color: 'magenta').inspect
43
+ end
44
+
45
+ private
46
+ def create_widgets
47
+ Widget.elastic_connection.index({'widget' => {'color' => 'red'}}, {index: 'widgets', type: 'widget', id: 5})
48
+ Widget.elastic_connection.index({'widget' => {'color' => 'blue'}}, {index: 'widgets', type: 'widget', id: 10})
49
+
50
+ Widget.elastic_connection.refresh
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ require 'helper'
2
+
3
+ class ElasticRecord::SearchingTest < MiniTest::Spec
4
+ def test_elastic_search
5
+
6
+ end
7
+
8
+ def test_elastic_scope
9
+ model = Class.new(Widget) do
10
+ elastic_scope :by_color, ->(color) { elastic_search.filter(color: color) } do
11
+ def negative_offset
12
+ -offset_value
13
+ end
14
+ end
15
+ end
16
+
17
+ relation = model.by_color('blue')
18
+
19
+ assert_equal model.relation.filter(color: 'blue'), relation
20
+ assert_equal -5, relation.offset(5).negative_offset
21
+ end
22
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'bundler/setup'
2
+ Bundler.require
3
+
4
+ require 'minitest/autorun'
5
+
6
+ require 'rubberband'
7
+ require 'active_support/core_ext/object/blank'
8
+ require 'active_model'
9
+
10
+ require 'support/widget'
11
+ require 'support/connect'
12
+
13
+ module MiniTest
14
+ class Spec
15
+ end
16
+ end
@@ -0,0 +1 @@
1
+ ElasticRecord::Config.servers = '127.0.0.1:9200'
@@ -0,0 +1,39 @@
1
+ class Widget
2
+ extend ActiveModel::Naming
3
+ include ElasticRecord::Model
4
+
5
+ class << self
6
+ def find(ids)
7
+ ids.map { |id| new(id: id, color: 'red') }
8
+ end
9
+
10
+
11
+ def reset_index!
12
+ elastic_connection.delete_index('widgets')
13
+ elastic_connection.create_index('widgets')
14
+ elastic_connection.update_mapping(
15
+ {
16
+ properties: {
17
+ color: {
18
+ type: 'string',
19
+ index: 'not_analyzed'
20
+ }
21
+ },
22
+ _source: {
23
+ enabled: false
24
+ }
25
+ },
26
+ {
27
+ index: 'widgets'
28
+ }
29
+ )
30
+ end
31
+ end
32
+
33
+ attr_accessor :id, :color
34
+ def initialize(attributes = {})
35
+ attributes.each do |key, val|
36
+ send("#{key}=", val)
37
+ end
38
+ end
39
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elastic_record
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matthew Higgins
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: arelastic
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rubberband
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.1.1
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.1.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: activemodel
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Find your records with elastic search
63
+ email: developer@matthewhiggins.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files:
67
+ - README.rdoc
68
+ files:
69
+ - lib/elastic_record/config.rb
70
+ - lib/elastic_record/connection.rb
71
+ - lib/elastic_record/model.rb
72
+ - lib/elastic_record/orm/active_record.rb
73
+ - lib/elastic_record/relation/batches.rb
74
+ - lib/elastic_record/relation/delegation.rb
75
+ - lib/elastic_record/relation/finder_methods.rb
76
+ - lib/elastic_record/relation/merging.rb
77
+ - lib/elastic_record/relation/search_methods.rb
78
+ - lib/elastic_record/relation.rb
79
+ - lib/elastic_record/searching.rb
80
+ - lib/elastic_record.rb
81
+ - test/elastic_record/config_test.rb
82
+ - test/elastic_record/connection_test.rb
83
+ - test/elastic_record/model_test.rb
84
+ - test/elastic_record/relation/batches_test.rb
85
+ - test/elastic_record/relation/delegation_test.rb
86
+ - test/elastic_record/relation/finder_methods_test.rb
87
+ - test/elastic_record/relation/merging_test.rb
88
+ - test/elastic_record/relation/search_methods_test.rb
89
+ - test/elastic_record/relation_test.rb
90
+ - test/elastic_record/searching_test.rb
91
+ - test/helper.rb
92
+ - test/support/connect.rb
93
+ - test/support/widget.rb
94
+ - README.rdoc
95
+ homepage: http://github.com/matthuhiggins/elastic_record
96
+ licenses:
97
+ - MIT
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: 1.9.3
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: 1.8.11
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 1.8.24
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: Use Elastic Search with your objects
120
+ test_files: []