elasticsearch-persistence-queryable 0.1.8
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 +17 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +678 -0
- data/Rakefile +57 -0
- data/elasticsearch-persistence.gemspec +57 -0
- data/examples/music/album.rb +34 -0
- data/examples/music/artist.rb +50 -0
- data/examples/music/artists/_form.html.erb +8 -0
- data/examples/music/artists/artists_controller.rb +67 -0
- data/examples/music/artists/artists_controller_test.rb +53 -0
- data/examples/music/artists/index.html.erb +57 -0
- data/examples/music/artists/show.html.erb +51 -0
- data/examples/music/assets/application.css +226 -0
- data/examples/music/assets/autocomplete.css +48 -0
- data/examples/music/assets/blank_cover.png +0 -0
- data/examples/music/assets/form.css +113 -0
- data/examples/music/index_manager.rb +60 -0
- data/examples/music/search/index.html.erb +93 -0
- data/examples/music/search/search_controller.rb +41 -0
- data/examples/music/search/search_controller_test.rb +9 -0
- data/examples/music/search/search_helper.rb +15 -0
- data/examples/music/suggester.rb +45 -0
- data/examples/music/template.rb +392 -0
- data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +7 -0
- data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +6 -0
- data/examples/notes/.gitignore +7 -0
- data/examples/notes/Gemfile +28 -0
- data/examples/notes/README.markdown +36 -0
- data/examples/notes/application.rb +238 -0
- data/examples/notes/config.ru +7 -0
- data/examples/notes/test.rb +118 -0
- data/lib/elasticsearch/per_thread_registry.rb +53 -0
- data/lib/elasticsearch/persistence/client.rb +51 -0
- data/lib/elasticsearch/persistence/inheritence.rb +9 -0
- data/lib/elasticsearch/persistence/model/base.rb +95 -0
- data/lib/elasticsearch/persistence/model/callbacks.rb +37 -0
- data/lib/elasticsearch/persistence/model/errors.rb +9 -0
- data/lib/elasticsearch/persistence/model/find.rb +155 -0
- data/lib/elasticsearch/persistence/model/gateway_delegation.rb +23 -0
- data/lib/elasticsearch/persistence/model/hash_wrapper.rb +17 -0
- data/lib/elasticsearch/persistence/model/rails.rb +39 -0
- data/lib/elasticsearch/persistence/model/store.rb +271 -0
- data/lib/elasticsearch/persistence/model.rb +148 -0
- data/lib/elasticsearch/persistence/null_relation.rb +56 -0
- data/lib/elasticsearch/persistence/query_cache.rb +68 -0
- data/lib/elasticsearch/persistence/querying.rb +21 -0
- data/lib/elasticsearch/persistence/relation/delegation.rb +130 -0
- data/lib/elasticsearch/persistence/relation/finder_methods.rb +39 -0
- data/lib/elasticsearch/persistence/relation/merger.rb +179 -0
- data/lib/elasticsearch/persistence/relation/query_builder.rb +279 -0
- data/lib/elasticsearch/persistence/relation/query_methods.rb +362 -0
- data/lib/elasticsearch/persistence/relation/search_option_methods.rb +44 -0
- data/lib/elasticsearch/persistence/relation/spawn_methods.rb +61 -0
- data/lib/elasticsearch/persistence/relation.rb +110 -0
- data/lib/elasticsearch/persistence/repository/class.rb +71 -0
- data/lib/elasticsearch/persistence/repository/find.rb +73 -0
- data/lib/elasticsearch/persistence/repository/naming.rb +115 -0
- data/lib/elasticsearch/persistence/repository/response/results.rb +105 -0
- data/lib/elasticsearch/persistence/repository/search.rb +156 -0
- data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
- data/lib/elasticsearch/persistence/repository/store.rb +94 -0
- data/lib/elasticsearch/persistence/repository.rb +77 -0
- data/lib/elasticsearch/persistence/scoping/default.rb +137 -0
- data/lib/elasticsearch/persistence/scoping/named.rb +70 -0
- data/lib/elasticsearch/persistence/scoping.rb +52 -0
- data/lib/elasticsearch/persistence/version.rb +5 -0
- data/lib/elasticsearch/persistence.rb +157 -0
- data/lib/elasticsearch/rails_compatibility.rb +17 -0
- data/lib/rails/generators/elasticsearch/model/model_generator.rb +21 -0
- data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +9 -0
- data/lib/rails/generators/elasticsearch_generator.rb +2 -0
- data/lib/rails/instrumentation/railtie.rb +31 -0
- data/lib/rails/instrumentation.rb +10 -0
- data/test/integration/model/model_basic_test.rb +157 -0
- data/test/integration/repository/custom_class_test.rb +85 -0
- data/test/integration/repository/customized_class_test.rb +82 -0
- data/test/integration/repository/default_class_test.rb +114 -0
- data/test/integration/repository/virtus_model_test.rb +114 -0
- data/test/test_helper.rb +53 -0
- data/test/unit/model_base_test.rb +48 -0
- data/test/unit/model_find_test.rb +148 -0
- data/test/unit/model_gateway_test.rb +99 -0
- data/test/unit/model_rails_test.rb +88 -0
- data/test/unit/model_store_test.rb +514 -0
- data/test/unit/persistence_test.rb +32 -0
- data/test/unit/repository_class_test.rb +51 -0
- data/test/unit/repository_client_test.rb +32 -0
- data/test/unit/repository_find_test.rb +388 -0
- data/test/unit/repository_indexing_test.rb +37 -0
- data/test/unit/repository_module_test.rb +146 -0
- data/test/unit/repository_naming_test.rb +146 -0
- data/test/unit/repository_response_results_test.rb +98 -0
- data/test/unit/repository_search_test.rb +117 -0
- data/test/unit/repository_serialize_test.rb +57 -0
- data/test/unit/repository_store_test.rb +303 -0
- metadata +487 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
require 'virtus'
|
5
|
+
|
6
|
+
require 'elasticsearch/persistence/model/errors'
|
7
|
+
require 'elasticsearch/persistence/model/find'
|
8
|
+
|
9
|
+
class Elasticsearch::Persistence::ModelFindTest < Test::Unit::TestCase
|
10
|
+
context "The model find module," do
|
11
|
+
|
12
|
+
class DummyFindModel
|
13
|
+
include ActiveModel::Naming
|
14
|
+
include ActiveModel::Conversion
|
15
|
+
include ActiveModel::Serialization
|
16
|
+
include ActiveModel::Serializers::JSON
|
17
|
+
include ActiveModel::Validations
|
18
|
+
|
19
|
+
include Virtus.model
|
20
|
+
|
21
|
+
extend Elasticsearch::Persistence::Model::Find::ClassMethods
|
22
|
+
|
23
|
+
extend ActiveModel::Callbacks
|
24
|
+
define_model_callbacks :create, :save, :update, :destroy
|
25
|
+
define_model_callbacks :find, :touch, only: :after
|
26
|
+
|
27
|
+
attribute :title, String
|
28
|
+
attribute :count, Integer, default: 0
|
29
|
+
attribute :created_at, DateTime, default: lambda { |o,a| Time.now.utc }
|
30
|
+
attribute :updated_at, DateTime, default: lambda { |o,a| Time.now.utc }
|
31
|
+
end
|
32
|
+
|
33
|
+
setup do
|
34
|
+
@gateway = stub(client: stub(), index_name: 'foo', document_type: 'bar')
|
35
|
+
DummyFindModel.stubs(:gateway).returns(@gateway)
|
36
|
+
|
37
|
+
@response = MultiJson.load <<-JSON
|
38
|
+
{
|
39
|
+
"took": 14,
|
40
|
+
"timed_out": false,
|
41
|
+
"_shards": {
|
42
|
+
"total": 5,
|
43
|
+
"successful": 5,
|
44
|
+
"failed": 0
|
45
|
+
},
|
46
|
+
"hits": {
|
47
|
+
"total": 1,
|
48
|
+
"max_score": 1.0,
|
49
|
+
"hits": [
|
50
|
+
{
|
51
|
+
"_index": "dummy",
|
52
|
+
"_type": "dummy",
|
53
|
+
"_id": "abc123",
|
54
|
+
"_score": 1.0,
|
55
|
+
"_source": {
|
56
|
+
"name": "TEST"
|
57
|
+
}
|
58
|
+
}
|
59
|
+
]
|
60
|
+
}
|
61
|
+
}
|
62
|
+
JSON
|
63
|
+
end
|
64
|
+
|
65
|
+
should "find all records" do
|
66
|
+
@gateway
|
67
|
+
.expects(:search)
|
68
|
+
.with({ query: { match_all: {} }, size: 10_000 })
|
69
|
+
.returns(@response)
|
70
|
+
|
71
|
+
DummyFindModel.all
|
72
|
+
end
|
73
|
+
|
74
|
+
should "pass options when finding all records" do
|
75
|
+
@gateway
|
76
|
+
.expects(:search)
|
77
|
+
.with({ query: { match: { title: 'test' } }, size: 10_000, routing: 'abc123' })
|
78
|
+
.returns(@response)
|
79
|
+
|
80
|
+
DummyFindModel.all( { query: { match: { title: 'test' } }, routing: 'abc123' } )
|
81
|
+
end
|
82
|
+
|
83
|
+
context "finding via scan/scroll" do
|
84
|
+
setup do
|
85
|
+
@gateway
|
86
|
+
.expects(:deserialize)
|
87
|
+
.with('_source' => {'foo' => 'bar'})
|
88
|
+
.returns('_source' => {'foo' => 'bar'})
|
89
|
+
|
90
|
+
@gateway.client
|
91
|
+
.expects(:search)
|
92
|
+
.with do |arguments|
|
93
|
+
assert_equal 'scan', arguments[:search_type]
|
94
|
+
assert_equal 'foo', arguments[:index]
|
95
|
+
assert_equal 'bar', arguments[:type]
|
96
|
+
true
|
97
|
+
end
|
98
|
+
.returns(MultiJson.load('{"_scroll_id":"abc123==", "hits":{"hits":[]}}'))
|
99
|
+
|
100
|
+
@gateway.client
|
101
|
+
.expects(:scroll)
|
102
|
+
.twice
|
103
|
+
.returns(MultiJson.load('{"_scroll_id":"abc456==", "hits":{"hits":[{"_source":{"foo":"bar"}}]}}'))
|
104
|
+
.then
|
105
|
+
.returns(MultiJson.load('{"_scroll_id":"abc789==", "hits":{"hits":[]}}'))
|
106
|
+
end
|
107
|
+
|
108
|
+
should "find all records in batches" do
|
109
|
+
@doc = nil
|
110
|
+
result = DummyFindModel.find_in_batches { |batch| @doc = batch.first['_source']['foo'] }
|
111
|
+
|
112
|
+
assert_equal 'abc789==', result
|
113
|
+
assert_equal 'bar', @doc
|
114
|
+
end
|
115
|
+
|
116
|
+
should "return an Enumerator for find in batches" do
|
117
|
+
@doc = nil
|
118
|
+
assert_nothing_raised do
|
119
|
+
e = DummyFindModel.find_in_batches
|
120
|
+
assert_instance_of Enumerator, e
|
121
|
+
|
122
|
+
e.each { |batch| @doc = batch.first['_source']['foo'] }
|
123
|
+
assert_equal 'bar', @doc
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
should "find each" do
|
128
|
+
@doc = nil
|
129
|
+
result = DummyFindModel.find_each { |doc| @doc = doc['_source']['foo'] }
|
130
|
+
|
131
|
+
assert_equal 'abc789==', result
|
132
|
+
assert_equal 'bar', @doc
|
133
|
+
end
|
134
|
+
|
135
|
+
should "return an Enumerator for find each" do
|
136
|
+
@doc = nil
|
137
|
+
assert_nothing_raised do
|
138
|
+
e = DummyFindModel.find_each
|
139
|
+
assert_instance_of Enumerator, e
|
140
|
+
|
141
|
+
e.each { |doc| @doc = doc['_source']['foo'] }
|
142
|
+
assert_equal 'bar', @doc
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'elasticsearch/persistence/model'
|
4
|
+
require 'elasticsearch/persistence/model/rails'
|
5
|
+
|
6
|
+
class Elasticsearch::Persistence::ModelGatewayTest < Test::Unit::TestCase
|
7
|
+
context "The model gateway" do
|
8
|
+
setup do
|
9
|
+
class DummyGatewayModel
|
10
|
+
include Elasticsearch::Persistence::Model
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
teardown do
|
15
|
+
Elasticsearch::Persistence::ModelGatewayTest.__send__ :remove_const, :DummyGatewayModel \
|
16
|
+
rescue NameError; nil
|
17
|
+
end
|
18
|
+
|
19
|
+
should "be accessible" do
|
20
|
+
assert_instance_of Elasticsearch::Persistence::Repository::Class, DummyGatewayModel.gateway
|
21
|
+
|
22
|
+
$a = 0
|
23
|
+
DummyGatewayModel.gateway { $a += 1 }
|
24
|
+
assert_equal 1, $a
|
25
|
+
|
26
|
+
@b = 0
|
27
|
+
def run!; DummyGatewayModel.gateway { |g| @b += 1 }; end
|
28
|
+
run!
|
29
|
+
assert_equal 1, @b
|
30
|
+
|
31
|
+
assert_equal DummyGatewayModel, DummyGatewayModel.gateway.klass
|
32
|
+
end
|
33
|
+
|
34
|
+
should "define common attributes" do
|
35
|
+
d = DummyGatewayModel.new
|
36
|
+
|
37
|
+
assert_respond_to d, :updated_at
|
38
|
+
assert_respond_to d, :created_at
|
39
|
+
end
|
40
|
+
|
41
|
+
should "allow to configure settings" do
|
42
|
+
DummyGatewayModel.settings(number_of_shards: 1)
|
43
|
+
|
44
|
+
assert_equal 1, DummyGatewayModel.settings.to_hash[:number_of_shards]
|
45
|
+
end
|
46
|
+
|
47
|
+
should "allow to configure mappings" do
|
48
|
+
DummyGatewayModel.mapping { indexes :name, analyzer: 'snowball' }
|
49
|
+
|
50
|
+
assert_equal 'snowball',
|
51
|
+
DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
|
52
|
+
end
|
53
|
+
|
54
|
+
should "configure the mapping via attribute" do
|
55
|
+
DummyGatewayModel.attribute :name, String, mapping: { analyzer: 'snowball' }
|
56
|
+
|
57
|
+
assert_respond_to DummyGatewayModel, :name
|
58
|
+
assert_equal 'snowball',
|
59
|
+
DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
|
60
|
+
end
|
61
|
+
|
62
|
+
should "configure the mapping via an attribute block" do
|
63
|
+
DummyGatewayModel.attribute :name, String do
|
64
|
+
indexes :name, analyzer: 'custom'
|
65
|
+
end
|
66
|
+
|
67
|
+
assert_respond_to DummyGatewayModel, :name
|
68
|
+
assert_equal 'custom',
|
69
|
+
DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
|
70
|
+
end
|
71
|
+
|
72
|
+
should "properly look up types for classes" do
|
73
|
+
assert_equal 'string', Elasticsearch::Persistence::Model::Utils::lookup_type(String)
|
74
|
+
assert_equal 'integer', Elasticsearch::Persistence::Model::Utils::lookup_type(Integer)
|
75
|
+
assert_equal 'float', Elasticsearch::Persistence::Model::Utils::lookup_type(Float)
|
76
|
+
assert_equal 'date', Elasticsearch::Persistence::Model::Utils::lookup_type(Date)
|
77
|
+
assert_equal 'boolean', Elasticsearch::Persistence::Model::Utils::lookup_type(Virtus::Attribute::Boolean)
|
78
|
+
end
|
79
|
+
|
80
|
+
should "remove IDs from hash when serializing" do
|
81
|
+
assert_equal( {foo: 'bar'}, DummyGatewayModel.gateway.serialize(id: '123', foo: 'bar') )
|
82
|
+
end
|
83
|
+
|
84
|
+
should "set IDs from hash when deserializing" do
|
85
|
+
assert_equal 'abc123', DummyGatewayModel.gateway.deserialize('_id' => 'abc123', '_source' => {}).id
|
86
|
+
end
|
87
|
+
|
88
|
+
should "set @persisted variable from hash when deserializing" do
|
89
|
+
assert DummyGatewayModel.gateway.deserialize('_id' => 'abc123', '_source' => {}).instance_variable_get(:@persisted)
|
90
|
+
end
|
91
|
+
|
92
|
+
should "allow to access the raw hit from results as Hashie::Mash" do
|
93
|
+
assert_equal 0.42, DummyGatewayModel.gateway.deserialize('_score' => 0.42, '_source' => {}).hit._score
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'elasticsearch/persistence/model'
|
4
|
+
require 'elasticsearch/persistence/model/rails'
|
5
|
+
|
6
|
+
require 'rails'
|
7
|
+
require 'action_controller/railtie'
|
8
|
+
require 'action_view/railtie'
|
9
|
+
|
10
|
+
class ::MyRailsModel
|
11
|
+
include Elasticsearch::Persistence::Model
|
12
|
+
include Elasticsearch::Persistence::Model::Rails
|
13
|
+
|
14
|
+
attribute :name, String, mapping: { analyzer: 'string' }
|
15
|
+
attribute :published_at, DateTime
|
16
|
+
attribute :published_on, Date
|
17
|
+
end
|
18
|
+
|
19
|
+
class Application < Rails::Application
|
20
|
+
config.eager_load = false
|
21
|
+
config.root = File.dirname(File.expand_path('../../../tmp', __FILE__))
|
22
|
+
config.logger = Logger.new($stderr)
|
23
|
+
|
24
|
+
routes.append do
|
25
|
+
resources :my_rails_models
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ApplicationController < ActionController::Base
|
30
|
+
include Application.routes.url_helpers
|
31
|
+
include ActionController::UrlFor
|
32
|
+
end
|
33
|
+
ApplicationController.default_url_options = { host: 'localhost' }
|
34
|
+
ApplicationController._routes.append { resources :my_rails_models }
|
35
|
+
|
36
|
+
class MyRailsModelController < ApplicationController; end
|
37
|
+
|
38
|
+
Application.initialize!
|
39
|
+
|
40
|
+
class Elasticsearch::Persistence::ModelRailsTest < Test::Unit::TestCase
|
41
|
+
context "The model in a Rails application" do
|
42
|
+
|
43
|
+
should "generate proper URLs and paths" do
|
44
|
+
model = MyRailsModel.new name: 'Test'
|
45
|
+
model.stubs(:id).returns(1)
|
46
|
+
model.stubs(:persisted?).returns(true)
|
47
|
+
|
48
|
+
controller = MyRailsModelController.new
|
49
|
+
controller.request = ActionDispatch::Request.new({})
|
50
|
+
|
51
|
+
assert_equal 'http://localhost/my_rails_models/1', controller.url_for(model)
|
52
|
+
assert_equal '/my_rails_models/1/edit', controller.edit_my_rails_model_path(model)
|
53
|
+
end
|
54
|
+
|
55
|
+
should "generate a link" do
|
56
|
+
class MyView; include ActionView::Helpers::UrlHelper; end
|
57
|
+
|
58
|
+
model = MyRailsModel.new name: 'Test'
|
59
|
+
view = MyView.new
|
60
|
+
view.expects(:url_for).with(model).returns('foo/bar')
|
61
|
+
|
62
|
+
assert_equal '<a href="foo/bar">Show</a>', view.link_to('Show', model)
|
63
|
+
end
|
64
|
+
|
65
|
+
should "parse DateTime from Rails forms" do
|
66
|
+
params = { "published_at(1i)"=>"2014",
|
67
|
+
"published_at(2i)"=>"1",
|
68
|
+
"published_at(3i)"=>"1",
|
69
|
+
"published_at(4i)"=>"12",
|
70
|
+
"published_at(5i)"=>"00"
|
71
|
+
}
|
72
|
+
|
73
|
+
m = MyRailsModel.new params
|
74
|
+
assert_equal "2014-01-01T12:00:00+00:00", m.published_at.iso8601
|
75
|
+
end
|
76
|
+
|
77
|
+
should "parse Date from Rails forms" do
|
78
|
+
params = { "published_on(1i)"=>"2014",
|
79
|
+
"published_on(2i)"=>"1",
|
80
|
+
"published_on(3i)"=>"1"
|
81
|
+
}
|
82
|
+
|
83
|
+
m = MyRailsModel.new params
|
84
|
+
assert_equal "2014-01-01", m.published_on.iso8601
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|