elasticsearch-model-queryable 0.1.5
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 +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +695 -0
- data/Rakefile +59 -0
- data/elasticsearch-model.gemspec +57 -0
- data/examples/activerecord_article.rb +77 -0
- data/examples/activerecord_associations.rb +162 -0
- data/examples/couchbase_article.rb +66 -0
- data/examples/datamapper_article.rb +71 -0
- data/examples/mongoid_article.rb +68 -0
- data/examples/ohm_article.rb +70 -0
- data/examples/riak_article.rb +52 -0
- data/gemfiles/3.0.gemfile +12 -0
- data/gemfiles/4.0.gemfile +11 -0
- data/lib/elasticsearch/model/adapter.rb +145 -0
- data/lib/elasticsearch/model/adapters/active_record.rb +104 -0
- data/lib/elasticsearch/model/adapters/default.rb +50 -0
- data/lib/elasticsearch/model/adapters/mongoid.rb +92 -0
- data/lib/elasticsearch/model/callbacks.rb +35 -0
- data/lib/elasticsearch/model/client.rb +61 -0
- data/lib/elasticsearch/model/ext/active_record.rb +14 -0
- data/lib/elasticsearch/model/hash_wrapper.rb +15 -0
- data/lib/elasticsearch/model/importing.rb +144 -0
- data/lib/elasticsearch/model/indexing.rb +472 -0
- data/lib/elasticsearch/model/naming.rb +101 -0
- data/lib/elasticsearch/model/proxy.rb +127 -0
- data/lib/elasticsearch/model/response/base.rb +44 -0
- data/lib/elasticsearch/model/response/pagination.rb +173 -0
- data/lib/elasticsearch/model/response/records.rb +69 -0
- data/lib/elasticsearch/model/response/result.rb +63 -0
- data/lib/elasticsearch/model/response/results.rb +31 -0
- data/lib/elasticsearch/model/response.rb +71 -0
- data/lib/elasticsearch/model/searching.rb +107 -0
- data/lib/elasticsearch/model/serializing.rb +35 -0
- data/lib/elasticsearch/model/version.rb +5 -0
- data/lib/elasticsearch/model.rb +157 -0
- data/test/integration/active_record_associations_parent_child.rb +139 -0
- data/test/integration/active_record_associations_test.rb +307 -0
- data/test/integration/active_record_basic_test.rb +179 -0
- data/test/integration/active_record_custom_serialization_test.rb +62 -0
- data/test/integration/active_record_import_test.rb +100 -0
- data/test/integration/active_record_namespaced_model_test.rb +49 -0
- data/test/integration/active_record_pagination_test.rb +132 -0
- data/test/integration/mongoid_basic_test.rb +193 -0
- data/test/test_helper.rb +63 -0
- data/test/unit/adapter_active_record_test.rb +140 -0
- data/test/unit/adapter_default_test.rb +41 -0
- data/test/unit/adapter_mongoid_test.rb +102 -0
- data/test/unit/adapter_test.rb +69 -0
- data/test/unit/callbacks_test.rb +31 -0
- data/test/unit/client_test.rb +27 -0
- data/test/unit/importing_test.rb +176 -0
- data/test/unit/indexing_test.rb +478 -0
- data/test/unit/module_test.rb +57 -0
- data/test/unit/naming_test.rb +76 -0
- data/test/unit/proxy_test.rb +89 -0
- data/test/unit/response_base_test.rb +40 -0
- data/test/unit/response_pagination_kaminari_test.rb +189 -0
- data/test/unit/response_pagination_will_paginate_test.rb +208 -0
- data/test/unit/response_records_test.rb +91 -0
- data/test/unit/response_result_test.rb +90 -0
- data/test/unit/response_results_test.rb +31 -0
- data/test/unit/response_test.rb +67 -0
- data/test/unit/searching_search_request_test.rb +78 -0
- data/test/unit/searching_test.rb +41 -0
- data/test/unit/serializing_test.rb +17 -0
- metadata +466 -0
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'mongoid'
|
5
|
+
session = Moped::Connection.new("localhost", 27017, 0.5)
|
6
|
+
session.connect
|
7
|
+
ENV["MONGODB_AVAILABLE"] = 'yes'
|
8
|
+
rescue LoadError, Moped::Errors::ConnectionFailure => e
|
9
|
+
$stderr.puts "MongoDB not installed or running: #{e}"
|
10
|
+
end
|
11
|
+
|
12
|
+
if ENV["MONGODB_AVAILABLE"]
|
13
|
+
$stderr.puts "Mongoid #{Mongoid::VERSION}", '-'*80
|
14
|
+
|
15
|
+
logger = ::Logger.new($stderr)
|
16
|
+
logger.formatter = lambda { |s, d, p, m| " #{m.ansi(:faint, :cyan)}\n" }
|
17
|
+
logger.level = ::Logger::DEBUG
|
18
|
+
|
19
|
+
Mongoid.logger = logger unless ENV['QUIET']
|
20
|
+
Moped.logger = logger unless ENV['QUIET']
|
21
|
+
|
22
|
+
Mongoid.connect_to 'mongoid_articles'
|
23
|
+
|
24
|
+
module Elasticsearch
|
25
|
+
module Model
|
26
|
+
class MongoidBasicIntegrationTest < Elasticsearch::Test::IntegrationTestCase
|
27
|
+
|
28
|
+
class ::MongoidArticle
|
29
|
+
include Mongoid::Document
|
30
|
+
include Elasticsearch::Model
|
31
|
+
include Elasticsearch::Model::Callbacks
|
32
|
+
|
33
|
+
field :id, type: String
|
34
|
+
field :title, type: String
|
35
|
+
attr_accessible :title if respond_to? :attr_accessible
|
36
|
+
|
37
|
+
settings index: { number_of_shards: 1, number_of_replicas: 0 } do
|
38
|
+
mapping do
|
39
|
+
indexes :title, type: 'string', analyzer: 'snowball'
|
40
|
+
indexes :created_at, type: 'date'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def as_indexed_json(options={})
|
45
|
+
as_json(except: [:id, :_id])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "Mongoid integration" do
|
50
|
+
setup do
|
51
|
+
Elasticsearch::Model::Adapter.register \
|
52
|
+
Elasticsearch::Model::Adapter::Mongoid,
|
53
|
+
lambda { |klass| !!defined?(::Mongoid::Document) && klass.ancestors.include?(::Mongoid::Document) }
|
54
|
+
|
55
|
+
MongoidArticle.__elasticsearch__.create_index! force: true
|
56
|
+
|
57
|
+
MongoidArticle.delete_all
|
58
|
+
|
59
|
+
MongoidArticle.create! title: 'Test'
|
60
|
+
MongoidArticle.create! title: 'Testing Coding'
|
61
|
+
MongoidArticle.create! title: 'Coding'
|
62
|
+
|
63
|
+
MongoidArticle.__elasticsearch__.refresh_index!
|
64
|
+
MongoidArticle.__elasticsearch__.client.cluster.health wait_for_status: 'yellow'
|
65
|
+
end
|
66
|
+
|
67
|
+
should "index and find a document" do
|
68
|
+
response = MongoidArticle.search('title:test')
|
69
|
+
|
70
|
+
assert response.any?
|
71
|
+
|
72
|
+
assert_equal 2, response.results.size
|
73
|
+
assert_equal 2, response.records.size
|
74
|
+
|
75
|
+
assert_instance_of Elasticsearch::Model::Response::Result, response.results.first
|
76
|
+
assert_instance_of MongoidArticle, response.records.first
|
77
|
+
|
78
|
+
assert_equal 'Test', response.results.first.title
|
79
|
+
assert_equal 'Test', response.records.first.title
|
80
|
+
end
|
81
|
+
|
82
|
+
should "iterate over results" do
|
83
|
+
response = MongoidArticle.search('title:test')
|
84
|
+
|
85
|
+
assert_equal ['Test', 'Testing Coding'], response.results.map(&:title)
|
86
|
+
assert_equal ['Test', 'Testing Coding'], response.records.map(&:title)
|
87
|
+
end
|
88
|
+
|
89
|
+
should "access results from records" do
|
90
|
+
response = MongoidArticle.search('title:test')
|
91
|
+
|
92
|
+
response.records.each_with_hit do |r, h|
|
93
|
+
assert_not_nil h._score
|
94
|
+
assert_not_nil h._source.title
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
should "preserve the search results order for records" do
|
99
|
+
response = MongoidArticle.search('title:code')
|
100
|
+
|
101
|
+
response.records.each_with_hit do |r, h|
|
102
|
+
assert_equal h._id, r.id.to_s
|
103
|
+
end
|
104
|
+
|
105
|
+
response.records.map_with_hit do |r, h|
|
106
|
+
assert_equal h._id, r.id.to_s
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
should "remove document from index on destroy" do
|
111
|
+
article = MongoidArticle.first
|
112
|
+
|
113
|
+
article.destroy
|
114
|
+
assert_equal 2, MongoidArticle.count
|
115
|
+
|
116
|
+
MongoidArticle.__elasticsearch__.refresh_index!
|
117
|
+
|
118
|
+
response = MongoidArticle.search 'title:test'
|
119
|
+
|
120
|
+
assert_equal 1, response.results.size
|
121
|
+
assert_equal 1, response.records.size
|
122
|
+
end
|
123
|
+
|
124
|
+
should "index updates to the document" do
|
125
|
+
article = MongoidArticle.first
|
126
|
+
|
127
|
+
article.title = 'Writing'
|
128
|
+
article.save
|
129
|
+
|
130
|
+
MongoidArticle.__elasticsearch__.refresh_index!
|
131
|
+
|
132
|
+
response = MongoidArticle.search 'title:write'
|
133
|
+
|
134
|
+
assert_equal 1, response.results.size
|
135
|
+
assert_equal 1, response.records.size
|
136
|
+
end
|
137
|
+
|
138
|
+
should "return results for a DSL search" do
|
139
|
+
response = MongoidArticle.search query: { match: { title: { query: 'test' } } }
|
140
|
+
|
141
|
+
assert_equal 2, response.results.size
|
142
|
+
assert_equal 2, response.records.size
|
143
|
+
end
|
144
|
+
|
145
|
+
should "return a paged collection" do
|
146
|
+
response = MongoidArticle.search query: { match: { title: { query: 'test' } } },
|
147
|
+
size: 2,
|
148
|
+
from: 1
|
149
|
+
|
150
|
+
assert_equal 1, response.results.size
|
151
|
+
assert_equal 1, response.records.size
|
152
|
+
|
153
|
+
assert_equal 'Testing Coding', response.results.first.title
|
154
|
+
assert_equal 'Testing Coding', response.records.first.title
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
context "importing" do
|
159
|
+
setup do
|
160
|
+
MongoidArticle.delete_all
|
161
|
+
97.times { |i| MongoidArticle.create! title: "Test #{i}" }
|
162
|
+
MongoidArticle.__elasticsearch__.create_index! force: true
|
163
|
+
MongoidArticle.__elasticsearch__.client.cluster.health wait_for_status: 'yellow'
|
164
|
+
end
|
165
|
+
|
166
|
+
should "import all the documents" do
|
167
|
+
assert_equal 97, MongoidArticle.count
|
168
|
+
|
169
|
+
MongoidArticle.__elasticsearch__.refresh_index!
|
170
|
+
assert_equal 0, MongoidArticle.search('*').results.total
|
171
|
+
|
172
|
+
batches = 0
|
173
|
+
errors = MongoidArticle.import(batch_size: 10) do |response|
|
174
|
+
batches += 1
|
175
|
+
end
|
176
|
+
|
177
|
+
assert_equal 0, errors
|
178
|
+
assert_equal 10, batches
|
179
|
+
|
180
|
+
MongoidArticle.__elasticsearch__.refresh_index!
|
181
|
+
assert_equal 97, MongoidArticle.search('*').results.total
|
182
|
+
|
183
|
+
response = MongoidArticle.search('test')
|
184
|
+
assert response.results.any?, "Search has not returned results: #{response.to_a}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
RUBY_1_8 = defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
|
2
|
+
|
3
|
+
exit(0) if RUBY_1_8
|
4
|
+
|
5
|
+
require 'simplecov' and SimpleCov.start { add_filter "/test|test_/" } if ENV["COVERAGE"]
|
6
|
+
|
7
|
+
# Register `at_exit` handler for integration tests shutdown.
|
8
|
+
# MUST be called before requiring `test/unit`.
|
9
|
+
at_exit { Elasticsearch::Test::IntegrationTestCase.__run_at_exit_hooks }
|
10
|
+
|
11
|
+
puts '-'*80
|
12
|
+
|
13
|
+
if defined?(RUBY_VERSION) && RUBY_VERSION > '2.2'
|
14
|
+
require 'test-unit'
|
15
|
+
require 'mocha/test_unit'
|
16
|
+
else
|
17
|
+
require 'minitest/autorun'
|
18
|
+
require 'mocha/mini_test'
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'shoulda-context'
|
22
|
+
|
23
|
+
require 'turn' unless ENV["TM_FILEPATH"] || ENV["NOTURN"] || defined?(RUBY_VERSION) && RUBY_VERSION > '2.2'
|
24
|
+
|
25
|
+
require 'ansi'
|
26
|
+
require 'oj'
|
27
|
+
|
28
|
+
require 'active_model'
|
29
|
+
|
30
|
+
require 'kaminari'
|
31
|
+
|
32
|
+
require 'elasticsearch/model'
|
33
|
+
|
34
|
+
require 'elasticsearch/extensions/test/cluster'
|
35
|
+
require 'elasticsearch/extensions/test/startup_shutdown'
|
36
|
+
|
37
|
+
module Elasticsearch
|
38
|
+
module Test
|
39
|
+
class IntegrationTestCase < ::Test::Unit::TestCase
|
40
|
+
extend Elasticsearch::Extensions::Test::StartupShutdown
|
41
|
+
|
42
|
+
startup { Elasticsearch::Extensions::Test::Cluster.start(nodes: 1) if ENV['SERVER'] and not Elasticsearch::Extensions::Test::Cluster.running? }
|
43
|
+
shutdown { Elasticsearch::Extensions::Test::Cluster.stop if ENV['SERVER'] && started? }
|
44
|
+
context "IntegrationTest" do; should "noop on Ruby 1.8" do; end; end if RUBY_1_8
|
45
|
+
|
46
|
+
def setup
|
47
|
+
ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ":memory:" )
|
48
|
+
logger = ::Logger.new(STDERR)
|
49
|
+
logger.formatter = lambda { |s, d, p, m| "\e[2;36m#{m}\e[0m\n" }
|
50
|
+
ActiveRecord::Base.logger = logger unless ENV['QUIET']
|
51
|
+
|
52
|
+
ActiveRecord::LogSubscriber.colorize_logging = false
|
53
|
+
ActiveRecord::Migration.verbose = false
|
54
|
+
|
55
|
+
tracer = ::Logger.new(STDERR)
|
56
|
+
tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
|
57
|
+
|
58
|
+
Elasticsearch::Model.client = Elasticsearch::Client.new host: "localhost:#{(ENV['TEST_CLUSTER_PORT'] || 9250)}",
|
59
|
+
tracer: (ENV['QUIET'] ? nil : tracer)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Model::AdapterActiveRecordTest < Test::Unit::TestCase
|
4
|
+
context "Adapter ActiveRecord module: " do
|
5
|
+
class ::DummyClassForActiveRecord
|
6
|
+
RESPONSE = Struct.new('DummyActiveRecordResponse') do
|
7
|
+
def response
|
8
|
+
{ 'hits' => {'hits' => [ {'_id' => 2}, {'_id' => 1} ]} }
|
9
|
+
end
|
10
|
+
end.new
|
11
|
+
|
12
|
+
def response
|
13
|
+
RESPONSE
|
14
|
+
end
|
15
|
+
|
16
|
+
def ids
|
17
|
+
[2, 1]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
RESPONSE = { 'hits' => { 'total' => 123, 'max_score' => 456, 'hits' => [] } }
|
22
|
+
|
23
|
+
setup do
|
24
|
+
@records = [ stub(id: 1, inspect: '<Model-1>'), stub(id: 2, inspect: '<Model-2>') ]
|
25
|
+
@records.stubs(:load).returns(true)
|
26
|
+
@records.stubs(:exec_queries).returns(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
should "have the register condition" do
|
30
|
+
assert_not_nil Elasticsearch::Model::Adapter.adapters[Elasticsearch::Model::Adapter::ActiveRecord]
|
31
|
+
assert_equal false, Elasticsearch::Model::Adapter.adapters[Elasticsearch::Model::Adapter::ActiveRecord].call(DummyClassForActiveRecord)
|
32
|
+
end
|
33
|
+
|
34
|
+
context "Records" do
|
35
|
+
setup do
|
36
|
+
DummyClassForActiveRecord.__send__ :include, Elasticsearch::Model::Adapter::ActiveRecord::Records
|
37
|
+
end
|
38
|
+
|
39
|
+
should "have the implementation" do
|
40
|
+
assert_instance_of Module, Elasticsearch::Model::Adapter::ActiveRecord::Records
|
41
|
+
|
42
|
+
instance = DummyClassForActiveRecord.new
|
43
|
+
instance.expects(:klass).returns(mock('class', primary_key: :some_key, where: @records)).at_least_once
|
44
|
+
|
45
|
+
assert_equal @records, instance.records
|
46
|
+
end
|
47
|
+
|
48
|
+
should "load the records" do
|
49
|
+
instance = DummyClassForActiveRecord.new
|
50
|
+
instance.expects(:records).returns(@records)
|
51
|
+
instance.load
|
52
|
+
end
|
53
|
+
|
54
|
+
should "reorder the records based on hits order" do
|
55
|
+
@records.instance_variable_set(:@records, @records)
|
56
|
+
|
57
|
+
instance = DummyClassForActiveRecord.new
|
58
|
+
instance.expects(:klass).returns(mock('class', primary_key: :some_key, where: @records)).at_least_once
|
59
|
+
|
60
|
+
assert_equal [1, 2], @records. to_a.map(&:id)
|
61
|
+
assert_equal [2, 1], instance.records.to_a.map(&:id)
|
62
|
+
end
|
63
|
+
|
64
|
+
should "not reorder records when SQL order is present" do
|
65
|
+
@records.instance_variable_set(:@records, @records)
|
66
|
+
|
67
|
+
instance = DummyClassForActiveRecord.new
|
68
|
+
instance.expects(:klass).returns(stub('class', primary_key: :some_key, where: @records)).at_least_once
|
69
|
+
instance.records.expects(:order).returns(@records)
|
70
|
+
|
71
|
+
assert_equal [2, 1], instance.records. to_a.map(&:id)
|
72
|
+
assert_equal [1, 2], instance.order(:foo).to_a.map(&:id)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "Callbacks" do
|
77
|
+
should "register hooks for automatically updating the index" do
|
78
|
+
DummyClassForActiveRecord.expects(:after_commit).times(3)
|
79
|
+
|
80
|
+
Elasticsearch::Model::Adapter::ActiveRecord::Callbacks.included(DummyClassForActiveRecord)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "Importing" do
|
85
|
+
setup do
|
86
|
+
DummyClassForActiveRecord.__send__ :extend, Elasticsearch::Model::Adapter::ActiveRecord::Importing
|
87
|
+
end
|
88
|
+
|
89
|
+
should "raise an exception when passing an invalid scope" do
|
90
|
+
assert_raise NoMethodError do
|
91
|
+
DummyClassForActiveRecord.__find_in_batches(scope: :not_found_method) do; end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
should "implement the __find_in_batches method" do
|
96
|
+
DummyClassForActiveRecord.expects(:find_in_batches).returns([])
|
97
|
+
DummyClassForActiveRecord.__find_in_batches do; end
|
98
|
+
end
|
99
|
+
|
100
|
+
should "limit the relation to a specific scope" do
|
101
|
+
DummyClassForActiveRecord.expects(:find_in_batches).returns([])
|
102
|
+
DummyClassForActiveRecord.expects(:published).returns(DummyClassForActiveRecord)
|
103
|
+
|
104
|
+
DummyClassForActiveRecord.__find_in_batches(scope: :published) do; end
|
105
|
+
end
|
106
|
+
|
107
|
+
should "preprocess the batch if option provided" do
|
108
|
+
class << DummyClassForActiveRecord
|
109
|
+
# Updates/transforms the batch while fetching it from the database
|
110
|
+
# (eg. with information from an external system)
|
111
|
+
#
|
112
|
+
def update_batch(batch)
|
113
|
+
batch.collect { |b| b.to_s + '!' }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
DummyClassForActiveRecord.expects(:__find_in_batches).returns( [:a, :b] )
|
118
|
+
|
119
|
+
DummyClassForActiveRecord.__find_in_batches(preprocess: :update_batch) do |batch|
|
120
|
+
assert_same_elements ["a!", "b!"], batch
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when transforming models" do
|
125
|
+
setup do
|
126
|
+
@transform = DummyClassForActiveRecord.__transform
|
127
|
+
end
|
128
|
+
|
129
|
+
should "provide an object that responds to #call" do
|
130
|
+
assert_respond_to @transform, :call
|
131
|
+
end
|
132
|
+
|
133
|
+
should "provide default transformation" do
|
134
|
+
model = mock("model", id: 1, __elasticsearch__: stub(as_indexed_json: {}))
|
135
|
+
assert_equal @transform.call(model), { index: { _id: 1, data: {} } }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Model::AdapterDefaultTest < Test::Unit::TestCase
|
4
|
+
context "Adapter default module" do
|
5
|
+
class ::DummyClassForDefaultAdapter; end
|
6
|
+
|
7
|
+
should "have the default Records implementation" do
|
8
|
+
assert_instance_of Module, Elasticsearch::Model::Adapter::Default::Records
|
9
|
+
|
10
|
+
DummyClassForDefaultAdapter.__send__ :include, Elasticsearch::Model::Adapter::Default::Records
|
11
|
+
|
12
|
+
instance = DummyClassForDefaultAdapter.new
|
13
|
+
klass = mock('class', find: [1])
|
14
|
+
instance.expects(:klass).returns(klass)
|
15
|
+
instance.records
|
16
|
+
end
|
17
|
+
|
18
|
+
should "have the default Callbacks implementation" do
|
19
|
+
assert_instance_of Module, Elasticsearch::Model::Adapter::Default::Callbacks
|
20
|
+
end
|
21
|
+
|
22
|
+
context "concerning abstract methods" do
|
23
|
+
setup do
|
24
|
+
DummyClassForDefaultAdapter.__send__ :include, Elasticsearch::Model::Adapter::Default::Importing
|
25
|
+
end
|
26
|
+
|
27
|
+
should "have the default Importing implementation" do
|
28
|
+
assert_raise Elasticsearch::Model::NotImplemented do
|
29
|
+
DummyClassForDefaultAdapter.new.__find_in_batches
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
should "have the default transform implementation" do
|
34
|
+
assert_raise Elasticsearch::Model::NotImplemented do
|
35
|
+
DummyClassForDefaultAdapter.new.__transform
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Model::AdapterMongoidTest < Test::Unit::TestCase
|
4
|
+
context "Adapter Mongoid module: " do
|
5
|
+
class ::DummyClassForMongoid
|
6
|
+
RESPONSE = Struct.new('DummyMongoidResponse') do
|
7
|
+
def response
|
8
|
+
{ 'hits' => {'hits' => [ {'_id' => 2}, {'_id' => 1} ]} }
|
9
|
+
end
|
10
|
+
end.new
|
11
|
+
|
12
|
+
def response
|
13
|
+
RESPONSE
|
14
|
+
end
|
15
|
+
|
16
|
+
def ids
|
17
|
+
[2, 1]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
setup do
|
22
|
+
@records = [ stub(id: 1, inspect: '<Model-1>'), stub(id: 2, inspect: '<Model-2>') ]
|
23
|
+
::Symbol.any_instance.stubs(:in).returns(@records)
|
24
|
+
end
|
25
|
+
|
26
|
+
should "have the register condition" do
|
27
|
+
assert_not_nil Elasticsearch::Model::Adapter.adapters[Elasticsearch::Model::Adapter::Mongoid]
|
28
|
+
assert_equal false, Elasticsearch::Model::Adapter.adapters[Elasticsearch::Model::Adapter::Mongoid].call(DummyClassForMongoid)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "Records" do
|
32
|
+
setup do
|
33
|
+
DummyClassForMongoid.__send__ :include, Elasticsearch::Model::Adapter::Mongoid::Records
|
34
|
+
end
|
35
|
+
|
36
|
+
should "have the implementation" do
|
37
|
+
assert_instance_of Module, Elasticsearch::Model::Adapter::Mongoid::Records
|
38
|
+
|
39
|
+
instance = DummyClassForMongoid.new
|
40
|
+
instance.expects(:klass).returns(mock('class', where: @records))
|
41
|
+
|
42
|
+
assert_equal @records, instance.records
|
43
|
+
end
|
44
|
+
|
45
|
+
should "reorder the records based on hits order" do
|
46
|
+
@records.instance_variable_set(:@records, @records)
|
47
|
+
|
48
|
+
instance = DummyClassForMongoid.new
|
49
|
+
instance.expects(:klass).returns(mock('class', where: @records))
|
50
|
+
|
51
|
+
assert_equal [1, 2], @records. to_a.map(&:id)
|
52
|
+
assert_equal [2, 1], instance.records.to_a.map(&:id)
|
53
|
+
end
|
54
|
+
|
55
|
+
should "not reorder records when SQL order is present" do
|
56
|
+
@records.instance_variable_set(:@records, @records)
|
57
|
+
|
58
|
+
instance = DummyClassForMongoid.new
|
59
|
+
instance.expects(:klass).returns(stub('class', where: @records)).at_least_once
|
60
|
+
instance.records.expects(:asc).returns(@records)
|
61
|
+
|
62
|
+
assert_equal [2, 1], instance.records.to_a.map(&:id)
|
63
|
+
assert_equal [1, 2], instance.asc.to_a.map(&:id)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "Callbacks" do
|
68
|
+
should "register hooks for automatically updating the index" do
|
69
|
+
DummyClassForMongoid.expects(:after_create)
|
70
|
+
DummyClassForMongoid.expects(:after_update)
|
71
|
+
DummyClassForMongoid.expects(:after_destroy)
|
72
|
+
|
73
|
+
Elasticsearch::Model::Adapter::Mongoid::Callbacks.included(DummyClassForMongoid)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "Importing" do
|
78
|
+
should "implement the __find_in_batches method" do
|
79
|
+
DummyClassForMongoid.expects(:all).returns([])
|
80
|
+
|
81
|
+
DummyClassForMongoid.__send__ :extend, Elasticsearch::Model::Adapter::Mongoid::Importing
|
82
|
+
DummyClassForMongoid.__find_in_batches do; end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when transforming models" do
|
86
|
+
setup do
|
87
|
+
@transform = DummyClassForMongoid.__transform
|
88
|
+
end
|
89
|
+
|
90
|
+
should "provide an object that responds to #call" do
|
91
|
+
assert_respond_to @transform, :call
|
92
|
+
end
|
93
|
+
|
94
|
+
should "provide basic transformation" do
|
95
|
+
model = mock("model", id: 1, as_indexed_json: {})
|
96
|
+
assert_equal @transform.call(model), { index: { _id: "1", data: {} } }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Model::AdapterTest < Test::Unit::TestCase
|
4
|
+
context "Adapter module" do
|
5
|
+
class ::DummyAdapterClass; end
|
6
|
+
class ::DummyAdapterClassWithAdapter; end
|
7
|
+
class ::DummyAdapter
|
8
|
+
Records = Module.new
|
9
|
+
Callbacks = Module.new
|
10
|
+
Importing = Module.new
|
11
|
+
end
|
12
|
+
|
13
|
+
should "return an Adapter instance" do
|
14
|
+
assert_instance_of Elasticsearch::Model::Adapter::Adapter,
|
15
|
+
Elasticsearch::Model::Adapter.from_class(DummyAdapterClass)
|
16
|
+
end
|
17
|
+
|
18
|
+
should "return a list of adapters" do
|
19
|
+
Elasticsearch::Model::Adapter::Adapter.expects(:adapters)
|
20
|
+
Elasticsearch::Model::Adapter.adapters
|
21
|
+
end
|
22
|
+
|
23
|
+
should "register an adapter" do
|
24
|
+
begin
|
25
|
+
Elasticsearch::Model::Adapter::Adapter.expects(:register)
|
26
|
+
Elasticsearch::Model::Adapter.register(:foo, lambda { |c| false })
|
27
|
+
ensure
|
28
|
+
Elasticsearch::Model::Adapter::Adapter.instance_variable_set(:@adapters, {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "Adapter class" do
|
34
|
+
should "register an adapter" do
|
35
|
+
begin
|
36
|
+
Elasticsearch::Model::Adapter::Adapter.register(:foo, lambda { |c| false })
|
37
|
+
assert Elasticsearch::Model::Adapter::Adapter.adapters[:foo]
|
38
|
+
ensure
|
39
|
+
Elasticsearch::Model::Adapter::Adapter.instance_variable_set(:@adapters, {})
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
should "return the default adapter" do
|
44
|
+
adapter = Elasticsearch::Model::Adapter::Adapter.new(DummyAdapterClass)
|
45
|
+
assert_equal Elasticsearch::Model::Adapter::Default, adapter.adapter
|
46
|
+
end
|
47
|
+
|
48
|
+
should "return a specific adapter" do
|
49
|
+
Elasticsearch::Model::Adapter::Adapter.register(DummyAdapter,
|
50
|
+
lambda { |c| c == DummyAdapterClassWithAdapter })
|
51
|
+
|
52
|
+
adapter = Elasticsearch::Model::Adapter::Adapter.new(DummyAdapterClassWithAdapter)
|
53
|
+
assert_equal DummyAdapter, adapter.adapter
|
54
|
+
end
|
55
|
+
|
56
|
+
should "return the modules" do
|
57
|
+
assert_nothing_raised do
|
58
|
+
Elasticsearch::Model::Adapter::Adapter.register(DummyAdapter,
|
59
|
+
lambda { |c| c == DummyAdapterClassWithAdapter })
|
60
|
+
|
61
|
+
adapter = Elasticsearch::Model::Adapter::Adapter.new(DummyAdapterClassWithAdapter)
|
62
|
+
|
63
|
+
assert_instance_of Module, adapter.records_mixin
|
64
|
+
assert_instance_of Module, adapter.callbacks_mixin
|
65
|
+
assert_instance_of Module, adapter.importing_mixin
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Model::CallbacksTest < Test::Unit::TestCase
|
4
|
+
context "Callbacks module" do
|
5
|
+
class ::DummyCallbacksModel
|
6
|
+
end
|
7
|
+
|
8
|
+
module DummyCallbacksAdapter
|
9
|
+
module CallbacksMixin
|
10
|
+
end
|
11
|
+
|
12
|
+
def callbacks_mixin
|
13
|
+
CallbacksMixin
|
14
|
+
end; module_function :callbacks_mixin
|
15
|
+
end
|
16
|
+
|
17
|
+
should "include the callbacks mixin from adapter" do
|
18
|
+
Elasticsearch::Model::Adapter.expects(:from_class)
|
19
|
+
.with(DummyCallbacksModel)
|
20
|
+
.returns(DummyCallbacksAdapter)
|
21
|
+
|
22
|
+
::DummyCallbacksModel.expects(:__send__).with do |method, parameter|
|
23
|
+
assert_equal :include, method
|
24
|
+
assert_equal DummyCallbacksAdapter::CallbacksMixin, parameter
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
Elasticsearch::Model::Callbacks.included(DummyCallbacksModel)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Model::ClientTest < Test::Unit::TestCase
|
4
|
+
context "Client module" do
|
5
|
+
class ::DummyClientModel
|
6
|
+
extend Elasticsearch::Model::Client::ClassMethods
|
7
|
+
include Elasticsearch::Model::Client::InstanceMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
should "have the default client method" do
|
11
|
+
assert_instance_of Elasticsearch::Transport::Client, DummyClientModel.client
|
12
|
+
assert_instance_of Elasticsearch::Transport::Client, DummyClientModel.new.client
|
13
|
+
end
|
14
|
+
|
15
|
+
should "set the client for the model" do
|
16
|
+
DummyClientModel.client = 'foobar'
|
17
|
+
assert_equal 'foobar', DummyClientModel.client
|
18
|
+
assert_equal 'foobar', DummyClientModel.new.client
|
19
|
+
end
|
20
|
+
|
21
|
+
should "set the client for a model instance" do
|
22
|
+
instance = DummyClientModel.new
|
23
|
+
instance.client = 'moobam'
|
24
|
+
assert_equal 'moobam', instance.client
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|