elastic_record 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []